diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 764aec6..2447264 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -81,6 +81,49 @@ jobs: echo "== timings =="; cat bench.txt echo "== trend json =="; grep '"bench"' bench.json + patches-apply: + # The RV1106 series must apply cleanly onto pristine linux-6.18.46. + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: cache pristine kernel tarball + uses: actions/cache@v4 + with: + path: ~/linux-6.18.46.tar.xz + key: linux-6.18.46-tarball + - name: fetch + verify pristine + run: | + [ -f ~/linux-6.18.46.tar.xz ] || \ + curl -fSL https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.18.46.tar.xz -o ~/linux-6.18.46.tar.xz + echo "$(cat build/linux-6.18.46.tar.xz.sha256) $HOME/linux-6.18.46.tar.xz" | sha256sum -c - + - name: apply the series in order + run: | + tar -C /tmp -xf ~/linux-6.18.46.tar.xz + for p in patches/*.patch; do + git -C /tmp/linux-6.18.46 apply --whitespace=nowarn "$GITHUB_WORKSPACE/$p" \ + && echo "applied $p" || { echo "FAILED to apply $p"; exit 1; } + done + echo "full series applied cleanly onto pristine 6.18.46" + + kernel-build: + # Full hermetic build on the warden-sdk self-hosted runner (bfe-mpc-0640, + # ADR-0004). Gated on manual dispatch until that runner is registered. + if: github.event_name == 'workflow_dispatch' + runs-on: [self-hosted, warden-sdk] + steps: + - uses: actions/checkout@v4 + - name: build zImage + rv1106-warden.dtb + env: + WORK: ${{ github.workspace }}/kbuild-out + run: bash build/build-kernel.sh + - uses: actions/upload-artifact@v4 + with: + name: kernel-rv1106 + path: | + ${{ github.workspace }}/kbuild-out/linux-6.18.46/arch/arm/boot/zImage + ${{ github.workspace }}/kbuild-out/linux-6.18.46/arch/arm/boot/dts/rockchip/rv1106-warden.dtb + retention-days: 14 + badges: needs: [test] if: github.event_name == 'push' && github.ref == 'refs/heads/bringup' diff --git a/build/build-kernel.sh b/build/build-kernel.sh new file mode 100755 index 0000000..1eae7ba --- /dev/null +++ b/build/build-kernel.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +# Hermetic-ish kernel build for the WardenOS 86-Panel (RV1106). +# +# fetch pristine linux-6.18.46 -> apply patches/ in order -> configure with +# build/warden_defconfig -> build zImage + rv1106-warden.dtb. +# +# The pristine tree is the ONLY external input; the delta is patches/. A build +# from a clean checkout + a verified tarball is reproducible. +# +# Env: +# KERNEL_TARBALL path to a local linux-6.18.46.tar.xz (skips the download) +# SDK_TC dir holding the arm-rockchip830 uclibc cross toolchain bin/ +# WORK build scratch dir (default: a mktemp under $TMPDIR) +# JOBS parallel make jobs (default: nproc) +# +# Requires: `python` (not python3) on PATH — the SDK quirk; the CI runner provides +# a project-local venv. Builds are SERIAL on the shared SDK box — never run two. +set -euo pipefail + +KVER=6.18.46 +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # build/ +REPO="$(cd "$HERE/.." && pwd)" +PATCHES="$REPO/patches" +SHA_FILE="$HERE/linux-$KVER.tar.xz.sha256" +JOBS="${JOBS:-$(nproc)}" +WORK="${WORK:-$(mktemp -d "${TMPDIR:-/tmp}/warden-kbuild.XXXXXX")}" +URL="https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-$KVER.tar.xz" + +log() { printf '\033[36m== %s\033[0m\n' "$*"; } + +command -v python >/dev/null || { echo "need 'python' (not python3) on PATH — SDK quirk" >&2; exit 1; } + +# 1. obtain + verify the pristine tarball +mkdir -p "$WORK" +TB="${KERNEL_TARBALL:-$WORK/linux-$KVER.tar.xz}" +if [ ! -f "$TB" ]; then + log "downloading $URL" + curl -fSL "$URL" -o "$TB" +fi +if [ -f "$SHA_FILE" ]; then + want="$(cat "$SHA_FILE")" + got="$(sha256sum "$TB" | awk '{print $1}')" + [ "$want" = "$got" ] || { echo "tarball sha256 mismatch: want $want got $got" >&2; exit 1; } + log "tarball sha256 verified" +fi + +# 2. extract pristine +SRC="$WORK/linux-$KVER" +rm -rf "$SRC" +log "extracting pristine" +tar -C "$WORK" -xf "$TB" + +# 3. apply the patch series in order +log "applying patch series" +for p in "$PATCHES"/*.patch; do + git -C "$SRC" apply --whitespace=nowarn "$p" 2>/dev/null \ + || patch -d "$SRC" -p1 --no-backup-if-mismatch < "$p" + echo " applied $(basename "$p")" +done + +# 4. configure +log "configuring (warden_defconfig)" +cp "$HERE/warden_defconfig" "$SRC/.config" +export ARCH=arm CROSS_COMPILE=arm-rockchip830-linux-uclibcgnueabihf- +if [ -n "${SDK_TC:-}" ]; then export PATH="$SDK_TC:$PATH"; fi +command -v "${CROSS_COMPILE}gcc" >/dev/null \ + || { echo "cross toolchain ${CROSS_COMPILE}gcc not on PATH (set SDK_TC)" >&2; exit 1; } +make -C "$SRC" ARCH=arm CROSS_COMPILE="$CROSS_COMPILE" olddefconfig >/dev/null + +# 5. build zImage + the board dtb +log "building zImage + rv1106-warden.dtb (-j$JOBS)" +make -C "$SRC" ARCH=arm CROSS_COMPILE="$CROSS_COMPILE" -j"$JOBS" \ + zImage rockchip/rv1106-warden.dtb + +Z="$SRC/arch/arm/boot/zImage" +D="$SRC/arch/arm/boot/dts/rockchip/rv1106-warden.dtb" +log "build OK" +ls -la "$Z" "$D" +echo "zImage: $Z" +echo "dtb: $D" diff --git a/build/linux-6.18.46.tar.xz.sha256 b/build/linux-6.18.46.tar.xz.sha256 new file mode 100644 index 0000000..1a6134e --- /dev/null +++ b/build/linux-6.18.46.tar.xz.sha256 @@ -0,0 +1 @@ +f5d44b93808b02cc2969c5404ba081d97523719c9fd2ba2de6db318b4141cca0 diff --git a/build/warden_defconfig b/build/warden_defconfig new file mode 100644 index 0000000..e0fabac --- /dev/null +++ b/build/warden_defconfig @@ -0,0 +1,1310 @@ +CONFIG_KERNEL_XZ=y +CONFIG_SYSVIPC=y +CONFIG_NO_HZ_IDLE=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_CGROUPS=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_EXPERT=y +CONFIG_PERF_EVENTS=y +CONFIG_KEXEC=y +CONFIG_ARCH_VIRT=y +CONFIG_ARCH_AIROHA=y +CONFIG_ARCH_HPE=y +CONFIG_ARCH_HPE_GXP=y +CONFIG_ARCH_SUNPLUS=y +CONFIG_ARCH_UNIPHIER=y +CONFIG_ARCH_ACTIONS=y +CONFIG_ARCH_ALPINE=y +CONFIG_ARCH_ARTPEC=y +CONFIG_MACH_ARTPEC6=y +CONFIG_ARCH_ASPEED=y +CONFIG_MACH_ASPEED_G6=y +CONFIG_ARCH_AT91=y +CONFIG_SOC_SAMA5D2=y +CONFIG_SOC_SAMA5D3=y +CONFIG_SOC_SAMA5D4=y +CONFIG_SOC_SAMA7D65=y +CONFIG_SOC_SAMA7G5=y +CONFIG_SOC_LAN966=y +CONFIG_ARCH_BCM=y +CONFIG_ARCH_BCM_CYGNUS=y +CONFIG_ARCH_BCM_HR2=y +CONFIG_ARCH_BCM_NSP=y +CONFIG_ARCH_BCM_5301X=y +CONFIG_ARCH_BCM_281XX=y +CONFIG_ARCH_BCM_21664=y +CONFIG_ARCH_BCM_23550=y +CONFIG_ARCH_BCM2835=y +CONFIG_ARCH_BCM_53573=y +CONFIG_ARCH_BRCMSTB=y +CONFIG_ARCH_BCMBCA=y +CONFIG_ARCH_BCMBCA_CORTEXA7=y +CONFIG_ARCH_BCMBCA_CORTEXA9=y +CONFIG_ARCH_BCMBCA_BRAHMAB15=y +CONFIG_ARCH_BERLIN=y +CONFIG_MACH_BERLIN_BG2=y +CONFIG_MACH_BERLIN_BG2CD=y +CONFIG_MACH_BERLIN_BG2Q=y +CONFIG_ARCH_DIGICOLOR=y +CONFIG_ARCH_EXYNOS=y +CONFIG_ARCH_HIGHBANK=y +CONFIG_ARCH_HISI=y +CONFIG_ARCH_HI3xxx=y +CONFIG_ARCH_HIP01=y +CONFIG_ARCH_HIP04=y +CONFIG_ARCH_HIX5HD2=y +CONFIG_ARCH_MXC=y +CONFIG_SOC_IMX50=y +CONFIG_SOC_IMX51=y +CONFIG_SOC_IMX53=y +CONFIG_SOC_IMX6Q=y +CONFIG_SOC_IMX6SL=y +CONFIG_SOC_IMX6SLL=y +CONFIG_SOC_IMX6SX=y +CONFIG_SOC_IMX6UL=y +CONFIG_SOC_LS1021A=y +CONFIG_SOC_IMX7D=y +CONFIG_SOC_IMX7ULP=y +CONFIG_SOC_VF610=y +CONFIG_ARCH_KEYSTONE=y +CONFIG_ARCH_MEDIATEK=y +CONFIG_ARCH_MESON=y +CONFIG_ARCH_MILBEAUT=y +CONFIG_ARCH_MILBEAUT_M10V=y +CONFIG_ARCH_MMP=y +CONFIG_MACH_MMP2_DT=y +CONFIG_MACH_MMP3_DT=y +CONFIG_ARCH_MVEBU=y +CONFIG_MACH_ARMADA_370=y +CONFIG_MACH_ARMADA_375=y +CONFIG_MACH_ARMADA_38X=y +CONFIG_MACH_ARMADA_39X=y +CONFIG_MACH_ARMADA_XP=y +CONFIG_MACH_DOVE=y +CONFIG_ARCH_OMAP3=y +CONFIG_ARCH_OMAP4=y +CONFIG_SOC_OMAP5=y +CONFIG_SOC_AM33XX=y +CONFIG_SOC_AM43XX=y +CONFIG_SOC_DRA7XX=y +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_ROCKCHIP=y +CONFIG_ARCH_RENESAS=y +CONFIG_ARCH_INTEL_SOCFPGA=y +CONFIG_PLAT_SPEAR=y +CONFIG_ARCH_SPEAR13XX=y +CONFIG_MACH_SPEAR1310=y +CONFIG_MACH_SPEAR1340=y +CONFIG_ARCH_STI=y +CONFIG_ARCH_STM32=y +CONFIG_ARCH_SUNXI=y +CONFIG_ARCH_TEGRA=y +CONFIG_ARCH_U8500=y +CONFIG_ARCH_VEXPRESS=y +CONFIG_ARCH_VEXPRESS_TC2_PM=y +CONFIG_ARCH_WM8850=y +CONFIG_ARCH_ZYNQ=y +CONFIG_SMP=y +CONFIG_NR_CPUS=16 +CONFIG_ARM_APPENDED_DTB=y +CONFIG_ARM_ATAG_DTB_COMPAT=y +CONFIG_EFI=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_USERSPACE=m +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_CPUFREQ_DT=y +CONFIG_ARM_IMX6Q_CPUFREQ=y +CONFIG_ARM_QCOM_CPUFREQ_NVMEM=y +CONFIG_ARM_RASPBERRYPI_CPUFREQ=y +CONFIG_ARM_SCMI_CPUFREQ=y +CONFIG_QORIQ_CPUFREQ=y +CONFIG_CPU_IDLE=y +CONFIG_ARM_CPUIDLE=y +CONFIG_ARM_PSCI_CPUIDLE=y +CONFIG_ARM_ZYNQ_CPUIDLE=y +CONFIG_ARM_EXYNOS_CPUIDLE=y +CONFIG_ARM_TEGRA_CPUIDLE=y +CONFIG_ARM_QCOM_SPM_CPUIDLE=y +CONFIG_KERNEL_MODE_NEON=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_CMDLINE_PARTITION=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_MIP6=m +CONFIG_IPV6_TUNNEL=m +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_NET_DSA=m +CONFIG_QRTR=m +CONFIG_QRTR_SMD=m +CONFIG_CAN=y +CONFIG_BT=y +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_BCM=y +CONFIG_BT_MRVL=m +CONFIG_BT_MRVL_SDIO=m +CONFIG_BT_QCOMSMD=m +CONFIG_CFG80211=y +CONFIG_RFKILL=y +CONFIG_RFKILL_INPUT=y +CONFIG_RFKILL_GPIO=y +CONFIG_NFC=m +CONFIG_NFC_DIGITAL=m +CONFIG_NFC_NCI=m +CONFIG_NFC_NCI_SPI=m +CONFIG_NFC_NCI_UART=m +CONFIG_NFC_HCI=m +CONFIG_NFC_SHDLC=y +CONFIG_NFC_S3FWRN5_I2C=m +CONFIG_PCIEPORTBUS=y +CONFIG_PCI_MVEBU=y +CONFIG_PCI_TEGRA=y +CONFIG_PCIE_RCAR_HOST=y +CONFIG_PCI_RCAR_GEN2=y +CONFIG_PCI_LAYERSCAPE=y +CONFIG_PCI_DRA7XX_EP=y +CONFIG_PCI_KEYSTONE_HOST=y +CONFIG_PCI_ENDPOINT=y +CONFIG_PCI_ENDPOINT_CONFIGFS=y +CONFIG_PCI_EPF_TEST=m +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_OMAP_OCP2SCP=y +CONFIG_ARM_SCMI_PROTOCOL=y +CONFIG_RASPBERRYPI_FIRMWARE=y +CONFIG_TI_SCI_PROTOCOL=y +CONFIG_TRUSTED_FOUNDATIONS=y +CONFIG_BCM47XX_NVRAM=y +CONFIG_BCM47XX_SPROM=y +CONFIG_EFI_CAPSULE_LOADER=m +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_OF=y +CONFIG_MTD_RAW_NAND=y +CONFIG_MTD_NAND_DENALI_DT=y +CONFIG_MTD_NAND_OMAP2=y +CONFIG_MTD_NAND_OMAP_BCH=y +CONFIG_MTD_NAND_ATMEL=y +CONFIG_MTD_NAND_MARVELL=y +CONFIG_MTD_NAND_BRCMNAND=y +CONFIG_MTD_NAND_GPMI_NAND=y +CONFIG_MTD_NAND_VF610_NFC=y +CONFIG_MTD_NAND_DAVINCI=y +CONFIG_MTD_NAND_STM32_FMC2=y +CONFIG_MTD_NAND_PL35X=y +CONFIG_MTD_SPI_NOR=y +CONFIG_MTD_UBI=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=65536 +CONFIG_VIRTIO_BLK=y +CONFIG_AD525X_DPOT=y +CONFIG_AD525X_DPOT_I2C=y +CONFIG_ICS932S401=y +CONFIG_ATMEL_SSC=m +CONFIG_QCOM_COINCELL=m +CONFIG_QCOM_FASTRPC=m +CONFIG_APDS9802ALS=y +CONFIG_ISL29003=y +CONFIG_PCI_ENDPOINT_TEST=m +CONFIG_EEPROM_AT24=y +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_DEV_SR=y +CONFIG_ATA=y +CONFIG_SATA_AHCI=y +CONFIG_SATA_AHCI_PLATFORM=y +CONFIG_AHCI_BRCM=y +CONFIG_AHCI_DM816=y +CONFIG_AHCI_DWC=m +CONFIG_AHCI_ST=y +CONFIG_AHCI_IMX=y +CONFIG_AHCI_SUNXI=y +CONFIG_AHCI_TEGRA=y +CONFIG_AHCI_QORIQ=y +CONFIG_SATA_HIGHBANK=y +CONFIG_SATA_MV=y +CONFIG_SATA_RCAR=y +CONFIG_NETDEVICES=y +CONFIG_VIRTIO_NET=y +CONFIG_B53_SPI_DRIVER=m +CONFIG_B53_MDIO_DRIVER=m +CONFIG_B53_MMAP_DRIVER=m +CONFIG_NET_DSA_BCM_SF2=m +CONFIG_NET_DSA_RZN1_A5PSW=m +CONFIG_SUN4I_EMAC=y +CONFIG_SPI_AX88796C=m +CONFIG_BCMGENET=m +CONFIG_BGMAC_BCMA=y +CONFIG_SYSTEMPORT=m +CONFIG_MACB=y +CONFIG_NET_CALXEDA_XGMAC=y +CONFIG_FTGMAC100=m +CONFIG_GIANFAR=y +CONFIG_HIX5HD2_GMAC=y +CONFIG_E1000E=y +CONFIG_IGB=y +CONFIG_MV643XX_ETH=y +CONFIG_MVNETA=y +CONFIG_PXA168_ETH=m +CONFIG_KS8851=y +CONFIG_LAN966X_SWITCH=m +CONFIG_R8169=y +CONFIG_SH_ETH=y +CONFIG_RAVB=y +CONFIG_SMSC911X=y +CONFIG_SNI_AVE=y +CONFIG_STMMAC_ETH=y +CONFIG_DWMAC_DWC_QOS_ETH=y +CONFIG_TI_CPSW=y +CONFIG_TI_CPSW_SWITCHDEV=y +CONFIG_TI_CPTS=y +CONFIG_TI_KEYSTONE_NETCP=y +CONFIG_TI_KEYSTONE_NETCP_ETHSS=y +CONFIG_XILINX_EMACLITE=y +CONFIG_SFP=m +CONFIG_BROADCOM_PHY=y +CONFIG_ICPLUS_PHY=y +CONFIG_MARVELL_PHY=y +CONFIG_AT803X_PHY=y +CONFIG_ROCKCHIP_PHY=y +CONFIG_DP83867_PHY=y +CONFIG_CAN_AT91=m +CONFIG_CAN_FLEXCAN=m +CONFIG_CAN_SUN4I=y +CONFIG_CAN_XILINXCAN=y +CONFIG_CAN_C_CAN=m +CONFIG_CAN_C_CAN_PLATFORM=m +CONFIG_CAN_RCAR=m +CONFIG_CAN_MCP251X=y +CONFIG_MDIO_MSCC_MIIM=m +CONFIG_USB_PEGASUS=y +CONFIG_USB_RTL8152=m +CONFIG_USB_LAN78XX=m +CONFIG_USB_USBNET=y +CONFIG_USB_NET_SMSC75XX=y +CONFIG_USB_NET_SMSC95XX=y +CONFIG_BRCMFMAC=m +CONFIG_MWIFIEX=m +CONFIG_MWIFIEX_SDIO=m +CONFIG_INPUT_JOYDEV=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_QT1070=m +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYBOARD_TEGRA=y +CONFIG_KEYBOARD_PXA27x=m +CONFIG_KEYBOARD_SAMSUNG=m +CONFIG_KEYBOARD_ST_KEYSCAN=y +CONFIG_KEYBOARD_SPEAR=y +CONFIG_KEYBOARD_TM2_TOUCHKEY=m +CONFIG_KEYBOARD_CROS_EC=m +CONFIG_MOUSE_PS2_ELANTECH=y +CONFIG_MOUSE_CYAPA=m +CONFIG_MOUSE_ELAN_I2C=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ADC=m +CONFIG_TOUCHSCREEN_ATMEL_MXT=m +CONFIG_TOUCHSCREEN_GOODIX=y +CONFIG_TOUCHSCREEN_ELAN=m +CONFIG_TOUCHSCREEN_MMS114=m +CONFIG_TOUCHSCREEN_EDT_FT5X06=m +CONFIG_TOUCHSCREEN_WM97XX=m +CONFIG_TOUCHSCREEN_ST1232=m +CONFIG_TOUCHSCREEN_STMPE=y +CONFIG_TOUCHSCREEN_SUN4I=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_PM8941_PWRKEY=y +CONFIG_INPUT_MAX77693_HAPTIC=m +CONFIG_INPUT_MAX8997_HAPTIC=m +CONFIG_INPUT_GPIO_DECODER=m +CONFIG_INPUT_CPCAP_PWRBUTTON=m +CONFIG_INPUT_TPS65219_PWRBUTTON=m +CONFIG_INPUT_AXP20X_PEK=m +CONFIG_INPUT_DA9063_ONKEY=m +CONFIG_INPUT_ADXL34X=m +CONFIG_INPUT_STPMIC1_ONKEY=y +CONFIG_SERIO_AMBAKMI=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=5 +CONFIG_SERIAL_8250_RUNTIME_UARTS=5 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_ASPEED_VUART=m +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_BCM2835AUX=y +CONFIG_SERIAL_8250_DW=y +CONFIG_SERIAL_8250_EM=y +CONFIG_SERIAL_8250_OMAP=y +CONFIG_SERIAL_8250_MT6577=y +CONFIG_SERIAL_8250_UNIPHIER=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +CONFIG_SERIAL_ATMEL=y +CONFIG_SERIAL_ATMEL_CONSOLE=y +CONFIG_SERIAL_ATMEL_TTYAT=y +CONFIG_SERIAL_MESON=y +CONFIG_SERIAL_MESON_CONSOLE=y +CONFIG_SERIAL_SAMSUNG=y +CONFIG_SERIAL_SAMSUNG_CONSOLE=y +CONFIG_SERIAL_TEGRA=y +CONFIG_SERIAL_IMX=y +CONFIG_SERIAL_IMX_CONSOLE=y +CONFIG_SERIAL_SH_SCI=y +CONFIG_SERIAL_SH_SCI_NR_UARTS=20 +CONFIG_SERIAL_MSM=y +CONFIG_SERIAL_MSM_CONSOLE=y +CONFIG_SERIAL_VT8500=y +CONFIG_SERIAL_VT8500_CONSOLE=y +CONFIG_SERIAL_BCM63XX_CONSOLE=y +CONFIG_SERIAL_XILINX_PS_UART=y +CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y +CONFIG_SERIAL_FSL_LPUART=y +CONFIG_SERIAL_FSL_LPUART_CONSOLE=y +CONFIG_SERIAL_CONEXANT_DIGICOLOR=y +CONFIG_SERIAL_CONEXANT_DIGICOLOR_CONSOLE=y +CONFIG_SERIAL_ST_ASC=y +CONFIG_SERIAL_ST_ASC_CONSOLE=y +CONFIG_SERIAL_STM32=y +CONFIG_SERIAL_STM32_CONSOLE=y +CONFIG_SERIAL_OWL=y +CONFIG_SERIAL_DEV_BUS=y +CONFIG_VIRTIO_CONSOLE=y +CONFIG_ASPEED_KCS_IPMI_BMC=m +CONFIG_ASPEED_BT_IPMI_BMC=m +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_ST=y +CONFIG_TCG_TPM=m +CONFIG_TCG_TIS_I2C_INFINEON=m +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_ARB_GPIO_CHALLENGE=m +CONFIG_I2C_MUX_GPIO=y +CONFIG_I2C_MUX_PCA954x=y +CONFIG_I2C_MUX_PINCTRL=y +CONFIG_I2C_DEMUX_PINCTRL=y +CONFIG_I2C_ASPEED=m +CONFIG_I2C_AT91=m +CONFIG_I2C_BCM2835=y +CONFIG_I2C_CADENCE=y +CONFIG_I2C_DAVINCI=y +CONFIG_I2C_DESIGNWARE_CORE=y +CONFIG_I2C_DIGICOLOR=m +CONFIG_I2C_EMEV2=m +CONFIG_I2C_IMX=y +CONFIG_I2C_MESON=y +CONFIG_I2C_MV64XXX=y +CONFIG_I2C_OWL=y +CONFIG_I2C_QCOM_CCI=m +CONFIG_I2C_QUP=y +CONFIG_I2C_RIIC=y +CONFIG_I2C_RK3X=y +CONFIG_I2C_S3C2410=y +CONFIG_I2C_SH_MOBILE=y +CONFIG_I2C_ST=y +CONFIG_I2C_STM32F7=y +CONFIG_I2C_SUN6I_P2WI=y +CONFIG_I2C_TEGRA=y +CONFIG_I2C_UNIPHIER=y +CONFIG_I2C_UNIPHIER_F=y +CONFIG_I2C_XILINX=y +CONFIG_I2C_RCAR=y +CONFIG_I2C_CROS_EC_TUNNEL=m +CONFIG_I2C_SLAVE_EEPROM=y +CONFIG_SPI=y +CONFIG_SPI_ASPEED_SMC=m +CONFIG_SPI_ATMEL=m +CONFIG_SPI_ATMEL_QUADSPI=m +CONFIG_SPI_BCM2835=y +CONFIG_SPI_BCM2835AUX=y +CONFIG_SPI_CADENCE=y +CONFIG_SPI_CADENCE_QUADSPI=y +CONFIG_SPI_DAVINCI=y +CONFIG_SPI_FSL_QUADSPI=m +CONFIG_SPI_GXP=m +CONFIG_SPI_GPIO=m +CONFIG_SPI_FSL_DSPI=m +CONFIG_SPI_OMAP24XX=y +CONFIG_SPI_ORION=y +CONFIG_SPI_PL022=y +CONFIG_SPI_ROCKCHIP=m +CONFIG_SPI_RSPI=y +CONFIG_SPI_QUP=m +CONFIG_SPI_S3C64XX=m +CONFIG_SPI_SH_MSIOF=m +CONFIG_SPI_SH_HSPI=y +CONFIG_SPI_STM32=m +CONFIG_SPI_STM32_QSPI=y +CONFIG_SPI_SUN4I=y +CONFIG_SPI_SUN6I=y +CONFIG_SPI_TEGRA114=y +CONFIG_SPI_TEGRA20_SFLASH=y +CONFIG_SPI_TEGRA20_SLINK=y +CONFIG_SPI_XILINX=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPMI=y +CONFIG_PINCTRL_AS3722=y +CONFIG_PINCTRL_MCP23S08=m +CONFIG_PINCTRL_MICROCHIP_SGPIO=y +CONFIG_PINCTRL_OCELOT=y +CONFIG_PINCTRL_PALMAS=y +CONFIG_PINCTRL_STMFX=y +CONFIG_PINCTRL_OWL=y +CONFIG_PINCTRL_S500=y +CONFIG_PINCTRL_MSM=y +CONFIG_PINCTRL_APQ8064=y +CONFIG_PINCTRL_APQ8084=y +CONFIG_PINCTRL_IPQ8064=y +CONFIG_PINCTRL_MSM8660=y +CONFIG_PINCTRL_MSM8960=y +CONFIG_PINCTRL_MSM8X74=y +CONFIG_PINCTRL_MSM8916=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_PINCTRL_QCOM_SSBI_PMIC=y +CONFIG_PINCTRL_RZA2=y +CONFIG_PINCTRL_RZN1=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_ASPEED_SGPIO=y +CONFIG_GPIO_DAVINCI=y +CONFIG_GPIO_DWAPB=y +CONFIG_GPIO_EM=y +CONFIG_GPIO_MPC8XXX=y +CONFIG_GPIO_MXC=y +CONFIG_GPIO_RCAR=y +CONFIG_GPIO_SYSCON=y +CONFIG_GPIO_UNIPHIER=y +CONFIG_GPIO_XILINX=y +CONFIG_GPIO_ZYNQ=y +CONFIG_GPIO_PCA953X=y +CONFIG_GPIO_PCA953X_IRQ=y +CONFIG_GPIO_PCF857X=y +CONFIG_GPIO_PALMAS=y +CONFIG_GPIO_STMPE=y +CONFIG_GPIO_TPS6586X=y +CONFIG_GPIO_TPS65910=y +CONFIG_GPIO_TWL4030=y +CONFIG_POWER_RESET_AS3722=y +CONFIG_POWER_RESET_GPIO=y +CONFIG_POWER_RESET_GPIO_RESTART=y +CONFIG_POWER_RESET_MSM=y +CONFIG_POWER_RESET_QCOM_PON=y +CONFIG_POWER_RESET_ST=y +CONFIG_POWER_RESET_KEYSTONE=y +CONFIG_POWER_RESET_RMOBILE=y +CONFIG_BATTERY_ACT8945A=y +CONFIG_BATTERY_CPCAP=m +CONFIG_BATTERY_SBS=y +CONFIG_BATTERY_BQ27XXX=m +CONFIG_AXP20X_POWER=m +CONFIG_BATTERY_MAX17040=m +CONFIG_BATTERY_MAX17042=m +CONFIG_CHARGER_CPCAP=m +CONFIG_CHARGER_GPIO=m +CONFIG_CHARGER_MAX14577=m +CONFIG_CHARGER_MAX77693=m +CONFIG_CHARGER_MAX8997=m +CONFIG_CHARGER_MAX8998=m +CONFIG_CHARGER_SMB347=m +CONFIG_CHARGER_TPS65090=y +CONFIG_BATTERY_ACER_A500=m +CONFIG_SENSORS_ARM_SCMI=y +CONFIG_SENSORS_ASPEED=m +CONFIG_SENSORS_GXP_FAN_CTRL=m +CONFIG_SENSORS_IIO_HWMON=y +CONFIG_SENSORS_LAN966X=m +CONFIG_SENSORS_LM90=y +CONFIG_SENSORS_LM95245=y +CONFIG_SENSORS_NTC_THERMISTOR=m +CONFIG_SENSORS_PWM_FAN=m +CONFIG_SENSORS_RASPBERRYPI_HWMON=m +CONFIG_SENSORS_INA2XX=m +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_IMX_THERMAL=y +CONFIG_QORIQ_THERMAL=m +CONFIG_ROCKCHIP_THERMAL=y +CONFIG_ARMADA_THERMAL=y +CONFIG_BCM2711_THERMAL=m +CONFIG_BCM2835_THERMAL=m +CONFIG_BRCMSTB_THERMAL=m +CONFIG_ST_THERMAL_MEMMAP=y +CONFIG_RCAR_THERMAL=y +CONFIG_TEGRA_SOCTHERM=m +CONFIG_TEGRA30_TSENSOR=m +CONFIG_GENERIC_ADC_THERMAL=m +CONFIG_QCOM_TSENS=y +CONFIG_UNIPHIER_THERMAL=y +CONFIG_DA9063_WATCHDOG=m +CONFIG_XILINX_WATCHDOG=y +CONFIG_ARM_SP805_WATCHDOG=y +CONFIG_AT91SAM9X_WATCHDOG=y +CONFIG_SAMA5D4_WATCHDOG=y +CONFIG_S3C2410_WATCHDOG=m +CONFIG_DW_WATCHDOG=y +CONFIG_DAVINCI_WATCHDOG=m +CONFIG_ORION_WATCHDOG=y +CONFIG_RN5T618_WATCHDOG=y +CONFIG_SUNXI_WATCHDOG=y +CONFIG_IMX2_WDT=y +CONFIG_ST_LPC_WATCHDOG=y +CONFIG_TEGRA_WATCHDOG=m +CONFIG_QCOM_WDT=m +CONFIG_MESON_WATCHDOG=y +CONFIG_DIGICOLOR_WATCHDOG=y +CONFIG_RENESAS_WDT=m +CONFIG_RENESAS_RZAWDT=m +CONFIG_RENESAS_RZN1WDT=m +CONFIG_STPMIC1_WATCHDOG=y +CONFIG_PM8916_WATCHDOG=m +CONFIG_BCM47XX_WDT=y +CONFIG_BCM2835_WDT=y +CONFIG_BCM_KONA_WDT=y +CONFIG_BCM7038_WDT=m +CONFIG_GXP_WATCHDOG=y +CONFIG_BCMA_HOST_SOC=y +CONFIG_BCMA_DRIVER_GMAC_CMN=y +CONFIG_BCMA_DRIVER_GPIO=y +CONFIG_MFD_ACT8945A=y +CONFIG_MFD_AS3711=y +CONFIG_MFD_AS3722=y +CONFIG_MFD_ATMEL_FLEXCOM=y +CONFIG_MFD_ATMEL_HLCDC=m +CONFIG_MFD_BCM590XX=y +CONFIG_MFD_AC100=y +CONFIG_MFD_AXP20X_I2C=y +CONFIG_MFD_AXP20X_RSB=y +CONFIG_MFD_DA9063=m +CONFIG_MFD_MAX14577=y +CONFIG_MFD_MAX77686=y +CONFIG_MFD_MAX77693=m +CONFIG_MFD_MAX8907=y +CONFIG_MFD_MAX8997=y +CONFIG_MFD_MAX8998=y +CONFIG_MFD_CPCAP=y +CONFIG_MFD_PM8XXX=y +CONFIG_MFD_QCOM_RPM=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_MFD_RK8XX_I2C=y +CONFIG_MFD_RN5T618=y +CONFIG_MFD_SEC_I2C=y +CONFIG_MFD_STMPE=y +CONFIG_MFD_PALMAS=y +CONFIG_MFD_TPS65090=y +CONFIG_MFD_TPS65217=y +CONFIG_MFD_TPS65218=y +CONFIG_MFD_TPS65219=y +CONFIG_MFD_TPS6586X=y +CONFIG_MFD_TPS65910=y +CONFIG_MFD_STM32_LPTIMER=m +CONFIG_MFD_STPMIC1=y +CONFIG_MFD_ACER_A500_EC=m +CONFIG_REGULATOR_ACT8865=y +CONFIG_REGULATOR_ACT8945A=y +CONFIG_REGULATOR_ANATOP=y +CONFIG_REGULATOR_AB8500=y +CONFIG_REGULATOR_ARM_SCMI=y +CONFIG_REGULATOR_AS3711=y +CONFIG_REGULATOR_AS3722=y +CONFIG_REGULATOR_AXP20X=y +CONFIG_REGULATOR_BCM590XX=y +CONFIG_REGULATOR_CPCAP=y +CONFIG_REGULATOR_DA9210=y +CONFIG_REGULATOR_FAN53555=y +CONFIG_REGULATOR_GPIO=y +CONFIG_REGULATOR_LP872X=y +CONFIG_REGULATOR_MAX14577=m +CONFIG_REGULATOR_MAX8907=y +CONFIG_REGULATOR_MAX8952=m +CONFIG_REGULATOR_MAX8973=y +CONFIG_REGULATOR_MAX8997=m +CONFIG_REGULATOR_MAX8998=m +CONFIG_REGULATOR_MAX77686=y +CONFIG_REGULATOR_MAX77693=m +CONFIG_REGULATOR_MAX77802=y +CONFIG_REGULATOR_PALMAS=y +CONFIG_REGULATOR_PBIAS=y +CONFIG_REGULATOR_PWM=y +CONFIG_REGULATOR_QCOM_RPM=y +CONFIG_REGULATOR_QCOM_SMD_RPM=y +CONFIG_REGULATOR_QCOM_SPMI=y +CONFIG_REGULATOR_RK808=y +CONFIG_REGULATOR_RN5T618=y +CONFIG_REGULATOR_S2MPA01=m +CONFIG_REGULATOR_S2MPS11=y +CONFIG_REGULATOR_S5M8767=y +CONFIG_REGULATOR_STM32_BOOSTER=m +CONFIG_REGULATOR_STM32_VREFBUF=m +CONFIG_REGULATOR_STM32_PWR=y +CONFIG_REGULATOR_STPMIC1=y +CONFIG_REGULATOR_TI_ABB=y +CONFIG_REGULATOR_TPS51632=y +CONFIG_REGULATOR_TPS62360=y +CONFIG_REGULATOR_TPS65090=y +CONFIG_REGULATOR_TPS65217=y +CONFIG_REGULATOR_TPS65218=y +CONFIG_REGULATOR_TPS65219=y +CONFIG_REGULATOR_TPS6586X=y +CONFIG_REGULATOR_TPS65910=y +CONFIG_REGULATOR_TWL4030=y +CONFIG_REGULATOR_VEXPRESS=y +CONFIG_REGULATOR_WM8994=m +CONFIG_CEC_SAMSUNG_S5P=m +CONFIG_CEC_STM32=m +CONFIG_MEDIA_SUPPORT=m +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_USB_VIDEO_CLASS=m +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_V4L_MEM2MEM_DRIVERS=y +CONFIG_VIDEO_ASPEED=m +CONFIG_VIDEO_ATMEL_ISI=m +CONFIG_VIDEO_MMP_CAMERA=m +CONFIG_VIDEO_MICROCHIP_ISC=m +CONFIG_VIDEO_MICROCHIP_XISC=m +CONFIG_VIDEO_MICROCHIP_CSI2DC=m +CONFIG_VIDEO_TEGRA_VDE=m +CONFIG_VIDEO_RENESAS_CEU=m +CONFIG_VIDEO_RCAR_VIN=m +CONFIG_VIDEO_RENESAS_FDP1=m +CONFIG_VIDEO_RENESAS_JPU=m +CONFIG_VIDEO_RENESAS_VSP1=m +CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC=m +CONFIG_VIDEO_SAMSUNG_EXYNOS4_IS=m +CONFIG_VIDEO_S5P_FIMC=m +CONFIG_VIDEO_S5P_MIPI_CSIS=m +CONFIG_VIDEO_EXYNOS_FIMC_LITE=m +CONFIG_VIDEO_EXYNOS4_FIMC_IS=m +CONFIG_VIDEO_SAMSUNG_S5P_JPEG=m +CONFIG_VIDEO_SAMSUNG_S5P_MFC=m +CONFIG_VIDEO_STI_BDISP=m +CONFIG_VIDEO_STI_DELTA=m +CONFIG_VIDEO_STI_HVA=m +CONFIG_VIDEO_STM32_DCMI=m +CONFIG_VIDEO_STM32_DCMIPP=m +CONFIG_V4L_TEST_DRIVERS=y +CONFIG_VIDEO_VIVID=m +CONFIG_VIDEO_S5C73M3=m +CONFIG_VIDEO_S5K6A3=m +CONFIG_VIDEO_ADV7180=m +CONFIG_VIDEO_ADV7604=m +CONFIG_VIDEO_ADV7604_CEC=y +CONFIG_VIDEO_ML86V7667=m +CONFIG_IMX_IPUV3_CORE=m +CONFIG_DRM=y +CONFIG_DRM_NOUVEAU=m +# CONFIG_DRM_NOUVEAU_CH7006 is not set +# CONFIG_DRM_NOUVEAU_SIL164 is not set +CONFIG_DRM_EXYNOS=m +CONFIG_DRM_EXYNOS_FIMD=y +CONFIG_DRM_EXYNOS_MIXER=y +CONFIG_DRM_EXYNOS_DPI=y +CONFIG_DRM_EXYNOS_DSI=y +CONFIG_DRM_EXYNOS_HDMI=y +CONFIG_DRM_ROCKCHIP=y +CONFIG_ROCKCHIP_ANALOGIX_DP=y +CONFIG_ROCKCHIP_DW_HDMI=y +CONFIG_ROCKCHIP_DW_MIPI_DSI=y +CONFIG_ROCKCHIP_INNO_HDMI=y +CONFIG_ROCKCHIP_RGB=y +CONFIG_DRM_ATMEL_HLCDC=m +CONFIG_DRM_RCAR_DU=m +CONFIG_DRM_SUN4I=m +CONFIG_DRM_OMAP=m +CONFIG_OMAP5_DSS_HDMI=y +CONFIG_DRM_MSM=m +CONFIG_DRM_FSL_DCU=m +CONFIG_DRM_TEGRA=y +CONFIG_DRM_STM=m +CONFIG_DRM_STM_DSI=m +CONFIG_DRM_PANEL_LVDS=m +CONFIG_DRM_PANEL_ORISETECH_OTM8009A=m +CONFIG_DRM_PANEL_RAYDIUM_RM68200=m +CONFIG_DRM_PANEL_SAMSUNG_LD9040=m +CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03=m +CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=m +CONFIG_DRM_PANEL_SHARP_LQ101R1SX01=m +CONFIG_DRM_PANEL_EDP=y +CONFIG_DRM_PANEL_SIMPLE=y +CONFIG_DRM_DISPLAY_CONNECTOR=m +CONFIG_DRM_I2C_NXP_TDA998X=m +CONFIG_DRM_LVDS_CODEC=m +CONFIG_DRM_NXP_PTN3460=m +CONFIG_DRM_PARADE_PS8622=m +CONFIG_DRM_SII902X=m +CONFIG_DRM_SII9234=m +CONFIG_DRM_SIMPLE_BRIDGE=m +CONFIG_DRM_TOSHIBA_TC358764=m +CONFIG_DRM_TOSHIBA_TC358768=m +CONFIG_DRM_TI_TFP410=m +CONFIG_DRM_TI_TPD12S015=m +CONFIG_DRM_I2C_ADV7511=m +CONFIG_DRM_I2C_ADV7511_AUDIO=y +CONFIG_DRM_STI=m +CONFIG_DRM_IMX=m +CONFIG_DRM_IMX_PARALLEL_DISPLAY=m +CONFIG_DRM_IMX_TVE=m +CONFIG_DRM_IMX_LDB=m +CONFIG_DRM_IMX_HDMI=m +CONFIG_DRM_V3D=m +CONFIG_DRM_VC4=m +CONFIG_DRM_ETNAVIV=m +CONFIG_DRM_MXSFB=m +CONFIG_DRM_PL111=m +CONFIG_DRM_LIMA=m +CONFIG_DRM_PANFROST=m +CONFIG_DRM_ASPEED_GFX=m +CONFIG_FB=y +CONFIG_FB_EFI=y +CONFIG_FB_WM8505=y +CONFIG_FB_SIMPLE=y +CONFIG_ROCKCHIP_MULTI_RGA=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_PWM=y +CONFIG_BACKLIGHT_AS3711=y +CONFIG_BACKLIGHT_GPIO=y +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +CONFIG_ROCKCHIP_RKNPU=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_HDA_INPUT_BEEP=y +CONFIG_SND_HDA_PATCH_LOADER=y +CONFIG_SND_HDA_TEGRA=m +CONFIG_SND_HDA_CODEC_REALTEK=m +CONFIG_SND_HDA_CODEC_HDMI=m +CONFIG_SND_USB_AUDIO=m +CONFIG_SND_SOC=y +CONFIG_SND_ATMEL_SOC_WM8904=m +CONFIG_SND_ATMEL_SOC_PDMIC=m +CONFIG_SND_ATMEL_SOC_I2S=m +CONFIG_SND_BCM2835_SOC_I2S=m +CONFIG_SND_IMX_SOC=m +CONFIG_SND_SOC_FSL_ASOC_CARD=m +CONFIG_SND_MMP_SOC_SSPA=m +CONFIG_SND_PXA910_SOC=m +CONFIG_SND_SOC_QCOM=m +CONFIG_SND_SOC_APQ8016_SBC=m +CONFIG_SND_SOC_SH4_FSI=m +CONFIG_SND_SOC_RCAR=m +CONFIG_SND_SOC_ROCKCHIP_I2S_TDM=y +CONFIG_SND_SOC_ROCKCHIP_SPDIF=m +CONFIG_SND_SOC_ROCKCHIP_MAX98090=m +CONFIG_SND_SOC_ROCKCHIP_RT5645=m +CONFIG_SND_SOC_SAMSUNG=m +CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994=m +CONFIG_SND_SOC_SMDK_WM8994_PCM=m +CONFIG_SND_SOC_SNOW=m +CONFIG_SND_SOC_ODROID=m +CONFIG_SND_SOC_ARNDALE=m +CONFIG_SND_SOC_SAMSUNG_MIDAS_WM1811=m +CONFIG_SND_SOC_STI=m +CONFIG_SND_SOC_STM32_SAI=m +CONFIG_SND_SOC_STM32_I2S=m +CONFIG_SND_SOC_STM32_SPDIFRX=m +CONFIG_SND_SOC_STM32_DFSDM=m +CONFIG_SND_SUN4I_CODEC=m +CONFIG_SND_SOC_TEGRA=m +CONFIG_SND_SOC_TEGRA20_I2S=m +CONFIG_SND_SOC_TEGRA20_SPDIF=m +CONFIG_SND_SOC_TEGRA30_I2S=m +CONFIG_SND_SOC_TEGRA_RT5640=m +CONFIG_SND_SOC_TEGRA_WM8753=m +CONFIG_SND_SOC_TEGRA_WM8903=m +CONFIG_SND_SOC_TEGRA_WM9712=m +CONFIG_SND_SOC_TEGRA_TRIMSLICE=m +CONFIG_SND_SOC_TEGRA_ALC5632=m +CONFIG_SND_SOC_TEGRA_MAX98090=m +CONFIG_SND_SOC_DAVINCI_MCASP=m +CONFIG_SND_SOC_AC97_CODEC=m +CONFIG_SND_SOC_AK4642=m +CONFIG_SND_SOC_CPCAP=m +CONFIG_SND_SOC_CS42L51_I2C=m +CONFIG_SND_SOC_MSM8916_WCD_ANALOG=m +CONFIG_SND_SOC_MSM8916_WCD_DIGITAL=m +CONFIG_SND_SOC_RK_DSM=y +CONFIG_SND_SOC_RV1106=y +CONFIG_SND_SOC_SGTL5000=m +CONFIG_SND_SOC_STI_SAS=m +CONFIG_SND_SOC_TLV320AIC32X4_I2C=m +CONFIG_SND_SOC_TLV320AIC3X_I2C=m +CONFIG_SND_SOC_WM8960=m +CONFIG_SND_SOC_WM8962=m +CONFIG_SND_SOC_WM8978=m +CONFIG_SND_SIMPLE_CARD=y +CONFIG_USB=y +CONFIG_USB_OTG=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_MVEBU=y +CONFIG_USB_XHCI_TEGRA=m +CONFIG_USB_BRCMSTB=m +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_FSL=m +CONFIG_USB_EHCI_HCD_STI=y +CONFIG_USB_EHCI_EXYNOS=m +CONFIG_USB_EHCI_MV=m +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_STI=y +CONFIG_USB_OHCI_EXYNOS=m +CONFIG_USB_R8A66597_HCD=m +CONFIG_USB_RENESAS_USBHS=m +CONFIG_USB_STORAGE=y +CONFIG_USB_UAS=m +CONFIG_USB_MUSB_HDRC=m +CONFIG_USB_MUSB_SUNXI=m +CONFIG_USB_MUSB_TUSB6010=m +CONFIG_USB_MUSB_OMAP2PLUS=m +CONFIG_USB_MUSB_DSPS=m +CONFIG_USB_MUSB_UX500=m +CONFIG_USB_UX500_DMA=y +CONFIG_USB_INVENTRA_DMA=y +CONFIG_USB_TI_CPPI41_DMA=y +CONFIG_USB_TUSB_OMAP_DMA=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC2=y +CONFIG_USB_CHIPIDEA=y +CONFIG_USB_CHIPIDEA_UDC=y +CONFIG_USB_CHIPIDEA_HOST=y +CONFIG_USB_ISP1760=y +CONFIG_USB_HSIC_USB3503=y +CONFIG_USB_ONBOARD_DEV=m +CONFIG_AB8500_USB=y +CONFIG_KEYSTONE_USB_PHY=m +CONFIG_NOP_USB_XCEIV=y +CONFIG_AM335X_PHY_USB=m +CONFIG_TWL6030_USB=m +CONFIG_USB_ISP1301=y +CONFIG_USB_MXS_PHY=y +CONFIG_USB_GADGET=y +CONFIG_USB_RENESAS_USBHS_UDC=m +CONFIG_USB_RENESAS_USBF=m +CONFIG_USB_ASPEED_VHUB=m +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_SERIAL=y +CONFIG_USB_CONFIGFS_ACM=y +CONFIG_USB_CONFIGFS_OBEX=y +CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_ECM=y +CONFIG_USB_CONFIGFS_ECM_SUBSET=y +CONFIG_USB_CONFIGFS_RNDIS=y +CONFIG_USB_CONFIGFS_EEM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_LB_SS=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_UAC1=y +CONFIG_USB_CONFIGFS_F_UAC1_LEGACY=y +CONFIG_USB_CONFIGFS_F_UAC2=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_USB_CONFIGFS_F_UVC=y +CONFIG_USB_CONFIGFS_F_PRINTER=y +CONFIG_USB_ETH=m +CONFIG_TYPEC=m +CONFIG_TYPEC_UCSI=m +CONFIG_UCSI_STM32G0=m +CONFIG_TYPEC_STUSB160X=m +CONFIG_MMC=y +CONFIG_MMC_BLOCK_MINORS=16 +CONFIG_MMC_ARMMMCI=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_OF_ARASAN=y +CONFIG_MMC_SDHCI_OF_AT91=y +CONFIG_MMC_SDHCI_OF_ESDHC=y +CONFIG_MMC_SDHCI_ESDHC_IMX=y +CONFIG_MMC_SDHCI_DOVE=y +CONFIG_MMC_SDHCI_TEGRA=y +CONFIG_MMC_SDHCI_S3C=y +CONFIG_MMC_SDHCI_PXAV3=y +CONFIG_MMC_SDHCI_PXAV2=m +CONFIG_MMC_SDHCI_SPEAR=y +CONFIG_MMC_SDHCI_S3C_DMA=y +CONFIG_MMC_SDHCI_BCM_KONA=y +CONFIG_MMC_MESON_MX_SDHC=y +CONFIG_MMC_MESON_MX_SDIO=y +CONFIG_MMC_SDHCI_ST=y +CONFIG_MMC_OMAP=y +CONFIG_MMC_OMAP_HS=y +CONFIG_MMC_ATMELMCI=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_MVSDIO=y +CONFIG_MMC_SDHI=y +CONFIG_MMC_UNIPHIER=y +CONFIG_MMC_DW=y +CONFIG_MMC_DW_EXYNOS=y +CONFIG_MMC_DW_ROCKCHIP=y +CONFIG_MMC_SH_MMCIF=y +CONFIG_MMC_SUNXI=y +CONFIG_MMC_BCM2835=y +CONFIG_MMC_SDHCI_OMAP=y +CONFIG_MMC_OWL=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_CLASS_FLASH=m +CONFIG_LEDS_CPCAP=m +CONFIG_LEDS_PCA9532=m +CONFIG_LEDS_PCA9532_GPIO=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_PWM=y +CONFIG_LEDS_MAX8997=m +CONFIG_LEDS_ACER_A500=m +CONFIG_LEDS_MAX77693=m +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_ONESHOT=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_BACKLIGHT=y +CONFIG_LEDS_TRIGGER_CPU=y +CONFIG_LEDS_TRIGGER_GPIO=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_LEDS_TRIGGER_TRANSIENT=y +CONFIG_LEDS_TRIGGER_CAMERA=y +CONFIG_EDAC=y +CONFIG_EDAC_LAYERSCAPE=y +CONFIG_EDAC_HIGHBANK_MC=y +CONFIG_EDAC_HIGHBANK_L2=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_AC100=y +CONFIG_RTC_DRV_AS3722=y +CONFIG_RTC_DRV_DS1307=y +CONFIG_RTC_DRV_HYM8563=m +CONFIG_RTC_DRV_MAX8907=y +CONFIG_RTC_DRV_MAX8998=m +CONFIG_RTC_DRV_MAX8997=m +CONFIG_RTC_DRV_MAX77686=y +CONFIG_RTC_DRV_RK808=m +CONFIG_RTC_DRV_RS5C372=m +CONFIG_RTC_DRV_PCF85363=m +CONFIG_RTC_DRV_BQ32K=m +CONFIG_RTC_DRV_TWL4030=y +CONFIG_RTC_DRV_PALMAS=y +CONFIG_RTC_DRV_TPS6586X=y +CONFIG_RTC_DRV_TPS65910=y +CONFIG_RTC_DRV_S35390A=m +CONFIG_RTC_DRV_RX8581=m +CONFIG_RTC_DRV_EM3027=y +CONFIG_RTC_DRV_S5M=m +CONFIG_RTC_DRV_PCF85063=m +CONFIG_RTC_DRV_DA9063=m +CONFIG_RTC_DRV_EFI=m +CONFIG_RTC_DRV_ROCKCHIP=y +CONFIG_RTC_DRV_DIGICOLOR=m +CONFIG_RTC_DRV_S3C=m +CONFIG_RTC_DRV_SA1100=m +CONFIG_RTC_DRV_SH=m +CONFIG_RTC_DRV_PL031=y +CONFIG_RTC_DRV_AT91RM9200=m +CONFIG_RTC_DRV_AT91SAM9=m +CONFIG_RTC_DRV_RZN1=m +CONFIG_RTC_DRV_VT8500=y +CONFIG_RTC_DRV_SUNXI=y +CONFIG_RTC_DRV_MV=y +CONFIG_RTC_DRV_PM8XXX=m +CONFIG_RTC_DRV_TEGRA=y +CONFIG_RTC_DRV_ST_LPC=y +CONFIG_RTC_DRV_STM32=y +CONFIG_RTC_DRV_CPCAP=m +CONFIG_RTC_DRV_ASPEED=m +CONFIG_DMADEVICES=y +CONFIG_AT_HDMAC=y +CONFIG_AT_XDMAC=y +CONFIG_DMA_BCM2835=y +CONFIG_DMA_SUN6I=y +CONFIG_FSL_EDMA=y +CONFIG_IMX_DMA=y +CONFIG_IMX_SDMA=y +CONFIG_MV_XOR=y +CONFIG_MXS_DMA=y +CONFIG_OWL_DMA=y +CONFIG_PL330_DMA=y +CONFIG_STE_DMA40=y +CONFIG_ST_FDMA=m +CONFIG_TEGRA20_APB_DMA=y +CONFIG_UNIPHIER_MDMAC=y +CONFIG_XILINX_DMA=y +CONFIG_QCOM_BAM_DMA=y +CONFIG_DW_DMAC=y +CONFIG_RZN1_DMAMUX=m +CONFIG_RCAR_DMAC=y +CONFIG_RENESAS_USB_DMAC=m +CONFIG_STM32_DMA=y +CONFIG_STM32_DMAMUX=y +CONFIG_STM32_MDMA=y +CONFIG_DMABUF_HEAPS=y +CONFIG_DMABUF_HEAPS_SYSTEM=y +CONFIG_DMABUF_HEAPS_CMA=y +CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_MMIO=y +CONFIG_STAGING=y +CONFIG_MFD_NVEC=y +CONFIG_KEYBOARD_NVEC=y +CONFIG_SERIO_NVEC_PS2=y +CONFIG_NVEC_POWER=y +CONFIG_NVEC_PAZ00=y +CONFIG_CHROME_PLATFORMS=y +CONFIG_CROS_EC=m +CONFIG_CROS_EC_I2C=m +CONFIG_CROS_EC_SPI=m +CONFIG_COMMON_CLK_MAX77686=y +CONFIG_COMMON_CLK_RK808=m +CONFIG_COMMON_CLK_SCMI=y +CONFIG_COMMON_CLK_LAN966X=y +CONFIG_COMMON_CLK_S2MPS11=m +CONFIG_CLK_RASPBERRYPI=y +CONFIG_COMMON_CLK_QCOM=y +CONFIG_QCOM_A53PLL=y +CONFIG_QCOM_CLK_APCS_MSM8916=y +CONFIG_QCOM_CLK_RPM=y +CONFIG_QCOM_CLK_SMD_RPM=y +CONFIG_APQ_MMCC_8084=y +CONFIG_MSM_GCC_8660=y +CONFIG_MSM_GCC_8916=y +CONFIG_MSM_MMCC_8960=y +CONFIG_MSM_MMCC_8974=y +CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_OMAP=y +CONFIG_HWSPINLOCK_QCOM=y +CONFIG_OMAP2PLUS_MBOX=y +CONFIG_ROCKCHIP_MBOX=y +CONFIG_BCM2835_MBOX=y +CONFIG_TI_MESSAGE_MANAGER=y +CONFIG_QCOM_APCS_IPC=y +CONFIG_STM32_IPCC=m +CONFIG_QCOM_IPCC=y +CONFIG_QCOM_IOMMU=y +CONFIG_OMAP_IOMMU=y +CONFIG_OMAP_IOMMU_DEBUG=y +CONFIG_ROCKCHIP_IOMMU=y +CONFIG_TEGRA_IOMMU_SMMU=y +CONFIG_EXYNOS_IOMMU=y +CONFIG_REMOTEPROC=y +CONFIG_OMAP_REMOTEPROC=m +CONFIG_OMAP_REMOTEPROC_WATCHDOG=y +CONFIG_KEYSTONE_REMOTEPROC=m +CONFIG_QCOM_Q6V5_MSS=m +CONFIG_QCOM_SYSMON=m +CONFIG_QCOM_WCNSS_PIL=m +CONFIG_ST_REMOTEPROC=m +CONFIG_RPMSG_CHAR=m +CONFIG_RPMSG_CTRL=m +CONFIG_RPMSG_QCOM_SMD=y +CONFIG_RPMSG_VIRTIO=m +CONFIG_ASPEED_LPC_CTRL=m +CONFIG_ASPEED_LPC_SNOOP=m +CONFIG_ASPEED_P2A_CTRL=m +CONFIG_QCOM_COMMAND_DB=m +CONFIG_QCOM_GSBI=y +CONFIG_QCOM_OCMEM=m +CONFIG_QCOM_RMTFS_MEM=m +CONFIG_QCOM_RPMH=m +CONFIG_QCOM_SMEM=y +CONFIG_QCOM_SMD_RPM=y +CONFIG_QCOM_SMP2P=y +CONFIG_QCOM_SMSM=y +CONFIG_QCOM_SOCINFO=m +CONFIG_QCOM_STATS=m +CONFIG_QCOM_WCNSS_CTRL=m +CONFIG_ROCKCHIP_IODOMAIN=y +CONFIG_ROCKCHIP_PVTM=y +CONFIG_ARCH_TEGRA_2x_SOC=y +CONFIG_ARCH_TEGRA_3x_SOC=y +CONFIG_ARCH_TEGRA_114_SOC=y +CONFIG_ARCH_TEGRA_124_SOC=y +CONFIG_SOC_TI=y +CONFIG_KEYSTONE_NAVIGATOR_QMSS=y +CONFIG_KEYSTONE_NAVIGATOR_DMA=y +CONFIG_RASPBERRYPI_POWER=y +CONFIG_QCOM_CPR=y +CONFIG_QCOM_RPMHPD=m +CONFIG_QCOM_RPMPD=y +CONFIG_TI_SCI_PM_DOMAINS=y +CONFIG_ARM_EXYNOS_BUS_DEVFREQ=m +CONFIG_ARM_TEGRA_DEVFREQ=m +CONFIG_DEVFREQ_EVENT_EXYNOS_NOCP=m +CONFIG_EXTCON_MAX14577=m +CONFIG_EXTCON_MAX77693=m +CONFIG_EXTCON_MAX8997=m +CONFIG_EXTCON_USB_GPIO=y +CONFIG_TI_AEMIF=y +CONFIG_STM32_FMC2_EBI=y +CONFIG_EXYNOS5422_DMC=m +CONFIG_IIO=y +CONFIG_IIO_SW_TRIGGER=y +CONFIG_IIO_ST_ACCEL_3AXIS=m +# CONFIG_IIO_ST_ACCEL_SPI_3AXIS is not set +CONFIG_ASPEED_ADC=m +CONFIG_AT91_ADC=m +CONFIG_AT91_SAMA5D2_ADC=m +CONFIG_BERLIN2_ADC=m +CONFIG_CPCAP_ADC=m +CONFIG_EXYNOS_ADC=m +CONFIG_MESON_SARADC=m +CONFIG_QCOM_SPMI_VADC=m +CONFIG_ROCKCHIP_SARADC=y +CONFIG_STM32_ADC_CORE=m +CONFIG_STM32_ADC=m +CONFIG_STM32_DFSDM_ADC=m +CONFIG_STMPE_ADC=m +CONFIG_VF610_ADC=m +CONFIG_XILINX_XADC=y +CONFIG_IIO_CROS_EC_SENSORS_CORE=m +CONFIG_IIO_CROS_EC_SENSORS=m +CONFIG_STM32_DAC=m +CONFIG_MPU3050_I2C=y +CONFIG_IIO_ST_GYRO_3AXIS=m +CONFIG_CM36651=m +CONFIG_IIO_CROS_EC_LIGHT_PROX=m +CONFIG_SENSORS_ISL29018=y +CONFIG_SENSORS_ISL29028=y +CONFIG_AK8975=y +CONFIG_IIO_HRTIMER_TRIGGER=y +CONFIG_IIO_STM32_LPTIMER_TRIGGER=m +CONFIG_PWM=y +CONFIG_PWM_ATMEL=m +CONFIG_PWM_ATMEL_HLCDC_PWM=m +CONFIG_PWM_ATMEL_TCB=m +CONFIG_PWM_BCM2835=y +CONFIG_PWM_BRCMSTB=m +CONFIG_PWM_FSL_FTM=m +CONFIG_PWM_MESON=m +CONFIG_PWM_RENESAS_RCAR=m +CONFIG_PWM_RENESAS_TPU=y +CONFIG_PWM_ROCKCHIP=y +CONFIG_PWM_SAMSUNG=m +CONFIG_PWM_STI=y +CONFIG_PWM_STM32=m +CONFIG_PWM_STM32_LP=m +CONFIG_PWM_SUN4I=y +CONFIG_PWM_TEGRA=y +CONFIG_PWM_TIECAP=m +CONFIG_PWM_VT8500=y +CONFIG_KEYSTONE_IRQ=y +CONFIG_RESET_MCHP_SPARX5=y +CONFIG_RESET_TI_SCI=m +CONFIG_RESET_TI_SYSCON=m +CONFIG_PHY_SUN4I_USB=y +CONFIG_PHY_SUN9I_USB=y +CONFIG_PHY_BRCM_USB=m +CONFIG_PHY_HIX5HD2_SATA=y +CONFIG_PHY_BERLIN_SATA=y +CONFIG_PHY_BERLIN_USB=y +CONFIG_PHY_MMP3_USB=m +CONFIG_PHY_LAN966X_SERDES=m +CONFIG_PHY_CPCAP_USB=m +CONFIG_PHY_QCOM_APQ8064_SATA=m +CONFIG_PHY_QCOM_USB_HS=y +CONFIG_PHY_RCAR_GEN2=m +CONFIG_PHY_ROCKCHIP_DP=m +CONFIG_PHY_ROCKCHIP_INNO_USB2=y +CONFIG_PHY_ROCKCHIP_USB=y +CONFIG_PHY_EXYNOS_DP_VIDEO=m +CONFIG_PHY_EXYNOS_MIPI_VIDEO=m +CONFIG_PHY_SAMSUNG_USB2=m +CONFIG_PHY_EXYNOS5250_SATA=m +CONFIG_PHY_UNIPHIER_USB2=y +CONFIG_PHY_UNIPHIER_USB3=y +CONFIG_PHY_MIPHY28LP=y +CONFIG_PHY_STIH407_USB=y +CONFIG_PHY_STM32_USBPHYC=y +CONFIG_PHY_TEGRA_XUSB=y +CONFIG_PHY_DM816X_USB=m +CONFIG_OMAP_USB2=y +CONFIG_TI_PIPE3=y +CONFIG_TWL4030_USB=m +CONFIG_RAS=y +CONFIG_NVMEM_IMX_OCOTP=y +CONFIG_NVMEM_MESON_MX_EFUSE=m +CONFIG_NVMEM_QCOM_QFPROM=y +CONFIG_NVMEM_RMEM=m +CONFIG_NVMEM_ROCKCHIP_EFUSE=m +CONFIG_NVMEM_ROCKCHIP_OTP=y +CONFIG_NVMEM_STM32_ROMEM=m +CONFIG_NVMEM_SUNXI_SID=y +CONFIG_NVMEM_VF610_OCOTP=y +CONFIG_FSI=m +CONFIG_FSI_MASTER_GPIO=m +CONFIG_FSI_MASTER_HUB=m +CONFIG_FSI_MASTER_ASPEED=m +CONFIG_FSI_SCOM=m +CONFIG_FSI_SBEFIFO=m +CONFIG_FSI_OCC=m +CONFIG_TEE=y +CONFIG_OPTEE=y +CONFIG_INTERCONNECT_QCOM=y +CONFIG_INTERCONNECT_QCOM_MSM8916=y +CONFIG_COUNTER=m +CONFIG_STM32_LPTIMER_CNT=m +CONFIG_STM32_TIMER_CNT=m +CONFIG_EXT4_FS=y +CONFIG_AUTOFS_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_NTFS_FS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_UBIFS_FS=y +CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_LZO=y +CONFIG_SQUASHFS_XZ=y +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_PMSG=y +CONFIG_PSTORE_RAM=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_V4_1=y +CONFIG_NFS_V4_2=y +CONFIG_ROOT_NFS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_UTF8=y +CONFIG_CRYPTO_USER=m +CONFIG_CRYPTO_ARC4=y +CONFIG_CRYPTO_CCM=y +CONFIG_CRYPTO_USER_API_HASH=m +CONFIG_CRYPTO_USER_API_SKCIPHER=m +CONFIG_CRYPTO_USER_API_RNG=m +CONFIG_CRYPTO_USER_API_AEAD=m +CONFIG_CRYPTO_GHASH_ARM_CE=m +CONFIG_CRYPTO_AES_ARM=y +CONFIG_CRYPTO_AES_ARM_BS=m +CONFIG_CRYPTO_AES_ARM_CE=m +CONFIG_CRYPTO_DEV_SUN4I_SS=m +CONFIG_CRYPTO_DEV_FSL_CAAM=m +CONFIG_CRYPTO_DEV_EXYNOS_RNG=m +CONFIG_CRYPTO_DEV_S5P=m +CONFIG_CRYPTO_DEV_ATMEL_AES=m +CONFIG_CRYPTO_DEV_ATMEL_TDES=m +CONFIG_CRYPTO_DEV_ATMEL_SHA=m +CONFIG_CRYPTO_DEV_MARVELL_CESA=m +CONFIG_CRYPTO_DEV_QCE=m +CONFIG_CRYPTO_DEV_QCOM_RNG=m +CONFIG_CRYPTO_DEV_ROCKCHIP=m +CONFIG_CRYPTO_DEV_STM32_HASH=m +CONFIG_CRYPTO_DEV_STM32_CRYP=m +CONFIG_CMA_SIZE_MBYTES=64 +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y +CONFIG_DEBUG_INFO_REDUCED=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_LL=y +CONFIG_DEBUG_LL_UART_8250=y +CONFIG_DEBUG_UART_PHYS=0xff4c0000 +CONFIG_DEBUG_UART_VIRT=0xff4c0000 +CONFIG_DEBUG_UART_8250_WORD=y +CONFIG_EARLY_PRINTK=y diff --git a/patches/05-build-wiring.patch b/patches/05-build-wiring.patch new file mode 100644 index 0000000..2fb0cbd --- /dev/null +++ b/patches/05-build-wiring.patch @@ -0,0 +1,28 @@ +diff --git a/drivers/Kconfig b/drivers/Kconfig +index 4915a6386..f6d41eb71 100644 +--- a/drivers/Kconfig ++++ b/drivers/Kconfig +@@ -113,6 +113,8 @@ source "drivers/video/Kconfig" + + source "drivers/accel/Kconfig" + ++source "drivers/rknpu/Kconfig" ++ + source "sound/Kconfig" + + source "drivers/hid/Kconfig" +diff --git a/drivers/Makefile b/drivers/Makefile +index 8e1ffa435..82ed17463 100644 +--- a/drivers/Makefile ++++ b/drivers/Makefile +@@ -67,6 +67,10 @@ obj-y += iommu/ + # gpu/ comes after char for AGP vs DRM startup and after iommu + obj-y += gpu/ + ++# rknpu registers a classic DRM device (not drivers/accel/) -- must come ++# after gpu/ for the same reason (DRM core needs to be ready first). ++obj-$(CONFIG_ROCKCHIP_RKNPU) += rknpu/ ++ + obj-$(CONFIG_CONNECTOR) += connector/ + + # i810fb depends on char/agp/ diff --git a/patches/10-clk-rv1106.patch b/patches/10-clk-rv1106.patch new file mode 100644 index 0000000..342c04f --- /dev/null +++ b/patches/10-clk-rv1106.patch @@ -0,0 +1,1404 @@ +diff --git a/drivers/clk/rockchip/Kconfig b/drivers/clk/rockchip/Kconfig +index febb7944f..31d10e032 100644 +--- a/drivers/clk/rockchip/Kconfig ++++ b/drivers/clk/rockchip/Kconfig +@@ -30,6 +30,13 @@ config CLK_RV1126 + help + Build the driver for RV1126 Clock Driver. + ++config CLK_RV1106 ++ bool "Rockchip RV1106 clock controller support" ++ depends on ARM || COMPILE_TEST ++ default y ++ help ++ Build the driver for RV1106 Clock Driver. ++ + config CLK_RK3036 + bool "Rockchip RK3036 clock controller support" + depends on ARM || COMPILE_TEST +diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile +index c281a9738..1d9e81ee8 100644 +--- a/drivers/clk/rockchip/Makefile ++++ b/drivers/clk/rockchip/Makefile +@@ -20,6 +20,7 @@ clk-rockchip-$(CONFIG_RESET_CONTROLLER) += softrst.o + obj-$(CONFIG_CLK_PX30) += clk-px30.o + obj-$(CONFIG_CLK_RV110X) += clk-rv1108.o + obj-$(CONFIG_CLK_RV1126) += clk-rv1126.o ++obj-$(CONFIG_CLK_RV1106) += clk-rv1106.o + obj-$(CONFIG_CLK_RK3036) += clk-rk3036.o + obj-$(CONFIG_CLK_RK312X) += clk-rk3128.o + obj-$(CONFIG_CLK_RK3188) += clk-rk3188.o +diff --git a/drivers/clk/rockchip/clk-rv1106.c b/drivers/clk/rockchip/clk-rv1106.c +new file mode 100644 +index 000000000..b44eeeadd +--- /dev/null ++++ b/drivers/clk/rockchip/clk-rv1106.c +@@ -0,0 +1,1299 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (c) 2022 Rockchip Electronics Co. Ltd. ++ * Author: Elaine Zhang ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "clk.h" ++ ++/* PORT(6.18): Rockchip downstream-only frac-divider flag; mainline has no ++ * min/max-limit opt-out, so map to 0 (default limit). PORT-VERIFY: UART frac ++ * baud accuracy on the 6 clk_uart*_frac clocks. */ ++#ifndef CLK_FRAC_DIVIDER_NO_LIMIT ++#define CLK_FRAC_DIVIDER_NO_LIMIT 0 ++#endif ++ ++#define CRU_PVTPLL0_CON0_L 0x11000 ++#define CRU_PVTPLL0_CON0_H 0x11004 ++#define CRU_PVTPLL0_CON1_L 0x11008 ++#define CRU_PVTPLL0_CON1_H 0x1100c ++#define CRU_PVTPLL0_CON2_L 0x11010 ++#define CRU_PVTPLL0_CON2_H 0x11014 ++#define CRU_PVTPLL0_CON3_L 0x11018 ++#define CRU_PVTPLL0_CON3_H 0x1101c ++#define CRU_PVTPLL0_OSC_CNT 0x11020 ++#define CRU_PVTPLL0_OSC_CNT_AVG 0x11024 ++ ++#define CRU_PVTPLL1_CON0_L 0x11030 ++#define CRU_PVTPLL1_CON0_H 0x11034 ++#define CRU_PVTPLL1_CON1_L 0x11038 ++#define CRU_PVTPLL1_CON1_H 0x1103c ++#define CRU_PVTPLL1_CON2_L 0x11040 ++#define CRU_PVTPLL1_CON2_H 0x11044 ++#define CRU_PVTPLL1_CON3_L 0x11048 ++#define CRU_PVTPLL1_CON3_H 0x1104c ++#define CRU_PVTPLL1_OSC_CNT 0x11050 ++#define CRU_PVTPLL1_OSC_CNT_AVG 0x11054 ++ ++#define RV1106_GRF_SOC_STATUS0 0x10 ++#define CPU_PVTPLL_CON0_L 0x40000 ++#define CPU_PVTPLL_CON0_H 0x40004 ++#define CPU_PVTPLL_CON1 0x40008 ++#define CPU_PVTPLL_CON2 0x4000c ++#define CPU_PVTPLL_CON3 0x40010 ++#define CPU_PVTPLL_OSC_CNT 0x40018 ++#define CPU_PVTPLL_OSC_CNT_AVG 0x4001c ++ ++#define PVTPLL_RING_SEL_MASK 0x7 ++#define PVTPLL_RING_SEL_SHIFT 8 ++#define PVTPLL_EN_MASK 0x3 ++#define PVTPLL_EN_SHIFT 0 ++#define PVTPLL_LENGTH_SEL_MASK 0x7f ++#define PVTPLL_LENGTH_SEL_SHIFT 0 ++ ++#define CPU_CLK_PATH_BASE (0x18300) ++#define CPU_PVTPLL_PATH_CORE ((1 << 12) | (1 << 28)) ++ ++#define RV1106_FRAC_MAX_PRATE 1200000000 ++ ++enum rv1106_plls { ++ apll, dpll, cpll, gpll, ++}; ++ ++static struct rockchip_pll_rate_table rv1106_pll_rates[] = { ++ /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */ ++ RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0), ++ RK3036_PLL_RATE(1600000000, 3, 200, 1, 1, 1, 0), ++ RK3036_PLL_RATE(1584000000, 1, 132, 2, 1, 1, 0), ++ RK3036_PLL_RATE(1560000000, 1, 130, 2, 1, 1, 0), ++ RK3036_PLL_RATE(1536000000, 1, 128, 2, 1, 1, 0), ++ RK3036_PLL_RATE(1512000000, 1, 126, 2, 1, 1, 0), ++ RK3036_PLL_RATE(1488000000, 1, 124, 2, 1, 1, 0), ++ RK3036_PLL_RATE(1464000000, 1, 122, 2, 1, 1, 0), ++ RK3036_PLL_RATE(1440000000, 1, 120, 2, 1, 1, 0), ++ RK3036_PLL_RATE(1416000000, 1, 118, 2, 1, 1, 0), ++ RK3036_PLL_RATE(1400000000, 3, 350, 2, 1, 1, 0), ++ RK3036_PLL_RATE(1392000000, 1, 116, 2, 1, 1, 0), ++ RK3036_PLL_RATE(1368000000, 1, 114, 2, 1, 1, 0), ++ RK3036_PLL_RATE(1344000000, 1, 112, 2, 1, 1, 0), ++ RK3036_PLL_RATE(1320000000, 1, 110, 2, 1, 1, 0), ++ RK3036_PLL_RATE(1296000000, 1, 108, 2, 1, 1, 0), ++ RK3036_PLL_RATE(1272000000, 1, 106, 2, 1, 1, 0), ++ RK3036_PLL_RATE(1248000000, 1, 104, 2, 1, 1, 0), ++ RK3036_PLL_RATE(1200000000, 1, 100, 2, 1, 1, 0), ++ RK3036_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0), ++ RK3036_PLL_RATE(1104000000, 1, 92, 2, 1, 1, 0), ++ RK3036_PLL_RATE(1100000000, 3, 275, 2, 1, 1, 0), ++ RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0), ++ RK3036_PLL_RATE(1000000000, 3, 250, 2, 1, 1, 0), ++ RK3036_PLL_RATE(993484800, 1, 124, 3, 1, 0, 3113851), ++ RK3036_PLL_RATE(984000000, 1, 82, 2, 1, 1, 0), ++ RK3036_PLL_RATE(983040000, 1, 81, 2, 1, 0, 15435038), ++ RK3036_PLL_RATE(960000000, 1, 80, 2, 1, 1, 0), ++ RK3036_PLL_RATE(936000000, 1, 78, 2, 1, 1, 0), ++ RK3036_PLL_RATE(912000000, 1, 76, 2, 1, 1, 0), ++ RK3036_PLL_RATE(900000000, 1, 75, 2, 1, 1, 0), ++ RK3036_PLL_RATE(888000000, 1, 74, 2, 1, 1, 0), ++ RK3036_PLL_RATE(864000000, 1, 72, 2, 1, 1, 0), ++ RK3036_PLL_RATE(840000000, 1, 70, 2, 1, 1, 0), ++ RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0), ++ RK3036_PLL_RATE(800000000, 3, 200, 2, 1, 1, 0), ++ RK3036_PLL_RATE(700000000, 3, 350, 4, 1, 1, 0), ++ RK3036_PLL_RATE(696000000, 1, 116, 4, 1, 1, 0), ++ RK3036_PLL_RATE(624000000, 1, 104, 4, 1, 1, 0), ++ RK3036_PLL_RATE(600000000, 1, 100, 4, 1, 1, 0), ++ RK3036_PLL_RATE(594000000, 1, 99, 4, 1, 1, 0), ++ RK3036_PLL_RATE(504000000, 1, 84, 4, 1, 1, 0), ++ RK3036_PLL_RATE(500000000, 1, 125, 6, 1, 1, 0), ++ RK3036_PLL_RATE(496742400, 1, 124, 6, 1, 0, 3113851), ++ RK3036_PLL_RATE(491520000, 1, 40, 2, 1, 0, 16106127), ++ RK3036_PLL_RATE(408000000, 1, 68, 2, 2, 1, 0), ++ RK3036_PLL_RATE(312000000, 1, 78, 6, 1, 1, 0), ++ RK3036_PLL_RATE(216000000, 1, 72, 4, 2, 1, 0), ++ RK3036_PLL_RATE(96000000, 1, 96, 6, 4, 1, 0), ++ { /* sentinel */ }, ++}; ++ ++#define RV1106_DIV_ACLK_CORE_MASK 0x1f ++#define RV1106_DIV_ACLK_CORE_SHIFT 7 ++#define RV1106_DIV_PCLK_DBG_MASK 0x1f ++#define RV1106_DIV_PCLK_DBG_SHIFT 0 ++#define RV1106_CORE_SEL_MASK 0x3 ++#define RV1106_CORE_SEL_SHIFT 5 ++#define RV1106_ALT_DIV_MASK 0x1f ++#define RV1106_ALT_DIV_SHIFT 0 ++ ++#define RV1106_CLKSEL0(_aclk_core) \ ++{ \ ++ .reg = RV1106_CORECLKSEL_CON(0), \ ++ .val = HIWORD_UPDATE(_aclk_core, RV1106_DIV_ACLK_CORE_MASK, \ ++ RV1106_DIV_ACLK_CORE_SHIFT), \ ++} ++ ++#define RV1106_CLKSEL1(_pclk_dbg) \ ++{ \ ++ .reg = RV1106_CORECLKSEL_CON(1), \ ++ .val = HIWORD_UPDATE(_pclk_dbg, RV1106_DIV_PCLK_DBG_MASK, \ ++ RV1106_DIV_PCLK_DBG_SHIFT), \ ++} ++ ++#define RV1106_CLKSEL2(_is_pvtpll) \ ++{ \ ++ .reg = RV1106_CORECLKSEL_CON(0), \ ++ .val = HIWORD_UPDATE(_is_pvtpll, RV1106_CORE_SEL_MASK, \ ++ RV1106_CORE_SEL_SHIFT), \ ++} ++ ++#define RV1106_CLKSEL3(_alt_div) \ ++{ \ ++ .reg = RV1106_CORECLKSEL_CON(0), \ ++ .val = HIWORD_UPDATE(_alt_div, RV1106_ALT_DIV_MASK, \ ++ RV1106_ALT_DIV_SHIFT), \ ++} ++ ++#define RV1106_CPUCLK_RATE(_prate, _aclk_core, _pclk_dbg, _is_pvtpll) \ ++{ \ ++ .prate = _prate, \ ++ .divs = { \ ++ RV1106_CLKSEL0(_aclk_core), \ ++ RV1106_CLKSEL1(_pclk_dbg), \ ++ }, \ ++ .pre_muxs = { \ ++ RV1106_CLKSEL3(1), \ ++ RV1106_CLKSEL2(2), \ ++ }, \ ++ .post_muxs = { \ ++ RV1106_CLKSEL2(_is_pvtpll), \ ++ RV1106_CLKSEL3(0), \ ++ }, \ ++} ++ ++static struct rockchip_cpuclk_rate_table rv1106_cpuclk_rates[] __initdata = { ++ RV1106_CPUCLK_RATE(1608000000, 3, 7, 1), ++ RV1106_CPUCLK_RATE(1584000000, 3, 7, 1), ++ RV1106_CPUCLK_RATE(1560000000, 3, 7, 1), ++ RV1106_CPUCLK_RATE(1536000000, 3, 7, 1), ++ RV1106_CPUCLK_RATE(1512000000, 3, 7, 1), ++ RV1106_CPUCLK_RATE(1488000000, 2, 5, 1), ++ RV1106_CPUCLK_RATE(1464000000, 2, 5, 1), ++ RV1106_CPUCLK_RATE(1440000000, 2, 5, 1), ++ RV1106_CPUCLK_RATE(1416000000, 2, 5, 1), ++ RV1106_CPUCLK_RATE(1392000000, 2, 5, 1), ++ RV1106_CPUCLK_RATE(1368000000, 2, 5, 1), ++ RV1106_CPUCLK_RATE(1344000000, 2, 5, 1), ++ RV1106_CPUCLK_RATE(1320000000, 2, 5, 1), ++ RV1106_CPUCLK_RATE(1296000000, 2, 5, 1), ++ RV1106_CPUCLK_RATE(1272000000, 2, 5, 1), ++ RV1106_CPUCLK_RATE(1248000000, 2, 5, 1), ++ RV1106_CPUCLK_RATE(1224000000, 2, 5, 1), ++ RV1106_CPUCLK_RATE(1200000000, 2, 5, 1), ++ RV1106_CPUCLK_RATE(1104000000, 2, 5, 1), ++ RV1106_CPUCLK_RATE(1096000000, 2, 5, 1), ++ RV1106_CPUCLK_RATE(1008000000, 1, 5, 1), ++ RV1106_CPUCLK_RATE(912000000, 1, 5, 1), ++ RV1106_CPUCLK_RATE(816000000, 1, 3, 1), ++ RV1106_CPUCLK_RATE(696000000, 1, 3, 0), ++ RV1106_CPUCLK_RATE(600000000, 1, 3, 0), ++ RV1106_CPUCLK_RATE(408000000, 1, 1, 0), ++ RV1106_CPUCLK_RATE(312000000, 1, 1, 0), ++ RV1106_CPUCLK_RATE(216000000, 1, 1, 0), ++ RV1106_CPUCLK_RATE(96000000, 1, 1, 0), ++}; ++ ++static const struct rockchip_cpuclk_reg_data rv1106_cpuclk_data = { ++ .core_reg[0] = RV1106_CORECLKSEL_CON(0), ++ .div_core_shift[0] = 0, ++ .div_core_mask[0] = 0x1f, ++ .num_cores = 1, ++ .mux_core_alt = 2, ++ .mux_core_main = 2, ++ .mux_core_shift = 5, ++ .mux_core_mask = 0x3, ++}; ++ ++PNAME(mux_pll_p) = { "xin24m" }; ++PNAME(mux_24m_32k_p) = { "xin24m", "clk_rtc_32k" }; ++PNAME(mux_gpll_cpll_p) = { "gpll", "cpll" }; ++PNAME(mux_gpll_24m_p) = { "gpll", "xin24m" }; ++/* PORT-VERIFY(6.18): armclk mux inputs vs RV1106 CORECLKSEL_CON TRM field; index 2 = apll = cpuclk_data.mux_core_main */ ++PNAME(mux_armclk_p) = { "gpll", "cpll", "apll" }; ++PNAME(mux_100m_50m_24m_p) = { "clk_100m_src", "clk_50m_src", "xin24m" }; ++PNAME(mux_150m_100m_50m_24m_p) = { "clk_150m_src", "clk_100m_src", "clk_50m_src", "xin24m" }; ++PNAME(mux_500m_300m_100m_24m_p) = { "clk_500m_src", "clk_300m_src", "clk_100m_src", "xin24m" }; ++PNAME(mux_400m_300m_pvtpll0_pvtpll1_p) = { "clk_400m_src", "clk_300m_src", "clk_pvtpll_0", "clk_pvtpll_1" }; ++PNAME(mux_500m_300m_pvtpll0_pvtpll1_p) = { "clk_500m_src", "clk_300m_src", "clk_pvtpll_0", "clk_pvtpll_1" }; ++PNAME(mux_339m_200m_pvtpll0_pvtpll1_p) = { "clk_339m_src", "clk_200m_src", "clk_pvtpll_0", "clk_pvtpll_1" }; ++PNAME(mux_400m_200m_100m_24m_p) = { "clk_400m_src", "clk_200m_src", "clk_100m_src", "xin24m" }; ++PNAME(mux_200m_100m_50m_24m_p) = { "clk_200m_src", "clk_100m_src", "clk_50m_src", "xin24m" }; ++PNAME(mux_300m_200m_100m_24m_p) = { "clk_300m_src", "clk_200m_src", "clk_100m_src", "xin24m" }; ++PNAME(mux_500m_300m_200m_24m_p) = { "clk_500m_src", "clk_300m_src", "clk_200m_src", "xin24m" }; ++PNAME(mux_50m_24m_p) = { "clk_50m_src", "xin24m" }; ++PNAME(mux_400m_24m_p) = { "clk_400m_src", "xin24m" }; ++PNAME(clk_rtc32k_pmu_p) = { "clk_rtc32k_frac", "xin32k", "clk_pvtm_32k" }; ++PNAME(mux_200m_100m_24m_32k_p) = { "clk_200m_src", "clk_100m_src", "xin24m", "clk_rtc_32k" }; ++PNAME(mux_100m_pmu_24m_p) = { "clk_100m_pmu", "xin24m" }; ++PNAME(mux_200m_100m_24m_p) = { "clk_200m_src", "clk_100m_pmu", "xin24m" }; ++PNAME(mux_339m_200m_100m_24m_p) = { "clk_339m_src", "clk_200m_src", "clk_100m_pmu", "xin24m" }; ++PNAME(mux_dpll_300m_p) = { "dpll", "clk_300m_src" }; ++PNAME(clk_i2s0_8ch_tx_p) = { "clk_i2s0_8ch_tx_src", "clk_i2s0_8ch_tx_frac", "i2s0_mclkin", "xin_osc0_half" }; ++PNAME(clk_i2s0_8ch_rx_p) = { "clk_i2s0_8ch_rx_src", "clk_i2s0_8ch_rx_frac", "i2s0_mclkin", "xin_osc0_half" }; ++PNAME(i2s0_8ch_mclkout_p) = { "mclk_i2s0_8ch_tx", "mclk_i2s0_8ch_rx", "xin_osc0_half" }; ++PNAME(clk_ref_mipi0_p) = { "clk_ref_mipi0_src", "clk_ref_mipi0_frac", "xin24m" }; ++PNAME(clk_ref_mipi1_p) = { "clk_ref_mipi1_src", "clk_ref_mipi1_frac", "xin24m" }; ++PNAME(clk_uart0_p) = { "clk_uart0_src", "clk_uart0_frac", "xin24m" }; ++PNAME(clk_uart1_p) = { "clk_uart1_src", "clk_uart1_frac", "xin24m" }; ++PNAME(clk_uart2_p) = { "clk_uart2_src", "clk_uart2_frac", "xin24m" }; ++PNAME(clk_uart3_p) = { "clk_uart3_src", "clk_uart3_frac", "xin24m" }; ++PNAME(clk_uart4_p) = { "clk_uart4_src", "clk_uart4_frac", "xin24m" }; ++PNAME(clk_uart5_p) = { "clk_uart5_src", "clk_uart5_frac", "xin24m" }; ++PNAME(clk_vicap_m0_p) = { "clk_vicap_m0_src", "clk_vicap_m0_frac", "xin24m" }; ++PNAME(clk_vicap_m1_p) = { "clk_vicap_m1_src", "clk_vicap_m1_frac", "xin24m" }; ++ ++static struct rockchip_pll_clock rv1106_pll_clks[] __initdata = { ++ [apll] = PLL(pll_rk3328, PLL_APLL, "apll", mux_pll_p, ++ CLK_IGNORE_UNUSED, RV1106_PLL_CON(0), ++ RV1106_MODE_CON, 0, 10, 0, rv1106_pll_rates), ++ [cpll] = PLL(pll_rk3328, PLL_CPLL, "cpll", mux_pll_p, ++ 0, RV1106_PLL_CON(8), ++ RV1106_MODE_CON, 2, 10, 0, rv1106_pll_rates), ++ [dpll] = PLL(pll_rk3328, PLL_DPLL, "dpll", mux_pll_p, ++ CLK_IGNORE_UNUSED, RV1106_PLL_CON(16), ++ RV1106_SUBDDRMODE_CON, 0, 10, 0, NULL), ++ [gpll] = PLL(pll_rk3328, PLL_GPLL, "gpll", mux_pll_p, ++ 0, RV1106_PLL_CON(24), ++ RV1106_MODE_CON, 4, 10, 0, rv1106_pll_rates), ++}; ++ ++#define MFLAGS CLK_MUX_HIWORD_MASK ++#define DFLAGS CLK_DIVIDER_HIWORD_MASK ++#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE) ++ ++static struct rockchip_clk_branch rv1106_rtc32k_pmu_fracmux __initdata = ++ MUX(CLK_RTC_32K, "clk_rtc_32k", clk_rtc32k_pmu_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, ++ RV1106_PMUCLKSEL_CON(0), 6, 2, MFLAGS); ++ ++static struct rockchip_clk_branch rv1106_i2s0_8ch_tx_fracmux __initdata = ++ MUX(CLK_I2S0_8CH_TX, "clk_i2s0_8ch_tx", clk_i2s0_8ch_tx_p, CLK_SET_RATE_PARENT, ++ RV1106_CLKSEL_CON(19), 0, 2, MFLAGS); ++ ++static struct rockchip_clk_branch rv1106_i2s0_8ch_rx_fracmux __initdata = ++ MUX(CLK_I2S0_8CH_RX, "clk_i2s0_8ch_rx", clk_i2s0_8ch_rx_p, CLK_SET_RATE_PARENT, ++ RV1106_CLKSEL_CON(21), 0, 2, MFLAGS); ++ ++static struct rockchip_clk_branch rv1106_clk_ref_mipi0_fracmux __initdata = ++ MUX(CLK_REF_MIPI0, "clk_ref_mipi0", clk_ref_mipi0_p, CLK_SET_RATE_PARENT, ++ RV1106_CLKSEL_CON(27), 0, 2, MFLAGS); ++ ++static struct rockchip_clk_branch rv1106_clk_ref_mipi1_fracmux __initdata = ++ MUX(CLK_REF_MIPI1, "clk_ref_mipi1", clk_ref_mipi1_p, CLK_SET_RATE_PARENT, ++ RV1106_CLKSEL_CON(29), 0, 2, MFLAGS); ++ ++static struct rockchip_clk_branch rv1106_clk_uart0_fracmux __initdata = ++ MUX(CLK_UART0, "clk_uart0", clk_uart0_p, CLK_SET_RATE_PARENT, ++ RV1106_CLKSEL_CON(7), 0, 2, MFLAGS); ++ ++static struct rockchip_clk_branch rv1106_clk_uart1_fracmux __initdata = ++ MUX(CLK_UART1, "clk_uart1", clk_uart1_p, CLK_SET_RATE_PARENT, ++ RV1106_CLKSEL_CON(9), 0, 2, MFLAGS); ++ ++static struct rockchip_clk_branch rv1106_clk_uart2_fracmux __initdata = ++ MUX(CLK_UART2, "clk_uart2", clk_uart2_p, CLK_SET_RATE_PARENT, ++ RV1106_CLKSEL_CON(11), 0, 2, MFLAGS); ++ ++static struct rockchip_clk_branch rv1106_clk_uart3_fracmux __initdata = ++ MUX(CLK_UART3, "clk_uart3", clk_uart3_p, CLK_SET_RATE_PARENT, ++ RV1106_CLKSEL_CON(13), 0, 2, MFLAGS); ++ ++static struct rockchip_clk_branch rv1106_clk_uart4_fracmux __initdata = ++ MUX(CLK_UART4, "clk_uart4", clk_uart4_p, CLK_SET_RATE_PARENT, ++ RV1106_CLKSEL_CON(15), 0, 2, MFLAGS); ++ ++static struct rockchip_clk_branch rv1106_clk_uart5_fracmux __initdata = ++ MUX(CLK_UART5, "clk_uart5", clk_uart5_p, CLK_SET_RATE_PARENT, ++ RV1106_CLKSEL_CON(17), 0, 2, MFLAGS); ++ ++static struct rockchip_clk_branch rv1106_clk_vicap_m0_fracmux __initdata = ++ MUX(CLK_VICAP_M0, "clk_vicap_m0", clk_vicap_m0_p, CLK_SET_RATE_PARENT, ++ RV1106_CLKSEL_CON(31), 0, 2, MFLAGS); ++ ++static struct rockchip_clk_branch rv1106_clk_vicap_m1_fracmux __initdata = ++ MUX(CLK_VICAP_M1, "clk_vicap_m1", clk_vicap_m1_p, CLK_SET_RATE_PARENT, ++ RV1106_CLKSEL_CON(33), 0, 2, MFLAGS); ++ ++static struct rockchip_clk_branch rv1106_clk_branches[] __initdata = { ++ ++ FACTOR(0, "xin_osc0_half", "xin24m", 0, 1, 2), ++ ++ /* PD_CORE */ ++ GATE(CLK_PVTM_CORE, "clk_pvtm_core", "xin24m", 0, ++ RV1106_CORECLKGATE_CON(0), 14, GFLAGS), ++ GATE(CLK_CORE_MCU_RTC, "clk_core_mcu_rtc", "xin24m", 0, ++ RV1106_CORECLKGATE_CON(1), 6, GFLAGS), ++ COMPOSITE(HCLK_CPU, "hclk_cpu", mux_gpll_24m_p, CLK_IS_CRITICAL, ++ RV1106_CORECLKSEL_CON(2), 5, 1, MFLAGS, 0, 5, DFLAGS, ++ RV1106_CORECLKGATE_CON(0), 12, GFLAGS), ++ /* The HPMCU (RISC-V SCR1 coprocessor) runs on clk_core_mcu, but nothing in ++ * Linux claims it, so clk_disable_unused() switches it off at boot and any ++ * firmware loaded into the coprocessor never executes. Mark it ++ * IGNORE_UNUSED so the coprocessor clock stays up (5.10 left it running; ++ * our 6.18 disabled it). A future remoteproc/coproc driver could claim it. */ ++ COMPOSITE(CLK_CORE_MCU, "clk_core_mcu", mux_gpll_24m_p, CLK_IGNORE_UNUSED, ++ RV1106_CORECLKSEL_CON(3), 11, 1, MFLAGS, 6, 5, DFLAGS, ++ RV1106_CORECLKGATE_CON(1), 1, GFLAGS), ++ COMPOSITE_NOMUX(0, "pclk_dbg", "armclk", CLK_IS_CRITICAL, ++ RV1106_CORECLKSEL_CON(1), 0, 5, DFLAGS | CLK_DIVIDER_READ_ONLY, ++ RV1106_CORECLKGATE_CON(0), 6, GFLAGS), ++ GATE(0, "pclk_cpu_root", "pclk_dbg", CLK_IS_CRITICAL, ++ RV1106_CORECLKGATE_CON(0), 10, GFLAGS), ++ GATE(PCLK_MAILBOX, "pclk_mailbox", "pclk_cpu_root", 0, ++ RV1106_CORECLKGATE_CON(1), 8, GFLAGS), ++ ++ /* PD _TOP */ ++ COMPOSITE(CLK_50M_SRC, "clk_50m_src", mux_gpll_cpll_p, CLK_IS_CRITICAL, ++ RV1106_CLKSEL_CON(0), 5, 1, MFLAGS, 0, 5, DFLAGS, ++ RV1106_CLKGATE_CON(0), 1, GFLAGS), ++ COMPOSITE(CLK_100M_SRC, "clk_100m_src", mux_gpll_cpll_p, CLK_IS_CRITICAL, ++ RV1106_CLKSEL_CON(0), 11, 1, MFLAGS, 6, 5, DFLAGS, ++ RV1106_CLKGATE_CON(0), 2, GFLAGS), ++ COMPOSITE(CLK_150M_SRC, "clk_150m_src", mux_gpll_cpll_p, CLK_IS_CRITICAL, ++ RV1106_CLKSEL_CON(1), 5, 1, MFLAGS, 0, 5, DFLAGS, ++ RV1106_CLKGATE_CON(0), 3, GFLAGS), ++ COMPOSITE(CLK_200M_SRC, "clk_200m_src", mux_gpll_cpll_p, CLK_IS_CRITICAL, ++ RV1106_CLKSEL_CON(1), 11, 1, MFLAGS, 6, 5, DFLAGS, ++ RV1106_CLKGATE_CON(0), 4, GFLAGS), ++ COMPOSITE(CLK_250M_SRC, "clk_250m_src", mux_gpll_cpll_p, CLK_IS_CRITICAL, ++ RV1106_CLKSEL_CON(2), 5, 1, MFLAGS, 0, 5, DFLAGS, ++ RV1106_CLKGATE_CON(0), 5, GFLAGS), ++ COMPOSITE(CLK_300M_SRC, "clk_300m_src", mux_gpll_cpll_p, CLK_IS_CRITICAL, ++ RV1106_CLKSEL_CON(2), 11, 1, MFLAGS, 6, 5, DFLAGS, ++ RV1106_CLKGATE_CON(0), 6, GFLAGS), ++ COMPOSITE_HALFDIV(CLK_339M_SRC, "clk_339m_src", mux_gpll_cpll_p, CLK_IS_CRITICAL, ++ RV1106_CLKSEL_CON(3), 5, 1, MFLAGS, 0, 5, DFLAGS, ++ RV1106_CLKGATE_CON(0), 7, GFLAGS), ++ COMPOSITE(CLK_400M_SRC, "clk_400m_src", mux_gpll_cpll_p, CLK_IS_CRITICAL, ++ RV1106_CLKSEL_CON(3), 11, 1, MFLAGS, 6, 5, DFLAGS, ++ RV1106_CLKGATE_CON(0), 8, GFLAGS), ++ COMPOSITE_HALFDIV(CLK_450M_SRC, "clk_450m_src", mux_gpll_cpll_p, CLK_IS_CRITICAL, ++ RV1106_CLKSEL_CON(4), 5, 1, MFLAGS, 0, 5, DFLAGS, ++ RV1106_CLKGATE_CON(0), 9, GFLAGS), ++ COMPOSITE(CLK_500M_SRC, "clk_500m_src", mux_gpll_cpll_p, CLK_IS_CRITICAL, ++ RV1106_CLKSEL_CON(4), 11, 1, MFLAGS, 6, 5, DFLAGS, ++ RV1106_CLKGATE_CON(0), 10, GFLAGS), ++ ++ COMPOSITE_NODIV(PCLK_TOP_ROOT, "pclk_top_root", mux_100m_50m_24m_p, CLK_IS_CRITICAL, ++ RV1106_CLKSEL_CON(24), 5, 2, MFLAGS, ++ RV1106_CLKGATE_CON(2), 9, GFLAGS), ++ ++ COMPOSITE(CLK_I2S0_8CH_TX_SRC, "clk_i2s0_8ch_tx_src", mux_gpll_cpll_p, 0, ++ RV1106_CLKSEL_CON(17), 7, 1, MFLAGS, 2, 5, DFLAGS, ++ RV1106_CLKGATE_CON(1), 13, GFLAGS), ++ COMPOSITE_FRACMUX(CLK_I2S0_8CH_TX_FRAC, "clk_i2s0_8ch_tx_frac", "clk_i2s0_8ch_tx_src", CLK_SET_RATE_PARENT, ++ RV1106_CLKSEL_CON(18), 0, ++ RV1106_CLKGATE_CON(1), 14, GFLAGS, ++ &rv1106_i2s0_8ch_tx_fracmux), ++ GATE(MCLK_I2S0_8CH_TX, "mclk_i2s0_8ch_tx", "clk_i2s0_8ch_tx", 0, ++ RV1106_CLKGATE_CON(1), 15, GFLAGS), ++ COMPOSITE(CLK_I2S0_8CH_RX_SRC, "clk_i2s0_8ch_rx_src", mux_gpll_cpll_p, 0, ++ RV1106_CLKSEL_CON(19), 7, 1, MFLAGS, 2, 5, DFLAGS, ++ RV1106_CLKGATE_CON(2), 0, GFLAGS), ++ COMPOSITE_FRACMUX(CLK_I2S0_8CH_RX_FRAC, "clk_i2s0_8ch_rx_frac", "clk_i2s0_8ch_rx_src", CLK_SET_RATE_PARENT, ++ RV1106_CLKSEL_CON(20), 0, ++ RV1106_CLKGATE_CON(2), 1, GFLAGS, ++ &rv1106_i2s0_8ch_rx_fracmux), ++ GATE(MCLK_I2S0_8CH_RX, "mclk_i2s0_8ch_rx", "clk_i2s0_8ch_rx", 0, ++ RV1106_CLKGATE_CON(2), 2, GFLAGS), ++ MUX(I2S0_8CH_MCLKOUT, "i2s0_8ch_mclkout", i2s0_8ch_mclkout_p, CLK_SET_RATE_PARENT, ++ RV1106_CLKSEL_CON(21), 2, 2, MFLAGS), ++ COMPOSITE(CLK_REF_MIPI0_SRC, "clk_ref_mipi0_src", mux_gpll_cpll_p, 0, ++ RV1106_CLKSEL_CON(25), 7, 1, MFLAGS, 2, 5, DFLAGS, ++ RV1106_CLKGATE_CON(3), 4, GFLAGS), ++ COMPOSITE_FRACMUX(CLK_REF_MIPI0_FRAC, "clk_ref_mipi0_frac", "clk_ref_mipi0_src", CLK_SET_RATE_PARENT, ++ RV1106_CLKSEL_CON(26), 0, ++ RV1106_CLKGATE_CON(3), 5, GFLAGS, ++ &rv1106_clk_ref_mipi0_fracmux), ++ GATE(MCLK_REF_MIPI0, "mclk_ref_mipi0", "clk_ref_mipi0", 0, ++ RV1106_CLKGATE_CON(3), 6, GFLAGS), ++ COMPOSITE(CLK_REF_MIPI1_SRC, "clk_ref_mipi1_src", mux_gpll_cpll_p, 0, ++ RV1106_CLKSEL_CON(27), 7, 1, MFLAGS, 2, 5, DFLAGS, ++ RV1106_CLKGATE_CON(3), 7, GFLAGS), ++ COMPOSITE_FRACMUX(CLK_REF_MIPI1_FRAC, "clk_ref_mipi1_frac", "clk_ref_mipi1_src", CLK_SET_RATE_PARENT, ++ RV1106_CLKSEL_CON(28), 0, ++ RV1106_CLKGATE_CON(3), 8, GFLAGS, ++ &rv1106_clk_ref_mipi1_fracmux), ++ GATE(MCLK_REF_MIPI1, "mclk_ref_mipi1", "clk_ref_mipi1", 0, ++ RV1106_CLKGATE_CON(3), 9, GFLAGS), ++ COMPOSITE(CLK_UART0_SRC, "clk_uart0_src", mux_gpll_cpll_p, 0, ++ RV1106_CLKSEL_CON(5), 5, 1, MFLAGS, 0, 5, DFLAGS, ++ RV1106_CLKGATE_CON(0), 11, GFLAGS), ++ COMPOSITE_FRACMUX(CLK_UART0_FRAC, "clk_uart0_frac", "clk_uart0_src", CLK_SET_RATE_PARENT, ++ RV1106_CLKSEL_CON(6), CLK_FRAC_DIVIDER_NO_LIMIT, ++ RV1106_CLKGATE_CON(0), 12, GFLAGS, ++ &rv1106_clk_uart0_fracmux), ++ GATE(SCLK_UART0, "sclk_uart0", "clk_uart0", 0, ++ RV1106_CLKGATE_CON(0), 13, GFLAGS), ++ COMPOSITE(CLK_UART1_SRC, "clk_uart1_src", mux_gpll_cpll_p, 0, ++ RV1106_CLKSEL_CON(7), 7, 1, MFLAGS, 2, 5, DFLAGS, ++ RV1106_CLKGATE_CON(0), 14, GFLAGS), ++ COMPOSITE_FRACMUX(CLK_UART1_FRAC, "clk_uart1_frac", "clk_uart1_src", CLK_SET_RATE_PARENT, ++ RV1106_CLKSEL_CON(8), CLK_FRAC_DIVIDER_NO_LIMIT, ++ RV1106_CLKGATE_CON(0), 15, GFLAGS, ++ &rv1106_clk_uart1_fracmux), ++ GATE(SCLK_UART1, "sclk_uart1", "clk_uart1", 0, ++ RV1106_CLKGATE_CON(1), 0, GFLAGS), ++ COMPOSITE(CLK_UART2_SRC, "clk_uart2_src", mux_gpll_cpll_p, 0, ++ RV1106_CLKSEL_CON(9), 7, 1, MFLAGS, 2, 5, DFLAGS, ++ RV1106_CLKGATE_CON(1), 1, GFLAGS), ++ COMPOSITE_FRACMUX(CLK_UART2_FRAC, "clk_uart2_frac", "clk_uart2_src", CLK_SET_RATE_PARENT, ++ RV1106_CLKSEL_CON(10), CLK_FRAC_DIVIDER_NO_LIMIT, ++ RV1106_CLKGATE_CON(1), 2, GFLAGS, ++ &rv1106_clk_uart2_fracmux), ++ GATE(SCLK_UART2, "sclk_uart2", "clk_uart2", 0, ++ RV1106_CLKGATE_CON(1), 3, GFLAGS), ++ COMPOSITE(CLK_UART3_SRC, "clk_uart3_src", mux_gpll_cpll_p, 0, ++ RV1106_CLKSEL_CON(11), 7, 1, MFLAGS, 2, 5, DFLAGS, ++ RV1106_CLKGATE_CON(1), 4, GFLAGS), ++ COMPOSITE_FRACMUX(CLK_UART3_FRAC, "clk_uart3_frac", "clk_uart3_src", CLK_SET_RATE_PARENT, ++ RV1106_CLKSEL_CON(12), CLK_FRAC_DIVIDER_NO_LIMIT, ++ RV1106_CLKGATE_CON(1), 5, GFLAGS, ++ &rv1106_clk_uart3_fracmux), ++ GATE(SCLK_UART3, "sclk_uart3", "clk_uart3", 0, ++ RV1106_CLKGATE_CON(1), 6, GFLAGS), ++ COMPOSITE(CLK_UART4_SRC, "clk_uart4_src", mux_gpll_cpll_p, 0, ++ RV1106_CLKSEL_CON(13), 7, 1, MFLAGS, 2, 5, DFLAGS, ++ RV1106_CLKGATE_CON(1), 7, GFLAGS), ++ COMPOSITE_FRACMUX(CLK_UART4_FRAC, "clk_uart4_frac", "clk_uart4_src", CLK_SET_RATE_PARENT, ++ RV1106_CLKSEL_CON(14), CLK_FRAC_DIVIDER_NO_LIMIT, ++ RV1106_CLKGATE_CON(1), 8, GFLAGS, ++ &rv1106_clk_uart4_fracmux), ++ GATE(SCLK_UART4, "sclk_uart4", "clk_uart4", 0, ++ RV1106_CLKGATE_CON(1), 9, GFLAGS), ++ COMPOSITE(CLK_UART5_SRC, "clk_uart5_src", mux_gpll_cpll_p, 0, ++ RV1106_CLKSEL_CON(15), 7, 1, MFLAGS, 2, 5, DFLAGS, ++ RV1106_CLKGATE_CON(1), 10, GFLAGS), ++ COMPOSITE_FRACMUX(CLK_UART5_FRAC, "clk_uart5_frac", "clk_uart5_src", CLK_SET_RATE_PARENT, ++ RV1106_CLKSEL_CON(16), CLK_FRAC_DIVIDER_NO_LIMIT, ++ RV1106_CLKGATE_CON(1), 11, GFLAGS, ++ &rv1106_clk_uart5_fracmux), ++ GATE(SCLK_UART5, "sclk_uart5", "clk_uart5", 0, ++ RV1106_CLKGATE_CON(1), 12, GFLAGS), ++ COMPOSITE(CLK_VICAP_M0_SRC, "clk_vicap_m0_src", mux_gpll_cpll_p, 0, ++ RV1106_CLKSEL_CON(29), 7, 1, MFLAGS, 2, 5, DFLAGS, ++ RV1106_CLKGATE_CON(3), 10, GFLAGS), ++ COMPOSITE_FRACMUX(CLK_VICAP_M0_FRAC, "clk_vicap_m0_frac", "clk_vicap_m0_src", CLK_SET_RATE_PARENT, ++ RV1106_CLKSEL_CON(30), 0, ++ RV1106_CLKGATE_CON(3), 11, GFLAGS, ++ &rv1106_clk_vicap_m0_fracmux), ++ GATE(SCLK_VICAP_M0, "sclk_vicap_m0", "clk_vicap_m0", 0, ++ RV1106_CLKGATE_CON(3), 12, GFLAGS), ++ COMPOSITE(CLK_VICAP_M1_SRC, "clk_vicap_m1_src", mux_gpll_cpll_p, 0, ++ RV1106_CLKSEL_CON(31), 7, 1, MFLAGS, 2, 5, DFLAGS, ++ RV1106_CLKGATE_CON(3), 13, GFLAGS), ++ COMPOSITE_FRACMUX(CLK_VICAP_M1_FRAC, "clk_vicap_m1_frac", "clk_vicap_m1_src", 0, ++ RV1106_CLKSEL_CON(32), 0, ++ RV1106_CLKGATE_CON(3), 14, GFLAGS, ++ &rv1106_clk_vicap_m1_fracmux), ++ GATE(SCLK_VICAP_M1, "sclk_vicap_m1", "clk_vicap_m1", 0, ++ RV1106_CLKGATE_CON(3), 15, GFLAGS), ++ COMPOSITE(DCLK_VOP_SRC, "dclk_vop_src", mux_gpll_cpll_p, 0, ++ RV1106_CLKSEL_CON(23), 8, 1, MFLAGS, 3, 5, DFLAGS, ++ RV1106_CLKGATE_CON(2), 6, GFLAGS), ++ ++ /* PD_DDR */ ++ COMPOSITE_NODIV(PCLK_DDR_ROOT, "pclk_ddr_root", mux_100m_50m_24m_p, CLK_IS_CRITICAL, ++ RV1106_DDRCLKSEL_CON(0), 0, 2, MFLAGS, ++ RV1106_DDRCLKGATE_CON(0), 0, GFLAGS), ++ COMPOSITE_NODIV(ACLK_DDR_ROOT, "aclk_ddr_root", mux_500m_300m_100m_24m_p, CLK_IS_CRITICAL, ++ RV1106_DDRCLKSEL_CON(0), 8, 2, MFLAGS, ++ RV1106_DDRCLKGATE_CON(0), 12, GFLAGS), ++ GATE(PCLK_DDRPHY, "pclk_ddrphy", "pclk_ddr_root", CLK_IGNORE_UNUSED, ++ RV1106_DDRCLKGATE_CON(1), 3, GFLAGS), ++ GATE(PCLK_DDR_HWLP, "pclk_ddr_hwlp", "pclk_ddr_root", CLK_IGNORE_UNUSED, ++ RV1106_DDRCLKGATE_CON(1), 2, GFLAGS), ++ GATE(PCLK_DDRMON, "pclk_ddrmon", "pclk_ddr_root", 0, ++ RV1106_DDRCLKGATE_CON(0), 7, GFLAGS), ++ GATE(CLK_TIMER_DDRMON, "clk_timer_ddrmon", "xin24m", 0, ++ RV1106_DDRCLKGATE_CON(0), 8, GFLAGS), ++ GATE(PCLK_DDRC, "pclk_ddrc", "pclk_ddr_root", CLK_IGNORE_UNUSED, ++ RV1106_DDRCLKGATE_CON(0), 5, GFLAGS), ++ GATE(PCLK_DFICTRL, "pclk_dfictrl", "pclk_ddr_root", CLK_IS_CRITICAL, ++ RV1106_DDRCLKGATE_CON(0), 11, GFLAGS), ++ GATE(ACLK_SYS_SHRM, "aclk_sys_shrm", "aclk_ddr_root", CLK_IS_CRITICAL, ++ RV1106_DDRCLKGATE_CON(0), 13, GFLAGS), ++ ++ /* PD_NPU */ ++ COMPOSITE_NODIV(HCLK_NPU_ROOT, "hclk_npu_root", mux_150m_100m_50m_24m_p, CLK_IS_CRITICAL, ++ RV1106_NPUCLKSEL_CON(0), 0, 2, MFLAGS, ++ RV1106_NPUCLKGATE_CON(0), 0, GFLAGS), ++ COMPOSITE_NODIV(ACLK_NPU_ROOT, "aclk_npu_root", mux_500m_300m_pvtpll0_pvtpll1_p, CLK_IS_CRITICAL, ++ RV1106_NPUCLKSEL_CON(0), 2, 2, MFLAGS, ++ RV1106_NPUCLKGATE_CON(0), 1, GFLAGS), ++ COMPOSITE_NODIV(PCLK_NPU_ROOT, "pclk_npu_root", mux_100m_50m_24m_p, CLK_IS_CRITICAL, ++ RV1106_NPUCLKSEL_CON(0), 4, 2, MFLAGS, ++ RV1106_NPUCLKGATE_CON(0), 2, GFLAGS), ++ GATE(HCLK_RKNN, "hclk_rknn", "hclk_npu_root", 0, ++ RV1106_NPUCLKGATE_CON(0), 9, GFLAGS), ++ GATE(ACLK_RKNN, "aclk_rknn", "aclk_npu_root", 0, ++ RV1106_NPUCLKGATE_CON(0), 10, GFLAGS), ++ ++ /* PD_PERI */ ++ COMPOSITE_NODIV(PCLK_PERI_ROOT, "pclk_peri_root", mux_100m_50m_24m_p, CLK_IS_CRITICAL, ++ RV1106_PERICLKSEL_CON(1), 0, 2, MFLAGS, ++ RV1106_PERICLKGATE_CON(0), 0, GFLAGS), ++ COMPOSITE_NODIV(ACLK_PERI_ROOT, "aclk_peri_root", mux_400m_200m_100m_24m_p, CLK_IS_CRITICAL, ++ RV1106_PERICLKSEL_CON(1), 2, 2, MFLAGS, ++ RV1106_PERICLKGATE_CON(0), 1, GFLAGS), ++ COMPOSITE_NODIV(HCLK_PERI_ROOT, "hclk_peri_root", mux_200m_100m_50m_24m_p, CLK_IS_CRITICAL, ++ RV1106_PERICLKSEL_CON(1), 4, 2, MFLAGS, ++ RV1106_PERICLKGATE_CON(0), 2, GFLAGS), ++ COMPOSITE_NODIV(ACLK_BUS_ROOT, "aclk_bus_root", mux_300m_200m_100m_24m_p, CLK_IS_CRITICAL, ++ RV1106_PERICLKSEL_CON(9), 0, 2, MFLAGS, ++ RV1106_PERICLKGATE_CON(6), 8, GFLAGS), ++ GATE(PCLK_ACODEC, "pclk_acodec", "pclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(6), 3, GFLAGS), ++ COMPOSITE_NOMUX(MCLK_ACODEC_TX, "mclk_acodec_tx", "mclk_i2s0_8ch_tx", 0, ++ RV1106_PERICLKSEL_CON(8), 0, 8, DFLAGS, ++ RV1106_PERICLKGATE_CON(6), 4, GFLAGS), ++ COMPOSITE_NODIV(CLK_CORE_CRYPTO, "clk_core_crypto", mux_300m_200m_100m_24m_p, 0, ++ RV1106_PERICLKSEL_CON(6), 5, 2, MFLAGS, ++ RV1106_PERICLKGATE_CON(3), 11, GFLAGS), ++ COMPOSITE_NODIV(CLK_PKA_CRYPTO, "clk_pka_crypto", mux_300m_200m_100m_24m_p, 0, ++ RV1106_PERICLKSEL_CON(6), 7, 2, MFLAGS, ++ RV1106_PERICLKGATE_CON(3), 12, GFLAGS), ++ GATE(ACLK_CRYPTO, "aclk_crypto", "aclk_bus_root", 0, ++ RV1106_PERICLKGATE_CON(3), 13, GFLAGS), ++ GATE(HCLK_CRYPTO, "hclk_crypto", "hclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(3), 14, GFLAGS), ++ GATE(ACLK_DECOM, "aclk_decom", "aclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(5), 9, GFLAGS), ++ GATE(PCLK_DECOM, "pclk_decom", "pclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(5), 10, GFLAGS), ++ COMPOSITE_NODIV(DCLK_DECOM, "dclk_decom", mux_400m_200m_100m_24m_p, 0, ++ RV1106_PERICLKSEL_CON(7), 14, 2, MFLAGS, ++ RV1106_PERICLKGATE_CON(5), 11, GFLAGS), ++ GATE(ACLK_DMAC, "aclk_dmac", "aclk_bus_root", 0, ++ RV1106_PERICLKGATE_CON(5), 8, GFLAGS), ++ GATE(PCLK_DSM, "pclk_dsm", "pclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(6), 2, GFLAGS), ++ GATE(MCLK_DSM, "mclk_dsm", "mclk_i2s0_8ch_tx", 0, ++ RV1106_PERICLKGATE_CON(6), 1, GFLAGS), ++ COMPOSITE(CCLK_SRC_EMMC, "cclk_src_emmc", mux_400m_24m_p, 0, ++ RV1106_PERICLKSEL_CON(7), 6, 1, MFLAGS, 0, 6, DFLAGS, ++ RV1106_PERICLKGATE_CON(4), 12, GFLAGS), ++ GATE(HCLK_EMMC, "hclk_emmc", "hclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(4), 13, GFLAGS), ++ GATE(PCLK_GPIO4, "pclk_gpio4", "pclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(2), 0, GFLAGS), ++ GATE(DBCLK_GPIO4, "dbclk_gpio4", "xin24m", 0, ++ RV1106_PERICLKGATE_CON(2), 1, GFLAGS), ++ GATE(PCLK_I2C0, "pclk_i2c0", "pclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(1), 6, GFLAGS), ++ COMPOSITE_NODIV(CLK_I2C0, "clk_i2c0", mux_200m_100m_50m_24m_p, 0, ++ RV1106_PERICLKSEL_CON(1), 8, 2, MFLAGS, ++ RV1106_PERICLKGATE_CON(1), 7, GFLAGS), ++ GATE(PCLK_I2C2, "pclk_i2c2", "pclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(1), 10, GFLAGS), ++ COMPOSITE_NODIV(CLK_I2C2, "clk_i2c2", mux_200m_100m_50m_24m_p, 0, ++ RV1106_PERICLKSEL_CON(1), 12, 2, MFLAGS, ++ RV1106_PERICLKGATE_CON(1), 11, GFLAGS), ++ GATE(PCLK_I2C3, "pclk_i2c3", "pclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(1), 12, GFLAGS), ++ COMPOSITE_NODIV(CLK_I2C3, "clk_i2c3", mux_200m_100m_50m_24m_p, 0, ++ RV1106_PERICLKSEL_CON(1), 14, 2, MFLAGS, ++ RV1106_PERICLKGATE_CON(1), 13, GFLAGS), ++ GATE(PCLK_I2C4, "pclk_i2c4", "pclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(1), 14, GFLAGS), ++ COMPOSITE_NODIV(CLK_I2C4, "clk_i2c4", mux_200m_100m_50m_24m_p, 0, ++ RV1106_PERICLKSEL_CON(2), 0, 2, MFLAGS, ++ RV1106_PERICLKGATE_CON(1), 15, GFLAGS), ++ GATE(HCLK_I2S0, "hclk_i2s0", "hclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(6), 0, GFLAGS), ++ GATE(PCLK_DFT2APB, "pclk_dft2apb", "pclk_peri_root", CLK_IGNORE_UNUSED, ++ RV1106_PERICLKGATE_CON(6), 7, GFLAGS), ++ GATE(HCLK_IVE, "hclk_ive", "hclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(6), 9, GFLAGS), ++ GATE(ACLK_IVE, "aclk_ive", "aclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(6), 10, GFLAGS), ++ GATE(PCLK_PWM0_PERI, "pclk_pwm0_peri", "pclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(7), 3, GFLAGS), ++ COMPOSITE_NODIV(CLK_PWM0_PERI, "clk_pwm0_peri", mux_100m_50m_24m_p, 0, ++ RV1106_PERICLKSEL_CON(11), 0, 2, MFLAGS, ++ RV1106_PERICLKGATE_CON(7), 4, GFLAGS), ++ GATE(CLK_CAPTURE_PWM0_PERI, "clk_capture_pwm0_peri", "xin24m", 0, ++ RV1106_PERICLKGATE_CON(7), 5, GFLAGS), ++ GATE(CLK_TIMER_ROOT, "clk_timer_root", "xin24m", 0, ++ RV1106_PERICLKGATE_CON(0), 3, GFLAGS), ++ GATE(HCLK_SFC, "hclk_sfc", "hclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(4), 14, GFLAGS), ++ COMPOSITE(SCLK_SFC, "sclk_sfc", mux_500m_300m_200m_24m_p, 0, ++ RV1106_PERICLKSEL_CON(7), 12, 2, MFLAGS, 7, 5, DFLAGS, ++ RV1106_PERICLKGATE_CON(5), 0, GFLAGS), ++ GATE(PCLK_UART0, "pclk_uart0", "pclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(6), 11, GFLAGS), ++ GATE(PCLK_UART1, "pclk_uart1", "pclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(6), 15, GFLAGS), ++ GATE(PCLK_PWM1_PERI, "pclk_pwm1_peri", "pclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(3), 15, GFLAGS), ++ COMPOSITE_NODIV(CLK_PWM1_PERI, "clk_pwm1_peri", mux_100m_50m_24m_p, 0, ++ RV1106_PERICLKSEL_CON(6), 9, 2, MFLAGS, ++ RV1106_PERICLKGATE_CON(4), 0, GFLAGS), ++ GATE(CLK_CAPTURE_PWM1_PERI, "clk_capture_pwm1_peri", "xin24m", 0, ++ RV1106_PERICLKGATE_CON(4), 1, GFLAGS), ++ GATE(PCLK_PWM2_PERI, "pclk_pwm2_peri", "pclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(4), 2, GFLAGS), ++ COMPOSITE_NODIV(CLK_PWM2_PERI, "clk_pwm2_peri", mux_100m_50m_24m_p, 0, ++ RV1106_PERICLKSEL_CON(6), 11, 2, MFLAGS, ++ RV1106_PERICLKGATE_CON(4), 3, GFLAGS), ++ GATE(CLK_CAPTURE_PWM2_PERI, "clk_capture_pwm2_peri", "xin24m", 0, ++ RV1106_PERICLKGATE_CON(4), 4, GFLAGS), ++ GATE(HCLK_BOOTROM, "hclk_bootrom", "hclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(0), 7, GFLAGS), ++ GATE(HCLK_SAI, "hclk_sai", "hclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(5), 13, GFLAGS), ++ GATE(MCLK_SAI, "mclk_sai", "mclk_i2s0_8ch_tx", 0, ++ RV1106_PERICLKGATE_CON(5), 14, GFLAGS), ++ GATE(PCLK_SARADC, "pclk_saradc", "pclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(3), 3, GFLAGS), ++ COMPOSITE_NOMUX(CLK_SARADC, "clk_saradc", "xin24m", 0, ++ RV1106_PERICLKSEL_CON(6), 0, 3, DFLAGS, ++ RV1106_PERICLKGATE_CON(3), 4, GFLAGS), ++ GATE(PCLK_SPI1, "pclk_spi1", "pclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(3), 6, GFLAGS), ++ COMPOSITE_NODIV(CLK_SPI1, "clk_spi1", mux_200m_100m_50m_24m_p, 0, ++ RV1106_PERICLKSEL_CON(6), 3, 2, MFLAGS, ++ RV1106_PERICLKGATE_CON(3), 7, GFLAGS), ++ GATE(PCLK_STIMER, "pclk_stimer", "pclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(0), 15, GFLAGS), ++ GATE(CLK_STIMER0, "clk_stimer0", "clk_timer_root", 0, ++ RV1106_PERICLKGATE_CON(1), 0, GFLAGS), ++ GATE(CLK_STIMER1, "clk_stimer1", "clk_timer_root", 0, ++ RV1106_PERICLKGATE_CON(1), 1, GFLAGS), ++ GATE(PCLK_TIMER, "pclk_timer", "pclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(0), 8, GFLAGS), ++ GATE(CLK_TIMER0, "clk_timer0", "clk_timer_root", 0, ++ RV1106_PERICLKGATE_CON(0), 9, GFLAGS), ++ GATE(CLK_TIMER1, "clk_timer1", "clk_timer_root", 0, ++ RV1106_PERICLKGATE_CON(0), 10, GFLAGS), ++ GATE(CLK_TIMER2, "clk_timer2", "clk_timer_root", 0, ++ RV1106_PERICLKGATE_CON(0), 11, GFLAGS), ++ GATE(CLK_TIMER3, "clk_timer3", "clk_timer_root", 0, ++ RV1106_PERICLKGATE_CON(0), 12, GFLAGS), ++ GATE(CLK_TIMER4, "clk_timer4", "clk_timer_root", 0, ++ RV1106_PERICLKGATE_CON(0), 13, GFLAGS), ++ GATE(CLK_TIMER5, "clk_timer5", "clk_timer_root", 0, ++ RV1106_PERICLKGATE_CON(0), 14, GFLAGS), ++ GATE(HCLK_TRNG_NS, "hclk_trng_ns", "hclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(3), 9, GFLAGS), ++ GATE(HCLK_TRNG_S, "hclk_trng_s", "hclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(3), 10, GFLAGS), ++ GATE(PCLK_UART2, "pclk_uart2", "pclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(2), 3, GFLAGS), ++ GATE(PCLK_UART3, "pclk_uart3", "pclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(2), 7, GFLAGS), ++ GATE(PCLK_UART4, "pclk_uart4", "pclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(2), 11, GFLAGS), ++ GATE(PCLK_UART5, "pclk_uart5", "pclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(2), 15, GFLAGS), ++ GATE(ACLK_USBOTG, "aclk_usbotg", "aclk_bus_root", 0, ++ RV1106_PERICLKGATE_CON(4), 7, GFLAGS), ++ GATE(CLK_REF_USBOTG, "clk_ref_usbotg", "xin24m", 0, ++ RV1106_PERICLKGATE_CON(4), 8, GFLAGS), ++ GATE(PCLK_USBPHY, "pclk_usbphy", "pclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(5), 1, GFLAGS), ++ GATE(CLK_REF_USBPHY, "clk_ref_usbphy", "xin24m", 0, ++ RV1106_PERICLKGATE_CON(5), 2, GFLAGS), ++ GATE(PCLK_WDT_NS, "pclk_wdt_ns", "pclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(1), 2, GFLAGS), ++ GATE(TCLK_WDT_NS, "tclk_wdt_ns", "xin24m", 0, ++ RV1106_PERICLKGATE_CON(1), 3, GFLAGS), ++ GATE(PCLK_WDT_S, "pclk_wdt_s", "pclk_peri_root", 0, ++ RV1106_PERICLKGATE_CON(1), 4, GFLAGS), ++ GATE(TCLK_WDT_S, "tclk_wdt_s", "xin24m", 0, ++ RV1106_PERICLKGATE_CON(1), 5, GFLAGS), ++ ++ /* PD_PMU */ ++ COMPOSITE_FRACMUX(0, "clk_rtc32k_frac", "xin24m", CLK_IGNORE_UNUSED, ++ RV1106_PMUCLKSEL_CON(6), 0, ++ RV1106_PMUCLKGATE_CON(1), 14, GFLAGS, ++ &rv1106_rtc32k_pmu_fracmux), ++ DIV(CLK_100M_PMU, "clk_100m_pmu", "clk_200m_src", 0, ++ RV1106_PMUCLKSEL_CON(0), 0, 3, DFLAGS), ++ COMPOSITE_NODIV(PCLK_PMU_ROOT, "pclk_pmu_root", mux_100m_pmu_24m_p, CLK_IS_CRITICAL, ++ RV1106_PMUCLKSEL_CON(0), 3, 1, MFLAGS, ++ RV1106_PMUCLKGATE_CON(0), 1, GFLAGS), ++ COMPOSITE_NODIV(HCLK_PMU_ROOT, "hclk_pmu_root", mux_200m_100m_24m_p, CLK_IS_CRITICAL, ++ RV1106_PMUCLKSEL_CON(0), 4, 2, MFLAGS, ++ RV1106_PMUCLKGATE_CON(0), 2, GFLAGS), ++ GATE(CLK_PMU, "clk_pmu", "xin24m", CLK_IS_CRITICAL, ++ RV1106_PMUCLKGATE_CON(1), 0, GFLAGS), ++ GATE(PCLK_PMU, "pclk_pmu", "pclk_pmu_root", CLK_IS_CRITICAL, ++ RV1106_PMUCLKGATE_CON(1), 1, GFLAGS), ++ GATE(CLK_DDR_FAIL_SAFE, "clk_ddr_fail_safe", "clk_pmu", 0, ++ RV1106_PMUCLKGATE_CON(1), 15, GFLAGS), ++ GATE(PCLK_PMU_GPIO0, "pclk_pmu_gpio0", "pclk_pmu_root", 0, ++ RV1106_PMUCLKGATE_CON(1), 2, GFLAGS), ++ COMPOSITE_NODIV(DBCLK_PMU_GPIO0, "dbclk_pmu_gpio0", mux_24m_32k_p, 0, ++ RV1106_PMUCLKSEL_CON(0), 15, 1, MFLAGS, ++ RV1106_PMUCLKGATE_CON(1), 3, GFLAGS), ++ GATE(PCLK_I2C1, "pclk_i2c1", "pclk_pmu_root", 0, ++ RV1106_PMUCLKGATE_CON(0), 3, GFLAGS), ++ COMPOSITE_NODIV(CLK_I2C1, "clk_i2c1", mux_200m_100m_24m_32k_p, 0, ++ RV1106_PMUCLKSEL_CON(0), 6, 2, MFLAGS, ++ RV1106_PMUCLKGATE_CON(0), 4, GFLAGS), ++ GATE(PCLK_PMU_MAILBOX, "pclk_pmu_mailbox", "pclk_pmu_root", 0, ++ RV1106_PMUCLKGATE_CON(2), 10, GFLAGS), ++ GATE(CLK_PMU_MCU, "clk_pmu_mcu", "hclk_pmu_root", 0, ++ RV1106_PMUCLKGATE_CON(0), 9, GFLAGS), ++ GATE(CLK_PMU_MCU_RTC, "clk_pmu_mcu_rtc", "xin24m", 0, ++ RV1106_PMUCLKGATE_CON(0), 13, GFLAGS), ++ COMPOSITE_NOMUX(CLK_PVTM_PMU, "clk_pvtm_pmu", "xin24m", 0, ++ RV1106_PMUCLKSEL_CON(1), 0, 5, DFLAGS, ++ RV1106_PMUCLKGATE_CON(1), 4, GFLAGS), ++ GATE(PCLK_PVTM_PMU, "pclk_pvtm_pmu", "pclk_pmu_root", 0, ++ RV1106_PMUCLKGATE_CON(1), 5, GFLAGS), ++ GATE(CLK_REFOUT, "clk_refout", "xin24m", 0, ++ RV1106_PMUCLKGATE_CON(2), 13, GFLAGS), ++ GATE(HCLK_PMU_SRAM, "hclk_pmu_sram", "hclk_pmu_root", CLK_IGNORE_UNUSED, ++ RV1106_PMUCLKGATE_CON(0), 8, GFLAGS), ++ GATE(PCLK_PMU_WDT, "pclk_pmu_wdt", "pclk_pmu_root", 0, ++ RV1106_PMUCLKGATE_CON(2), 8, GFLAGS), ++ COMPOSITE_NODIV(TCLK_PMU_WDT, "tclk_pmu_wdt", mux_24m_32k_p, 0, ++ RV1106_PMUCLKSEL_CON(7), 2, 1, MFLAGS, ++ RV1106_PMUCLKGATE_CON(2), 9, GFLAGS), ++ ++ /* PD_SUBDDR */ ++ COMPOSITE(CLK_CORE_DDRC_SRC, "clk_core_ddrc_src", mux_dpll_300m_p, CLK_IGNORE_UNUSED, ++ RV1106_SUBDDRCLKSEL_CON(0), 5, 1, MFLAGS, 0, 5, DFLAGS, ++ RV1106_SUBDDRCLKGATE_CON(0), 2, GFLAGS), ++ GATE(CLK_DFICTRL, "clk_dfictrl", "clk_core_ddrc_src", CLK_IGNORE_UNUSED, ++ RV1106_SUBDDRCLKGATE_CON(0), 5, GFLAGS), ++ GATE(CLK_DDRMON, "clk_ddrmon", "clk_core_ddrc_src", CLK_IGNORE_UNUSED, ++ RV1106_SUBDDRCLKGATE_CON(0), 4, GFLAGS), ++ GATE(CLK_DDR_PHY, "clk_ddr_phy", "clk_core_ddrc_src", CLK_IGNORE_UNUSED, ++ RV1106_SUBDDRCLKGATE_CON(0), 6, GFLAGS), ++ GATE(ACLK_DDRC, "aclk_ddrc", "clk_core_ddrc_src", CLK_IS_CRITICAL, ++ RV1106_SUBDDRCLKGATE_CON(0), 1, GFLAGS), ++ GATE(CLK_CORE_DDRC, "clk_core_ddrc", "clk_core_ddrc_src", CLK_IS_CRITICAL, ++ RV1106_SUBDDRCLKGATE_CON(0), 3, GFLAGS), ++ ++ ++ /* PD_VEPU */ ++ COMPOSITE_NODIV(HCLK_VEPU_ROOT, "hclk_vepu_root", mux_200m_100m_50m_24m_p, CLK_IS_CRITICAL, ++ RV1106_VEPUCLKSEL_CON(0), 0, 2, MFLAGS, ++ RV1106_VEPUCLKGATE_CON(0), 0, GFLAGS), ++ COMPOSITE_NODIV(ACLK_VEPU_COM_ROOT, "aclk_vepu_com_root", mux_400m_200m_100m_24m_p, CLK_IS_CRITICAL, ++ RV1106_VEPUCLKSEL_CON(0), 2, 2, MFLAGS, ++ RV1106_VEPUCLKGATE_CON(0), 1, GFLAGS), ++ COMPOSITE_NODIV(ACLK_VEPU_ROOT, "aclk_vepu_root", mux_300m_200m_100m_24m_p, CLK_IS_CRITICAL, ++ RV1106_VEPUCLKSEL_CON(0), 4, 2, MFLAGS, ++ RV1106_VEPUCLKGATE_CON(0), 2, GFLAGS), ++ COMPOSITE_NODIV(PCLK_VEPU_ROOT, "pclk_vepu_root", mux_100m_50m_24m_p, CLK_IS_CRITICAL, ++ RV1106_VEPUCLKSEL_CON(0), 6, 2, MFLAGS, ++ RV1106_VEPUCLKGATE_CON(0), 3, GFLAGS), ++ GATE(PCLK_SPI0, "pclk_spi0", "pclk_vepu_root", 0, ++ RV1106_VEPUCLKGATE_CON(1), 2, GFLAGS), ++ COMPOSITE_NODIV(CLK_SPI0, "clk_spi0", mux_200m_100m_50m_24m_p, 0, ++ RV1106_VEPUCLKSEL_CON(0), 12, 2, MFLAGS, ++ RV1106_VEPUCLKGATE_CON(1), 3, GFLAGS), ++ GATE(CLK_UART_DETN_FLT, "clk_uart_detn_flt", "xin24m", 0, ++ RV1106_VEPUCLKGATE_CON(1), 8, GFLAGS), ++ GATE(HCLK_VEPU, "hclk_vepu", "hclk_vepu_root", 0, ++ RV1106_VEPUCLKGATE_CON(0), 8, GFLAGS), ++ GATE(ACLK_VEPU, "aclk_vepu", "aclk_vepu_root", 0, ++ RV1106_VEPUCLKGATE_CON(0), 9, GFLAGS), ++ COMPOSITE_NODIV(CLK_CORE_VEPU, "clk_core_vepu", mux_400m_300m_pvtpll0_pvtpll1_p, 0, ++ RV1106_VEPUCLKSEL_CON(0), 8, 2, MFLAGS, ++ RV1106_VEPUCLKGATE_CON(0), 10, GFLAGS), ++ COMPOSITE_NODIV(CLK_CORE_VEPU_DVBM, "clk_core_vepu_dvbm", mux_200m_100m_50m_24m_p, 0, ++ RV1106_VEPUCLKSEL_CON(0), 10, 2, MFLAGS, ++ RV1106_VEPUCLKGATE_CON(0), 13, GFLAGS), ++ GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_vepu_root", 0, ++ RV1106_VEPUCLKGATE_CON(0), 15, GFLAGS), ++ GATE(DBCLK_GPIO1, "dbclk_gpio1", "xin24m", 0, ++ RV1106_VEPUCLKGATE_CON(1), 0, GFLAGS), ++ GATE(HCLK_VEPU_PP, "hclk_vepu_pp", "hclk_vepu_root", 0, ++ RV1106_VEPUCLKGATE_CON(0), 11, GFLAGS), ++ GATE(ACLK_VEPU_PP, "aclk_vepu_pp", "aclk_vepu_root", 0, ++ RV1106_VEPUCLKGATE_CON(0), 12, GFLAGS), ++ ++ /* PD_VI */ ++ COMPOSITE_NODIV(HCLK_VI_ROOT, "hclk_vi_root", mux_150m_100m_50m_24m_p, CLK_IS_CRITICAL, ++ RV1106_VICLKSEL_CON(0), 0, 2, MFLAGS, ++ RV1106_VICLKGATE_CON(0), 0, GFLAGS), ++ COMPOSITE_NODIV(ACLK_VI_ROOT, "aclk_vi_root", mux_339m_200m_100m_24m_p, CLK_IS_CRITICAL, ++ RV1106_VICLKSEL_CON(0), 2, 2, MFLAGS, ++ RV1106_VICLKGATE_CON(0), 1, GFLAGS), ++ COMPOSITE_NODIV(PCLK_VI_ROOT, "pclk_vi_root", mux_150m_100m_50m_24m_p, CLK_IS_CRITICAL, ++ RV1106_VICLKSEL_CON(0), 4, 2, MFLAGS, ++ RV1106_VICLKGATE_CON(0), 2, GFLAGS), ++ COMPOSITE_NODIV(PCLK_VI_RTC_ROOT, "pclk_vi_rtc_root", mux_50m_24m_p, 0, ++ RV1106_VICLKSEL_CON(0), 6, 1, MFLAGS, ++ RV1106_VICLKGATE_CON(0), 3, GFLAGS), ++ ++ GATE(PCLK_CSIHOST0, "pclk_csihost0", "pclk_vi_root", 0, ++ RV1106_VICLKGATE_CON(1), 3, GFLAGS), ++ GATE(PCLK_CSIHOST1, "pclk_csihost1", "pclk_vi_root", 0, ++ RV1106_VICLKGATE_CON(1), 5, GFLAGS), ++ GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_vi_root", 0, ++ RV1106_VICLKGATE_CON(1), 15, GFLAGS), ++ GATE(DBCLK_GPIO3, "dbclk_gpio3", "xin24m", 0, ++ RV1106_VICLKGATE_CON(2), 0, GFLAGS), ++ GATE(HCLK_ISP3P2, "hclk_isp3p2", "hclk_vi_root", 0, ++ RV1106_VICLKGATE_CON(0), 7, GFLAGS), ++ GATE(ACLK_ISP3P2, "aclk_isp3p2", "aclk_vi_root", 0, ++ RV1106_VICLKGATE_CON(0), 8, GFLAGS), ++ COMPOSITE_NODIV(CLK_CORE_ISP3P2, "clk_core_isp3p2", mux_339m_200m_pvtpll0_pvtpll1_p, 0, ++ RV1106_VICLKSEL_CON(0), 7, 2, MFLAGS, ++ RV1106_VICLKGATE_CON(0), 9, GFLAGS), ++ GATE(PCLK_MIPICSIPHY, "pclk_mipicsiphy", "pclk_vi_root", 0, ++ RV1106_VICLKGATE_CON(1), 14, GFLAGS), ++ COMPOSITE(CCLK_SRC_SDMMC, "cclk_src_sdmmc", mux_400m_24m_p, 0, ++ RV1106_VICLKSEL_CON(1), 14, 1, MFLAGS, 8, 6, DFLAGS, ++ RV1106_VICLKGATE_CON(1), 11, GFLAGS), ++ GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_vi_root", 0, ++ RV1106_VICLKGATE_CON(1), 12, GFLAGS), ++ GATE(CLK_SDMMC_DETN_FLT, "clk_sdmmc_detn_flt", "xin24m", 0, ++ RV1106_VICLKGATE_CON(1), 13, GFLAGS), ++ GATE(PCLK_VI_RTC_TEST, "pclk_vi_rtc_test", "pclk_vi_rtc_root", 0, ++ RV1106_VICLKGATE_CON(2), 5, GFLAGS), ++ GATE(PCLK_VI_RTC_PHY, "pclk_vi_rtc_phy", "pclk_vi_rtc_root", 0, ++ RV1106_VICLKGATE_CON(2), 6, GFLAGS), ++ COMPOSITE_NODIV(DCLK_VICAP, "dclk_vicap", mux_339m_200m_100m_24m_p, 0, ++ RV1106_VICLKSEL_CON(0), 9, 2, MFLAGS, ++ RV1106_VICLKGATE_CON(0), 10, GFLAGS), ++ GATE(ACLK_VICAP, "aclk_vicap", "aclk_vi_root", 0, ++ RV1106_VICLKGATE_CON(0), 12, GFLAGS), ++ GATE(HCLK_VICAP, "hclk_vicap", "hclk_vi_root", 0, ++ RV1106_VICLKGATE_CON(0), 13, GFLAGS), ++ ++ /* PD_VO */ ++ COMPOSITE_NODIV(ACLK_MAC_ROOT, "aclk_mac_root", mux_300m_200m_100m_24m_p, 0, ++ RV1106_VOCLKSEL_CON(1), 12, 2, MFLAGS, ++ RV1106_VOCLKGATE_CON(1), 4, GFLAGS), ++ COMPOSITE_NODIV(ACLK_VO_ROOT, "aclk_vo_root", mux_400m_200m_100m_24m_p, CLK_IS_CRITICAL, ++ RV1106_VOCLKSEL_CON(0), 0, 2, MFLAGS, ++ RV1106_VOCLKGATE_CON(0), 0, GFLAGS), ++ COMPOSITE_NODIV(HCLK_VO_ROOT, "hclk_vo_root", mux_200m_100m_50m_24m_p, CLK_IS_CRITICAL, ++ RV1106_VOCLKSEL_CON(0), 2, 2, MFLAGS, ++ RV1106_VOCLKGATE_CON(0), 1, GFLAGS), ++ COMPOSITE_NODIV(PCLK_VO_ROOT, "pclk_vo_root", mux_150m_100m_50m_24m_p, CLK_IS_CRITICAL, ++ RV1106_VOCLKSEL_CON(0), 4, 2, MFLAGS, ++ RV1106_VOCLKGATE_CON(0), 2, GFLAGS), ++ COMPOSITE_NODIV(ACLK_VOP_ROOT, "aclk_vop_root", mux_300m_200m_100m_24m_p, 0, ++ RV1106_VOCLKSEL_CON(1), 10, 2, MFLAGS, ++ RV1106_VOCLKGATE_CON(0), 11, GFLAGS), ++ ++ GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_vo_root", 0, ++ RV1106_VOCLKGATE_CON(3), 0, GFLAGS), ++ GATE(DBCLK_GPIO2, "dbclk_gpio2", "xin24m", 0, ++ RV1106_VOCLKGATE_CON(3), 1, GFLAGS), ++ GATE(ACLK_MAC, "aclk_mac", "aclk_mac_root", 0, ++ RV1106_VOCLKGATE_CON(1), 8, GFLAGS), ++ GATE(PCLK_MAC, "pclk_mac", "pclk_vo_root", 0, ++ RV1106_VOCLKGATE_CON(1), 9, GFLAGS), ++ FACTOR(CLK_GMAC0_50M_O, "clk_gmac0_50m_o", "clk_50m_src", 0, 1, 1), ++ FACTOR(CLK_GMAC0_REF_50M, "clk_gmac0_ref_50m", "clk_gmac0_50m_o", 0, 1, 1), ++ DIV(CLK_GMAC0_TX_50M_O, "clk_gmac0_tx_50m_o", "clk_gmac0_50m_o", 0, ++ RV1106_VOCLKSEL_CON(2), 1, 6, DFLAGS), ++ GATE(CLK_MACPHY, "clk_macphy", "xin24m", 0, ++ RV1106_VOCLKGATE_CON(2), 13, GFLAGS), ++ GATE(CLK_OTPC_ARB, "clk_otpc_arb", "xin24m", 0, ++ RV1106_VOCLKGATE_CON(2), 11, GFLAGS), ++ GATE(PCLK_OTPC_NS, "pclk_otpc_ns", "pclk_vo_root", 0, ++ RV1106_VOCLKGATE_CON(2), 3, GFLAGS), ++ GATE(CLK_SBPI_OTPC_NS, "clk_sbpi_otpc_ns", "xin24m", 0, ++ RV1106_VOCLKGATE_CON(2), 5, GFLAGS), ++ COMPOSITE_NOMUX(CLK_USER_OTPC_NS, "clk_user_otpc_ns", "xin24m", 0, ++ RV1106_VOCLKSEL_CON(3), 10, 3, DFLAGS, ++ RV1106_VOCLKGATE_CON(2), 6, GFLAGS), ++ GATE(PCLK_OTPC_S, "pclk_otpc_s", "pclk_vo_root", 0, ++ RV1106_VOCLKGATE_CON(2), 7, GFLAGS), ++ GATE(CLK_SBPI_OTPC_S, "clk_sbpi_otpc_s", "xin24m", 0, ++ RV1106_VOCLKGATE_CON(2), 9, GFLAGS), ++ COMPOSITE_NOMUX(CLK_USER_OTPC_S, "clk_user_otpc_s", "xin24m", 0, ++ RV1106_VOCLKSEL_CON(3), 13, 3, DFLAGS, ++ RV1106_VOCLKGATE_CON(2), 10, GFLAGS), ++ GATE(PCLK_OTP_MASK, "pclk_otp_mask", "pclk_vo_root", 0, ++ RV1106_VOCLKGATE_CON(2), 14, GFLAGS), ++ GATE(CLK_PMC_OTP, "clk_pmc_otp", "clk_sbpi_otpc_s", 0, ++ RV1106_VOCLKGATE_CON(2), 15, GFLAGS), ++ GATE(HCLK_RGA2E, "hclk_rga2e", "hclk_vo_root", 0, ++ RV1106_VOCLKGATE_CON(0), 7, GFLAGS), ++ GATE(ACLK_RGA2E, "aclk_rga2e", "aclk_vo_root", 0, ++ RV1106_VOCLKGATE_CON(0), 8, GFLAGS), ++ COMPOSITE_NODIV(CLK_CORE_RGA2E, "clk_core_rga2e", mux_400m_200m_100m_24m_p, 0, ++ RV1106_VOCLKSEL_CON(1), 8, 2, MFLAGS, ++ RV1106_VOCLKGATE_CON(0), 9, GFLAGS), ++ COMPOSITE(CCLK_SRC_SDIO, "cclk_src_sdio", mux_400m_24m_p, 0, ++ RV1106_VOCLKSEL_CON(2), 13, 1, MFLAGS, 7, 6, DFLAGS, ++ RV1106_VOCLKGATE_CON(1), 14, GFLAGS), ++ GATE(HCLK_SDIO, "hclk_sdio", "hclk_vo_root", 0, ++ RV1106_VOCLKGATE_CON(1), 15, GFLAGS), ++ GATE(PCLK_TSADC, "pclk_tsadc", "pclk_vo_root", 0, ++ RV1106_VOCLKGATE_CON(2), 0, GFLAGS), ++ COMPOSITE_NOMUX(CLK_TSADC, "clk_tsadc", "xin24m", 0, ++ RV1106_VOCLKSEL_CON(3), 0, 5, DFLAGS, ++ RV1106_VOCLKGATE_CON(2), 1, GFLAGS), ++ COMPOSITE_NOMUX(CLK_TSADC_TSEN, "clk_tsadc_tsen", "xin24m", 0, ++ RV1106_VOCLKSEL_CON(3), 5, 5, DFLAGS, ++ RV1106_VOCLKGATE_CON(2), 2, GFLAGS), ++ GATE(HCLK_VOP, "hclk_vop", "hclk_vo_root", 0, ++ RV1106_VOCLKGATE_CON(0), 13, GFLAGS), ++ GATE(DCLK_VOP, "dclk_vop", "dclk_vop_src", 0, ++ RV1106_VOCLKGATE_CON(0), 14, GFLAGS), ++ GATE(ACLK_VOP, "aclk_vop", "aclk_vop_root", 0, ++ RV1106_VOCLKGATE_CON(0), 15, GFLAGS), ++ ++ /* IO CLK */ ++ GATE(RX0PCLK_VICAP, "rx0pclk_vicap", "rx0pclk_vicap_io", 0, ++ RV1106_VICLKGATE_CON(1), 0, GFLAGS), ++ GATE(RX1PCLK_VICAP, "rx1pclk_vicap", "rx1pclk_vicap_io", 0, ++ RV1106_VICLKGATE_CON(1), 1, GFLAGS), ++ GATE(ISP0CLK_VICAP, "isp0clk_vicap", "isp0clk_vicap_io", 0, ++ RV1106_VICLKGATE_CON(1), 2, GFLAGS), ++ GATE(I0CLK_VICAP, "i0clk_vicap", "i0clk_vicap_io", 0, ++ RV1106_VICLKGATE_CON(0), 14, GFLAGS), ++ GATE(I1CLK_VICAP, "i1clk_vicap", "i1clk_vicap_io", 0, ++ RV1106_VICLKGATE_CON(0), 15, GFLAGS), ++ GATE(PCLK_VICAP, "pclk_vicap", "pclk_vicap_io", 0, ++ RV1106_VICLKGATE_CON(0), 11, GFLAGS), ++ GATE(CLK_RXBYTECLKHS_0, "clk_rxbyteclkhs_0", "clk_rxbyteclkhs_0_io", 0, ++ RV1106_VICLKGATE_CON(1), 4, GFLAGS), ++ GATE(CLK_RXBYTECLKHS_1, "clk_rxbyteclkhs_1", "clk_rxbyteclkhs_1_io", 0, ++ RV1106_VICLKGATE_CON(1), 6, GFLAGS), ++ ++ GATE(PCLK_VICAP_VEPU, "pclk_vicap_vepu", "pclk_vicap_vepu_io", 0, ++ RV1106_VEPUCLKGATE_CON(0), 14, GFLAGS), ++ GATE(SCLK_IN_SPI0, "sclk_in_spi0", "sclk_in_spi0_io", 0, ++ RV1106_VEPUCLKGATE_CON(1), 4, GFLAGS), ++ ++ GATE(CLK_UTMI_USBOTG, "clk_utmi_usbotg", "clk_utmi_usbotg_io", 0, ++ RV1106_PERICLKGATE_CON(4), 9, GFLAGS), ++ ++}; ++ ++static struct rockchip_clk_branch rv1106_grf_clk_branches[] __initdata = { ++ MMC(SCLK_EMMC_DRV, "emmc_drv", "cclk_src_emmc", RV1106_EMMC_CON0, 1), ++ MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "cclk_src_emmc", RV1106_EMMC_CON1, 1), ++ MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "cclk_src_sdmmc", RV1106_SDMMC_CON0, 1), ++ MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "cclk_src_sdmmc", RV1106_SDMMC_CON1, 1), ++ MMC(SCLK_SDIO_DRV, "sdio_drv", "cclk_src_sdio", RV1106_SDIO_CON0, 1), ++ MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "cclk_src_sdio", RV1106_SDIO_CON1, 1), ++}; ++ ++static void __iomem *rv1106_cru_base; ++static struct rockchip_clk_provider *grf_ctx, *cru_ctx; ++ ++void rv1106_dump_cru(void) ++{ ++ if (rv1106_cru_base) { ++ pr_warn("CRU:\n"); ++ print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, ++ 32, 4, rv1106_cru_base, ++ 0x588, false); ++ } ++} ++EXPORT_SYMBOL_GPL(rv1106_dump_cru); ++ ++static void _cru_pvtpll_calibrate(int count_offset, int length_offset, int target_rate) ++{ ++ unsigned int rate0, rate1, delta, length_ori, length, step, val, i = 0; ++ ++ rate0 = readl_relaxed(rv1106_cru_base + count_offset); ++ if (rate0 < target_rate) ++ return; ++ /* delta < (3.125% * target_rate) */ ++ if ((rate0 - target_rate) < (target_rate >> 5)) ++ return; ++ ++ length_ori = readl_relaxed(rv1106_cru_base + length_offset) & PVTPLL_LENGTH_SEL_MASK; ++ length = length_ori; ++ length++; ++ val = HIWORD_UPDATE(length, PVTPLL_LENGTH_SEL_MASK, PVTPLL_LENGTH_SEL_SHIFT); ++ writel_relaxed(val, rv1106_cru_base + length_offset); ++ usleep_range(2000, 2100); ++ rate1 = readl_relaxed(rv1106_cru_base + count_offset); ++ if (rate1 < target_rate) ++ return; ++ if (abs(rate1 - target_rate) < (target_rate >> 5)) ++ return; ++ ++ if (rate1 < rate0) ++ step = rate0 - rate1; ++ else ++ step = 5; ++ step = max_t(unsigned int, step, 5); ++ delta = rate1 - target_rate; ++ length += delta / step; ++ val = HIWORD_UPDATE(length, PVTPLL_LENGTH_SEL_MASK, PVTPLL_LENGTH_SEL_SHIFT); ++ writel_relaxed(val, rv1106_cru_base + length_offset); ++ usleep_range(2000, 2100); ++ rate0 = readl_relaxed(rv1106_cru_base + count_offset); ++ ++ while (abs(rate0 - target_rate) >= (target_rate >> 5)) { ++ if (i++ > 20) ++ break; ++ if (rate0 > target_rate) ++ length++; ++ else ++ length--; ++ if (length <= length_ori) ++ break; ++ val = HIWORD_UPDATE(length, PVTPLL_LENGTH_SEL_MASK, PVTPLL_LENGTH_SEL_SHIFT); ++ writel_relaxed(val, rv1106_cru_base + length_offset); ++ usleep_range(2000, 2100); ++ rate0 = readl_relaxed(rv1106_cru_base + count_offset); ++ } ++} ++ ++static void _grf_pvtpll_calibrate(int count_offset, int length_offset, int target_rate) ++{ ++ unsigned int rate0, rate1, delta, length_ori, length, step, val, i = 0; ++ ++ regmap_read(cru_ctx->grf, count_offset, &rate0); ++ if (rate0 < target_rate) ++ return; ++ /* delta < (3.125% * target_rate) */ ++ if ((rate0 - target_rate) < (target_rate >> 5)) ++ return; ++ ++ regmap_read(cru_ctx->grf, length_offset, &length_ori); ++ length = length_ori; ++ length_ori = length; ++ length &= PVTPLL_LENGTH_SEL_MASK; ++ length++; ++ val = HIWORD_UPDATE(length, PVTPLL_LENGTH_SEL_MASK, PVTPLL_LENGTH_SEL_SHIFT); ++ regmap_write(cru_ctx->grf, length_offset, val); ++ usleep_range(2000, 2100); ++ regmap_read(cru_ctx->grf, count_offset, &rate1); ++ if ((rate1 < target_rate) || (rate1 >= rate0)) ++ return; ++ if (abs(rate1 - target_rate) < (target_rate >> 5)) ++ return; ++ ++ step = rate0 - rate1; ++ delta = rate1 - target_rate; ++ length += delta / step; ++ val = HIWORD_UPDATE(length, PVTPLL_LENGTH_SEL_MASK, PVTPLL_LENGTH_SEL_SHIFT); ++ regmap_write(cru_ctx->grf, length_offset, val); ++ usleep_range(2000, 2100); ++ regmap_read(cru_ctx->grf, count_offset, &rate0); ++ ++ while (abs(rate0 - target_rate) >= (target_rate >> 5)) { ++ if (i++ > 20) ++ break; ++ if (rate0 > target_rate) ++ length++; ++ else ++ length--; ++ if (length <= length_ori) ++ break; ++ val = HIWORD_UPDATE(length, PVTPLL_LENGTH_SEL_MASK, PVTPLL_LENGTH_SEL_SHIFT); ++ regmap_write(cru_ctx->grf, length_offset, val); ++ usleep_range(2000, 2100); ++ regmap_read(cru_ctx->grf, count_offset, &rate0); ++ } ++} ++ ++static void rockchip_rv1106_pvtpll_calibrate(struct work_struct *w) ++{ ++ struct clk *clk; ++ unsigned long rate; ++ ++ clk = __clk_lookup("clk_pvtpll_0"); ++ if (clk) { ++ rate = clk_get_rate(clk); ++ _cru_pvtpll_calibrate(CRU_PVTPLL0_OSC_CNT_AVG, ++ CRU_PVTPLL0_CON0_H, rate / 1000000); ++ } ++ ++ clk = __clk_lookup("clk_pvtpll_1"); ++ if (clk) { ++ rate = clk_get_rate(clk); ++ _cru_pvtpll_calibrate(CRU_PVTPLL1_OSC_CNT_AVG, ++ CRU_PVTPLL1_CON0_H, rate / 1000000); ++ } ++ ++ clk = __clk_lookup("cpu_pvtpll"); ++ if (clk) { ++ rate = clk_get_rate(clk); ++ _grf_pvtpll_calibrate(CPU_PVTPLL_OSC_CNT_AVG, ++ CPU_PVTPLL_CON0_H, rate / 1000000); ++ } ++} ++static DECLARE_DEFERRABLE_WORK(pvtpll_calibrate_work, rockchip_rv1106_pvtpll_calibrate); ++ ++static void rockchip_rv1106_pvtpll_init(struct rockchip_clk_provider *ctx) ++{ ++ /* set pvtpll ref clk mux */ ++ writel_relaxed(CPU_PVTPLL_PATH_CORE, ctx->reg_base + CPU_CLK_PATH_BASE); ++ ++ regmap_write(ctx->grf, CPU_PVTPLL_CON0_H, HIWORD_UPDATE(0x7, PVTPLL_LENGTH_SEL_MASK, ++ PVTPLL_LENGTH_SEL_SHIFT)); ++ regmap_write(ctx->grf, CPU_PVTPLL_CON0_L, HIWORD_UPDATE(0x1, PVTPLL_RING_SEL_MASK, ++ PVTPLL_RING_SEL_SHIFT)); ++ regmap_write(ctx->grf, CPU_PVTPLL_CON0_L, HIWORD_UPDATE(0x3, PVTPLL_EN_MASK, ++ PVTPLL_EN_SHIFT)); ++ ++ writel_relaxed(0x007f0000, ctx->reg_base + CRU_PVTPLL0_CON0_H); ++ writel_relaxed(0xffff0018, ctx->reg_base + CRU_PVTPLL0_CON1_L); ++ writel_relaxed(0xffff0004, ctx->reg_base + CRU_PVTPLL0_CON2_H); ++ writel_relaxed(0x00030003, ctx->reg_base + CRU_PVTPLL0_CON0_L); ++ ++ writel_relaxed(0x007f0000, ctx->reg_base + CRU_PVTPLL1_CON0_H); ++ writel_relaxed(0xffff0018, ctx->reg_base + CRU_PVTPLL1_CON1_L); ++ writel_relaxed(0xffff0004, ctx->reg_base + CRU_PVTPLL1_CON2_H); ++ writel_relaxed(0x00030003, ctx->reg_base + CRU_PVTPLL1_CON0_L); ++ ++ queue_delayed_work(system_freezable_wq, &pvtpll_calibrate_work, msecs_to_jiffies(300)); ++} ++ ++static int rv1106_clk_panic(struct notifier_block *this, ++ unsigned long ev, void *ptr) ++{ ++ rv1106_dump_cru(); ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block rv1106_clk_panic_block = { ++ .notifier_call = rv1106_clk_panic, ++}; ++ ++static void __init rv1106_clk_init(struct device_node *np) ++{ ++ struct rockchip_clk_provider *ctx; ++ void __iomem *reg_base; ++ struct clk **cru_clks; ++ ++ reg_base = of_iomap(np, 0); ++ if (!reg_base) { ++ pr_err("%s: could not map cru region\n", __func__); ++ return; ++ } ++ ++ rv1106_cru_base = reg_base; ++ ++ ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS); ++ if (IS_ERR(ctx)) { ++ pr_err("%s: rockchip clk init failed\n", __func__); ++ iounmap(reg_base); ++ return; ++ } ++ cru_ctx = ctx; ++ ++ rockchip_rv1106_pvtpll_init(ctx); ++ ++ cru_clks = ctx->clk_data.clks; ++ ++ rockchip_clk_register_plls(ctx, rv1106_pll_clks, ++ ARRAY_SIZE(rv1106_pll_clks), ++ RV1106_GRF_SOC_STATUS0); ++ ++ rockchip_clk_register_armclk(ctx, ARMCLK, "armclk", ++ mux_armclk_p, ARRAY_SIZE(mux_armclk_p), ++ &rv1106_cpuclk_data, rv1106_cpuclk_rates, ++ ARRAY_SIZE(rv1106_cpuclk_rates)); ++ ++ rockchip_clk_register_branches(ctx, rv1106_clk_branches, ++ ARRAY_SIZE(rv1106_clk_branches)); ++ ++ rockchip_clk_register_branches(grf_ctx, rv1106_grf_clk_branches, ++ ARRAY_SIZE(rv1106_grf_clk_branches)); ++ ++ rockchip_register_softrst(np, 31745, reg_base + RV1106_PMUSOFTRST_CON(0), ++ ROCKCHIP_SOFTRST_HIWORD_MASK); ++ ++ rockchip_register_restart_notifier(ctx, RV1106_GLB_SRST_FST, NULL); ++ ++ rockchip_clk_of_add_provider(np, ctx); ++ ++ atomic_notifier_chain_register(&panic_notifier_list, ++ &rv1106_clk_panic_block); ++} ++ ++CLK_OF_DECLARE(rv1106_cru, "rockchip,rv1106-cru", rv1106_clk_init); ++ ++static void __init rv1106_grf_clk_init(struct device_node *np) ++{ ++ struct rockchip_clk_provider *ctx; ++ void __iomem *reg_base; ++ ++ reg_base = of_iomap(of_get_parent(np), 0); ++ if (!reg_base) { ++ pr_err("%s: could not map cru grf region\n", __func__); ++ return; ++ } ++ ++ ctx = rockchip_clk_init(np, reg_base, CLK_NR_GRF_CLKS); ++ if (IS_ERR(ctx)) { ++ pr_err("%s: rockchip grf clk init failed\n", __func__); ++ return; ++ } ++ grf_ctx = ctx; ++ ++ rockchip_clk_of_add_provider(np, ctx); ++} ++CLK_OF_DECLARE(rv1106_grf_cru, "rockchip,rv1106-grf-cru", rv1106_grf_clk_init); ++ ++#ifdef MODULE ++struct clk_rv1106_inits { ++ void (*inits)(struct device_node *np); ++}; ++ ++static const struct clk_rv1106_inits clk_rv1106_init = { ++ .inits = rv1106_clk_init, ++}; ++ ++static const struct clk_rv1106_inits clk_rv1106_grf_init = { ++ .inits = rv1106_grf_clk_init, ++}; ++ ++static const struct of_device_id clk_rv1106_match_table[] = { ++ { ++ .compatible = "rockchip,rv1106-cru", ++ .data = &clk_rv1106_init, ++ }, { ++ .compatible = "rockchip,rv1106-grf-cru", ++ .data = &clk_rv1106_grf_init, ++ }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, clk_rv1106_match_table); ++ ++static int __init clk_rv1106_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ const struct of_device_id *match; ++ const struct clk_rv1106_inits *init_data; ++ ++ match = of_match_device(clk_rv1106_match_table, &pdev->dev); ++ if (!match || !match->data) ++ return -EINVAL; ++ ++ init_data = match->data; ++ if (init_data->inits) ++ init_data->inits(np); ++ ++ return 0; ++} ++ ++static struct platform_driver clk_rv1106_driver = { ++ .driver = { ++ .name = "clk-rv1106", ++ .of_match_table = clk_rv1106_match_table, ++ }, ++}; ++builtin_platform_driver_probe(clk_rv1106_driver, clk_rv1106_probe); ++ ++MODULE_DESCRIPTION("Rockchip RV1106 Clock Driver"); ++MODULE_LICENSE("GPL"); ++#endif /* MODULE */ +diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h +index 7c5e74c7a..c9bb9d526 100644 +--- a/drivers/clk/rockchip/clk.h ++++ b/drivers/clk/rockchip/clk.h +@@ -92,6 +92,64 @@ struct clk; + #define RV1126_SOFTRST_CON(x) ((x) * 0x4 + 0x300) + #define RV1126_GLB_SRST_FST 0x408 + #define RV1126_GLB_SRST_SND 0x40c ++ ++/* RV1106 CRU register map — forward-ported from vendor 5.10 */ ++#define RV1106_TOPCRU_BASE 0x10000 ++#define RV1106_PERICRU_BASE 0x12000 ++#define RV1106_VICRU_BASE 0x14000 ++#define RV1106_NPUCRU_BASE 0x16000 ++#define RV1106_CORECRU_BASE 0x18000 ++#define RV1106_VEPUCRU_BASE 0x1A000 ++#define RV1106_VOCRU_BASE 0x1C000 ++#define RV1106_DDRCRU_BASE 0x1E000 ++#define RV1106_SUBDDRCRU_BASE 0x1F000 ++#define RV1106_VI_GRF_BASE 0x50000 ++#define RV1106_VO_GRF_BASE 0x60000 ++#define RV1106_PMUCLKSEL_CON(x) ((x) * 0x4 + 0x300) ++#define RV1106_PMUCLKGATE_CON(x) ((x) * 0x4 + 0x800) ++#define RV1106_PMUSOFTRST_CON(x) ((x) * 0x4 + 0xa00) ++#define RV1106_PLL_CON(x) ((x) * 0x4 + RV1106_TOPCRU_BASE) ++#define RV1106_MODE_CON (0x280 + RV1106_TOPCRU_BASE) ++#define RV1106_CLKSEL_CON(x) ((x) * 0x4 + 0x300 + RV1106_TOPCRU_BASE) ++#define RV1106_CLKGATE_CON(x) ((x) * 0x4 + 0x800 + RV1106_TOPCRU_BASE) ++#define RV1106_SOFTRST_CON(x) ((x) * 0x4 + 0xa00 + RV1106_TOPCRU_BASE) ++#define RV1106_GLB_SRST_FST (0xc08 + RV1106_TOPCRU_BASE) ++#define RV1106_GLB_SRST_SND (0xc0c + RV1106_TOPCRU_BASE) ++#define RV1106_SDIO_CON0 (0x1c + RV1106_VO_GRF_BASE) ++#define RV1106_SDIO_CON1 (0x20 + RV1106_VO_GRF_BASE) ++#define RV1106_SDMMC_CON0 (0x4 + RV1106_VI_GRF_BASE) ++#define RV1106_SDMMC_CON1 (0x8 + RV1106_VI_GRF_BASE) ++#define RV1106_EMMC_CON0 (0x20) ++#define RV1106_EMMC_CON1 (0x24) ++#define RV1106_PERICLKSEL_CON(x) ((x) * 0x4 + 0x300 + RV1106_PERICRU_BASE) ++#define RV1106_PERICLKGATE_CON(x) ((x) * 0x4 + 0x800 + RV1106_PERICRU_BASE) ++#define RV1106_PERISOFTRST_CON(x) ((x) * 0x4 + 0xa00 + RV1106_PERICRU_BASE) ++#define RV1106_VICLKSEL_CON(x) ((x) * 0x4 + 0x300 + RV1106_VICRU_BASE) ++#define RV1106_VICLKGATE_CON(x) ((x) * 0x4 + 0x800 + RV1106_VICRU_BASE) ++#define RV1106_VISOFTRST_CON(x) ((x) * 0x4 + 0xa00 + RV1106_VICRU_BASE) ++#define RV1106_VICLKSEL_CON(x) ((x) * 0x4 + 0x300 + RV1106_VICRU_BASE) ++#define RV1106_VICLKGATE_CON(x) ((x) * 0x4 + 0x800 + RV1106_VICRU_BASE) ++#define RV1106_VISOFTRST_CON(x) ((x) * 0x4 + 0xa00 + RV1106_VICRU_BASE) ++#define RV1106_NPUCLKSEL_CON(x) ((x) * 0x4 + 0x300 + RV1106_NPUCRU_BASE) ++#define RV1106_NPUCLKGATE_CON(x) ((x) * 0x4 + 0x800 + RV1106_NPUCRU_BASE) ++#define RV1106_NPUSOFTRST_CON(x) ((x) * 0x4 + 0xa00 + RV1106_NPUCRU_BASE) ++#define RV1106_CORECLKSEL_CON(x) ((x) * 0x4 + 0x300 + RV1106_CORECRU_BASE) ++#define RV1106_CORECLKGATE_CON(x) ((x) * 0x4 + 0x800 + RV1106_CORECRU_BASE) ++#define RV1106_CORESOFTRST_CON(x) ((x) * 0x4 + 0xa00 + RV1106_CORECRU_BASE) ++#define RV1106_VEPUCLKSEL_CON(x) ((x) * 0x4 + 0x300 + RV1106_VEPUCRU_BASE) ++#define RV1106_VEPUCLKGATE_CON(x) ((x) * 0x4 + 0x800 + RV1106_VEPUCRU_BASE) ++#define RV1106_VEPUSOFTRST_CON(x) ((x) * 0x4 + 0xa00 + RV1106_VEPUCRU_BASE) ++#define RV1106_VOCLKSEL_CON(x) ((x) * 0x4 + 0x300 + RV1106_VOCRU_BASE) ++#define RV1106_VOCLKGATE_CON(x) ((x) * 0x4 + 0x800 + RV1106_VOCRU_BASE) ++#define RV1106_VOSOFTRST_CON(x) ((x) * 0x4 + 0xa00 + RV1106_VOCRU_BASE) ++#define RV1106_DDRCLKSEL_CON(x) ((x) * 0x4 + 0x300 + RV1106_DDRCRU_BASE) ++#define RV1106_DDRCLKGATE_CON(x) ((x) * 0x4 + 0x800 + RV1106_DDRCRU_BASE) ++#define RV1106_DDRSOFTRST_CON(x) ((x) * 0x4 + 0xa00 + RV1106_DDRCRU_BASE) ++#define RV1106_SUBDDRCLKSEL_CON(x) ((x) * 0x4 + 0x300 + RV1106_SUBDDRCRU_BASE) ++#define RV1106_SUBDDRCLKGATE_CON(x) ((x) * 0x4 + 0x800 + RV1106_SUBDDRCRU_BASE) ++#define RV1106_SUBDDRSOFTRST_CON(x) ((x) * 0x4 + 0xa00 + RV1106_SUBDDRCRU_BASE) ++#define RV1106_SUBDDRMODE_CON (0x280 + RV1106_SUBDDRCRU_BASE) ++ + #define RV1126_SDMMC_CON0 0x440 + #define RV1126_SDMMC_CON1 0x444 + #define RV1126_SDIO_CON0 0x448 diff --git a/patches/15-pinctrl.patch b/patches/15-pinctrl.patch new file mode 100644 index 0000000..bd1bd36 --- /dev/null +++ b/patches/15-pinctrl.patch @@ -0,0 +1,275 @@ +diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c +index f1cba3d23..71ec73d41 100644 +--- a/drivers/pinctrl/pinctrl-rockchip.c ++++ b/drivers/pinctrl/pinctrl-rockchip.c +@@ -1466,6 +1466,166 @@ static int rv1108_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, + #define RV1108_DRV_PINS_PER_REG 8 + #define RV1108_DRV_BANK_STRIDE 16 + ++#define RV1106_DRV_BITS_PER_PIN 8 ++#define RV1106_DRV_PINS_PER_REG 2 ++#define RV1106_DRV_GPIO0_OFFSET 0x10 ++#define RV1106_DRV_GPIO1_OFFSET 0x80 ++#define RV1106_DRV_GPIO2_OFFSET 0x100C0 ++#define RV1106_DRV_GPIO3_OFFSET 0x20100 ++#define RV1106_DRV_GPIO4_OFFSET 0x30020 ++ ++static int rv1106_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, ++ int pin_num, struct regmap **regmap, ++ int *reg, u8 *bit) ++{ ++ struct rockchip_pinctrl *info = bank->drvdata; ++ ++ /* GPIO0_IOC is located in PMU */ ++ switch (bank->bank_num) { ++ case 0: ++ *regmap = info->regmap_pmu; ++ *reg = RV1106_DRV_GPIO0_OFFSET; ++ break; ++ ++ case 1: ++ *regmap = info->regmap_base; ++ *reg = RV1106_DRV_GPIO1_OFFSET; ++ break; ++ ++ case 2: ++ *regmap = info->regmap_base; ++ *reg = RV1106_DRV_GPIO2_OFFSET; ++ break; ++ ++ case 3: ++ *regmap = info->regmap_base; ++ *reg = RV1106_DRV_GPIO3_OFFSET; ++ break; ++ ++ case 4: ++ *regmap = info->regmap_base; ++ *reg = RV1106_DRV_GPIO4_OFFSET; ++ break; ++ ++ default: ++ dev_err(info->dev, "unsupported bank_num %d\n", bank->bank_num); ++ break; ++ } ++ ++ *reg += ((pin_num / RV1106_DRV_PINS_PER_REG) * 4); ++ *bit = pin_num % RV1106_DRV_PINS_PER_REG; ++ *bit *= RV1106_DRV_BITS_PER_PIN; ++ ++ return 0; ++} ++ ++#define RV1106_PULL_BITS_PER_PIN 2 ++#define RV1106_PULL_PINS_PER_REG 8 ++#define RV1106_PULL_GPIO0_OFFSET 0x38 ++#define RV1106_PULL_GPIO1_OFFSET 0x1C0 ++#define RV1106_PULL_GPIO2_OFFSET 0x101D0 ++#define RV1106_PULL_GPIO3_OFFSET 0x201E0 ++#define RV1106_PULL_GPIO4_OFFSET 0x30070 ++ ++static int rv1106_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, ++ int pin_num, struct regmap **regmap, ++ int *reg, u8 *bit) ++{ ++ struct rockchip_pinctrl *info = bank->drvdata; ++ ++ /* GPIO0_IOC is located in PMU */ ++ switch (bank->bank_num) { ++ case 0: ++ *regmap = info->regmap_pmu; ++ *reg = RV1106_PULL_GPIO0_OFFSET; ++ break; ++ ++ case 1: ++ *regmap = info->regmap_base; ++ *reg = RV1106_PULL_GPIO1_OFFSET; ++ break; ++ ++ case 2: ++ *regmap = info->regmap_base; ++ *reg = RV1106_PULL_GPIO2_OFFSET; ++ break; ++ ++ case 3: ++ *regmap = info->regmap_base; ++ *reg = RV1106_PULL_GPIO3_OFFSET; ++ break; ++ ++ case 4: ++ *regmap = info->regmap_base; ++ *reg = RV1106_PULL_GPIO4_OFFSET; ++ break; ++ ++ default: ++ dev_err(info->dev, "unsupported bank_num %d\n", bank->bank_num); ++ break; ++ } ++ ++ *reg += ((pin_num / RV1106_PULL_PINS_PER_REG) * 4); ++ *bit = pin_num % RV1106_PULL_PINS_PER_REG; ++ *bit *= RV1106_PULL_BITS_PER_PIN; ++ ++ return 0; ++} ++ ++#define RV1106_SMT_BITS_PER_PIN 1 ++#define RV1106_SMT_PINS_PER_REG 8 ++#define RV1106_SMT_GPIO0_OFFSET 0x40 ++#define RV1106_SMT_GPIO1_OFFSET 0x280 ++#define RV1106_SMT_GPIO2_OFFSET 0x10290 ++#define RV1106_SMT_GPIO3_OFFSET 0x202A0 ++#define RV1106_SMT_GPIO4_OFFSET 0x300A0 ++ ++static int rv1106_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank, ++ int pin_num, ++ struct regmap **regmap, ++ int *reg, u8 *bit) ++{ ++ struct rockchip_pinctrl *info = bank->drvdata; ++ ++ /* GPIO0_IOC is located in PMU */ ++ switch (bank->bank_num) { ++ case 0: ++ *regmap = info->regmap_pmu; ++ *reg = RV1106_SMT_GPIO0_OFFSET; ++ break; ++ ++ case 1: ++ *regmap = info->regmap_base; ++ *reg = RV1106_SMT_GPIO1_OFFSET; ++ break; ++ ++ case 2: ++ *regmap = info->regmap_base; ++ *reg = RV1106_SMT_GPIO2_OFFSET; ++ break; ++ ++ case 3: ++ *regmap = info->regmap_base; ++ *reg = RV1106_SMT_GPIO3_OFFSET; ++ break; ++ ++ case 4: ++ *regmap = info->regmap_base; ++ *reg = RV1106_SMT_GPIO4_OFFSET; ++ break; ++ ++ default: ++ dev_err(info->dev, "unsupported bank_num %d\n", bank->bank_num); ++ break; ++ } ++ ++ *reg += ((pin_num / RV1106_SMT_PINS_PER_REG) * 4); ++ *bit = pin_num % RV1106_SMT_PINS_PER_REG; ++ *bit *= RV1106_SMT_BITS_PER_PIN; ++ ++ return 0; ++} ++ + static int rv1108_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) +@@ -2751,7 +2911,8 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank, + goto config; + } else if (ctrl->type == RK3528 || + ctrl->type == RK3562 || +- ctrl->type == RK3568) { ++ ctrl->type == RK3568 || ++ ctrl->type == RV1106) { + rmask_bits = RK3568_DRV_BITS_PER_PIN; + ret = (1 << (strength + 1)) - 1; + goto config; +@@ -2888,6 +3049,7 @@ static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num) + ? PIN_CONFIG_BIAS_PULL_PIN_DEFAULT + : PIN_CONFIG_BIAS_DISABLE; + case PX30: ++ case RV1106: + case RV1108: + case RK3188: + case RK3288: +@@ -2949,6 +3111,7 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank, + ret = regmap_write(regmap, reg, data); + break; + case PX30: ++ case RV1106: + case RV1108: + case RV1126: + case RK3188: +@@ -3218,6 +3381,7 @@ static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl, + case RK3066B: + return pull ? false : true; + case PX30: ++ case RV1106: + case RV1108: + case RV1126: + case RK3188: +@@ -3960,6 +4124,48 @@ static struct rockchip_pin_ctrl px30_pin_ctrl = { + .schmitt_calc_reg = px30_calc_schmitt_reg_and_bit, + }; + ++static struct rockchip_pin_bank rv1106_pin_banks[] = { ++ PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", ++ IOMUX_WIDTH_4BIT | IOMUX_SOURCE_PMU, ++ IOMUX_WIDTH_4BIT | IOMUX_SOURCE_PMU, ++ IOMUX_WIDTH_4BIT | IOMUX_SOURCE_PMU, ++ IOMUX_WIDTH_4BIT | IOMUX_SOURCE_PMU), ++ PIN_BANK_IOMUX_FLAGS_OFFSET(1, 32, "gpio1", ++ IOMUX_WIDTH_4BIT, ++ IOMUX_WIDTH_4BIT, ++ IOMUX_WIDTH_4BIT, ++ IOMUX_WIDTH_4BIT, ++ 0, 0x08, 0x10, 0x18), ++ PIN_BANK_IOMUX_FLAGS_OFFSET(2, 32, "gpio2", ++ IOMUX_WIDTH_4BIT, ++ IOMUX_WIDTH_4BIT, ++ IOMUX_WIDTH_4BIT, ++ IOMUX_WIDTH_4BIT, ++ 0x10020, 0x10028, 0, 0), ++ PIN_BANK_IOMUX_FLAGS_OFFSET(3, 32, "gpio3", ++ IOMUX_WIDTH_4BIT, ++ IOMUX_WIDTH_4BIT, ++ IOMUX_WIDTH_4BIT, ++ IOMUX_WIDTH_4BIT, ++ 0x20040, 0x20048, 0x20050, 0x20058), ++ PIN_BANK_IOMUX_FLAGS_OFFSET(4, 24, "gpio4", ++ IOMUX_WIDTH_4BIT, ++ IOMUX_WIDTH_4BIT, ++ IOMUX_WIDTH_4BIT, ++ 0, ++ 0x30000, 0x30008, 0x30010, 0), ++}; ++ ++static struct rockchip_pin_ctrl rv1106_pin_ctrl __maybe_unused = { ++ .pin_banks = rv1106_pin_banks, ++ .nr_banks = ARRAY_SIZE(rv1106_pin_banks), ++ .label = "RV1106-GPIO", ++ .type = RV1106, ++ .pull_calc_reg = rv1106_calc_pull_reg_and_bit, ++ .drv_calc_reg = rv1106_calc_drv_reg_and_bit, ++ .schmitt_calc_reg = rv1106_calc_schmitt_reg_and_bit, ++}; ++ + static struct rockchip_pin_bank rv1108_pin_banks[] = { + PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", IOMUX_SOURCE_PMU, + IOMUX_SOURCE_PMU, +@@ -4531,6 +4737,8 @@ static struct rockchip_pin_ctrl rk3588_pin_ctrl = { + static const struct of_device_id rockchip_pinctrl_dt_match[] = { + { .compatible = "rockchip,px30-pinctrl", + .data = &px30_pin_ctrl }, ++ { .compatible = "rockchip,rv1106-pinctrl", ++ .data = &rv1106_pin_ctrl }, + { .compatible = "rockchip,rv1108-pinctrl", + .data = &rv1108_pin_ctrl }, + { .compatible = "rockchip,rv1126-pinctrl", +diff --git a/drivers/pinctrl/pinctrl-rockchip.h b/drivers/pinctrl/pinctrl-rockchip.h +index 35cd38079..8d4b753ba 100644 +--- a/drivers/pinctrl/pinctrl-rockchip.h ++++ b/drivers/pinctrl/pinctrl-rockchip.h +@@ -185,6 +185,7 @@ + + enum rockchip_pinctrl_type { + PX30, ++ RV1106, + RV1108, + RV1126, + RK2928, diff --git a/patches/20-arch-dts-bindings.patch b/patches/20-arch-dts-bindings.patch new file mode 100644 index 0000000..d10e8d4 --- /dev/null +++ b/patches/20-arch-dts-bindings.patch @@ -0,0 +1,4641 @@ +diff --git a/arch/arm/boot/dts/rockchip/Makefile b/arch/arm/boot/dts/rockchip/Makefile +index 716f5540e..6ad282422 100644 +--- a/arch/arm/boot/dts/rockchip/Makefile ++++ b/arch/arm/boot/dts/rockchip/Makefile +@@ -43,4 +43,6 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ + rk3288-veyron-pinky.dtb \ + rk3288-veyron-speedy.dtb \ + rk3288-veyron-tiger.dtb \ +- rk3288-vyasa.dtb ++ rk3288-vyasa.dtb \ ++ rv1106-warden-m2.dtb \ ++ rv1106-warden.dtb +diff --git a/arch/arm/boot/dts/rockchip/rockchip-pinconf.dtsi b/arch/arm/boot/dts/rockchip/rockchip-pinconf.dtsi +new file mode 100644 +index 000000000..fc0145333 +--- /dev/null ++++ b/arch/arm/boot/dts/rockchip/rockchip-pinconf.dtsi +@@ -0,0 +1,382 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright (c) 2020~2021 Rockchip Electronics Co., Ltd. ++ */ ++ ++&pinctrl { ++ ++ /omit-if-no-ref/ ++ pcfg_pull_up: pcfg-pull-up { ++ bias-pull-up; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_down: pcfg-pull-down { ++ bias-pull-down; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_none: pcfg-pull-none { ++ bias-disable; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_none_drv_level_0: pcfg-pull-none-drv-level-0 { ++ bias-disable; ++ drive-strength = <0>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_none_drv_level_1: pcfg-pull-none-drv-level-1 { ++ bias-disable; ++ drive-strength = <1>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_none_drv_level_2: pcfg-pull-none-drv-level-2 { ++ bias-disable; ++ drive-strength = <2>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_none_drv_level_3: pcfg-pull-none-drv-level-3 { ++ bias-disable; ++ drive-strength = <3>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_none_drv_level_4: pcfg-pull-none-drv-level-4 { ++ bias-disable; ++ drive-strength = <4>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_none_drv_level_5: pcfg-pull-none-drv-level-5 { ++ bias-disable; ++ drive-strength = <5>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_none_drv_level_6: pcfg-pull-none-drv-level-6 { ++ bias-disable; ++ drive-strength = <6>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_none_drv_level_7: pcfg-pull-none-drv-level-7 { ++ bias-disable; ++ drive-strength = <7>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_none_drv_level_8: pcfg-pull-none-drv-level-8 { ++ bias-disable; ++ drive-strength = <8>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_none_drv_level_9: pcfg-pull-none-drv-level-9 { ++ bias-disable; ++ drive-strength = <9>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_none_drv_level_10: pcfg-pull-none-drv-level-10 { ++ bias-disable; ++ drive-strength = <10>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_none_drv_level_11: pcfg-pull-none-drv-level-11 { ++ bias-disable; ++ drive-strength = <11>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_none_drv_level_12: pcfg-pull-none-drv-level-12 { ++ bias-disable; ++ drive-strength = <12>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_none_drv_level_13: pcfg-pull-none-drv-level-13 { ++ bias-disable; ++ drive-strength = <13>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_none_drv_level_14: pcfg-pull-none-drv-level-14 { ++ bias-disable; ++ drive-strength = <14>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_none_drv_level_15: pcfg-pull-none-drv-level-15 { ++ bias-disable; ++ drive-strength = <15>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_up_drv_level_0: pcfg-pull-up-drv-level-0 { ++ bias-pull-up; ++ drive-strength = <0>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_up_drv_level_1: pcfg-pull-up-drv-level-1 { ++ bias-pull-up; ++ drive-strength = <1>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_up_drv_level_2: pcfg-pull-up-drv-level-2 { ++ bias-pull-up; ++ drive-strength = <2>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_up_drv_level_3: pcfg-pull-up-drv-level-3 { ++ bias-pull-up; ++ drive-strength = <3>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_up_drv_level_4: pcfg-pull-up-drv-level-4 { ++ bias-pull-up; ++ drive-strength = <4>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_up_drv_level_5: pcfg-pull-up-drv-level-5 { ++ bias-pull-up; ++ drive-strength = <5>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_up_drv_level_6: pcfg-pull-up-drv-level-6 { ++ bias-pull-up; ++ drive-strength = <6>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_up_drv_level_7: pcfg-pull-up-drv-level-7 { ++ bias-pull-up; ++ drive-strength = <7>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_up_drv_level_8: pcfg-pull-up-drv-level-8 { ++ bias-pull-up; ++ drive-strength = <8>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_up_drv_level_9: pcfg-pull-up-drv-level-9 { ++ bias-pull-up; ++ drive-strength = <9>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_up_drv_level_10: pcfg-pull-up-drv-level-10 { ++ bias-pull-up; ++ drive-strength = <10>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_up_drv_level_11: pcfg-pull-up-drv-level-11 { ++ bias-pull-up; ++ drive-strength = <11>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_up_drv_level_12: pcfg-pull-up-drv-level-12 { ++ bias-pull-up; ++ drive-strength = <12>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_up_drv_level_13: pcfg-pull-up-drv-level-13 { ++ bias-pull-up; ++ drive-strength = <13>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_up_drv_level_14: pcfg-pull-up-drv-level-14 { ++ bias-pull-up; ++ drive-strength = <14>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_up_drv_level_15: pcfg-pull-up-drv-level-15 { ++ bias-pull-up; ++ drive-strength = <15>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_down_drv_level_0: pcfg-pull-down-drv-level-0 { ++ bias-pull-down; ++ drive-strength = <0>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_down_drv_level_1: pcfg-pull-down-drv-level-1 { ++ bias-pull-down; ++ drive-strength = <1>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_down_drv_level_2: pcfg-pull-down-drv-level-2 { ++ bias-pull-down; ++ drive-strength = <2>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_down_drv_level_3: pcfg-pull-down-drv-level-3 { ++ bias-pull-down; ++ drive-strength = <3>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_down_drv_level_4: pcfg-pull-down-drv-level-4 { ++ bias-pull-down; ++ drive-strength = <4>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_down_drv_level_5: pcfg-pull-down-drv-level-5 { ++ bias-pull-down; ++ drive-strength = <5>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_down_drv_level_6: pcfg-pull-down-drv-level-6 { ++ bias-pull-down; ++ drive-strength = <6>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_down_drv_level_7: pcfg-pull-down-drv-level-7 { ++ bias-pull-down; ++ drive-strength = <7>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_down_drv_level_8: pcfg-pull-down-drv-level-8 { ++ bias-pull-down; ++ drive-strength = <8>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_down_drv_level_9: pcfg-pull-down-drv-level-9 { ++ bias-pull-down; ++ drive-strength = <9>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_down_drv_level_10: pcfg-pull-down-drv-level-10 { ++ bias-pull-down; ++ drive-strength = <10>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_down_drv_level_11: pcfg-pull-down-drv-level-11 { ++ bias-pull-down; ++ drive-strength = <11>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_down_drv_level_12: pcfg-pull-down-drv-level-12 { ++ bias-pull-down; ++ drive-strength = <12>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_down_drv_level_13: pcfg-pull-down-drv-level-13 { ++ bias-pull-down; ++ drive-strength = <13>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_down_drv_level_14: pcfg-pull-down-drv-level-14 { ++ bias-pull-down; ++ drive-strength = <14>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_down_drv_level_15: pcfg-pull-down-drv-level-15 { ++ bias-pull-down; ++ drive-strength = <15>; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_up_smt: pcfg-pull-up-smt { ++ bias-pull-up; ++ input-schmitt-enable; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_down_smt: pcfg-pull-down-smt { ++ bias-pull-down; ++ input-schmitt-enable; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_none_smt: pcfg-pull-none-smt { ++ bias-disable; ++ input-schmitt-enable; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_pull_none_drv_level_0_smt: pcfg-pull-none-drv-level-0-smt { ++ bias-disable; ++ drive-strength = <0>; ++ input-schmitt-enable; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_output_high: pcfg-output-high { ++ output-high; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_output_high_pull_up: pcfg-output-high-pull-up { ++ output-high; ++ bias-pull-up; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_output_high_pull_down: pcfg-output-high-pull-down { ++ output-high; ++ bias-pull-down; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_output_high_pull_none: pcfg-output-high-pull-none { ++ output-high; ++ bias-disable; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_output_low: pcfg-output-low { ++ output-low; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_output_low_pull_up: pcfg-output-low-pull-up { ++ output-low; ++ bias-pull-up; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_output_low_pull_down: pcfg-output-low-pull-down { ++ output-low; ++ bias-pull-down; ++ }; ++ ++ /omit-if-no-ref/ ++ pcfg_output_low_pull_none: pcfg-output-low-pull-none { ++ output-low; ++ bias-disable; ++ }; ++}; ++ +diff --git a/arch/arm/boot/dts/rockchip/rv1106-pinctrl.dtsi b/arch/arm/boot/dts/rockchip/rv1106-pinctrl.dtsi +new file mode 100644 +index 000000000..a7bd376a2 +--- /dev/null ++++ b/arch/arm/boot/dts/rockchip/rv1106-pinctrl.dtsi +@@ -0,0 +1,1398 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright (c) 2022 Rockchip Electronics Co., Ltd. ++ */ ++ ++#include ++#include "rockchip-pinconf.dtsi" ++ ++/* ++ * This file is auto generated by pin2dts tool, please keep these code ++ * by adding changes at end of this file. ++ */ ++&pinctrl { ++ adc { ++ /omit-if-no-ref/ ++ adc_pins: adc-pins { ++ rockchip,pins = ++ /* adc_in0 */ ++ <4 RK_PC0 1 &pcfg_pull_none>, ++ /* adc_in1 */ ++ <4 RK_PC1 1 &pcfg_pull_none>; ++ }; ++ }; ++ ++ avs { ++ /omit-if-no-ref/ ++ avs_pins: avs-pins { ++ rockchip,pins = ++ /* avs_arm */ ++ <1 RK_PA2 2 &pcfg_pull_none>; ++ }; ++ }; ++ ++ clk { ++ /omit-if-no-ref/ ++ clk_32k: clk-32k { ++ rockchip,pins = ++ /* clk_32k */ ++ <0 RK_PA0 2 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ clk_refout: clk-refout { ++ rockchip,pins = ++ /* clk_refout */ ++ <0 RK_PA0 3 &pcfg_pull_none>; ++ }; ++ }; ++ ++ dsmaudio { ++ /omit-if-no-ref/ ++ dsmaudio_pins: dsmaudio-pins { ++ rockchip,pins = ++ /* dsmaudio_n */ ++ <1 RK_PD3 7 &pcfg_pull_none>, ++ /* dsmaudio_p */ ++ <1 RK_PD2 7 &pcfg_pull_none>; ++ }; ++ }; ++ ++ emmc { ++ /omit-if-no-ref/ ++ emmc_bus8: emmc-bus8 { ++ rockchip,pins = ++ /* emmc_d0 */ ++ <4 RK_PA4 1 &pcfg_pull_up_drv_level_2>, ++ /* emmc_d1 */ ++ <4 RK_PA3 1 &pcfg_pull_up_drv_level_2>, ++ /* emmc_d2 */ ++ <4 RK_PA2 1 &pcfg_pull_up_drv_level_2>, ++ /* emmc_d3 */ ++ <4 RK_PA6 1 &pcfg_pull_up_drv_level_2>, ++ /* emmc_d4 */ ++ <4 RK_PA5 1 &pcfg_pull_up_drv_level_2>, ++ /* emmc_d5 */ ++ <4 RK_PA7 1 &pcfg_pull_up_drv_level_2>, ++ /* emmc_d6 */ ++ <4 RK_PA1 1 &pcfg_pull_up_drv_level_2>, ++ /* emmc_d7 */ ++ <4 RK_PA0 1 &pcfg_pull_up_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ emmc_clk: emmc-clk { ++ rockchip,pins = ++ /* emmc_clk */ ++ <4 RK_PB1 1 &pcfg_pull_up_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ emmc_cmd: emmc-cmd { ++ rockchip,pins = ++ /* emmc_cmd */ ++ <4 RK_PB0 1 &pcfg_pull_up_drv_level_2>; ++ }; ++ }; ++ ++ flash { ++ /omit-if-no-ref/ ++ flash_pins: flash-pins { ++ rockchip,pins = ++ /* flash_trig_out */ ++ <2 RK_PA6 6 &pcfg_pull_none>; ++ }; ++ }; ++ ++ fspi { ++ /omit-if-no-ref/ ++ fspi_pins: fspi-pins { ++ rockchip,pins = ++ /* fspi_clk */ ++ <4 RK_PB1 2 &pcfg_pull_up_drv_level_2>, ++ /* fspi_d0 */ ++ <4 RK_PA4 2 &pcfg_pull_none>, ++ /* fspi_d1 */ ++ <4 RK_PA3 2 &pcfg_pull_none>, ++ /* fspi_d2 */ ++ <4 RK_PA2 2 &pcfg_pull_none>, ++ /* fspi_d3 */ ++ <4 RK_PA6 2 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ fspi_cs0: fspi-cs0 { ++ rockchip,pins = ++ /* fspi_cs0n */ ++ <4 RK_PB0 2 &pcfg_pull_up>; ++ }; ++ }; ++ ++ hpmcu { ++ /omit-if-no-ref/ ++ hpmcum0_pins: hpmcum0-pins { ++ rockchip,pins = ++ /* hpmcu_jtag_tck_m0 */ ++ <1 RK_PB2 3 &pcfg_pull_none>, ++ /* hpmcu_jtag_tms_m0 */ ++ <1 RK_PB3 3 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ hpmcum1_pins: hpmcum1-pins { ++ rockchip,pins = ++ /* hpmcu_jtag_tck_m1 */ ++ <3 RK_PA7 4 &pcfg_pull_none>, ++ /* hpmcu_jtag_tms_m1 */ ++ <3 RK_PA6 4 &pcfg_pull_none>; ++ }; ++ }; ++ ++ i2c0 { ++ /omit-if-no-ref/ ++ i2c0m0_xfer: i2c0m0-xfer { ++ rockchip,pins = ++ /* i2c0_scl_m0 */ ++ <1 RK_PA3 2 &pcfg_pull_none_smt>, ++ /* i2c0_sda_m0 */ ++ <1 RK_PA4 2 &pcfg_pull_none_smt>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2c0m1_xfer: i2c0m1-xfer { ++ rockchip,pins = ++ /* i2c0_scl_m1 */ ++ <4 RK_PA1 4 &pcfg_pull_none_smt>, ++ /* i2c0_sda_m1 */ ++ <4 RK_PA0 4 &pcfg_pull_none_smt>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2c0m2_xfer: i2c0m2-xfer { ++ rockchip,pins = ++ /* i2c0_scl_m2 */ ++ <3 RK_PA4 3 &pcfg_pull_none_smt>, ++ /* i2c0_sda_m2 */ ++ <3 RK_PA5 3 &pcfg_pull_none_smt>; ++ }; ++ }; ++ ++ i2c1 { ++ /omit-if-no-ref/ ++ i2c1m0_xfer: i2c1m0-xfer { ++ rockchip,pins = ++ /* i2c1_scl_m0 */ ++ <0 RK_PA5 1 &pcfg_pull_none_smt>, ++ /* i2c1_sda_m0 */ ++ <0 RK_PA6 1 &pcfg_pull_none_smt>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2c1m1_xfer: i2c1m1-xfer { ++ rockchip,pins = ++ /* i2c1_scl_m1 */ ++ <2 RK_PB0 2 &pcfg_pull_none_smt>, ++ /* i2c1_sda_m1 */ ++ <2 RK_PB1 2 &pcfg_pull_none_smt>; ++ }; ++ }; ++ ++ i2c2 { ++ /omit-if-no-ref/ ++ i2c2m0_xfer: i2c2m0-xfer { ++ rockchip,pins = ++ /* i2c2_scl_m0 */ ++ <1 RK_PA0 2 &pcfg_pull_none_smt>, ++ /* i2c2_sda_m0 */ ++ <1 RK_PA1 2 &pcfg_pull_none_smt>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2c2m1_xfer: i2c2m1-xfer { ++ rockchip,pins = ++ /* i2c2_scl_m1 */ ++ <4 RK_PA7 4 &pcfg_pull_none_smt>, ++ /* i2c2_sda_m1 */ ++ <4 RK_PA5 4 &pcfg_pull_none_smt>; ++ }; ++ }; ++ ++ i2c3 { ++ /omit-if-no-ref/ ++ i2c3m0_xfer: i2c3m0-xfer { ++ rockchip,pins = ++ /* i2c3_scl_m0 */ ++ <2 RK_PA6 5 &pcfg_pull_none_smt>, ++ /* i2c3_sda_m0 */ ++ <2 RK_PA7 5 &pcfg_pull_none_smt>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2c3m1_xfer: i2c3m1-xfer { ++ rockchip,pins = ++ /* i2c3_scl_m1 */ ++ <1 RK_PD3 3 &pcfg_pull_none_smt>, ++ /* i2c3_sda_m1 */ ++ <1 RK_PD2 3 &pcfg_pull_none_smt>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2c3m2_xfer: i2c3m2-xfer { ++ rockchip,pins = ++ /* i2c3_scl_m2 */ ++ <3 RK_PD1 3 &pcfg_pull_none_smt>, ++ /* i2c3_sda_m2 */ ++ <3 RK_PD2 3 &pcfg_pull_none_smt>; ++ }; ++ }; ++ ++ i2c4 { ++ /omit-if-no-ref/ ++ i2c4m0_xfer: i2c4m0-xfer { ++ rockchip,pins = ++ /* i2c4_scl_m0 */ ++ <2 RK_PA1 5 &pcfg_pull_none_smt>, ++ /* i2c4_sda_m0 */ ++ <2 RK_PA0 5 &pcfg_pull_none_smt>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2c4m1_xfer: i2c4m1-xfer { ++ rockchip,pins = ++ /* i2c4_scl_m1 */ ++ <1 RK_PC2 4 &pcfg_pull_none_smt>, ++ /* i2c4_sda_m1 */ ++ <1 RK_PC3 4 &pcfg_pull_none_smt>; ++ }; ++ ++ /omit-if-no-ref/ ++ i2c4m2_xfer: i2c4m2-xfer { ++ rockchip,pins = ++ /* i2c4_scl_m2 */ ++ <3 RK_PC7 3 &pcfg_pull_none_smt>, ++ /* i2c4_sda_m2 */ ++ <3 RK_PD0 3 &pcfg_pull_none_smt>; ++ }; ++ }; ++ ++ i2s0 { ++ /omit-if-no-ref/ ++ i2s0_pins: i2s0-pins { ++ rockchip,pins = ++ /* i2s0_lrck */ ++ <2 RK_PA1 2 &pcfg_pull_none>, ++ /* i2s0_mclk */ ++ <2 RK_PA2 2 &pcfg_pull_none>, ++ /* i2s0_sclk */ ++ <2 RK_PA0 2 &pcfg_pull_none>, ++ /* i2s0_sdi0 */ ++ <2 RK_PA5 2 &pcfg_pull_none>, ++ /* i2s0_sdo0 */ ++ <2 RK_PA4 2 &pcfg_pull_none>, ++ /* i2s0_sdo1_sdi3 */ ++ <2 RK_PA7 2 &pcfg_pull_none>, ++ /* i2s0_sdo2_sdi2 */ ++ <2 RK_PA6 2 &pcfg_pull_none>, ++ /* i2s0_sdo3_sdi1 */ ++ <2 RK_PA3 2 &pcfg_pull_none>; ++ }; ++ }; ++ ++ lcd { ++ /omit-if-no-ref/ ++ lcd_pins: lcd-pins { ++ rockchip,pins = ++ /* lcd_clk */ ++ <1 RK_PD3 1 &pcfg_pull_none_drv_level_4>, ++ /* lcd_d0 */ ++ <1 RK_PC7 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d1 */ ++ <1 RK_PC6 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d2 */ ++ <1 RK_PC5 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d3 */ ++ <1 RK_PC4 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d4 */ ++ <1 RK_PC3 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d5 */ ++ <1 RK_PC2 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d6 */ ++ <1 RK_PC1 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d7 */ ++ <1 RK_PC0 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d8 */ ++ <2 RK_PA0 3 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d9 */ ++ <2 RK_PA1 3 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d10 */ ++ <2 RK_PA2 3 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d11 */ ++ <2 RK_PA3 3 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d12 */ ++ <2 RK_PA4 3 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d13 */ ++ <2 RK_PA5 3 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d14 */ ++ <2 RK_PA6 3 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d15 */ ++ <2 RK_PA7 3 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d16 */ ++ <2 RK_PB0 3 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d17 */ ++ <2 RK_PB1 3 &pcfg_pull_none_drv_level_3>, ++ /* lcd_den */ ++ <1 RK_PD0 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_hsync */ ++ <1 RK_PD1 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_vsync */ ++ <1 RK_PD2 1 &pcfg_pull_none_drv_level_3>; ++ }; ++ }; ++ ++ lpmcu { ++ /omit-if-no-ref/ ++ lpmcum0_pins: lpmcum0-pins { ++ rockchip,pins = ++ /* lpmcu_jtag_tck_m0 */ ++ <1 RK_PB2 4 &pcfg_pull_none>, ++ /* lpmcu_jtag_tms_m0 */ ++ <1 RK_PB3 4 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ lpmcum1_pins: lpmcum1-pins { ++ rockchip,pins = ++ /* lpmcu_jtag_tck_m1 */ ++ <3 RK_PA4 4 &pcfg_pull_none>, ++ /* lpmcu_jtag_tms_m1 */ ++ <3 RK_PA5 4 &pcfg_pull_none>; ++ }; ++ }; ++ ++ mipi { ++ /omit-if-no-ref/ ++ mipi_pins: mipi-pins { ++ rockchip,pins = ++ /* mipi_lvds_ck0n */ ++ <3 RK_PC0 2 &pcfg_pull_none>, ++ /* mipi_lvds_ck0p */ ++ <3 RK_PC1 2 &pcfg_pull_none>, ++ /* mipi_lvds_ck1n */ ++ <3 RK_PB2 2 &pcfg_pull_none>, ++ /* mipi_lvds_ck1p */ ++ <3 RK_PB3 2 &pcfg_pull_none>, ++ /* mipi_lvds_d0n */ ++ <3 RK_PC2 2 &pcfg_pull_none>, ++ /* mipi_lvds_d0p */ ++ <3 RK_PC3 2 &pcfg_pull_none>, ++ /* mipi_lvds_d1n */ ++ <3 RK_PB6 2 &pcfg_pull_none>, ++ /* mipi_lvds_d1p */ ++ <3 RK_PB7 2 &pcfg_pull_none>, ++ /* mipi_lvds_d2n */ ++ <3 RK_PB4 2 &pcfg_pull_none>, ++ /* mipi_lvds_d2p */ ++ <3 RK_PB5 2 &pcfg_pull_none>, ++ /* mipi_lvds_d3n */ ++ <3 RK_PB0 2 &pcfg_pull_none>, ++ /* mipi_lvds_d3p */ ++ <3 RK_PB1 2 &pcfg_pull_none>; ++ }; ++ }; ++ ++ pmic { ++ /omit-if-no-ref/ ++ pmicm0_pins: pmicm0-pins { ++ rockchip,pins = ++ /* pmic_sleep_m0 */ ++ <0 RK_PA4 1 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pmicm1_pins: pmicm1-pins { ++ rockchip,pins = ++ /* pmic_sleep_m1 */ ++ <0 RK_PA3 1 &pcfg_pull_none>; ++ }; ++ }; ++ ++ pmu { ++ /omit-if-no-ref/ ++ pmu_pins: pmu-pins { ++ rockchip,pins = ++ /* pmu_debug */ ++ <1 RK_PA1 3 &pcfg_pull_none>; ++ }; ++ }; ++ ++ prelight { ++ /omit-if-no-ref/ ++ prelight_pins: prelight-pins { ++ rockchip,pins = ++ /* prelight_trig_out */ ++ <2 RK_PA7 6 &pcfg_pull_none>; ++ }; ++ }; ++ ++ pwm0 { ++ /omit-if-no-ref/ ++ pwm0m0_pins: pwm0m0-pins { ++ rockchip,pins = ++ /* pwm0_m0 */ ++ <1 RK_PA2 1 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm0m1_pins: pwm0m1-pins { ++ rockchip,pins = ++ /* pwm0_m1 */ ++ <1 RK_PD2 6 &pcfg_pull_none>; ++ }; ++ }; ++ ++ pwm1 { ++ /omit-if-no-ref/ ++ pwm1m0_pins: pwm1m0-pins { ++ rockchip,pins = ++ /* pwm1_m0 */ ++ <0 RK_PA4 2 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm1m1_pins: pwm1m1-pins { ++ rockchip,pins = ++ /* pwm1_m1 */ ++ <4 RK_PC1 2 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm1m2_pins: pwm1m2-pins { ++ rockchip,pins = ++ /* pwm1_m2 */ ++ <3 RK_PD3 2 &pcfg_pull_none>; ++ }; ++ }; ++ ++ pwm2 { ++ /omit-if-no-ref/ ++ pwm2m0_pins: pwm2m0-pins { ++ rockchip,pins = ++ /* pwm2_m0 */ ++ <0 RK_PA1 2 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm2m1_pins: pwm2m1-pins { ++ rockchip,pins = ++ /* pwm2_m1 */ ++ <2 RK_PA6 4 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm2m2_pins: pwm2m2-pins { ++ rockchip,pins = ++ /* pwm2_m2 */ ++ <1 RK_PC0 3 &pcfg_pull_none>; ++ }; ++ }; ++ ++ pwm3 { ++ /omit-if-no-ref/ ++ pwm3m0_pins: pwm3m0-pins { ++ rockchip,pins = ++ /* pwm3_ir_m0 */ ++ <0 RK_PA2 1 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm3m1_pins: pwm3m1-pins { ++ rockchip,pins = ++ /* pwm3_ir_m1 */ ++ <1 RK_PB0 2 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm3m2_pins: pwm3m2-pins { ++ rockchip,pins = ++ /* pwm3_ir_m2 */ ++ <1 RK_PD0 3 &pcfg_pull_none>; ++ }; ++ }; ++ ++ pwm4 { ++ /omit-if-no-ref/ ++ pwm4m0_pins: pwm4m0-pins { ++ rockchip,pins = ++ /* pwm4_m0 */ ++ <1 RK_PA1 4 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm4m1_pins: pwm4m1-pins { ++ rockchip,pins = ++ /* pwm4_m1 */ ++ <2 RK_PA7 4 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm4m2_pins: pwm4m2-pins { ++ rockchip,pins = ++ /* pwm4_m2 */ ++ <1 RK_PC1 3 &pcfg_pull_none>; ++ }; ++ }; ++ ++ pwm5 { ++ /omit-if-no-ref/ ++ pwm5m0_pins: pwm5m0-pins { ++ rockchip,pins = ++ /* pwm5_m0 */ ++ <0 RK_PA5 3 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm5m1_pins: pwm5m1-pins { ++ rockchip,pins = ++ /* pwm5_m1 */ ++ <2 RK_PB0 4 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm5m2_pins: pwm5m2-pins { ++ rockchip,pins = ++ /* pwm5_m2 */ ++ <1 RK_PC2 3 &pcfg_pull_none>; ++ }; ++ }; ++ ++ pwm6 { ++ /omit-if-no-ref/ ++ pwm6m0_pins: pwm6m0-pins { ++ rockchip,pins = ++ /* pwm6_m0 */ ++ <0 RK_PA6 3 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm6m1_pins: pwm6m1-pins { ++ rockchip,pins = ++ /* pwm6_m1 */ ++ <2 RK_PB1 4 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm6m2_pins: pwm6m2-pins { ++ rockchip,pins = ++ /* pwm6_m2 */ ++ <1 RK_PC3 3 &pcfg_pull_none>; ++ }; ++ }; ++ ++ pwm7 { ++ /omit-if-no-ref/ ++ pwm7m0_pins: pwm7m0-pins { ++ rockchip,pins = ++ /* pwm7_ir_m0 */ ++ <1 RK_PA0 3 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm7m1_pins: pwm7m1-pins { ++ rockchip,pins = ++ /* pwm7_ir_m1 */ ++ <1 RK_PB1 2 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm7m2_pins: pwm7m2-pins { ++ rockchip,pins = ++ /* pwm7_ir_m2 */ ++ <3 RK_PC6 2 &pcfg_pull_none>; ++ }; ++ }; ++ ++ pwm8 { ++ /omit-if-no-ref/ ++ pwm8m0_pins: pwm8m0-pins { ++ rockchip,pins = ++ /* pwm8_m0 */ ++ <3 RK_PA3 4 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm8m1_pins: pwm8m1-pins { ++ rockchip,pins = ++ /* pwm8_m1 */ ++ <1 RK_PC4 3 &pcfg_pull_none>; ++ }; ++ }; ++ ++ pwm9 { ++ /omit-if-no-ref/ ++ pwm9m0_pins: pwm9m0-pins { ++ rockchip,pins = ++ /* pwm9_m0 */ ++ <3 RK_PA2 4 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm9m1_pins: pwm9m1-pins { ++ rockchip,pins = ++ /* pwm9_m1 */ ++ <1 RK_PC5 3 &pcfg_pull_none>; ++ }; ++ }; ++ ++ pwm10 { ++ /omit-if-no-ref/ ++ pwm10m0_pins: pwm10m0-pins { ++ rockchip,pins = ++ /* pwm10_m0 */ ++ <3 RK_PA4 5 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm10m1_pins: pwm10m1-pins { ++ rockchip,pins = ++ /* pwm10_m1 */ ++ <1 RK_PC6 3 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm10m2_pins: pwm10m2-pins { ++ rockchip,pins = ++ /* pwm10_m2 */ ++ <1 RK_PD1 3 &pcfg_pull_none>; ++ }; ++ }; ++ ++ pwm11 { ++ /omit-if-no-ref/ ++ pwm11m0_pins: pwm11m0-pins { ++ rockchip,pins = ++ /* pwm11_ir_m0 */ ++ <3 RK_PA5 5 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm11m1_pins: pwm11m1-pins { ++ rockchip,pins = ++ /* pwm11_ir_m1 */ ++ <1 RK_PC7 3 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ pwm11m2_pins: pwm11m2-pins { ++ rockchip,pins = ++ /* pwm11_ir_m2 */ ++ <1 RK_PD3 5 &pcfg_pull_none>; ++ }; ++ }; ++ ++ rtc { ++ /omit-if-no-ref/ ++ rtc_pins: rtc-pins { ++ rockchip,pins = ++ /* rtc_clko */ ++ <0 RK_PA0 4 &pcfg_pull_none>; ++ }; ++ }; ++ ++ sdmmc0 { ++ /omit-if-no-ref/ ++ sdmmc0_bus4: sdmmc0-bus4 { ++ rockchip,pins = ++ /* sdmmc0_d0 */ ++ <3 RK_PA3 1 &pcfg_pull_up_drv_level_2>, ++ /* sdmmc0_d1 */ ++ <3 RK_PA2 1 &pcfg_pull_up_drv_level_2>, ++ /* sdmmc0_d2 */ ++ <3 RK_PA7 1 &pcfg_pull_up_drv_level_2>, ++ /* sdmmc0_d3 */ ++ <3 RK_PA6 1 &pcfg_pull_up_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ sdmmc0_clk: sdmmc0-clk { ++ rockchip,pins = ++ /* sdmmc0_clk */ ++ <3 RK_PA4 1 &pcfg_pull_up_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ sdmmc0_cmd: sdmmc0-cmd { ++ rockchip,pins = ++ /* sdmmc0_cmd */ ++ <3 RK_PA5 1 &pcfg_pull_up_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ sdmmc0_det: sdmmc0-det { ++ rockchip,pins = ++ /* sdmmc0_det */ ++ <3 RK_PA1 1 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ sdmmc0_idle_pins: sdmmc0-idle-pins { ++ rockchip,pins = ++ <3 RK_PA2 RK_FUNC_GPIO &pcfg_pull_down>, ++ <3 RK_PA3 RK_FUNC_GPIO &pcfg_pull_down>, ++ <3 RK_PA4 RK_FUNC_GPIO &pcfg_pull_down>, ++ <3 RK_PA5 RK_FUNC_GPIO &pcfg_pull_down>, ++ <3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_down>, ++ <3 RK_PA7 RK_FUNC_GPIO &pcfg_pull_down>; ++ }; ++ }; ++ ++ sdmmc1 { ++ /omit-if-no-ref/ ++ sdmmc1m0_bus1: sdmmc1m0-bus1 { ++ rockchip,pins = ++ /* sdmmc1_d0_m0 */ ++ <2 RK_PA1 1 &pcfg_pull_up_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ sdmmc1m0_bus4: sdmmc1m0-bus4 { ++ rockchip,pins = ++ /* sdmmc1_d0_m0 */ ++ <2 RK_PA1 1 &pcfg_pull_up_drv_level_2>, ++ /* sdmmc1_d1_m0 */ ++ <2 RK_PA0 1 &pcfg_pull_up_drv_level_2>, ++ /* sdmmc1_d2_m0 */ ++ <2 RK_PA5 1 &pcfg_pull_up_drv_level_2>, ++ /* sdmmc1_d3_m0 */ ++ <2 RK_PA4 1 &pcfg_pull_up_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ sdmmc1m0_clk: sdmmc1m0-clk { ++ rockchip,pins = ++ /* sdmmc1_clk_m0 */ ++ <2 RK_PA2 1 &pcfg_pull_up_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ sdmmc1m0_cmd: sdmmc1m0-cmd { ++ rockchip,pins = ++ /* sdmmc1_cmd_m0 */ ++ <2 RK_PA3 1 &pcfg_pull_up_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ sdmmc1m0_idle_pins: sdmmc1m0-idle-pins { ++ rockchip,pins = ++ <2 RK_PA0 RK_FUNC_GPIO &pcfg_pull_down>, ++ <2 RK_PA1 RK_FUNC_GPIO &pcfg_pull_down>, ++ <2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_down>, ++ <2 RK_PA3 RK_FUNC_GPIO &pcfg_pull_down>, ++ <2 RK_PA4 RK_FUNC_GPIO &pcfg_pull_down>, ++ <2 RK_PA5 RK_FUNC_GPIO &pcfg_pull_down>; ++ }; ++ ++ /omit-if-no-ref/ ++ sdmmc1m1_bus4: sdmmc1m1-bus4 { ++ rockchip,pins = ++ /* sdmmc1_d0_m1 */ ++ <1 RK_PC1 5 &pcfg_pull_up_drv_level_2>, ++ /* sdmmc1_d1_m1 */ ++ <1 RK_PC0 5 &pcfg_pull_up_drv_level_2>, ++ /* sdmmc1_d2_m1 */ ++ <1 RK_PC5 5 &pcfg_pull_up_drv_level_2>, ++ /* sdmmc1_d3_m1 */ ++ <1 RK_PC4 5 &pcfg_pull_up_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ sdmmc1m1_clk: sdmmc1m1-clk { ++ rockchip,pins = ++ /* sdmmc1_clk_m1 */ ++ <1 RK_PC2 5 &pcfg_pull_up_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ sdmmc1m1_cmd: sdmmc1m1-cmd { ++ rockchip,pins = ++ /* sdmmc1_cmd_m1 */ ++ <1 RK_PC3 5 &pcfg_pull_up_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ sdmmc1m1_idle_pins: sdmmc1m1-idle-pins { ++ rockchip,pins = ++ <1 RK_PC0 RK_FUNC_GPIO &pcfg_pull_down>, ++ <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>, ++ <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_down>, ++ <1 RK_PC3 RK_FUNC_GPIO &pcfg_pull_down>, ++ <1 RK_PC4 RK_FUNC_GPIO &pcfg_pull_down>, ++ <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_down>; ++ }; ++ }; ++ ++ spi0 { ++ /omit-if-no-ref/ ++ spi0m0_pins: spi0m0-pins { ++ rockchip,pins = ++ /* spi0_clk_m0 */ ++ <1 RK_PC1 4 &pcfg_pull_none>, ++ /* spi0_miso_m0 */ ++ <1 RK_PC3 6 &pcfg_pull_none>, ++ /* spi0_mosi_m0 */ ++ <1 RK_PC2 6 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ spi0m0_cs0: spi0m0-cs0 { ++ rockchip,pins = ++ /* spi0_cs0n_m0 */ ++ <1 RK_PC0 4 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ spi0m0_cs1: spi0m0-cs1 { ++ rockchip,pins = ++ /* spi0_cs1n_m0 */ ++ <1 RK_PD2 5 &pcfg_pull_none>; ++ }; ++ }; ++ ++ spi1 { ++ /omit-if-no-ref/ ++ spi1m0_pins: spi1m0-pins { ++ rockchip,pins = ++ /* spi1_clk_m0 */ ++ <4 RK_PA7 2 &pcfg_pull_none>, ++ /* spi1_miso_m0 */ ++ <4 RK_PA0 2 &pcfg_pull_none>, ++ /* spi1_mosi_m0 */ ++ <4 RK_PA1 2 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ spi1m0_cs0: spi1m0-cs0 { ++ rockchip,pins = ++ /* spi1_cs0n_m0 */ ++ <4 RK_PA5 2 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ spi1m0_cs1: spi1m0-cs1 { ++ rockchip,pins = ++ /* spi1_cs1n_m0 */ ++ <1 RK_PB1 3 &pcfg_pull_none>; ++ }; ++ }; ++ ++ uart0 { ++ /omit-if-no-ref/ ++ uart0m0_xfer: uart0m0-xfer { ++ rockchip,pins = ++ /* uart0_rx_m0 */ ++ <0 RK_PA0 1 &pcfg_pull_up>, ++ /* uart0_tx_m0 */ ++ <0 RK_PA1 1 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart0m1_xfer: uart0m1-xfer { ++ rockchip,pins = ++ /* uart0_rx_m1 */ ++ <2 RK_PB0 1 &pcfg_pull_up>, ++ /* uart0_tx_m1 */ ++ <2 RK_PB1 1 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart0m1_ctsn: uart0m1-ctsn { ++ rockchip,pins = ++ /* uart0m1_ctsn */ ++ <2 RK_PA7 1 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ uart0m1_rtsn: uart0m1-rtsn { ++ rockchip,pins = ++ /* uart0m1_rtsn */ ++ <2 RK_PA6 1 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart0m2_xfer: uart0m2-xfer { ++ rockchip,pins = ++ /* uart0_rx_m2 */ ++ <4 RK_PA0 3 &pcfg_pull_up>, ++ /* uart0_tx_m2 */ ++ <4 RK_PA1 3 &pcfg_pull_up>; ++ }; ++ }; ++ ++ uart1 { ++ /omit-if-no-ref/ ++ uart1m0_xfer: uart1m0-xfer { ++ rockchip,pins = ++ /* uart1_rx_m0 */ ++ <1 RK_PA4 1 &pcfg_pull_up>, ++ /* uart1_tx_m0 */ ++ <1 RK_PA3 1 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart1m0_ctsn: uart1m0-ctsn { ++ rockchip,pins = ++ /* uart1m0_ctsn */ ++ <0 RK_PA6 2 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ uart1m0_rtsn: uart1m0-rtsn { ++ rockchip,pins = ++ /* uart1m0_rtsn */ ++ <0 RK_PA5 2 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart1m1_xfer: uart1m1-xfer { ++ rockchip,pins = ++ /* uart1_rx_m1 */ ++ <2 RK_PA5 4 &pcfg_pull_up>, ++ /* uart1_tx_m1 */ ++ <2 RK_PA4 4 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart1m1_ctsn: uart1m1-ctsn { ++ rockchip,pins = ++ /* uart1m1_ctsn */ ++ <2 RK_PA0 4 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ uart1m1_rtsn: uart1m1-rtsn { ++ rockchip,pins = ++ /* uart1m1_rtsn */ ++ <2 RK_PA1 4 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart1m2_xfer: uart1m2-xfer { ++ rockchip,pins = ++ /* uart1_rx_m2 */ ++ <4 RK_PA7 3 &pcfg_pull_up>, ++ /* uart1_tx_m2 */ ++ <4 RK_PA5 3 &pcfg_pull_up>; ++ }; ++ }; ++ ++ uart2 { ++ /omit-if-no-ref/ ++ uart2m0_xfer: uart2m0-xfer { ++ rockchip,pins = ++ /* uart2_rx_m0 */ ++ <3 RK_PA3 2 &pcfg_pull_up>, ++ /* uart2_tx_m0 */ ++ <3 RK_PA2 2 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart2m1_xfer: uart2m1-xfer { ++ rockchip,pins = ++ /* uart2_rx_m1 */ ++ <1 RK_PB3 2 &pcfg_pull_up>, ++ /* uart2_tx_m1 */ ++ <1 RK_PB2 2 &pcfg_pull_up>; ++ }; ++ }; ++ ++ uart3 { ++ /omit-if-no-ref/ ++ uart3m0_xfer: uart3m0-xfer { ++ rockchip,pins = ++ /* uart3_rx_m0 */ ++ <1 RK_PA1 1 &pcfg_pull_up>, ++ /* uart3_tx_m0 */ ++ <1 RK_PA0 1 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart3m1_xfer: uart3m1-xfer { ++ rockchip,pins = ++ /* uart3_rx_m1 */ ++ <1 RK_PD1 5 &pcfg_pull_up>, ++ /* uart3_tx_m1 */ ++ <1 RK_PD0 5 &pcfg_pull_up>; ++ }; ++ }; ++ ++ uart4 { ++ /omit-if-no-ref/ ++ uart4m0_xfer: uart4m0-xfer { ++ rockchip,pins = ++ /* uart4_rx_m0 */ ++ <1 RK_PB0 1 &pcfg_pull_up>, ++ /* uart4_tx_m0 */ ++ <1 RK_PB1 1 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart4m1_xfer: uart4m1-xfer { ++ rockchip,pins = ++ /* uart4_rx_m1 */ ++ <1 RK_PC4 4 &pcfg_pull_up>, ++ /* uart4_tx_m1 */ ++ <1 RK_PC5 4 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart4m1_ctsn: uart4m1-ctsn { ++ rockchip,pins = ++ /* uart4m1_ctsn */ ++ <1 RK_PC7 4 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ uart4m1_rtsn: uart4m1-rtsn { ++ rockchip,pins = ++ /* uart4m1_rtsn */ ++ <1 RK_PC6 4 &pcfg_pull_none>; ++ }; ++ }; ++ ++ uart5 { ++ /omit-if-no-ref/ ++ uart5m0_xfer: uart5m0-xfer { ++ rockchip,pins = ++ /* uart5_rx_m0 */ ++ <3 RK_PA7 2 &pcfg_pull_up>, ++ /* uart5_tx_m0 */ ++ <3 RK_PA6 2 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart5m0_ctsn: uart5m0-ctsn { ++ rockchip,pins = ++ /* uart5m0_ctsn */ ++ <3 RK_PA5 2 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ uart5m0_rtsn: uart5m0-rtsn { ++ rockchip,pins = ++ /* uart5m0_rtsn */ ++ <3 RK_PA4 2 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart5m1_xfer: uart5m1-xfer { ++ rockchip,pins = ++ /* uart5_rx_m1 */ ++ <1 RK_PD2 4 &pcfg_pull_up>, ++ /* uart5_tx_m1 */ ++ <1 RK_PD3 4 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart5m1_ctsn: uart5m1-ctsn { ++ rockchip,pins = ++ /* uart5m1_ctsn */ ++ <1 RK_PD1 4 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ uart5m1_rtsn: uart5m1-rtsn { ++ rockchip,pins = ++ /* uart5m1_rtsn */ ++ <1 RK_PD0 4 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart5m2_xfer: uart5m2-xfer { ++ rockchip,pins = ++ /* uart5_rx_m2 */ ++ <3 RK_PD0 2 &pcfg_pull_up>, ++ /* uart5_tx_m2 */ ++ <3 RK_PC7 2 &pcfg_pull_up>; ++ }; ++ ++ /omit-if-no-ref/ ++ uart5m2_ctsn: uart5m2-ctsn { ++ rockchip,pins = ++ /* uart5m2_ctsn */ ++ <3 RK_PD2 2 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ uart5m2_rtsn: uart5m2-rtsn { ++ rockchip,pins = ++ /* uart5m2_rtsn */ ++ <3 RK_PD1 2 &pcfg_pull_none>; ++ }; ++ }; ++ ++ vicap { ++ /omit-if-no-ref/ ++ vicapm0_pins: vicapm0-pins { ++ rockchip,pins = ++ /* vicap_clkin_m0 */ ++ <3 RK_PC2 1 &pcfg_pull_none>, ++ /* vicap_d0_m0 */ ++ <3 RK_PB0 1 &pcfg_pull_none>, ++ /* vicap_d1_m0 */ ++ <3 RK_PB1 1 &pcfg_pull_none>, ++ /* vicap_d2_m0 */ ++ <3 RK_PB2 1 &pcfg_pull_none>, ++ /* vicap_d3_m0 */ ++ <3 RK_PB3 1 &pcfg_pull_none>, ++ /* vicap_d4_m0 */ ++ <3 RK_PB4 1 &pcfg_pull_none>, ++ /* vicap_d5_m0 */ ++ <3 RK_PB5 1 &pcfg_pull_none>, ++ /* vicap_d6_m0 */ ++ <3 RK_PB6 1 &pcfg_pull_none>, ++ /* vicap_d7_m0 */ ++ <3 RK_PB7 1 &pcfg_pull_none>, ++ /* vicap_d8_m0 */ ++ <3 RK_PC0 1 &pcfg_pull_none>, ++ /* vicap_d9_m0 */ ++ <3 RK_PC1 1 &pcfg_pull_none>, ++ /* vicap_hsync_m0 */ ++ <3 RK_PC3 1 &pcfg_pull_none>, ++ /* vicap_vsync_m0 */ ++ <3 RK_PC5 1 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ vicapm1_pins: vicapm1-pins { ++ rockchip,pins = ++ /* vicap_clkin_m1 */ ++ <1 RK_PD0 2 &pcfg_pull_none>, ++ /* vicap_d0_m1 */ ++ <1 RK_PA2 3 &pcfg_pull_none>, ++ /* vicap_d1_m1 */ ++ <1 RK_PB1 4 &pcfg_pull_none>, ++ /* vicap_d2_m1 */ ++ <1 RK_PC0 2 &pcfg_pull_none>, ++ /* vicap_d3_m1 */ ++ <1 RK_PC1 2 &pcfg_pull_none>, ++ /* vicap_d4_m1 */ ++ <1 RK_PC2 2 &pcfg_pull_none>, ++ /* vicap_d5_m1 */ ++ <1 RK_PC3 2 &pcfg_pull_none>, ++ /* vicap_d6_m1 */ ++ <1 RK_PC4 2 &pcfg_pull_none>, ++ /* vicap_d7_m1 */ ++ <1 RK_PC5 2 &pcfg_pull_none>, ++ /* vicap_d8_m1 */ ++ <1 RK_PC6 2 &pcfg_pull_none>, ++ /* vicap_d9_m1 */ ++ <1 RK_PC7 2 &pcfg_pull_none>, ++ /* vicap_hsync_m1 */ ++ <1 RK_PD1 2 &pcfg_pull_none>, ++ /* vicap_vsync_m1 */ ++ <1 RK_PD2 2 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ vicap_d10: vicap-d10 { ++ rockchip,pins = ++ /* vicap_d10 */ ++ <3 RK_PC6 1 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ vicap_d11: vicap-d11 { ++ rockchip,pins = ++ /* vicap_d11 */ ++ <3 RK_PC7 1 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ vicap_d12: vicap-d12 { ++ rockchip,pins = ++ /* vicap_d12 */ ++ <3 RK_PD0 1 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ vicap_d13: vicap-d13 { ++ rockchip,pins = ++ /* vicap_d13 */ ++ <3 RK_PD1 1 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ vicap_d14: vicap-d14 { ++ rockchip,pins = ++ /* vicap_d14 */ ++ <3 RK_PD2 1 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ vicap_d15: vicap-d15 { ++ rockchip,pins = ++ /* vicap_d15 */ ++ <3 RK_PD3 1 &pcfg_pull_none>; ++ }; ++ }; ++}; ++ ++/* ++ * This part is edited handly. ++ */ ++&pinctrl { ++ vicap { ++ /omit-if-no-ref/ ++ vicap_clkout_m0: vicap-clkout-m0 { ++ rockchip,pins = ++ /* vicap_clkout_m0 */ ++ <3 RK_PC4 1 &pcfg_pull_none>; ++ }; ++ ++ /omit-if-no-ref/ ++ vicap_clkout_m1: vicap-clkout-m1 { ++ rockchip,pins = ++ /* vicap_clkout_m1 */ ++ <1 RK_PD3 2 &pcfg_pull_none>; ++ }; ++ }; ++ ++ mipi { ++ /omit-if-no-ref/ ++ mipi_refclk_out0: mipi-refclk-out0 { ++ rockchip,pins = ++ /* mipi_refclk_out0 */ ++ <3 RK_PC4 2 &pcfg_pull_none>; ++ }; ++ /omit-if-no-ref/ ++ mipi_refclk_out1: mipi-refclk-out1 { ++ rockchip,pins = ++ /* mipi_refclk_out1 */ ++ <3 RK_PC6 3 &pcfg_pull_none>; ++ }; ++ }; ++ ++ lcd { ++ /omit-if-no-ref/ ++ bt1120_pins: bt1120-pins { ++ rockchip,pins = ++ /* lcd_clk */ ++ <1 RK_PD3 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d0 */ ++ <1 RK_PC7 1 &pcfg_pull_none_drv_level_2>, ++ /* lcd_d1 */ ++ <1 RK_PC6 1 &pcfg_pull_none_drv_level_2>, ++ /* lcd_d2 */ ++ <1 RK_PC5 1 &pcfg_pull_none_drv_level_2>, ++ /* lcd_d3 */ ++ <1 RK_PC4 1 &pcfg_pull_none_drv_level_2>, ++ /* lcd_d4 */ ++ <1 RK_PC3 1 &pcfg_pull_none_drv_level_2>, ++ /* lcd_d5 */ ++ <1 RK_PC2 1 &pcfg_pull_none_drv_level_2>, ++ /* lcd_d6 */ ++ <1 RK_PC1 1 &pcfg_pull_none_drv_level_2>, ++ /* lcd_d7 */ ++ <1 RK_PC0 1 &pcfg_pull_none_drv_level_2>, ++ /* lcd_d8 */ ++ <2 RK_PA0 3 &pcfg_pull_none_drv_level_2>, ++ /* lcd_d9 */ ++ <2 RK_PA1 3 &pcfg_pull_none_drv_level_2>, ++ /* lcd_d10 */ ++ <2 RK_PA2 3 &pcfg_pull_none_drv_level_2>, ++ /* lcd_d11 */ ++ <2 RK_PA3 3 &pcfg_pull_none_drv_level_2>, ++ /* lcd_d12 */ ++ <2 RK_PA4 3 &pcfg_pull_none_drv_level_2>, ++ /* lcd_d13 */ ++ <2 RK_PA5 3 &pcfg_pull_none_drv_level_2>, ++ /* lcd_d14 */ ++ <2 RK_PA6 3 &pcfg_pull_none_drv_level_2>, ++ /* lcd_d15 */ ++ <2 RK_PA7 3 &pcfg_pull_none_drv_level_2>; ++ }; ++ ++ /omit-if-no-ref/ ++ bt656_pins: bt656-pins { ++ rockchip,pins = ++ /* lcd_clk */ ++ <1 RK_PD3 1 &pcfg_pull_none_drv_level_2>, ++ /* lcd_d0 */ ++ <1 RK_PC7 1 &pcfg_pull_none_drv_level_1>, ++ /* lcd_d1 */ ++ <1 RK_PC6 1 &pcfg_pull_none_drv_level_1>, ++ /* lcd_d2 */ ++ <1 RK_PC5 1 &pcfg_pull_none_drv_level_1>, ++ /* lcd_d3 */ ++ <1 RK_PC4 1 &pcfg_pull_none_drv_level_1>, ++ /* lcd_d4 */ ++ <1 RK_PC3 1 &pcfg_pull_none_drv_level_1>, ++ /* lcd_d5 */ ++ <1 RK_PC2 1 &pcfg_pull_none_drv_level_1>, ++ /* lcd_d6 */ ++ <1 RK_PC1 1 &pcfg_pull_none_drv_level_1>, ++ /* lcd_d7 */ ++ <1 RK_PC0 1 &pcfg_pull_none_drv_level_1>; ++ }; ++ ++ /omit-if-no-ref/ ++ rgb3x8_pins: rgb3x8-pins { ++ rockchip,pins = ++ /* lcd_clk */ ++ <1 RK_PD3 1 &pcfg_pull_none_drv_level_4>, ++ /* lcd_d0 */ ++ <1 RK_PC7 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d1 */ ++ <1 RK_PC6 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d2 */ ++ <1 RK_PC5 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d3 */ ++ <1 RK_PC4 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d4 */ ++ <1 RK_PC3 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d5 */ ++ <1 RK_PC2 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d6 */ ++ <1 RK_PC1 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d7 */ ++ <1 RK_PC0 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_den */ ++ <1 RK_PD0 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_hsync */ ++ <1 RK_PD1 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_vsync */ ++ <1 RK_PD2 1 &pcfg_pull_none_drv_level_3>; ++ }; ++ ++ /omit-if-no-ref/ ++ rgb565_pins: rgb565-pins { ++ rockchip,pins = ++ /* lcd_clk */ ++ <1 RK_PD3 1 &pcfg_pull_none_drv_level_4>, ++ /* lcd_d0 */ ++ <1 RK_PC7 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d1 */ ++ <1 RK_PC6 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d2 */ ++ <1 RK_PC5 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d3 */ ++ <1 RK_PC4 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d4 */ ++ <1 RK_PC3 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d5 */ ++ <1 RK_PC2 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d6 */ ++ <1 RK_PC1 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d7 */ ++ <1 RK_PC0 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d8 */ ++ <2 RK_PA0 3 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d9 */ ++ <2 RK_PA1 3 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d10 */ ++ <2 RK_PA2 3 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d11 */ ++ <2 RK_PA3 3 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d12 */ ++ <2 RK_PA4 3 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d13 */ ++ <2 RK_PA5 3 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d14 */ ++ <2 RK_PA6 3 &pcfg_pull_none_drv_level_3>, ++ /* lcd_d15 */ ++ <2 RK_PA7 3 &pcfg_pull_none_drv_level_3>, ++ /* lcd_den */ ++ <1 RK_PD0 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_hsync */ ++ <1 RK_PD1 1 &pcfg_pull_none_drv_level_3>, ++ /* lcd_vsync */ ++ <1 RK_PD2 1 &pcfg_pull_none_drv_level_3>; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/rockchip/rv1106-warden-m2.dts b/arch/arm/boot/dts/rockchip/rv1106-warden-m2.dts +new file mode 100644 +index 000000000..418652552 +--- /dev/null ++++ b/arch/arm/boot/dts/rockchip/rv1106-warden-m2.dts +@@ -0,0 +1,145 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Minimal RV1106 devicetree for the WardenOS 86-Panel — M2 "earlycon" bring-up ++ * of the self-built Linux 6.18 forward-port (warden-sdk kernel/docs/bringup.md). ++ * ++ * Deliberately NOT the full vendor rv1106.dtsi: just the core needed to reach ++ * "it's alive" on the debug UART — CPU, GIC, arch timer, RAM, the CRU (our ++ * ported clk-rv1106), GRF, and uart2 (the console, driven by mainline 8250_dw). ++ * earlycon writes uart2's MMIO directly at the bootloader's divisor, so it prints ++ * before the clock/pinctrl drivers probe; the real ttyS console then needs the ++ * CRU to hand out SCLK_UART2, which is exactly what this validates on hardware. ++ * ++ * PORT-VERIFY (must be checked against the TRM / on hardware before trusting a ++ * boot — a wrong value here silently hangs the board): ++ * - memory size/base (256 MiB @ 0x0 assumed for the 86-Panel; the loader ++ * usually patches this — confirm against the real DDR init); ++ * - uart2 is the console at 0xff4c0000 (matches the vendor ttyFIQ0 base); ++ * - CRU needs no assigned-clocks here (PLLs keep their loader rates) — fine for ++ * earlycon/console, revisit for the full clock tree. ++ */ ++/dts-v1/; ++ ++#include ++#include ++#include ++ ++/ { ++ model = "WardenOS 86-Panel (RV1106) — M2 earlycon bring-up"; ++ compatible = "rockchip,rv1106"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ interrupt-parent = <&gic>; ++ ++ aliases { ++ serial2 = &uart2; ++ }; ++ ++ chosen { ++ stdout-path = "serial2:115200n8"; ++ /* ++ * earlycon with no baud = reuse the divisor the bootloader left in ++ * uart2, so the first prints work regardless of our clock tree. The ++ * ttyS console rate (1.5M) is PORT-VERIFY against the board. ++ */ ++ bootargs = "earlycon=uart8250,mmio32,0xff4c0000 console=ttyS2,115200n8 earlyprintk rootwait"; ++ }; ++ ++ memory@0 { ++ device_type = "memory"; ++ reg = <0x00000000 0x10000000>; /* 256 MiB — PORT-VERIFY */ ++ }; ++ ++ xin24m: oscillator { ++ compatible = "fixed-clock"; ++ clock-frequency = <24000000>; ++ clock-output-names = "xin24m"; ++ #clock-cells = <0>; ++ }; ++ ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a7"; ++ reg = <0x0>; ++ clocks = <&cru ARMCLK>; ++ }; ++ }; ++ ++ timer { ++ compatible = "arm,armv7-timer"; ++ interrupts = , ++ ; ++ clock-frequency = <24000000>; ++ }; ++ ++ gic: interrupt-controller@ff1f0000 { ++ compatible = "arm,gic-400"; ++ interrupt-controller; ++ #interrupt-cells = <3>; ++ #address-cells = <0>; ++ reg = <0xff1f1000 0x1000>, ++ <0xff1f2000 0x2000>, ++ <0xff1f4000 0x2000>, ++ <0xff1f6000 0x2000>; ++ interrupts = ; ++ }; ++ ++ grf: syscon@ff000000 { ++ compatible = "rockchip,rv1106-grf", "syscon", "simple-mfd"; ++ reg = <0xff000000 0x68000>; ++ ++ /* The CRU's clk-rv1106 registers a second branch set against this ++ * GRF clock-controller (grf_ctx); without the node grf_ctx is NULL ++ * and of_clk_init NULL-derefs in rockchip_clk_register_branches. */ ++ grf_cru: grf-clock-controller { ++ compatible = "rockchip,rv1106-grf-cru"; ++ #clock-cells = <1>; ++ }; ++ }; ++ ++ cru: clock-controller@ff3a0000 { ++ compatible = "rockchip,rv1106-cru"; ++ reg = <0xff3a0000 0x20000>; ++ rockchip,grf = <&grf>; ++ clocks = <&xin24m>; ++ clock-names = "xin24m"; ++ #clock-cells = <1>; ++ #reset-cells = <1>; ++ }; ++ ++ uart2: serial@ff4c0000 { ++ compatible = "rockchip,rv1106-uart", "snps,dw-apb-uart"; ++ reg = <0xff4c0000 0x100>; ++ interrupts = ; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ clock-frequency = <24000000>; ++ clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>; ++ clock-names = "baudclk", "apb_pclk"; ++ status = "okay"; ++ }; ++ ++ /* M3: the eMMC (dw_mmc). Lets the kernel enumerate mmcblk0 and mount an ++ * ext4 rootfs. ciu-drive/ciu-sample clocks come from grf_cru, so the ++ * grf-clock-controller node above is a hard dependency. */ ++ emmc: mmc@ffa90000 { ++ compatible = "rockchip,rv1106-dw-mshc", "rockchip,rk3288-dw-mshc"; ++ reg = <0xffa90000 0x4000>; ++ interrupts = ; ++ clocks = <&cru HCLK_EMMC>, <&cru CCLK_SRC_EMMC>, ++ <&grf_cru SCLK_EMMC_DRV>, <&grf_cru SCLK_EMMC_SAMPLE>; ++ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; ++ fifo-depth = <0x100>; ++ max-frequency = <200000000>; ++ rockchip,use-v2-tuning; ++ bus-width = <8>; ++ non-removable; ++ cap-mmc-highspeed; ++ mmc-hs200-1_8v; ++ status = "okay"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/rockchip/rv1106-warden.dts b/arch/arm/boot/dts/rockchip/rv1106-warden.dts +new file mode 100644 +index 000000000..c89c21d7c +--- /dev/null ++++ b/arch/arm/boot/dts/rockchip/rv1106-warden.dts +@@ -0,0 +1,346 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * WardenOS 86-Panel board DT for the self-built Linux 6.18 forward-port. ++ * ++ * Includes the full vendor rv1106.dtsi (SoC nodes + pinctrl + gpio + dmac), then ++ * enables only what our wall-HMI needs — no camera/ISP/CSI. Grows one driver ++ * batch at a time toward full parity with the 5.10 kernel (DRIVER-PARITY.md). ++ */ ++/dts-v1/; ++ ++#include ++#include "rv1106.dtsi" ++ ++/ { ++ model = "WardenOS 86-Panel (RV1106)"; ++ compatible = "rockchip,rv1106-warden", "rockchip,rv1106"; ++ ++ chosen { ++ stdout-path = "serial2:115200n8"; ++ bootargs = "earlycon=uart8250,mmio32,0xff4c0000 console=ttyS2,115200n8 earlyprintk rootwait"; ++ }; ++ ++ memory@0 { ++ device_type = "memory"; ++ reg = <0x00000000 0x10000000>; /* 256 MiB */ ++ }; ++ ++ /* --- M5: AIC8800DC wifi/BT power sequencing --- */ ++ sdio_pwrseq: sdio-pwrseq { ++ compatible = "mmc-pwrseq-simple"; ++ pinctrl-names = "default"; ++ reset-gpios = <&gpio1 RK_PA2 GPIO_ACTIVE_LOW>; ++ }; ++ ++ /* SARADC voltage reference (1.8V) — the driver reads this for scale; ++ without it saradc probes -22 (regulator_get_voltage on the dummy). */ ++ vcc_1v8: vcc-1v8 { ++ compatible = "regulator-fixed"; ++ regulator-name = "vcc_1v8"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ }; ++}; ++ ++/* --- console --- */ ++&uart2 { ++ status = "okay"; ++}; ++ ++/* --- eMMC rootfs (M3) --- */ ++&emmc { ++ bus-width = <8>; ++ cap-mmc-highspeed; ++ mmc-hs200-1_8v; ++ non-removable; ++ status = "okay"; ++}; ++ ++/* --- M5: AIC8800DC wifi/BT SDIO (on &sdmmc, mmc@ffaa0000 — NOT &sdio) --- */ ++&sdmmc { ++ max-frequency = <50000000>; ++ bus-width = <4>; ++ cap-sd-highspeed; ++ cap-sdio-irq; ++ keep-power-in-suspend; ++ non-removable; ++ rockchip,default-sample-phase = <90>; ++ supports-sdio; ++ mmc-pwrseq = <&sdio_pwrseq>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_bus4 &sdmmc0_det>; ++ status = "okay"; ++}; ++ ++/* --- batch 1: mainline peripherals (wire DT + config) --- */ ++&uart1 { ++ status = "okay"; ++}; ++ ++&uart4 { ++ status = "okay"; ++}; ++ ++/* --- GT911 capacitive touch on i2c3 (86-Panel HMI) --- ++ * The stock rootfs ships a goodix.ko built for the 5.10 kernel; it cannot load ++ * on our 6.18 (`struct module` size mismatch) so touch was dead on _b. Build ++ * CONFIG_TOUCHSCREEN_GOODIX=y instead (in the config fragment) and describe the ++ * GT911 here, matching the vendor 86-panel wiring: addr 0x14, IRQ GPIO0_A0 ++ * (edge-falling), reset GPIO3_D0 (active-low). reset-gpios + irq-gpios let the ++ * mainline goodix driver run the GT911 power-on/address-select sequence. */ ++&i2c3 { ++ status = "okay"; ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c3m2_xfer &tp_rst &tp_irq>; ++ ++ touchscreen@14 { ++ compatible = "goodix,gt911"; ++ reg = <0x14>; ++ interrupt-parent = <&gpio0>; ++ interrupts = ; ++ irq-gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>; ++ reset-gpios = <&gpio3 RK_PD0 GPIO_ACTIVE_HIGH>; ++ }; ++}; ++ ++&pinctrl { ++ touch { ++ tp_rst: tp-rst { ++ rockchip,pins = <3 RK_PD0 RK_FUNC_GPIO &pcfg_pull_up>; ++ }; ++ tp_irq: tp-irq { ++ rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ }; ++}; ++ ++&saradc { ++ vref-supply = <&vcc_1v8>; ++ status = "okay"; ++}; ++ ++&wdt { ++ status = "okay"; ++}; ++ ++/* --- M4: display (VOP + RGB → 720x720 panel + PWM backlight) --- */ ++&display_subsystem { ++ status = "okay"; ++}; ++ ++&vop { ++ status = "okay"; ++ /* mainline rockchip_drm_vop requests named "ahb" + "dclk" resets that the ++ * vendor node omits; without them vop_bind fails "failed to get ahb reset". */ ++ resets = <&cru SRST_H_VOP>, <&cru SRST_D_VOP>; ++ reset-names = "ahb", "dclk"; ++ /* ++ * The 18-bit parallel RGB output (lcd_clk + lcd_d0..d17 + den/hsync/vsync, ++ * 22 pins) must be muxed to the VOP's LCDC function or NO pixel data reaches ++ * the panel -> backlit-black even with a fully healthy DRM pipeline. The ++ * vendor board carried this mux as pinctrl-0 = <&lcd_pins> ON THE &rgb node; ++ * we deleted &rgb (dangling-endpoint graph cycle), which silently dropped it. ++ * Re-attach it here: the driver core auto-applies the "default" pinctrl state ++ * when the VOP probes, exactly like the pwm1 backlight pin. Same root cause ++ * as the dark backlight -- an unmuxed output pin group. */ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&lcd_pins>; ++}; ++ ++/* mainline wires vop_out straight to the panel (no separate rgb node) */ ++&vop_out_rgb { ++ remote-endpoint = <&panel_in_vop>; ++}; ++ ++&pwm1 { ++ status = "okay"; ++ /* mainline pwm-rockchip does NOT pinctrl_select_state("active") the way ++ * the vendor 5.10 driver did; it relies on the pinctrl core auto-applying ++ * the "default" state at probe. With "active" the pin never gets muxed to ++ * PWM, so the backlight stays dark. Use "default". */ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwm1m2_pins>; ++}; ++ ++/* ++ * NOTE on the RGB panel init MCU (WCH CH32V003, U6, net RGB_RES = GPIO0_A1): ++ * the panel controller is configured by that MCU's SPI init sequence, released ++ * once by U-Boot board_init() (stock boot). The WardenOS *userspace* (identical ++ * rootfs on _a and _b) also drives GPIO0_A1 as part of the panel bring-up, and ++ * on stock 5.10 (_a) the panel comes up fine that way. A kernel gpio-hog here ++ * FIGHTS that userspace management (two owners on the same line) and left the ++ * panel black on _b, so it is deliberately NOT hogged — matching _a, where only ++ * userspace touches the line. ++ */ ++ ++/ { ++ backlight: backlight { ++ compatible = "pwm-backlight"; ++ pwms = <&pwm1 0 100000 50000>; ++ brightness-levels = <0 32 64 96 128 160 192 224 255>; ++ default-brightness-level = <8>; ++ status = "okay"; ++ }; ++ ++ panel: panel { ++ compatible = "panel-dpi"; ++ backlight = <&backlight>; ++ /* the 86-Panel is an 18-bit parallel RGB (RGB666) panel; without a ++ * bus-format the RGB output width is unset and the screen stays ++ * black. Read by our panel-dpi patch (upstream ignores it). */ ++ bus-format = ; ++ /* ++ * Deliberately NO reset-gpios / reset-delay-ms on this node. ++ * RGB_RES (GPIO0_A1) resets the CH32V003 init MCU, which is ++ * released exactly once, early, by U-Boot board_init() (shared ++ * across A/B slots) so the MCU SPI-inits the NV3052 panel ++ * controller before Linux. Handing reset-gpios to panel-simple ++ * makes drm_panel_prepare() REBOOT the MCU while the VOP is ++ * scanning out -- Luckfox deleted these two properties upstream ++ * for exactly this reason (commit e2b0ffa22), and the flare-edge ++ * 5.10 board DTS documents them as "the fix", not a regression. ++ * Verified black-screen root cause was the VOP dclk polarity, not ++ * this line (see rockchip_drm_vop.c rgb_dclk_pol). backlight stays ++ * (U-Boot rockchip_panel.c reads its handle from this node). ++ */ ++ width-mm = <85>; ++ height-mm = <85>; ++ ++ panel-timing { ++ clock-frequency = <30000000>; ++ hactive = <720>; ++ vactive = <720>; ++ hback-porch = <44>; ++ hfront-porch = <46>; ++ vback-porch = <18>; ++ vfront-porch = <16>; ++ hsync-len = <2>; ++ vsync-len = <2>; ++ hsync-active = <0>; ++ vsync-active = <0>; ++ de-active = <0>; ++ pixelclk-active = <0>; ++ }; ++ ++ port { ++ panel_in_vop: endpoint { ++ remote-endpoint = <&vop_out_rgb>; ++ }; ++ }; ++ }; ++}; ++ ++/* The vendor rgb bridge node has no 6.18 driver and its dangling endpoint ++ * (rgb_in_vop -> vop_out_rgb) leaves a stray graph link that fw_devlink reads ++ * as a vop<->panel dependency cycle, so the VOP probes before the panel and the ++ * RGB connector is never created. DELETE it outright (disabling still left the ++ * endpoint in the graph) so vop_out_rgb <-> panel_in_vop is the only link. */ ++/delete-node/ &rgb; ++ ++/* --- sweep: USB OTG (eth0 gadget / host) via the ported inno-usb2 phy --- */ ++&u2phy { ++ status = "okay"; ++}; ++ ++&u2phy_otg { ++ status = "okay"; ++}; ++ ++&usbdrd { ++ status = "okay"; ++}; ++ ++&usbdrd_dwc3 { ++ status = "okay"; ++ dr_mode = "otg"; ++}; ++ ++/* --- sweep: RTC + thermal (tsadc) + I2S audio DAI --- */ ++&rtc { ++ status = "okay"; ++}; ++ ++&tsadc { ++ status = "okay"; ++}; ++ ++&i2s0_8ch { ++ status = "okay"; ++}; ++ ++ ++&rga2 { ++ status = "okay"; ++}; ++ ++/* --- batch A: hardware RNG (trngv1, same IP as rk3588) --- */ ++&rng { ++ compatible = "rockchip,rv1106-rng"; ++ status = "okay"; ++}; ++ ++/* --- batch A: OTP / nvmem (chip id, MAC, PHY bandgap for GMAC) --- */ ++&otp { ++ status = "okay"; ++}; ++ ++/* --- GMAC: wired 10/100 ethernet via the on-die RMII FEPHY --- */ ++&gmac { ++ status = "okay"; ++}; ++ ++/* --- audio: i2s0_8ch (DAI) -> acodec (analog codec) -> speaker/headphone, ++ * tied together by a simple-audio-card. Matches the vendor 86-Panel wiring ++ * in rv1106-luckfox-pico-86panel-ipc.dtsi. The digital speaker modulator ++ * (dsm) driver is ported and builds, but is left disabled here: the panel ++ * uses the acodec path only, and the vendor board itself ships dsm ++ * disabled. --- */ ++&acodec { ++ #sound-dai-cells = <0>; ++ status = "okay"; ++}; ++ ++&dsm { ++ status = "disabled"; ++}; ++ ++/ { ++ acodec_sound: acodec-sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "rv1106-acodec"; ++ simple-audio-card,format = "i2s"; ++ simple-audio-card,mclk-fs = <256>; ++ simple-audio-card,cpu { ++ sound-dai = <&i2s0_8ch>; ++ }; ++ simple-audio-card,codec { ++ sound-dai = <&acodec>; ++ }; ++ }; ++}; ++ ++/* --- HPMCU mailbox (A7 <-> RISC-V SCR1). Controller binds via the rk3368 ++ * fallback compatible with zero driver patch; @ff5c0000 is the HPMCU-connected ++ * instance (SRST_CORE_MCU on the Linux side, MBOX_BASE 0xFF5C0000 on the MCU ++ * side). M-MBOX-1 proves the controller; M-MBOX-2 adds the SCR1 echo + round-trip. */ ++&mailbox { ++ status = "okay"; ++}; ++ ++/* --- NPU (rknpu, ff660000). Kernel driver ported from the vendor 5.10 BSP ++ * (GPL source port -- see warden-sdk/kernel/rv1106-enablement/npu/PORT-PLAN.md ++ * and PORT-PROGRESS.md). compatible/reg/interrupts/clocks/resets are already ++ * fully specified in rv1106.dtsi's rv1106_rknpu_config-matching npu node -- ++ * this is only the status flip, same pattern as every other block enabled ++ * in this file. No iommus= property (this board's NPU runs non-iommu, ++ * matching the 5.10 boot-log finding), no power-domains (single-rail). */ ++&npu { ++ /* the rknpu driver requests its IRQ by name ("npu_irq"); the base dtsi ++ * node declares the interrupt but no interrupt-names, so probe fails ++ * "IRQ npu_irq not found" without this. */ ++ interrupt-names = "npu_irq"; ++ status = "okay"; ++}; +diff --git a/arch/arm/boot/dts/rockchip/rv1106.dtsi b/arch/arm/boot/dts/rockchip/rv1106.dtsi +new file mode 100644 +index 000000000..a6d26cc2b +--- /dev/null ++++ b/arch/arm/boot/dts/rockchip/rv1106.dtsi +@@ -0,0 +1,1554 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright (c) 2022 Rockchip Electronics Co., Ltd. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/ { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ compatible = "rockchip,rv1106"; ++ ++ interrupt-parent = <&gic>; ++ ++ aliases { ++ csi2dphy0 = &csi2_dphy0; ++ csi2dphy1 = &csi2_dphy1; ++ csi2dphy2 = &csi2_dphy2; ++ ethernet0 = &gmac; ++ gpio0 = &gpio0; ++ gpio1 = &gpio1; ++ gpio2 = &gpio2; ++ gpio3 = &gpio3; ++ gpio4 = &gpio4; ++ i2c0 = &i2c0; ++ i2c1 = &i2c1; ++ i2c2 = &i2c2; ++ i2c3 = &i2c3; ++ i2c4 = &i2c4; ++ mmc0 = &emmc; ++ mmc1 = &sdmmc; ++ mmc2 = &sdio; ++ pwm0 = &pwm0; ++ pwm1 = &pwm1; ++ pwm2 = &pwm2; ++ pwm3 = &pwm3; ++ pwm4 = &pwm4; ++ pwm5 = &pwm5; ++ pwm6 = &pwm6; ++ pwm7 = &pwm7; ++ pwm8 = &pwm8; ++ pwm9 = &pwm9; ++ pwm10 = &pwm10; ++ pwm11 = &pwm11; ++ rkcif_mipi_lvds0 = &rkcif_mipi_lvds; ++ rkcif_mipi_lvds1 = &rkcif_mipi_lvds1; ++ serial0 = &uart0; ++ serial1 = &uart1; ++ serial2 = &uart2; ++ serial3 = &uart3; ++ serial4 = &uart4; ++ serial5 = &uart5; ++ spi0 = &spi0; ++ spi1 = &spi1; ++ spi2 = &sfc; ++ }; ++ ++ clocks { ++ compatible = "simple-bus"; ++ ++ cpu_pvtpll: cpu-pvtpll { ++ compatible = "fixed-clock"; ++ clock-frequency = <1300000000>; ++ clock-output-names = "cpu_pvtpll"; ++ #clock-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ rkvenc_pvtpll: pvtpll-0 { ++ compatible = "fixed-clock"; ++ clock-frequency = <410000000>; ++ clock-output-names = "clk_pvtpll_0"; ++ #clock-cells = <0>; ++ }; ++ ++ npu_pvtpll: pvtpll-1 { ++ compatible = "fixed-clock"; ++ clock-frequency = <420000000>; ++ clock-output-names = "clk_pvtpll_1"; ++ #clock-cells = <0>; ++ }; ++ ++ xin24m: oscillator { ++ compatible = "fixed-clock"; ++ clock-frequency = <24000000>; ++ clock-output-names = "xin24m"; ++ #clock-cells = <0>; ++ }; ++ }; ++ ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a7"; ++ reg = <0x0>; ++ clocks = <&cru ARMCLK>; ++ operating-points-v2 = <&cpu0_opp_table>; ++ }; ++ }; ++ ++ cpu0_opp_table: cpu0-opp-table { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ nvmem-cells = <&cpu_leakage>; ++ nvmem-cell-names = "leakage"; ++ ++ rockchip,pvtpll-avg-offset = <0x4001c>; ++ rockchip,pvtpll-min-rate = <1104000>; ++ rockchip,pvtpll-volt-step = <12500>; ++ rockchip,grf = <&grf>; ++ rockchip,temp-hysteresis = <5000>; ++ rockchip,low-temp = <10000>; ++ rockchip,low-temp-min-volt = <900000>; ++ ++ opp-408000000 { ++ opp-hz = /bits/ 64 <408000000>; ++ opp-microvolt = <850000 850000 1000000>; ++ clock-latency-ns = <40000>; ++ }; ++ opp-600000000 { ++ opp-hz = /bits/ 64 <600000000>; ++ opp-microvolt = <850000 850000 1000000>; ++ clock-latency-ns = <40000>; ++ }; ++ opp-816000000 { ++ opp-hz = /bits/ 64 <816000000>; ++ opp-microvolt = <850000 850000 1000000>; ++ clock-latency-ns = <40000>; ++ opp-suspend; ++ }; ++ opp-1104000000 { ++ opp-hz = /bits/ 64 <1104000000>; ++ opp-microvolt = <850000 850000 1000000>; ++ clock-latency-ns = <40000>; ++ }; ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt = <850000 850000 1000000>; ++ clock-latency-ns = <40000>; ++ }; ++ opp-1296000000 { ++ opp-hz = /bits/ 64 <1296000000>; ++ opp-microvolt = <875000 850000 1000000>; ++ clock-latency-ns = <40000>; ++ }; ++ opp-1416000000 { ++ opp-hz = /bits/ 64 <1416000000>; ++ opp-microvolt = <925000 850000 1000000>; ++ clock-latency-ns = <40000>; ++ }; ++ opp-1512000000 { ++ opp-hz = /bits/ 64 <1512000000>; ++ opp-microvolt = <975000 850000 1000000>; ++ clock-latency-ns = <40000>; ++ }; ++ opp-1608000000 { ++ opp-hz = /bits/ 64 <1608000000>; ++ opp-microvolt = <1000000 850000 1000000>; ++ clock-latency-ns = <40000>; ++ }; ++ }; ++ ++ arm-pmu { ++ compatible = "arm,cortex-a7-pmu"; ++ interrupts = ; ++ interrupt-affinity = <&cpu0>; ++ }; ++ ++ cpuinfo { ++ compatible = "rockchip,cpuinfo"; ++ nvmem-cells = <&otp_id>, <&otp_cpu_version>, <&cpu_code>; ++ nvmem-cell-names = "id", "cpu-version", "cpu-code"; ++ }; ++ ++ /* dphy0 full mode */ ++ csi2_dphy0: csi2-dphy0 { ++ compatible = "rockchip,rv1106-csi2-dphy"; ++ rockchip,hw = <&csi2_dphy_hw>; ++ status = "disabled"; ++ }; ++ ++ /* dphy1 split mode 01 */ ++ csi2_dphy1: csi2-dphy1 { ++ compatible = "rockchip,rv1106-csi2-dphy"; ++ rockchip,hw = <&csi2_dphy_hw>; ++ status = "disabled"; ++ }; ++ ++ /* dphy2 split mode 23 */ ++ csi2_dphy2: csi2-dphy2 { ++ compatible = "rockchip,rv1106-csi2-dphy"; ++ rockchip,hw = <&csi2_dphy_hw>; ++ status = "disabled"; ++ }; ++ ++ display_subsystem: display-subsystem { ++ compatible = "rockchip,display-subsystem"; ++ ports = <&vop_out>; ++ status = "disabled"; ++ ++ route { ++ route_rgb: route-rgb { ++ status = "disabled"; ++ logo,uboot = "logo.bmp"; ++ logo,kernel = "logo_kernel.bmp"; ++ logo,mode = "center"; ++ charge_logo,mode = "center"; ++ connect = <&vop_out_rgb>; ++ }; ++ }; ++ }; ++ ++ fiq_debugger: fiq-debugger { ++ compatible = "rockchip,fiq-debugger"; ++ rockchip,serial-id = <2>; ++ rockchip,wake-irq = <0>; ++ rockchip,irq-mode-enable = <0>; ++ rockchip,baudrate = <115200>; /* Only 115200 and 1500000 */ ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ firmware { ++ optee: optee { ++ compatible = "linaro,optee-tz"; ++ method = "smc"; ++ status = "disabled"; ++ }; ++ }; ++ ++ mipi0_csi2: mipi0-csi2 { ++ compatible = "rockchip,rv1106-mipi-csi2"; ++ rockchip,hw = <&mipi0_csi2_hw>, <&mipi1_csi2_hw>; ++ status = "disabled"; ++ }; ++ ++ mipi1_csi2: mipi1-csi2 { ++ compatible = "rockchip,rv1106-mipi-csi2"; ++ rockchip,hw = <&mipi0_csi2_hw>, <&mipi1_csi2_hw>; ++ status = "disabled"; ++ }; ++ ++ mpp_srv: mpp-srv { ++ compatible = "rockchip,mpp-service"; ++ rockchip,taskqueue-count = <2>; ++ status = "disabled"; ++ }; ++ ++ mpp_vcodec: mpp-vcodec { ++ compatible = "rockchip,vcodec"; ++ status = "disabled"; ++ }; ++ ++ ++ rkcif_dvp: rkcif-dvp { ++ compatible = "rockchip,rkcif-dvp"; ++ rockchip,hw = <&rkcif>; ++ status = "disabled"; ++ }; ++ ++ rkcif_dvp_sditf: rkcif-dvp-sditf { ++ compatible = "rockchip,rkcif-sditf"; ++ rockchip,cif = <&rkcif_dvp>; ++ status = "disabled"; ++ }; ++ ++ rkcif_mipi_lvds: rkcif-mipi-lvds { ++ compatible = "rockchip,rkcif-mipi-lvds"; ++ rockchip,hw = <&rkcif>; ++ status = "disabled"; ++ }; ++ ++ rkcif_mipi_lvds_sditf: rkcif-mipi-lvds-sditf { ++ compatible = "rockchip,rkcif-sditf"; ++ rockchip,cif = <&rkcif_mipi_lvds>; ++ status = "disabled"; ++ }; ++ ++ rkcif_mipi_lvds1: rkcif-mipi-lvds1 { ++ compatible = "rockchip,rkcif-mipi-lvds"; ++ rockchip,hw = <&rkcif>; ++ status = "disabled"; ++ }; ++ ++ rkcif_mipi_lvds1_sditf: rkcif-mipi-lvds1-sditf { ++ compatible = "rockchip,rkcif-sditf"; ++ rockchip,cif = <&rkcif_mipi_lvds1>; ++ status = "disabled"; ++ }; ++ ++ rkisp_vir0: rkisp-vir0 { ++ compatible = "rockchip,rkisp-vir"; ++ rockchip,hw = <&rkisp>; ++ dvbm = <&rkdvbm>; ++ status = "disabled"; ++ }; ++ ++ rkisp_vir1: rkisp-vir1 { ++ compatible = "rockchip,rkisp-vir"; ++ rockchip,hw = <&rkisp>; ++ dvbm = <&rkdvbm>; ++ status = "disabled"; ++ }; ++ ++ rkisp_vir2: rkisp-vir2 { ++ compatible = "rockchip,rkisp-vir"; ++ rockchip,hw = <&rkisp>; ++ dvbm = <&rkdvbm>; ++ status = "disabled"; ++ }; ++ ++ rkisp_vir3: rkisp-vir3 { ++ compatible = "rockchip,rkisp-vir"; ++ rockchip,hw = <&rkisp>; ++ dvbm = <&rkdvbm>; ++ status = "disabled"; ++ }; ++ ++ rockchip_suspend: rockchip-suspend { ++ compatible = "rockchip,pm-config"; ++ status = "okay"; ++ rockchip,sleep-io-config = < ++ (0 ++ | RKPM_IO_CFG_IOMUX_GPIO ++ | RKPM_IO_CFG_GPIO_DIR_INPUT ++ | RKPM_IO_CFG_PULL_DOWN ++ | RKPM_IO_CFG_ID(0) ++ ) ++ (0 ++ | RKPM_IO_CFG_IOMUX_GPIO ++ | RKPM_IO_CFG_GPIO_DIR_INPUT ++ | RKPM_IO_CFG_PULL_DOWN ++ | RKPM_IO_CFG_ID(1) ++ ) ++ (0 ++ | RKPM_IO_CFG_IOMUX_GPIO ++ | RKPM_IO_CFG_GPIO_DIR_INPUT ++ | RKPM_IO_CFG_PULL_DOWN ++ | RKPM_IO_CFG_ID(2) ++ ) ++ (0 ++ | RKPM_IO_CFG_IOMUX_GPIO ++ | RKPM_IO_CFG_GPIO_DIR_INPUT ++ | RKPM_IO_CFG_PULL_UP ++ | RKPM_IO_CFG_ID(3) ++ ) ++ (0 ++ | RKPM_IO_CFG_IOMUX_GPIO ++ | RKPM_IO_CFG_GPIO_DIR_INPUT ++ | RKPM_IO_CFG_PULL_UP ++ | RKPM_IO_CFG_ID(4) ++ ) ++ (0 ++ | RKPM_IO_CFG_IOMUX_GPIO ++ | RKPM_IO_CFG_GPIO_DIR_INPUT ++ | RKPM_IO_CFG_PULL_NONE ++ | RKPM_IO_CFG_ID(5) ++ ) ++ (0 ++ | RKPM_IO_CFG_IOMUX_GPIO ++ | RKPM_IO_CFG_GPIO_DIR_INPUT ++ | RKPM_IO_CFG_PULL_NONE ++ | RKPM_IO_CFG_ID(6) ++ ) ++ >; ++ }; ++ ++ rockchip_system_monitor: rockchip-system-monitor { ++ compatible = "rockchip,system-monitor"; ++ ++ rockchip,thermal-zone = "soc-thermal"; ++ }; ++ ++ thermal_zones: thermal-zones { ++ soc_thermal: soc-thermal { ++ polling-delay-passive = <20>; /* milliseconds */ ++ polling-delay = <1000>; /* milliseconds */ ++ sustainable-power = <2100>; /* milliwatts */ ++ ++ thermal-sensors = <&tsadc 0>; ++ trips { ++ threshold: trip-point-0 { ++ temperature = <75000>; ++ hysteresis = <2000>; ++ type = "passive"; ++ }; ++ target: trip-point-1 { ++ temperature = <85000>; ++ hysteresis = <2000>; ++ type = "passive"; ++ }; ++ soc_crit: soc-crit { ++ /* millicelsius */ ++ temperature = <115000>; ++ /* millicelsius */ ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ }; ++ }; ++ }; ++ ++ timer { ++ compatible = "arm,armv7-timer"; ++ interrupts = , ++ ; ++ clock-frequency = <24000000>; ++ }; ++ ++ grf: syscon@ff000000 { ++ compatible = "rockchip,rv1106-grf", "syscon", "simple-mfd"; ++ reg = <0xff000000 0x68000>; ++ ++ grf_cru: grf-clock-controller { ++ compatible = "rockchip,rv1106-grf-cru"; ++ #clock-cells = <1>; ++ }; ++ ++ reboot_mode: reboot-mode { ++ compatible = "syscon-reboot-mode"; ++ offset = <0x20200>; ++ mode-bootloader = ; ++ mode-charge = ; ++ mode-fastboot = ; ++ mode-loader = ; ++ mode-normal = ; ++ mode-recovery = ; ++ mode-ums = ; ++ mode-panic = ; ++ mode-watchdog = ; ++ }; ++ ++ rgb: rgb { ++ compatible = "rockchip,rv1106-rgb"; ++ status = "disabled"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ reg = <0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ rgb_in_vop: endpoint@0 { ++ reg = <0>; ++ remote-endpoint = <&vop_out_rgb>; ++ }; ++ }; ++ }; ++ }; ++ ++ rknpor_powergood: rknpor-powergood { ++ compatible = "rockchip,rv1106-npor-powergood"; ++ interrupts = ; ++ status = "okay"; ++ }; ++ }; ++ ++ rtc: rtc@ff1c0000 { ++ compatible = "rockchip,rv1106-rtc"; ++ reg = <0xff1c0000 0x1000>; ++ rockchip,grf = <&grf>; ++ interrupts = ; ++ clocks = <&cru PCLK_VI_RTC_PHY>, <&cru PCLK_VI_RTC_TEST>; ++ clock-names = "pclk_phy", "pclk_test"; ++ assigned-clocks = <&cru PCLK_VI_RTC_PHY>; ++ assigned-clock-rates = <24000000>; ++ status = "disabled"; ++ }; ++ ++ gic: interrupt-controller@ff1f0000 { ++ compatible = "arm,gic-400"; ++ interrupt-controller; ++ #interrupt-cells = <3>; ++ #address-cells = <0>; ++ ++ reg = <0xff1f1000 0x1000>, ++ <0xff1f2000 0x2000>, ++ <0xff1f4000 0x2000>, ++ <0xff1f6000 0x2000>; ++ interrupts = ; ++ }; ++ ++ arm-debug@ff200000 { ++ compatible = "rockchip,debug"; ++ reg = <0xff200000 0x1000>; ++ }; ++ ++ pvtm@ff240000 { ++ compatible = "rockchip,rv1106-core-pvtm"; ++ reg = <0xff240000 0x100>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ pvtm@0 { ++ reg = <0>; ++ clocks = <&cru CLK_PVTM_CORE>; ++ clock-names = "clk"; ++ resets = <&cru SRST_PVTM_CORE>, <&cru SRST_P_PVTM_CORE>; ++ reset-names = "rst", "rst-p"; ++ }; ++ }; ++ ++ pmu: power-management@ff300000 { ++ compatible = "rockchip,rv1106-pmu", "syscon"; ++ reg = <0xff300000 0x1000>; ++ }; ++ ++ i2c0: i2c@ff310000 { ++ compatible = "rockchip,rv1106-i2c", "rockchip,rk3399-i2c"; ++ reg = <0xff310000 0x1000>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&cru CLK_I2C0>, <&cru PCLK_I2C0>; ++ clock-names = "i2c", "pclk"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c0m0_xfer>; ++ status = "disabled"; ++ }; ++ ++ i2c1: i2c@ff320000 { ++ compatible = "rockchip,rv1106-i2c", "rockchip,rk3399-i2c"; ++ reg = <0xff320000 0x1000>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&cru CLK_I2C1>, <&cru PCLK_I2C1>; ++ clock-names = "i2c", "pclk"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c1m0_xfer>; ++ status = "disabled"; ++ }; ++ ++ dsm: codec-digital@ff340000 { ++ compatible = "rockchip,rv1106-codec-digital", "rockchip,codec-digital-v1"; ++ reg = <0xff340000 0x1000>; ++ clocks = <&cru MCLK_DSM>, <&cru PCLK_DSM>; ++ clock-names = "dac", "pclk"; ++ resets = <&cru SRST_M_DSM>; ++ reset-names = "reset" ; ++ rockchip,grf = <&grf>; ++ rockchip,pwm-output-mode; ++ #sound-dai-cells = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&dsmaudio_pins>; ++ status = "disabled"; ++ }; ++ ++ pwm0: pwm@ff350000 { ++ compatible = "rockchip,rv1106-pwm", "rockchip,rk3328-pwm"; ++ reg = <0xff350000 0x10>; ++ interrupts = ; ++ #pwm-cells = <3>; ++ pinctrl-names = "active"; ++ pinctrl-0 = <&pwm0m0_pins>; ++ clocks = <&cru CLK_PWM0_PERI>, <&cru PCLK_PWM0_PERI>; ++ clock-names = "pwm", "pclk"; ++ status = "disabled"; ++ }; ++ ++ pwm1: pwm@ff350010 { ++ compatible = "rockchip,rv1106-pwm", "rockchip,rk3328-pwm"; ++ reg = <0xff350010 0x10>; ++ interrupts = ; ++ #pwm-cells = <3>; ++ pinctrl-names = "active"; ++ pinctrl-0 = <&pwm1m0_pins>; ++ clocks = <&cru CLK_PWM0_PERI>, <&cru PCLK_PWM0_PERI>; ++ clock-names = "pwm", "pclk"; ++ status = "disabled"; ++ }; ++ ++ pwm2: pwm@ff350020 { ++ compatible = "rockchip,rv1106-pwm", "rockchip,rk3328-pwm"; ++ reg = <0xff350020 0x10>; ++ interrupts = ; ++ #pwm-cells = <3>; ++ pinctrl-names = "active"; ++ pinctrl-0 = <&pwm2m0_pins>; ++ clocks = <&cru CLK_PWM0_PERI>, <&cru PCLK_PWM0_PERI>; ++ clock-names = "pwm", "pclk"; ++ status = "disabled"; ++ }; ++ ++ pwm3: pwm@ff350030 { ++ compatible = "rockchip,rv1106-pwm", "rockchip,rk3328-pwm"; ++ reg = <0xff350030 0x10>; ++ interrupts = , ++ ; ++ #pwm-cells = <3>; ++ pinctrl-names = "active"; ++ pinctrl-0 = <&pwm3m0_pins>; ++ clocks = <&cru CLK_PWM0_PERI>, <&cru PCLK_PWM0_PERI>; ++ clock-names = "pwm", "pclk"; ++ status = "disabled"; ++ }; ++ ++ pwm4: pwm@ff360000 { ++ compatible = "rockchip,rv1106-pwm", "rockchip,rk3328-pwm"; ++ reg = <0xff360000 0x10>; ++ interrupts = ; ++ #pwm-cells = <3>; ++ pinctrl-names = "active"; ++ pinctrl-0 = <&pwm4m0_pins>; ++ clocks = <&cru CLK_PWM1_PERI>, <&cru PCLK_PWM1_PERI>; ++ clock-names = "pwm", "pclk"; ++ status = "disabled"; ++ }; ++ ++ pwm5: pwm@ff360010 { ++ compatible = "rockchip,rv1106-pwm", "rockchip,rk3328-pwm"; ++ reg = <0xff360010 0x10>; ++ interrupts = ; ++ #pwm-cells = <3>; ++ pinctrl-names = "active"; ++ pinctrl-0 = <&pwm5m0_pins>; ++ clocks = <&cru CLK_PWM1_PERI>, <&cru PCLK_PWM1_PERI>; ++ clock-names = "pwm", "pclk"; ++ status = "disabled"; ++ }; ++ ++ pwm6: pwm@ff360020 { ++ compatible = "rockchip,rv1106-pwm", "rockchip,rk3328-pwm"; ++ reg = <0xff360020 0x10>; ++ interrupts = ; ++ #pwm-cells = <3>; ++ pinctrl-names = "active"; ++ pinctrl-0 = <&pwm6m0_pins>; ++ clocks = <&cru CLK_PWM1_PERI>, <&cru PCLK_PWM1_PERI>; ++ clock-names = "pwm", "pclk"; ++ status = "disabled"; ++ }; ++ ++ pwm7: pwm@ff360030 { ++ compatible = "rockchip,rv1106-pwm", "rockchip,rk3328-pwm"; ++ reg = <0xff360030 0x10>; ++ interrupts = , ++ ; ++ #pwm-cells = <3>; ++ pinctrl-names = "active"; ++ pinctrl-0 = <&pwm7m0_pins>; ++ clocks = <&cru CLK_PWM1_PERI>, <&cru PCLK_PWM1_PERI>; ++ clock-names = "pwm", "pclk"; ++ status = "disabled"; ++ }; ++ ++ pmu_mailbox: mailbox@ff378000 { ++ compatible = "rockchip,rv1106-mailbox", ++ "rockchip,rk3368-mailbox"; ++ reg = <0xff378000 0x200>; ++ interrupts = ; ++ clocks = <&cru PCLK_PMU_MAILBOX>; ++ clock-names = "pclk_mailbox"; ++ #mbox-cells = <1>; ++ status = "disabled"; ++ }; ++ ++ pmuioc: syscon@ff388000 { ++ compatible = "rockchip,rv1106-pmuioc", "syscon"; ++ reg = <0xff388000 0x1000>; ++ }; ++ ++ pvtm@ff390000 { ++ compatible = "rockchip,rv1106-pmu-pvtm"; ++ reg = <0xff390000 0x100>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ pvtm@0 { ++ reg = <1>; ++ clocks = <&cru CLK_PVTM_PMU>, <&cru PCLK_PVTM_PMU>; ++ clock-names = "clk", "pclk"; ++ resets = <&cru SRST_PVTM_PMU>, <&cru SRST_P_PVTM_PMU>; ++ reset-names = "rst", "rst-p"; ++ }; ++ }; ++ ++ cru: clock-controller@ff3a0000 { ++ compatible = "rockchip,rv1106-cru"; ++ reg = <0xff3a0000 0x20000>; ++ rockchip,grf = <&grf>; ++ #clock-cells = <1>; ++ #reset-cells = <1>; ++ ++ assigned-clocks = ++ <&cru PLL_GPLL>, <&cru PLL_CPLL>, ++ <&cru ARMCLK>, ++ <&cru ACLK_PERI_ROOT>, <&cru HCLK_PERI_ROOT>, ++ <&cru PCLK_PERI_ROOT>, <&cru ACLK_BUS_ROOT>, ++ <&cru PCLK_TOP_ROOT>, <&cru PCLK_PMU_ROOT>, ++ <&cru HCLK_PMU_ROOT>; ++ assigned-clock-rates = ++ <1188000000>, <1000000000>, ++ <1104000000>, ++ <400000000>, <200000000>, ++ <100000000>, <300000000>, ++ <100000000>, <100000000>, ++ <200000000>; ++ }; ++ ++ saradc: saradc@ff3c0000 { ++ compatible = "rockchip,rv1106-saradc"; ++ reg = <0xff3c0000 0x200>; ++ interrupts = ; ++ #io-channel-cells = <1>; ++ clocks = <&cru CLK_SARADC>, <&cru PCLK_SARADC>; ++ clock-names = "saradc", "apb_pclk"; ++ resets = <&cru SRST_P_SARADC>; ++ reset-names = "saradc-apb"; ++ status = "disabled"; ++ }; ++ ++ tsadc: tsadc@ff3c8000 { ++ compatible = "rockchip,rv1106-tsadc"; ++ reg = <0xff3c8000 0x1000>; ++ rockchip,grf = <&grf>; ++ interrupts = ; ++ clocks = <&cru CLK_TSADC>, <&cru PCLK_TSADC>, <&cru CLK_TSADC_TSEN>; ++ clock-names = "tsadc", "apb_pclk", "tsen"; ++ assigned-clocks = <&cru CLK_TSADC>, <&cru CLK_TSADC_TSEN>; ++ assigned-clock-rates = <1000000>, <12000000>; ++ resets = <&cru SRST_TSADC>, <&cru SRST_P_TSADC>; ++ reset-names = "tsadc", "tsadc-apb"; ++ #thermal-sensor-cells = <1>; ++ rockchip,hw-tshut-temp = <120000>; ++ rockchip,hw-tshut-mode = <0>; /* tshut mode 0:CRU 1:GPIO */ ++ rockchip,hw-tshut-polarity = <0>; /* tshut polarity 0:LOW 1:HIGH */ ++ status = "disabled"; ++ }; ++ ++ otp: otp@ff3d0000 { ++ compatible = "rockchip,rv1106-otp"; ++ reg = <0xff3d0000 0x4000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ clocks = <&cru CLK_USER_OTPC_NS>, <&cru CLK_SBPI_OTPC_NS>, ++ <&cru PCLK_OTPC_NS>, <&cru PCLK_OTP_MASK>, ++ <&cru CLK_OTPC_ARB>, <&cru CLK_PMC_OTP>; ++ clock-names = "usr", "sbpi", "apb", "phy", "arb", "pmc"; ++ resets = <&cru SRST_USER_OTPC_NS>, <&cru SRST_SBPI_OTPC_NS>, ++ <&cru SRST_P_OTPC_NS>, <&cru SRST_P_OTP_MASK>, ++ <&cru SRST_OTPC_ARB>, <&cru SRST_PMC_OTP>; ++ reset-names = "usr", "sbpi", "apb", "phy", "arb", "pmc"; ++ ++ /* Data cells */ ++ cpu_code: cpu-code@2 { ++ reg = <0x02 0x2>; ++ }; ++ otp_cpu_version: cpu-version@8 { ++ reg = <0x08 0x1>; ++ bits = <3 3>; ++ }; ++ otp_id: id@a { ++ reg = <0x0a 0x10>; ++ }; ++ cpu_leakage: cpu-leakage@1a { ++ reg = <0x1a 0x1>; ++ }; ++ log_leakage: log-leakage@1b { ++ reg = <0x1b 0x1>; ++ }; ++ macphy_bgs: macphy-bgs@2d { ++ reg = <0x2d 0x1>; ++ }; ++ macphy_txlevel: macphy-txlevel@2e { ++ reg = <0x2e 0x2>; ++ }; ++ }; ++ ++ u2phy: usb2-phy@ff3e0000 { ++ compatible = "rockchip,rv1106-usb2phy"; ++ reg = <0xff3e0000 0x8000>; ++ rockchip,usbgrf = <&grf>; ++ clocks = <&cru CLK_REF_USBPHY>, <&cru PCLK_USBPHY>; ++ clock-names = "phyclk", "pclk"; ++ resets = <&cru SRST_USBPHY_POR>, <&cru SRST_P_USBPHY>; ++ reset-names = "u2phy", "u2phy-apb"; ++ #clock-cells = <0>; ++ status = "disabled"; ++ ++ u2phy_otg: otg-port { ++ #phy-cells = <0>; ++ interrupts = , ++ , ++ , ++ ; ++ interrupt-names = "otg-bvalid", "otg-id", ++ "linestate", "disconnect"; ++ status = "disabled"; ++ }; ++ }; ++ ++ csi2_dphy_hw: csi2-dphy-hw@ff3e8000 { ++ compatible = "rockchip,rv1106-csi2-dphy-hw"; ++ reg = <0xff3e8000 0x8000>; ++ clocks = <&cru PCLK_MIPICSIPHY>; ++ clock-names = "pclk"; ++ resets = <&cru SRST_P_MIPICSIPHY>; ++ reset-names = "srst_p_csiphy"; ++ rockchip,grf = <&grf>; ++ status = "disabled"; ++ }; ++ ++ dmac: dma-controller@ff420000 { ++ compatible = "arm,pl330", "arm,primecell"; ++ reg = <0xff420000 0x4000>; ++ interrupts = , ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ ; ++ #dma-cells = <1>; ++ clocks = <&cru ACLK_DMAC>; ++ clock-names = "apb_pclk"; ++ arm,pl330-periph-burst; ++ }; ++ ++ crypto: crypto@ff440000 { ++ compatible = "rockchip,crypto-v3"; ++ reg = <0xff440000 0x2000>; ++ interrupts = ; ++ clocks = <&cru ACLK_CRYPTO>, <&cru HCLK_CRYPTO>, ++ <&cru CLK_CORE_CRYPTO>, <&cru CLK_PKA_CRYPTO>; ++ clock-names = "aclk", "hclk", "sclk", "pka"; ++ assigned-clocks = <&cru CLK_CORE_CRYPTO>, <&cru CLK_PKA_CRYPTO>; ++ assigned-clock-rates = <200000000>, <200000000>; ++ resets = <&cru SRST_CORE_CRYPTO>; ++ reset-names = "crypto-rst"; ++ status = "disabled"; ++ }; ++ ++ rng: rng@ff448000 { ++ compatible = "rockchip,trngv1"; ++ reg = <0xff448000 0x200>; ++ interrupts = ; ++ clocks = <&cru HCLK_TRNG_NS>; ++ clock-names = "hclk_trng"; ++ resets = <&cru SRST_H_TRNG_NS>; ++ reset-names = "reset"; ++ status = "disabled"; ++ }; ++ ++ i2c2: i2c@ff450000 { ++ compatible = "rockchip,rv1106-i2c", "rockchip,rk3399-i2c"; ++ reg = <0xff450000 0x1000>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&cru CLK_I2C2>, <&cru PCLK_I2C2>; ++ clock-names = "i2c", "pclk"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c2m0_xfer>; ++ status = "disabled"; ++ }; ++ ++ i2c3: i2c@ff460000 { ++ compatible = "rockchip,rv1106-i2c", "rockchip,rk3399-i2c"; ++ reg = <0xff460000 0x1000>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&cru CLK_I2C3>, <&cru PCLK_I2C3>; ++ clock-names = "i2c", "pclk"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c3m0_xfer>; ++ status = "disabled"; ++ }; ++ ++ i2c4: i2c@ff470000 { ++ compatible = "rockchip,rv1106-i2c", "rockchip,rk3399-i2c"; ++ reg = <0xff470000 0x1000>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&cru CLK_I2C4>, <&cru PCLK_I2C4>; ++ clock-names = "i2c", "pclk"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c4m0_xfer>; ++ status = "disabled"; ++ }; ++ ++ acodec: acodec@ff480000 { ++ compatible = "rockchip,rv1106-codec"; ++ reg = <0xff480000 0x1000>; ++ rockchip,grf = <&grf>; ++ clocks = <&cru PCLK_ACODEC>, ++ <&cru MCLK_ACODEC_TX>, ++ <&cru MCLK_I2S0_8CH_TX>; ++ clock-names = "pclk_acodec", "mclk_acodec", "mclk_cpu"; ++ resets = <&cru SRST_P_ACODEC>; ++ reset-names = "acodec-reset"; ++ acodec,micbias; ++ init-mic-gain = <0x22>; /* Left:20dB Right:20dB */ ++ status = "disabled"; ++ }; ++ ++ pwm8: pwm@ff490000 { ++ compatible = "rockchip,rv1106-pwm", "rockchip,rk3328-pwm"; ++ reg = <0xff490000 0x10>; ++ interrupts = ; ++ #pwm-cells = <3>; ++ pinctrl-names = "active"; ++ pinctrl-0 = <&pwm8m0_pins>; ++ clocks = <&cru CLK_PWM2_PERI>, <&cru PCLK_PWM2_PERI>; ++ clock-names = "pwm", "pclk"; ++ status = "disabled"; ++ }; ++ ++ pwm9: pwm@ff490010 { ++ compatible = "rockchip,rv1106-pwm", "rockchip,rk3328-pwm"; ++ reg = <0xff490010 0x10>; ++ interrupts = ; ++ #pwm-cells = <3>; ++ pinctrl-names = "active"; ++ pinctrl-0 = <&pwm9m0_pins>; ++ clocks = <&cru CLK_PWM2_PERI>, <&cru PCLK_PWM2_PERI>; ++ clock-names = "pwm", "pclk"; ++ status = "disabled"; ++ }; ++ ++ pwm10: pwm@ff490020 { ++ compatible = "rockchip,rv1106-pwm", "rockchip,rk3328-pwm"; ++ reg = <0xff490020 0x10>; ++ interrupts = ; ++ #pwm-cells = <3>; ++ pinctrl-names = "active"; ++ pinctrl-0 = <&pwm10m0_pins>; ++ clocks = <&cru CLK_PWM2_PERI>, <&cru PCLK_PWM2_PERI>; ++ clock-names = "pwm", "pclk"; ++ status = "disabled"; ++ }; ++ ++ pwm11: pwm@ff490030 { ++ compatible = "rockchip,rv1106-pwm", "rockchip,rk3328-pwm"; ++ reg = <0xff490030 0x10>; ++ interrupts = , ++ ; ++ #pwm-cells = <3>; ++ pinctrl-names = "active"; ++ pinctrl-0 = <&pwm11m0_pins>; ++ clocks = <&cru CLK_PWM2_PERI>, <&cru PCLK_PWM2_PERI>; ++ clock-names = "pwm", "pclk"; ++ status = "disabled"; ++ }; ++ ++ uart0: serial@ff4a0000 { ++ compatible = "rockchip,rv1106-uart", "snps,dw-apb-uart"; ++ reg = <0xff4a0000 0x100>; ++ interrupts = ; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ dmas = <&dmac 7>, <&dmac 6>; ++ clock-frequency = <24000000>; ++ clocks = <&cru SCLK_UART0>, <&cru PCLK_UART0>; ++ clock-names = "baudclk", "apb_pclk"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart0m0_xfer>; ++ status = "disabled"; ++ }; ++ ++ uart1: serial@ff4b0000 { ++ compatible = "rockchip,rv1106-uart", "snps,dw-apb-uart"; ++ reg = <0xff4b0000 0x100>; ++ interrupts = ; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ dmas = <&dmac 9>, <&dmac 8>; ++ clock-frequency = <24000000>; ++ clocks = <&cru SCLK_UART1>, <&cru PCLK_UART1>; ++ clock-names = "baudclk", "apb_pclk"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart1m0_xfer &uart1m0_ctsn &uart1m0_rtsn>; ++ status = "disabled"; ++ }; ++ ++ uart2: serial@ff4c0000 { ++ compatible = "rockchip,rv1106-uart", "snps,dw-apb-uart"; ++ reg = <0xff4c0000 0x100>; ++ interrupts = ; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ dmas = <&dmac 11>, <&dmac 10>; ++ clock-frequency = <24000000>; ++ clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>; ++ clock-names = "baudclk", "apb_pclk"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart2m1_xfer>; ++ status = "disabled"; ++ }; ++ ++ uart3: serial@ff4d0000 { ++ compatible = "rockchip,rv1106-uart", "snps,dw-apb-uart"; ++ reg = <0xff4d0000 0x100>; ++ interrupts = ; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ dmas = <&dmac 13>, <&dmac 12>; ++ clock-frequency = <24000000>; ++ clocks = <&cru SCLK_UART3>, <&cru PCLK_UART3>; ++ clock-names = "baudclk", "apb_pclk"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart3m0_xfer>; ++ status = "disabled"; ++ }; ++ ++ uart4: serial@ff4e0000 { ++ compatible = "rockchip,rv1106-uart", "snps,dw-apb-uart"; ++ reg = <0xff4e0000 0x100>; ++ interrupts = ; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ dmas = <&dmac 15>, <&dmac 14>; ++ clock-frequency = <24000000>; ++ clocks = <&cru SCLK_UART4>, <&cru PCLK_UART4>; ++ clock-names = "baudclk", "apb_pclk"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart4m0_xfer>; ++ status = "disabled"; ++ }; ++ ++ uart5: serial@ff4f0000 { ++ compatible = "rockchip,rv1106-uart", "snps,dw-apb-uart"; ++ reg = <0xff4f0000 0x100>; ++ interrupts = ; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ dmas = <&dmac 17>, <&dmac 16>; ++ clock-frequency = <24000000>; ++ clocks = <&cru SCLK_UART5>, <&cru PCLK_UART5>; ++ clock-names = "baudclk", "apb_pclk"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart5m0_xfer &uart5m0_ctsn &uart5m0_rtsn>; ++ status = "disabled"; ++ }; ++ ++ spi0: spi@ff500000 { ++ compatible = "rockchip,rv1106-spi", "rockchip,rk3066-spi"; ++ reg = <0xff500000 0x1000>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&cru CLK_SPI0>, <&cru PCLK_SPI0>, <&cru SCLK_IN_SPI0>; ++ clock-names = "spiclk", "apb_pclk", "sclk_in"; ++ dmas = <&dmac 1>, <&dmac 0>; ++ dma-names = "tx", "rx"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi0m0_cs0 &spi0m0_cs1 &spi0m0_pins>; ++ status = "disabled"; ++ }; ++ ++ spi1: spi@ff510000 { ++ compatible = "rockchip,rv1106-spi", "rockchip,rk3066-spi"; ++ reg = <0xff510000 0x1000>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&cru CLK_SPI1>, <&cru PCLK_SPI1>; ++ clock-names = "spiclk", "apb_pclk"; ++ assigned-clocks = <&cru CLK_SPI1>; ++ assigned-clock-rates = <200000000>; ++ dmas = <&dmac 3>, <&dmac 2>; ++ dma-names = "tx", "rx"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi1m0_cs0 &spi1m0_cs1 &spi1m0_pins>; ++ status = "disabled"; ++ }; ++ ++ hw_decompress: decompress@ff520000 { ++ compatible = "rockchip,hw-decompress"; ++ reg = <0xff520000 0x1000>; ++ interrupts = ; ++ clocks = <&cru ACLK_DECOM>, <&cru DCLK_DECOM>, <&cru PCLK_DECOM>; ++ clock-names = "aclk", "dclk", "pclk"; ++ resets = <&cru SRST_D_DECOM>; ++ reset-names = "dresetn"; ++ status = "disabled"; ++ }; ++ ++ ioc: syscon@ff538000 { ++ compatible = "rockchip,rv1106-ioc", "syscon"; ++ reg = <0xff538000 0x40000>; ++ }; ++ ++ wdt: watchdog@ff5a0000 { ++ compatible = "rockchip,rv1106-wdt", "snps,dw-wdt"; ++ reg = <0xff5a0000 0x100>; ++ clocks = <&cru TCLK_WDT_NS>, <&cru PCLK_WDT_NS>; ++ clock-names = "tclk", "pclk"; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ mailbox: mailbox@ff5c0000 { ++ compatible = "rockchip,rv1106-mailbox", ++ "rockchip,rk3368-mailbox"; ++ reg = <0xff5c0000 0x200>; ++ interrupts = ; ++ clocks = <&cru PCLK_MAILBOX>; ++ clock-names = "pclk_mailbox"; ++ #mbox-cells = <1>; ++ status = "disabled"; ++ }; ++ ++ npu: npu@ff660000 { ++ compatible = "rockchip,rv1106-rknpu"; ++ reg = <0xff660000 0x10000>; ++ interrupts = ; ++ clocks = <&cru ACLK_RKNN>, <&cru HCLK_RKNN>; ++ clock-names = "aclk", "hclk"; ++ assigned-clocks = <&cru ACLK_RKNN>; ++ assigned-clock-rates = <420000000>; ++ resets = <&cru SRST_A_RKNN>, <&cru SRST_H_RKNN>; ++ reset-names = "srst_a", "srst_h"; ++ status = "disabled"; ++ }; ++ ++ system_sram: sram@ff6c0000 { ++ compatible = "mmio-sram"; ++ reg = <0xff6c0000 0x40000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0 0xff6c0000 0x40000>; ++ rkisp_sram: rkisp-sram@0 { ++ reg = <0x0 0x3e000>; ++ }; ++ hpmcu_sram: hpmcu-sram@3e000 { ++ reg = <0x3e000 0x2000>; ++ }; ++ }; ++ ++ rga2: rga@ff980000 { ++ compatible = "rockchip,rga2_core0"; ++ reg = <0xff980000 0x1000>; ++ interrupts = ; ++ clocks = <&cru ACLK_RGA2E>, <&cru HCLK_RGA2E>, <&cru CLK_CORE_RGA2E>; ++ clock-names = "aclk_rga2", "hclk_rga2", "clk_rga2"; ++ status = "disabled"; ++ }; ++ ++ vop: vop@ff990000 { ++ compatible = "rockchip,rv1106-vop"; ++ reg = <0xff990000 0x200>; ++ reg-names = "regs"; ++ rockchip,grf = <&grf>; ++ interrupts = ; ++ clocks = <&cru ACLK_VOP>, <&cru DCLK_VOP>, <&cru HCLK_VOP>; ++ clock-names = "aclk_vop", "dclk_vop", "hclk_vop"; ++ status = "disabled"; ++ ++ vop_out: port { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ vop_out_rgb: endpoint@0 { ++ reg = <0>; ++ remote-endpoint = <&rgb_in_vop>; ++ }; ++ }; ++ }; ++ ++ sdio: mmc@ff9a0000 { ++ compatible = "rockchip,rv1106-dw-mshc", "rockchip,rk3288-dw-mshc"; ++ reg = <0xff9a0000 0x4000>; ++ interrupts = ; ++ clocks = <&cru HCLK_SDIO>, <&cru CCLK_SRC_SDIO>, ++ <&grf_cru SCLK_SDIO_DRV>, <&grf_cru SCLK_SDIO_SAMPLE>; ++ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; ++ fifo-depth = <0x100>; ++ max-frequency = <200000000>; ++ status = "disabled"; ++ }; ++ ++ rkisp: rkisp@ffa00000 { ++ compatible = "rockchip,rv1106-rkisp"; ++ reg = <0xffa00000 0x7f00>; ++ interrupts = , ++ , ++ ; ++ interrupt-names = "isp_irq", "mi_irq", "mipi_irq"; ++ clocks = <&cru ACLK_ISP3P2>, <&cru HCLK_ISP3P2>, ++ <&cru CLK_CORE_ISP3P2>, <&cru ISP0CLK_VICAP>; ++ clock-names = "aclk_isp", "hclk_isp", ++ "clk_isp_core", "clk_isp_core_vicap"; ++ rockchip,sram = <&rkisp_sram>; ++ status = "disabled"; ++ }; ++ ++ rkcif: rkcif@ffa10000 { ++ compatible = "rockchip,rv1106-cif"; ++ reg = <0xffa10000 0x10000>; ++ reg-names = "cif_regs"; ++ interrupts = ; ++ interrupt-names = "cif-intr"; ++ clocks = <&cru ACLK_VICAP>, <&cru HCLK_VICAP>, ++ <&cru DCLK_VICAP>, <&cru PCLK_VICAP>, ++ <&cru I0CLK_VICAP>, <&cru I1CLK_VICAP>, ++ <&cru RX0PCLK_VICAP>, <&cru RX1PCLK_VICAP>, ++ <&cru ISP0CLK_VICAP>, <&cru SCLK_VICAP_M0>, ++ <&cru SCLK_VICAP_M1>, <&cru PCLK_VICAP_VEPU>; ++ clock-names = "aclk_cif","hclk_cif", ++ "dclk_cif", "pclk_cif", ++ "i0clk_cif", "i1clk_cif", ++ "rx0clk_cif", "rx1clk_cif", ++ "isp0clk_cif", "sclk_m0_cif", ++ "sclk_m1_cif", "pclk_vepu_cif"; ++ resets = <&cru SRST_A_VICAP>, <&cru SRST_H_VICAP>, ++ <&cru SRST_D_VICAP>, <&cru SRST_P_VICAP>, ++ <&cru SRST_VICAP_I0>, <&cru SRST_VICAP_I1>, ++ <&cru SRST_VICAP_RX0>, <&cru SRST_VICAP_RX1>, ++ <&cru SRST_VICAP_ISP0>, <&cru SRST_P_VICAP_VEPU>; ++ reset-names = "rst_cif_a","rst_cif_h", ++ "rst_cif_d", "rst_cif_p", ++ "rst_cif_i0", "rst_cif_i1", ++ "rst_cif_rx0", "rst_cif_rx1", ++ "rst_cif_isp0", "rst_cif_pclk_vepu"; ++ rockchip,grf = <&grf>; ++ status = "disabled"; ++ }; ++ ++ mipi0_csi2_hw: mipi-csi2-hw@ffa20000 { ++ compatible = "rockchip,rv1106-mipi-csi2-hw"; ++ reg = <0xffa20000 0x10000>; ++ reg-names = "csihost_regs"; ++ interrupts = , ++ ; ++ interrupt-names = "csi-intr1", "csi-intr2"; ++ clocks = <&cru PCLK_CSIHOST0>, <&cru CLK_RXBYTECLKHS_0>; ++ clock-names = "pclk_csi2host", "clk_rxbyte_hs"; ++ resets = <&cru SRST_P_CSIHOST0>; ++ reset-names = "srst_csihost_p"; ++ status = "okay"; ++ }; ++ ++ mipi1_csi2_hw: mipi-csi2-hw@ffa30000 { ++ compatible = "rockchip,rv1106-mipi-csi2-hw"; ++ reg = <0xffa30000 0x10000>; ++ reg-names = "csihost_regs"; ++ interrupts = , ++ ; ++ interrupt-names = "csi-intr1", "csi-intr2"; ++ clocks = <&cru PCLK_CSIHOST1>, <&cru CLK_RXBYTECLKHS_1>; ++ clock-names = "pclk_csi2host", "clk_rxbyte_hs"; ++ resets = <&cru SRST_P_CSIHOST1>; ++ reset-names = "srst_csihost_p"; ++ status = "okay"; ++ }; ++ ++ rkvenc: rkvenc@ffa50000 { ++ compatible = "rockchip,rkv-encoder-rv1106"; ++ reg = <0xffa50000 0x6000>; ++ interrupts = ; ++ interrupt-names = "irq_rkvenc"; ++ clocks = <&cru ACLK_VEPU>, <&cru HCLK_VEPU>, <&cru CLK_CORE_VEPU>; ++ clock-names = "aclk_vcodec", "hclk_vcodec", "clk_core"; ++ rockchip,normal-rates = <300000000>, <0>, <410000000>; ++ assigned-clocks = <&cru ACLK_VEPU>, <&cru CLK_CORE_VEPU>; ++ assigned-clock-rates = <300000000>, <400000000>; ++ resets = <&cru SRST_A_VEPU>, <&cru SRST_H_VEPU>, <&cru SRST_CORE_VEPU>; ++ reset-names = "video_a", "video_h", "video_core"; ++ rockchip,srv = <&mpp_srv>; ++ rockchip,taskqueue-node = <0>; ++ dvbm = <&rkdvbm>; ++ status = "disabled"; ++ }; ++ ++ rkvenc_pp: rkvenc-pp@ffa60000 { ++ compatible = "rockchip,rkvenc-pp-rv1106"; ++ reg = <0xffa60000 0x900>; ++ interrupts = ; ++ interrupt-names = "irq_rkvenc_pp"; ++ clocks = <&cru ACLK_VEPU_PP>, <&cru HCLK_VEPU_PP>; ++ clock-names = "aclk_vepu_pp", "hclk_vepu_pp"; ++ assigned-clocks = <&cru ACLK_VEPU_PP>, <&cru HCLK_VEPU_PP>; ++ resets = <&cru SRST_A_VEPU_PP>, <&cru SRST_H_VEPU_PP>; ++ rockchip,srv = <&mpp_srv>; ++ rockchip,taskqueue-node = <1>; ++ status = "disabled"; ++ }; ++ ++ rkdvbm: rkdvbm@ffa70000 { ++ compatible = "rockchip,rk-dvbm"; ++ reg = <0xffa70000 0x90>; ++ interrupts = ; ++ interrupt-names = "irq_rkdvbm"; ++ clocks = <&cru CLK_CORE_VEPU_DVBM>; ++ clock-names = "clk_core"; ++ assigned-clocks = <&cru CLK_CORE_VEPU_DVBM>; ++ assigned-clock-rates = <200000000>; ++ resets = <&cru SRST_CORE_VEPU_DVBM>; ++ reset-names = "dvbm_rst"; ++ status = "disabled"; ++ }; ++ ++ gmac: ethernet@ffa80000 { ++ compatible = "rockchip,rv1106-gmac", "snps,dwmac-4.20a"; ++ reg = <0xffa80000 0x10000>; ++ interrupts = , ++ ; ++ interrupt-names = "macirq", "eth_wake_irq"; ++ rockchip,grf = <&grf>; ++ clocks = <&cru CLK_GMAC0_TX_50M_O>, <&cru CLK_GMAC0_REF_50M>, ++ <&cru ACLK_MAC>, <&cru PCLK_MAC>; ++ clock-names = "stmmaceth", "clk_mac_ref", ++ "aclk_mac", "pclk_mac"; ++ resets = <&cru SRST_A_MAC>; ++ reset-names = "stmmaceth"; ++ ++ snps,mixed-burst; ++ snps,tso; ++ ++ tx-dma-size = <256>; ++ rx-dma-size = <128>; ++ ++ snps,axi-config = <&stmmac_axi_setup>; ++ snps,mtl-rx-config = <&mtl_rx_setup>; ++ snps,mtl-tx-config = <&mtl_tx_setup>; ++ ++ phy-mode = "rmii"; ++ clock_in_out = "input"; ++ phy-handle = <&rmii_phy>; ++ ++ /* FLOW_OFF: 0, FLOW_RX: 1, FLOW_TX: 2, FLOW_AUTO: 3 */ ++ snps,flow-ctrl = <0>; ++ ++ nvmem-cells = <&macphy_bgs>; ++ nvmem-cell-names = "bgs"; ++ status = "disabled"; ++ ++ mdio: mdio { ++ compatible = "snps,dwmac-mdio"; ++ #address-cells = <0x1>; ++ #size-cells = <0x0>; ++ rmii_phy: ethernet-phy@2 { ++ compatible = "ethernet-phy-id0044.1400", "ethernet-phy-ieee802.3-c22"; ++ reg = <2>; ++ clocks = <&cru CLK_MACPHY>; ++ resets = <&cru SRST_MACPHY>; ++ phy-is-integrated; ++ nvmem-cells = <&macphy_txlevel>; ++ nvmem-cell-names = "txlevel"; ++ bgs,increment = <2>; ++ rockchip,thermal-zone = "soc-thermal"; ++ }; ++ }; ++ ++ stmmac_axi_setup: stmmac-axi-config { ++ snps,wr_osr_lmt = <4>; ++ snps,rd_osr_lmt = <8>; ++ snps,blen = <0 0 0 0 16 8 4>; ++ }; ++ ++ mtl_rx_setup: rx-queues-config { ++ snps,rx-queues-to-use = <1>; ++ queue0 { ++ status = "okay"; ++ }; ++ }; ++ ++ mtl_tx_setup: tx-queues-config { ++ snps,tx-queues-to-use = <1>; ++ queue0 { ++ status = "okay"; ++ }; ++ }; ++ }; ++ ++ emmc: mmc@ffa90000 { ++ compatible = "rockchip,rv1106-dw-mshc", "rockchip,rk3288-dw-mshc"; ++ reg = <0xffa90000 0x4000>; ++ interrupts = ; ++ clocks = <&cru HCLK_EMMC>, <&cru CCLK_SRC_EMMC>, ++ <&grf_cru SCLK_EMMC_DRV>, <&grf_cru SCLK_EMMC_SAMPLE>; ++ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; ++ fifo-depth = <0x100>; ++ max-frequency = <200000000>; ++ rockchip,use-v2-tuning; ++ status = "disabled"; ++ }; ++ ++ sdmmc: mmc@ffaa0000 { ++ compatible = "rockchip,rv1106-dw-mshc", "rockchip,rk3288-dw-mshc"; ++ reg = <0xffaa0000 0x4000>; ++ interrupts = ; ++ clocks = <&cru HCLK_SDMMC>, <&cru CCLK_SRC_SDMMC>, ++ <&grf_cru SCLK_SDMMC_DRV>, <&grf_cru SCLK_SDMMC_SAMPLE>; ++ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; ++ fifo-depth = <0x100>; ++ max-frequency = <200000000>; ++ status = "disabled"; ++ }; ++ ++ sfc: spi@ffac0000 { ++ compatible = "rockchip,sfc"; ++ reg = <0xffac0000 0x4000>; ++ interrupts = ; ++ clocks = <&cru SCLK_SFC>, <&cru HCLK_SFC>; ++ clock-names = "clk_sfc", "hclk_sfc"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ rve: rve@ffad0000 { ++ compatible = "rockchip,rve"; ++ reg = <0xffad0000 0x1000>; ++ interrupts = ; ++ clocks = <&cru ACLK_IVE>, <&cru HCLK_IVE>; ++ clock-names = "aclk_rve", "hclk_rve"; ++ status = "disabled"; ++ }; ++ ++ i2s0_8ch: i2s@ffae0000 { ++ compatible = "rockchip,rv1106-i2s-tdm", "rockchip,rv1126-i2s-tdm"; ++ reg = <0xffae0000 0x1000>; ++ interrupts = ; ++ clocks = <&cru MCLK_I2S0_8CH_TX>, <&cru MCLK_I2S0_8CH_RX>, <&cru HCLK_I2S0>; ++ clock-names = "mclk_tx", "mclk_rx", "hclk"; ++ dmas = <&dmac 22>, <&dmac 21>; ++ dma-names = "tx", "rx"; ++ resets = <&cru SRST_M_I2S0_8CH_TX>, <&cru SRST_M_I2S0_8CH_RX>; ++ reset-names = "tx-m", "rx-m"; ++ rockchip,clk-trcm = <1>; ++ #sound-dai-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ usbdrd: usbdrd { ++ compatible = "rockchip,rv1106-dwc3", "rockchip,rk3399-dwc3"; ++ clocks = <&cru CLK_REF_USBOTG>, <&cru CLK_UTMI_USBOTG>, ++ <&cru ACLK_USBOTG>; ++ clock-names = "ref", "utmi", "bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ status = "disabled"; ++ ++ usbdrd_dwc3: usb@ffb00000 { ++ compatible = "snps,dwc3"; ++ reg = <0xffb00000 0x100000>; ++ interrupts = ; ++ resets = <&cru SRST_A_USBOTG>; ++ reset-names = "usb3-otg"; ++ dr_mode = "otg"; ++ maximum-speed = "high-speed"; ++ phys = <&u2phy_otg>; ++ phy-names = "usb2-phy"; ++ phy_type = "utmi_wide"; ++ snps,dis_enblslpm_quirk; ++ snps,dis-u2-freeclk-exists-quirk; ++ snps,dis_u2_susphy_quirk; ++ snps,dis-del-phy-power-chg-quirk; ++ snps,dis-tx-ipgap-linecheck-quirk; ++ snps,usb2-gadget-lpm-disable; ++ snps,usb2-lpm-disable; ++ snps,parkmode-disable-hs-quirk; ++ status = "disabled"; ++ }; ++ }; ++ ++ pinctrl: pinctrl { ++ compatible = "rockchip,rv1106-pinctrl"; ++ rockchip,grf = <&ioc>; ++ rockchip,pmu = <&pmuioc>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ gpio0: gpio@ff380000 { ++ compatible = "rockchip,gpio-bank"; ++ reg = <0xff380000 0x100>; ++ interrupts = ; ++ clocks = <&cru PCLK_PMU_GPIO0>, <&cru DBCLK_PMU_GPIO0>; ++ ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pinctrl 0 0 32>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio1: gpio@ff530000 { ++ compatible = "rockchip,gpio-bank"; ++ reg = <0xff530000 0x100>; ++ interrupts = ; ++ clocks = <&cru PCLK_GPIO1>, <&cru DBCLK_GPIO1>; ++ ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pinctrl 0 32 32>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio2: gpio@ff540000 { ++ compatible = "rockchip,gpio-bank"; ++ reg = <0xff540000 0x100>; ++ interrupts = ; ++ clocks = <&cru PCLK_GPIO2>, <&cru DBCLK_GPIO2>; ++ ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pinctrl 0 64 32>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio3: gpio@ff550000 { ++ compatible = "rockchip,gpio-bank"; ++ reg = <0xff550000 0x100>; ++ interrupts = ; ++ clocks = <&cru PCLK_GPIO3>, <&cru DBCLK_GPIO3>; ++ ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pinctrl 0 96 32>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio4: gpio@ff560000 { ++ compatible = "rockchip,gpio-bank"; ++ reg = <0xff560000 0x100>; ++ interrupts = ; ++ clocks = <&cru PCLK_GPIO4>, <&cru DBCLK_GPIO4>; ++ ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&pinctrl 0 128 32>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ }; ++}; ++ ++#include "rv1106-pinctrl.dtsi" +diff --git a/arch/arm/mach-rockchip/rockchip.c b/arch/arm/mach-rockchip/rockchip.c +index 82102fbab..19547418f 100644 +--- a/arch/arm/mach-rockchip/rockchip.c ++++ b/arch/arm/mach-rockchip/rockchip.c +@@ -58,6 +58,8 @@ static const char * const rockchip_board_dt_compat[] = { + "rockchip,rk3188", + "rockchip,rk3228", + "rockchip,rk3288", ++ "rockchip,rv1103", ++ "rockchip,rv1106", + "rockchip,rv1108", + NULL, + }; +diff --git a/include/dt-bindings/clock/rv1106-cru.h b/include/dt-bindings/clock/rv1106-cru.h +new file mode 100644 +index 000000000..95d3652fa +--- /dev/null ++++ b/include/dt-bindings/clock/rv1106-cru.h +@@ -0,0 +1,571 @@ ++/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ ++/* ++ * Copyright (c) 2022 Rockchip Electronics Co. Ltd. ++ * Author: Elaine Zhang ++ */ ++ ++#ifndef _DT_BINDINGS_CLK_ROCKCHIP_RV1106_H ++#define _DT_BINDINGS_CLK_ROCKCHIP_RV1106_H ++ ++/* pll clocks */ ++#define PLL_APLL 1 ++#define PLL_DPLL 2 ++#define PLL_CPLL 3 ++#define PLL_GPLL 4 ++#define ARMCLK 5 ++ ++/* clk (clocks) */ ++#define PCLK_DDRPHY 11 ++#define PCLK_DDR_ROOT 12 ++#define PCLK_DDRMON 13 ++#define CLK_TIMER_DDRMON 14 ++#define PCLK_DDRC 15 ++#define PCLK_DFICTRL 16 ++#define ACLK_DDR_ROOT 17 ++#define ACLK_SYS_SHRM 18 ++#define HCLK_NPU_ROOT 19 ++#define ACLK_NPU_ROOT 20 ++#define PCLK_NPU_ROOT 21 ++#define HCLK_RKNN 22 ++#define ACLK_RKNN 23 ++#define PCLK_ACODEC 24 ++#define MCLK_ACODEC_TX 25 ++#define CLK_CORE_CRYPTO 27 ++#define CLK_PKA_CRYPTO 28 ++#define ACLK_CRYPTO 29 ++#define HCLK_CRYPTO 30 ++#define ACLK_DECOM 31 ++#define PCLK_DECOM 32 ++#define DCLK_DECOM 33 ++#define ACLK_DMAC 34 ++#define PCLK_DSM 35 ++#define MCLK_DSM 36 ++#define CCLK_SRC_EMMC 37 ++#define HCLK_EMMC 38 ++#define PCLK_GPIO4 39 ++#define DBCLK_GPIO4 40 ++#define PCLK_I2C0 41 ++#define CLK_I2C0 42 ++#define PCLK_I2C2 43 ++#define CLK_I2C2 44 ++#define PCLK_I2C3 45 ++#define CLK_I2C3 46 ++#define PCLK_I2C4 47 ++#define CLK_I2C4 48 ++#define HCLK_I2S0 49 ++#define PCLK_DFT2APB 50 ++#define HCLK_IVE 51 ++#define ACLK_IVE 52 ++#define PCLK_PWM0_PERI 53 ++#define CLK_PWM0_PERI 54 ++#define CLK_CAPTURE_PWM0_PERI 55 ++#define PCLK_PERI_ROOT 56 ++#define ACLK_PERI_ROOT 57 ++#define HCLK_PERI_ROOT 58 ++#define CLK_TIMER_ROOT 59 ++#define ACLK_BUS_ROOT 60 ++#define HCLK_SFC 61 ++#define SCLK_SFC 62 ++#define PCLK_UART0 63 ++#define CLK_PVTM_CORE 64 ++#define PCLK_UART1 65 ++#define CLK_CORE_MCU_RTC 66 ++#define PCLK_PWM1_PERI 67 ++#define CLK_PWM1_PERI 68 ++#define CLK_CAPTURE_PWM1_PERI 69 ++#define PCLK_PWM2_PERI 70 ++#define CLK_PWM2_PERI 71 ++#define CLK_CAPTURE_PWM2_PERI 72 ++#define HCLK_BOOTROM 73 ++#define HCLK_SAI 74 ++#define MCLK_SAI 75 ++#define PCLK_SARADC 76 ++#define CLK_SARADC 77 ++#define PCLK_SPI1 78 ++#define CLK_SPI1 79 ++#define PCLK_STIMER 80 ++#define CLK_STIMER0 81 ++#define CLK_STIMER1 82 ++#define PCLK_TIMER 83 ++#define CLK_TIMER0 84 ++#define CLK_TIMER1 85 ++#define CLK_TIMER2 86 ++#define CLK_TIMER3 87 ++#define CLK_TIMER4 88 ++#define CLK_TIMER5 89 ++#define HCLK_TRNG_NS 90 ++#define HCLK_TRNG_S 91 ++#define PCLK_UART2 92 ++#define HCLK_CPU 93 ++#define PCLK_UART3 94 ++#define CLK_CORE_MCU 95 ++#define PCLK_UART4 96 ++#define PCLK_DDR_HWLP 97 ++#define PCLK_UART5 98 ++#define ACLK_USBOTG 100 ++#define CLK_REF_USBOTG 101 ++#define CLK_UTMI_USBOTG 102 ++#define PCLK_USBPHY 103 ++#define CLK_REF_USBPHY 104 ++#define PCLK_WDT_NS 105 ++#define TCLK_WDT_NS 106 ++#define PCLK_WDT_S 107 ++#define TCLK_WDT_S 108 ++#define CLK_DDR_FAIL_SAFE 109 ++#define XIN_OSC0_DIV 110 ++#define CLK_DEEPSLOW 111 ++#define PCLK_PMU_GPIO0 112 ++#define DBCLK_PMU_GPIO0 113 ++#define CLK_PMU 114 ++#define PCLK_PMU 115 ++#define PCLK_PMU_HP_TIMER 116 ++#define CLK_PMU_HP_TIMER 117 ++#define CLK_PMU_32K_HP_TIMER 118 ++#define PCLK_I2C1 119 ++#define CLK_I2C1 120 ++#define PCLK_PMU_IOC 121 ++#define PCLK_PMU_MAILBOX 122 ++#define CLK_PMU_MCU 123 ++#define CLK_PMU_MCU_RTC 124 ++#define CLK_PMU_MCU_JTAG 125 ++#define CLK_PVTM_PMU 126 ++#define PCLK_PVTM_PMU 127 ++#define CLK_REFOUT 128 ++#define CLK_100M_PMU 129 ++#define PCLK_PMU_ROOT 130 ++#define HCLK_PMU_ROOT 131 ++#define HCLK_PMU_SRAM 132 ++#define PCLK_PMU_WDT 133 ++#define TCLK_PMU_WDT 134 ++#define CLK_DFICTRL 135 ++#define CLK_DDRMON 136 ++#define CLK_DDR_PHY 137 ++#define ACLK_DDRC 138 ++#define CLK_CORE_DDRC_SRC 139 ++#define CLK_CORE_DDRC 140 ++#define CLK_50M_SRC 141 ++#define CLK_100M_SRC 142 ++#define CLK_150M_SRC 143 ++#define CLK_200M_SRC 144 ++#define CLK_250M_SRC 145 ++#define CLK_300M_SRC 146 ++#define CLK_339M_SRC 147 ++#define CLK_400M_SRC 148 ++#define CLK_450M_SRC 149 ++#define CLK_500M_SRC 150 ++#define CLK_I2S0_8CH_TX_SRC 151 ++#define CLK_I2S0_8CH_TX_FRAC 152 ++#define CLK_I2S0_8CH_TX 153 ++#define CLK_I2S0_8CH_RX_SRC 154 ++#define CLK_I2S0_8CH_RX_FRAC 155 ++#define CLK_I2S0_8CH_RX 156 ++#define I2S0_8CH_MCLKOUT 157 ++#define MCLK_I2S0_8CH_RX 158 ++#define MCLK_I2S0_8CH_TX 159 ++#define CLK_REF_MIPI0_SRC 160 ++#define CLK_REF_MIPI0_FRAC 161 ++#define CLK_REF_MIPI0_OUT 162 ++#define CLK_REF_MIPI1_SRC 163 ++#define CLK_REF_MIPI1_FRAC 164 ++#define MCLK_REF_MIPI0 165 ++#define MCLK_REF_MIPI1 166 ++#define CLK_REF_MIPI0 167 ++#define CLK_REF_MIPI1 168 ++#define CLK_UART0_SRC 169 ++#define CLK_UART0_FRAC 170 ++#define CLK_UART0 171 ++#define SCLK_UART0 172 ++#define CLK_UART1_SRC 173 ++#define CLK_UART1_FRAC 174 ++#define CLK_UART1 175 ++#define SCLK_UART1 176 ++#define CLK_UART2_SRC 177 ++#define CLK_UART2_FRAC 178 ++#define CLK_UART2 179 ++#define SCLK_UART2 180 ++#define CLK_UART3_SRC 181 ++#define CLK_UART3_FRAC 182 ++#define CLK_UART3 183 ++#define SCLK_UART3 184 ++#define CLK_UART4_SRC 185 ++#define CLK_UART4_FRAC 186 ++#define CLK_UART4 187 ++#define SCLK_UART4 188 ++#define CLK_UART5_SRC 189 ++#define CLK_UART5_FRAC 190 ++#define CLK_UART5 191 ++#define SCLK_UART5 192 ++#define CLK_VICAP_M0_SRC 193 ++#define CLK_VICAP_M0_FRAC 194 ++#define CLK_VICAP_M0 195 ++#define SCLK_VICAP_M0 196 ++#define CLK_VICAP_M1_SRC 197 ++#define CLK_VICAP_M1_FRAC 198 ++#define CLK_VICAP_M1 199 ++#define SCLK_VICAP_M1 200 ++#define DCLK_VOP_SRC 201 ++#define PCLK_CRU 202 ++#define PCLK_TOP_ROOT 203 ++#define PCLK_SPI0 204 ++#define CLK_SPI0 205 ++#define SCLK_IN_SPI0 206 ++#define CLK_UART_DETN_FLT 207 ++#define HCLK_VEPU 208 ++#define ACLK_VEPU 209 ++#define CLK_CORE_VEPU 210 ++#define CLK_CORE_VEPU_DVBM 211 ++#define PCLK_GPIO1 212 ++#define DBCLK_GPIO1 213 ++#define HCLK_VEPU_PP 214 ++#define ACLK_VEPU_PP 215 ++#define HCLK_VEPU_ROOT 216 ++#define ACLK_VEPU_COM_ROOT 217 ++#define ACLK_VEPU_ROOT 218 ++#define PCLK_VEPU_ROOT 219 ++#define PCLK_VICAP_VEPU 220 ++#define PCLK_CSIHOST0 221 ++#define CLK_RXBYTECLKHS_0 222 ++#define PCLK_CSIHOST1 223 ++#define CLK_RXBYTECLKHS_1 224 ++#define PCLK_GPIO3 225 ++#define DBCLK_GPIO3 226 ++#define HCLK_ISP3P2 227 ++#define ACLK_ISP3P2 228 ++#define CLK_CORE_ISP3P2 229 ++#define PCLK_MIPICSIPHY 230 ++#define CCLK_SRC_SDMMC 231 ++#define HCLK_SDMMC 232 ++#define CLK_SDMMC_DETN_FLT 233 ++#define HCLK_VI_ROOT 234 ++#define ACLK_VI_ROOT 235 ++#define PCLK_VI_ROOT 236 ++#define PCLK_VI_RTC_ROOT 237 ++#define PCLK_VI_RTC_TEST 238 ++#define PCLK_VI_RTC_PHY 239 ++#define DCLK_VICAP 240 ++#define PCLK_VICAP 241 ++#define ACLK_VICAP 242 ++#define HCLK_VICAP 243 ++#define I0CLK_VICAP 244 ++#define I1CLK_VICAP 245 ++#define RX0PCLK_VICAP 246 ++#define RX1PCLK_VICAP 247 ++#define ISP0CLK_VICAP 248 ++#define PCLK_GPIO2 249 ++#define DBCLK_GPIO2 250 ++#define ACLK_MAC 251 ++#define PCLK_MAC 252 ++#define CLK_GMAC0_50M_O 253 ++#define CLK_GMAC0_TX_50M_O 254 ++#define CLK_GMAC0_REF_50M 255 ++#define CLK_GMAC0_TX_50M 256 ++#define CLK_GMAC0_RX_50M 257 ++#define ACLK_MAC_ROOT 258 ++#define CLK_MACPHY 259 ++#define CLK_OTPC_ARB 260 ++#define PCLK_OTPC_NS 261 ++#define CLK_SBPI_OTPC_NS 262 ++#define CLK_USER_OTPC_NS 263 ++#define PCLK_OTPC_S 264 ++#define CLK_SBPI_OTPC_S 265 ++#define CLK_USER_OTPC_S 266 ++#define PCLK_OTP_MASK 267 ++#define CLK_PMC_OTP 268 ++#define HCLK_RGA2E 269 ++#define ACLK_RGA2E 270 ++#define CLK_CORE_RGA2E 271 ++#define CCLK_SRC_SDIO 272 ++#define HCLK_SDIO 273 ++#define PCLK_TSADC 274 ++#define CLK_TSADC 275 ++#define CLK_TSADC_TSEN 276 ++#define ACLK_VO_ROOT 277 ++#define HCLK_VO_ROOT 278 ++#define PCLK_VO_ROOT 279 ++#define ACLK_VOP_ROOT 280 ++#define HCLK_VOP 281 ++#define DCLK_VOP 282 ++#define ACLK_VOP 283 ++#define CLK_RTC_32K 284 ++#define PCLK_MAILBOX 291 ++ ++#define CLK_NR_CLKS (PCLK_MAILBOX + 1) ++ ++#define SCLK_EMMC_DRV 1 ++#define SCLK_EMMC_SAMPLE 2 ++#define SCLK_SDMMC_DRV 3 ++#define SCLK_SDMMC_SAMPLE 4 ++#define SCLK_SDIO_DRV 5 ++#define SCLK_SDIO_SAMPLE 6 ++ ++#define CLK_NR_GRF_CLKS (SCLK_SDIO_SAMPLE + 1) ++ ++/********Name=PMUSOFTRST_CON00,Offset=0xA00********/ ++#define SRST_P_I2C1 3 ++#define SRST_I2C1 4 ++#define SRST_H_PMU_BIU 6 ++#define SRST_P_PMU_BIU 7 ++#define SRST_H_PMU_SRAM 8 ++#define SRST_PMU_MCU 9 ++#define SRST_PMU_MCU_PWRUP 10 ++#define SRST_PMU_MCU_CPU 11 ++#define SRST_T_PMU_MCU_CPU 12 ++/********Name=PMUSOFTRST_CON01,Offset=0xA04********/ ++#define SRST_P_PMU_GPIO0 18 ++#define SRST_PMU_GPIO0 19 ++#define SRST_PVTM_PMU 20 ++#define SRST_P_PVTM_PMU 21 ++#define SRST_DDR_FAIL_SAFE 31 ++/********Name=PMUSOFTRST_CON02,Offset=0xA08********/ ++#define SRST_P_PMU_HP_TIMER 32 ++#define SRST_PMU_HP_TIMER 33 ++#define SRST_PMU_32K_HP_TIMER 34 ++#define SRST_P_PMU_IOC 35 ++#define SRST_P_PMU_CRU 36 ++#define SRST_P_PMU_GRF 37 ++#define SRST_P_PMU_SGRF 38 ++#define SRST_P_PMU_SGRF_REMAP 39 ++#define SRST_P_PMU_WDT 40 ++#define SRST_T_PMU_WDT 41 ++#define SRST_P_PMU_MAILBOX 42 ++#define SRST_WRITE_ENABLE 48 ++/********Name=SOFTRST_CON02,Offset=0x10A08********/ ++#define SRST_REF_PVTPLL_0 262183 ++#define SRST_REF_PVTPLL_1 262184 ++#define SRST_P_CRU 262186 ++#define SRST_P_CRU_BIU 262187 ++/********Name=PERISOFTRST_CON00,Offset=0x12A00********/ ++#define SRST_P_PERI_BIU 294916 ++#define SRST_A_PERI_BIU 294917 ++#define SRST_H_PERI_BIU 294918 ++#define SRST_H_BOOTROM 294919 ++#define SRST_P_TIMER 294920 ++#define SRST_TIMER0 294921 ++#define SRST_TIMER1 294922 ++#define SRST_TIMER2 294923 ++#define SRST_TIMER3 294924 ++#define SRST_TIMER4 294925 ++#define SRST_TIMER5 294926 ++#define SRST_P_STIMER 294927 ++/********Name=PERISOFTRST_CON01,Offset=0x12A04********/ ++#define SRST_STIMER0 294928 ++#define SRST_STIMER1 294929 ++#define SRST_P_WDT_NS 294930 ++#define SRST_T_WDT_NS 294931 ++#define SRST_P_WDT_S 294932 ++#define SRST_T_WDT_S 294933 ++#define SRST_P_I2C0 294934 ++#define SRST_I2C0 294935 ++#define SRST_P_I2C2 294938 ++#define SRST_I2C2 294939 ++#define SRST_P_I2C3 294940 ++#define SRST_I2C3 294941 ++#define SRST_P_I2C4 294942 ++#define SRST_I2C4 294943 ++/********Name=PERISOFTRST_CON02,Offset=0x12A08********/ ++#define SRST_P_GPIO4 294944 ++#define SRST_GPIO4 294945 ++#define SRST_P_PERI_IOC 294946 ++#define SRST_P_UART2 294947 ++#define SRST_S_UART2 294950 ++#define SRST_P_UART3 294951 ++#define SRST_S_UART3 294954 ++#define SRST_P_UART4 294955 ++#define SRST_S_UART4 294958 ++#define SRST_P_UART5 294959 ++/********Name=PERISOFTRST_CON03,Offset=0x12A0C********/ ++#define SRST_S_UART5 294962 ++#define SRST_P_SARADC 294963 ++#define SRST_SARADC 294964 ++#define SRST_SARADC_PHY 294965 ++#define SRST_P_SPI1 294966 ++#define SRST_SPI1 294967 ++#define SRST_H_TRNG_NS 294969 ++#define SRST_H_TRNG_S 294970 ++#define SRST_CORE_CRYPTO 294971 ++#define SRST_PKA_CRYPTO 294972 ++#define SRST_A_CRYPTO 294973 ++#define SRST_H_CRYPTO 294974 ++#define SRST_P_PWM1_PERI 294975 ++/********Name=PERISOFTRST_CON04,Offset=0x12A10********/ ++#define SRST_PWM1_PERI 294976 ++#define SRST_P_PWM2_PERI 294978 ++#define SRST_PWM2_PERI 294979 ++#define SRST_P_PERI_GRF 294981 ++#define SRST_P_PERI_CRU 294982 ++#define SRST_A_USBOTG 294983 ++#define SRST_A_BUS_BIU 294986 ++#define SRST_H_EMMC 294989 ++#define SRST_H_SFC 294990 ++/********Name=PERISOFTRST_CON05,Offset=0x12A14********/ ++#define SRST_S_SFC 294992 ++#define SRST_P_USBPHY 294993 ++#define SRST_USBPHY_POR 294994 ++#define SRST_USBPHY_OTG 294995 ++#define SRST_A_DMAC 295000 ++#define SRST_A_DECOM 295001 ++#define SRST_P_DECOM 295002 ++#define SRST_D_DECOM 295003 ++#define SRST_P_PERI_SGRF 295004 ++#define SRST_H_SAI 295005 ++#define SRST_M_SAI 295006 ++#define SRST_M_I2S0_8CH_TX 295007 ++/********Name=PERISOFTRST_CON06,Offset=0x12A18********/ ++#define SRST_H_I2S0 295008 ++#define SRST_M_DSM 295009 ++#define SRST_P_DSM 295010 ++#define SRST_P_ACODEC 295011 ++#define SRST_M_I2S0_8CH_RX 295014 ++#define SRST_P_DFT2APB 295015 ++#define SRST_H_IVE 295017 ++#define SRST_A_IVE 295018 ++#define SRST_P_UART0 295019 ++#define SRST_S_UART0 295022 ++#define SRST_P_UART1 295023 ++/********Name=PERISOFTRST_CON07,Offset=0x12A1C********/ ++#define SRST_S_UART1 295026 ++#define SRST_P_PWM0_PERI 295027 ++#define SRST_PWM0_PERI 295028 ++/********Name=VISOFTRST_CON00,Offset=0x14A00********/ ++#define SRST_H_VI_BIU 327684 ++#define SRST_A_VI_BIU 327685 ++#define SRST_P_VI_BIU 327686 ++#define SRST_CORE_ISP3P2 327689 ++#define SRST_D_VICAP 327690 ++#define SRST_P_VICAP 327691 ++#define SRST_A_VICAP 327692 ++#define SRST_H_VICAP 327693 ++#define SRST_VICAP_I0 327694 ++#define SRST_VICAP_I1 327695 ++/********Name=VISOFTRST_CON01,Offset=0x14A04********/ ++#define SRST_VICAP_RX0 327696 ++#define SRST_VICAP_RX1 327697 ++#define SRST_VICAP_ISP0 327698 ++#define SRST_P_CSIHOST0 327700 ++#define SRST_P_CSIHOST1 327702 ++#define SRST_H_SDMMC 327708 ++#define SRST_SDMMC_DETN_FLT 327709 ++#define SRST_P_MIPICSIPHY 327710 ++#define SRST_P_GPIO3 327711 ++/********Name=VISOFTRST_CON02,Offset=0x14A08********/ ++#define SRST_GPIO3 327712 ++#define SRST_P_VI_IOC 327713 ++#define SRST_P_VI_GRF 327714 ++#define SRST_P_VI_SGRF 327715 ++#define SRST_P_VI_CRU 327716 ++#define SRST_P_VI_RTC_TEST 327717 ++#define SRST_P_VI_RTC_NIU 327719 ++/********Name=NPUSOFTRST_CON00,Offset=0x16A00********/ ++#define SRST_H_NPU_BIU 360451 ++#define SRST_A_NPU_BIU 360452 ++#define SRST_P_NPU_BIU 360453 ++#define SRST_P_NPU_CRU 360454 ++#define SRST_P_NPU_SGRF 360455 ++#define SRST_P_NPU_GRF 360456 ++#define SRST_H_RKNN 360457 ++#define SRST_A_RKNN 360458 ++/********Name=CORESOFTRST_CON00,Offset=0x18A00********/ ++#define SRST_NCOREPORESET 393217 ++#define SRST_NCORESET 393218 ++#define SRST_NDBGRESET 393219 ++#define SRST_NL2RESET 393220 ++#define SRST_A_M_CORE_BIU 393221 ++#define SRST_P_DBG 393222 ++#define SRST_POT_DBG 393223 ++#define SRST_NT_DBG 393224 ++#define SRST_P_CORE_GRF 393227 ++#define SRST_H_CPU_BIU 393228 ++#define SRST_P_CPU_BIU 393229 ++#define SRST_PVTM_CORE 393230 ++#define SRST_P_PVTM_CORE 393231 ++/********Name=CORESOFTRST_CON01,Offset=0x18A04********/ ++#define SRST_REF_PVTPLL_CORE 393232 ++#define SRST_CORE_MCU 393233 ++#define SRST_CORE_MCU_PWRUP 393234 ++#define SRST_CORE_MCU_CPU 393235 ++#define SRST_T_CORE_MCU_CPU 393236 ++#define SRST_MCU_BIU 393237 ++#define SRST_P_MAILBOX 393240 ++#define SRST_P_INTMUX 393241 ++#define SRST_P_CORE_CRU 393242 ++#define SRST_P_CORE_SGRF 393243 ++#define SRST_H_CACHE 393244 ++/********Name=VEPUSOFTRST_CON00,Offset=0x1AA00********/ ++#define SRST_H_VEPU_BIU 425988 ++#define SRST_A_VEPU_BIU 425989 ++#define SRST_A_VEPU_COM_BIU 425990 ++#define SRST_P_VEPU_BIU 425991 ++#define SRST_H_VEPU 425992 ++#define SRST_A_VEPU 425993 ++#define SRST_CORE_VEPU 425994 ++#define SRST_H_VEPU_PP 425995 ++#define SRST_A_VEPU_PP 425996 ++#define SRST_CORE_VEPU_DVBM 425997 ++#define SRST_P_VICAP_VEPU 425998 ++#define SRST_P_GPIO1 425999 ++/********Name=VEPUSOFTRST_CON01,Offset=0x1AA04********/ ++#define SRST_GPIO1 426000 ++#define SRST_P_VEPU_IOC 426001 ++#define SRST_P_SPI0 426002 ++#define SRST_SPI0 426003 ++#define SRST_P_VEPU_CRU 426005 ++#define SRST_P_VEPU_SGRF 426006 ++#define SRST_P_VEPU_GRF 426007 ++#define SRST_UART_DETN_FLT 426008 ++/********Name=VOSOFTRST_CON00,Offset=0x1CA00********/ ++#define SRST_A_VO_BIU 458755 ++#define SRST_H_VO_BIU 458756 ++#define SRST_H_RGA2E 458759 ++#define SRST_A_RGA2E 458760 ++#define SRST_CORE_RGA2E 458761 ++#define SRST_P_VO_GRF 458762 ++#define SRST_A_VOP_BIU 458764 ++#define SRST_H_VOP 458765 ++#define SRST_D_VOP 458766 ++#define SRST_A_VOP 458767 ++/********Name=VOSOFTRST_CON01,Offset=0x1CA04********/ ++#define SRST_P_MAC_BIU 458774 ++#define SRST_A_MAC_BIU 458775 ++#define SRST_A_MAC 458776 ++#define SRST_P_VO_SGRF 458780 ++#define SRST_P_VO_CRU 458781 ++#define SRST_H_SDIO 458783 ++/********Name=VOSOFTRST_CON02,Offset=0x1CA08********/ ++#define SRST_P_TSADC 458784 ++#define SRST_TSADC 458785 ++#define SRST_P_OTPC_NS 458787 ++#define SRST_SBPI_OTPC_NS 458789 ++#define SRST_USER_OTPC_NS 458790 ++#define SRST_P_OTPC_S 458791 ++#define SRST_SBPI_OTPC_S 458793 ++#define SRST_USER_OTPC_S 458794 ++#define SRST_OTPC_ARB 458795 ++#define SRST_MACPHY 458797 ++#define SRST_P_OTP_MASK 458798 ++#define SRST_PMC_OTP 458799 ++/********Name=VOSOFTRST_CON03,Offset=0x1CA0C********/ ++#define SRST_P_GPIO2 458800 ++#define SRST_GPIO2 458801 ++#define SRST_P_VO_IOC 458802 ++/********Name=DDRSOFTRST_CON00,Offset=0x1EA00********/ ++#define SRST_P_DDR_BIU 491522 ++#define SRST_P_DDRC 491525 ++#define SRST_P_DDRMON 491527 ++#define SRST_TIMER_DDRMON 491528 ++#define SRST_P_DFICTRL 491531 ++#define SRST_A_SYS_SHRM 491533 ++#define SRST_A_SHRM_NIU 491534 ++#define SRST_P_DDR_GRF 491535 ++/********Name=DDRSOFTRST_CON01,Offset=0x1EA04********/ ++#define SRST_P_DDR_CRU 491536 ++#define SRST_P_DDR_HWLP 491538 ++#define SRST_P_DDRPHY 491539 ++/********Name=SUBDDRSOFTRST_CON00,Offset=0x1FA00********/ ++#define SRST_MSCH_BIU 507904 ++#define SRST_A_DDRC 507905 ++#define SRST_CORE_DDRC 507907 ++#define SRST_DDRMON 507908 ++#define SRST_DFICTRL 507909 ++#define SRST_DDR_PHY 507910 ++ ++#endif +diff --git a/include/dt-bindings/display/media-bus-format.h b/include/dt-bindings/display/media-bus-format.h +new file mode 100644 +index 000000000..8d1f8733b +--- /dev/null ++++ b/include/dt-bindings/display/media-bus-format.h +@@ -0,0 +1,2 @@ ++/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ ++#include "../../uapi/linux/media-bus-format.h" +diff --git a/include/dt-bindings/soc/rockchip,boot-mode.h b/include/dt-bindings/soc/rockchip,boot-mode.h +index 4b0914c09..0a7a2133a 100644 +--- a/include/dt-bindings/soc/rockchip,boot-mode.h ++++ b/include/dt-bindings/soc/rockchip,boot-mode.h +@@ -10,7 +10,19 @@ + #define BOOT_BL_DOWNLOAD (REBOOT_FLAG + 1) + /* enter recovery */ + #define BOOT_RECOVERY (REBOOT_FLAG + 3) +- /* enter fastboot mode */ ++/* reboot by panic */ ++#define BOOT_PANIC (REBOOT_FLAG + 7) ++/* reboot by watchdog */ ++#define BOOT_WATCHDOG (REBOOT_FLAG + 8) ++/* enter fastboot mode */ + #define BOOT_FASTBOOT (REBOOT_FLAG + 9) ++/* enter charging mode */ ++#define BOOT_CHARGING (REBOOT_FLAG + 11) ++/* enter usb mass storage mode */ ++#define BOOT_UMS (REBOOT_FLAG + 12) ++/* reboot system quiescent */ ++#define BOOT_QUIESCENT (REBOOT_FLAG + 14) ++ ++#define BOOT_TO_UBOOT (REBOOT_FLAG + 16) + + #endif +diff --git a/include/dt-bindings/soc/rockchip-system-status.h b/include/dt-bindings/soc/rockchip-system-status.h +new file mode 100644 +index 000000000..51364815d +--- /dev/null ++++ b/include/dt-bindings/soc/rockchip-system-status.h +@@ -0,0 +1,58 @@ ++/* ++ * ++ * Copyright (C) 2017 ROCKCHIP, 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 _DT_BINDINGS_SOC_ROCKCHIP_SYSTEM_STATUS_H ++#define _DT_BINDINGS_SOC_ROCKCHIP_SYSTEM_STATUS_H ++ ++#define SYS_STATUS_NORMAL (1 << 0) ++#define SYS_STATUS_SUSPEND (1 << 1) ++#define SYS_STATUS_IDLE (1 << 2) ++#define SYS_STATUS_REBOOT (1 << 3) ++#define SYS_STATUS_VIDEO_4K (1 << 4) ++#define SYS_STATUS_VIDEO_1080P (1 << 5) ++#define SYS_STATUS_GPU (1 << 6) ++#define SYS_STATUS_RGA (1 << 7) ++#define SYS_STATUS_CIF0 (1 << 8) ++#define SYS_STATUS_CIF1 (1 << 9) ++#define SYS_STATUS_LCDC0 (1 << 10) ++#define SYS_STATUS_LCDC1 (1 << 11) ++#define SYS_STATUS_BOOST (1 << 12) ++#define SYS_STATUS_PERFORMANCE (1 << 13) ++#define SYS_STATUS_ISP (1 << 14) ++#define SYS_STATUS_HDMI (1 << 15) ++#define SYS_STATUS_VIDEO_4K_10B (1 << 16) ++#define SYS_STATUS_LOW_POWER (1 << 17) ++#define SYS_STATUS_HDMIRX (1 << 18) ++#define SYS_STATUS_VIDEO_SVEP (1 << 19) ++#define SYS_STATUS_VIDEO_4K_60P (1 << 20) ++ ++#define SYS_STATUS_VIDEO (SYS_STATUS_VIDEO_4K | \ ++ SYS_STATUS_VIDEO_1080P | \ ++ SYS_STATUS_VIDEO_4K_10B | \ ++ SYS_STATUS_VIDEO_4K_60P) ++#define SYS_STATUS_DUALVIEW (SYS_STATUS_LCDC0 | SYS_STATUS_LCDC1) ++ ++#define DMC_FREQ_LEVEL_LOW (0x1 << 0) ++#define DMC_FREQ_LEVEL_MID_LOW (0x1 << 1) ++#define DMC_FREQ_LEVEL_MID_HIGH (0x1 << 2) ++#define DMC_FREQ_LEVEL_HIGH (0x1 << 3) ++ ++#define DMC_WAIT_MODE_NORMAL (0x1 << 0) ++#define DMC_WAIT_MODE_VOP_VBANK (0x1 << 1) ++#define DMC_WAIT_MODE_VOP_LINE (0x1 << 2) ++#define DMC_WAIT_MODE_VOP_AUTO (0x1 << 3) ++#define DMC_WAIT_MODE_ISP_VBANK (0x1 << 4) ++ ++#endif +diff --git a/include/dt-bindings/suspend/rockchip-rv1106.h b/include/dt-bindings/suspend/rockchip-rv1106.h +new file mode 100644 +index 000000000..3e3e6ce6b +--- /dev/null ++++ b/include/dt-bindings/suspend/rockchip-rv1106.h +@@ -0,0 +1,81 @@ ++/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ ++/* ++ * Copyright (c) 2023 Rockchip Electronics Co., Ltd. ++ */ ++ ++#ifndef __DT_BINDINGS_RV1106_PM_H__ ++#define __DT_BINDINGS_RV1106_PM_H__ ++/******************************bits ops************************************/ ++ ++#ifndef BIT ++#define BIT(nr) (1 << (nr)) ++#endif ++ ++/* all plls except ddr's pll*/ ++#define RKPM_SLP_32K_EXT BIT(24) ++#define RKPM_SLP_TIME_OUT_WKUP BIT(25) ++#define RKPM_SLP_PMU_DBG BIT(26) ++ ++/* the wake up source */ ++#define RKPM_CPU_WKUP_EN BIT(0) ++#define RKPM_GPIO_WKUP_EN BIT(1) ++#define RKPM_SDMMC_WKUP_EN BIT(2) ++#define RKPM_SDIO_WKUP_EN BIT(3) ++#define RKPM_USB_WKUP_EN BIT(4) ++#define RKPM_TIMER_WKUP_EN BIT(5) ++#define RKPM_TIME_OUT_WKUP_EN BIT(6) ++#define RKPM_PMU_SFT_WKUP_EN BIT(7) ++ ++/* io config */ ++#define RKPM_IO_CFG_IOMUX_SFT 0 ++#define RKPM_IO_CFG_GPIO_DIR_SFT 8 ++#define RKPM_IO_CFG_GPIO_LVL_SFT 9 ++#define RKPM_IO_CFG_PULL_SFT 10 ++#define RKPM_IO_CFG_ID_SFT 16 ++ ++#define RKPM_IO_CFG_IOMUX_MSK 0x3f ++#define RKPM_IO_CFG_GPIO_DIR_MSK 0x1 ++#define RKPM_IO_CFG_GPIO_LVL_MSK 0x1 ++#define RKPM_IO_CFG_PULL_MSK 0x3 ++#define RKPM_IO_CFG_ID_MSK 0xffff ++ ++#define RKPM_IO_CFG_IOMUX_GPIO_VAL 0 ++#define RKPM_IO_CFG_GPIO_DIR_INPUT_VAL 0 ++#define RKPM_IO_CFG_GPIO_DIR_OUTPUT_VAL 1 ++#define RKPM_IO_CFG_GPIO_LVL_LOW_VAL 0 ++#define RKPM_IO_CFG_GPIO_LVL_HIGH_VAL 1 ++#define RKPM_IO_CFG_PULL_NONE_VAL 0 ++#define RKPM_IO_CFG_PULL_UP_VAL 1 ++#define RKPM_IO_CFG_PULL_DOWN_VAL 2 ++ ++#define RKPM_IO_CFG_IOMUX(func) ((func) << RKPM_IO_CFG_IOMUX_SFT) ++#define RKPM_IO_CFG_GPIO_DIR_INPUT \ ++ (RKPM_IO_CFG_GPIO_DIR_INPUT_VAL << RKPM_IO_CFG_GPIO_DIR_SFT) ++#define RKPM_IO_CFG_GPIO_DIR_OUTPUT \ ++ (RKPM_IO_CFG_GPIO_DIR_OUTPUT_VAL << RKPM_IO_CFG_GPIO_DIR_SFT) ++#define RKPM_IO_CFG_GPIO_LVL_LOW \ ++ (RKPM_IO_CFG_GPIO_LVL_LOW_VAL << RKPM_IO_CFG_GPIO_LVL_SFT) ++#define RKPM_IO_CFG_GPIO_LVL_HIGH \ ++ (RKPM_IO_CFG_GPIO_LVL_HIGH_VAL << RKPM_IO_CFG_GPIO_LVL_SFT) ++#define RKPM_IO_CFG_PULL_NONE \ ++ (RKPM_IO_CFG_PULL_NONE_VAL << RKPM_IO_CFG_PULL_SFT) ++#define RKPM_IO_CFG_PULL_UP \ ++ (RKPM_IO_CFG_PULL_UP_VAL << RKPM_IO_CFG_PULL_SFT) ++#define RKPM_IO_CFG_PULL_DOWN \ ++ (RKPM_IO_CFG_PULL_DOWN_VAL << RKPM_IO_CFG_PULL_SFT) ++#define RKPM_IO_CFG_ID(id) ((id) << RKPM_IO_CFG_ID_SFT) ++#define RKPM_IO_CFG_IOMUX_GPIO \ ++ RKPM_IO_CFG_IOMUX(RKPM_IO_CFG_IOMUX_GPIO_VAL) ++ ++#define RKPM_IO_CFG_GET_IOMUX(cfg) \ ++ (((cfg) >> RKPM_IO_CFG_IOMUX_SFT) & RKPM_IO_CFG_IOMUX_MSK) ++#define RKPM_IO_CFG_GET_GPIO_DIR(cfg) \ ++ (((cfg) >> RKPM_IO_CFG_GPIO_DIR_SFT) & RKPM_IO_CFG_GPIO_DIR_MSK) ++#define RKPM_IO_CFG_GET_GPIO_LVL(cfg) \ ++ (((cfg) >> RKPM_IO_CFG_GPIO_LVL_SFT) & RKPM_IO_CFG_GPIO_LVL_MSK) ++#define RKPM_IO_CFG_GET_PULL(cfg) \ ++ (((cfg) >> RKPM_IO_CFG_PULL_SFT) & RKPM_IO_CFG_PULL_MSK) ++#define RKPM_IO_CFG_GET_ID(cfg) \ ++ (((cfg) >> RKPM_IO_CFG_ID_SFT) & RKPM_IO_CFG_ID_MSK) ++ ++#endif diff --git a/patches/25-usb-phy.patch b/patches/25-usb-phy.patch new file mode 100644 index 0000000..ab72294 --- /dev/null +++ b/patches/25-usb-phy.patch @@ -0,0 +1,61 @@ +diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +index 8f4c08e59..1d0d254a7 100644 +--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c ++++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +@@ -2285,7 +2285,56 @@ static const struct rockchip_usb2phy_cfg rv1108_phy_cfgs[] = { + { /* sentinel */ } + }; + ++/* ++ * RV1106 USB2 PHY: single OTG port at 0xff3e0000 (ported from the vendor driver; ++ * fields map 1:1 to 6.18 except utmi_iddig -> utmi_id, and the 5.10-only ++ * iddig_output/iddig_en/bvalid_grf_sel are dropped). Signal-quality phy_tuning is ++ * left off for now (guarded, so NULL is safe) — the phy is functional without it. ++ */ ++static const struct rockchip_usb2phy_cfg rv1106_phy_cfgs[] = { ++ { ++ .reg = 0xff3e0000, ++ .num_ports = 1, ++ .clkout_ctl = { 0x0058, 4, 4, 1, 0 }, ++ .port_cfgs = { ++ [USB2PHY_PORT_OTG] = { ++ .phy_sus = { 0x0050, 8, 0, 0, 0x1d1 }, ++ .bvalid_det_en = { 0x0100, 2, 2, 0, 1 }, ++ .bvalid_det_st = { 0x0104, 2, 2, 0, 1 }, ++ .bvalid_det_clr = { 0x0108, 2, 2, 0, 1 }, ++ .idfall_det_en = { 0x0100, 5, 5, 0, 1 }, ++ .idfall_det_st = { 0x0104, 5, 5, 0, 1 }, ++ .idfall_det_clr = { 0x0108, 5, 5, 0, 1 }, ++ .idrise_det_en = { 0x0100, 4, 4, 0, 1 }, ++ .idrise_det_st = { 0x0104, 4, 4, 0, 1 }, ++ .idrise_det_clr = { 0x0108, 4, 4, 0, 1 }, ++ .ls_det_en = { 0x0100, 0, 0, 0, 1 }, ++ .ls_det_st = { 0x0104, 0, 0, 0, 1 }, ++ .ls_det_clr = { 0x0108, 0, 0, 0, 1 }, ++ .utmi_avalid = { 0x0060, 10, 10, 0, 1 }, ++ .utmi_bvalid = { 0x0060, 9, 9, 0, 1 }, ++ .utmi_id = { 0x0060, 6, 6, 0, 1 }, ++ .utmi_ls = { 0x0060, 5, 4, 0, 1 }, ++ }, ++ }, ++ .chg_det = { ++ .opmode = { 0x0050, 8, 0, 0, 0x1d7 }, ++ .cp_det = { 0x0060, 13, 13, 0, 1 }, ++ .dcp_det = { 0x0060, 12, 12, 0, 1 }, ++ .dp_det = { 0x0060, 14, 14, 0, 1 }, ++ .idm_sink_en = { 0x0058, 8, 8, 0, 1 }, ++ .idp_sink_en = { 0x0058, 7, 7, 0, 1 }, ++ .idp_src_en = { 0x0058, 9, 9, 0, 1 }, ++ .rdm_pdwn_en = { 0x0058, 10, 10, 0, 1 }, ++ .vdm_src_en = { 0x0058, 12, 12, 0, 1 }, ++ .vdp_src_en = { 0x0058, 11, 11, 0, 1 }, ++ }, ++ }, ++ { /* sentinel */ } ++}; ++ + static const struct of_device_id rockchip_usb2phy_dt_match[] = { ++ { .compatible = "rockchip,rv1106-usb2phy", .data = &rv1106_phy_cfgs }, + { .compatible = "rockchip,px30-usb2phy", .data = &rk3328_phy_cfgs }, + { .compatible = "rockchip,rk3036-usb2phy", .data = &rk3036_phy_cfgs }, + { .compatible = "rockchip,rk3128-usb2phy", .data = &rk3128_phy_cfgs }, diff --git a/patches/30-drm-vop-panel-rgb.patch b/patches/30-drm-vop-panel-rgb.patch new file mode 100644 index 0000000..ba3d728 --- /dev/null +++ b/patches/30-drm-vop-panel-rgb.patch @@ -0,0 +1,107 @@ +diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c +index ef1c4b929..1b286f081 100644 +--- a/drivers/gpu/drm/panel/panel-simple.c ++++ b/drivers/gpu/drm/panel/panel-simple.c +@@ -476,6 +476,26 @@ static struct panel_desc *panel_dpi_probe(struct device *dev) + drm_bus_flags_from_videomode(&vm, &bus_flags); + desc->bus_flags = bus_flags; + ++ /* ++ * Optional bus-format (a MEDIA_BUS_FMT_* code, e.g. RGB666_1X18) so the ++ * RGB/parallel output can be configured for the panel's real data width. ++ * Upstream panel-dpi doesn't read this, but a parallel RGB panel with no ++ * bus_format leaves the encoder guessing and the screen black. Match the ++ * vendor bindings, which carry bus-format on the panel node. Derive bpc ++ * from the width so panel-simple's {6,8} check is satisfied. ++ */ ++ if (!of_property_read_u32(np, "bus-format", &desc->bus_format)) { ++ switch (desc->bus_format) { ++ case MEDIA_BUS_FMT_RGB666_1X18: ++ case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: ++ desc->bpc = 6; ++ break; ++ default: ++ desc->bpc = 8; ++ break; ++ } ++ } ++ + /* We do not know the connector for the DT node, so guess it */ + desc->connector_type = DRM_MODE_CONNECTOR_DPI; + +diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +index ba6b0528d..f678ad891 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +@@ -1406,7 +1406,19 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc, + + switch (s->output_type) { + case DRM_MODE_CONNECTOR_LVDS: +- VOP_REG_SET(vop, output, rgb_dclk_pol, 1); ++ /* ++ * WardenOS 86-Panel (RV1106 internal parallel RGB): the panel ++ * latches pixel data on the NON-inverted dclk edge. Mainline ++ * hardcodes rgb_dclk_pol=1 here (inverted), which makes the ++ * panel sample RGB on the wrong clock edge -> fully healthy ++ * pipeline (connector connected, VOP streaming, backlight on) ++ * but a physically BLACK screen. Verified by reading the working ++ * vendor-5.10 _a slot's VOP register PX30_DSP_CTRL0 (0xff990020) ++ * on real hardware: rgb_dclk_pol (bit1) = 0. The vendor 5.10 VOP ++ * driver derives this as (bus_flags & PIXDATA_DRIVE_NEGEDGE)?1:0, ++ * which resolves to 0 for this panel. Match that. ++ */ ++ VOP_REG_SET(vop, output, rgb_dclk_pol, 0); + VOP_REG_SET(vop, output, rgb_pin_pol, pin_pol); + VOP_REG_SET(vop, output, rgb_en, 1); + break; +diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +index d1f788763..e0d09595f 100644 +--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c ++++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +@@ -1232,6 +1232,37 @@ static const struct vop_data rv1126_vop = { + .lut_size = 1024, + }; + ++/* ++ * RV1106 VOP: the same RV-series "lite" VOP as rv1126 (VOP_VERSION 2.0xc vs ++ * 2.0xb), so it reuses rv1126's register sub-structs. Only the version and the ++ * smaller max raster differ. Ported for the WardenOS 86-Panel (720x720 RGB). ++ */ ++/* ++ * RV1106 uses WIN1 as its (only) primary scanout plane -- see px30_win1_data. ++ * The vendor rv1106_vop_win_data is { NULL-win0, win1-primary }; mirror that ++ * as a single primary win1 here (mainline registers one plane per non-NULL ++ * entry). Reusing rv1126's { win0-overlay, win2-primary } set left the panel ++ * black because WIN2 does not drive this SoC's RGB output. ++ */ ++static const struct vop_win_data rv1106_vop_win_data[] = { ++ { .base = 0x00, .phy = &px30_win1_data, ++ .type = DRM_PLANE_TYPE_PRIMARY }, ++}; ++ ++static const struct vop_data rv1106_vop = { ++ .version = VOP_VERSION(2, 0xc), ++ .feature = VOP_FEATURE_INTERNAL_RGB, /* RV1106 drives a parallel-RGB panel */ ++ .intr = &px30_intr, ++ .common = &rv1126_common, ++ .modeset = &rv1126_modeset, ++ .output = &rv1126_output, ++ .misc = &rv1126_misc, ++ .win = rv1106_vop_win_data, ++ .win_size = ARRAY_SIZE(rv1106_vop_win_data), ++ .max_output = { 1280, 1280 }, ++ .lut_size = 1024, ++}; ++ + static const struct of_device_id vop_driver_dt_match[] = { + { .compatible = "rockchip,rk3036-vop", + .data = &rk3036_vop }, +@@ -1261,6 +1292,8 @@ static const struct of_device_id vop_driver_dt_match[] = { + .data = &rk3328_vop }, + { .compatible = "rockchip,rv1126-vop", + .data = &rv1126_vop }, ++ { .compatible = "rockchip,rv1106-vop", ++ .data = &rv1106_vop }, + {}, + }; + MODULE_DEVICE_TABLE(of, vop_driver_dt_match); diff --git a/patches/35-mailbox-hpmcu.patch b/patches/35-mailbox-hpmcu.patch new file mode 100644 index 0000000..0400846 --- /dev/null +++ b/patches/35-mailbox-hpmcu.patch @@ -0,0 +1,25 @@ +diff --git a/drivers/mailbox/rockchip-mailbox.c b/drivers/mailbox/rockchip-mailbox.c +index 4d966cb2e..31c5a693f 100644 +--- a/drivers/mailbox/rockchip-mailbox.c ++++ b/drivers/mailbox/rockchip-mailbox.c +@@ -155,7 +155,20 @@ static const struct rockchip_mbox_data rk3368_drv_data = { + .num_chans = 4, + }; + ++/* ++ * RV1106's mailbox IP is register-identical to rk3368's, but the SoC wires a ++ * single shared interrupt (GIC_SPI 1) rather than one IRQ per channel. The ++ * per-channel-IRQ probe loop below would fail requesting IRQ index 1, so ++ * declare a single channel (channel 0) — which is all the A7<->HPMCU doorbell ++ * needs. (Matched ahead of the rk3368 fallback via the more-specific ++ * "rockchip,rv1106-mailbox" compatible the DT node also carries.) ++ */ ++static const struct rockchip_mbox_data rv1106_drv_data = { ++ .num_chans = 1, ++}; ++ + static const struct of_device_id rockchip_mbox_of_match[] = { ++ { .compatible = "rockchip,rv1106-mailbox", .data = &rv1106_drv_data}, + { .compatible = "rockchip,rk3368-mailbox", .data = &rk3368_drv_data}, + { }, + }; diff --git a/patches/40-pvtm-soc.patch b/patches/40-pvtm-soc.patch new file mode 100644 index 0000000..7280428 --- /dev/null +++ b/patches/40-pvtm-soc.patch @@ -0,0 +1,1106 @@ +diff --git a/drivers/soc/rockchip/Kconfig b/drivers/soc/rockchip/Kconfig +index 785f60c6f..eba75818d 100644 +--- a/drivers/soc/rockchip/Kconfig ++++ b/drivers/soc/rockchip/Kconfig +@@ -30,4 +30,13 @@ config ROCKCHIP_DTPM + on this platform. That will create all the power capping capable + devices. + ++config ROCKCHIP_PVTM ++ tristate "Rockchip PVTM support" ++ help ++ Say y here to enable PVTM support. The Process-Voltage-Temperature ++ Monitor (PVTM) uses a ring oscillator to characterise the silicon ++ (process corner, voltage, temperature); it is read via debugfs ++ (/sys/kernel/debug/pvtm/*/value) and exports rockchip_get_pvtm_value() ++ for DVFS voltage margining. Ported from the vendor 5.10 driver. ++ + endif +diff --git a/drivers/soc/rockchip/Makefile b/drivers/soc/rockchip/Makefile +index 23d414433..228b0865d 100644 +--- a/drivers/soc/rockchip/Makefile ++++ b/drivers/soc/rockchip/Makefile +@@ -5,3 +5,4 @@ + obj-$(CONFIG_ROCKCHIP_GRF) += grf.o + obj-$(CONFIG_ROCKCHIP_IODOMAIN) += io-domain.o + obj-$(CONFIG_ROCKCHIP_DTPM) += dtpm.o ++obj-$(CONFIG_ROCKCHIP_PVTM) += rockchip_pvtm.o +diff --git a/drivers/soc/rockchip/rockchip_pvtm.c b/drivers/soc/rockchip/rockchip_pvtm.c +new file mode 100644 +index 000000000..8ade1ba32 +--- /dev/null ++++ b/drivers/soc/rockchip/rockchip_pvtm.c +@@ -0,0 +1,1050 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Rockchip PVTM support. ++ * ++ * Copyright (c) 2016 Rockchip Electronics Co. Ltd. ++ * Author: Finley Xiao ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define wr_mask_bit(v, off, mask) ((v) << (off) | (mask) << (16 + off)) ++ ++#define PVTM(_id, _name, _num_rings, _start, _en, _cal, _done, _freq) \ ++{ \ ++ .id = _id, \ ++ .name = _name, \ ++ .num_rings = _num_rings, \ ++ .bit_start = _start, \ ++ .bit_en = _en, \ ++ .reg_cal = _cal, \ ++ .bit_freq_done = _done, \ ++ .reg_freq = _freq, \ ++} ++ ++struct rockchip_pvtm; ++ ++struct rockchip_pvtm_ops { ++ u32 (*get_value)(struct rockchip_pvtm *pvtm, unsigned int ring_sel, ++ unsigned int time_us); ++ void (*set_ring_sel)(struct rockchip_pvtm *pvtm, unsigned int ring_sel); ++}; ++ ++struct rockchip_pvtm_info { ++ u32 reg_cal; ++ u32 reg_freq; ++ unsigned char id; ++ unsigned char *name; ++ unsigned int num_rings; ++ unsigned int bit_start; ++ unsigned int bit_en; ++ unsigned int bit_freq_done; ++}; ++ ++struct rockchip_pvtm_data { ++ u32 con; ++ u32 sta; ++ unsigned int num_pvtms; ++ const struct rockchip_pvtm_info *infos; ++ const struct rockchip_pvtm_ops ops; ++}; ++ ++struct rockchip_pvtm { ++ u32 con; ++ u32 sta; ++ struct list_head node; ++ struct device *dev; ++ struct regmap *grf; ++ void __iomem *base; ++ int num_clks; ++ struct clk_bulk_data *clks; ++ struct reset_control *rst; ++ struct thermal_zone_device *tz; ++ const struct rockchip_pvtm_info *info; ++ const struct rockchip_pvtm_ops *ops; ++ struct dentry *dentry; ++}; ++ ++static LIST_HEAD(pvtm_list); ++ ++#ifdef CONFIG_DEBUG_FS ++static struct dentry *rockchip_pvtm_debugfs_root; ++ ++static int pvtm_value_show(struct seq_file *s, void *data) ++{ ++ struct rockchip_pvtm *pvtm = (struct rockchip_pvtm *)s->private; ++ u32 value; ++ int i, ret, cur_temp; ++ ++ if (!pvtm || !pvtm->ops->get_value) { ++ seq_puts(s, "unsupported\n"); ++ return 0; ++ } ++ ++ /* 6.x: struct thermal_zone_device is opaque; use the public accessor ++ * instead of dereferencing ->ops->get_temp. */ ++ if (pvtm->tz) { ++ ret = thermal_zone_get_temp(pvtm->tz, &cur_temp); ++ if (ret) ++ dev_err(pvtm->dev, "debug failed to get temp\n"); ++ else ++ seq_printf(s, "temp: %d ", cur_temp); ++ } ++ seq_puts(s, "pvtm: "); ++ for (i = 0; i < pvtm->info->num_rings; i++) { ++ value = pvtm->ops->get_value(pvtm, i, 1000); ++ seq_printf(s, "%d ", value); ++ } ++ seq_puts(s, "\n"); ++ ++ return 0; ++} ++ ++static int pvtm_value_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, pvtm_value_show, inode->i_private); ++} ++ ++static const struct file_operations pvtm_value_fops = { ++ .open = pvtm_value_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static int rockchip_pvtm_debugfs_init(void) ++{ ++ rockchip_pvtm_debugfs_root = debugfs_create_dir("pvtm", NULL); ++ if (IS_ERR_OR_NULL(rockchip_pvtm_debugfs_root)) { ++ pr_err("Failed to create pvtm debug directory\n"); ++ rockchip_pvtm_debugfs_root = NULL; ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static void rockchip_pvtm_debugfs_exit(void) ++{ ++ debugfs_remove_recursive(rockchip_pvtm_debugfs_root); ++} ++ ++static int rockchip_pvtm_add_debugfs(struct rockchip_pvtm *pvtm) ++{ ++ struct dentry *d; ++ ++ if (!rockchip_pvtm_debugfs_root) ++ return 0; ++ ++ pvtm->dentry = debugfs_create_dir(pvtm->info->name, ++ rockchip_pvtm_debugfs_root); ++ if (!pvtm->dentry) { ++ dev_err(pvtm->dev, "failed to create pvtm %s debug dir\n", ++ pvtm->info->name); ++ return -ENOMEM; ++ } ++ ++ d = debugfs_create_file("value", 0444, pvtm->dentry, ++ (void *)pvtm, &pvtm_value_fops); ++ if (!d) { ++ dev_err(pvtm->dev, "failed to pvtm %s value node\n", ++ pvtm->info->name); ++ debugfs_remove_recursive(pvtm->dentry); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++#else ++static inline int rockchip_pvtm_debugfs_init(void) ++{ ++ return 0; ++} ++ ++static inline void rockchip_pvtm_debugfs_exit(void) ++{ ++} ++ ++static inline int rockchip_pvtm_add_debugfs(struct rockchip_pvtm *pvtm) ++{ ++ return 0; ++} ++#endif ++ ++static int rockchip_pvtm_reset(struct rockchip_pvtm *pvtm) ++{ ++ int ret; ++ ++ ret = reset_control_assert(pvtm->rst); ++ if (ret) { ++ dev_err(pvtm->dev, "failed to assert pvtm %d\n", ret); ++ return ret; ++ } ++ ++ udelay(2); ++ ++ ret = reset_control_deassert(pvtm->rst); ++ if (ret) { ++ dev_err(pvtm->dev, "failed to deassert pvtm %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++u32 rockchip_get_pvtm_value(unsigned int id, unsigned int ring_sel, ++ unsigned int time_us) ++{ ++ struct rockchip_pvtm *p, *pvtm = NULL; ++ ++ if (list_empty(&pvtm_list)) { ++ pr_err("pvtm list NULL\n"); ++ return -EINVAL; ++ } ++ ++ list_for_each_entry(p, &pvtm_list, node) { ++ if (p->info->id == id) { ++ pvtm = p; ++ break; ++ } ++ } ++ ++ if (!pvtm) { ++ pr_err("invalid pvtm id %d\n", id); ++ return -EINVAL; ++ } ++ ++ if (ring_sel >= pvtm->info->num_rings) { ++ pr_err("invalid pvtm ring %d\n", ring_sel); ++ return -EINVAL; ++ } ++ ++ return pvtm->ops->get_value(pvtm, ring_sel, time_us); ++} ++EXPORT_SYMBOL(rockchip_get_pvtm_value); ++ ++static void rockchip_pvtm_delay(unsigned int delay) ++{ ++ unsigned int ms = delay / 1000; ++ unsigned int us = delay % 1000; ++ ++ if (ms > 0) { ++ if (ms < 20) ++ us += ms * 1000; ++ else ++ msleep(ms); ++ } ++ ++ if (us >= 10) ++ usleep_range(us, us + 100); ++ else ++ udelay(us); ++} ++ ++static void px30_pvtm_set_ring_sel(struct rockchip_pvtm *pvtm, ++ unsigned int ring_sel) ++{ ++ unsigned int id = pvtm->info->id; ++ ++ regmap_write(pvtm->grf, pvtm->con, ++ wr_mask_bit(ring_sel, (id * 0x4 + 0x2), 0x3)); ++} ++ ++static void rk1808_pvtm_set_ring_sel(struct rockchip_pvtm *pvtm, ++ unsigned int ring_sel) ++{ ++ regmap_write(pvtm->grf, pvtm->con, ++ wr_mask_bit(ring_sel, 0x2, 0x7)); ++} ++ ++static void rk3399_pvtm_set_ring_sel(struct rockchip_pvtm *pvtm, ++ unsigned int ring_sel) ++{ ++ unsigned int id = pvtm->info->id; ++ ++ if (id == 1) { ++ regmap_write(pvtm->grf, pvtm->con + 0x14, ++ wr_mask_bit(ring_sel >> 0x3, 0, 0x1)); ++ ring_sel &= 0x3; ++ } ++ if (id != 4) ++ regmap_write(pvtm->grf, pvtm->con, ++ wr_mask_bit(ring_sel, (id * 0x4 + 0x2), 0x3)); ++} ++ ++static u32 rockchip_pvtm_get_value(struct rockchip_pvtm *pvtm, ++ unsigned int ring_sel, ++ unsigned int time_us) ++{ ++ const struct rockchip_pvtm_info *info = pvtm->info; ++ unsigned int clk_cnt, check_cnt = 100; ++ u32 sta, val = 0; ++ int ret; ++ ++ ret = clk_bulk_prepare_enable(pvtm->num_clks, pvtm->clks); ++ if (ret < 0) { ++ dev_err(pvtm->dev, "failed to prepare/enable pvtm clks\n"); ++ return 0; ++ } ++ ret = rockchip_pvtm_reset(pvtm); ++ if (ret) { ++ dev_err(pvtm->dev, "failed to reset pvtm\n"); ++ goto disable_clks; ++ } ++ ++ /* if last status is enabled, stop calculating cycles first*/ ++ regmap_read(pvtm->grf, pvtm->con, &sta); ++ if (sta & BIT(info->bit_en)) ++ regmap_write(pvtm->grf, pvtm->con, ++ wr_mask_bit(0, info->bit_start, 0x1)); ++ ++ regmap_write(pvtm->grf, pvtm->con, ++ wr_mask_bit(0x1, info->bit_en, 0x1)); ++ ++ if (pvtm->ops->set_ring_sel) ++ pvtm->ops->set_ring_sel(pvtm, ring_sel); ++ ++ /* clk = 24 Mhz, T = 1 / 24 us */ ++ clk_cnt = time_us * 24; ++ regmap_write(pvtm->grf, pvtm->con + info->reg_cal, clk_cnt); ++ ++ regmap_write(pvtm->grf, pvtm->con, ++ wr_mask_bit(0x1, info->bit_start, 0x1)); ++ ++ rockchip_pvtm_delay(time_us); ++ ++ while (check_cnt) { ++ regmap_read(pvtm->grf, pvtm->sta, &sta); ++ if (sta & BIT(info->bit_freq_done)) ++ break; ++ udelay(4); ++ check_cnt--; ++ } ++ ++ if (check_cnt) { ++ regmap_read(pvtm->grf, pvtm->sta + info->reg_freq, &val); ++ } else { ++ dev_err(pvtm->dev, "wait pvtm_done timeout!\n"); ++ val = 0; ++ } ++ ++ regmap_write(pvtm->grf, pvtm->con, ++ wr_mask_bit(0, info->bit_start, 0x1)); ++ ++ regmap_write(pvtm->grf, pvtm->con, ++ wr_mask_bit(0, info->bit_en, 0x1)); ++ ++disable_clks: ++ clk_bulk_disable_unprepare(pvtm->num_clks, pvtm->clks); ++ ++ return val; ++} ++ ++static void rv1106_core_pvtm_set_ring_sel(struct rockchip_pvtm *pvtm, ++ unsigned int ring_sel) ++{ ++ writel_relaxed(wr_mask_bit(ring_sel + 4, 0x2, 0x7), pvtm->base + pvtm->con); ++} ++ ++static void rv1126_pvtm_set_ring_sel(struct rockchip_pvtm *pvtm, ++ unsigned int ring_sel) ++{ ++ writel_relaxed(wr_mask_bit(ring_sel, 0x2, 0x7), pvtm->base + pvtm->con); ++} ++ ++static u32 rv1126_pvtm_get_value(struct rockchip_pvtm *pvtm, ++ unsigned int ring_sel, ++ unsigned int time_us) ++{ ++ const struct rockchip_pvtm_info *info = pvtm->info; ++ unsigned int clk_cnt, check_cnt = 100; ++ u32 sta, val = 0; ++ int ret; ++ ++ ret = clk_bulk_prepare_enable(pvtm->num_clks, pvtm->clks); ++ if (ret < 0) { ++ dev_err(pvtm->dev, "failed to prepare/enable pvtm clks\n"); ++ return 0; ++ } ++ ret = rockchip_pvtm_reset(pvtm); ++ if (ret) { ++ dev_err(pvtm->dev, "failed to reset pvtm\n"); ++ goto disable_clks; ++ } ++ ++ /* if last status is enabled, stop calculating cycles first*/ ++ sta = readl_relaxed(pvtm->base + pvtm->con); ++ if (sta & BIT(info->bit_en)) ++ writel_relaxed(wr_mask_bit(0, info->bit_start, 0x1), ++ pvtm->base + pvtm->con); ++ ++ writel_relaxed(wr_mask_bit(0x1, info->bit_en, 0x1), ++ pvtm->base + pvtm->con); ++ ++ if (pvtm->ops->set_ring_sel) ++ pvtm->ops->set_ring_sel(pvtm, ring_sel); ++ ++ /* clk = 24 Mhz, T = 1 / 24 us */ ++ clk_cnt = time_us * 24; ++ writel_relaxed(clk_cnt, pvtm->base + pvtm->con + info->reg_cal); ++ ++ writel_relaxed(wr_mask_bit(0x1, info->bit_start, 0x1), ++ pvtm->base + pvtm->con); ++ ++ rockchip_pvtm_delay(time_us); ++ ++ while (check_cnt) { ++ sta = readl_relaxed(pvtm->base + pvtm->sta); ++ if (sta & BIT(info->bit_freq_done)) ++ break; ++ udelay(4); ++ check_cnt--; ++ } ++ ++ if (check_cnt) { ++ val = readl_relaxed(pvtm->base + pvtm->sta + info->reg_freq); ++ } else { ++ dev_err(pvtm->dev, "wait pvtm_done timeout!\n"); ++ val = 0; ++ } ++ ++ writel_relaxed(wr_mask_bit(0, info->bit_start, 0x1), ++ pvtm->base + pvtm->con); ++ writel_relaxed(wr_mask_bit(0, info->bit_en, 0x1), ++ pvtm->base + pvtm->con); ++ ++disable_clks: ++ clk_bulk_disable_unprepare(pvtm->num_clks, pvtm->clks); ++ ++ return val; ++} ++ ++static const struct rockchip_pvtm_info px30_pvtm_infos[] = { ++ PVTM(0, "core", 3, 0, 1, 0x4, 0, 0x4), ++}; ++ ++static const struct rockchip_pvtm_data px30_pvtm = { ++ .con = 0x80, ++ .sta = 0x88, ++ .num_pvtms = ARRAY_SIZE(px30_pvtm_infos), ++ .infos = px30_pvtm_infos, ++ .ops = { ++ .get_value = rockchip_pvtm_get_value, ++ .set_ring_sel = px30_pvtm_set_ring_sel, ++ }, ++}; ++ ++static const struct rockchip_pvtm_info px30_pmupvtm_infos[] = { ++ PVTM(1, "pmu", 1, 0, 1, 0x4, 0, 0x4), ++}; ++ ++static const struct rockchip_pvtm_data px30_pmupvtm = { ++ .con = 0x180, ++ .sta = 0x190, ++ .num_pvtms = ARRAY_SIZE(px30_pmupvtm_infos), ++ .infos = px30_pmupvtm_infos, ++ .ops = { ++ .get_value = rockchip_pvtm_get_value, ++ }, ++}; ++ ++static const struct rockchip_pvtm_info rk1808_pvtm_infos[] = { ++ PVTM(0, "core", 5, 0, 1, 0x4, 0, 0x4), ++}; ++ ++static const struct rockchip_pvtm_data rk1808_pvtm = { ++ .con = 0x80, ++ .sta = 0x88, ++ .num_pvtms = ARRAY_SIZE(rk1808_pvtm_infos), ++ .infos = rk1808_pvtm_infos, ++ .ops = { ++ .get_value = rockchip_pvtm_get_value, ++ .set_ring_sel = rk1808_pvtm_set_ring_sel, ++ }, ++}; ++ ++static const struct rockchip_pvtm_info rk1808_pmupvtm_infos[] = { ++ PVTM(1, "pmu", 1, 0, 1, 0x4, 0, 0x4), ++}; ++ ++static const struct rockchip_pvtm_data rk1808_pmupvtm = { ++ .con = 0x180, ++ .sta = 0x190, ++ .num_pvtms = ARRAY_SIZE(rk1808_pmupvtm_infos), ++ .infos = rk1808_pmupvtm_infos, ++ .ops = { ++ .get_value = rockchip_pvtm_get_value, ++ }, ++}; ++ ++static const struct rockchip_pvtm_info rk1808_npupvtm_infos[] = { ++ PVTM(2, "npu", 5, 0, 1, 0x4, 0, 0x4), ++}; ++ ++static const struct rockchip_pvtm_data rk1808_npupvtm = { ++ .con = 0x780, ++ .sta = 0x788, ++ .num_pvtms = ARRAY_SIZE(rk1808_npupvtm_infos), ++ .infos = rk1808_npupvtm_infos, ++ .ops = { ++ .get_value = rockchip_pvtm_get_value, ++ .set_ring_sel = rk1808_pvtm_set_ring_sel, ++ }, ++}; ++ ++static const struct rockchip_pvtm_info rk3288_pvtm_infos[] = { ++ PVTM(0, "core", 1, 0, 1, 0x4, 1, 0x4), ++ PVTM(1, "gpu", 1, 8, 9, 0x8, 0, 0x8), ++}; ++ ++static const struct rockchip_pvtm_data rk3288_pvtm = { ++ .con = 0x368, ++ .sta = 0x374, ++ .num_pvtms = ARRAY_SIZE(rk3288_pvtm_infos), ++ .infos = rk3288_pvtm_infos, ++ .ops = { ++ .get_value = rockchip_pvtm_get_value, ++ }, ++}; ++ ++static const struct rockchip_pvtm_data rk3308_pmupvtm = { ++ .con = 0x440, ++ .sta = 0x448, ++ .num_pvtms = ARRAY_SIZE(px30_pmupvtm_infos), ++ .infos = px30_pmupvtm_infos, ++ .ops = { ++ .get_value = rockchip_pvtm_get_value, ++ }, ++}; ++ ++static const struct rockchip_pvtm_info rk3399_pvtm_infos[] = { ++ PVTM(0, "core_l", 4, 0, 1, 0x4, 0, 0x4), ++ PVTM(1, "core_b", 6, 4, 5, 0x8, 1, 0x8), ++ PVTM(2, "ddr", 4, 8, 9, 0xc, 3, 0x10), ++ PVTM(3, "gpu", 4, 12, 13, 0x10, 2, 0xc), ++}; ++ ++static const struct rockchip_pvtm_data rk3399_pvtm = { ++ .con = 0xe600, ++ .sta = 0xe620, ++ .num_pvtms = ARRAY_SIZE(rk3399_pvtm_infos), ++ .infos = rk3399_pvtm_infos, ++ .ops = { ++ .get_value = rockchip_pvtm_get_value, ++ .set_ring_sel = rk3399_pvtm_set_ring_sel, ++ }, ++}; ++ ++static const struct rockchip_pvtm_info rk3399_pmupvtm_infos[] = { ++ PVTM(4, "pmu", 1, 0, 1, 0x4, 0, 0x4), ++}; ++ ++static const struct rockchip_pvtm_data rk3399_pmupvtm = { ++ .con = 0x240, ++ .sta = 0x248, ++ .num_pvtms = ARRAY_SIZE(rk3399_pmupvtm_infos), ++ .infos = rk3399_pmupvtm_infos, ++ .ops = { ++ .get_value = rockchip_pvtm_get_value, ++ }, ++}; ++ ++static const struct rockchip_pvtm_info rk3568_corepvtm_infos[] = { ++ PVTM(0, "core", 7, 0, 1, 0x4, 0, 0x4), ++}; ++ ++static const struct rockchip_pvtm_data rk3568_corepvtm = { ++ .con = 0x4, ++ .sta = 0x80, ++ .num_pvtms = ARRAY_SIZE(rk3568_corepvtm_infos), ++ .infos = rk3568_corepvtm_infos, ++ .ops = { ++ .get_value = rv1126_pvtm_get_value, ++ .set_ring_sel = rv1126_pvtm_set_ring_sel, ++ }, ++}; ++ ++static const struct rockchip_pvtm_info rk3568_gpupvtm_infos[] = { ++ PVTM(1, "gpu", 7, 0, 1, 0x4, 0, 0x4), ++}; ++ ++static const struct rockchip_pvtm_data rk3568_gpupvtm = { ++ .con = 0x4, ++ .sta = 0x80, ++ .num_pvtms = ARRAY_SIZE(rk3568_gpupvtm_infos), ++ .infos = rk3568_gpupvtm_infos, ++ .ops = { ++ .get_value = rv1126_pvtm_get_value, ++ .set_ring_sel = rv1126_pvtm_set_ring_sel, ++ }, ++}; ++ ++static const struct rockchip_pvtm_info rk3568_npupvtm_infos[] = { ++ PVTM(2, "npu", 7, 0, 1, 0x4, 0, 0x4), ++}; ++ ++static const struct rockchip_pvtm_data rk3568_npupvtm = { ++ .con = 0x4, ++ .sta = 0x80, ++ .num_pvtms = ARRAY_SIZE(rk3568_npupvtm_infos), ++ .infos = rk3568_npupvtm_infos, ++ .ops = { ++ .get_value = rv1126_pvtm_get_value, ++ .set_ring_sel = rv1126_pvtm_set_ring_sel, ++ }, ++}; ++ ++static const struct rockchip_pvtm_info rk3588_bigcore0_pvtm_infos[] = { ++ PVTM(0, "bigcore0", 7, 0, 1, 0x4, 0, 0x4), ++}; ++ ++static const struct rockchip_pvtm_data rk3588_bigcore0_pvtm = { ++ .con = 0x4, ++ .sta = 0x80, ++ .num_pvtms = ARRAY_SIZE(rk3588_bigcore0_pvtm_infos), ++ .infos = rk3588_bigcore0_pvtm_infos, ++ .ops = { ++ .get_value = rv1126_pvtm_get_value, ++ .set_ring_sel = rv1126_pvtm_set_ring_sel, ++ }, ++}; ++ ++static const struct rockchip_pvtm_info rk3588_bigcore1_pvtm_infos[] = { ++ PVTM(1, "bigcore1", 7, 0, 1, 0x4, 0, 0x4), ++}; ++ ++static const struct rockchip_pvtm_data rk3588_bigcore1_pvtm = { ++ .con = 0x4, ++ .sta = 0x80, ++ .num_pvtms = ARRAY_SIZE(rk3588_bigcore1_pvtm_infos), ++ .infos = rk3588_bigcore1_pvtm_infos, ++ .ops = { ++ .get_value = rv1126_pvtm_get_value, ++ .set_ring_sel = rv1126_pvtm_set_ring_sel, ++ }, ++}; ++ ++static const struct rockchip_pvtm_info rk3588_litcore_pvtm_infos[] = { ++ PVTM(2, "litcore", 7, 0, 1, 0x4, 0, 0x4), ++}; ++ ++static const struct rockchip_pvtm_data rk3588_litcore_pvtm = { ++ .con = 0x4, ++ .sta = 0x80, ++ .num_pvtms = ARRAY_SIZE(rk3588_litcore_pvtm_infos), ++ .infos = rk3588_litcore_pvtm_infos, ++ .ops = { ++ .get_value = rv1126_pvtm_get_value, ++ .set_ring_sel = rv1126_pvtm_set_ring_sel, ++ }, ++}; ++ ++static const struct rockchip_pvtm_info rk3588_npu_pvtm_infos[] = { ++ PVTM(3, "npu", 2, 0, 1, 0x4, 0, 0x4), ++}; ++ ++static const struct rockchip_pvtm_data rk3588_npu_pvtm = { ++ .con = 0x4, ++ .sta = 0x80, ++ .num_pvtms = ARRAY_SIZE(rk3588_npu_pvtm_infos), ++ .infos = rk3588_npu_pvtm_infos, ++ .ops = { ++ .get_value = rv1126_pvtm_get_value, ++ .set_ring_sel = rv1126_pvtm_set_ring_sel, ++ }, ++}; ++ ++static const struct rockchip_pvtm_info rk3588_gpu_pvtm_infos[] = { ++ PVTM(4, "gpu", 2, 0, 1, 0x4, 0, 0x4), ++}; ++ ++static const struct rockchip_pvtm_data rk3588_gpu_pvtm = { ++ .con = 0x4, ++ .sta = 0x80, ++ .num_pvtms = ARRAY_SIZE(rk3588_gpu_pvtm_infos), ++ .infos = rk3588_gpu_pvtm_infos, ++ .ops = { ++ .get_value = rv1126_pvtm_get_value, ++ .set_ring_sel = rv1126_pvtm_set_ring_sel, ++ }, ++}; ++ ++static const struct rockchip_pvtm_info rk3588_pmu_pvtm_infos[] = { ++ PVTM(5, "pmu", 1, 0, 1, 0x4, 0, 0x4), ++}; ++ ++static const struct rockchip_pvtm_data rk3588_pmu_pvtm = { ++ .con = 0x4, ++ .sta = 0x80, ++ .num_pvtms = ARRAY_SIZE(rk3588_pmu_pvtm_infos), ++ .infos = rk3588_pmu_pvtm_infos, ++ .ops = { ++ .get_value = rv1126_pvtm_get_value, ++ }, ++}; ++ ++static const struct rockchip_pvtm_info rv1106_corepvtm_infos[] = { ++ PVTM(0, "core", 2, 0, 1, 0x4, 0, 0x4), ++}; ++ ++static const struct rockchip_pvtm_data rv1106_corepvtm = { ++ .con = 0x4, ++ .sta = 0x80, ++ .num_pvtms = ARRAY_SIZE(rv1106_corepvtm_infos), ++ .infos = rv1106_corepvtm_infos, ++ .ops = { ++ .get_value = rv1126_pvtm_get_value, ++ .set_ring_sel = rv1106_core_pvtm_set_ring_sel, ++ }, ++}; ++ ++static const struct rockchip_pvtm_info rv1106_pmupvtm_infos[] = { ++ PVTM(1, "pmu", 1, 0, 1, 0x4, 0, 0x4), ++}; ++ ++static const struct rockchip_pvtm_data rv1106_pmupvtm = { ++ .con = 0x4, ++ .sta = 0x80, ++ .num_pvtms = ARRAY_SIZE(rv1106_pmupvtm_infos), ++ .infos = rv1106_pmupvtm_infos, ++ .ops = { ++ .get_value = rv1126_pvtm_get_value, ++ }, ++}; ++ ++static const struct rockchip_pvtm_info rv1126_cpupvtm_infos[] = { ++ PVTM(0, "cpu", 7, 0, 1, 0x4, 0, 0x4), ++}; ++ ++static const struct rockchip_pvtm_data rv1126_cpupvtm = { ++ .con = 0x4, ++ .sta = 0x80, ++ .num_pvtms = ARRAY_SIZE(rv1126_cpupvtm_infos), ++ .infos = rv1126_cpupvtm_infos, ++ .ops = { ++ .get_value = rv1126_pvtm_get_value, ++ .set_ring_sel = rv1126_pvtm_set_ring_sel, ++ }, ++}; ++ ++static const struct rockchip_pvtm_info rv1126_npupvtm_infos[] = { ++ PVTM(1, "npu", 7, 0, 1, 0x4, 0, 0x4), ++}; ++ ++static const struct rockchip_pvtm_data rv1126_npupvtm = { ++ .con = 0x4, ++ .sta = 0x80, ++ .num_pvtms = ARRAY_SIZE(rv1126_npupvtm_infos), ++ .infos = rv1126_npupvtm_infos, ++ .ops = { ++ .get_value = rv1126_pvtm_get_value, ++ .set_ring_sel = rv1126_pvtm_set_ring_sel, ++ }, ++}; ++ ++static const struct rockchip_pvtm_info rv1126_pmupvtm_infos[] = { ++ PVTM(2, "pmu", 1, 0, 1, 0x4, 0, 0x4), ++}; ++ ++static const struct rockchip_pvtm_data rv1126_pmupvtm = { ++ .con = 0x4, ++ .sta = 0x80, ++ .num_pvtms = ARRAY_SIZE(rv1126_pmupvtm_infos), ++ .infos = rv1126_pmupvtm_infos, ++ .ops = { ++ .get_value = rv1126_pvtm_get_value, ++ }, ++}; ++ ++static const struct of_device_id rockchip_pvtm_match[] = { ++#ifdef CONFIG_CPU_PX30 ++ { ++ .compatible = "rockchip,px30-pvtm", ++ .data = (void *)&px30_pvtm, ++ }, ++ { ++ .compatible = "rockchip,px30-pmu-pvtm", ++ .data = (void *)&px30_pmupvtm, ++ }, ++#endif ++#ifdef CONFIG_CPU_RK1808 ++ { ++ .compatible = "rockchip,rk1808-pvtm", ++ .data = (void *)&rk1808_pvtm, ++ }, ++ { ++ .compatible = "rockchip,rk1808-pmu-pvtm", ++ .data = (void *)&rk1808_pmupvtm, ++ }, ++ { ++ .compatible = "rockchip,rk1808-npu-pvtm", ++ .data = (void *)&rk1808_npupvtm, ++ }, ++#endif ++#ifdef CONFIG_CPU_RK3288 ++ { ++ .compatible = "rockchip,rk3288-pvtm", ++ .data = (void *)&rk3288_pvtm, ++ }, ++#endif ++#ifdef CONFIG_CPU_RK3308 ++ { ++ .compatible = "rockchip,rk3308-pvtm", ++ .data = (void *)&px30_pvtm, ++ }, ++ { ++ .compatible = "rockchip,rk3308-pmu-pvtm", ++ .data = (void *)&rk3308_pmupvtm, ++ }, ++#endif ++#ifdef CONFIG_CPU_RK3399 ++ { ++ .compatible = "rockchip,rk3399-pvtm", ++ .data = (void *)&rk3399_pvtm, ++ }, ++ { ++ .compatible = "rockchip,rk3399-pmu-pvtm", ++ .data = (void *)&rk3399_pmupvtm, ++ }, ++#endif ++#ifdef CONFIG_CPU_RK3568 ++ { ++ .compatible = "rockchip,rK3568-core-pvtm", ++ .data = (void *)&rk3568_corepvtm, ++ }, ++ { ++ .compatible = "rockchip,rk3568-gpu-pvtm", ++ .data = (void *)&rk3568_gpupvtm, ++ }, ++ { ++ .compatible = "rockchip,rk3568-npu-pvtm", ++ .data = (void *)&rk3568_npupvtm, ++ }, ++#endif ++#ifdef CONFIG_CPU_RK3588 ++ { ++ .compatible = "rockchip,rk3588-bigcore0-pvtm", ++ .data = (void *)&rk3588_bigcore0_pvtm, ++ }, ++ { ++ .compatible = "rockchip,rk3588-bigcore1-pvtm", ++ .data = (void *)&rk3588_bigcore1_pvtm, ++ }, ++ { ++ .compatible = "rockchip,rk3588-litcore-pvtm", ++ .data = (void *)&rk3588_litcore_pvtm, ++ }, ++ { ++ .compatible = "rockchip,rk3588-gpu-pvtm", ++ .data = (void *)&rk3588_gpu_pvtm, ++ }, ++ { ++ .compatible = "rockchip,rk3588-npu-pvtm", ++ .data = (void *)&rk3588_npu_pvtm, ++ }, ++ { ++ .compatible = "rockchip,rk3588-pmu-pvtm", ++ .data = (void *)&rk3588_pmu_pvtm, ++ }, ++#endif ++ /* CONFIG_CPU_RV1106 (a vendor per-SoC symbol) does not exist in ++ * mainline; our tree only ever builds for rv1106, so keep these ++ * match entries unconditional — else the devices never bind. */ ++ { ++ .compatible = "rockchip,rv1106-core-pvtm", ++ .data = (void *)&rv1106_corepvtm, ++ }, ++ { ++ .compatible = "rockchip,rv1106-pmu-pvtm", ++ .data = (void *)&rv1106_pmupvtm, ++ }, ++#ifdef CONFIG_CPU_RV1126 ++ { ++ .compatible = "rockchip,rv1126-cpu-pvtm", ++ .data = (void *)&rv1126_cpupvtm, ++ }, ++ { ++ .compatible = "rockchip,rv1126-npu-pvtm", ++ .data = (void *)&rv1126_npupvtm, ++ }, ++ { ++ .compatible = "rockchip,rv1126-pmu-pvtm", ++ .data = (void *)&rv1126_pmupvtm, ++ }, ++#endif ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, rockchip_pvtm_match); ++ ++static int rockchip_pvtm_get_index(const struct rockchip_pvtm_data *data, ++ u32 ch, u32 *index) ++{ ++ int i; ++ ++ for (i = 0; i < data->num_pvtms; i++) { ++ if (ch == data->infos[i].id) { ++ *index = i; ++ return 0; ++ } ++ } ++ ++ return -EINVAL; ++} ++ ++static struct rockchip_pvtm * ++rockchip_pvtm_init(struct device *dev, struct device_node *node, ++ const struct rockchip_pvtm_data *data, ++ struct regmap *grf, void __iomem *base) ++{ ++ struct rockchip_pvtm *pvtm; ++ const char *tz_name; ++ u32 id, index; ++ int i; ++ ++ if (of_property_read_u32(node, "reg", &id)) { ++ dev_err(dev, "%s: failed to retrieve pvtm id\n", node->name); ++ return NULL; ++ } ++ if (rockchip_pvtm_get_index(data, id, &index)) { ++ dev_err(dev, "%s: invalid pvtm id %d\n", node->name, id); ++ return NULL; ++ } ++ ++ pvtm = devm_kzalloc(dev, sizeof(*pvtm), GFP_KERNEL); ++ if (!pvtm) ++ return NULL; ++ ++ pvtm->dev = dev; ++ pvtm->grf = grf; ++ pvtm->base = base; ++ pvtm->con = data->con; ++ pvtm->sta = data->sta; ++ pvtm->ops = &data->ops; ++ pvtm->info = &data->infos[index]; ++ ++ if (!of_property_read_string(node, "thermal-zone", &tz_name)) { ++ pvtm->tz = thermal_zone_get_zone_by_name(tz_name); ++ if (IS_ERR(pvtm->tz)) { ++ dev_err(pvtm->dev, "failed to retrieve pvtm_tz\n"); ++ pvtm->tz = NULL; ++ } ++ } ++ ++ pvtm->num_clks = of_clk_get_parent_count(node); ++ if (pvtm->num_clks <= 0) { ++ dev_err(dev, "%s: does not have clocks\n", node->name); ++ goto clk_num_err; ++ } ++ pvtm->clks = devm_kcalloc(dev, pvtm->num_clks, sizeof(*pvtm->clks), ++ GFP_KERNEL); ++ if (!pvtm->clks) ++ goto clk_num_err; ++ for (i = 0; i < pvtm->num_clks; i++) { ++ pvtm->clks[i].clk = of_clk_get(node, i); ++ if (IS_ERR(pvtm->clks[i].clk)) { ++ dev_err(dev, "%s: failed to get clk at index %d\n", ++ node->name, i); ++ goto clk_err; ++ } ++ } ++ ++ pvtm->rst = devm_reset_control_array_get_optional_exclusive(dev); ++ if (IS_ERR(pvtm->rst)) ++ dev_dbg(dev, "%s: failed to get reset\n", node->name); ++ ++ rockchip_pvtm_add_debugfs(pvtm); ++ ++ return pvtm; ++ ++clk_err: ++ while (--i >= 0) ++ clk_put(pvtm->clks[i].clk); ++ devm_kfree(dev, pvtm->clks); ++clk_num_err: ++ devm_kfree(dev, pvtm); ++ ++ return NULL; ++} ++ ++static int rockchip_pvtm_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = pdev->dev.of_node; ++ struct device_node *node; ++ const struct of_device_id *match; ++ struct rockchip_pvtm *pvtm; ++ struct regmap *grf = NULL; ++ void __iomem *base = NULL; ++ ++ match = of_match_device(dev->driver->of_match_table, dev); ++ if (!match || !match->data) { ++ dev_err(dev, "missing pvtm data\n"); ++ return -EINVAL; ++ } ++ ++ if (dev->parent && dev->parent->of_node) { ++ grf = syscon_node_to_regmap(dev->parent->of_node); ++ if (IS_ERR(grf)) ++ return PTR_ERR(grf); ++ } else { ++ base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); ++ } ++ ++ for_each_available_child_of_node(np, node) { ++ pvtm = rockchip_pvtm_init(dev, node, match->data, grf, base); ++ if (!pvtm) { ++ dev_err(dev, "failed to handle node %s\n", ++ node->full_name); ++ continue; ++ } ++ list_add(&pvtm->node, &pvtm_list); ++ dev_info(dev, "%s probed\n", node->full_name); ++ } ++ ++ return 0; ++} ++ ++static struct platform_driver rockchip_pvtm_driver = { ++ .probe = rockchip_pvtm_probe, ++ .driver = { ++ .name = "rockchip-pvtm", ++ .of_match_table = rockchip_pvtm_match, ++ }, ++}; ++ ++static int __init rockchip_pvtm_module_init(void) ++{ ++ rockchip_pvtm_debugfs_init(); ++ ++ return platform_driver_register(&rockchip_pvtm_driver); ++} ++module_init(rockchip_pvtm_module_init); ++ ++static void __exit rockchip_pvtm_module_exit(void) ++{ ++ rockchip_pvtm_debugfs_exit(); ++ platform_driver_unregister(&rockchip_pvtm_driver); ++} ++module_exit(rockchip_pvtm_module_exit); ++ ++MODULE_DESCRIPTION("Rockchip PVTM driver"); ++MODULE_AUTHOR("Finley Xiao "); ++MODULE_LICENSE("GPL v2"); +diff --git a/include/linux/soc/rockchip/pvtm.h b/include/linux/soc/rockchip/pvtm.h +new file mode 100644 +index 000000000..3d2495cfd +--- /dev/null ++++ b/include/linux/soc/rockchip/pvtm.h +@@ -0,0 +1,17 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __SOC_ROCKCHIP_PVTM_H ++#define __SOC_ROCKCHIP_PVTM_H ++ ++#if IS_ENABLED(CONFIG_ROCKCHIP_PVTM) ++u32 rockchip_get_pvtm_value(unsigned int id, unsigned int ring_sel, ++ unsigned int time_us); ++#else ++static inline u32 rockchip_get_pvtm_value(unsigned int id, ++ unsigned int ring_sel, ++ unsigned int time_us) ++{ ++ return 0; ++} ++#endif ++ ++#endif /* __SOC_ROCKCHIP_PVTM_H */ diff --git a/patches/45-npu-rknpu.patch b/patches/45-npu-rknpu.patch new file mode 100644 index 0000000..4cca473 --- /dev/null +++ b/patches/45-npu-rknpu.patch @@ -0,0 +1,7405 @@ +diff --git a/drivers/rknpu/Kconfig b/drivers/rknpu/Kconfig +new file mode 100644 +index 000000000..29007caac +--- /dev/null ++++ b/drivers/rknpu/Kconfig +@@ -0,0 +1,59 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# ++# RKNPU -- Rockchip NPU (rknpu) kernel driver, forward-ported from the ++# vendor 5.10.160 RV1106 BSP (drivers/rknpu/, v0.9.2) to 6.18. ++# See warden-sdk/kernel/rv1106-enablement/npu/PORT-PLAN.md for the full ++# port plan and warden-sdk/kernel/rv1106-enablement/npu/PORT-PROGRESS.md ++# for what was actually done. ++# ++# Trimmed vs the vendor Kconfig: no ROCKCHIP_RKNPU_SRAM/FENCE/DMA_HEAP ++# choice here -- RV1106 needs none of them (single-core NPU, no NBUF, no ++# multi-domain fencing; DRM_GEM is the only memory manager wired in). ++ ++menu "RKNPU" ++ depends on ARCH_ROCKCHIP ++ ++config ROCKCHIP_RKNPU ++ tristate "Rockchip RKNPU support" ++ depends on DRM ++ help ++ Kernel-mode driver for the Rockchip NPU (RKNPU) found on RV1106 ++ and other Rockchip SoCs. Registers a DRM device (/dev/dri/cardN) ++ and implements power/clock/reset sequencing, GEM buffer ++ management, and the regcmd task-queue submit ioctl. Does not ++ include a compiler/runtime capable of producing regcmd programs ++ for the NPU to execute -- that piece is closed-source Rockchip ++ userspace (RKNN-Toolkit2 / librknnrt) and is not shipped by this ++ port. See npu/OPEN-NPU-PLAN.md for what this does and does not ++ unlock. ++ ++if ROCKCHIP_RKNPU ++ ++config ROCKCHIP_RKNPU_DEBUG_FS ++ bool "RKNPU debugfs" ++ depends on DEBUG_FS ++ default y ++ help ++ Enable debugfs to debug RKNPU usage. ++ ++config ROCKCHIP_RKNPU_PROC_FS ++ bool "RKNPU procfs" ++ depends on PROC_FS ++ default y ++ help ++ Enable /proc/rknpu/load (the Monitor page's continuity target -- ++ see npu/PORT-PLAN.md §2.1). ++ ++config ROCKCHIP_RKNPU_DRM_GEM ++ bool "RKNPU DRM GEM" ++ depends on DRM ++ default y ++ help ++ RKNPU memory manager backed by DRM GEM (/dev/dri/cardN, ++ DRM_IOCTL_RKNPU_*). The only memory manager this port wires up -- ++ the vendor's alternative DMA_HEAP path is not ported (see ++ npu/PORT-PLAN.md §2.1/§2.2). ++ ++endif ++ ++endmenu +diff --git a/drivers/rknpu/Makefile b/drivers/rknpu/Makefile +new file mode 100644 +index 000000000..687cbb5fc +--- /dev/null ++++ b/drivers/rknpu/Makefile +@@ -0,0 +1,19 @@ ++# SPDX-License-Identifier: GPL-2.0 ++obj-$(CONFIG_ROCKCHIP_RKNPU) += rknpu.o ++ ++# compat/ goes FIRST so our stub soc/rockchip/rockchip_{iommu,opp_select, ++# system_monitor,ipa}.h shadow anything a future in-tree header of the same ++# name might introduce (see PORT-PLAN.md §2.4 -- rockchip_iommu.h in ++# particular must not resolve to this tree's real, unrelated ++# CONFIG_ROCKCHIP_IOMMU driver headers). ++ccflags-y += -I$(srctree)/$(src)/compat ++ccflags-y += -I$(srctree)/$(src)/include ++ccflags-y += -I$(src)/include ++ccflags-y += -Werror ++ ++rknpu-y += rknpu_drv.o ++rknpu-y += rknpu_reset.o ++rknpu-y += rknpu_job.o ++rknpu-y += rknpu_debugger.o ++rknpu-y += rknpu_iommu.o ++rknpu-$(CONFIG_ROCKCHIP_RKNPU_DRM_GEM) += rknpu_gem.o +diff --git a/drivers/rknpu/compat/soc/rockchip/rockchip_iommu.h b/drivers/rknpu/compat/soc/rockchip/rockchip_iommu.h +new file mode 100644 +index 000000000..d829ecd31 +--- /dev/null ++++ b/drivers/rknpu/compat/soc/rockchip/rockchip_iommu.h +@@ -0,0 +1,30 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Compat shim for the vendor-BSP-only ++ * convenience wrapper, absent from mainline (PORT-PLAN.md §2.4). ++ * ++ * NOT a copy of the vendor header's own #if IS_ENABLED(CONFIG_ROCKCHIP_IOMMU) ++ * gate: this 6.18 tree already has a *real*, unrelated CONFIG_ROCKCHIP_IOMMU ++ * (drivers/iommu/rockchip-iommu.c, the mainline IOMMU driver, =y in our ++ * .config for the display/VOP2 path) that does not implement this vendor ++ * convenience API at all. Gating on that symbol here would silently select ++ * extern declarations with no definition anywhere -> link failure. So this ++ * shim is unconditional, independent of CONFIG_ROCKCHIP_IOMMU. ++ * ++ * rknpu_drv.c's only call site (rknpu_power_off(), guarded by ++ * `if (rknpu_dev->multiple_domains)`) is dead code for RV1106: the board DT ++ * carries no `iommus =` property and rv1106_rknpu_config never sets ++ * multiple_domains (that's an RK3588 3-core-NPU-only path). Stub returns ++ * false, matching the vendor's own "IOMMU disabled" default. ++ */ ++#ifndef __SOC_ROCKCHIP_IOMMU_H ++#define __SOC_ROCKCHIP_IOMMU_H ++ ++struct device; ++ ++static inline bool rockchip_iommu_is_enabled(struct device *dev) ++{ ++ return false; ++} ++ ++#endif +diff --git a/drivers/rknpu/compat/soc/rockchip/rockchip_ipa.h b/drivers/rknpu/compat/soc/rockchip/rockchip_ipa.h +new file mode 100644 +index 000000000..074da2ebc +--- /dev/null ++++ b/drivers/rknpu/compat/soc/rockchip/rockchip_ipa.h +@@ -0,0 +1,46 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd ++ * ++ * 6.18 port compat-shim note (PORT-PLAN.md §2.4): copied verbatim from the ++ * vendor 5.10 BSP. CONFIG_ROCKCHIP_IPA does not exist anywhere in ++ * mainline, so `#if IS_ENABLED(CONFIG_ROCKCHIP_IPA)` below always ++ * evaluates false and the static-inline stub branch is always selected ++ * (rockchip_ipa_power_model_init() returns ERR_PTR(-ENOTSUPP)). ++ */ ++#ifndef __SOC_ROCKCHIP_IPA_H ++#define __SOC_ROCKCHIP_IPA_H ++ ++struct ipa_power_model_data { ++ u32 static_coefficient; ++ u32 dynamic_coefficient; ++ s32 ts[4]; /* temperature scaling factor */ ++ struct thermal_zone_device *tz; ++ u32 leakage; ++ u32 ref_leakage; ++ u32 lkg_range[2]; /* min leakage and max leakage */ ++ s32 ls[3]; /* leakage scaling factor */ ++}; ++ ++#if IS_ENABLED(CONFIG_ROCKCHIP_IPA) ++struct ipa_power_model_data *rockchip_ipa_power_model_init(struct device *dev, ++ char *lkg_name); ++unsigned long ++rockchip_ipa_get_static_power(struct ipa_power_model_data *model_data, ++ unsigned long voltage_mv); ++#else ++static inline struct ipa_power_model_data * ++rockchip_ipa_power_model_init(struct device *dev, char *lkg_name) ++{ ++ return ERR_PTR(-ENOTSUPP); ++}; ++ ++static inline unsigned long ++rockchip_ipa_get_static_power(struct ipa_power_model_data *data, ++ unsigned long voltage_mv) ++{ ++ return 0; ++} ++#endif /* CONFIG_ROCKCHIP_IPA */ ++ ++#endif +diff --git a/drivers/rknpu/compat/soc/rockchip/rockchip_opp_select.h b/drivers/rknpu/compat/soc/rockchip/rockchip_opp_select.h +new file mode 100644 +index 000000000..c245eb946 +--- /dev/null ++++ b/drivers/rknpu/compat/soc/rockchip/rockchip_opp_select.h +@@ -0,0 +1,262 @@ ++/* ++ * Copyright (c) 2017 Fuzhou Rockchip Electronics Co., Ltd ++ * ++ * SPDX-License-Identifier: GPL-2.0+ ++ * ++ * 6.18 port compat-shim note (PORT-PLAN.md §2.4): copied verbatim from the ++ * vendor 5.10 BSP (drivers/rknpu is the only in-tree includer). Safe as-is: ++ * CONFIG_ROCKCHIP_OPP does not exist anywhere in mainline (grepped this ++ * tree's Kconfig + .config), so `#if IS_ENABLED(CONFIG_ROCKCHIP_OPP)` below ++ * always evaluates false and the file's own static-inline stub branch ++ * (returns -EOPNOTSUPP / no-ops) is always selected. The struct definitions ++ * (struct rockchip_opp_info et al.) are still needed unconditionally -- ++ * rknpu_device embeds a `struct rockchip_opp_info opp_info;` by value. ++ */ ++#ifndef __SOC_ROCKCHIP_OPP_SELECT_H ++#define __SOC_ROCKCHIP_OPP_SELECT_H ++ ++#define VOLT_RM_TABLE_END ~1 ++ ++/* ++ * [0]: set intermediate rate ++ * [1]: scaling up rate or scaling down rate ++ * [1]: add length for pvtpll ++ * [2:5]: length ++ * [2]: use low length for pvtpll ++ * [3:5]: reserved ++ */ ++#define OPP_RATE_MASK 0x3f ++ ++/* Set intermediate rate */ ++#define OPP_INTERMEDIATE_RATE BIT(0) ++#define OPP_SCALING_UP_RATE BIT(1) ++#define OPP_SCALING_UP_INTER (OPP_INTERMEDIATE_RATE | OPP_SCALING_UP_RATE) ++#define OPP_SCALING_DOWN_INTER OPP_INTERMEDIATE_RATE ++ ++/* Add length for pvtpll */ ++#define OPP_ADD_LENGTH BIT(1) ++#define OPP_LENGTH_MASK 0xf ++#define OPP_LENGTH_SHIFT 2 ++ ++/* Use low length for pvtpll */ ++#define OPP_LENGTH_LOW BIT(2) ++ ++struct rockchip_opp_info; ++ ++struct volt_rm_table { ++ int volt; ++ int rm; ++}; ++ ++struct rockchip_opp_data { ++ int (*get_soc_info)(struct device *dev, struct device_node *np, ++ int *bin, int *process); ++ int (*set_soc_info)(struct device *dev, struct device_node *np, ++ int bin, int process, int volt_sel); ++ int (*set_read_margin)(struct device *dev, ++ struct rockchip_opp_info *opp_info, ++ u32 rm); ++}; ++ ++struct pvtpll_opp_table { ++ unsigned long rate; ++ unsigned long u_volt; ++ unsigned long u_volt_min; ++ unsigned long u_volt_max; ++ unsigned long u_volt_mem; ++ unsigned long u_volt_mem_min; ++ unsigned long u_volt_mem_max; ++}; ++ ++struct rockchip_opp_info { ++ struct device *dev; ++ struct pvtpll_opp_table *opp_table; ++ const struct rockchip_opp_data *data; ++ struct volt_rm_table *volt_rm_tbl; ++ struct regmap *grf; ++ struct regmap *dsu_grf; ++ struct clk_bulk_data *clks; ++ struct clk *scmi_clk; ++ /* The threshold frequency for set intermediate rate */ ++ unsigned long intermediate_threshold_freq; ++ unsigned int pvtpll_avg_offset; ++ unsigned int pvtpll_min_rate; ++ unsigned int pvtpll_volt_step; ++ int num_clks; ++ /* The read margin for low voltage */ ++ u32 low_rm; ++ u32 current_rm; ++ u32 target_rm; ++}; ++ ++#if IS_ENABLED(CONFIG_ROCKCHIP_OPP) ++int rockchip_of_get_leakage(struct device *dev, char *lkg_name, int *leakage); ++void rockchip_of_get_lkg_sel(struct device *dev, struct device_node *np, ++ char *lkg_name, int process, ++ int *volt_sel, int *scale_sel); ++void rockchip_pvtpll_calibrate_opp(struct rockchip_opp_info *info); ++void rockchip_pvtpll_add_length(struct rockchip_opp_info *info); ++void rockchip_of_get_pvtm_sel(struct device *dev, struct device_node *np, ++ char *reg_name, int process, ++ int *volt_sel, int *scale_sel); ++void rockchip_of_get_bin_sel(struct device *dev, struct device_node *np, ++ int bin, int *scale_sel); ++void rockchip_of_get_bin_volt_sel(struct device *dev, struct device_node *np, ++ int bin, int *bin_volt_sel); ++int rockchip_nvmem_cell_read_u8(struct device_node *np, const char *cell_id, ++ u8 *val); ++int rockchip_nvmem_cell_read_u16(struct device_node *np, const char *cell_id, ++ u16 *val); ++int rockchip_get_volt_rm_table(struct device *dev, struct device_node *np, ++ char *porp_name, struct volt_rm_table **table); ++void rockchip_get_opp_data(const struct of_device_id *matches, ++ struct rockchip_opp_info *info); ++void rockchip_get_scale_volt_sel(struct device *dev, char *lkg_name, ++ char *reg_name, int bin, int process, ++ int *scale, int *volt_sel); ++struct opp_table *rockchip_set_opp_prop_name(struct device *dev, int process, ++ int volt_sel); ++int rockchip_adjust_power_scale(struct device *dev, int scale); ++int rockchip_get_read_margin(struct device *dev, ++ struct rockchip_opp_info *opp_info, ++ unsigned long volt, u32 *target_rm); ++int rockchip_set_read_margin(struct device *dev, ++ struct rockchip_opp_info *opp_info, u32 rm, ++ bool is_set_rm); ++int rockchip_init_read_margin(struct device *dev, ++ struct rockchip_opp_info *opp_info, ++ char *reg_name); ++int rockchip_set_intermediate_rate(struct device *dev, ++ struct rockchip_opp_info *opp_info, ++ struct clk *clk, unsigned long old_freq, ++ unsigned long new_freq, bool is_scaling_up, ++ bool is_set_clk); ++int rockchip_init_opp_table(struct device *dev, ++ struct rockchip_opp_info *info, ++ char *lkg_name, char *reg_name); ++#else ++static inline int rockchip_of_get_leakage(struct device *dev, char *lkg_name, ++ int *leakage) ++{ ++ return -EOPNOTSUPP; ++} ++ ++static inline void rockchip_of_get_lkg_sel(struct device *dev, ++ struct device_node *np, ++ char *lkg_name, int process, ++ int *volt_sel, int *scale_sel) ++{ ++} ++ ++static inline void rockchip_pvtpll_calibrate_opp(struct rockchip_opp_info *info) ++{ ++} ++ ++static inline void rockchip_pvtpll_add_length(struct rockchip_opp_info *info) ++{ ++} ++ ++static inline void rockchip_of_get_pvtm_sel(struct device *dev, ++ struct device_node *np, ++ char *reg_name, int process, ++ int *volt_sel, int *scale_sel) ++{ ++} ++ ++static inline void rockchip_of_get_bin_sel(struct device *dev, ++ struct device_node *np, int bin, ++ int *scale_sel) ++{ ++} ++ ++static inline void rockchip_of_get_bin_volt_sel(struct device *dev, ++ struct device_node *np, ++ int bin, int *bin_volt_sel) ++{ ++} ++ ++static inline int rockchip_nvmem_cell_read_u8(struct device_node *np, ++ const char *cell_id, u8 *val) ++{ ++ return -EOPNOTSUPP; ++} ++ ++static inline int rockchip_nvmem_cell_read_u16(struct device_node *np, ++ const char *cell_id, u16 *val) ++{ ++ return -EOPNOTSUPP; ++} ++ ++static inline int rockchip_get_volt_rm_table(struct device *dev, ++ struct device_node *np, ++ char *porp_name, ++ struct volt_rm_table **table) ++{ ++ return -EOPNOTSUPP; ++ ++} ++ ++static inline void rockchip_get_opp_data(const struct of_device_id *matches, ++ struct rockchip_opp_info *info) ++{ ++} ++ ++static inline void rockchip_get_scale_volt_sel(struct device *dev, ++ char *lkg_name, char *reg_name, ++ int bin, int process, int *scale, ++ int *volt_sel) ++{ ++} ++ ++static inline struct opp_table *rockchip_set_opp_prop_name(struct device *dev, ++ int process, ++ int volt_sel) ++{ ++ return ERR_PTR(-EOPNOTSUPP); ++} ++ ++static inline int rockchip_adjust_power_scale(struct device *dev, int scale) ++{ ++ return -EOPNOTSUPP; ++} ++ ++static inline int rockchip_get_read_margin(struct device *dev, ++ struct rockchip_opp_info *opp_info, ++ unsigned long volt, u32 *target_rm) ++{ ++ return -EOPNOTSUPP; ++} ++static inline int rockchip_set_read_margin(struct device *dev, ++ struct rockchip_opp_info *opp_info, ++ u32 rm, bool is_set_rm) ++{ ++ return -EOPNOTSUPP; ++} ++ ++static inline int rockchip_init_read_margin(struct device *dev, ++ struct rockchip_opp_info *opp_info, ++ char *reg_name) ++{ ++ return -EOPNOTSUPP; ++} ++ ++static inline int ++rockchip_set_intermediate_rate(struct device *dev, ++ struct rockchip_opp_info *opp_info, ++ struct clk *clk, unsigned long old_freq, ++ unsigned long new_freq, bool is_scaling_up, ++ bool is_set_clk) ++{ ++ return -EOPNOTSUPP; ++} ++ ++static inline int rockchip_init_opp_table(struct device *dev, ++ struct rockchip_opp_info *info, ++ char *lkg_name, char *reg_name) ++{ ++ return -EOPNOTSUPP; ++} ++ ++#endif /* CONFIG_ROCKCHIP_OPP */ ++ ++#endif +diff --git a/drivers/rknpu/compat/soc/rockchip/rockchip_system_monitor.h b/drivers/rknpu/compat/soc/rockchip/rockchip_system_monitor.h +new file mode 100644 +index 000000000..c1f603159 +--- /dev/null ++++ b/drivers/rknpu/compat/soc/rockchip/rockchip_system_monitor.h +@@ -0,0 +1,245 @@ ++/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ ++/* ++ * Copyright (C) 2019, Fuzhou Rockchip Electronics Co., Ltd ++ * ++ * 6.18 port compat-shim note (PORT-PLAN.md §2.4): copied verbatim from the ++ * vendor 5.10 BSP. CONFIG_ROCKCHIP_SYSTEM_MONITOR does not exist anywhere ++ * in mainline, so `#if IS_REACHABLE(CONFIG_ROCKCHIP_SYSTEM_MONITOR)` below ++ * always evaluates false and the static-inline stub branch is always ++ * selected (rockchip_system_monitor_register() returns ERR_PTR(-ENOTSUPP)). ++ * The struct definitions are needed unconditionally: rknpu_device holds a ++ * `struct monitor_dev_info *mdev_info` pointer, dereferenced in dead ++ * (RV1106 has no DVFS/OPP table) but still-compiled code. ++ */ ++#ifndef __SOC_ROCKCHIP_SYSTEM_MONITOR_H ++#define __SOC_ROCKCHIP_SYSTEM_MONITOR_H ++ ++#include ++#include ++#include ++ ++enum monitor_dev_type { ++ MONITOR_TPYE_CPU = 0, /* CPU */ ++ MONITOR_TPYE_DEV, /* GPU, NPU, DMC, and so on */ ++}; ++ ++enum system_monitor_event_type { ++ SYSTEM_MONITOR_CHANGE_TEMP = 0, ++}; ++ ++struct system_monitor_event_data { ++ int temp; ++}; ++ ++struct volt_adjust_table { ++ unsigned int min; /* Minimum frequency in MHz */ ++ unsigned int max; /* Maximum frequency in MHz */ ++ int volt; /* Voltage in microvolt */ ++}; ++ ++struct temp_freq_table { ++ int temp; /* millicelsius */ ++ unsigned int freq; /* KHz */ ++}; ++ ++/** ++ * struct temp_opp_table - System monitor device OPP description structure ++ * @rate: Frequency in hertz ++ * @volt: Target voltage in microvolt ++ * @mem_volt: Target voltage for memory in microvolt ++ * @low_temp_volt: Target voltage when low temperature, in microvolt ++ * @low_temp_mem_volt: Target voltage for memory when low temperature, ++ * in microvolt ++ * @max_volt: Maximum voltage in microvolt ++ * @max_mem_volt: Maximum voltage for memory in microvolt ++ */ ++struct temp_opp_table { ++ unsigned long rate; ++ unsigned long volt; ++ unsigned long mem_volt; ++ unsigned long low_temp_volt; ++ unsigned long low_temp_mem_volt; ++ unsigned long max_volt; ++ unsigned long max_mem_volt; ++}; ++ ++/** ++ * struct monitor_dev_info - structure for a system monitor device ++ * @dev: Device registered by system monitor ++ * @low_temp_adjust_table: Voltage margin for different OPPs when lowe ++ * temperature ++ * @opp_table: Frequency and voltage information of device ++ * @devp: Device-specific system monitor profile ++ * @node: Node in monitor_dev_list ++ * @high_limit_table: Limit maximum frequency at different temperature, ++ * but the frequency is also changed by thermal framework. ++ * @volt_adjust_mutex: A mutex to protect changing voltage. ++ * @max_temp_freq_req: CPU maximum frequency constraint changed according ++ * to temperature. ++ * @min_sta_freq_req: CPU minimum frequency constraint changed according ++ * to system status. ++ * @max_sta_freq_req: CPU maximum frequency constraint changed according ++ * to system status. ++ * @dev_max_freq_req: Devices maximum frequency constraint changed according ++ * to temperature. ++ * @low_limit: Limit maximum frequency when low temperature, in Hz ++ * @high_limit: Limit maximum frequency when high temperature, in Hz ++ * @max_volt: Maximum voltage in microvolt ++ * @low_temp_min_volt: Minimum voltage of OPPs when low temperature, in ++ * microvolt ++ * @high_temp_max_volt: Maximum voltage when high temperature, in microvolt ++ * @wide_temp_limit: Target maximum frequency when low or high temperature, ++ * in Hz ++ * @video_4k_freq: Maximum frequency when paly 4k video, in KHz ++ * @reboot_freq: Limit maximum and minimum frequency when reboot, in KHz ++ * @status_min_limit: Minimum frequency of some status frequency, in KHz ++ * @status_max_limit: Minimum frequency of all status frequency, in KHz ++ * @low_temp: Low temperature trip point, in millicelsius ++ * @high_temp: High temperature trip point, in millicelsius ++ * @temp_hysteresis: A low hysteresis value on low_temp, in millicelsius ++ * @is_low_temp: True if current temperature less than low_temp ++ * @is_high_temp: True if current temperature greater than high_temp ++ * @is_low_temp_enabled: True if device node contains low temperature ++ * configuration ++ * @is_status_freq_fixed: True if enter into some status ++ */ ++struct monitor_dev_info { ++ struct device *dev; ++ struct volt_adjust_table *low_temp_adjust_table; ++ struct temp_opp_table *opp_table; ++ struct monitor_dev_profile *devp; ++ struct list_head node; ++ struct temp_freq_table *high_limit_table; ++ struct mutex volt_adjust_mutex; ++ struct freq_qos_request max_temp_freq_req; ++ struct freq_qos_request min_sta_freq_req; ++ struct freq_qos_request max_sta_freq_req; ++ struct dev_pm_qos_request dev_max_freq_req; ++ struct regulator *early_reg; ++ struct regulator **regulators; ++ struct dev_pm_set_opp_data *set_opp_data; ++ struct clk *clk; ++ unsigned long low_limit; ++ unsigned long high_limit; ++ unsigned long max_volt; ++ unsigned long low_temp_min_volt; ++ unsigned long high_temp_max_volt; ++ unsigned int video_4k_freq; ++ unsigned int reboot_freq; ++ unsigned int init_freq; ++ unsigned int status_min_limit; ++ unsigned int status_max_limit; ++ unsigned int early_min_volt; ++ unsigned int regulator_count; ++ int low_temp; ++ int high_temp; ++ int temp_hysteresis; ++ bool is_low_temp; ++ bool is_high_temp; ++ bool is_low_temp_enabled; ++}; ++ ++struct monitor_dev_profile { ++ enum monitor_dev_type type; ++ void *data; ++ bool is_checked; ++ int (*low_temp_adjust)(struct monitor_dev_info *info, bool is_low); ++ int (*high_temp_adjust)(struct monitor_dev_info *info, bool is_low); ++ int (*update_volt)(struct monitor_dev_info *info); ++ int (*set_opp)(struct dev_pm_set_opp_data *data); ++ struct cpumask allowed_cpus; ++ struct rockchip_opp_info *opp_info; ++}; ++ ++#if IS_REACHABLE(CONFIG_ROCKCHIP_SYSTEM_MONITOR) ++struct monitor_dev_info * ++rockchip_system_monitor_register(struct device *dev, ++ struct monitor_dev_profile *devp); ++void rockchip_system_monitor_unregister(struct monitor_dev_info *info); ++int rockchip_monitor_cpu_low_temp_adjust(struct monitor_dev_info *info, ++ bool is_low); ++int rockchip_monitor_cpu_high_temp_adjust(struct monitor_dev_info *info, ++ bool is_high); ++void rockchip_monitor_volt_adjust_lock(struct monitor_dev_info *info); ++void rockchip_monitor_volt_adjust_unlock(struct monitor_dev_info *info); ++int rockchip_monitor_check_rate_volt(struct monitor_dev_info *info); ++int rockchip_monitor_dev_low_temp_adjust(struct monitor_dev_info *info, ++ bool is_low); ++int rockchip_monitor_dev_high_temp_adjust(struct monitor_dev_info *info, ++ bool is_high); ++int rockchip_monitor_suspend_low_temp_adjust(int cpu); ++int rockchip_system_monitor_register_notifier(struct notifier_block *nb); ++void rockchip_system_monitor_unregister_notifier(struct notifier_block *nb); ++#else ++static inline struct monitor_dev_info * ++rockchip_system_monitor_register(struct device *dev, ++ struct monitor_dev_profile *devp) ++{ ++ return ERR_PTR(-ENOTSUPP); ++}; ++ ++static inline void ++rockchip_system_monitor_unregister(struct monitor_dev_info *info) ++{ ++} ++ ++static inline int ++rockchip_monitor_cpu_low_temp_adjust(struct monitor_dev_info *info, bool is_low) ++{ ++ return 0; ++}; ++ ++static inline int ++rockchip_monitor_cpu_high_temp_adjust(struct monitor_dev_info *info, ++ bool is_high) ++{ ++ return 0; ++}; ++ ++static inline void ++rockchip_monitor_volt_adjust_lock(struct monitor_dev_info *info) ++{ ++} ++ ++static inline void ++rockchip_monitor_volt_adjust_unlock(struct monitor_dev_info *info) ++{ ++} ++ ++static inline int ++rockchip_monitor_check_rate_volt(struct monitor_dev_info *info) ++{ ++ return 0; ++} ++ ++static inline int ++rockchip_monitor_dev_low_temp_adjust(struct monitor_dev_info *info, bool is_low) ++{ ++ return 0; ++}; ++ ++static inline int ++rockchip_monitor_dev_high_temp_adjust(struct monitor_dev_info *info, ++ bool is_high) ++{ ++ return 0; ++}; ++ ++static inline int rockchip_monitor_suspend_low_temp_adjust(int cpu) ++{ ++ return 0; ++}; ++ ++static inline int ++rockchip_system_monitor_register_notifier(struct notifier_block *nb) ++{ ++ return 0; ++}; ++ ++static inline void ++rockchip_system_monitor_unregister_notifier(struct notifier_block *nb) ++{ ++}; ++#endif /* CONFIG_ROCKCHIP_SYSTEM_MONITOR */ ++ ++#endif +diff --git a/drivers/rknpu/include/rknpu_debugger.h b/drivers/rknpu/include/rknpu_debugger.h +new file mode 100644 +index 000000000..3f4420d44 +--- /dev/null ++++ b/drivers/rknpu/include/rknpu_debugger.h +@@ -0,0 +1,88 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) Rockchip Electronics Co.Ltd ++ * Author: Felix Zeng ++ */ ++ ++#ifndef __LINUX_RKNPU_DEBUGGER_H_ ++#define __LINUX_RKNPU_DEBUGGER_H_ ++ ++#include ++ ++/* ++ * struct rknpu_debugger - rknpu debugger information ++ * ++ * This structure represents a debugger to be created by the rknpu driver ++ * or core. ++ */ ++struct rknpu_debugger { ++#ifdef CONFIG_ROCKCHIP_RKNPU_DEBUG_FS ++ /* Directory of debugfs file */ ++ struct dentry *debugfs_dir; ++ struct list_head debugfs_entry_list; ++ struct mutex debugfs_lock; ++#endif ++#ifdef CONFIG_ROCKCHIP_RKNPU_PROC_FS ++ /* Directory of procfs file */ ++ struct proc_dir_entry *procfs_dir; ++ struct list_head procfs_entry_list; ++ struct mutex procfs_lock; ++#endif ++}; ++ ++/* ++ * struct rknpu_debugger_list - debugfs/procfs info list entry ++ * ++ * This structure represents a debugfs/procfs file to be created by the npu ++ * driver or core. ++ */ ++struct rknpu_debugger_list { ++ /* File name */ ++ const char *name; ++ /* ++ * Show callback. &seq_file->private will be set to the &struct ++ * rknpu_debugger_node corresponding to the instance of this info ++ * on a given &struct rknpu_debugger. ++ */ ++ int (*show)(struct seq_file *seq, void *data); ++ /* ++ * Write callback. &seq_file->private will be set to the &struct ++ * rknpu_debugger_node corresponding to the instance of this info ++ * on a given &struct rknpu_debugger. ++ */ ++ ssize_t (*write)(struct file *file, const char __user *ubuf, size_t len, ++ loff_t *offp); ++ /* Procfs/Debugfs private data. */ ++ void *data; ++}; ++ ++/* ++ * struct rknpu_debugger_node - Nodes for debugfs/procfs ++ * ++ * This structure represents each instance of procfs/debugfs created from the ++ * template. ++ */ ++struct rknpu_debugger_node { ++ struct rknpu_debugger *debugger; ++ ++ /* template for this node. */ ++ const struct rknpu_debugger_list *info_ent; ++ ++ /* Each Procfs/Debugfs file. */ ++#ifdef CONFIG_ROCKCHIP_RKNPU_DEBUG_FS ++ struct dentry *dent; ++#endif ++ ++#ifdef CONFIG_ROCKCHIP_RKNPU_PROC_FS ++ struct proc_dir_entry *pent; ++#endif ++ ++ struct list_head list; ++}; ++ ++struct rknpu_device; ++ ++int rknpu_debugger_init(struct rknpu_device *rknpu_dev); ++int rknpu_debugger_remove(struct rknpu_device *rknpu_dev); ++ ++#endif /* __LINUX_RKNPU_FENCE_H_ */ +diff --git a/drivers/rknpu/include/rknpu_drv.h b/drivers/rknpu/include/rknpu_drv.h +new file mode 100644 +index 000000000..2f7de548a +--- /dev/null ++++ b/drivers/rknpu/include/rknpu_drv.h +@@ -0,0 +1,174 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) Rockchip Electronics Co.Ltd ++ * Author: Felix Zeng ++ */ ++ ++#ifndef __LINUX_RKNPU_DRV_H_ ++#define __LINUX_RKNPU_DRV_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifndef FPGA_PLATFORM ++#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE ++#include ++#endif ++#endif ++ ++#include "rknpu_job.h" ++#include "rknpu_fence.h" ++#include "rknpu_debugger.h" ++#include "rknpu_mm.h" ++ ++#define DRIVER_NAME "rknpu" ++#define DRIVER_DESC "RKNPU driver" ++#define DRIVER_DATE "20230825" ++#define DRIVER_MAJOR 0 ++#define DRIVER_MINOR 9 ++#define DRIVER_PATCHLEVEL 2 ++ ++#define LOG_TAG "RKNPU" ++ ++/* sample interval: 1000ms */ ++#define RKNPU_LOAD_INTERVAL 1000000000 ++ ++#define LOG_INFO(fmt, args...) pr_info(LOG_TAG ": " fmt, ##args) ++#if KERNEL_VERSION(5, 5, 0) <= LINUX_VERSION_CODE ++#define LOG_WARN(fmt, args...) pr_warn(LOG_TAG ": " fmt, ##args) ++#else ++#define LOG_WARN(fmt, args...) pr_warning(LOG_TAG ": " fmt, ##args) ++#endif ++#define LOG_DEBUG(fmt, args...) pr_devel(LOG_TAG ": " fmt, ##args) ++#define LOG_ERROR(fmt, args...) pr_err(LOG_TAG ": " fmt, ##args) ++ ++#define LOG_DEV_INFO(dev, fmt, args...) dev_info(dev, LOG_TAG ": " fmt, ##args) ++#define LOG_DEV_WARN(dev, fmt, args...) dev_warn(dev, LOG_TAG ": " fmt, ##args) ++#define LOG_DEV_DEBUG(dev, fmt, args...) dev_dbg(dev, LOG_TAG ": " fmt, ##args) ++#define LOG_DEV_ERROR(dev, fmt, args...) dev_err(dev, LOG_TAG ": " fmt, ##args) ++ ++struct rknpu_reset_data { ++ const char *srst_a_name; ++ const char *srst_h_name; ++}; ++ ++struct rknpu_config { ++ __u32 bw_priority_addr; ++ __u32 bw_priority_length; ++ __u64 dma_mask; ++ __u32 pc_data_amount_scale; ++ __u32 pc_task_number_bits; ++ __u32 pc_task_number_mask; ++ __u32 pc_task_status_offset; ++ __u32 pc_dma_ctrl; ++ __u32 bw_enable; ++ const struct rknpu_irqs_data *irqs; ++ const struct rknpu_reset_data *resets; ++ int num_irqs; ++ int num_resets; ++ __u64 nbuf_phyaddr; ++ __u64 nbuf_size; ++ __u64 max_submit_number; ++}; ++ ++struct rknpu_timer { ++ __u32 busy_time; ++ __u32 busy_time_record; ++}; ++ ++struct rknpu_subcore_data { ++ struct list_head todo_list; ++ wait_queue_head_t job_done_wq; ++ struct rknpu_job *job; ++ int64_t task_num; ++ struct rknpu_timer timer; ++}; ++ ++/** ++ * RKNPU device ++ * ++ * @base: IO mapped base address for device ++ * @dev: Device instance ++ * @drm_dev: DRM device instance ++ */ ++struct rknpu_device { ++ void __iomem *base[RKNPU_MAX_CORES]; ++ struct device *dev; ++#ifdef CONFIG_ROCKCHIP_RKNPU_DRM_GEM ++ struct device *fake_dev; ++ struct drm_device *drm_dev; ++#endif ++#ifdef CONFIG_ROCKCHIP_RKNPU_DMA_HEAP ++ struct miscdevice miscdev; ++ struct rk_dma_heap *heap; ++#endif ++ atomic_t sequence; ++ spinlock_t lock; ++ spinlock_t irq_lock; ++ struct mutex power_lock; ++ struct mutex reset_lock; ++ struct rknpu_subcore_data subcore_datas[RKNPU_MAX_CORES]; ++ const struct rknpu_config *config; ++ void __iomem *bw_priority_base; ++ struct rknpu_fence_context *fence_ctx; ++ bool iommu_en; ++ struct reset_control *srst_a[RKNPU_MAX_CORES]; ++ struct reset_control *srst_h[RKNPU_MAX_CORES]; ++ struct clk_bulk_data *clks; ++ int num_clks; ++ struct regulator *vdd; ++ struct regulator *mem; ++ struct monitor_dev_info *mdev_info; ++ struct ipa_power_model_data *model_data; ++ struct thermal_cooling_device *devfreq_cooling; ++ struct devfreq *devfreq; ++ unsigned long ondemand_freq; ++#ifndef FPGA_PLATFORM ++#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE ++ struct rockchip_opp_info opp_info; ++#endif ++#endif ++ unsigned long current_freq; ++ unsigned long current_volt; ++ int bypass_irq_handler; ++ int bypass_soft_reset; ++ bool soft_reseting; ++ struct device *genpd_dev_npu0; ++ struct device *genpd_dev_npu1; ++ struct device *genpd_dev_npu2; ++ bool multiple_domains; ++ atomic_t power_refcount; ++ atomic_t cmdline_power_refcount; ++ struct delayed_work power_off_work; ++ struct workqueue_struct *power_off_wq; ++ struct rknpu_debugger debugger; ++ struct hrtimer timer; ++ ktime_t kt; ++ phys_addr_t sram_start; ++ phys_addr_t sram_end; ++ phys_addr_t nbuf_start; ++ phys_addr_t nbuf_end; ++ uint32_t sram_size; ++ uint32_t nbuf_size; ++ void __iomem *sram_base_io; ++ void __iomem *nbuf_base_io; ++ struct rknpu_mm *sram_mm; ++ unsigned long power_put_delay; ++}; ++ ++struct rknpu_session { ++ struct rknpu_device *rknpu_dev; ++ struct list_head list; ++}; ++ ++int rknpu_power_get(struct rknpu_device *rknpu_dev); ++int rknpu_power_put(struct rknpu_device *rknpu_dev); ++ ++#endif /* __LINUX_RKNPU_DRV_H_ */ +diff --git a/drivers/rknpu/include/rknpu_fence.h b/drivers/rknpu/include/rknpu_fence.h +new file mode 100644 +index 000000000..164f6de41 +--- /dev/null ++++ b/drivers/rknpu/include/rknpu_fence.h +@@ -0,0 +1,24 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) Rockchip Electronics Co.Ltd ++ * Author: Felix Zeng ++ */ ++ ++#ifndef __LINUX_RKNPU_FENCE_H_ ++#define __LINUX_RKNPU_FENCE_H_ ++ ++#include "rknpu_job.h" ++ ++struct rknpu_fence_context { ++ unsigned int context; ++ unsigned int seqno; ++ spinlock_t spinlock; ++}; ++ ++int rknpu_fence_context_alloc(struct rknpu_device *rknpu_dev); ++ ++int rknpu_fence_alloc(struct rknpu_job *job); ++ ++int rknpu_fence_get_fd(struct rknpu_job *job); ++ ++#endif /* __LINUX_RKNPU_FENCE_H_ */ +diff --git a/drivers/rknpu/include/rknpu_gem.h b/drivers/rknpu/include/rknpu_gem.h +new file mode 100644 +index 000000000..aedcab89d +--- /dev/null ++++ b/drivers/rknpu/include/rknpu_gem.h +@@ -0,0 +1,213 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) Rockchip Electronics Co.Ltd ++ * Author: Felix Zeng ++ */ ++ ++#ifndef __LINUX_RKNPU_GEM_H ++#define __LINUX_RKNPU_GEM_H ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#if KERNEL_VERSION(4, 14, 0) > LINUX_VERSION_CODE ++#include ++#endif ++ ++#include "rknpu_mm.h" ++ ++#define to_rknpu_obj(x) container_of(x, struct rknpu_gem_object, base) ++ ++/* ++ * rknpu drm buffer structure. ++ * ++ * @base: a gem object. ++ * - a new handle to this gem object would be created ++ * by drm_gem_handle_create(). ++ * @flags: indicate memory type to allocated buffer and cache attribute. ++ * @size: size requested from user, in bytes and this size is aligned ++ * in page unit. ++ * @cookie: cookie returned by dma_alloc_attrs ++ * @kv_addr: kernel virtual address to allocated memory region. ++ * @dma_addr: bus address(accessed by dma) to allocated memory region. ++ * - this address could be physical address without IOMMU and ++ * device address with IOMMU. ++ * @pages: Array of backing pages. ++ * @sgt: Imported sg_table. ++ * ++ * P.S. this object would be transferred to user as kms_bo.handle so ++ * user can access the buffer through kms_bo.handle. ++ */ ++struct rknpu_gem_object { ++ struct drm_gem_object base; ++ unsigned int flags; ++ unsigned long size; ++ unsigned long sram_size; ++ unsigned long nbuf_size; ++ struct rknpu_mm_obj *sram_obj; ++ dma_addr_t iova_start; ++ unsigned long iova_size; ++ void *cookie; ++ void __iomem *kv_addr; ++ dma_addr_t dma_addr; ++ unsigned long dma_attrs; ++ unsigned long num_pages; ++ struct page **pages; ++ struct sg_table *sgt; ++ struct drm_mm_node mm_node; ++}; ++ ++enum rknpu_cache_type { ++ RKNPU_CACHE_SRAM = 1 << 0, ++ RKNPU_CACHE_NBUF = 1 << 1, ++}; ++ ++/* create a new buffer with gem object */ ++struct rknpu_gem_object *rknpu_gem_object_create(struct drm_device *dev, ++ unsigned int flags, ++ unsigned long size, ++ unsigned long sram_size); ++ ++/* destroy a buffer with gem object */ ++void rknpu_gem_object_destroy(struct rknpu_gem_object *rknpu_obj); ++ ++/* request gem object creation and buffer allocation as the size */ ++int rknpu_gem_create_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++ ++/* get fake-offset of gem object that can be used with mmap. */ ++int rknpu_gem_map_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++ ++int rknpu_gem_destroy_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++ ++/* ++ * get rknpu drm object, ++ * gem object reference count would be increased. ++ */ ++static inline void rknpu_gem_object_get(struct drm_gem_object *obj) ++{ ++#if KERNEL_VERSION(4, 13, 0) < LINUX_VERSION_CODE ++ drm_gem_object_get(obj); ++#else ++ drm_gem_object_reference(obj); ++#endif ++} ++ ++/* ++ * put rknpu drm object acquired from rknpu_gem_object_find() or rknpu_gem_object_get(), ++ * gem object reference count would be decreased. ++ */ ++static inline void rknpu_gem_object_put(struct drm_gem_object *obj) ++{ ++#if KERNEL_VERSION(5, 9, 0) <= LINUX_VERSION_CODE ++ drm_gem_object_put(obj); ++#elif KERNEL_VERSION(4, 13, 0) < LINUX_VERSION_CODE ++ drm_gem_object_put_unlocked(obj); ++#else ++ drm_gem_object_unreference_unlocked(obj); ++#endif ++} ++ ++/* ++ * get rknpu drm object from gem handle, this function could be used for ++ * other drivers such as 2d/3d acceleration drivers. ++ * with this function call, gem object reference count would be increased. ++ */ ++static inline struct rknpu_gem_object * ++rknpu_gem_object_find(struct drm_file *filp, unsigned int handle) ++{ ++ struct drm_gem_object *obj; ++ ++ obj = drm_gem_object_lookup(filp, handle); ++ if (!obj) { ++ // DRM_ERROR("failed to lookup gem object.\n"); ++ return NULL; ++ } ++ ++ rknpu_gem_object_put(obj); ++ ++ return to_rknpu_obj(obj); ++} ++ ++/* get buffer information to memory region allocated by gem. */ ++int rknpu_gem_get_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++ ++/* free gem object. */ ++void rknpu_gem_free_object(struct drm_gem_object *obj); ++ ++/* create memory region for drm framebuffer. */ ++int rknpu_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev, ++ struct drm_mode_create_dumb *args); ++ ++#if KERNEL_VERSION(4, 19, 0) > LINUX_VERSION_CODE ++/* map memory region for drm framebuffer to user space. */ ++int rknpu_gem_dumb_map_offset(struct drm_file *file_priv, ++ struct drm_device *dev, uint32_t handle, ++ uint64_t *offset); ++#endif ++ ++/* page fault handler and mmap fault address(virtual) to physical memory. */ ++#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE ++vm_fault_t rknpu_gem_fault(struct vm_fault *vmf); ++#elif KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE ++int rknpu_gem_fault(struct vm_fault *vmf); ++#else ++int rknpu_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); ++#endif ++ ++int rknpu_gem_mmap_obj(struct drm_gem_object *obj, struct vm_area_struct *vma); ++ ++/* set vm_flags and we can change the vm attribute to other one at here. */ ++int rknpu_gem_mmap(struct file *filp, struct vm_area_struct *vma); ++ ++/* low-level interface prime helpers */ ++#if KERNEL_VERSION(4, 13, 0) <= LINUX_VERSION_CODE ++struct drm_gem_object *rknpu_gem_prime_import(struct drm_device *dev, ++ struct dma_buf *dma_buf); ++#endif ++struct sg_table *rknpu_gem_prime_get_sg_table(struct drm_gem_object *obj); ++struct drm_gem_object * ++rknpu_gem_prime_import_sg_table(struct drm_device *dev, ++ struct dma_buf_attachment *attach, ++ struct sg_table *sgt); ++#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE ++void *rknpu_gem_prime_vmap(struct drm_gem_object *obj); ++void rknpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr); ++#else ++int rknpu_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map); ++void rknpu_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map *map); ++#endif ++int rknpu_gem_prime_mmap(struct drm_gem_object *obj, ++ struct vm_area_struct *vma); ++ ++int rknpu_gem_sync_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++ ++static inline void *rknpu_gem_alloc_page(size_t nr_pages) ++{ ++#if KERNEL_VERSION(4, 13, 0) <= LINUX_VERSION_CODE ++ return kvmalloc_array(nr_pages, sizeof(struct page *), ++ GFP_KERNEL | __GFP_ZERO); ++#else ++ return drm_calloc_large(nr_pages, sizeof(struct page *)); ++#endif ++} ++ ++static inline void rknpu_gem_free_page(void *pages) ++{ ++#if KERNEL_VERSION(4, 13, 0) <= LINUX_VERSION_CODE ++ kvfree(pages); ++#else ++ drm_free_large(pages); ++#endif ++} ++ ++#endif +diff --git a/drivers/rknpu/include/rknpu_ioctl.h b/drivers/rknpu/include/rknpu_ioctl.h +new file mode 100644 +index 000000000..2397dd295 +--- /dev/null ++++ b/drivers/rknpu/include/rknpu_ioctl.h +@@ -0,0 +1,12 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) Rockchip Electronics Co.Ltd ++ * Author: Felix Zeng ++ * ++ * 6.18 port note: the real UAPI content lives at ++ * include/uapi/drm/rknpu_ioctl.h (mainline convention for DRM ioctl UAPI ++ * headers -- drivers/accel/rocket dot-c files include drm/rocket_accel.h ++ * the same way). This redirect keeps the vendor source's local ++ * #include "rknpu_ioctl.h" working unmodified. ++ */ ++#include +diff --git a/drivers/rknpu/include/rknpu_iommu.h b/drivers/rknpu/include/rknpu_iommu.h +new file mode 100644 +index 000000000..aa680c997 +--- /dev/null ++++ b/drivers/rknpu/include/rknpu_iommu.h +@@ -0,0 +1,40 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) Rockchip Electronics Co.Ltd ++ * Author: Felix Zeng ++ */ ++ ++#ifndef __LINUX_RKNPU_IOMMU_H ++#define __LINUX_RKNPU_IOMMU_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE ++#include ++#endif ++ ++#include "rknpu_drv.h" ++ ++enum iommu_dma_cookie_type { ++ IOMMU_DMA_IOVA_COOKIE, ++ IOMMU_DMA_MSI_COOKIE, ++}; ++ ++struct rknpu_iommu_dma_cookie { ++ enum iommu_dma_cookie_type type; ++ ++ /* Full allocator for IOMMU_DMA_IOVA_COOKIE */ ++ struct iova_domain iovad; ++}; ++ ++dma_addr_t rknpu_iommu_dma_alloc_iova(struct iommu_domain *domain, size_t size, ++ u64 dma_limit, struct device *dev); ++ ++void rknpu_iommu_dma_free_iova(struct rknpu_iommu_dma_cookie *cookie, ++ dma_addr_t iova, size_t size); ++ ++#endif +diff --git a/drivers/rknpu/include/rknpu_job.h b/drivers/rknpu/include/rknpu_job.h +new file mode 100644 +index 000000000..c62b1bf8e +--- /dev/null ++++ b/drivers/rknpu/include/rknpu_job.h +@@ -0,0 +1,79 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) Rockchip Electronics Co.Ltd ++ * Author: Felix Zeng ++ */ ++ ++#ifndef __LINUX_RKNPU_JOB_H_ ++#define __LINUX_RKNPU_JOB_H_ ++ ++#include ++#include ++#include ++ ++#include ++ ++#include "rknpu_ioctl.h" ++ ++#define RKNPU_MAX_CORES 3 ++ ++#define RKNPU_JOB_DONE (1 << 0) ++#define RKNPU_JOB_ASYNC (1 << 1) ++#define RKNPU_JOB_DETACHED (1 << 2) ++ ++#define RKNPU_CORE_AUTO_MASK 0x00 ++#define RKNPU_CORE0_MASK 0x01 ++#define RKNPU_CORE1_MASK 0x02 ++#define RKNPU_CORE2_MASK 0x04 ++ ++struct rknpu_job { ++ struct rknpu_device *rknpu_dev; ++ struct list_head head[RKNPU_MAX_CORES]; ++ struct work_struct cleanup_work; ++ bool irq_entry[RKNPU_MAX_CORES]; ++ unsigned int flags; ++ int ret; ++ struct rknpu_submit *args; ++ bool args_owner; ++ struct rknpu_task *first_task; ++ struct rknpu_task *last_task; ++ uint32_t int_mask[RKNPU_MAX_CORES]; ++ uint32_t int_status[RKNPU_MAX_CORES]; ++ struct dma_fence *fence; ++ ktime_t timestamp; ++ uint32_t use_core_num; ++ atomic_t run_count; ++ atomic_t interrupt_count; ++ ktime_t hw_recoder_time; ++ ktime_t commit_pc_time; ++ atomic_t submit_count[RKNPU_MAX_CORES]; ++}; ++ ++irqreturn_t rknpu_core0_irq_handler(int irq, void *data); ++irqreturn_t rknpu_core1_irq_handler(int irq, void *data); ++irqreturn_t rknpu_core2_irq_handler(int irq, void *data); ++ ++#ifdef CONFIG_ROCKCHIP_RKNPU_DRM_GEM ++int rknpu_submit_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++#endif ++#ifdef CONFIG_ROCKCHIP_RKNPU_DMA_HEAP ++int rknpu_submit_ioctl(struct rknpu_device *rknpu_dev, unsigned long data); ++#endif ++ ++int rknpu_get_hw_version(struct rknpu_device *rknpu_dev, uint32_t *version); ++ ++int rknpu_get_bw_priority(struct rknpu_device *rknpu_dev, uint32_t *priority, ++ uint32_t *expect, uint32_t *tw); ++ ++int rknpu_set_bw_priority(struct rknpu_device *rknpu_dev, uint32_t priority, ++ uint32_t expect, uint32_t tw); ++ ++int rknpu_clear_rw_amount(struct rknpu_device *rknpu_dev); ++ ++int rknpu_get_rw_amount(struct rknpu_device *rknpu_dev, uint32_t *dt_wr, ++ uint32_t *dt_rd, uint32_t *wd_rd); ++ ++int rknpu_get_total_rw_amount(struct rknpu_device *rknpu_dev, uint32_t *amount); ++ ++#endif /* __LINUX_RKNPU_JOB_H_ */ +diff --git a/drivers/rknpu/include/rknpu_mem.h b/drivers/rknpu/include/rknpu_mem.h +new file mode 100644 +index 000000000..69975408f +--- /dev/null ++++ b/drivers/rknpu/include/rknpu_mem.h +@@ -0,0 +1,46 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) Rockchip Electronics Co.Ltd ++ * Author: Felix Zeng ++ */ ++ ++#ifndef __LINUX_RKNPU_MEM_H ++#define __LINUX_RKNPU_MEM_H ++ ++#include ++#include ++ ++/* ++ * rknpu DMA buffer structure. ++ * ++ * @flags: indicate memory type to allocated buffer and cache attribute. ++ * @size: size requested from user, in bytes and this size is aligned ++ * in page unit. ++ * @kv_addr: kernel virtual address to allocated memory region. ++ * @dma_addr: bus address(accessed by dma) to allocated memory region. ++ * - this address could be physical address without IOMMU and ++ * device address with IOMMU. ++ * @pages: Array of backing pages. ++ * @sgt: Imported sg_table. ++ * @dmabuf: buffer for this attachment. ++ * @owner: Is this memory internally allocated. ++ */ ++struct rknpu_mem_object { ++ unsigned long flags; ++ unsigned long size; ++ void __iomem *kv_addr; ++ dma_addr_t dma_addr; ++ struct page **pages; ++ struct sg_table *sgt; ++ struct dma_buf *dmabuf; ++ struct list_head head; ++ unsigned int owner; ++}; ++ ++int rknpu_mem_create_ioctl(struct rknpu_device *rknpu_dev, unsigned long data, ++ struct file *file); ++int rknpu_mem_destroy_ioctl(struct rknpu_device *rknpu_dev, unsigned long data, ++ struct file *file); ++int rknpu_mem_sync_ioctl(struct rknpu_device *rknpu_dev, unsigned long data); ++ ++#endif +diff --git a/drivers/rknpu/include/rknpu_mm.h b/drivers/rknpu/include/rknpu_mm.h +new file mode 100644 +index 000000000..73ae6d7ce +--- /dev/null ++++ b/drivers/rknpu/include/rknpu_mm.h +@@ -0,0 +1,42 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) Rockchip Electronics Co.Ltd ++ * Author: Felix Zeng ++ */ ++ ++#ifndef __LINUX_RKNPU_MM_H ++#define __LINUX_RKNPU_MM_H ++ ++#include ++#include ++#include ++#include ++ ++#include "rknpu_drv.h" ++ ++struct rknpu_mm { ++ void *bitmap; ++ struct mutex lock; ++ unsigned int chunk_size; ++ unsigned int total_chunks; ++ unsigned int free_chunks; ++}; ++ ++struct rknpu_mm_obj { ++ uint32_t range_start; ++ uint32_t range_end; ++}; ++ ++int rknpu_mm_create(unsigned int mem_size, unsigned int chunk_size, ++ struct rknpu_mm **mm); ++ ++void rknpu_mm_destroy(struct rknpu_mm *mm); ++ ++int rknpu_mm_alloc(struct rknpu_mm *mm, unsigned int size, ++ struct rknpu_mm_obj **mm_obj); ++ ++int rknpu_mm_free(struct rknpu_mm *mm, struct rknpu_mm_obj *mm_obj); ++ ++int rknpu_mm_dump(struct seq_file *m, void *data); ++ ++#endif +diff --git a/drivers/rknpu/include/rknpu_reset.h b/drivers/rknpu/include/rknpu_reset.h +new file mode 100644 +index 000000000..b80e29b32 +--- /dev/null ++++ b/drivers/rknpu/include/rknpu_reset.h +@@ -0,0 +1,18 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) Rockchip Electronics Co.Ltd ++ * Author: Felix Zeng ++ */ ++ ++#ifndef __LINUX_RKNPU_RESET_H ++#define __LINUX_RKNPU_RESET_H ++ ++#include ++ ++#include "rknpu_drv.h" ++ ++int rknpu_reset_get(struct rknpu_device *rknpu_dev); ++ ++int rknpu_soft_reset(struct rknpu_device *rknpu_dev); ++ ++#endif +diff --git a/drivers/rknpu/rknpu_debugger.c b/drivers/rknpu/rknpu_debugger.c +new file mode 100644 +index 000000000..97c875215 +--- /dev/null ++++ b/drivers/rknpu/rknpu_debugger.c +@@ -0,0 +1,605 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) Rockchip Electronics Co.Ltd ++ * Author: Felix Zeng ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifndef FPGA_PLATFORM ++#ifdef CONFIG_PM_DEVFREQ ++#include <../drivers/devfreq/governor.h> ++#endif ++#endif ++ ++#include "rknpu_drv.h" ++#include "rknpu_mm.h" ++#include "rknpu_reset.h" ++#include "rknpu_debugger.h" ++ ++#define RKNPU_DEBUGGER_ROOT_NAME "rknpu" ++ ++#if defined(CONFIG_ROCKCHIP_RKNPU_DEBUG_FS) || \ ++ defined(CONFIG_ROCKCHIP_RKNPU_PROC_FS) ++static int rknpu_version_show(struct seq_file *m, void *data) ++{ ++ seq_printf(m, "%s: v%d.%d.%d\n", DRIVER_DESC, DRIVER_MAJOR, ++ DRIVER_MINOR, DRIVER_PATCHLEVEL); ++ ++ return 0; ++} ++ ++static int rknpu_load_show(struct seq_file *m, void *data) ++{ ++ struct rknpu_debugger_node *node = m->private; ++ struct rknpu_debugger *debugger = node->debugger; ++ struct rknpu_device *rknpu_dev = ++ container_of(debugger, struct rknpu_device, debugger); ++ struct rknpu_subcore_data *subcore_data = NULL; ++ unsigned long flags; ++ int i; ++ int load; ++ uint64_t busy_time_total, div_value; ++ ++ seq_puts(m, "NPU load: "); ++ for (i = 0; i < rknpu_dev->config->num_irqs; i++) { ++ subcore_data = &rknpu_dev->subcore_datas[i]; ++ ++ if (rknpu_dev->config->num_irqs > 1) ++ seq_printf(m, " Core%d: ", i); ++ ++ spin_lock_irqsave(&rknpu_dev->irq_lock, flags); ++ ++ busy_time_total = subcore_data->timer.busy_time_record; ++ ++ spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags); ++ ++ div_value = (RKNPU_LOAD_INTERVAL / 100000); ++ do_div(busy_time_total, div_value); ++ load = busy_time_total > 100 ? 100 : busy_time_total; ++ ++ if (rknpu_dev->config->num_irqs > 1) ++ seq_printf(m, "%2.d%%,", load); ++ else ++ seq_printf(m, "%2.d%%", load); ++ } ++ seq_puts(m, "\n"); ++ ++ return 0; ++} ++ ++static int rknpu_power_show(struct seq_file *m, void *data) ++{ ++ struct rknpu_debugger_node *node = m->private; ++ struct rknpu_debugger *debugger = node->debugger; ++ struct rknpu_device *rknpu_dev = ++ container_of(debugger, struct rknpu_device, debugger); ++ ++ if (atomic_read(&rknpu_dev->power_refcount) > 0) ++ seq_puts(m, "on\n"); ++ else ++ seq_puts(m, "off\n"); ++ ++ return 0; ++} ++ ++static ssize_t rknpu_power_set(struct file *file, const char __user *ubuf, ++ size_t len, loff_t *offp) ++{ ++ struct seq_file *priv = file->private_data; ++ struct rknpu_debugger_node *node = priv->private; ++ struct rknpu_debugger *debugger = node->debugger; ++ struct rknpu_device *rknpu_dev = ++ container_of(debugger, struct rknpu_device, debugger); ++ char buf[8]; ++ ++ if (len > sizeof(buf) - 1) ++ return -EINVAL; ++ if (copy_from_user(buf, ubuf, len)) ++ return -EFAULT; ++ buf[len - 1] = '\0'; ++ ++ if (strcmp(buf, "on") == 0) { ++ atomic_inc(&rknpu_dev->cmdline_power_refcount); ++ rknpu_power_get(rknpu_dev); ++ LOG_INFO("rknpu power is on!"); ++ } else if (strcmp(buf, "off") == 0) { ++ if (atomic_read(&rknpu_dev->power_refcount) > 0 && ++ atomic_dec_if_positive( ++ &rknpu_dev->cmdline_power_refcount) >= 0) { ++ atomic_sub( ++ atomic_read(&rknpu_dev->cmdline_power_refcount), ++ &rknpu_dev->power_refcount); ++ atomic_set(&rknpu_dev->cmdline_power_refcount, 0); ++ rknpu_power_put(rknpu_dev); ++ } ++ if (atomic_read(&rknpu_dev->power_refcount) <= 0) ++ LOG_INFO("rknpu power is off!"); ++ } else { ++ LOG_ERROR("rknpu power node params is invalid!"); ++ } ++ ++ return len; ++} ++ ++static int rknpu_power_put_delay_show(struct seq_file *m, void *data) ++{ ++ struct rknpu_debugger_node *node = m->private; ++ struct rknpu_debugger *debugger = node->debugger; ++ struct rknpu_device *rknpu_dev = ++ container_of(debugger, struct rknpu_device, debugger); ++ ++ seq_printf(m, "%lu\n", rknpu_dev->power_put_delay); ++ ++ return 0; ++} ++ ++static ssize_t rknpu_power_put_delay_set(struct file *file, ++ const char __user *ubuf, size_t len, ++ loff_t *offp) ++{ ++ struct seq_file *priv = file->private_data; ++ struct rknpu_debugger_node *node = priv->private; ++ struct rknpu_debugger *debugger = node->debugger; ++ struct rknpu_device *rknpu_dev = ++ container_of(debugger, struct rknpu_device, debugger); ++ char buf[16]; ++ unsigned long power_put_delay = 0; ++ int ret = 0; ++ ++ if (len > sizeof(buf) - 1) ++ return -EINVAL; ++ if (copy_from_user(buf, ubuf, len)) ++ return -EFAULT; ++ buf[len - 1] = '\0'; ++ ++ ret = kstrtoul(buf, 10, &power_put_delay); ++ if (ret) { ++ LOG_ERROR("failed to parse power put delay string: %s\n", buf); ++ return -EFAULT; ++ } ++ ++ rknpu_dev->power_put_delay = power_put_delay; ++ ++ LOG_INFO("set rknpu power put delay time %lums\n", ++ rknpu_dev->power_put_delay); ++ ++ return len; ++} ++ ++static int rknpu_freq_show(struct seq_file *m, void *data) ++{ ++ struct rknpu_debugger_node *node = m->private; ++ struct rknpu_debugger *debugger = node->debugger; ++ struct rknpu_device *rknpu_dev = ++ container_of(debugger, struct rknpu_device, debugger); ++ unsigned long current_freq = 0; ++ ++ rknpu_power_get(rknpu_dev); ++ ++ current_freq = clk_get_rate(rknpu_dev->clks[0].clk); ++ ++ rknpu_power_put(rknpu_dev); ++ ++ seq_printf(m, "%lu\n", current_freq); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_DEVFREQ ++static ssize_t rknpu_freq_set(struct file *file, const char __user *ubuf, ++ size_t len, loff_t *offp) ++{ ++ struct seq_file *priv = file->private_data; ++ struct rknpu_debugger_node *node = priv->private; ++ struct rknpu_debugger *debugger = node->debugger; ++ struct rknpu_device *rknpu_dev = ++ container_of(debugger, struct rknpu_device, debugger); ++ unsigned long current_freq = 0; ++ char buf[16]; ++ unsigned long freq = 0; ++ int ret = 0; ++ ++ if (len > sizeof(buf) - 1) ++ return -EINVAL; ++ if (copy_from_user(buf, ubuf, len)) ++ return -EFAULT; ++ buf[len - 1] = '\0'; ++ ++ ret = kstrtoul(buf, 10, &freq); ++ if (ret) { ++ LOG_ERROR("failed to parse freq string: %s\n", buf); ++ return -EFAULT; ++ } ++ ++ if (!rknpu_dev->devfreq) ++ return -EFAULT; ++ ++ rknpu_power_get(rknpu_dev); ++ ++ current_freq = clk_get_rate(rknpu_dev->clks[0].clk); ++ if (freq != current_freq) { ++ rknpu_dev->ondemand_freq = freq; ++ mutex_lock(&rknpu_dev->devfreq->lock); ++ update_devfreq(rknpu_dev->devfreq); ++ mutex_unlock(&rknpu_dev->devfreq->lock); ++ } ++ ++ rknpu_power_put(rknpu_dev); ++ ++ return len; ++} ++#else ++static ssize_t rknpu_freq_set(struct file *file, const char __user *ubuf, ++ size_t len, loff_t *offp) ++{ ++ return -EFAULT; ++} ++#endif ++ ++static int rknpu_volt_show(struct seq_file *m, void *data) ++{ ++ struct rknpu_debugger_node *node = m->private; ++ struct rknpu_debugger *debugger = node->debugger; ++ struct rknpu_device *rknpu_dev = ++ container_of(debugger, struct rknpu_device, debugger); ++ unsigned long current_volt = 0; ++ ++ current_volt = regulator_get_voltage(rknpu_dev->vdd); ++ ++ seq_printf(m, "%lu\n", current_volt); ++ ++ return 0; ++} ++ ++static int rknpu_reset_show(struct seq_file *m, void *data) ++{ ++ struct rknpu_debugger_node *node = m->private; ++ struct rknpu_debugger *debugger = node->debugger; ++ struct rknpu_device *rknpu_dev = ++ container_of(debugger, struct rknpu_device, debugger); ++ ++ if (!rknpu_dev->bypass_soft_reset) ++ seq_puts(m, "on\n"); ++ else ++ seq_puts(m, "off\n"); ++ ++ return 0; ++} ++ ++static ssize_t rknpu_reset_set(struct file *file, const char __user *ubuf, ++ size_t len, loff_t *offp) ++{ ++ struct seq_file *priv = file->private_data; ++ struct rknpu_debugger_node *node = priv->private; ++ struct rknpu_debugger *debugger = node->debugger; ++ struct rknpu_device *rknpu_dev = ++ container_of(debugger, struct rknpu_device, debugger); ++ char buf[8]; ++ ++ if (len > sizeof(buf) - 1) ++ return -EINVAL; ++ if (copy_from_user(buf, ubuf, len)) ++ return -EFAULT; ++ buf[len - 1] = '\0'; ++ ++ if (strcmp(buf, "1") == 0 && ++ atomic_read(&rknpu_dev->power_refcount) > 0) ++ rknpu_soft_reset(rknpu_dev); ++ else if (strcmp(buf, "on") == 0) ++ rknpu_dev->bypass_soft_reset = 0; ++ else if (strcmp(buf, "off") == 0) ++ rknpu_dev->bypass_soft_reset = 1; ++ ++ return len; ++} ++ ++static struct rknpu_debugger_list rknpu_debugger_root_list[] = { ++ { "version", rknpu_version_show, NULL, NULL }, ++ { "load", rknpu_load_show, NULL, NULL }, ++ { "power", rknpu_power_show, rknpu_power_set, NULL }, ++ { "freq", rknpu_freq_show, rknpu_freq_set, NULL }, ++ { "volt", rknpu_volt_show, NULL, NULL }, ++ { "delayms", rknpu_power_put_delay_show, rknpu_power_put_delay_set, ++ NULL }, ++ { "reset", rknpu_reset_show, rknpu_reset_set, NULL }, ++#ifdef CONFIG_ROCKCHIP_RKNPU_SRAM ++ { "mm", rknpu_mm_dump, NULL, NULL }, ++#endif ++}; ++ ++static ssize_t rknpu_debugger_write(struct file *file, const char __user *ubuf, ++ size_t len, loff_t *offp) ++{ ++ struct seq_file *priv = file->private_data; ++ struct rknpu_debugger_node *node = priv->private; ++ ++ if (node->info_ent->write) ++ return node->info_ent->write(file, ubuf, len, offp); ++ else ++ return len; ++} ++ ++static int rknpu_debugfs_open(struct inode *inode, struct file *file) ++{ ++ struct rknpu_debugger_node *node = inode->i_private; ++ ++ return single_open(file, node->info_ent->show, node); ++} ++ ++static const struct file_operations rknpu_debugfs_fops = { ++ .owner = THIS_MODULE, ++ .open = rknpu_debugfs_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++ .write = rknpu_debugger_write, ++}; ++#endif /* #if defined(CONFIG_ROCKCHIP_RKNPU_DEBUG_FS) || defined(CONFIG_ROCKCHIP_RKNPU_PROC_FS) */ ++ ++#ifdef CONFIG_ROCKCHIP_RKNPU_DEBUG_FS ++static int rknpu_debugfs_remove_files(struct rknpu_debugger *debugger) ++{ ++ struct rknpu_debugger_node *pos, *q; ++ struct list_head *entry_list; ++ ++ mutex_lock(&debugger->debugfs_lock); ++ ++ /* Delete debugfs entry list */ ++ entry_list = &debugger->debugfs_entry_list; ++ list_for_each_entry_safe(pos, q, entry_list, list) { ++ if (pos->dent == NULL) ++ continue; ++ list_del(&pos->list); ++ kfree(pos); ++ pos = NULL; ++ } ++ ++ /* Delete all debugfs node in this directory */ ++ debugfs_remove_recursive(debugger->debugfs_dir); ++ debugger->debugfs_dir = NULL; ++ ++ mutex_unlock(&debugger->debugfs_lock); ++ ++ return 0; ++} ++ ++static int rknpu_debugfs_create_files(const struct rknpu_debugger_list *files, ++ int count, struct dentry *root, ++ struct rknpu_debugger *debugger) ++{ ++ int i; ++ struct dentry *ent; ++ struct rknpu_debugger_node *tmp; ++ ++ for (i = 0; i < count; i++) { ++ tmp = kmalloc(sizeof(struct rknpu_debugger_node), GFP_KERNEL); ++ if (tmp == NULL) { ++ LOG_ERROR( ++ "Cannot alloc node path /sys/kernel/debug/%pd/%s\n", ++ root, files[i].name); ++ goto MALLOC_FAIL; ++ } ++ ++ tmp->info_ent = &files[i]; ++ tmp->debugger = debugger; ++ ++ ent = debugfs_create_file(files[i].name, S_IFREG | S_IRUGO, ++ root, tmp, &rknpu_debugfs_fops); ++ if (!ent) { ++ LOG_ERROR("Cannot create /sys/kernel/debug/%pd/%s\n", ++ root, files[i].name); ++ goto CREATE_FAIL; ++ } ++ ++ tmp->dent = ent; ++ ++ mutex_lock(&debugger->debugfs_lock); ++ list_add_tail(&tmp->list, &debugger->debugfs_entry_list); ++ mutex_unlock(&debugger->debugfs_lock); ++ } ++ ++ return 0; ++ ++CREATE_FAIL: ++ kfree(tmp); ++MALLOC_FAIL: ++ rknpu_debugfs_remove_files(debugger); ++ ++ return -1; ++} ++ ++static int rknpu_debugfs_remove(struct rknpu_debugger *debugger) ++{ ++ rknpu_debugfs_remove_files(debugger); ++ ++ return 0; ++} ++ ++static int rknpu_debugfs_init(struct rknpu_debugger *debugger) ++{ ++ int ret; ++ ++ debugger->debugfs_dir = ++ debugfs_create_dir(RKNPU_DEBUGGER_ROOT_NAME, NULL); ++ if (IS_ERR_OR_NULL(debugger->debugfs_dir)) { ++ LOG_ERROR("failed on mkdir /sys/kernel/debug/%s\n", ++ RKNPU_DEBUGGER_ROOT_NAME); ++ debugger->debugfs_dir = NULL; ++ return -EIO; ++ } ++ ++ ret = rknpu_debugfs_create_files(rknpu_debugger_root_list, ++ ARRAY_SIZE(rknpu_debugger_root_list), ++ debugger->debugfs_dir, debugger); ++ if (ret) { ++ LOG_ERROR( ++ "Could not install rknpu_debugger_root_list debugfs\n"); ++ goto CREATE_FAIL; ++ } ++ ++ return 0; ++ ++CREATE_FAIL: ++ rknpu_debugfs_remove(debugger); ++ ++ return ret; ++} ++#endif /* #ifdef CONFIG_ROCKCHIP_RKNPU_DEBUG_FS */ ++ ++#ifdef CONFIG_ROCKCHIP_RKNPU_PROC_FS ++static int rknpu_procfs_open(struct inode *inode, struct file *file) ++{ ++#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE ++ struct rknpu_debugger_node *node = PDE_DATA(inode); ++#else ++ struct rknpu_debugger_node *node = pde_data(inode); ++#endif ++ ++ return single_open(file, node->info_ent->show, node); ++} ++ ++static const struct proc_ops rknpu_procfs_fops = { ++ .proc_open = rknpu_procfs_open, ++ .proc_read = seq_read, ++ .proc_lseek = seq_lseek, ++ .proc_release = single_release, ++ .proc_write = rknpu_debugger_write, ++}; ++ ++static int rknpu_procfs_remove_files(struct rknpu_debugger *debugger) ++{ ++ struct rknpu_debugger_node *pos, *q; ++ struct list_head *entry_list; ++ ++ mutex_lock(&debugger->procfs_lock); ++ ++ /* Delete procfs entry list */ ++ entry_list = &debugger->procfs_entry_list; ++ list_for_each_entry_safe(pos, q, entry_list, list) { ++ if (pos->pent == NULL) ++ continue; ++ list_del(&pos->list); ++ kfree(pos); ++ pos = NULL; ++ } ++ ++ /* Delete all procfs node in this directory */ ++ proc_remove(debugger->procfs_dir); ++ debugger->procfs_dir = NULL; ++ ++ mutex_unlock(&debugger->procfs_lock); ++ ++ return 0; ++} ++ ++static int rknpu_procfs_create_files(const struct rknpu_debugger_list *files, ++ int count, struct proc_dir_entry *root, ++ struct rknpu_debugger *debugger) ++{ ++ int i; ++ struct proc_dir_entry *ent; ++ struct rknpu_debugger_node *tmp; ++ ++ for (i = 0; i < count; i++) { ++ tmp = kmalloc(sizeof(struct rknpu_debugger_node), GFP_KERNEL); ++ if (tmp == NULL) { ++ LOG_ERROR("Cannot alloc node path for /proc/%s/%s\n", ++ RKNPU_DEBUGGER_ROOT_NAME, files[i].name); ++ goto MALLOC_FAIL; ++ } ++ ++ tmp->info_ent = &files[i]; ++ tmp->debugger = debugger; ++ ++ ent = proc_create_data(files[i].name, S_IFREG | S_IRUGO, root, ++ &rknpu_procfs_fops, tmp); ++ if (!ent) { ++ LOG_ERROR("Cannot create /proc/%s/%s\n", ++ RKNPU_DEBUGGER_ROOT_NAME, files[i].name); ++ goto CREATE_FAIL; ++ } ++ ++ tmp->pent = ent; ++ ++ mutex_lock(&debugger->procfs_lock); ++ list_add_tail(&tmp->list, &debugger->procfs_entry_list); ++ mutex_unlock(&debugger->procfs_lock); ++ } ++ ++ return 0; ++ ++CREATE_FAIL: ++ kfree(tmp); ++MALLOC_FAIL: ++ rknpu_procfs_remove_files(debugger); ++ return -1; ++} ++ ++static int rknpu_procfs_remove(struct rknpu_debugger *debugger) ++{ ++ rknpu_procfs_remove_files(debugger); ++ ++ return 0; ++} ++ ++static int rknpu_procfs_init(struct rknpu_debugger *debugger) ++{ ++ int ret; ++ ++ debugger->procfs_dir = proc_mkdir(RKNPU_DEBUGGER_ROOT_NAME, NULL); ++ if (IS_ERR_OR_NULL(debugger->procfs_dir)) { ++ pr_err("failed on mkdir /proc/%s\n", RKNPU_DEBUGGER_ROOT_NAME); ++ debugger->procfs_dir = NULL; ++ return -EIO; ++ } ++ ++ ret = rknpu_procfs_create_files(rknpu_debugger_root_list, ++ ARRAY_SIZE(rknpu_debugger_root_list), ++ debugger->procfs_dir, debugger); ++ if (ret) { ++ pr_err("Could not install rknpu_debugger_root_list procfs\n"); ++ goto CREATE_FAIL; ++ } ++ ++ return 0; ++ ++CREATE_FAIL: ++ rknpu_procfs_remove(debugger); ++ ++ return ret; ++} ++#endif /* #ifdef CONFIG_ROCKCHIP_RKNPU_PROC_FS */ ++ ++int rknpu_debugger_init(struct rknpu_device *rknpu_dev) ++{ ++#ifdef CONFIG_ROCKCHIP_RKNPU_DEBUG_FS ++ mutex_init(&rknpu_dev->debugger.debugfs_lock); ++ INIT_LIST_HEAD(&rknpu_dev->debugger.debugfs_entry_list); ++ rknpu_debugfs_init(&rknpu_dev->debugger); ++#endif ++#ifdef CONFIG_ROCKCHIP_RKNPU_PROC_FS ++ mutex_init(&rknpu_dev->debugger.procfs_lock); ++ INIT_LIST_HEAD(&rknpu_dev->debugger.procfs_entry_list); ++ rknpu_procfs_init(&rknpu_dev->debugger); ++#endif ++ return 0; ++} ++ ++int rknpu_debugger_remove(struct rknpu_device *rknpu_dev) ++{ ++#ifdef CONFIG_ROCKCHIP_RKNPU_DEBUG_FS ++ rknpu_debugfs_remove(&rknpu_dev->debugger); ++#endif ++#ifdef CONFIG_ROCKCHIP_RKNPU_PROC_FS ++ rknpu_procfs_remove(&rknpu_dev->debugger); ++#endif ++ return 0; ++} +diff --git a/drivers/rknpu/rknpu_drv.c b/drivers/rknpu/rknpu_drv.c +new file mode 100644 +index 000000000..bd49075f6 +--- /dev/null ++++ b/drivers/rknpu/rknpu_drv.c +@@ -0,0 +1,2202 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) Rockchip Electronics Co.Ltd ++ * Author: Felix Zeng ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifndef FPGA_PLATFORM ++#include ++#include ++#include ++#include ++#ifdef CONFIG_PM_DEVFREQ ++#include <../drivers/devfreq/governor.h> ++#endif ++#endif ++ ++#include "rknpu_ioctl.h" ++#include "rknpu_reset.h" ++#include "rknpu_fence.h" ++#include "rknpu_drv.h" ++#include "rknpu_gem.h" ++ ++#ifdef CONFIG_ROCKCHIP_RKNPU_DRM_GEM ++#include ++#include ++#include ++#include ++#include "rknpu_gem.h" ++#endif ++ ++#ifdef CONFIG_ROCKCHIP_RKNPU_DMA_HEAP ++#include ++#include "rknpu_mem.h" ++#endif ++ ++#define POWER_DOWN_FREQ 200000000 ++#define NPU_MMU_DISABLED_POLL_PERIOD_US 1000 ++#define NPU_MMU_DISABLED_POLL_TIMEOUT_US 20000 ++ ++static int bypass_irq_handler; ++module_param(bypass_irq_handler, int, 0644); ++MODULE_PARM_DESC(bypass_irq_handler, ++ "bypass RKNPU irq handler if set it to 1, disabled by default"); ++ ++static int bypass_soft_reset; ++module_param(bypass_soft_reset, int, 0644); ++MODULE_PARM_DESC(bypass_soft_reset, ++ "bypass RKNPU soft reset if set it to 1, disabled by default"); ++ ++struct rknpu_irqs_data { ++ const char *name; ++ irqreturn_t (*irq_hdl)(int irq, void *ctx); ++}; ++ ++static const struct rknpu_irqs_data rknpu_irqs[] = { ++ { "npu_irq", rknpu_core0_irq_handler } ++}; ++ ++static const struct rknpu_irqs_data rk3588_npu_irqs[] = { ++ { "npu0_irq", rknpu_core0_irq_handler }, ++ { "npu1_irq", rknpu_core1_irq_handler }, ++ { "npu2_irq", rknpu_core2_irq_handler } ++}; ++ ++static const struct rknpu_reset_data rknpu_resets[] = { { "srst_a", ++ "srst_h" } }; ++ ++static const struct rknpu_reset_data rk3588_npu_resets[] = { ++ { "srst_a0", "srst_h0" }, ++ { "srst_a1", "srst_h1" }, ++ { "srst_a2", "srst_h2" } ++}; ++ ++static const struct rknpu_config rk356x_rknpu_config = { ++ .bw_priority_addr = 0xfe180008, ++ .bw_priority_length = 0x10, ++ .dma_mask = DMA_BIT_MASK(32), ++ .pc_data_amount_scale = 1, ++ .pc_task_number_bits = 12, ++ .pc_task_number_mask = 0xfff, ++ .pc_task_status_offset = 0x3c, ++ .pc_dma_ctrl = 0, ++ .bw_enable = 1, ++ .irqs = rknpu_irqs, ++ .resets = rknpu_resets, ++ .num_irqs = ARRAY_SIZE(rknpu_irqs), ++ .num_resets = ARRAY_SIZE(rknpu_resets), ++ .nbuf_phyaddr = 0, ++ .nbuf_size = 0, ++ .max_submit_number = (1 << 12) - 1 ++}; ++ ++static const struct rknpu_config rk3588_rknpu_config = { ++ .bw_priority_addr = 0x0, ++ .bw_priority_length = 0x0, ++ .dma_mask = DMA_BIT_MASK(40), ++ .pc_data_amount_scale = 2, ++ .pc_task_number_bits = 12, ++ .pc_task_number_mask = 0xfff, ++ .pc_task_status_offset = 0x3c, ++ .pc_dma_ctrl = 0, ++ .bw_enable = 0, ++ .irqs = rk3588_npu_irqs, ++ .resets = rk3588_npu_resets, ++ .num_irqs = ARRAY_SIZE(rk3588_npu_irqs), ++ .num_resets = ARRAY_SIZE(rk3588_npu_resets), ++ .nbuf_phyaddr = 0, ++ .nbuf_size = 0, ++ .max_submit_number = (1 << 12) - 1 ++}; ++ ++static const struct rknpu_config rv1106_rknpu_config = { ++ .bw_priority_addr = 0x0, ++ .bw_priority_length = 0x0, ++ .dma_mask = DMA_BIT_MASK(32), ++ .pc_data_amount_scale = 2, ++ .pc_task_number_bits = 16, ++ .pc_task_number_mask = 0xffff, ++ .pc_task_status_offset = 0x3c, ++ .pc_dma_ctrl = 0, ++ .bw_enable = 1, ++ .irqs = rknpu_irqs, ++ .resets = rknpu_resets, ++ .num_irqs = ARRAY_SIZE(rknpu_irqs), ++ .num_resets = ARRAY_SIZE(rknpu_resets), ++ .nbuf_phyaddr = 0, ++ .nbuf_size = 0, ++ .max_submit_number = (1 << 16) - 1 ++}; ++ ++static const struct rknpu_config rk3562_rknpu_config = { ++ .bw_priority_addr = 0x0, ++ .bw_priority_length = 0x0, ++ .dma_mask = DMA_BIT_MASK(40), ++ .pc_data_amount_scale = 2, ++ .pc_task_number_bits = 16, ++ .pc_task_number_mask = 0xffff, ++ .pc_task_status_offset = 0x48, ++ .pc_dma_ctrl = 1, ++ .bw_enable = 1, ++ .irqs = rknpu_irqs, ++ .resets = rknpu_resets, ++ .num_irqs = ARRAY_SIZE(rknpu_irqs), ++ .num_resets = ARRAY_SIZE(rknpu_resets), ++ .nbuf_phyaddr = 0xfe400000, ++ .nbuf_size = 256 * 1024, ++ .max_submit_number = (1 << 16) - 1 ++}; ++ ++/* driver probe and init */ ++static const struct of_device_id rknpu_of_match[] = { ++ { ++ .compatible = "rockchip,rknpu", ++ .data = &rk356x_rknpu_config, ++ }, ++ { ++ .compatible = "rockchip,rk3568-rknpu", ++ .data = &rk356x_rknpu_config, ++ }, ++ { ++ .compatible = "rockchip,rk3588-rknpu", ++ .data = &rk3588_rknpu_config, ++ }, ++ { ++ .compatible = "rockchip,rv1106-rknpu", ++ .data = &rv1106_rknpu_config, ++ }, ++ { ++ .compatible = "rockchip,rk3562-rknpu", ++ .data = &rk3562_rknpu_config, ++ }, ++ {}, ++}; ++ ++static int rknpu_get_drv_version(uint32_t *version) ++{ ++ *version = RKNPU_GET_DRV_VERSION_CODE(DRIVER_MAJOR, DRIVER_MINOR, ++ DRIVER_PATCHLEVEL); ++ return 0; ++} ++ ++static int rknpu_power_on(struct rknpu_device *rknpu_dev); ++static int rknpu_power_off(struct rknpu_device *rknpu_dev); ++ ++static void rknpu_power_off_delay_work(struct work_struct *power_off_work) ++{ ++ struct rknpu_device *rknpu_dev = ++ container_of(to_delayed_work(power_off_work), ++ struct rknpu_device, power_off_work); ++ mutex_lock(&rknpu_dev->power_lock); ++ if (atomic_dec_if_positive(&rknpu_dev->power_refcount) == 0) ++ rknpu_power_off(rknpu_dev); ++ mutex_unlock(&rknpu_dev->power_lock); ++} ++ ++int rknpu_power_get(struct rknpu_device *rknpu_dev) ++{ ++ int ret = 0; ++ ++ mutex_lock(&rknpu_dev->power_lock); ++ if (atomic_inc_return(&rknpu_dev->power_refcount) == 1) ++ ret = rknpu_power_on(rknpu_dev); ++ mutex_unlock(&rknpu_dev->power_lock); ++ ++ return ret; ++} ++ ++int rknpu_power_put(struct rknpu_device *rknpu_dev) ++{ ++ int ret = 0; ++ ++ mutex_lock(&rknpu_dev->power_lock); ++ if (atomic_dec_if_positive(&rknpu_dev->power_refcount) == 0) ++ ret = rknpu_power_off(rknpu_dev); ++ mutex_unlock(&rknpu_dev->power_lock); ++ ++ return ret; ++} ++ ++static int rknpu_power_put_delay(struct rknpu_device *rknpu_dev) ++{ ++ if (rknpu_dev->power_put_delay == 0) ++ return rknpu_power_put(rknpu_dev); ++ ++ mutex_lock(&rknpu_dev->power_lock); ++ if (atomic_read(&rknpu_dev->power_refcount) == 1) ++ queue_delayed_work( ++ rknpu_dev->power_off_wq, &rknpu_dev->power_off_work, ++ msecs_to_jiffies(rknpu_dev->power_put_delay)); ++ else ++ atomic_dec_if_positive(&rknpu_dev->power_refcount); ++ mutex_unlock(&rknpu_dev->power_lock); ++ ++ return 0; ++} ++ ++static int rknpu_action(struct rknpu_device *rknpu_dev, ++ struct rknpu_action *args) ++{ ++ int ret = -EINVAL; ++ ++ switch (args->flags) { ++ case RKNPU_GET_HW_VERSION: ++ ret = rknpu_get_hw_version(rknpu_dev, &args->value); ++ break; ++ case RKNPU_GET_DRV_VERSION: ++ ret = rknpu_get_drv_version(&args->value); ++ break; ++ case RKNPU_GET_FREQ: ++#ifndef FPGA_PLATFORM ++ args->value = clk_get_rate(rknpu_dev->clks[0].clk); ++#endif ++ ret = 0; ++ break; ++ case RKNPU_SET_FREQ: ++ break; ++ case RKNPU_GET_VOLT: ++#ifndef FPGA_PLATFORM ++ args->value = regulator_get_voltage(rknpu_dev->vdd); ++#endif ++ ret = 0; ++ break; ++ case RKNPU_SET_VOLT: ++ break; ++ case RKNPU_ACT_RESET: ++ ret = rknpu_soft_reset(rknpu_dev); ++ break; ++ case RKNPU_GET_BW_PRIORITY: ++ ret = rknpu_get_bw_priority(rknpu_dev, &args->value, NULL, ++ NULL); ++ break; ++ case RKNPU_SET_BW_PRIORITY: ++ ret = rknpu_set_bw_priority(rknpu_dev, args->value, 0, 0); ++ break; ++ case RKNPU_GET_BW_EXPECT: ++ ret = rknpu_get_bw_priority(rknpu_dev, NULL, &args->value, ++ NULL); ++ break; ++ case RKNPU_SET_BW_EXPECT: ++ ret = rknpu_set_bw_priority(rknpu_dev, 0, args->value, 0); ++ break; ++ case RKNPU_GET_BW_TW: ++ ret = rknpu_get_bw_priority(rknpu_dev, NULL, NULL, ++ &args->value); ++ break; ++ case RKNPU_SET_BW_TW: ++ ret = rknpu_set_bw_priority(rknpu_dev, 0, 0, args->value); ++ break; ++ case RKNPU_ACT_CLR_TOTAL_RW_AMOUNT: ++ ret = rknpu_clear_rw_amount(rknpu_dev); ++ break; ++ case RKNPU_GET_DT_WR_AMOUNT: ++ ret = rknpu_get_rw_amount(rknpu_dev, &args->value, NULL, NULL); ++ break; ++ case RKNPU_GET_DT_RD_AMOUNT: ++ ret = rknpu_get_rw_amount(rknpu_dev, NULL, &args->value, NULL); ++ break; ++ case RKNPU_GET_WT_RD_AMOUNT: ++ ret = rknpu_get_rw_amount(rknpu_dev, NULL, NULL, &args->value); ++ break; ++ case RKNPU_GET_TOTAL_RW_AMOUNT: ++ ret = rknpu_get_total_rw_amount(rknpu_dev, &args->value); ++ break; ++ case RKNPU_GET_IOMMU_EN: ++ args->value = rknpu_dev->iommu_en; ++ ret = 0; ++ break; ++ case RKNPU_SET_PROC_NICE: ++ set_user_nice(current, *(int32_t *)&args->value); ++ ret = 0; ++ break; ++ case RKNPU_GET_TOTAL_SRAM_SIZE: ++ if (rknpu_dev->sram_mm) ++ args->value = rknpu_dev->sram_mm->total_chunks * ++ rknpu_dev->sram_mm->chunk_size; ++ else ++ args->value = 0; ++ ret = 0; ++ break; ++ case RKNPU_GET_FREE_SRAM_SIZE: ++ if (rknpu_dev->sram_mm) ++ args->value = rknpu_dev->sram_mm->free_chunks * ++ rknpu_dev->sram_mm->chunk_size; ++ else ++ args->value = 0; ++ ret = 0; ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++#ifdef CONFIG_ROCKCHIP_RKNPU_DMA_HEAP ++static int rknpu_open(struct inode *inode, struct file *file) ++{ ++ struct rknpu_device *rknpu_dev = ++ container_of(file->private_data, struct rknpu_device, miscdev); ++ struct rknpu_session *session = NULL; ++ ++ session = kzalloc(sizeof(*session), GFP_KERNEL); ++ if (!session) { ++ LOG_ERROR("rknpu session alloc failed\n"); ++ return -ENOMEM; ++ } ++ ++ session->rknpu_dev = rknpu_dev; ++ INIT_LIST_HEAD(&session->list); ++ ++ file->private_data = (void *)session; ++ ++ return nonseekable_open(inode, file); ++} ++ ++static int rknpu_release(struct inode *inode, struct file *file) ++{ ++ struct rknpu_mem_object *entry; ++ struct rknpu_session *session = file->private_data; ++ struct rknpu_device *rknpu_dev = session->rknpu_dev; ++ LIST_HEAD(local_list); ++ ++ spin_lock(&rknpu_dev->lock); ++ list_replace_init(&session->list, &local_list); ++ file->private_data = NULL; ++ spin_unlock(&rknpu_dev->lock); ++ ++ while (!list_empty(&local_list)) { ++ entry = list_first_entry(&local_list, struct rknpu_mem_object, ++ head); ++ ++ LOG_DEBUG( ++ "Fd close free rknpu_obj: %#llx, rknpu_obj->dma_addr: %#llx\n", ++ (__u64)(uintptr_t)entry, (__u64)entry->dma_addr); ++ ++ vunmap(entry->kv_addr); ++ entry->kv_addr = NULL; ++ ++ if (!entry->owner) ++ dma_buf_put(entry->dmabuf); ++ ++ list_del(&entry->head); ++ kfree(entry); ++ } ++ ++ kfree(session); ++ ++ return 0; ++} ++ ++static int rknpu_action_ioctl(struct rknpu_device *rknpu_dev, ++ unsigned long data) ++{ ++ struct rknpu_action args; ++ int ret = -EINVAL; ++ ++ if (unlikely(copy_from_user(&args, (struct rknpu_action *)data, ++ sizeof(struct rknpu_action)))) { ++ LOG_ERROR("%s: copy_from_user failed\n", __func__); ++ ret = -EFAULT; ++ return ret; ++ } ++ ++ ret = rknpu_action(rknpu_dev, &args); ++ ++ if (unlikely(copy_to_user((struct rknpu_action *)data, &args, ++ sizeof(struct rknpu_action)))) { ++ LOG_ERROR("%s: copy_to_user failed\n", __func__); ++ ret = -EFAULT; ++ return ret; ++ } ++ ++ return ret; ++} ++ ++static long rknpu_ioctl(struct file *file, uint32_t cmd, unsigned long arg) ++{ ++ long ret = -EINVAL; ++ struct rknpu_device *rknpu_dev = NULL; ++ ++ if (!file->private_data) ++ return -EINVAL; ++ ++ rknpu_dev = ((struct rknpu_session *)file->private_data)->rknpu_dev; ++ ++ rknpu_power_get(rknpu_dev); ++ ++ switch (cmd) { ++ case IOCTL_RKNPU_ACTION: ++ ret = rknpu_action_ioctl(rknpu_dev, arg); ++ break; ++ case IOCTL_RKNPU_SUBMIT: ++ ret = rknpu_submit_ioctl(rknpu_dev, arg); ++ break; ++ case IOCTL_RKNPU_MEM_CREATE: ++ ret = rknpu_mem_create_ioctl(rknpu_dev, arg, file); ++ break; ++ case RKNPU_MEM_MAP: ++ break; ++ case IOCTL_RKNPU_MEM_DESTROY: ++ ret = rknpu_mem_destroy_ioctl(rknpu_dev, arg, file); ++ break; ++ case IOCTL_RKNPU_MEM_SYNC: ++ ret = rknpu_mem_sync_ioctl(rknpu_dev, arg); ++ break; ++ default: ++ break; ++ } ++ ++ rknpu_power_put_delay(rknpu_dev); ++ ++ return ret; ++} ++const struct file_operations rknpu_fops = { ++ .owner = THIS_MODULE, ++ .open = rknpu_open, ++ .release = rknpu_release, ++ .unlocked_ioctl = rknpu_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = rknpu_ioctl, ++#endif ++}; ++#endif ++ ++#ifdef CONFIG_ROCKCHIP_RKNPU_DRM_GEM ++#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE ++static const struct vm_operations_struct rknpu_gem_vm_ops = { ++ .fault = rknpu_gem_fault, ++ .open = drm_gem_vm_open, ++ .close = drm_gem_vm_close, ++}; ++#endif ++ ++static int rknpu_action_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct rknpu_device *rknpu_dev = dev_get_drvdata(dev->dev); ++ ++ return rknpu_action(rknpu_dev, (struct rknpu_action *)data); ++} ++ ++#define RKNPU_IOCTL(func) \ ++ static int __##func(struct drm_device *dev, void *data, \ ++ struct drm_file *file_priv) \ ++ { \ ++ struct rknpu_device *rknpu_dev = dev_get_drvdata(dev->dev); \ ++ int ret = -EINVAL; \ ++ rknpu_power_get(rknpu_dev); \ ++ ret = func(dev, data, file_priv); \ ++ rknpu_power_put_delay(rknpu_dev); \ ++ return ret; \ ++ } ++ ++RKNPU_IOCTL(rknpu_action_ioctl); ++RKNPU_IOCTL(rknpu_submit_ioctl); ++RKNPU_IOCTL(rknpu_gem_create_ioctl); ++RKNPU_IOCTL(rknpu_gem_map_ioctl); ++RKNPU_IOCTL(rknpu_gem_destroy_ioctl); ++RKNPU_IOCTL(rknpu_gem_sync_ioctl); ++ ++static const struct drm_ioctl_desc rknpu_ioctls[] = { ++ DRM_IOCTL_DEF_DRV(RKNPU_ACTION, __rknpu_action_ioctl, DRM_RENDER_ALLOW), ++ DRM_IOCTL_DEF_DRV(RKNPU_SUBMIT, __rknpu_submit_ioctl, DRM_RENDER_ALLOW), ++ DRM_IOCTL_DEF_DRV(RKNPU_MEM_CREATE, __rknpu_gem_create_ioctl, ++ DRM_RENDER_ALLOW), ++ DRM_IOCTL_DEF_DRV(RKNPU_MEM_MAP, __rknpu_gem_map_ioctl, ++ DRM_RENDER_ALLOW), ++ DRM_IOCTL_DEF_DRV(RKNPU_MEM_DESTROY, __rknpu_gem_destroy_ioctl, ++ DRM_RENDER_ALLOW), ++ DRM_IOCTL_DEF_DRV(RKNPU_MEM_SYNC, __rknpu_gem_sync_ioctl, ++ DRM_RENDER_ALLOW), ++}; ++ ++#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE ++DEFINE_DRM_GEM_FOPS(rknpu_drm_driver_fops); ++#else ++static const struct file_operations rknpu_drm_driver_fops = { ++ .owner = THIS_MODULE, ++ .open = drm_open, ++ .mmap = rknpu_gem_mmap, ++ .poll = drm_poll, ++ .read = drm_read, ++ .unlocked_ioctl = drm_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = drm_compat_ioctl, ++#endif ++ .release = drm_release, ++ .llseek = noop_llseek, ++}; ++#endif ++ ++static struct drm_driver rknpu_drm_driver = { ++#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE ++ .driver_features = DRIVER_GEM | DRIVER_RENDER, ++#else ++ .driver_features = DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER, ++#endif ++#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE ++ .gem_free_object_unlocked = rknpu_gem_free_object, ++ .gem_vm_ops = &rknpu_gem_vm_ops, ++ .dumb_destroy = drm_gem_dumb_destroy, ++ .gem_prime_export = drm_gem_prime_export, ++ .gem_prime_get_sg_table = rknpu_gem_prime_get_sg_table, ++ .gem_prime_vmap = rknpu_gem_prime_vmap, ++ .gem_prime_vunmap = rknpu_gem_prime_vunmap, ++#endif ++ .dumb_create = rknpu_gem_dumb_create, ++#if KERNEL_VERSION(4, 19, 0) > LINUX_VERSION_CODE ++ .dumb_map_offset = rknpu_gem_dumb_map_offset, ++#else ++ .dumb_map_offset = drm_gem_dumb_map_offset, ++#endif ++ .prime_handle_to_fd = drm_gem_prime_handle_to_fd, ++ .prime_fd_to_handle = drm_gem_prime_fd_to_handle, ++#if KERNEL_VERSION(4, 13, 0) <= LINUX_VERSION_CODE ++ .gem_prime_import = rknpu_gem_prime_import, ++#else ++ .gem_prime_import = drm_gem_prime_import, ++#endif ++ .gem_prime_import_sg_table = rknpu_gem_prime_import_sg_table, ++#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE ++ /* ++ * 6.18 port fix: struct drm_driver has no .gem_prime_mmap member any ++ * more (removed along with the rest of the legacy gem_prime_* ++ * driver-level fallback vtable). Per-object mmap is already wired ++ * via drm_gem_object_funcs.mmap = rknpu_gem_mmap_obj in ++ * rknpu_gem.c's rknpu_gem_object_funcs (see PORT-PLAN.md §2.5) -- ++ * that's the 6.1+ mechanism this used to fall back from, so simply ++ * dropping the driver-level field is correct, not a functionality ++ * loss. ++ */ ++#else ++ .gem_prime_mmap = rknpu_gem_prime_mmap, ++#endif ++ .ioctls = rknpu_ioctls, ++ .num_ioctls = ARRAY_SIZE(rknpu_ioctls), ++ .fops = &rknpu_drm_driver_fops, ++ .name = DRIVER_NAME, ++ .desc = DRIVER_DESC, ++ /* ++ * 6.18 port fix: struct drm_driver has no .date member any more ++ * (dropped from mainline DRM; the .major/.minor/.patchlevel triple ++ * below already carries the version). ++ */ ++ .major = DRIVER_MAJOR, ++ .minor = DRIVER_MINOR, ++ .patchlevel = DRIVER_PATCHLEVEL, ++}; ++ ++#endif ++ ++static enum hrtimer_restart hrtimer_handler(struct hrtimer *timer) ++{ ++ struct rknpu_device *rknpu_dev = ++ container_of(timer, struct rknpu_device, timer); ++ struct rknpu_subcore_data *subcore_data = NULL; ++ struct rknpu_job *job = NULL; ++ ktime_t now; ++ unsigned long flags; ++ int i; ++ ++ for (i = 0; i < rknpu_dev->config->num_irqs; i++) { ++ subcore_data = &rknpu_dev->subcore_datas[i]; ++ ++ spin_lock_irqsave(&rknpu_dev->irq_lock, flags); ++ ++ job = subcore_data->job; ++ if (job) { ++ now = ktime_get(); ++ subcore_data->timer.busy_time += ++ ktime_us_delta(now, job->hw_recoder_time); ++ job->hw_recoder_time = now; ++ } ++ ++ subcore_data->timer.busy_time_record = ++ subcore_data->timer.busy_time; ++ subcore_data->timer.busy_time = 0; ++ spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags); ++ } ++ ++ hrtimer_forward_now(timer, rknpu_dev->kt); ++ return HRTIMER_RESTART; ++} ++ ++static void rknpu_init_timer(struct rknpu_device *rknpu_dev) ++{ ++ rknpu_dev->kt = ktime_set(0, RKNPU_LOAD_INTERVAL); ++ /* ++ * 6.18 port fix: hrtimer_init() + separate `.function =` assignment ++ * was replaced by the combined hrtimer_setup(timer, function, ++ * clock_id, mode) (same fix class as the RGA port's hrtimer_setup ++ * change -- see rga/PORT-DONE.md item 2). ++ */ ++ hrtimer_setup(&rknpu_dev->timer, hrtimer_handler, CLOCK_MONOTONIC, ++ HRTIMER_MODE_REL); ++ hrtimer_start(&rknpu_dev->timer, rknpu_dev->kt, HRTIMER_MODE_REL); ++} ++ ++static void rknpu_cancel_timer(struct rknpu_device *rknpu_dev) ++{ ++ hrtimer_cancel(&rknpu_dev->timer); ++} ++ ++static bool rknpu_is_iommu_enable(struct device *dev) ++{ ++ struct device_node *iommu = NULL; ++ ++ iommu = of_parse_phandle(dev->of_node, "iommus", 0); ++ if (!iommu) { ++ LOG_DEV_INFO( ++ dev, ++ "rknpu iommu device-tree entry not found!, using non-iommu mode\n"); ++ return false; ++ } ++ ++ if (!of_device_is_available(iommu)) { ++ LOG_DEV_INFO(dev, ++ "rknpu iommu is disabled, using non-iommu mode\n"); ++ of_node_put(iommu); ++ return false; ++ } ++ of_node_put(iommu); ++ ++ LOG_DEV_INFO(dev, "rknpu iommu is enabled, using iommu mode\n"); ++ ++ return true; ++} ++ ++#ifdef CONFIG_ROCKCHIP_RKNPU_DRM_GEM ++static int drm_fake_dev_register(struct rknpu_device *rknpu_dev) ++{ ++ const struct platform_device_info rknpu_dev_info = { ++ .name = "rknpu_dev", ++ .id = PLATFORM_DEVID_AUTO, ++ .dma_mask = rknpu_dev->config->dma_mask, ++ }; ++ struct platform_device *pdev = NULL; ++ int ret = -EINVAL; ++ ++ pdev = platform_device_register_full(&rknpu_dev_info); ++ if (pdev) { ++ ret = of_dma_configure(&pdev->dev, NULL, true); ++ if (ret) { ++ platform_device_unregister(pdev); ++ pdev = NULL; ++ } ++ } ++ ++ rknpu_dev->fake_dev = pdev ? &pdev->dev : NULL; ++ ++ return ret; ++} ++ ++static void drm_fake_dev_unregister(struct rknpu_device *rknpu_dev) ++{ ++ struct platform_device *pdev = NULL; ++ ++ if (!rknpu_dev->fake_dev) ++ return; ++ ++ pdev = to_platform_device(rknpu_dev->fake_dev); ++ ++ platform_device_unregister(pdev); ++} ++ ++static int rknpu_drm_probe(struct rknpu_device *rknpu_dev) ++{ ++ struct device *dev = rknpu_dev->dev; ++ struct drm_device *drm_dev = NULL; ++ int ret = -EINVAL; ++ ++ drm_dev = drm_dev_alloc(&rknpu_drm_driver, dev); ++ if (IS_ERR(drm_dev)) ++ return PTR_ERR(drm_dev); ++ ++ /* register the DRM device */ ++ ret = drm_dev_register(drm_dev, 0); ++ if (ret < 0) ++ goto err_free_drm; ++ ++ drm_dev->dev_private = rknpu_dev; ++ rknpu_dev->drm_dev = drm_dev; ++ ++ drm_fake_dev_register(rknpu_dev); ++ ++ return 0; ++ ++err_free_drm: ++#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE ++ drm_dev_put(drm_dev); ++#else ++ drm_dev_unref(drm_dev); ++#endif ++ ++ return ret; ++} ++ ++static void rknpu_drm_remove(struct rknpu_device *rknpu_dev) ++{ ++ struct drm_device *drm_dev = rknpu_dev->drm_dev; ++ ++ drm_fake_dev_unregister(rknpu_dev); ++ ++ drm_dev_unregister(drm_dev); ++ ++#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE ++ drm_dev_put(drm_dev); ++#else ++ drm_dev_unref(drm_dev); ++#endif ++} ++#endif ++ ++static int rknpu_power_on(struct rknpu_device *rknpu_dev) ++{ ++ struct device *dev = rknpu_dev->dev; ++ int ret = -EINVAL; ++ ++#ifndef FPGA_PLATFORM ++ if (rknpu_dev->vdd) { ++ ret = regulator_enable(rknpu_dev->vdd); ++ if (ret) { ++ LOG_DEV_ERROR( ++ dev, ++ "failed to enable vdd reg for rknpu, ret: %d\n", ++ ret); ++ return ret; ++ } ++ } ++ ++ if (rknpu_dev->mem) { ++ ret = regulator_enable(rknpu_dev->mem); ++ if (ret) { ++ LOG_DEV_ERROR( ++ dev, ++ "failed to enable mem reg for rknpu, ret: %d\n", ++ ret); ++ return ret; ++ } ++ } ++#endif ++ ++ ret = clk_bulk_prepare_enable(rknpu_dev->num_clks, rknpu_dev->clks); ++ if (ret) { ++ LOG_DEV_ERROR(dev, "failed to enable clk for rknpu, ret: %d\n", ++ ret); ++ return ret; ++ } ++ ++#ifndef FPGA_PLATFORM ++#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE && \ ++ KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE ++ rockchip_monitor_volt_adjust_lock(rknpu_dev->mdev_info); ++#endif ++#endif ++ ++ if (rknpu_dev->multiple_domains) { ++ if (rknpu_dev->genpd_dev_npu0) { ++#if KERNEL_VERSION(5, 5, 0) < LINUX_VERSION_CODE ++ ret = pm_runtime_resume_and_get( ++ rknpu_dev->genpd_dev_npu0); ++#else ++ ret = pm_runtime_get_sync(rknpu_dev->genpd_dev_npu0); ++#endif ++ if (ret < 0) { ++ LOG_DEV_ERROR( ++ dev, ++ "failed to get pm runtime for npu0, ret: %d\n", ++ ret); ++ goto out; ++ } ++ } ++ if (rknpu_dev->genpd_dev_npu1) { ++#if KERNEL_VERSION(5, 5, 0) < LINUX_VERSION_CODE ++ ret = pm_runtime_resume_and_get( ++ rknpu_dev->genpd_dev_npu1); ++#else ++ ret = pm_runtime_get_sync(rknpu_dev->genpd_dev_npu1); ++#endif ++ if (ret < 0) { ++ LOG_DEV_ERROR( ++ dev, ++ "failed to get pm runtime for npu1, ret: %d\n", ++ ret); ++ goto out; ++ } ++ } ++ if (rknpu_dev->genpd_dev_npu2) { ++#if KERNEL_VERSION(5, 5, 0) < LINUX_VERSION_CODE ++ ret = pm_runtime_resume_and_get( ++ rknpu_dev->genpd_dev_npu2); ++#else ++ ret = pm_runtime_get_sync(rknpu_dev->genpd_dev_npu2); ++#endif ++ if (ret < 0) { ++ LOG_DEV_ERROR( ++ dev, ++ "failed to get pm runtime for npu2, ret: %d\n", ++ ret); ++ goto out; ++ } ++ } ++ } ++ ret = pm_runtime_get_sync(dev); ++ if (ret < 0) { ++ LOG_DEV_ERROR(dev, ++ "failed to get pm runtime for rknpu, ret: %d\n", ++ ret); ++ } ++ ++out: ++#ifndef FPGA_PLATFORM ++#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE && \ ++ KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE ++ rockchip_monitor_volt_adjust_unlock(rknpu_dev->mdev_info); ++#endif ++#endif ++ ++ return ret; ++} ++ ++static int rknpu_power_off(struct rknpu_device *rknpu_dev) ++{ ++ struct device *dev = rknpu_dev->dev; ++ ++#ifndef FPGA_PLATFORM ++ int ret; ++ bool val; ++ ++#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE && \ ++ KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE ++ rockchip_monitor_volt_adjust_lock(rknpu_dev->mdev_info); ++#endif ++#endif ++ ++ pm_runtime_put_sync(dev); ++ ++ if (rknpu_dev->multiple_domains) { ++#ifndef FPGA_PLATFORM ++ /* ++ * Because IOMMU's runtime suspend callback is asynchronous, ++ * So it may be executed after the NPU is turned off after PD/CLK/VD, ++ * and the runtime suspend callback has a register access. ++ * If the PD/VD/CLK is closed, the register access will crash. ++ * As a workaround, it's safe to close pd stuff until iommu disabled. ++ * If pm runtime framework can handle this issue in the future, remove ++ * this. ++ */ ++ ret = readx_poll_timeout(rockchip_iommu_is_enabled, dev, val, ++ !val, NPU_MMU_DISABLED_POLL_PERIOD_US, ++ NPU_MMU_DISABLED_POLL_TIMEOUT_US); ++ if (ret) { ++ LOG_DEV_ERROR(dev, "iommu still enabled\n"); ++ pm_runtime_get_sync(dev); ++#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE && \ ++ KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE ++ rockchip_monitor_volt_adjust_unlock( ++ rknpu_dev->mdev_info); ++#endif ++ return ret; ++ } ++#else ++ if (rknpu_dev->iommu_en) ++ msleep(20); ++#endif ++ if (rknpu_dev->genpd_dev_npu2) ++ pm_runtime_put_sync(rknpu_dev->genpd_dev_npu2); ++ if (rknpu_dev->genpd_dev_npu1) ++ pm_runtime_put_sync(rknpu_dev->genpd_dev_npu1); ++ if (rknpu_dev->genpd_dev_npu0) ++ pm_runtime_put_sync(rknpu_dev->genpd_dev_npu0); ++ } ++ ++#ifndef FPGA_PLATFORM ++#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE && \ ++ KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE ++ rockchip_monitor_volt_adjust_unlock(rknpu_dev->mdev_info); ++#endif ++#endif ++ ++ clk_bulk_disable_unprepare(rknpu_dev->num_clks, rknpu_dev->clks); ++ ++#ifndef FPGA_PLATFORM ++ if (rknpu_dev->vdd) ++ regulator_disable(rknpu_dev->vdd); ++ ++ if (rknpu_dev->mem) ++ regulator_disable(rknpu_dev->mem); ++#endif ++ ++ return 0; ++} ++ ++#ifndef FPGA_PLATFORM ++#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE ++static struct monitor_dev_profile npu_mdevp = { ++ .type = MONITOR_TPYE_DEV, ++ .low_temp_adjust = rockchip_monitor_dev_low_temp_adjust, ++ .high_temp_adjust = rockchip_monitor_dev_high_temp_adjust, ++#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE ++ .update_volt = rockchip_monitor_check_rate_volt, ++#endif ++}; ++ ++#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE ++static int npu_opp_helper(struct dev_pm_set_opp_data *data) ++{ ++ struct device *dev = data->dev; ++ struct dev_pm_opp_supply *old_supply_vdd = &data->old_opp.supplies[0]; ++ struct dev_pm_opp_supply *old_supply_mem = &data->old_opp.supplies[1]; ++ struct dev_pm_opp_supply *new_supply_vdd = &data->new_opp.supplies[0]; ++ struct dev_pm_opp_supply *new_supply_mem = &data->new_opp.supplies[1]; ++ struct regulator *vdd_reg = data->regulators[0]; ++ struct regulator *mem_reg = data->regulators[1]; ++ struct clk *clk = data->clk; ++ struct rknpu_device *rknpu_dev = dev_get_drvdata(dev); ++ struct rockchip_opp_info *opp_info = &rknpu_dev->opp_info; ++ unsigned long old_freq = data->old_opp.rate; ++ unsigned long new_freq = data->new_opp.rate; ++ bool is_set_rm = true; ++ bool is_set_clk = true; ++ u32 target_rm = UINT_MAX; ++ int ret = 0; ++ ++ if (!pm_runtime_active(dev)) { ++ is_set_rm = false; ++ if (opp_info->scmi_clk) ++ is_set_clk = false; ++ } ++ ++ ret = clk_bulk_prepare_enable(opp_info->num_clks, opp_info->clks); ++ if (ret < 0) { ++ LOG_DEV_ERROR(dev, "failed to enable opp clks\n"); ++ return ret; ++ } ++ rockchip_get_read_margin(dev, opp_info, new_supply_vdd->u_volt, ++ &target_rm); ++ ++ /* Change frequency */ ++ LOG_DEV_DEBUG(dev, "switching OPP: %lu Hz --> %lu Hz\n", old_freq, ++ new_freq); ++ /* Scaling up? Scale voltage before frequency */ ++ if (new_freq >= old_freq) { ++ rockchip_set_intermediate_rate(dev, opp_info, clk, old_freq, ++ new_freq, true, is_set_clk); ++ ret = regulator_set_voltage(mem_reg, new_supply_mem->u_volt, ++ INT_MAX); ++ if (ret) { ++ LOG_DEV_ERROR(dev, ++ "failed to set volt %lu uV for mem reg\n", ++ new_supply_mem->u_volt); ++ goto restore_voltage; ++ } ++ ret = regulator_set_voltage(vdd_reg, new_supply_vdd->u_volt, ++ INT_MAX); ++ if (ret) { ++ LOG_DEV_ERROR(dev, ++ "failed to set volt %lu uV for vdd reg\n", ++ new_supply_vdd->u_volt); ++ goto restore_voltage; ++ } ++ rockchip_set_read_margin(dev, opp_info, target_rm, is_set_rm); ++ if (is_set_clk && clk_set_rate(clk, new_freq)) { ++ ret = -EINVAL; ++ LOG_DEV_ERROR(dev, "failed to set clk rate: %d\n", ret); ++ goto restore_rm; ++ } ++ /* Scaling down? Scale voltage after frequency */ ++ } else { ++ rockchip_set_intermediate_rate(dev, opp_info, clk, old_freq, ++ new_freq, false, is_set_clk); ++ rockchip_set_read_margin(dev, opp_info, target_rm, is_set_rm); ++ if (is_set_clk && clk_set_rate(clk, new_freq)) { ++ ret = -EINVAL; ++ LOG_DEV_ERROR(dev, "failed to set clk rate: %d\n", ret); ++ goto restore_rm; ++ } ++ ret = regulator_set_voltage(vdd_reg, new_supply_vdd->u_volt, ++ INT_MAX); ++ if (ret) { ++ LOG_DEV_ERROR(dev, ++ "failed to set volt %lu uV for vdd reg\n", ++ new_supply_vdd->u_volt); ++ goto restore_freq; ++ } ++ ret = regulator_set_voltage(mem_reg, new_supply_mem->u_volt, ++ INT_MAX); ++ if (ret) { ++ LOG_DEV_ERROR(dev, ++ "failed to set volt %lu uV for mem reg\n", ++ new_supply_mem->u_volt); ++ goto restore_freq; ++ } ++ } ++ ++ clk_bulk_disable_unprepare(opp_info->num_clks, opp_info->clks); ++ ++ return 0; ++ ++restore_freq: ++ if (is_set_clk && clk_set_rate(clk, old_freq)) ++ LOG_DEV_ERROR(dev, "failed to restore old-freq %lu Hz\n", ++ old_freq); ++restore_rm: ++ rockchip_get_read_margin(dev, opp_info, old_supply_vdd->u_volt, ++ &target_rm); ++ rockchip_set_read_margin(dev, opp_info, opp_info->current_rm, ++ is_set_rm); ++restore_voltage: ++ regulator_set_voltage(mem_reg, old_supply_mem->u_volt, INT_MAX); ++ regulator_set_voltage(vdd_reg, old_supply_vdd->u_volt, INT_MAX); ++ clk_bulk_disable_unprepare(opp_info->num_clks, opp_info->clks); ++ ++ return ret; ++} ++ ++static int npu_devfreq_target(struct device *dev, unsigned long *freq, ++ u32 flags) ++{ ++ struct rknpu_device *rknpu_dev = dev_get_drvdata(dev); ++ struct dev_pm_opp *opp; ++ unsigned long opp_volt; ++ int ret = 0; ++ ++ if (!npu_mdevp.is_checked) ++ return -EINVAL; ++ ++ opp = devfreq_recommended_opp(dev, freq, flags); ++ if (IS_ERR(opp)) ++ return PTR_ERR(opp); ++ opp_volt = dev_pm_opp_get_voltage(opp); ++ dev_pm_opp_put(opp); ++ ++#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE ++ rockchip_monitor_volt_adjust_lock(rknpu_dev->mdev_info); ++#endif ++ ret = dev_pm_opp_set_rate(dev, *freq); ++ if (!ret) { ++ rknpu_dev->current_freq = *freq; ++ if (rknpu_dev->devfreq) ++ rknpu_dev->devfreq->last_status.current_frequency = ++ *freq; ++ rknpu_dev->current_volt = opp_volt; ++ LOG_DEV_INFO(dev, "set rknpu freq: %lu, volt: %lu\n", ++ rknpu_dev->current_freq, rknpu_dev->current_volt); ++ } ++#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE ++ rockchip_monitor_volt_adjust_unlock(rknpu_dev->mdev_info); ++#endif ++ ++ return ret; ++} ++ ++#else ++ ++static int npu_devfreq_target(struct device *dev, unsigned long *target_freq, ++ u32 flags) ++{ ++ struct rknpu_device *rknpu_dev = dev_get_drvdata(dev); ++ struct dev_pm_opp *opp = NULL; ++ unsigned long freq = *target_freq; ++ unsigned long old_freq = rknpu_dev->current_freq; ++ unsigned long volt, old_volt = rknpu_dev->current_volt; ++ int ret = -EINVAL; ++ ++#if KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE ++ rcu_read_lock(); ++#endif ++ ++ opp = devfreq_recommended_opp(dev, &freq, flags); ++ if (IS_ERR(opp)) { ++#if KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE ++ rcu_read_unlock(); ++#endif ++ LOG_DEV_ERROR(dev, "failed to get opp (%ld)\n", PTR_ERR(opp)); ++ return PTR_ERR(opp); ++ } ++ volt = dev_pm_opp_get_voltage(opp); ++#if KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE ++ rcu_read_unlock(); ++#endif ++ ++ /* ++ * Only update if there is a change of frequency ++ */ ++ if (old_freq == freq) { ++ *target_freq = freq; ++ if (old_volt == volt) ++ return 0; ++ ret = regulator_set_voltage(rknpu_dev->vdd, volt, INT_MAX); ++ if (ret) { ++ LOG_DEV_ERROR(dev, "failed to set volt %lu\n", volt); ++ return ret; ++ } ++ rknpu_dev->current_volt = volt; ++ return 0; ++ } ++ ++ if (rknpu_dev->vdd && old_volt != volt && old_freq < freq) { ++ ret = regulator_set_voltage(rknpu_dev->vdd, volt, INT_MAX); ++ if (ret) { ++ LOG_DEV_ERROR(dev, "failed to increase volt %lu\n", ++ volt); ++ return ret; ++ } ++ } ++ LOG_DEV_DEBUG(dev, "%luHz %luuV -> %luHz %luuV\n", old_freq, old_volt, ++ freq, volt); ++ ret = clk_set_rate(rknpu_dev->clks[0].clk, freq); ++ if (ret) { ++ LOG_DEV_ERROR(dev, "failed to set clock %lu\n", freq); ++ return ret; ++ } ++ *target_freq = freq; ++ rknpu_dev->current_freq = freq; ++ ++ if (rknpu_dev->devfreq) ++ rknpu_dev->devfreq->last_status.current_frequency = freq; ++ ++ if (rknpu_dev->vdd && old_volt != volt && old_freq > freq) { ++ ret = regulator_set_voltage(rknpu_dev->vdd, volt, INT_MAX); ++ if (ret) { ++ LOG_DEV_ERROR(dev, "failed to decrease volt %lu\n", ++ volt); ++ return ret; ++ } ++ } ++ rknpu_dev->current_volt = volt; ++ ++ LOG_DEV_INFO(dev, "set rknpu freq: %lu, volt: %lu\n", ++ rknpu_dev->current_freq, rknpu_dev->current_volt); ++ ++ return ret; ++} ++#endif ++ ++static int npu_devfreq_get_dev_status(struct device *dev, ++ struct devfreq_dev_status *stat) ++{ ++ return 0; ++} ++ ++static int npu_devfreq_get_cur_freq(struct device *dev, unsigned long *freq) ++{ ++ struct rknpu_device *rknpu_dev = dev_get_drvdata(dev); ++ ++ *freq = rknpu_dev->current_freq; ++ ++ return 0; ++} ++ ++static struct devfreq_dev_profile npu_devfreq_profile = { ++ .polling_ms = 50, ++ .target = npu_devfreq_target, ++ .get_dev_status = npu_devfreq_get_dev_status, ++ .get_cur_freq = npu_devfreq_get_cur_freq, ++}; ++#endif ++ ++#ifdef CONFIG_PM_DEVFREQ ++static int devfreq_rknpu_ondemand_func(struct devfreq *df, unsigned long *freq) ++{ ++ struct rknpu_device *rknpu_dev = df->data; ++ ++ if (rknpu_dev) ++ *freq = rknpu_dev->ondemand_freq; ++ else ++ *freq = df->previous_freq; ++ ++ return 0; ++} ++ ++static int devfreq_rknpu_ondemand_handler(struct devfreq *devfreq, ++ unsigned int event, void *data) ++{ ++ return 0; ++} ++ ++static struct devfreq_governor devfreq_rknpu_ondemand = { ++ .name = "rknpu_ondemand", ++ .get_target_freq = devfreq_rknpu_ondemand_func, ++ .event_handler = devfreq_rknpu_ondemand_handler, ++}; ++#endif ++ ++#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE ++static unsigned long npu_get_static_power(struct devfreq *devfreq, ++ unsigned long voltage) ++{ ++ struct device *dev = devfreq->dev.parent; ++ struct rknpu_device *rknpu_dev = dev_get_drvdata(dev); ++ ++ if (!rknpu_dev->model_data) ++ return 0; ++ ++ return rockchip_ipa_get_static_power(rknpu_dev->model_data, voltage); ++} ++ ++static struct devfreq_cooling_power npu_cooling_power = { ++ .get_static_power = &npu_get_static_power, ++}; ++ ++#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE ++static int rk3588_npu_get_soc_info(struct device *dev, struct device_node *np, ++ int *bin, int *process) ++{ ++ int ret = 0; ++ u8 value = 0; ++ ++ if (!bin) ++ return 0; ++ ++ if (of_property_match_string(np, "nvmem-cell-names", ++ "specification_serial_number") >= 0) { ++ ret = rockchip_nvmem_cell_read_u8( ++ np, "specification_serial_number", &value); ++ if (ret) { ++ LOG_DEV_ERROR( ++ dev, ++ "Failed to get specification_serial_number\n"); ++ return ret; ++ } ++ /* RK3588M */ ++ if (value == 0xd) ++ *bin = 1; ++ /* RK3588J */ ++ else if (value == 0xa) ++ *bin = 2; ++ } ++ if (*bin < 0) ++ *bin = 0; ++ LOG_DEV_INFO(dev, "bin=%d\n", *bin); ++ ++ return ret; ++} ++ ++static int rk3588_npu_set_soc_info(struct device *dev, struct device_node *np, ++ int bin, int process, int volt_sel) ++{ ++ struct opp_table *opp_table; ++ u32 supported_hw[2]; ++ ++ if (volt_sel < 0) ++ return 0; ++ if (bin < 0) ++ bin = 0; ++ ++ if (!of_property_read_bool(np, "rockchip,supported-hw")) ++ return 0; ++ ++ /* SoC Version */ ++ supported_hw[0] = BIT(bin); ++ /* Speed Grade */ ++ supported_hw[1] = BIT(volt_sel); ++ opp_table = dev_pm_opp_set_supported_hw(dev, supported_hw, 2); ++ if (IS_ERR(opp_table)) { ++ LOG_DEV_ERROR(dev, "failed to set supported opp\n"); ++ return PTR_ERR(opp_table); ++ } ++ ++ return 0; ++} ++ ++static int rk3588_npu_set_read_margin(struct device *dev, ++ struct rockchip_opp_info *opp_info, ++ u32 rm) ++{ ++ u32 offset = 0, val = 0; ++ int i, ret = 0; ++ ++ if (!opp_info->grf || !opp_info->volt_rm_tbl) ++ return 0; ++ ++ if (rm == opp_info->current_rm || rm == UINT_MAX) ++ return 0; ++ ++ LOG_DEV_DEBUG(dev, "set rm to %d\n", rm); ++ ++ for (i = 0; i < 3; i++) { ++ ret = regmap_read(opp_info->grf, offset, &val); ++ if (ret < 0) { ++ LOG_DEV_ERROR(dev, "failed to get rm from 0x%x\n", ++ offset); ++ return ret; ++ } ++ val &= ~0x1c; ++ regmap_write(opp_info->grf, offset, val | (rm << 2)); ++ offset += 4; ++ } ++ opp_info->current_rm = rm; ++ ++ return 0; ++} ++ ++static const struct rockchip_opp_data rk3588_npu_opp_data = { ++ .get_soc_info = rk3588_npu_get_soc_info, ++ .set_soc_info = rk3588_npu_set_soc_info, ++ .set_read_margin = rk3588_npu_set_read_margin, ++}; ++ ++static const struct of_device_id rockchip_npu_of_match[] = { ++ { ++ .compatible = "rockchip,rk3588", ++ .data = (void *)&rk3588_npu_opp_data, ++ }, ++ {}, ++}; ++ ++static int rknpu_devfreq_init(struct rknpu_device *rknpu_dev) ++{ ++ struct device *dev = rknpu_dev->dev; ++ struct devfreq_dev_profile *dp = &npu_devfreq_profile; ++ struct dev_pm_opp *opp; ++ struct opp_table *reg_table = NULL; ++ struct opp_table *opp_table = NULL; ++ const char *const reg_names[] = { "rknpu", "mem" }; ++ int ret = -EINVAL; ++ ++ if (of_find_property(dev->of_node, "rknpu-supply", NULL) && ++ of_find_property(dev->of_node, "mem-supply", NULL)) { ++ reg_table = dev_pm_opp_set_regulators(dev, reg_names, 2); ++ if (IS_ERR(reg_table)) ++ return PTR_ERR(reg_table); ++ opp_table = ++ dev_pm_opp_register_set_opp_helper(dev, npu_opp_helper); ++ if (IS_ERR(opp_table)) { ++ dev_pm_opp_put_regulators(reg_table); ++ return PTR_ERR(opp_table); ++ } ++ } else { ++ reg_table = dev_pm_opp_set_regulators(dev, reg_names, 1); ++ if (IS_ERR(reg_table)) ++ return PTR_ERR(reg_table); ++ } ++ ++ rockchip_get_opp_data(rockchip_npu_of_match, &rknpu_dev->opp_info); ++ ret = rockchip_init_opp_table(dev, &rknpu_dev->opp_info, "npu_leakage", ++ "rknpu"); ++ if (ret) { ++ LOG_DEV_ERROR(dev, "failed to init_opp_table\n"); ++ return ret; ++ } ++ ++ rknpu_dev->current_freq = clk_get_rate(rknpu_dev->clks[0].clk); ++ ++ opp = devfreq_recommended_opp(dev, &rknpu_dev->current_freq, 0); ++ if (IS_ERR(opp)) { ++ ret = PTR_ERR(opp); ++ goto err_remove_table; ++ } ++ dev_pm_opp_put(opp); ++ dp->initial_freq = rknpu_dev->current_freq; ++ ++#ifdef CONFIG_PM_DEVFREQ ++ ret = devfreq_add_governor(&devfreq_rknpu_ondemand); ++ if (ret) { ++ LOG_DEV_ERROR(dev, "failed to add rknpu_ondemand governor\n"); ++ goto err_remove_table; ++ } ++#endif ++ ++ rknpu_dev->devfreq = devm_devfreq_add_device(dev, dp, "rknpu_ondemand", ++ (void *)rknpu_dev); ++ if (IS_ERR(rknpu_dev->devfreq)) { ++ LOG_DEV_ERROR(dev, "failed to add devfreq\n"); ++ ret = PTR_ERR(rknpu_dev->devfreq); ++ goto err_remove_governor; ++ } ++ devm_devfreq_register_opp_notifier(dev, rknpu_dev->devfreq); ++ ++ rknpu_dev->devfreq->last_status.current_frequency = dp->initial_freq; ++ rknpu_dev->devfreq->last_status.total_time = 1; ++ rknpu_dev->devfreq->last_status.busy_time = 1; ++ ++ npu_mdevp.data = rknpu_dev->devfreq; ++ npu_mdevp.opp_info = &rknpu_dev->opp_info; ++ rknpu_dev->mdev_info = ++ rockchip_system_monitor_register(dev, &npu_mdevp); ++ if (IS_ERR(rknpu_dev->mdev_info)) { ++ LOG_DEV_DEBUG(dev, "without system monitor\n"); ++ rknpu_dev->mdev_info = NULL; ++ npu_mdevp.is_checked = true; ++ } ++ rknpu_dev->current_freq = clk_get_rate(rknpu_dev->clks[0].clk); ++ rknpu_dev->current_volt = regulator_get_voltage(rknpu_dev->vdd); ++ ++ of_property_read_u32(dev->of_node, "dynamic-power-coefficient", ++ (u32 *)&npu_cooling_power.dyn_power_coeff); ++ rknpu_dev->model_data = ++ rockchip_ipa_power_model_init(dev, "npu_leakage"); ++ if (IS_ERR_OR_NULL(rknpu_dev->model_data)) { ++ rknpu_dev->model_data = NULL; ++ LOG_DEV_ERROR(dev, "failed to initialize power model\n"); ++ } else if (rknpu_dev->model_data->dynamic_coefficient) { ++ npu_cooling_power.dyn_power_coeff = ++ rknpu_dev->model_data->dynamic_coefficient; ++ } ++ if (!npu_cooling_power.dyn_power_coeff) { ++ LOG_DEV_ERROR(dev, "failed to get dynamic-coefficient\n"); ++ goto out; ++ } ++ ++ rknpu_dev->devfreq_cooling = of_devfreq_cooling_register_power( ++ dev->of_node, rknpu_dev->devfreq, &npu_cooling_power); ++ if (IS_ERR_OR_NULL(rknpu_dev->devfreq_cooling)) ++ LOG_DEV_ERROR(dev, "failed to register cooling device\n"); ++ ++out: ++ return 0; ++ ++err_remove_governor: ++#ifdef CONFIG_PM_DEVFREQ ++ devfreq_remove_governor(&devfreq_rknpu_ondemand); ++#endif ++err_remove_table: ++ dev_pm_opp_of_remove_table(dev); ++ ++ rknpu_dev->devfreq = NULL; ++ ++ return ret; ++} ++ ++#else ++ ++static int npu_devfreq_adjust_current_freq_volt(struct device *dev, ++ struct rknpu_device *rknpu_dev) ++{ ++ unsigned long volt, old_freq, freq; ++ struct dev_pm_opp *opp = NULL; ++ int ret = -EINVAL; ++ ++ old_freq = clk_get_rate(rknpu_dev->clks[0].clk); ++ freq = old_freq; ++ ++#if KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE ++ rcu_read_lock(); ++#endif ++ ++ opp = devfreq_recommended_opp(dev, &freq, 0); ++ volt = dev_pm_opp_get_voltage(opp); ++ ++#if KERNEL_VERSION(4, 11, 0) > LINUX_VERSION_CODE ++ rcu_read_unlock(); ++#endif ++ ++ if (freq >= old_freq && rknpu_dev->vdd) { ++ ret = regulator_set_voltage(rknpu_dev->vdd, volt, INT_MAX); ++ if (ret) { ++ LOG_DEV_ERROR(dev, "failed to set volt %lu\n", volt); ++ return ret; ++ } ++ } ++ LOG_DEV_DEBUG(dev, "adjust current freq=%luHz, volt=%luuV\n", freq, ++ volt); ++ ret = clk_set_rate(rknpu_dev->clks[0].clk, freq); ++ if (ret) { ++ LOG_DEV_ERROR(dev, "failed to set clock %lu\n", freq); ++ return ret; ++ } ++ if (freq < old_freq && rknpu_dev->vdd) { ++ ret = regulator_set_voltage(rknpu_dev->vdd, volt, INT_MAX); ++ if (ret) { ++ LOG_DEV_ERROR(dev, "failed to set volt %lu\n", volt); ++ return ret; ++ } ++ } ++ rknpu_dev->current_freq = freq; ++ rknpu_dev->current_volt = volt; ++ ++ return 0; ++} ++ ++static int rknpu_devfreq_init(struct rknpu_device *rknpu_dev) ++{ ++ struct device *dev = rknpu_dev->dev; ++ struct devfreq_dev_profile *dp = &npu_devfreq_profile; ++ int ret = -EINVAL; ++ ++ ret = rockchip_init_opp_table(dev, NULL, "npu_leakage", "rknpu"); ++ if (ret) { ++ LOG_DEV_ERROR(dev, "failed to init_opp_table\n"); ++ return ret; ++ } ++ ++ ret = npu_devfreq_adjust_current_freq_volt(dev, rknpu_dev); ++ if (ret) { ++ LOG_DEV_ERROR(dev, "failed to adjust current freq volt\n"); ++ goto err_remove_table; ++ } ++ dp->initial_freq = rknpu_dev->current_freq; ++ ++#ifdef CONFIG_PM_DEVFREQ ++ ret = devfreq_add_governor(&devfreq_rknpu_ondemand); ++ if (ret) { ++ LOG_DEV_ERROR(dev, "failed to add rknpu_ondemand governor\n"); ++ goto err_remove_table; ++ } ++#endif ++ ++ rknpu_dev->devfreq = devm_devfreq_add_device(dev, dp, "rknpu_ondemand", ++ (void *)rknpu_dev); ++ if (IS_ERR(rknpu_dev->devfreq)) { ++ LOG_DEV_ERROR(dev, "failed to add devfreq\n"); ++ ret = PTR_ERR(rknpu_dev->devfreq); ++ goto err_remove_governor; ++ } ++ devm_devfreq_register_opp_notifier(dev, rknpu_dev->devfreq); ++ ++ rknpu_dev->devfreq->last_status.current_frequency = dp->initial_freq; ++ rknpu_dev->devfreq->last_status.total_time = 1; ++ rknpu_dev->devfreq->last_status.busy_time = 1; ++ ++ npu_mdevp.data = rknpu_dev->devfreq; ++ rknpu_dev->mdev_info = ++ rockchip_system_monitor_register(dev, &npu_mdevp); ++ if (IS_ERR(rknpu_dev->mdev_info)) { ++ LOG_DEV_DEBUG(dev, "without system monitor\n"); ++ rknpu_dev->mdev_info = NULL; ++ } ++ rknpu_dev->current_freq = clk_get_rate(rknpu_dev->clks[0].clk); ++ rknpu_dev->current_volt = regulator_get_voltage(rknpu_dev->vdd); ++ ++ of_property_read_u32(dev->of_node, "dynamic-power-coefficient", ++ (u32 *)&npu_cooling_power.dyn_power_coeff); ++ rknpu_dev->model_data = ++ rockchip_ipa_power_model_init(dev, "npu_leakage"); ++ if (IS_ERR_OR_NULL(rknpu_dev->model_data)) { ++ rknpu_dev->model_data = NULL; ++ LOG_DEV_ERROR(dev, "failed to initialize power model\n"); ++ } else if (rknpu_dev->model_data->dynamic_coefficient) { ++ npu_cooling_power.dyn_power_coeff = ++ rknpu_dev->model_data->dynamic_coefficient; ++ } ++ ++ if (!npu_cooling_power.dyn_power_coeff) { ++ LOG_DEV_ERROR(dev, "failed to get dynamic-coefficient\n"); ++ goto out; ++ } ++ ++ rknpu_dev->devfreq_cooling = of_devfreq_cooling_register_power( ++ dev->of_node, rknpu_dev->devfreq, &npu_cooling_power); ++ if (IS_ERR_OR_NULL(rknpu_dev->devfreq_cooling)) ++ LOG_DEV_ERROR(dev, "failed to register cooling device\n"); ++ ++out: ++ return 0; ++ ++err_remove_governor: ++#ifdef CONFIG_PM_DEVFREQ ++ devfreq_remove_governor(&devfreq_rknpu_ondemand); ++#endif ++err_remove_table: ++ dev_pm_opp_of_remove_table(dev); ++ ++ rknpu_dev->devfreq = NULL; ++ ++ return ret; ++} ++#endif ++#endif ++ ++static int rknpu_devfreq_remove(struct rknpu_device *rknpu_dev) ++{ ++ if (rknpu_dev->devfreq) { ++ devfreq_unregister_opp_notifier(rknpu_dev->dev, ++ rknpu_dev->devfreq); ++ dev_pm_opp_of_remove_table(rknpu_dev->dev); ++#ifdef CONFIG_PM_DEVFREQ ++ devfreq_remove_governor(&devfreq_rknpu_ondemand); ++#endif ++ } ++ ++ return 0; ++} ++ ++#endif ++ ++static int rknpu_register_irq(struct platform_device *pdev, ++ struct rknpu_device *rknpu_dev) ++{ ++ const struct rknpu_config *config = rknpu_dev->config; ++ struct device *dev = &pdev->dev; ++#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE ++ struct resource *res; ++#endif ++ int i, ret, irq; ++ ++#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE ++ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, ++ config->irqs[0].name); ++ if (res) { ++ /* there are irq names in dts */ ++ for (i = 0; i < config->num_irqs; i++) { ++ irq = platform_get_irq_byname(pdev, ++ config->irqs[i].name); ++ if (irq < 0) { ++ LOG_DEV_ERROR(dev, "no npu %s in dts\n", ++ config->irqs[i].name); ++ return irq; ++ } ++ ++ ret = devm_request_irq(dev, irq, ++ config->irqs[i].irq_hdl, ++ IRQF_SHARED, dev_name(dev), ++ rknpu_dev); ++ if (ret < 0) { ++ LOG_DEV_ERROR(dev, "request %s failed: %d\n", ++ config->irqs[i].name, ret); ++ return ret; ++ } ++ } ++ } else { ++ /* no irq names in dts */ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ LOG_DEV_ERROR(dev, "no npu irq in dts\n"); ++ return irq; ++ } ++ ++ ret = devm_request_irq(dev, irq, rknpu_core0_irq_handler, ++ IRQF_SHARED, dev_name(dev), rknpu_dev); ++ if (ret < 0) { ++ LOG_DEV_ERROR(dev, "request irq failed: %d\n", ret); ++ return ret; ++ } ++ } ++#else ++ /* there are irq names in dts */ ++ for (i = 0; i < config->num_irqs; i++) { ++ irq = platform_get_irq_byname(pdev, config->irqs[i].name); ++ if (irq < 0) { ++ LOG_DEV_ERROR(dev, "no npu %s in dts\n", ++ config->irqs[i].name); ++ return irq; ++ } ++ ++ ret = devm_request_irq(dev, irq, config->irqs[i].irq_hdl, ++ IRQF_SHARED, dev_name(dev), rknpu_dev); ++ if (ret < 0) { ++ LOG_DEV_ERROR(dev, "request %s failed: %d\n", ++ config->irqs[i].name, ret); ++ return ret; ++ } ++ } ++#endif ++ ++ return 0; ++} ++ ++static int rknpu_find_sram_resource(struct rknpu_device *rknpu_dev) ++{ ++ struct device *dev = rknpu_dev->dev; ++ struct device_node *sram_node = NULL; ++ struct resource sram_res; ++ uint32_t sram_size = 0; ++ int ret = -EINVAL; ++ ++ /* get sram device node */ ++ sram_node = of_parse_phandle(dev->of_node, "rockchip,sram", 0); ++ rknpu_dev->sram_size = 0; ++ if (!sram_node) ++ return -EINVAL; ++ ++ /* get sram start and size */ ++ ret = of_address_to_resource(sram_node, 0, &sram_res); ++ of_node_put(sram_node); ++ if (ret) ++ return ret; ++ ++ /* check sram start and size is PAGE_SIZE align */ ++ rknpu_dev->sram_start = round_up(sram_res.start, PAGE_SIZE); ++ rknpu_dev->sram_end = round_down( ++ sram_res.start + resource_size(&sram_res), PAGE_SIZE); ++ if (rknpu_dev->sram_end <= rknpu_dev->sram_start) { ++ LOG_DEV_WARN( ++ dev, ++ "invalid sram resource, sram start %pa, sram end %pa\n", ++ &rknpu_dev->sram_start, &rknpu_dev->sram_end); ++ return -EINVAL; ++ } ++ ++ sram_size = rknpu_dev->sram_end - rknpu_dev->sram_start; ++ ++ rknpu_dev->sram_base_io = ++ devm_ioremap(dev, rknpu_dev->sram_start, sram_size); ++ if (IS_ERR(rknpu_dev->sram_base_io)) { ++ LOG_DEV_ERROR(dev, "failed to remap sram base io!\n"); ++ rknpu_dev->sram_base_io = NULL; ++ } ++ ++ rknpu_dev->sram_size = sram_size; ++ ++ LOG_DEV_INFO(dev, "sram region: [%pa, %pa), sram size: %#x\n", ++ &rknpu_dev->sram_start, &rknpu_dev->sram_end, ++ rknpu_dev->sram_size); ++ ++ return 0; ++} ++ ++static int rknpu_find_nbuf_resource(struct rknpu_device *rknpu_dev) ++{ ++ struct device *dev = rknpu_dev->dev; ++ ++ if (rknpu_dev->config->nbuf_size == 0) ++ return -EINVAL; ++ ++ rknpu_dev->nbuf_start = rknpu_dev->config->nbuf_phyaddr; ++ rknpu_dev->nbuf_size = rknpu_dev->config->nbuf_size; ++ rknpu_dev->nbuf_base_io = ++ devm_ioremap(dev, rknpu_dev->nbuf_start, rknpu_dev->nbuf_size); ++ if (IS_ERR(rknpu_dev->nbuf_base_io)) { ++ LOG_DEV_ERROR(dev, "failed to remap nbuf base io!\n"); ++ rknpu_dev->nbuf_base_io = NULL; ++ } ++ ++ rknpu_dev->nbuf_end = rknpu_dev->nbuf_start + rknpu_dev->nbuf_size; ++ ++ LOG_DEV_INFO(dev, "nbuf region: [%pa, %pa), nbuf size: %#x\n", ++ &rknpu_dev->nbuf_start, &rknpu_dev->nbuf_end, ++ rknpu_dev->nbuf_size); ++ ++ return 0; ++} ++ ++static int rknpu_probe(struct platform_device *pdev) ++{ ++ struct resource *res = NULL; ++ struct rknpu_device *rknpu_dev = NULL; ++ struct device *dev = &pdev->dev; ++ struct device *virt_dev = NULL; ++ const struct of_device_id *match = NULL; ++ const struct rknpu_config *config = NULL; ++ int ret = -EINVAL, i = 0; ++ ++ if (!pdev->dev.of_node) { ++ LOG_DEV_ERROR(dev, "rknpu device-tree data is missing!\n"); ++ return -ENODEV; ++ } ++ ++ match = of_match_device(rknpu_of_match, dev); ++ if (!match) { ++ LOG_DEV_ERROR(dev, "rknpu device-tree entry is missing!\n"); ++ return -ENODEV; ++ } ++ ++ rknpu_dev = devm_kzalloc(dev, sizeof(*rknpu_dev), GFP_KERNEL); ++ if (!rknpu_dev) { ++ LOG_DEV_ERROR(dev, "failed to allocate rknpu device!\n"); ++ return -ENOMEM; ++ } ++ ++ config = of_device_get_match_data(dev); ++ if (!config) ++ return -EINVAL; ++ ++ rknpu_dev->config = config; ++ rknpu_dev->dev = dev; ++ ++ rknpu_dev->iommu_en = rknpu_is_iommu_enable(dev); ++ if (!rknpu_dev->iommu_en) { ++ /* Initialize reserved memory resources */ ++ ret = of_reserved_mem_device_init(dev); ++ if (!ret) { ++ LOG_DEV_INFO( ++ dev, ++ "initialize reserved memory for rknpu device!\n"); ++ } ++ } ++ ++ rknpu_dev->bypass_irq_handler = bypass_irq_handler; ++ rknpu_dev->bypass_soft_reset = bypass_soft_reset; ++ ++ rknpu_reset_get(rknpu_dev); ++ ++ rknpu_dev->num_clks = devm_clk_bulk_get_all(dev, &rknpu_dev->clks); ++ if (rknpu_dev->num_clks < 1) { ++ LOG_DEV_ERROR(dev, "failed to get clk source for rknpu\n"); ++#ifndef FPGA_PLATFORM ++ return -ENODEV; ++#endif ++ } ++ ++#ifndef FPGA_PLATFORM ++#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE && \ ++ KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE ++ if (strstr(__clk_get_name(rknpu_dev->clks[0].clk), "scmi")) ++ rknpu_dev->opp_info.scmi_clk = rknpu_dev->clks[0].clk; ++#endif ++ ++ rknpu_dev->vdd = devm_regulator_get_optional(dev, "rknpu"); ++ if (IS_ERR(rknpu_dev->vdd)) { ++ if (PTR_ERR(rknpu_dev->vdd) != -ENODEV) { ++ ret = PTR_ERR(rknpu_dev->vdd); ++ LOG_DEV_ERROR( ++ dev, ++ "failed to get vdd regulator for rknpu: %d\n", ++ ret); ++ return ret; ++ } ++ rknpu_dev->vdd = NULL; ++ } ++ ++ rknpu_dev->mem = devm_regulator_get_optional(dev, "mem"); ++ if (IS_ERR(rknpu_dev->mem)) { ++ if (PTR_ERR(rknpu_dev->mem) != -ENODEV) { ++ ret = PTR_ERR(rknpu_dev->mem); ++ LOG_DEV_ERROR( ++ dev, ++ "failed to get mem regulator for rknpu: %d\n", ++ ret); ++ return ret; ++ } ++ rknpu_dev->mem = NULL; ++ } ++#endif ++ ++ spin_lock_init(&rknpu_dev->lock); ++ spin_lock_init(&rknpu_dev->irq_lock); ++ mutex_init(&rknpu_dev->power_lock); ++ mutex_init(&rknpu_dev->reset_lock); ++ for (i = 0; i < config->num_irqs; i++) { ++ INIT_LIST_HEAD(&rknpu_dev->subcore_datas[i].todo_list); ++ init_waitqueue_head(&rknpu_dev->subcore_datas[i].job_done_wq); ++ rknpu_dev->subcore_datas[i].task_num = 0; ++ res = platform_get_resource(pdev, IORESOURCE_MEM, i); ++ if (!res) { ++ LOG_DEV_ERROR( ++ dev, ++ "failed to get memory resource for rknpu\n"); ++ return -ENXIO; ++ } ++ ++ rknpu_dev->base[i] = devm_ioremap_resource(dev, res); ++ if (PTR_ERR(rknpu_dev->base[i]) == -EBUSY) { ++ rknpu_dev->base[i] = devm_ioremap(dev, res->start, ++ resource_size(res)); ++ } ++ ++ if (IS_ERR(rknpu_dev->base[i])) { ++ LOG_DEV_ERROR(dev, ++ "failed to remap register for rknpu\n"); ++ return PTR_ERR(rknpu_dev->base[i]); ++ } ++ } ++ ++ if (config->bw_priority_length > 0) { ++ rknpu_dev->bw_priority_base = ++ devm_ioremap(dev, config->bw_priority_addr, ++ config->bw_priority_length); ++ if (IS_ERR(rknpu_dev->bw_priority_base)) { ++ LOG_DEV_ERROR( ++ rknpu_dev->dev, ++ "failed to remap bw priority register for rknpu\n"); ++ rknpu_dev->bw_priority_base = NULL; ++ } ++ } ++ ++ if (!rknpu_dev->bypass_irq_handler) { ++ ret = rknpu_register_irq(pdev, rknpu_dev); ++ if (ret) ++ return ret; ++ } else { ++ LOG_DEV_WARN(dev, "bypass irq handler!\n"); ++ } ++ ++#ifdef CONFIG_ROCKCHIP_RKNPU_DRM_GEM ++ ret = rknpu_drm_probe(rknpu_dev); ++ if (ret) { ++ LOG_DEV_ERROR(dev, "failed to probe device for rknpu\n"); ++ return ret; ++ } ++#endif ++#ifdef CONFIG_ROCKCHIP_RKNPU_DMA_HEAP ++ rknpu_dev->miscdev.minor = MISC_DYNAMIC_MINOR; ++ rknpu_dev->miscdev.name = "rknpu"; ++ rknpu_dev->miscdev.fops = &rknpu_fops; ++ ++ ret = misc_register(&rknpu_dev->miscdev); ++ if (ret) { ++ LOG_DEV_ERROR(dev, "cannot register miscdev (%d)\n", ret); ++ return ret; ++ } ++ ++ rknpu_dev->heap = rk_dma_heap_find("rk-dma-heap-cma"); ++ if (!rknpu_dev->heap) { ++ LOG_DEV_ERROR(dev, "failed to find cma heap\n"); ++ return -ENOMEM; ++ } ++ rk_dma_heap_set_dev(dev); ++ LOG_DEV_INFO(dev, "Initialized %s: v%d.%d.%d for %s\n", DRIVER_DESC, ++ DRIVER_MAJOR, DRIVER_MINOR, DRIVER_PATCHLEVEL, ++ DRIVER_DATE); ++#endif ++ ++#ifdef CONFIG_ROCKCHIP_RKNPU_FENCE ++ ret = rknpu_fence_context_alloc(rknpu_dev); ++ if (ret) { ++ LOG_DEV_ERROR(dev, ++ "failed to allocate fence context for rknpu\n"); ++ goto err_remove_drv; ++ } ++#endif ++ ++ platform_set_drvdata(pdev, rknpu_dev); ++ ++ pm_runtime_enable(dev); ++ ++ if (of_count_phandle_with_args(dev->of_node, "power-domains", ++ "#power-domain-cells") > 1) { ++ virt_dev = dev_pm_domain_attach_by_name(dev, "npu0"); ++ if (!IS_ERR(virt_dev)) ++ rknpu_dev->genpd_dev_npu0 = virt_dev; ++ virt_dev = dev_pm_domain_attach_by_name(dev, "npu1"); ++ if (!IS_ERR(virt_dev)) ++ rknpu_dev->genpd_dev_npu1 = virt_dev; ++ virt_dev = dev_pm_domain_attach_by_name(dev, "npu2"); ++ if (!IS_ERR(virt_dev)) ++ rknpu_dev->genpd_dev_npu2 = virt_dev; ++ rknpu_dev->multiple_domains = true; ++ } ++ ++ ret = rknpu_power_on(rknpu_dev); ++ if (ret) ++ goto err_remove_drv; ++ ++#ifndef FPGA_PLATFORM ++#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE ++ rknpu_devfreq_init(rknpu_dev); ++#endif ++#endif ++ ++ // set default power put delay to 3s ++ rknpu_dev->power_put_delay = 3000; ++ rknpu_dev->power_off_wq = ++ create_freezable_workqueue("rknpu_power_off_wq"); ++ if (!rknpu_dev->power_off_wq) { ++ LOG_DEV_ERROR(dev, "rknpu couldn't create power_off workqueue"); ++ ret = -ENOMEM; ++ goto err_devfreq_remove; ++ } ++ INIT_DEFERRABLE_WORK(&rknpu_dev->power_off_work, ++ rknpu_power_off_delay_work); ++ ++ if (IS_ENABLED(CONFIG_NO_GKI) && ++ IS_ENABLED(CONFIG_ROCKCHIP_RKNPU_SRAM) && rknpu_dev->iommu_en) { ++ if (!rknpu_find_sram_resource(rknpu_dev)) { ++ ret = rknpu_mm_create(rknpu_dev->sram_size, PAGE_SIZE, ++ &rknpu_dev->sram_mm); ++ if (ret != 0) ++ goto err_remove_wq; ++ } else { ++ LOG_DEV_WARN(dev, "could not find sram resource!\n"); ++ } ++ } ++ ++ if (IS_ENABLED(CONFIG_NO_GKI) && rknpu_dev->iommu_en && ++ rknpu_dev->config->nbuf_size > 0) ++ rknpu_find_nbuf_resource(rknpu_dev); ++ ++ rknpu_power_off(rknpu_dev); ++ atomic_set(&rknpu_dev->power_refcount, 0); ++ atomic_set(&rknpu_dev->cmdline_power_refcount, 0); ++ ++ rknpu_debugger_init(rknpu_dev); ++ rknpu_init_timer(rknpu_dev); ++ ++ return 0; ++ ++err_remove_wq: ++ destroy_workqueue(rknpu_dev->power_off_wq); ++ ++err_devfreq_remove: ++#ifndef FPGA_PLATFORM ++ rknpu_devfreq_remove(rknpu_dev); ++#endif ++ ++err_remove_drv: ++#ifdef CONFIG_ROCKCHIP_RKNPU_DRM_GEM ++ rknpu_drm_remove(rknpu_dev); ++#endif ++#ifdef CONFIG_ROCKCHIP_RKNPU_DMA_HEAP ++ misc_deregister(&(rknpu_dev->miscdev)); ++#endif ++ ++ return ret; ++} ++ ++/* 6.18 port fix: platform_driver.remove is void(*)(...) now, was int(*)(...). */ ++static void rknpu_remove(struct platform_device *pdev) ++{ ++ struct rknpu_device *rknpu_dev = platform_get_drvdata(pdev); ++ int i = 0; ++ ++ cancel_delayed_work_sync(&rknpu_dev->power_off_work); ++ destroy_workqueue(rknpu_dev->power_off_wq); ++ ++ if (IS_ENABLED(CONFIG_ROCKCHIP_RKNPU_SRAM) && rknpu_dev->sram_mm) ++ rknpu_mm_destroy(rknpu_dev->sram_mm); ++ ++ rknpu_debugger_remove(rknpu_dev); ++ rknpu_cancel_timer(rknpu_dev); ++ ++ for (i = 0; i < rknpu_dev->config->num_irqs; i++) { ++ WARN_ON(rknpu_dev->subcore_datas[i].job); ++ WARN_ON(!list_empty(&rknpu_dev->subcore_datas[i].todo_list)); ++ } ++ ++#ifdef CONFIG_ROCKCHIP_RKNPU_DRM_GEM ++ rknpu_drm_remove(rknpu_dev); ++#endif ++#ifdef CONFIG_ROCKCHIP_RKNPU_DMA_HEAP ++ misc_deregister(&(rknpu_dev->miscdev)); ++#endif ++ ++#ifndef FPGA_PLATFORM ++ rknpu_devfreq_remove(rknpu_dev); ++#endif ++ ++ mutex_lock(&rknpu_dev->power_lock); ++ if (atomic_read(&rknpu_dev->power_refcount) > 0) ++ rknpu_power_off(rknpu_dev); ++ mutex_unlock(&rknpu_dev->power_lock); ++ ++ if (rknpu_dev->multiple_domains) { ++ if (rknpu_dev->genpd_dev_npu0) ++ dev_pm_domain_detach(rknpu_dev->genpd_dev_npu0, true); ++ if (rknpu_dev->genpd_dev_npu1) ++ dev_pm_domain_detach(rknpu_dev->genpd_dev_npu1, true); ++ if (rknpu_dev->genpd_dev_npu2) ++ dev_pm_domain_detach(rknpu_dev->genpd_dev_npu2, true); ++ } ++ ++ pm_runtime_disable(&pdev->dev); ++} ++ ++#ifndef FPGA_PLATFORM ++#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE && \ ++ KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE ++static int rknpu_runtime_suspend(struct device *dev) ++{ ++ struct rknpu_device *rknpu_dev = dev_get_drvdata(dev); ++ struct rockchip_opp_info *opp_info = &rknpu_dev->opp_info; ++ ++ if (opp_info->scmi_clk) { ++ if (clk_set_rate(opp_info->scmi_clk, POWER_DOWN_FREQ)) ++ LOG_DEV_ERROR(dev, "failed to restore clk rate\n"); ++ } ++ opp_info->current_rm = UINT_MAX; ++ ++ return 0; ++} ++ ++static int rknpu_runtime_resume(struct device *dev) ++{ ++ struct rknpu_device *rknpu_dev = dev_get_drvdata(dev); ++ struct rockchip_opp_info *opp_info = &rknpu_dev->opp_info; ++ int ret = 0; ++ ++ if (!rknpu_dev->current_freq || !rknpu_dev->current_volt) ++ return 0; ++ ++ ret = clk_bulk_prepare_enable(opp_info->num_clks, opp_info->clks); ++ if (ret) { ++ LOG_DEV_ERROR(dev, "failed to enable opp clks\n"); ++ return ret; ++ } ++ ++ if (opp_info->data && opp_info->data->set_read_margin) ++ opp_info->data->set_read_margin(dev, opp_info, ++ opp_info->target_rm); ++ if (opp_info->scmi_clk) { ++ if (clk_set_rate(opp_info->scmi_clk, rknpu_dev->current_freq)) ++ LOG_DEV_ERROR(dev, "failed to set power down rate\n"); ++ } ++ ++ clk_bulk_disable_unprepare(opp_info->num_clks, opp_info->clks); ++ ++ return ret; ++} ++ ++static const struct dev_pm_ops rknpu_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, ++ pm_runtime_force_resume) ++ SET_RUNTIME_PM_OPS(rknpu_runtime_suspend, rknpu_runtime_resume, ++ NULL) ++}; ++#endif ++#endif ++ ++static struct platform_driver rknpu_driver = { ++ .probe = rknpu_probe, ++ .remove = rknpu_remove, ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "RKNPU", ++#ifndef FPGA_PLATFORM ++#if KERNEL_VERSION(5, 5, 0) < LINUX_VERSION_CODE && \ ++ KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE ++ .pm = &rknpu_pm_ops, ++#endif ++#endif ++ .of_match_table = of_match_ptr(rknpu_of_match), ++ }, ++}; ++ ++static int rknpu_init(void) ++{ ++ return platform_driver_register(&rknpu_driver); ++} ++ ++static void rknpu_exit(void) ++{ ++ platform_driver_unregister(&rknpu_driver); ++} ++ ++late_initcall(rknpu_init); ++module_exit(rknpu_exit); ++ ++MODULE_DESCRIPTION("RKNPU driver"); ++MODULE_AUTHOR("Felix Zeng "); ++MODULE_ALIAS("rockchip-rknpu"); ++MODULE_LICENSE("GPL v2"); ++MODULE_VERSION(RKNPU_GET_DRV_VERSION_STRING(DRIVER_MAJOR, DRIVER_MINOR, ++ DRIVER_PATCHLEVEL)); ++#if KERNEL_VERSION(5, 16, 0) < LINUX_VERSION_CODE ++/* 6.18 port fix: MODULE_IMPORT_NS() now takes a quoted string (same fix as ++ * the RGA port's item 6, rga/PORT-DONE.md). ++ */ ++MODULE_IMPORT_NS("DMA_BUF"); ++#endif +diff --git a/drivers/rknpu/rknpu_gem.c b/drivers/rknpu/rknpu_gem.c +new file mode 100644 +index 000000000..c4849f37a +--- /dev/null ++++ b/drivers/rknpu/rknpu_gem.c +@@ -0,0 +1,1520 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) Rockchip Electronics Co.Ltd ++ * Author: Felix Zeng ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++/* ++ * 6.18 port fix: and the pfn_t wrapper type (along with ++ * __pfn_to_pfn_t()/PFN_DEV) were removed from mainline -- vmf_insert_mixed() ++ * (used below) now takes a plain `unsigned long pfn` directly. ++ */ ++/* ++ * 6.18 port fix: vmap()/vunmap()/VM_MAP used to come in transitively; now ++ * need explicitly. ++ */ ++#include ++#include ++#include ++ ++#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE ++#include ++#endif ++ ++#include "rknpu_drv.h" ++#include "rknpu_ioctl.h" ++#include "rknpu_gem.h" ++#include "rknpu_iommu.h" ++ ++#define RKNPU_GEM_ALLOC_FROM_PAGES 1 ++ ++#if RKNPU_GEM_ALLOC_FROM_PAGES ++static int rknpu_gem_get_pages(struct rknpu_gem_object *rknpu_obj) ++{ ++ struct drm_device *drm = rknpu_obj->base.dev; ++ struct scatterlist *s = NULL; ++ dma_addr_t dma_addr = 0; ++ dma_addr_t phys = 0; ++ int ret = -EINVAL, i = 0; ++ ++ rknpu_obj->pages = drm_gem_get_pages(&rknpu_obj->base); ++ if (IS_ERR(rknpu_obj->pages)) { ++ ret = PTR_ERR(rknpu_obj->pages); ++ LOG_ERROR("failed to get pages: %d\n", ret); ++ return ret; ++ } ++ ++ rknpu_obj->num_pages = rknpu_obj->size >> PAGE_SHIFT; ++ ++#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE ++ rknpu_obj->sgt = drm_prime_pages_to_sg(drm, rknpu_obj->pages, ++ rknpu_obj->num_pages); ++#else ++ rknpu_obj->sgt = ++ drm_prime_pages_to_sg(rknpu_obj->pages, rknpu_obj->num_pages); ++#endif ++ if (IS_ERR(rknpu_obj->sgt)) { ++ ret = PTR_ERR(rknpu_obj->sgt); ++ LOG_ERROR("failed to allocate sgt: %d\n", ret); ++ goto put_pages; ++ } ++ ++ ret = dma_map_sg(drm->dev, rknpu_obj->sgt->sgl, rknpu_obj->sgt->nents, ++ DMA_BIDIRECTIONAL); ++ if (ret == 0) { ++ ret = -EFAULT; ++ /* 6.18 port fix: rknpu_obj->size is `unsigned long`, not size_t. */ ++ LOG_DEV_ERROR(drm->dev, "%s: dma map %lu fail\n", __func__, ++ rknpu_obj->size); ++ goto free_sgt; ++ } ++ iommu_flush_iotlb_all(iommu_get_domain_for_dev(drm->dev)); ++ ++ if (rknpu_obj->flags & RKNPU_MEM_KERNEL_MAPPING) { ++ rknpu_obj->cookie = vmap(rknpu_obj->pages, rknpu_obj->num_pages, ++ VM_MAP, PAGE_KERNEL); ++ if (!rknpu_obj->cookie) { ++ ret = -ENOMEM; ++ LOG_ERROR("failed to vmap: %d\n", ret); ++ goto unmap_sg; ++ } ++ rknpu_obj->kv_addr = rknpu_obj->cookie; ++ } ++ ++ dma_addr = sg_dma_address(rknpu_obj->sgt->sgl); ++ rknpu_obj->dma_addr = dma_addr; ++ ++ for_each_sg(rknpu_obj->sgt->sgl, s, rknpu_obj->sgt->nents, i) { ++ dma_addr += s->length; ++ phys = sg_phys(s); ++ LOG_DEBUG( ++ "gem pages alloc sgt[%d], dma_address: %pad, length: %#x, phys: %pad, virt: %p\n", ++ i, &dma_addr, s->length, &phys, sg_virt(s)); ++ } ++ ++ return 0; ++ ++unmap_sg: ++ dma_unmap_sg(drm->dev, rknpu_obj->sgt->sgl, rknpu_obj->sgt->nents, ++ DMA_BIDIRECTIONAL); ++ ++free_sgt: ++ sg_free_table(rknpu_obj->sgt); ++ kfree(rknpu_obj->sgt); ++ ++put_pages: ++ drm_gem_put_pages(&rknpu_obj->base, rknpu_obj->pages, false, false); ++ ++ return ret; ++} ++ ++static void rknpu_gem_put_pages(struct rknpu_gem_object *rknpu_obj) ++{ ++ struct drm_device *drm = rknpu_obj->base.dev; ++ ++ if (rknpu_obj->flags & RKNPU_MEM_KERNEL_MAPPING) { ++ vunmap(rknpu_obj->kv_addr); ++ rknpu_obj->kv_addr = NULL; ++ } ++ ++ if (rknpu_obj->sgt != NULL) { ++ dma_unmap_sg(drm->dev, rknpu_obj->sgt->sgl, ++ rknpu_obj->sgt->nents, DMA_BIDIRECTIONAL); ++ sg_free_table(rknpu_obj->sgt); ++ kfree(rknpu_obj->sgt); ++ } ++ ++ drm_gem_put_pages(&rknpu_obj->base, rknpu_obj->pages, true, true); ++} ++#endif ++ ++static int rknpu_gem_alloc_buf(struct rknpu_gem_object *rknpu_obj) ++{ ++ struct drm_device *drm = rknpu_obj->base.dev; ++ struct rknpu_device *rknpu_dev = drm->dev_private; ++ unsigned int nr_pages = 0; ++ struct sg_table *sgt = NULL; ++ struct scatterlist *s = NULL; ++ gfp_t gfp_mask = GFP_KERNEL; ++ int ret = -EINVAL, i = 0; ++ ++ if (rknpu_obj->dma_addr) { ++ LOG_DEBUG("buffer already allocated.\n"); ++ return 0; ++ } ++ ++ rknpu_obj->dma_attrs = 0; ++ ++ /* ++ * if RKNPU_MEM_CONTIGUOUS, fully physically contiguous memory ++ * region will be allocated else physically contiguous ++ * as possible. ++ */ ++ if (!(rknpu_obj->flags & RKNPU_MEM_NON_CONTIGUOUS)) ++ rknpu_obj->dma_attrs |= DMA_ATTR_FORCE_CONTIGUOUS; ++ ++ // cacheable mapping or writecombine mapping ++ if (rknpu_obj->flags & RKNPU_MEM_CACHEABLE) { ++#ifdef DMA_ATTR_NON_CONSISTENT ++ rknpu_obj->dma_attrs |= DMA_ATTR_NON_CONSISTENT; ++#endif ++#ifdef DMA_ATTR_SYS_CACHE_ONLY ++ rknpu_obj->dma_attrs |= DMA_ATTR_SYS_CACHE_ONLY; ++#endif ++ } else if (rknpu_obj->flags & RKNPU_MEM_WRITE_COMBINE) { ++ rknpu_obj->dma_attrs |= DMA_ATTR_WRITE_COMBINE; ++ } ++ ++ if (!(rknpu_obj->flags & RKNPU_MEM_KERNEL_MAPPING)) ++ rknpu_obj->dma_attrs |= DMA_ATTR_NO_KERNEL_MAPPING; ++ ++#ifdef DMA_ATTR_SKIP_ZEROING ++ if (!(rknpu_obj->flags & RKNPU_MEM_ZEROING)) ++ rknpu_obj->dma_attrs |= DMA_ATTR_SKIP_ZEROING; ++#endif ++ ++#if RKNPU_GEM_ALLOC_FROM_PAGES ++ if ((rknpu_obj->flags & RKNPU_MEM_NON_CONTIGUOUS) && ++ rknpu_dev->iommu_en) { ++ return rknpu_gem_get_pages(rknpu_obj); ++ } ++#endif ++ ++ if (rknpu_obj->flags & RKNPU_MEM_ZEROING) ++ gfp_mask |= __GFP_ZERO; ++ ++ if (!rknpu_dev->iommu_en || ++ rknpu_dev->config->dma_mask <= DMA_BIT_MASK(32) || ++ (rknpu_obj->flags & RKNPU_MEM_DMA32)) { ++ gfp_mask &= ~__GFP_HIGHMEM; ++ gfp_mask |= __GFP_DMA32; ++ } ++ ++ nr_pages = rknpu_obj->size >> PAGE_SHIFT; ++ ++ rknpu_obj->pages = rknpu_gem_alloc_page(nr_pages); ++ if (!rknpu_obj->pages) { ++ LOG_ERROR("failed to allocate pages.\n"); ++ return -ENOMEM; ++ } ++ ++ rknpu_obj->cookie = ++ dma_alloc_attrs(drm->dev, rknpu_obj->size, &rknpu_obj->dma_addr, ++ gfp_mask, rknpu_obj->dma_attrs); ++ if (!rknpu_obj->cookie) { ++ /* ++ * when RKNPU_MEM_CONTIGUOUS and IOMMU is available ++ * try to fallback to allocate non-contiguous buffer ++ */ ++ if (!(rknpu_obj->flags & RKNPU_MEM_NON_CONTIGUOUS) && ++ rknpu_dev->iommu_en) { ++ LOG_DEV_WARN( ++ drm->dev, ++ "try to fallback to allocate non-contiguous %lu buffer.\n", ++ rknpu_obj->size); ++ rknpu_obj->dma_attrs &= ~DMA_ATTR_FORCE_CONTIGUOUS; ++ rknpu_obj->flags |= RKNPU_MEM_NON_CONTIGUOUS; ++ rknpu_obj->cookie = ++ dma_alloc_attrs(drm->dev, rknpu_obj->size, ++ &rknpu_obj->dma_addr, gfp_mask, ++ rknpu_obj->dma_attrs); ++ if (!rknpu_obj->cookie) { ++ LOG_DEV_ERROR( ++ drm->dev, ++ "failed to allocate non-contiguous %lu buffer.\n", ++ rknpu_obj->size); ++ goto err_free; ++ } ++ } else { ++ LOG_DEV_ERROR(drm->dev, ++ "failed to allocate %lu buffer.\n", ++ rknpu_obj->size); ++ goto err_free; ++ } ++ } ++ ++ if (rknpu_obj->flags & RKNPU_MEM_KERNEL_MAPPING) ++ rknpu_obj->kv_addr = rknpu_obj->cookie; ++ ++ sgt = kzalloc(sizeof(*sgt), GFP_KERNEL); ++ if (!sgt) { ++ ret = -ENOMEM; ++ goto err_free_dma; ++ } ++ ++ ret = dma_get_sgtable_attrs(drm->dev, sgt, rknpu_obj->cookie, ++ rknpu_obj->dma_addr, rknpu_obj->size, ++ rknpu_obj->dma_attrs); ++ if (ret < 0) { ++ LOG_DEV_ERROR(drm->dev, "failed to get sgtable.\n"); ++ goto err_free_sgt; ++ } ++ ++ for_each_sg(sgt->sgl, s, sgt->nents, i) { ++ sg_dma_address(s) = sg_phys(s); ++ LOG_DEBUG("dma alloc sgt[%d], phys_address: %pad, length: %u\n", ++ i, &s->dma_address, s->length); ++ } ++ ++#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE ++ ret = drm_prime_sg_to_page_addr_arrays(sgt, rknpu_obj->pages, NULL, ++ nr_pages); ++#else ++ ret = drm_prime_sg_to_page_array(sgt, rknpu_obj->pages, nr_pages); ++#endif ++ ++ if (ret < 0) { ++ LOG_DEV_ERROR(drm->dev, "invalid sgtable, ret: %d\n", ret); ++ goto err_free_sg_table; ++ } ++ ++ rknpu_obj->sgt = sgt; ++ ++ return ret; ++ ++err_free_sg_table: ++ sg_free_table(sgt); ++err_free_sgt: ++ kfree(sgt); ++err_free_dma: ++ dma_free_attrs(drm->dev, rknpu_obj->size, rknpu_obj->cookie, ++ rknpu_obj->dma_addr, rknpu_obj->dma_attrs); ++err_free: ++ rknpu_gem_free_page(rknpu_obj->pages); ++ ++ return ret; ++} ++ ++static void rknpu_gem_free_buf(struct rknpu_gem_object *rknpu_obj) ++{ ++ struct drm_device *drm = rknpu_obj->base.dev; ++#if RKNPU_GEM_ALLOC_FROM_PAGES ++ struct rknpu_device *rknpu_dev = drm->dev_private; ++#endif ++ ++ if (!rknpu_obj->dma_addr) { ++ LOG_DEBUG("dma handle is invalid.\n"); ++ return; ++ } ++ ++#if RKNPU_GEM_ALLOC_FROM_PAGES ++ if ((rknpu_obj->flags & RKNPU_MEM_NON_CONTIGUOUS) && ++ rknpu_dev->iommu_en) { ++ rknpu_gem_put_pages(rknpu_obj); ++ return; ++ } ++#endif ++ ++ sg_free_table(rknpu_obj->sgt); ++ kfree(rknpu_obj->sgt); ++ ++ dma_free_attrs(drm->dev, rknpu_obj->size, rknpu_obj->cookie, ++ rknpu_obj->dma_addr, rknpu_obj->dma_attrs); ++ ++ rknpu_gem_free_page(rknpu_obj->pages); ++ ++ rknpu_obj->dma_addr = 0; ++} ++ ++static int rknpu_gem_handle_create(struct drm_gem_object *obj, ++ struct drm_file *file_priv, ++ unsigned int *handle) ++{ ++ int ret = -EINVAL; ++ /* ++ * allocate a id of idr table where the obj is registered ++ * and handle has the id what user can see. ++ */ ++ ret = drm_gem_handle_create(file_priv, obj, handle); ++ if (ret) ++ return ret; ++ ++ LOG_DEBUG("gem handle: %#x\n", *handle); ++ ++ /* drop reference from allocate - handle holds it now. */ ++ rknpu_gem_object_put(obj); ++ ++ return 0; ++} ++ ++static int rknpu_gem_handle_destroy(struct drm_file *file_priv, ++ unsigned int handle) ++{ ++ return drm_gem_handle_delete(file_priv, handle); ++} ++ ++#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE ++static const struct vm_operations_struct vm_ops = { ++ .fault = rknpu_gem_fault, ++ .open = drm_gem_vm_open, ++ .close = drm_gem_vm_close, ++}; ++ ++static const struct drm_gem_object_funcs rknpu_gem_object_funcs = { ++ .free = rknpu_gem_free_object, ++ .export = drm_gem_prime_export, ++ .get_sg_table = rknpu_gem_prime_get_sg_table, ++ .vmap = rknpu_gem_prime_vmap, ++ .vunmap = rknpu_gem_prime_vunmap, ++ .mmap = rknpu_gem_mmap_obj, ++ .vm_ops = &vm_ops, ++}; ++#endif ++ ++static struct rknpu_gem_object *rknpu_gem_init(struct drm_device *drm, ++ unsigned long size) ++{ ++ struct rknpu_device *rknpu_dev = drm->dev_private; ++ struct rknpu_gem_object *rknpu_obj = NULL; ++ struct drm_gem_object *obj = NULL; ++ gfp_t gfp_mask; ++ int ret = -EINVAL; ++ ++ rknpu_obj = kzalloc(sizeof(*rknpu_obj), GFP_KERNEL); ++ if (!rknpu_obj) ++ return ERR_PTR(-ENOMEM); ++ ++ obj = &rknpu_obj->base; ++#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE ++ obj->funcs = &rknpu_gem_object_funcs; ++#endif ++ ++ ret = drm_gem_object_init(drm, obj, size); ++ if (ret < 0) { ++ LOG_DEV_ERROR(drm->dev, "failed to initialize gem object\n"); ++ kfree(rknpu_obj); ++ return ERR_PTR(ret); ++ } ++ ++ rknpu_obj->size = rknpu_obj->base.size; ++ ++ gfp_mask = mapping_gfp_mask(obj->filp->f_mapping); ++ ++ if (rknpu_obj->flags & RKNPU_MEM_ZEROING) ++ gfp_mask |= __GFP_ZERO; ++ ++ if (!rknpu_dev->iommu_en || ++ rknpu_dev->config->dma_mask <= DMA_BIT_MASK(32) || ++ (rknpu_obj->flags & RKNPU_MEM_DMA32)) { ++ gfp_mask &= ~__GFP_HIGHMEM; ++ gfp_mask |= __GFP_DMA32; ++ } ++ ++ mapping_set_gfp_mask(obj->filp->f_mapping, gfp_mask); ++ ++ return rknpu_obj; ++} ++ ++static void rknpu_gem_release(struct rknpu_gem_object *rknpu_obj) ++{ ++ /* release file pointer to gem object. */ ++ drm_gem_object_release(&rknpu_obj->base); ++ kfree(rknpu_obj); ++} ++ ++static int rknpu_gem_alloc_buf_with_cache(struct rknpu_gem_object *rknpu_obj, ++ enum rknpu_cache_type cache_type) ++{ ++ struct drm_device *drm = rknpu_obj->base.dev; ++ struct rknpu_device *rknpu_dev = drm->dev_private; ++ struct iommu_domain *domain = NULL; ++ struct rknpu_iommu_dma_cookie *cookie = NULL; ++ struct iova_domain *iovad = NULL; ++ struct scatterlist *s = NULL; ++ unsigned long length = 0; ++ unsigned long size = 0; ++ unsigned long offset = 0; ++ int i = 0; ++ int ret = -EINVAL; ++ phys_addr_t cache_start = 0; ++ unsigned long cache_offset = 0; ++ unsigned long cache_size = 0; ++ ++ switch (cache_type) { ++ case RKNPU_CACHE_SRAM: ++ cache_start = rknpu_dev->sram_start; ++ cache_offset = rknpu_obj->sram_obj->range_start * ++ rknpu_dev->sram_mm->chunk_size; ++ cache_size = rknpu_obj->sram_size; ++ break; ++ case RKNPU_CACHE_NBUF: ++ cache_start = rknpu_dev->nbuf_start; ++ cache_offset = 0; ++ cache_size = rknpu_obj->nbuf_size; ++ break; ++ default: ++ LOG_ERROR("Unknown rknpu_cache_type: %d", cache_type); ++ return -EINVAL; ++ } ++ ++ /* iova map to cache */ ++ domain = iommu_get_domain_for_dev(rknpu_dev->dev); ++ if (!domain) { ++ LOG_ERROR("failed to get iommu domain!"); ++ return -EINVAL; ++ } ++ ++ cookie = (void *)domain->iova_cookie; ++ iovad = &cookie->iovad; ++ rknpu_obj->iova_size = iova_align(iovad, cache_size + rknpu_obj->size); ++ rknpu_obj->iova_start = rknpu_iommu_dma_alloc_iova( ++ domain, rknpu_obj->iova_size, dma_get_mask(drm->dev), drm->dev); ++ if (!rknpu_obj->iova_start) { ++ LOG_ERROR("iommu_dma_alloc_iova failed\n"); ++ return -ENOMEM; ++ } ++ ++ LOG_INFO("allocate iova start: %pad, size: %lu\n", ++ &rknpu_obj->iova_start, rknpu_obj->iova_size); ++ ++ /* ++ * Overview cache + DDR map to IOVA ++ * -------- ++ * cache_size: ++ * - allocate from CACHE, this size value has been page-aligned ++ * size: rknpu_obj->size ++ * - allocate from DDR pages, this size value has been page-aligned ++ * iova_size: rknpu_obj->iova_size ++ * - from iova_align(cache_size + size) ++ * - it may be larger than the (cache_size + size), and the larger part is not mapped ++ * -------- ++ * ++ * |<- cache_size ->| |<- - - - size - - - ->| ++ * +---------------+ +----------------------+ ++ * | CACHE | | DDR | ++ * +---------------+ +----------------------+ ++ * | | ++ * | V | V | ++ * +---------------------------------------+ ++ * | IOVA range | ++ * +---------------------------------------+ ++ * |<- - - - - - - iova_size - - - - - - ->| ++ * ++ */ ++ /* 6.18 port fix: iommu_map() gained a trailing gfp_t arg. */ ++ ret = iommu_map(domain, rknpu_obj->iova_start, ++ cache_start + cache_offset, cache_size, ++ IOMMU_READ | IOMMU_WRITE, GFP_KERNEL); ++ if (ret) { ++ LOG_ERROR("cache iommu_map error: %d\n", ret); ++ goto free_iova; ++ } ++ ++ rknpu_obj->dma_addr = rknpu_obj->iova_start; ++ ++ if (rknpu_obj->size == 0) { ++ LOG_INFO("allocate cache size: %lu\n", cache_size); ++ return 0; ++ } ++ ++ rknpu_obj->pages = drm_gem_get_pages(&rknpu_obj->base); ++ if (IS_ERR(rknpu_obj->pages)) { ++ ret = PTR_ERR(rknpu_obj->pages); ++ LOG_ERROR("failed to get pages: %d\n", ret); ++ goto cache_unmap; ++ } ++ ++ rknpu_obj->num_pages = rknpu_obj->size >> PAGE_SHIFT; ++ ++#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE ++ rknpu_obj->sgt = drm_prime_pages_to_sg(drm, rknpu_obj->pages, ++ rknpu_obj->num_pages); ++#else ++ rknpu_obj->sgt = ++ drm_prime_pages_to_sg(rknpu_obj->pages, rknpu_obj->num_pages); ++#endif ++ if (IS_ERR(rknpu_obj->sgt)) { ++ ret = PTR_ERR(rknpu_obj->sgt); ++ LOG_ERROR("failed to allocate sgt: %d\n", ret); ++ goto put_pages; ++ } ++ ++ length = rknpu_obj->size; ++ offset = rknpu_obj->iova_start + cache_size; ++ ++ for_each_sg(rknpu_obj->sgt->sgl, s, rknpu_obj->sgt->nents, i) { ++ size = (length < s->length) ? length : s->length; ++ ++ /* 6.18 port fix: iommu_map() gained a trailing gfp_t arg. */ ++ ret = iommu_map(domain, offset, sg_phys(s), size, ++ IOMMU_READ | IOMMU_WRITE, GFP_KERNEL); ++ if (ret) { ++ LOG_ERROR("ddr iommu_map error: %d\n", ret); ++ goto sgl_unmap; ++ } ++ ++ length -= size; ++ offset += size; ++ ++ if (length == 0) ++ break; ++ } ++ ++ LOG_INFO("allocate size: %lu with cache size: %lu\n", rknpu_obj->size, ++ cache_size); ++ ++ return 0; ++ ++sgl_unmap: ++ iommu_unmap(domain, rknpu_obj->iova_start + cache_size, ++ rknpu_obj->size - length); ++ sg_free_table(rknpu_obj->sgt); ++ kfree(rknpu_obj->sgt); ++ ++put_pages: ++ drm_gem_put_pages(&rknpu_obj->base, rknpu_obj->pages, false, false); ++ ++cache_unmap: ++ iommu_unmap(domain, rknpu_obj->iova_start, cache_size); ++ ++free_iova: ++ rknpu_iommu_dma_free_iova((void *)domain->iova_cookie, ++ rknpu_obj->iova_start, rknpu_obj->iova_size); ++ ++ return ret; ++} ++ ++static void rknpu_gem_free_buf_with_cache(struct rknpu_gem_object *rknpu_obj, ++ enum rknpu_cache_type cache_type) ++{ ++ struct drm_device *drm = rknpu_obj->base.dev; ++ struct rknpu_device *rknpu_dev = drm->dev_private; ++ struct iommu_domain *domain = NULL; ++ unsigned long cache_size = 0; ++ ++ switch (cache_type) { ++ case RKNPU_CACHE_SRAM: ++ cache_size = rknpu_obj->sram_size; ++ break; ++ case RKNPU_CACHE_NBUF: ++ cache_size = rknpu_obj->nbuf_size; ++ break; ++ default: ++ LOG_ERROR("Unknown rknpu_cache_type: %d", cache_type); ++ return; ++ } ++ ++ domain = iommu_get_domain_for_dev(rknpu_dev->dev); ++ if (domain) { ++ iommu_unmap(domain, rknpu_obj->iova_start, cache_size); ++ if (rknpu_obj->size > 0) ++ iommu_unmap(domain, rknpu_obj->iova_start + cache_size, ++ rknpu_obj->size); ++ rknpu_iommu_dma_free_iova((void *)domain->iova_cookie, ++ rknpu_obj->iova_start, ++ rknpu_obj->iova_size); ++ } ++ ++ if (rknpu_obj->pages) ++ drm_gem_put_pages(&rknpu_obj->base, rknpu_obj->pages, true, ++ true); ++ ++ if (rknpu_obj->sgt != NULL) { ++ sg_free_table(rknpu_obj->sgt); ++ kfree(rknpu_obj->sgt); ++ } ++} ++ ++struct rknpu_gem_object *rknpu_gem_object_create(struct drm_device *drm, ++ unsigned int flags, ++ unsigned long size, ++ unsigned long sram_size) ++{ ++ struct rknpu_device *rknpu_dev = drm->dev_private; ++ struct rknpu_gem_object *rknpu_obj = NULL; ++ size_t remain_ddr_size = 0; ++ int ret = -EINVAL; ++ ++ if (!size) { ++ LOG_DEV_ERROR(drm->dev, "invalid buffer size: %lu\n", size); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ remain_ddr_size = round_up(size, PAGE_SIZE); ++ ++ if (!rknpu_dev->iommu_en && (flags & RKNPU_MEM_NON_CONTIGUOUS)) { ++ /* ++ * when no IOMMU is available, all allocated buffers are ++ * contiguous anyway, so drop RKNPU_MEM_NON_CONTIGUOUS flag ++ */ ++ flags &= ~RKNPU_MEM_NON_CONTIGUOUS; ++ LOG_WARN( ++ "non-contiguous allocation is not supported without IOMMU, falling back to contiguous buffer\n"); ++ } ++ ++ if (IS_ENABLED(CONFIG_ROCKCHIP_RKNPU_SRAM) && ++ (flags & RKNPU_MEM_TRY_ALLOC_SRAM) && rknpu_dev->sram_size > 0) { ++ size_t sram_free_size = 0; ++ size_t real_sram_size = 0; ++ ++ if (sram_size != 0) ++ sram_size = round_up(sram_size, PAGE_SIZE); ++ ++ rknpu_obj = rknpu_gem_init(drm, remain_ddr_size); ++ if (IS_ERR(rknpu_obj)) ++ return rknpu_obj; ++ ++ /* set memory type and cache attribute from user side. */ ++ rknpu_obj->flags = flags; ++ ++ sram_free_size = rknpu_dev->sram_mm->free_chunks * ++ rknpu_dev->sram_mm->chunk_size; ++ if (sram_free_size > 0) { ++ real_sram_size = remain_ddr_size; ++ if (sram_size != 0 && remain_ddr_size > sram_size) ++ real_sram_size = sram_size; ++ if (real_sram_size > sram_free_size) ++ real_sram_size = sram_free_size; ++ ret = rknpu_mm_alloc(rknpu_dev->sram_mm, real_sram_size, ++ &rknpu_obj->sram_obj); ++ if (ret != 0) { ++ sram_free_size = ++ rknpu_dev->sram_mm->free_chunks * ++ rknpu_dev->sram_mm->chunk_size; ++ LOG_WARN( ++ "mm allocate %zu failed, ret: %d, free size: %zu\n", ++ real_sram_size, ret, sram_free_size); ++ real_sram_size = 0; ++ } ++ } ++ ++ if (real_sram_size > 0) { ++ rknpu_obj->sram_size = real_sram_size; ++ ++ ret = rknpu_gem_alloc_buf_with_cache(rknpu_obj, ++ RKNPU_CACHE_SRAM); ++ if (ret < 0) ++ goto mm_free; ++ remain_ddr_size = 0; ++ } ++ } else if (IS_ENABLED(CONFIG_NO_GKI) && ++ (flags & RKNPU_MEM_TRY_ALLOC_NBUF) && ++ rknpu_dev->nbuf_size > 0) { ++ size_t nbuf_size = 0; ++ ++ rknpu_obj = rknpu_gem_init(drm, remain_ddr_size); ++ if (IS_ERR(rknpu_obj)) ++ return rknpu_obj; ++ ++ nbuf_size = remain_ddr_size <= rknpu_dev->nbuf_size ? ++ remain_ddr_size : ++ rknpu_dev->nbuf_size; ++ ++ /* set memory type and cache attribute from user side. */ ++ rknpu_obj->flags = flags; ++ ++ if (nbuf_size > 0) { ++ rknpu_obj->nbuf_size = nbuf_size; ++ ++ ret = rknpu_gem_alloc_buf_with_cache(rknpu_obj, ++ RKNPU_CACHE_NBUF); ++ if (ret < 0) ++ goto gem_release; ++ remain_ddr_size = 0; ++ } ++ } ++ ++ if (remain_ddr_size > 0) { ++ rknpu_obj = rknpu_gem_init(drm, remain_ddr_size); ++ if (IS_ERR(rknpu_obj)) ++ return rknpu_obj; ++ ++ /* set memory type and cache attribute from user side. */ ++ rknpu_obj->flags = flags; ++ ++ ret = rknpu_gem_alloc_buf(rknpu_obj); ++ if (ret < 0) ++ goto gem_release; ++ } ++ ++ if (rknpu_obj) ++ LOG_DEBUG( ++ "created dma addr: %pad, cookie: %p, ddr size: %lu, sram size: %lu, nbuf size: %lu, attrs: %#lx, flags: %#x\n", ++ &rknpu_obj->dma_addr, rknpu_obj->cookie, ++ rknpu_obj->size, rknpu_obj->sram_size, ++ rknpu_obj->nbuf_size, rknpu_obj->dma_attrs, ++ rknpu_obj->flags); ++ ++ return rknpu_obj; ++ ++mm_free: ++ if (IS_ENABLED(CONFIG_ROCKCHIP_RKNPU_SRAM) && ++ rknpu_obj->sram_obj != NULL) ++ rknpu_mm_free(rknpu_dev->sram_mm, rknpu_obj->sram_obj); ++ ++gem_release: ++ rknpu_gem_release(rknpu_obj); ++ ++ return ERR_PTR(ret); ++} ++ ++void rknpu_gem_object_destroy(struct rknpu_gem_object *rknpu_obj) ++{ ++ struct drm_gem_object *obj = &rknpu_obj->base; ++ ++ LOG_DEBUG( ++ "destroy dma addr: %pad, cookie: %p, size: %lu, attrs: %#lx, flags: %#x, handle count: %d\n", ++ &rknpu_obj->dma_addr, rknpu_obj->cookie, rknpu_obj->size, ++ rknpu_obj->dma_attrs, rknpu_obj->flags, obj->handle_count); ++ ++ /* ++ * do not release memory region from exporter. ++ * ++ * the region will be released by exporter ++ * once dmabuf's refcount becomes 0. ++ */ ++ if (obj->import_attach) { ++ drm_prime_gem_destroy(obj, rknpu_obj->sgt); ++ rknpu_gem_free_page(rknpu_obj->pages); ++ } else { ++ if (IS_ENABLED(CONFIG_ROCKCHIP_RKNPU_SRAM) && ++ rknpu_obj->sram_size > 0) { ++ struct rknpu_device *rknpu_dev = obj->dev->dev_private; ++ ++ if (rknpu_obj->sram_obj != NULL) ++ rknpu_mm_free(rknpu_dev->sram_mm, ++ rknpu_obj->sram_obj); ++ rknpu_gem_free_buf_with_cache(rknpu_obj, ++ RKNPU_CACHE_SRAM); ++ } else if (IS_ENABLED(CONFIG_NO_GKI) && ++ rknpu_obj->nbuf_size > 0) { ++ rknpu_gem_free_buf_with_cache(rknpu_obj, ++ RKNPU_CACHE_NBUF); ++ } else { ++ rknpu_gem_free_buf(rknpu_obj); ++ } ++ } ++ ++ rknpu_gem_release(rknpu_obj); ++} ++ ++int rknpu_gem_create_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct rknpu_mem_create *args = data; ++ struct rknpu_gem_object *rknpu_obj = NULL; ++ int ret = -EINVAL; ++ ++ rknpu_obj = rknpu_gem_object_find(file_priv, args->handle); ++ if (!rknpu_obj) { ++ rknpu_obj = rknpu_gem_object_create( ++ dev, args->flags, args->size, args->sram_size); ++ if (IS_ERR(rknpu_obj)) ++ return PTR_ERR(rknpu_obj); ++ ++ ret = rknpu_gem_handle_create(&rknpu_obj->base, file_priv, ++ &args->handle); ++ if (ret) { ++ rknpu_gem_object_destroy(rknpu_obj); ++ return ret; ++ } ++ } ++ ++ // rknpu_gem_object_get(&rknpu_obj->base); ++ ++ args->size = rknpu_obj->size; ++ args->sram_size = rknpu_obj->sram_size; ++ args->obj_addr = (__u64)(uintptr_t)rknpu_obj; ++ args->dma_addr = rknpu_obj->dma_addr; ++ ++ return 0; ++} ++ ++int rknpu_gem_map_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct rknpu_mem_map *args = data; ++ ++#if KERNEL_VERSION(4, 19, 0) > LINUX_VERSION_CODE ++ return rknpu_gem_dumb_map_offset(file_priv, dev, args->handle, ++ &args->offset); ++#else ++ return drm_gem_dumb_map_offset(file_priv, dev, args->handle, ++ &args->offset); ++#endif ++} ++ ++int rknpu_gem_destroy_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct rknpu_gem_object *rknpu_obj = NULL; ++ struct rknpu_mem_destroy *args = data; ++ ++ rknpu_obj = rknpu_gem_object_find(file_priv, args->handle); ++ if (!rknpu_obj) ++ return -EINVAL; ++ ++ // rknpu_gem_object_put(&rknpu_obj->base); ++ ++ return rknpu_gem_handle_destroy(file_priv, args->handle); ++} ++ ++#if RKNPU_GEM_ALLOC_FROM_PAGES ++/* ++ * __vm_map_pages - maps range of kernel pages into user vma ++ * @vma: user vma to map to ++ * @pages: pointer to array of source kernel pages ++ * @num: number of pages in page array ++ * @offset: user's requested vm_pgoff ++ * ++ * This allows drivers to map range of kernel pages into a user vma. ++ * ++ * Return: 0 on success and error code otherwise. ++ */ ++static int __vm_map_pages(struct vm_area_struct *vma, struct page **pages, ++ unsigned long num, unsigned long offset) ++{ ++ unsigned long count = vma_pages(vma); ++ unsigned long uaddr = vma->vm_start; ++ int ret = -EINVAL, i = 0; ++ ++ /* Fail if the user requested offset is beyond the end of the object */ ++ if (offset >= num) ++ return -ENXIO; ++ ++ /* Fail if the user requested size exceeds available object size */ ++ if (count > num - offset) ++ return -ENXIO; ++ ++ for (i = 0; i < count; i++) { ++ ret = vm_insert_page(vma, uaddr, pages[offset + i]); ++ if (ret < 0) ++ return ret; ++ uaddr += PAGE_SIZE; ++ } ++ ++ return 0; ++} ++ ++static int rknpu_gem_mmap_pages(struct rknpu_gem_object *rknpu_obj, ++ struct vm_area_struct *vma) ++{ ++ struct drm_device *drm = rknpu_obj->base.dev; ++ int ret = -EINVAL; ++ ++ /* 6.18 port fix: vm_flags is read-only now; use vm_flags_set(). */ ++ vm_flags_set(vma, VM_MIXEDMAP); ++ ++ ret = __vm_map_pages(vma, rknpu_obj->pages, rknpu_obj->num_pages, ++ vma->vm_pgoff); ++ if (ret < 0) ++ LOG_DEV_ERROR(drm->dev, "failed to map pages into vma: %d\n", ++ ret); ++ ++ return ret; ++} ++#endif ++ ++static int rknpu_gem_mmap_cache(struct rknpu_gem_object *rknpu_obj, ++ struct vm_area_struct *vma, ++ enum rknpu_cache_type cache_type) ++{ ++ struct drm_device *drm = rknpu_obj->base.dev; ++#if RKNPU_GEM_ALLOC_FROM_PAGES ++ struct rknpu_device *rknpu_dev = drm->dev_private; ++#endif ++ unsigned long vm_size = 0; ++ int ret = -EINVAL; ++ unsigned long offset = 0; ++ unsigned long num_pages = 0; ++ int i = 0; ++ phys_addr_t cache_start = 0; ++ unsigned long cache_offset = 0; ++ unsigned long cache_size = 0; ++ ++ switch (cache_type) { ++ case RKNPU_CACHE_SRAM: ++ cache_start = rknpu_dev->sram_start; ++ cache_offset = rknpu_obj->sram_obj->range_start * ++ rknpu_dev->sram_mm->chunk_size; ++ cache_size = rknpu_obj->sram_size; ++ break; ++ case RKNPU_CACHE_NBUF: ++ cache_start = rknpu_dev->nbuf_start; ++ cache_offset = 0; ++ cache_size = rknpu_obj->nbuf_size; ++ break; ++ default: ++ LOG_ERROR("Unknown rknpu_cache_type: %d", cache_type); ++ return -EINVAL; ++ } ++ ++ /* 6.18 port fix: vm_flags is read-only now; use vm_flags_set(). */ ++ vm_flags_set(vma, VM_MIXEDMAP); ++ ++ vm_size = vma->vm_end - vma->vm_start; ++ ++ /* ++ * Convert a physical address in a cache area to a page frame number (PFN), ++ * and store the resulting PFN in the vm_pgoff field of the given VMA. ++ * ++ * NOTE: This conversion carries a risk because the resulting PFN is not a true ++ * page frame number and may not be valid or usable in all contexts. ++ */ ++ vma->vm_pgoff = __phys_to_pfn(cache_start + cache_offset); ++ ++ ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, cache_size, ++ vma->vm_page_prot); ++ if (ret) ++ return -EAGAIN; ++ ++ if (rknpu_obj->size == 0) ++ return 0; ++ ++ offset = cache_size; ++ ++ num_pages = (vm_size - cache_size) / PAGE_SIZE; ++ for (i = 0; i < num_pages; ++i) { ++ ret = vm_insert_page(vma, vma->vm_start + offset, ++ rknpu_obj->pages[i]); ++ if (ret < 0) ++ return ret; ++ offset += PAGE_SIZE; ++ } ++ ++ return 0; ++} ++ ++static int rknpu_gem_mmap_buffer(struct rknpu_gem_object *rknpu_obj, ++ struct vm_area_struct *vma) ++{ ++ struct drm_device *drm = rknpu_obj->base.dev; ++#if RKNPU_GEM_ALLOC_FROM_PAGES ++ struct rknpu_device *rknpu_dev = drm->dev_private; ++#endif ++ unsigned long vm_size = 0; ++ int ret = -EINVAL; ++ ++ /* ++ * clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set the ++ * vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map ++ * the whole buffer. ++ */ ++ /* 6.18 port fix: vm_flags is read-only now; use vm_flags_set()/clear(). */ ++ vm_flags_set(vma, VM_DONTCOPY | VM_DONTEXPAND | VM_DONTDUMP | VM_IO); ++ vm_flags_clear(vma, VM_PFNMAP); ++ vma->vm_pgoff = 0; ++ ++ vm_size = vma->vm_end - vma->vm_start; ++ ++ /* check if user-requested size is valid. */ ++ if (vm_size > rknpu_obj->size) ++ return -EINVAL; ++ ++ if (rknpu_obj->sram_size > 0) ++ return rknpu_gem_mmap_cache(rknpu_obj, vma, RKNPU_CACHE_SRAM); ++ else if (rknpu_obj->nbuf_size > 0) ++ return rknpu_gem_mmap_cache(rknpu_obj, vma, RKNPU_CACHE_NBUF); ++ ++#if RKNPU_GEM_ALLOC_FROM_PAGES ++ if ((rknpu_obj->flags & RKNPU_MEM_NON_CONTIGUOUS) && ++ rknpu_dev->iommu_en) { ++ return rknpu_gem_mmap_pages(rknpu_obj, vma); ++ } ++#endif ++ ++ ret = dma_mmap_attrs(drm->dev, vma, rknpu_obj->cookie, ++ rknpu_obj->dma_addr, rknpu_obj->size, ++ rknpu_obj->dma_attrs); ++ if (ret < 0) { ++ LOG_DEV_ERROR(drm->dev, "failed to mmap, ret: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++void rknpu_gem_free_object(struct drm_gem_object *obj) ++{ ++ rknpu_gem_object_destroy(to_rknpu_obj(obj)); ++} ++ ++int rknpu_gem_dumb_create(struct drm_file *file_priv, struct drm_device *drm, ++ struct drm_mode_create_dumb *args) ++{ ++ struct rknpu_device *rknpu_dev = drm->dev_private; ++ struct rknpu_gem_object *rknpu_obj = NULL; ++ unsigned int flags = 0; ++ int ret = -EINVAL; ++ ++ /* ++ * allocate memory to be used for framebuffer. ++ * - this callback would be called by user application ++ * with DRM_IOCTL_MODE_CREATE_DUMB command. ++ */ ++ args->pitch = args->width * ((args->bpp + 7) / 8); ++ args->size = args->pitch * args->height; ++ ++ if (rknpu_dev->iommu_en) ++ flags = RKNPU_MEM_NON_CONTIGUOUS | RKNPU_MEM_WRITE_COMBINE; ++ else ++ flags = RKNPU_MEM_CONTIGUOUS | RKNPU_MEM_WRITE_COMBINE; ++ ++ rknpu_obj = rknpu_gem_object_create(drm, flags, args->size, 0); ++ if (IS_ERR(rknpu_obj)) { ++ LOG_DEV_ERROR(drm->dev, "gem object allocate failed.\n"); ++ return PTR_ERR(rknpu_obj); ++ } ++ ++ ret = rknpu_gem_handle_create(&rknpu_obj->base, file_priv, ++ &args->handle); ++ if (ret) { ++ rknpu_gem_object_destroy(rknpu_obj); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++#if KERNEL_VERSION(4, 19, 0) > LINUX_VERSION_CODE ++int rknpu_gem_dumb_map_offset(struct drm_file *file_priv, ++ struct drm_device *drm, uint32_t handle, ++ uint64_t *offset) ++{ ++ struct rknpu_gem_object *rknpu_obj = NULL; ++ struct drm_gem_object *obj = NULL; ++ int ret = -EINVAL; ++ ++ rknpu_obj = rknpu_gem_object_find(file_priv, handle); ++ if (!rknpu_obj) ++ return 0; ++ ++ /* Don't allow imported objects to be mapped */ ++ obj = &rknpu_obj->base; ++ if (obj->import_attach) ++ return -EINVAL; ++ ++ ret = drm_gem_create_mmap_offset(obj); ++ if (ret) ++ return ret; ++ ++ *offset = drm_vma_node_offset_addr(&obj->vma_node); ++ ++ return 0; ++} ++#endif ++ ++#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE ++vm_fault_t rknpu_gem_fault(struct vm_fault *vmf) ++{ ++ struct vm_area_struct *vma = vmf->vma; ++ struct drm_gem_object *obj = vma->vm_private_data; ++ struct rknpu_gem_object *rknpu_obj = to_rknpu_obj(obj); ++ struct drm_device *drm = rknpu_obj->base.dev; ++ unsigned long pfn = 0; ++ pgoff_t page_offset = 0; ++ ++ page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT; ++ ++ if (page_offset >= (rknpu_obj->size >> PAGE_SHIFT)) { ++ LOG_DEV_ERROR(drm->dev, "invalid page offset\n"); ++ return VM_FAULT_SIGBUS; ++ } ++ ++ pfn = page_to_pfn(rknpu_obj->pages[page_offset]); ++ /* 6.18 port fix: vmf_insert_mixed() takes a plain pfn now (no pfn_t). */ ++ return vmf_insert_mixed(vma, vmf->address, pfn); ++} ++#elif KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE ++int rknpu_gem_fault(struct vm_fault *vmf) ++{ ++ struct vm_area_struct *vma = vmf->vma; ++ struct drm_gem_object *obj = vma->vm_private_data; ++ struct rknpu_gem_object *rknpu_obj = to_rknpu_obj(obj); ++ struct drm_device *drm = rknpu_obj->base.dev; ++ unsigned long pfn = 0; ++ pgoff_t page_offset = 0; ++ int ret = -EINVAL; ++ ++ page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT; ++ ++ if (page_offset >= (rknpu_obj->size >> PAGE_SHIFT)) { ++ LOG_DEV_ERROR(drm->dev, "invalid page offset\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ pfn = page_to_pfn(rknpu_obj->pages[page_offset]); ++ ret = vm_insert_mixed(vma, vmf->address, __pfn_to_pfn_t(pfn, PFN_DEV)); ++ ++out: ++ switch (ret) { ++ case 0: ++ case -ERESTARTSYS: ++ case -EINTR: ++ return VM_FAULT_NOPAGE; ++ case -ENOMEM: ++ return VM_FAULT_OOM; ++ default: ++ return VM_FAULT_SIGBUS; ++ } ++} ++#else ++int rknpu_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ++{ ++ struct drm_gem_object *obj = vma->vm_private_data; ++ struct rknpu_gem_object *rknpu_obj = to_rknpu_obj(obj); ++ struct drm_device *drm = rknpu_obj->base.dev; ++ unsigned long pfn = 0; ++ pgoff_t page_offset = 0; ++ int ret = -EINVAL; ++ ++ page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >> ++ PAGE_SHIFT; ++ ++ if (page_offset >= (rknpu_obj->size >> PAGE_SHIFT)) { ++ LOG_DEV_ERROR(drm->dev, "invalid page offset\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ pfn = page_to_pfn(rknpu_obj->pages[page_offset]); ++ ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, ++ __pfn_to_pfn_t(pfn, PFN_DEV)); ++ ++out: ++ switch (ret) { ++ case 0: ++ case -ERESTARTSYS: ++ case -EINTR: ++ return VM_FAULT_NOPAGE; ++ case -ENOMEM: ++ return VM_FAULT_OOM; ++ default: ++ return VM_FAULT_SIGBUS; ++ } ++} ++#endif ++ ++int rknpu_gem_mmap_obj(struct drm_gem_object *obj, struct vm_area_struct *vma) ++{ ++ struct rknpu_gem_object *rknpu_obj = to_rknpu_obj(obj); ++ int ret = -EINVAL; ++ ++ LOG_DEBUG("flags: %#x\n", rknpu_obj->flags); ++ ++ /* non-cacheable as default. */ ++ if (rknpu_obj->flags & RKNPU_MEM_CACHEABLE) { ++ vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); ++ } else if (rknpu_obj->flags & RKNPU_MEM_WRITE_COMBINE) { ++ vma->vm_page_prot = ++ pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); ++ } else { ++ vma->vm_page_prot = ++ pgprot_noncached(vm_get_page_prot(vma->vm_flags)); ++ } ++ ++ ret = rknpu_gem_mmap_buffer(rknpu_obj, vma); ++ if (ret) ++ goto err_close_vm; ++ ++ return 0; ++ ++err_close_vm: ++ drm_gem_vm_close(vma); ++ ++ return ret; ++} ++ ++int rknpu_gem_mmap(struct file *filp, struct vm_area_struct *vma) ++{ ++ struct drm_gem_object *obj = NULL; ++ int ret = -EINVAL; ++ ++ /* set vm_area_struct. */ ++ ret = drm_gem_mmap(filp, vma); ++ if (ret < 0) { ++ LOG_ERROR("failed to mmap, ret: %d\n", ret); ++ return ret; ++ } ++ ++ obj = vma->vm_private_data; ++ ++ if (obj->import_attach) ++ return dma_buf_mmap(obj->dma_buf, vma, 0); ++ ++ return rknpu_gem_mmap_obj(obj, vma); ++} ++ ++/* low-level interface prime helpers */ ++#if KERNEL_VERSION(4, 13, 0) <= LINUX_VERSION_CODE ++struct drm_gem_object *rknpu_gem_prime_import(struct drm_device *dev, ++ struct dma_buf *dma_buf) ++{ ++ return drm_gem_prime_import_dev(dev, dma_buf, dev->dev); ++} ++#endif ++ ++struct sg_table *rknpu_gem_prime_get_sg_table(struct drm_gem_object *obj) ++{ ++ struct rknpu_gem_object *rknpu_obj = to_rknpu_obj(obj); ++ int npages = 0; ++ ++ npages = rknpu_obj->size >> PAGE_SHIFT; ++ ++#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE ++ return drm_prime_pages_to_sg(obj->dev, rknpu_obj->pages, npages); ++#else ++ return drm_prime_pages_to_sg(rknpu_obj->pages, npages); ++#endif ++} ++ ++struct drm_gem_object * ++rknpu_gem_prime_import_sg_table(struct drm_device *dev, ++ struct dma_buf_attachment *attach, ++ struct sg_table *sgt) ++{ ++ struct rknpu_gem_object *rknpu_obj = NULL; ++ int npages = 0; ++ int ret = -EINVAL; ++ ++ rknpu_obj = rknpu_gem_init(dev, attach->dmabuf->size); ++ if (IS_ERR(rknpu_obj)) { ++ ret = PTR_ERR(rknpu_obj); ++ return ERR_PTR(ret); ++ } ++ ++ rknpu_obj->dma_addr = sg_dma_address(sgt->sgl); ++ ++ npages = rknpu_obj->size >> PAGE_SHIFT; ++ rknpu_obj->pages = rknpu_gem_alloc_page(npages); ++ if (!rknpu_obj->pages) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE ++ ret = drm_prime_sg_to_page_addr_arrays(sgt, rknpu_obj->pages, NULL, ++ npages); ++#else ++ ret = drm_prime_sg_to_page_array(sgt, rknpu_obj->pages, npages); ++#endif ++ if (ret < 0) ++ goto err_free_large; ++ ++ rknpu_obj->sgt = sgt; ++ ++ if (sgt->nents == 1) { ++ /* always physically continuous memory if sgt->nents is 1. */ ++ rknpu_obj->flags |= RKNPU_MEM_CONTIGUOUS; ++ } else { ++ /* ++ * this case could be CONTIG or NONCONTIG type but for now ++ * sets NONCONTIG. ++ * TODO. we have to find a way that exporter can notify ++ * the type of its own buffer to importer. ++ */ ++ rknpu_obj->flags |= RKNPU_MEM_NON_CONTIGUOUS; ++ } ++ ++ return &rknpu_obj->base; ++ ++err_free_large: ++ rknpu_gem_free_page(rknpu_obj->pages); ++err: ++ rknpu_gem_release(rknpu_obj); ++ return ERR_PTR(ret); ++} ++ ++#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE ++void *rknpu_gem_prime_vmap(struct drm_gem_object *obj) ++{ ++ struct rknpu_gem_object *rknpu_obj = to_rknpu_obj(obj); ++ ++ if (!rknpu_obj->pages) ++ return NULL; ++ ++ return vmap(rknpu_obj->pages, rknpu_obj->num_pages, VM_MAP, ++ PAGE_KERNEL); ++} ++ ++void rknpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr) ++{ ++ vunmap(vaddr); ++} ++#else ++int rknpu_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map) ++{ ++ struct rknpu_gem_object *rknpu_obj = to_rknpu_obj(obj); ++ void *vaddr = NULL; ++ ++ if (!rknpu_obj->pages) ++ return -EINVAL; ++ ++ vaddr = vmap(rknpu_obj->pages, rknpu_obj->num_pages, VM_MAP, ++ PAGE_KERNEL); ++ if (!vaddr) ++ return -ENOMEM; ++ ++ iosys_map_set_vaddr(map, vaddr); ++ ++ return 0; ++} ++ ++void rknpu_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map *map) ++{ ++ struct rknpu_gem_object *rknpu_obj = to_rknpu_obj(obj); ++ ++ if (rknpu_obj->pages) { ++ vunmap(map->vaddr); ++ map->vaddr = NULL; ++ } ++} ++#endif ++ ++int rknpu_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) ++{ ++ int ret = -EINVAL; ++ ++ ret = drm_gem_mmap_obj(obj, obj->size, vma); ++ if (ret < 0) ++ return ret; ++ ++ return rknpu_gem_mmap_obj(obj, vma); ++} ++ ++static int rknpu_cache_sync(struct rknpu_gem_object *rknpu_obj, ++ unsigned long *length, unsigned long *offset, ++ enum rknpu_cache_type cache_type) ++{ ++#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE ++ struct drm_gem_object *obj = &rknpu_obj->base; ++ struct rknpu_device *rknpu_dev = obj->dev->dev_private; ++ void __iomem *cache_base_io = NULL; ++ unsigned long cache_offset = 0; ++ unsigned long cache_size = 0; ++ ++ switch (cache_type) { ++ case RKNPU_CACHE_SRAM: ++ cache_base_io = rknpu_dev->sram_base_io; ++ cache_offset = rknpu_obj->sram_obj->range_start * ++ rknpu_dev->sram_mm->chunk_size; ++ cache_size = rknpu_obj->sram_size; ++ break; ++ case RKNPU_CACHE_NBUF: ++ cache_base_io = rknpu_dev->nbuf_base_io; ++ cache_offset = 0; ++ cache_size = rknpu_obj->nbuf_size; ++ break; ++ default: ++ LOG_ERROR("Unknown rknpu_cache_type: %d", cache_type); ++ return -EINVAL; ++ } ++ ++ if ((*offset + *length) <= cache_size) { ++ __dma_map_area(cache_base_io + *offset + cache_offset, *length, ++ DMA_TO_DEVICE); ++ __dma_unmap_area(cache_base_io + *offset + cache_offset, ++ *length, DMA_FROM_DEVICE); ++ *length = 0; ++ *offset = 0; ++ } else if (*offset >= cache_size) { ++ *offset -= cache_size; ++ } else { ++ unsigned long cache_length = cache_size - *offset; ++ ++ __dma_map_area(cache_base_io + *offset + cache_offset, ++ cache_length, DMA_TO_DEVICE); ++ __dma_unmap_area(cache_base_io + *offset + cache_offset, ++ cache_length, DMA_FROM_DEVICE); ++ *length -= cache_length; ++ *offset = 0; ++ } ++#endif ++ ++ return 0; ++} ++ ++int rknpu_gem_sync_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct rknpu_gem_object *rknpu_obj = NULL; ++ struct rknpu_device *rknpu_dev = dev->dev_private; ++ struct rknpu_mem_sync *args = data; ++ struct scatterlist *sg; ++ dma_addr_t sg_phys_addr; ++ unsigned long length, offset = 0; ++ unsigned long sg_offset, sg_left, size = 0; ++ unsigned long len = 0; ++ int i; ++ ++ rknpu_obj = (struct rknpu_gem_object *)(uintptr_t)args->obj_addr; ++ if (!rknpu_obj) ++ return -EINVAL; ++ ++ if (!(rknpu_obj->flags & RKNPU_MEM_CACHEABLE)) ++ return -EINVAL; ++ ++ if (!(rknpu_obj->flags & RKNPU_MEM_NON_CONTIGUOUS)) { ++ if (args->flags & RKNPU_MEM_SYNC_TO_DEVICE) { ++ dma_sync_single_range_for_device( ++ dev->dev, rknpu_obj->dma_addr, args->offset, ++ args->size, DMA_TO_DEVICE); ++ } ++ if (args->flags & RKNPU_MEM_SYNC_FROM_DEVICE) { ++ dma_sync_single_range_for_cpu(dev->dev, ++ rknpu_obj->dma_addr, ++ args->offset, args->size, ++ DMA_FROM_DEVICE); ++ } ++ } else { ++ WARN_ON(!rknpu_dev->fake_dev); ++ ++ length = args->size; ++ offset = args->offset; ++ ++ if (IS_ENABLED(CONFIG_NO_GKI) && ++ IS_ENABLED(CONFIG_ROCKCHIP_RKNPU_SRAM) && ++ rknpu_obj->sram_size > 0) { ++ rknpu_cache_sync(rknpu_obj, &length, &offset, ++ RKNPU_CACHE_SRAM); ++ } else if (IS_ENABLED(CONFIG_NO_GKI) && ++ rknpu_obj->nbuf_size > 0) { ++ rknpu_cache_sync(rknpu_obj, &length, &offset, ++ RKNPU_CACHE_NBUF); ++ } ++ ++ for_each_sg(rknpu_obj->sgt->sgl, sg, rknpu_obj->sgt->nents, ++ i) { ++ if (length == 0) ++ break; ++ ++ len += sg->length; ++ if (len <= offset) ++ continue; ++ ++ sg_phys_addr = sg_phys(sg); ++ ++ sg_left = len - offset; ++ sg_offset = sg->length - sg_left; ++ ++ size = (length < sg_left) ? length : sg_left; ++ ++ if (args->flags & RKNPU_MEM_SYNC_TO_DEVICE) { ++ dma_sync_single_range_for_device( ++ rknpu_dev->fake_dev, sg_phys_addr, ++ sg_offset, size, DMA_TO_DEVICE); ++ } ++ ++ if (args->flags & RKNPU_MEM_SYNC_FROM_DEVICE) { ++ dma_sync_single_range_for_cpu( ++ rknpu_dev->fake_dev, sg_phys_addr, ++ sg_offset, size, DMA_FROM_DEVICE); ++ } ++ ++ offset += size; ++ length -= size; ++ } ++ } ++ ++ return 0; ++} +diff --git a/drivers/rknpu/rknpu_iommu.c b/drivers/rknpu/rknpu_iommu.c +new file mode 100644 +index 000000000..01620d9c3 +--- /dev/null ++++ b/drivers/rknpu/rknpu_iommu.c +@@ -0,0 +1,61 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) Rockchip Electronics Co.Ltd ++ * Author: Felix Zeng ++ */ ++ ++#include "rknpu_iommu.h" ++ ++dma_addr_t rknpu_iommu_dma_alloc_iova(struct iommu_domain *domain, size_t size, ++ u64 dma_limit, struct device *dev) ++{ ++ struct rknpu_iommu_dma_cookie *cookie = (void *)domain->iova_cookie; ++ struct iova_domain *iovad = &cookie->iovad; ++ unsigned long shift, iova_len, iova = 0; ++#if (KERNEL_VERSION(5, 4, 0) > LINUX_VERSION_CODE) ++ dma_addr_t limit; ++#endif ++ ++ shift = iova_shift(iovad); ++ iova_len = size >> shift; ++ ++#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE ++ /* ++ * Freeing non-power-of-two-sized allocations back into the IOVA caches ++ * will come back to bite us badly, so we have to waste a bit of space ++ * rounding up anything cacheable to make sure that can't happen. The ++ * order of the unadjusted size will still match upon freeing. ++ */ ++ if (iova_len < (1 << (IOVA_RANGE_CACHE_MAX_SIZE - 1))) ++ iova_len = roundup_pow_of_two(iova_len); ++#endif ++ ++#if (KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE) ++ dma_limit = min_not_zero(dma_limit, dev->bus_dma_limit); ++#else ++ if (dev->bus_dma_mask) ++ dma_limit &= dev->bus_dma_mask; ++#endif ++ ++ if (domain->geometry.force_aperture) ++ dma_limit = ++ min_t(u64, dma_limit, domain->geometry.aperture_end); ++ ++#if (KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE) ++ iova = alloc_iova_fast(iovad, iova_len, dma_limit >> shift, true); ++#else ++ limit = min_t(dma_addr_t, dma_limit >> shift, iovad->end_pfn); ++ ++ iova = alloc_iova_fast(iovad, iova_len, limit, true); ++#endif ++ ++ return (dma_addr_t)iova << shift; ++} ++ ++void rknpu_iommu_dma_free_iova(struct rknpu_iommu_dma_cookie *cookie, ++ dma_addr_t iova, size_t size) ++{ ++ struct iova_domain *iovad = &cookie->iovad; ++ ++ free_iova_fast(iovad, iova_pfn(iovad, iova), size >> iova_shift(iovad)); ++} +diff --git a/drivers/rknpu/rknpu_job.c b/drivers/rknpu/rknpu_job.c +new file mode 100644 +index 000000000..f0f1dd79c +--- /dev/null ++++ b/drivers/rknpu/rknpu_job.c +@@ -0,0 +1,1010 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) Rockchip Electronics Co.Ltd ++ * Author: Felix Zeng ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "rknpu_ioctl.h" ++#include "rknpu_drv.h" ++#include "rknpu_reset.h" ++#include "rknpu_gem.h" ++#include "rknpu_fence.h" ++#include "rknpu_job.h" ++#include "rknpu_mem.h" ++ ++#define _REG_READ(base, offset) readl(base + (offset)) ++#define _REG_WRITE(base, value, offset) writel(value, base + (offset)) ++ ++#define REG_READ(offset) _REG_READ(rknpu_core_base, offset) ++#define REG_WRITE(value, offset) _REG_WRITE(rknpu_core_base, value, offset) ++ ++static int rknpu_wait_core_index(int core_mask) ++{ ++ int index = 0; ++ ++ switch (core_mask & ((1 << RKNPU_MAX_CORES) - 1)) { ++ case RKNPU_CORE0_MASK: ++ case RKNPU_CORE0_MASK | RKNPU_CORE1_MASK: ++ case RKNPU_CORE0_MASK | RKNPU_CORE1_MASK | RKNPU_CORE2_MASK: ++ index = 0; ++ break; ++ case RKNPU_CORE1_MASK: ++ index = 1; ++ break; ++ case RKNPU_CORE2_MASK: ++ index = 2; ++ break; ++ default: ++ break; ++ } ++ ++ return index; ++} ++ ++static int rknpu_core_mask(int core_index) ++{ ++ int core_mask = RKNPU_CORE_AUTO_MASK; ++ ++ switch (core_index) { ++ case 0: ++ core_mask = RKNPU_CORE0_MASK; ++ break; ++ case 1: ++ core_mask = RKNPU_CORE1_MASK; ++ break; ++ case 2: ++ core_mask = RKNPU_CORE2_MASK; ++ break; ++ default: ++ break; ++ } ++ ++ return core_mask; ++} ++ ++static int rknpu_get_task_number(struct rknpu_job *job, int core_index) ++{ ++ struct rknpu_device *rknpu_dev = job->rknpu_dev; ++ int task_num = job->args->task_number; ++ ++ if (core_index >= RKNPU_MAX_CORES || core_index < 0) { ++ LOG_ERROR("core_index: %d set error!", core_index); ++ return 0; ++ } ++ ++ if (rknpu_dev->config->num_irqs > 1) { ++ if (job->use_core_num == 1 || job->use_core_num == 2) ++ task_num = ++ job->args->subcore_task[core_index].task_number; ++ else if (job->use_core_num == 3) ++ task_num = job->args->subcore_task[core_index + 2] ++ .task_number; ++ } ++ ++ return task_num; ++} ++ ++static void rknpu_job_free(struct rknpu_job *job) ++{ ++#ifdef CONFIG_ROCKCHIP_RKNPU_DRM_GEM ++ struct rknpu_gem_object *task_obj = NULL; ++ ++ task_obj = ++ (struct rknpu_gem_object *)(uintptr_t)job->args->task_obj_addr; ++ if (task_obj) ++ rknpu_gem_object_put(&task_obj->base); ++#endif ++ ++ if (job->fence) ++ dma_fence_put(job->fence); ++ ++ if (job->args_owner) ++ kfree(job->args); ++ ++ kfree(job); ++} ++ ++static int rknpu_job_cleanup(struct rknpu_job *job) ++{ ++ rknpu_job_free(job); ++ ++ return 0; ++} ++ ++static void rknpu_job_cleanup_work(struct work_struct *work) ++{ ++ struct rknpu_job *job = ++ container_of(work, struct rknpu_job, cleanup_work); ++ ++ rknpu_job_cleanup(job); ++} ++ ++static inline struct rknpu_job *rknpu_job_alloc(struct rknpu_device *rknpu_dev, ++ struct rknpu_submit *args) ++{ ++ struct rknpu_job *job = NULL; ++#ifdef CONFIG_ROCKCHIP_RKNPU_DRM_GEM ++ struct rknpu_gem_object *task_obj = NULL; ++#endif ++ if (rknpu_dev->config->num_irqs == 1) ++ args->core_mask = RKNPU_CORE0_MASK; ++ ++ job = kzalloc(sizeof(*job), GFP_KERNEL); ++ if (!job) ++ return NULL; ++ ++ job->timestamp = ktime_get(); ++ job->rknpu_dev = rknpu_dev; ++ job->use_core_num = (args->core_mask & RKNPU_CORE0_MASK) + ++ ((args->core_mask & RKNPU_CORE1_MASK) >> 1) + ++ ((args->core_mask & RKNPU_CORE2_MASK) >> 2); ++ atomic_set(&job->run_count, job->use_core_num); ++ atomic_set(&job->interrupt_count, job->use_core_num); ++#ifdef CONFIG_ROCKCHIP_RKNPU_DRM_GEM ++ task_obj = (struct rknpu_gem_object *)(uintptr_t)args->task_obj_addr; ++ if (task_obj) ++ rknpu_gem_object_get(&task_obj->base); ++#endif ++ ++ if (!(args->flags & RKNPU_JOB_NONBLOCK)) { ++ job->args = args; ++ job->args_owner = false; ++ return job; ++ } ++ ++ job->args = kzalloc(sizeof(*args), GFP_KERNEL); ++ if (!job->args) { ++ kfree(job); ++ return NULL; ++ } ++ *job->args = *args; ++ job->args_owner = true; ++ ++ INIT_WORK(&job->cleanup_work, rknpu_job_cleanup_work); ++ ++ return job; ++} ++ ++static inline int rknpu_job_wait(struct rknpu_job *job) ++{ ++ struct rknpu_device *rknpu_dev = job->rknpu_dev; ++ struct rknpu_submit *args = job->args; ++ struct rknpu_task *last_task = NULL; ++ struct rknpu_subcore_data *subcore_data = NULL; ++ struct rknpu_job *entry, *q; ++ void __iomem *rknpu_core_base = NULL; ++ int core_index = rknpu_wait_core_index(job->args->core_mask); ++ unsigned long flags; ++ int wait_count = 0; ++ bool continue_wait = false; ++ int ret = -EINVAL; ++ int i = 0; ++ ++ subcore_data = &rknpu_dev->subcore_datas[core_index]; ++ ++ do { ++ ret = wait_event_timeout(subcore_data->job_done_wq, ++ job->flags & RKNPU_JOB_DONE || ++ rknpu_dev->soft_reseting, ++ msecs_to_jiffies(args->timeout)); ++ ++ if (++wait_count >= 3) ++ break; ++ ++ if (ret == 0) { ++ int64_t commit_time = 0; ++ spin_lock_irqsave(&rknpu_dev->irq_lock, flags); ++ commit_time = ktime_us_delta(ktime_get(), ++ job->commit_pc_time); ++ continue_wait = ++ job->commit_pc_time == 0 ? ++ true : ++ (commit_time < args->timeout * 1000); ++ spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags); ++ LOG_ERROR( ++ "job: %p, wait_count: %d, continue_wait: %d, commit time: %lldus, wait time: %lldus, timeout time: %uus\n", ++ job, wait_count, continue_wait, ++ (job->commit_pc_time == 0 ? 0 : commit_time), ++ ktime_us_delta(ktime_get(), job->timestamp), ++ args->timeout * 1000); ++ } ++ } while (ret == 0 && continue_wait); ++ ++ last_task = job->last_task; ++ if (!last_task) { ++ spin_lock_irqsave(&rknpu_dev->lock, flags); ++ for (i = 0; i < job->use_core_num; i++) { ++ subcore_data = &rknpu_dev->subcore_datas[i]; ++ list_for_each_entry_safe( ++ entry, q, &subcore_data->todo_list, head[i]) { ++ if (entry == job) { ++ list_del(&job->head[i]); ++ break; ++ } ++ } ++ } ++ spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags); ++ ++ LOG_ERROR("job commit failed\n"); ++ return ret < 0 ? ret : -EINVAL; ++ } ++ ++ last_task->int_status = job->int_status[core_index]; ++ ++ if (ret <= 0) { ++ args->task_counter = 0; ++ rknpu_core_base = rknpu_dev->base[core_index]; ++ if (args->flags & RKNPU_JOB_PC) { ++ uint32_t task_status = REG_READ( ++ rknpu_dev->config->pc_task_status_offset); ++ args->task_counter = ++ (task_status & ++ rknpu_dev->config->pc_task_number_mask); ++ } ++ ++ LOG_ERROR( ++ "failed to wait job, task counter: %d, flags: %#x, ret = %d, elapsed time: %lldus\n", ++ args->task_counter, args->flags, ret, ++ ktime_us_delta(ktime_get(), job->timestamp)); ++ ++ return ret < 0 ? ret : -ETIMEDOUT; ++ } ++ ++ if (!(job->flags & RKNPU_JOB_DONE)) ++ return -EINVAL; ++ ++ args->task_counter = args->task_number; ++ ++ return 0; ++} ++ ++static inline int rknpu_job_subcore_commit_pc(struct rknpu_job *job, ++ int core_index) ++{ ++ struct rknpu_device *rknpu_dev = job->rknpu_dev; ++ struct rknpu_submit *args = job->args; ++#ifdef CONFIG_ROCKCHIP_RKNPU_DRM_GEM ++ struct rknpu_gem_object *task_obj = ++ (struct rknpu_gem_object *)(uintptr_t)args->task_obj_addr; ++#endif ++#ifdef CONFIG_ROCKCHIP_RKNPU_DMA_HEAP ++ struct rknpu_mem_object *task_obj = ++ (struct rknpu_mem_object *)(uintptr_t)args->task_obj_addr; ++#endif ++ struct rknpu_task *task_base = NULL; ++ struct rknpu_task *first_task = NULL; ++ struct rknpu_task *last_task = NULL; ++ void __iomem *rknpu_core_base = rknpu_dev->base[core_index]; ++ int task_start = args->task_start; ++ int task_end; ++ int task_number = args->task_number; ++ int task_pp_en = args->flags & RKNPU_JOB_PINGPONG ? 1 : 0; ++ int pc_data_amount_scale = rknpu_dev->config->pc_data_amount_scale; ++ int pc_task_number_bits = rknpu_dev->config->pc_task_number_bits; ++ int i = 0; ++ int submit_index = atomic_read(&job->submit_count[core_index]); ++ int max_submit_number = rknpu_dev->config->max_submit_number; ++ ++ if (!task_obj) { ++ job->ret = -EINVAL; ++ return job->ret; ++ } ++ ++ if (rknpu_dev->config->num_irqs > 1) { ++ for (i = 0; i < rknpu_dev->config->num_irqs; i++) { ++ if (i == core_index) { ++ REG_WRITE((0xe + 0x10000000 * i), 0x1004); ++ REG_WRITE((0xe + 0x10000000 * i), 0x3004); ++ } ++ } ++ ++ switch (job->use_core_num) { ++ case 1: ++ case 2: ++ task_start = args->subcore_task[core_index].task_start; ++ task_number = ++ args->subcore_task[core_index].task_number; ++ break; ++ case 3: ++ task_start = ++ args->subcore_task[core_index + 2].task_start; ++ task_number = ++ args->subcore_task[core_index + 2].task_number; ++ break; ++ default: ++ LOG_ERROR("Unknown use core num %d\n", ++ job->use_core_num); ++ break; ++ } ++ } ++ ++ task_start = task_start + submit_index * max_submit_number; ++ task_number = task_number - submit_index * max_submit_number; ++ task_number = task_number > max_submit_number ? max_submit_number : ++ task_number; ++ task_end = task_start + task_number - 1; ++ ++ task_base = task_obj->kv_addr; ++ ++ first_task = &task_base[task_start]; ++ last_task = &task_base[task_end]; ++ ++ spin_lock(&rknpu_dev->lock); ++ REG_WRITE(first_task->regcmd_addr, RKNPU_OFFSET_PC_DATA_ADDR); ++ spin_unlock(&rknpu_dev->lock); ++ ++ REG_WRITE((first_task->regcfg_amount + RKNPU_PC_DATA_EXTRA_AMOUNT + ++ pc_data_amount_scale - 1) / ++ pc_data_amount_scale - ++ 1, ++ RKNPU_OFFSET_PC_DATA_AMOUNT); ++ ++ REG_WRITE(last_task->int_mask, RKNPU_OFFSET_INT_MASK); ++ ++ REG_WRITE(first_task->int_mask, RKNPU_OFFSET_INT_CLEAR); ++ ++ REG_WRITE(((0x6 | task_pp_en) << pc_task_number_bits) | task_number, ++ RKNPU_OFFSET_PC_TASK_CONTROL); ++ ++ REG_WRITE(args->task_base_addr, RKNPU_OFFSET_PC_DMA_BASE_ADDR); ++ ++ job->first_task = first_task; ++ job->last_task = last_task; ++ job->int_mask[core_index] = last_task->int_mask; ++ ++ REG_WRITE(0x1, RKNPU_OFFSET_PC_OP_EN); ++ REG_WRITE(0x0, RKNPU_OFFSET_PC_OP_EN); ++ ++ return 0; ++} ++ ++static inline int rknpu_job_subcore_commit(struct rknpu_job *job, int core_index) ++{ ++ struct rknpu_device *rknpu_dev = job->rknpu_dev; ++ struct rknpu_submit *args = job->args; ++ void __iomem *rknpu_core_base = rknpu_dev->base[core_index]; ++ ++ // switch to slave mode ++ spin_lock(&rknpu_dev->lock); ++ REG_WRITE(0x1, RKNPU_OFFSET_PC_DATA_ADDR); ++ spin_unlock(&rknpu_dev->lock); ++ ++ if (!(args->flags & RKNPU_JOB_PC)) { ++ job->ret = -EINVAL; ++ return job->ret; ++ } ++ ++ return rknpu_job_subcore_commit_pc(job, core_index); ++} ++ ++static void rknpu_job_commit(struct rknpu_job *job) ++{ ++ switch (job->args->core_mask & ((1 << RKNPU_MAX_CORES) - 1)) { ++ case RKNPU_CORE0_MASK: ++ rknpu_job_subcore_commit(job, 0); ++ break; ++ case RKNPU_CORE1_MASK: ++ rknpu_job_subcore_commit(job, 1); ++ break; ++ case RKNPU_CORE2_MASK: ++ rknpu_job_subcore_commit(job, 2); ++ break; ++ case RKNPU_CORE0_MASK | RKNPU_CORE1_MASK: ++ rknpu_job_subcore_commit(job, 0); ++ rknpu_job_subcore_commit(job, 1); ++ break; ++ case RKNPU_CORE0_MASK | RKNPU_CORE1_MASK | RKNPU_CORE2_MASK: ++ rknpu_job_subcore_commit(job, 0); ++ rknpu_job_subcore_commit(job, 1); ++ rknpu_job_subcore_commit(job, 2); ++ break; ++ default: ++ LOG_ERROR("Unknown core mask: %d\n", job->args->core_mask); ++ break; ++ } ++} ++ ++static void rknpu_job_next(struct rknpu_device *rknpu_dev, int core_index) ++{ ++ struct rknpu_job *job = NULL; ++ struct rknpu_subcore_data *subcore_data = NULL; ++ unsigned long flags; ++ ++ if (rknpu_dev->soft_reseting) ++ return; ++ ++ subcore_data = &rknpu_dev->subcore_datas[core_index]; ++ ++ spin_lock_irqsave(&rknpu_dev->irq_lock, flags); ++ ++ if (subcore_data->job || list_empty(&subcore_data->todo_list)) { ++ spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags); ++ return; ++ } ++ ++ job = list_first_entry(&subcore_data->todo_list, struct rknpu_job, ++ head[core_index]); ++ ++ list_del_init(&job->head[core_index]); ++ subcore_data->job = job; ++ job->hw_recoder_time = ktime_get(); ++ job->commit_pc_time = job->hw_recoder_time; ++ spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags); ++ ++ if (atomic_dec_and_test(&job->run_count)) { ++ rknpu_job_commit(job); ++ } ++} ++ ++static void rknpu_job_done(struct rknpu_job *job, int ret, int core_index) ++{ ++ struct rknpu_device *rknpu_dev = job->rknpu_dev; ++ struct rknpu_subcore_data *subcore_data = NULL; ++ unsigned long flags; ++ int max_submit_number = rknpu_dev->config->max_submit_number; ++ ++ if (atomic_inc_return(&job->submit_count[core_index]) < ++ (rknpu_get_task_number(job, core_index) + max_submit_number - 1) / ++ max_submit_number) { ++ rknpu_job_commit(job); ++ return; ++ } ++ ++ subcore_data = &rknpu_dev->subcore_datas[core_index]; ++ ++ spin_lock_irqsave(&rknpu_dev->irq_lock, flags); ++ subcore_data->job = NULL; ++ subcore_data->task_num -= rknpu_get_task_number(job, core_index); ++ subcore_data->timer.busy_time += ++ ktime_us_delta(ktime_get(), job->hw_recoder_time); ++ spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags); ++ ++ if (atomic_dec_and_test(&job->interrupt_count)) { ++ int use_core_num = job->use_core_num; ++ ++ job->flags |= RKNPU_JOB_DONE; ++ job->ret = ret; ++ ++ if (job->fence) ++ dma_fence_signal(job->fence); ++ ++ if (job->flags & RKNPU_JOB_ASYNC) ++ schedule_work(&job->cleanup_work); ++ ++ if (use_core_num > 1) ++ wake_up(&(&rknpu_dev->subcore_datas[0])->job_done_wq); ++ else ++ wake_up(&subcore_data->job_done_wq); ++ } ++ ++ rknpu_job_next(rknpu_dev, core_index); ++} ++ ++static void rknpu_job_schedule(struct rknpu_job *job) ++{ ++ struct rknpu_device *rknpu_dev = job->rknpu_dev; ++ struct rknpu_subcore_data *subcore_data = NULL; ++ int i = 0, core_index = 0; ++ unsigned long flags; ++ int task_num_list[3] = { 0, 1, 2 }; ++ int tmp = 0; ++ ++ if ((job->args->core_mask & ((1 << RKNPU_MAX_CORES) - 1)) == ++ RKNPU_CORE_AUTO_MASK) { ++ if (rknpu_dev->subcore_datas[0].task_num > ++ rknpu_dev->subcore_datas[1].task_num) { ++ tmp = task_num_list[1]; ++ task_num_list[1] = task_num_list[0]; ++ task_num_list[0] = tmp; ++ } ++ if (rknpu_dev->subcore_datas[task_num_list[0]].task_num > ++ rknpu_dev->subcore_datas[2].task_num) { ++ tmp = task_num_list[2]; ++ task_num_list[2] = task_num_list[1]; ++ task_num_list[1] = task_num_list[0]; ++ task_num_list[0] = tmp; ++ } else if (rknpu_dev->subcore_datas[task_num_list[1]].task_num > ++ rknpu_dev->subcore_datas[2].task_num) { ++ tmp = task_num_list[2]; ++ task_num_list[2] = task_num_list[1]; ++ task_num_list[1] = tmp; ++ } ++ if (!rknpu_dev->subcore_datas[task_num_list[0]].job) ++ core_index = task_num_list[0]; ++ else if (!rknpu_dev->subcore_datas[task_num_list[1]].job) ++ core_index = task_num_list[1]; ++ else if (!rknpu_dev->subcore_datas[task_num_list[2]].job) ++ core_index = task_num_list[2]; ++ else ++ core_index = task_num_list[0]; ++ ++ job->args->core_mask = rknpu_core_mask(core_index); ++ job->use_core_num = 1; ++ atomic_set(&job->run_count, job->use_core_num); ++ atomic_set(&job->interrupt_count, job->use_core_num); ++ } ++ ++ spin_lock_irqsave(&rknpu_dev->irq_lock, flags); ++ for (i = 0; i < rknpu_dev->config->num_irqs; i++) { ++ if (job->args->core_mask & rknpu_core_mask(i)) { ++ subcore_data = &rknpu_dev->subcore_datas[i]; ++ list_add_tail(&job->head[i], &subcore_data->todo_list); ++ subcore_data->task_num += rknpu_get_task_number(job, i); ++ } ++ } ++ spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags); ++ ++ for (i = 0; i < rknpu_dev->config->num_irqs; i++) { ++ if (job->args->core_mask & rknpu_core_mask(i)) ++ rknpu_job_next(rknpu_dev, i); ++ } ++} ++ ++static void rknpu_job_abort(struct rknpu_job *job) ++{ ++ struct rknpu_device *rknpu_dev = job->rknpu_dev; ++ struct rknpu_subcore_data *subcore_data = NULL; ++ unsigned long flags; ++ int i = 0; ++ ++ msleep(100); ++ ++ spin_lock_irqsave(&rknpu_dev->irq_lock, flags); ++ for (i = 0; i < rknpu_dev->config->num_irqs; i++) { ++ if (job->args->core_mask & rknpu_core_mask(i)) { ++ subcore_data = &rknpu_dev->subcore_datas[i]; ++ if (job == subcore_data->job && !job->irq_entry[i]) { ++ subcore_data->job = NULL; ++ subcore_data->task_num -= ++ rknpu_get_task_number(job, i); ++ } ++ } ++ } ++ spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags); ++ ++ if (job->ret == -ETIMEDOUT) { ++ LOG_ERROR("job timeout, flags: %#x:\n", job->flags); ++ for (i = 0; i < rknpu_dev->config->num_irqs; i++) { ++ if (job->args->core_mask & rknpu_core_mask(i)) { ++ void __iomem *rknpu_core_base = ++ rknpu_dev->base[i]; ++ LOG_ERROR( ++ "\tcore %d irq status: %#x, raw status: %#x, require mask: %#x, task counter: %#x, elapsed time: %lldus\n", ++ i, REG_READ(RKNPU_OFFSET_INT_STATUS), ++ REG_READ(RKNPU_OFFSET_INT_RAW_STATUS), ++ job->int_mask[i], ++ (REG_READ( ++ rknpu_dev->config ++ ->pc_task_status_offset) & ++ rknpu_dev->config->pc_task_number_mask), ++ ktime_us_delta(ktime_get(), ++ job->timestamp)); ++ } ++ } ++ rknpu_soft_reset(rknpu_dev); ++ } else { ++ LOG_ERROR( ++ "job abort, flags: %#x, ret: %d, elapsed time: %lldus\n", ++ job->flags, job->ret, ++ ktime_us_delta(ktime_get(), job->timestamp)); ++ } ++ ++ rknpu_job_cleanup(job); ++} ++ ++static inline uint32_t rknpu_fuzz_status(uint32_t status) ++{ ++ uint32_t fuzz_status = 0; ++ ++ if ((status & 0x3) != 0) ++ fuzz_status |= 0x3; ++ ++ if ((status & 0xc) != 0) ++ fuzz_status |= 0xc; ++ ++ if ((status & 0x30) != 0) ++ fuzz_status |= 0x30; ++ ++ if ((status & 0xc0) != 0) ++ fuzz_status |= 0xc0; ++ ++ if ((status & 0x300) != 0) ++ fuzz_status |= 0x300; ++ ++ if ((status & 0xc00) != 0) ++ fuzz_status |= 0xc00; ++ ++ return fuzz_status; ++} ++ ++static inline irqreturn_t rknpu_irq_handler(int irq, void *data, int core_index) ++{ ++ struct rknpu_device *rknpu_dev = data; ++ void __iomem *rknpu_core_base = rknpu_dev->base[core_index]; ++ struct rknpu_subcore_data *subcore_data = NULL; ++ struct rknpu_job *job = NULL; ++ uint32_t status = 0; ++ unsigned long flags; ++ ++ subcore_data = &rknpu_dev->subcore_datas[core_index]; ++ ++ spin_lock_irqsave(&rknpu_dev->irq_lock, flags); ++ job = subcore_data->job; ++ if (!job) { ++ spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags); ++ REG_WRITE(RKNPU_INT_CLEAR, RKNPU_OFFSET_INT_CLEAR); ++ rknpu_job_next(rknpu_dev, core_index); ++ return IRQ_HANDLED; ++ } ++ job->irq_entry[core_index] = true; ++ spin_unlock_irqrestore(&rknpu_dev->irq_lock, flags); ++ ++ status = REG_READ(RKNPU_OFFSET_INT_STATUS); ++ ++ job->int_status[core_index] = status; ++ ++ if (rknpu_fuzz_status(status) != job->int_mask[core_index]) { ++ LOG_ERROR( ++ "invalid irq status: %#x, raw status: %#x, require mask: %#x, task counter: %#x\n", ++ status, REG_READ(RKNPU_OFFSET_INT_RAW_STATUS), ++ job->int_mask[core_index], ++ (REG_READ(rknpu_dev->config->pc_task_status_offset) & ++ rknpu_dev->config->pc_task_number_mask)); ++ REG_WRITE(RKNPU_INT_CLEAR, RKNPU_OFFSET_INT_CLEAR); ++ return IRQ_HANDLED; ++ } ++ ++ REG_WRITE(RKNPU_INT_CLEAR, RKNPU_OFFSET_INT_CLEAR); ++ ++ rknpu_job_done(job, 0, core_index); ++ ++ return IRQ_HANDLED; ++} ++ ++irqreturn_t rknpu_core0_irq_handler(int irq, void *data) ++{ ++ return rknpu_irq_handler(irq, data, 0); ++} ++ ++irqreturn_t rknpu_core1_irq_handler(int irq, void *data) ++{ ++ return rknpu_irq_handler(irq, data, 1); ++} ++ ++irqreturn_t rknpu_core2_irq_handler(int irq, void *data) ++{ ++ return rknpu_irq_handler(irq, data, 2); ++} ++ ++static void rknpu_job_timeout_clean(struct rknpu_device *rknpu_dev, ++ int core_mask) ++{ ++ struct rknpu_job *job = NULL; ++ unsigned long flags; ++ struct rknpu_subcore_data *subcore_data = NULL; ++ int i = 0; ++ ++ for (i = 0; i < rknpu_dev->config->num_irqs; i++) { ++ if (core_mask & rknpu_core_mask(i)) { ++ subcore_data = &rknpu_dev->subcore_datas[i]; ++ job = subcore_data->job; ++ if (job && ++ ktime_us_delta(ktime_get(), job->timestamp) >= ++ job->args->timeout) { ++ rknpu_soft_reset(rknpu_dev); ++ ++ spin_lock_irqsave(&rknpu_dev->irq_lock, flags); ++ subcore_data->job = NULL; ++ spin_unlock_irqrestore(&rknpu_dev->irq_lock, ++ flags); ++ ++ do { ++ schedule_work(&job->cleanup_work); ++ ++ spin_lock_irqsave(&rknpu_dev->irq_lock, ++ flags); ++ ++ if (!list_empty( ++ &subcore_data->todo_list)) { ++ job = list_first_entry( ++ &subcore_data->todo_list, ++ struct rknpu_job, ++ head[i]); ++ list_del_init(&job->head[i]); ++ } else { ++ job = NULL; ++ } ++ ++ spin_unlock_irqrestore( ++ &rknpu_dev->irq_lock, flags); ++ } while (job); ++ } ++ } ++ } ++} ++ ++static int rknpu_submit(struct rknpu_device *rknpu_dev, ++ struct rknpu_submit *args) ++{ ++ struct rknpu_job *job = NULL; ++ int ret = -EINVAL; ++ ++ if (args->task_number == 0) { ++ LOG_ERROR("invalid rknpu task number!\n"); ++ return -EINVAL; ++ } ++ ++ job = rknpu_job_alloc(rknpu_dev, args); ++ if (!job) { ++ LOG_ERROR("failed to allocate rknpu job!\n"); ++ return -ENOMEM; ++ } ++ ++ if (args->flags & RKNPU_JOB_FENCE_IN) { ++#ifdef CONFIG_ROCKCHIP_RKNPU_FENCE ++ struct dma_fence *in_fence; ++ ++ in_fence = sync_file_get_fence(args->fence_fd); ++ ++ if (!in_fence) { ++ LOG_ERROR("invalid fence in fd, fd: %d\n", ++ args->fence_fd); ++ return -EINVAL; ++ } ++ args->fence_fd = -1; ++ ++ /* ++ * Wait if the fence is from a foreign context, or if the fence ++ * array contains any fence from a foreign context. ++ */ ++ ret = 0; ++ if (!dma_fence_match_context(in_fence, ++ rknpu_dev->fence_ctx->context)) ++ ret = dma_fence_wait_timeout(in_fence, true, ++ args->timeout); ++ dma_fence_put(in_fence); ++ if (ret < 0) { ++ if (ret != -ERESTARTSYS) ++ LOG_ERROR("Error (%d) waiting for fence!\n", ++ ret); ++ ++ return ret; ++ } ++#else ++ LOG_ERROR( ++ "failed to use rknpu fence, please enable rknpu fence config!\n"); ++ rknpu_job_free(job); ++ return -EINVAL; ++#endif ++ } ++ ++ if (args->flags & RKNPU_JOB_FENCE_OUT) { ++#ifdef CONFIG_ROCKCHIP_RKNPU_FENCE ++ ret = rknpu_fence_alloc(job); ++ if (ret) { ++ rknpu_job_free(job); ++ return ret; ++ } ++ job->args->fence_fd = rknpu_fence_get_fd(job); ++ args->fence_fd = job->args->fence_fd; ++#else ++ LOG_ERROR( ++ "failed to use rknpu fence, please enable rknpu fence config!\n"); ++ rknpu_job_free(job); ++ return -EINVAL; ++#endif ++ } ++ ++ if (args->flags & RKNPU_JOB_NONBLOCK) { ++ job->flags |= RKNPU_JOB_ASYNC; ++ rknpu_job_timeout_clean(rknpu_dev, job->args->core_mask); ++ rknpu_job_schedule(job); ++ ret = job->ret; ++ if (ret) { ++ rknpu_job_abort(job); ++ return ret; ++ } ++ } else { ++ rknpu_job_schedule(job); ++ if (args->flags & RKNPU_JOB_PC) ++ job->ret = rknpu_job_wait(job); ++ ++ args->task_counter = job->args->task_counter; ++ ret = job->ret; ++ if (!ret) ++ rknpu_job_cleanup(job); ++ else ++ rknpu_job_abort(job); ++ } ++ ++ return ret; ++} ++ ++#ifdef CONFIG_ROCKCHIP_RKNPU_DRM_GEM ++int rknpu_submit_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct rknpu_device *rknpu_dev = dev_get_drvdata(dev->dev); ++ struct rknpu_submit *args = data; ++ ++ return rknpu_submit(rknpu_dev, args); ++} ++#endif ++ ++#ifdef CONFIG_ROCKCHIP_RKNPU_DMA_HEAP ++int rknpu_submit_ioctl(struct rknpu_device *rknpu_dev, unsigned long data) ++{ ++ struct rknpu_submit args; ++ int ret = -EINVAL; ++ ++ if (unlikely(copy_from_user(&args, (struct rknpu_submit *)data, ++ sizeof(struct rknpu_submit)))) { ++ LOG_ERROR("%s: copy_from_user failed\n", __func__); ++ ret = -EFAULT; ++ return ret; ++ } ++ ++ ret = rknpu_submit(rknpu_dev, &args); ++ ++ if (unlikely(copy_to_user((struct rknpu_submit *)data, &args, ++ sizeof(struct rknpu_submit)))) { ++ LOG_ERROR("%s: copy_to_user failed\n", __func__); ++ ret = -EFAULT; ++ return ret; ++ } ++ ++ return ret; ++} ++#endif ++ ++int rknpu_get_hw_version(struct rknpu_device *rknpu_dev, uint32_t *version) ++{ ++ void __iomem *rknpu_core_base = rknpu_dev->base[0]; ++ ++ if (version == NULL) ++ return -EINVAL; ++ ++ *version = REG_READ(RKNPU_OFFSET_VERSION) + ++ (REG_READ(RKNPU_OFFSET_VERSION_NUM) & 0xffff); ++ ++ return 0; ++} ++ ++int rknpu_get_bw_priority(struct rknpu_device *rknpu_dev, uint32_t *priority, ++ uint32_t *expect, uint32_t *tw) ++{ ++ void __iomem *base = rknpu_dev->bw_priority_base; ++ ++ if (!rknpu_dev->config->bw_enable) { ++ LOG_WARN("Get bw_priority is not supported on this device!\n"); ++ return 0; ++ } ++ ++ if (!base) ++ return -EINVAL; ++ ++ spin_lock(&rknpu_dev->lock); ++ ++ if (priority != NULL) ++ *priority = _REG_READ(base, 0x0); ++ ++ if (expect != NULL) ++ *expect = _REG_READ(base, 0x8); ++ ++ if (tw != NULL) ++ *tw = _REG_READ(base, 0xc); ++ ++ spin_unlock(&rknpu_dev->lock); ++ ++ return 0; ++} ++ ++int rknpu_set_bw_priority(struct rknpu_device *rknpu_dev, uint32_t priority, ++ uint32_t expect, uint32_t tw) ++{ ++ void __iomem *base = rknpu_dev->bw_priority_base; ++ ++ if (!rknpu_dev->config->bw_enable) { ++ LOG_WARN("Set bw_priority is not supported on this device!\n"); ++ return 0; ++ } ++ ++ if (!base) ++ return -EINVAL; ++ ++ spin_lock(&rknpu_dev->lock); ++ ++ if (priority != 0) ++ _REG_WRITE(base, priority, 0x0); ++ ++ if (expect != 0) ++ _REG_WRITE(base, expect, 0x8); ++ ++ if (tw != 0) ++ _REG_WRITE(base, tw, 0xc); ++ ++ spin_unlock(&rknpu_dev->lock); ++ ++ return 0; ++} ++ ++int rknpu_clear_rw_amount(struct rknpu_device *rknpu_dev) ++{ ++ void __iomem *rknpu_core_base = rknpu_dev->base[0]; ++ ++ if (!rknpu_dev->config->bw_enable) { ++ LOG_WARN("Clear rw_amount is not supported on this device!\n"); ++ return 0; ++ } ++ ++ spin_lock(&rknpu_dev->lock); ++ ++ if (rknpu_dev->config->pc_dma_ctrl) { ++ uint32_t pc_data_addr = REG_READ(RKNPU_OFFSET_PC_DATA_ADDR); ++ ++ REG_WRITE(0x1, RKNPU_OFFSET_PC_DATA_ADDR); ++ REG_WRITE(0x80000101, RKNPU_OFFSET_CLR_ALL_RW_AMOUNT); ++ REG_WRITE(0x00000101, RKNPU_OFFSET_CLR_ALL_RW_AMOUNT); ++ REG_WRITE(pc_data_addr, RKNPU_OFFSET_PC_DATA_ADDR); ++ } else { ++ REG_WRITE(0x80000101, RKNPU_OFFSET_CLR_ALL_RW_AMOUNT); ++ REG_WRITE(0x00000101, RKNPU_OFFSET_CLR_ALL_RW_AMOUNT); ++ } ++ ++ spin_unlock(&rknpu_dev->lock); ++ ++ return 0; ++} ++ ++int rknpu_get_rw_amount(struct rknpu_device *rknpu_dev, uint32_t *dt_wr, ++ uint32_t *dt_rd, uint32_t *wd_rd) ++{ ++ void __iomem *rknpu_core_base = rknpu_dev->base[0]; ++ int amount_scale = rknpu_dev->config->pc_data_amount_scale; ++ ++ if (!rknpu_dev->config->bw_enable) { ++ LOG_WARN("Get rw_amount is not supported on this device!\n"); ++ return 0; ++ } ++ ++ spin_lock(&rknpu_dev->lock); ++ ++ if (dt_wr != NULL) ++ *dt_wr = REG_READ(RKNPU_OFFSET_DT_WR_AMOUNT) * amount_scale; ++ ++ if (dt_rd != NULL) ++ *dt_rd = REG_READ(RKNPU_OFFSET_DT_RD_AMOUNT) * amount_scale; ++ ++ if (wd_rd != NULL) ++ *wd_rd = REG_READ(RKNPU_OFFSET_WT_RD_AMOUNT) * amount_scale; ++ ++ spin_unlock(&rknpu_dev->lock); ++ ++ return 0; ++} ++ ++int rknpu_get_total_rw_amount(struct rknpu_device *rknpu_dev, uint32_t *amount) ++{ ++ uint32_t dt_wr = 0; ++ uint32_t dt_rd = 0; ++ uint32_t wd_rd = 0; ++ int ret = -EINVAL; ++ ++ if (!rknpu_dev->config->bw_enable) { ++ LOG_WARN( ++ "Get total_rw_amount is not supported on this device!\n"); ++ return 0; ++ } ++ ++ ret = rknpu_get_rw_amount(rknpu_dev, &dt_wr, &dt_rd, &wd_rd); ++ ++ if (amount != NULL) ++ *amount = dt_wr + dt_rd + wd_rd; ++ ++ return ret; ++} +diff --git a/drivers/rknpu/rknpu_reset.c b/drivers/rknpu/rknpu_reset.c +new file mode 100644 +index 000000000..91c9b75d6 +--- /dev/null ++++ b/drivers/rknpu/rknpu_reset.c +@@ -0,0 +1,148 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) Rockchip Electronics Co.Ltd ++ * Author: Felix Zeng ++ */ ++ ++#include ++#include ++ ++#include "rknpu_reset.h" ++ ++#ifndef FPGA_PLATFORM ++static inline struct reset_control *rknpu_reset_control_get(struct device *dev, ++ const char *name) ++{ ++ struct reset_control *rst = NULL; ++ ++ rst = devm_reset_control_get(dev, name); ++ if (IS_ERR(rst)) ++ LOG_DEV_ERROR(dev, ++ "failed to get rknpu reset control: %s, %ld\n", ++ name, PTR_ERR(rst)); ++ ++ return rst; ++} ++#endif ++ ++int rknpu_reset_get(struct rknpu_device *rknpu_dev) ++{ ++#ifndef FPGA_PLATFORM ++ struct reset_control *srst_a = NULL; ++ struct reset_control *srst_h = NULL; ++ int i = 0; ++ ++ for (i = 0; i < rknpu_dev->config->num_resets; i++) { ++ srst_a = rknpu_reset_control_get( ++ rknpu_dev->dev, ++ rknpu_dev->config->resets[i].srst_a_name); ++ if (IS_ERR(srst_a)) ++ return PTR_ERR(srst_a); ++ ++ rknpu_dev->srst_a[i] = srst_a; ++ ++ srst_h = rknpu_reset_control_get( ++ rknpu_dev->dev, ++ rknpu_dev->config->resets[i].srst_h_name); ++ if (IS_ERR(srst_h)) ++ return PTR_ERR(srst_h); ++ ++ rknpu_dev->srst_h[i] = srst_h; ++ } ++#endif ++ ++ return 0; ++} ++ ++#ifndef FPGA_PLATFORM ++static int rknpu_reset_assert(struct reset_control *rst) ++{ ++ int ret = -EINVAL; ++ ++ if (!rst) ++ return -EINVAL; ++ ++ ret = reset_control_assert(rst); ++ if (ret < 0) { ++ LOG_ERROR("failed to assert rknpu reset: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int rknpu_reset_deassert(struct reset_control *rst) ++{ ++ int ret = -EINVAL; ++ ++ if (!rst) ++ return -EINVAL; ++ ++ ret = reset_control_deassert(rst); ++ if (ret < 0) { ++ LOG_ERROR("failed to deassert rknpu reset: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++#endif ++ ++int rknpu_soft_reset(struct rknpu_device *rknpu_dev) ++{ ++#ifndef FPGA_PLATFORM ++ struct iommu_domain *domain = NULL; ++ struct rknpu_subcore_data *subcore_data = NULL; ++ int ret = -EINVAL, i = 0; ++ ++ if (rknpu_dev->bypass_soft_reset) { ++ LOG_WARN("bypass soft reset\n"); ++ return 0; ++ } ++ ++ if (!mutex_trylock(&rknpu_dev->reset_lock)) ++ return 0; ++ ++ rknpu_dev->soft_reseting = true; ++ ++ msleep(100); ++ ++ for (i = 0; i < rknpu_dev->config->num_irqs; ++i) { ++ subcore_data = &rknpu_dev->subcore_datas[i]; ++ wake_up(&subcore_data->job_done_wq); ++ } ++ ++ LOG_INFO("soft reset\n"); ++ ++ for (i = 0; i < rknpu_dev->config->num_resets; i++) { ++ ret = rknpu_reset_assert(rknpu_dev->srst_a[i]); ++ ret |= rknpu_reset_assert(rknpu_dev->srst_h[i]); ++ ++ udelay(10); ++ ++ ret |= rknpu_reset_deassert(rknpu_dev->srst_a[i]); ++ ret |= rknpu_reset_deassert(rknpu_dev->srst_h[i]); ++ } ++ ++ if (ret) { ++ LOG_DEV_ERROR(rknpu_dev->dev, ++ "failed to soft reset for rknpu: %d\n", ret); ++ mutex_unlock(&rknpu_dev->reset_lock); ++ return ret; ++ } ++ ++ if (rknpu_dev->iommu_en) ++ domain = iommu_get_domain_for_dev(rknpu_dev->dev); ++ ++ if (domain) { ++ iommu_detach_device(domain, rknpu_dev->dev); ++ iommu_attach_device(domain, rknpu_dev->dev); ++ } ++ ++ rknpu_dev->soft_reseting = false; ++ ++ mutex_unlock(&rknpu_dev->reset_lock); ++#endif ++ ++ return 0; ++} +diff --git a/include/uapi/drm/rknpu_ioctl.h b/include/uapi/drm/rknpu_ioctl.h +new file mode 100644 +index 000000000..3b0b85710 +--- /dev/null ++++ b/include/uapi/drm/rknpu_ioctl.h +@@ -0,0 +1,324 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) Rockchip Electronics Co.Ltd ++ * Author: Felix Zeng ++ */ ++ ++#ifndef __LINUX_RKNPU_IOCTL_H ++#define __LINUX_RKNPU_IOCTL_H ++ ++#include ++#include ++ ++#if !defined(__KERNEL__) ++#define __user ++#endif ++ ++#ifndef __packed ++#define __packed __attribute__((packed)) ++#endif ++ ++#define RKNPU_OFFSET_VERSION 0x0 ++#define RKNPU_OFFSET_VERSION_NUM 0x4 ++#define RKNPU_OFFSET_PC_OP_EN 0x8 ++#define RKNPU_OFFSET_PC_DATA_ADDR 0x10 ++#define RKNPU_OFFSET_PC_DATA_AMOUNT 0x14 ++#define RKNPU_OFFSET_PC_TASK_CONTROL 0x30 ++#define RKNPU_OFFSET_PC_DMA_BASE_ADDR 0x34 ++ ++#define RKNPU_OFFSET_INT_MASK 0x20 ++#define RKNPU_OFFSET_INT_CLEAR 0x24 ++#define RKNPU_OFFSET_INT_STATUS 0x28 ++#define RKNPU_OFFSET_INT_RAW_STATUS 0x2c ++ ++#define RKNPU_OFFSET_CLR_ALL_RW_AMOUNT 0x8010 ++#define RKNPU_OFFSET_DT_WR_AMOUNT 0x8034 ++#define RKNPU_OFFSET_DT_RD_AMOUNT 0x8038 ++#define RKNPU_OFFSET_WT_RD_AMOUNT 0x803c ++ ++#define RKNPU_OFFSET_ENABLE_MASK 0xf008 ++ ++#define RKNPU_INT_CLEAR 0x1ffff ++ ++#define RKNPU_PC_DATA_EXTRA_AMOUNT 4 ++ ++#define RKNPU_STR_HELPER(x) #x ++ ++#define RKNPU_GET_DRV_VERSION_STRING(MAJOR, MINOR, PATCHLEVEL) \ ++ RKNPU_STR_HELPER(MAJOR) \ ++ "." RKNPU_STR_HELPER(MINOR) "." RKNPU_STR_HELPER(PATCHLEVEL) ++#define RKNPU_GET_DRV_VERSION_CODE(MAJOR, MINOR, PATCHLEVEL) \ ++ (MAJOR * 10000 + MINOR * 100 + PATCHLEVEL) ++#define RKNPU_GET_DRV_VERSION_MAJOR(CODE) (CODE / 10000) ++#define RKNPU_GET_DRV_VERSION_MINOR(CODE) ((CODE % 10000) / 100) ++#define RKNPU_GET_DRV_VERSION_PATCHLEVEL(CODE) (CODE % 100) ++ ++/* memory type definitions. */ ++enum e_rknpu_mem_type { ++ /* physically continuous memory and used as default. */ ++ RKNPU_MEM_CONTIGUOUS = 0 << 0, ++ /* physically non-continuous memory. */ ++ RKNPU_MEM_NON_CONTIGUOUS = 1 << 0, ++ /* non-cacheable mapping and used as default. */ ++ RKNPU_MEM_NON_CACHEABLE = 0 << 1, ++ /* cacheable mapping. */ ++ RKNPU_MEM_CACHEABLE = 1 << 1, ++ /* write-combine mapping. */ ++ RKNPU_MEM_WRITE_COMBINE = 1 << 2, ++ /* dma attr kernel mapping */ ++ RKNPU_MEM_KERNEL_MAPPING = 1 << 3, ++ /* iommu mapping */ ++ RKNPU_MEM_IOMMU = 1 << 4, ++ /* zero mapping */ ++ RKNPU_MEM_ZEROING = 1 << 5, ++ /* allocate secure buffer */ ++ RKNPU_MEM_SECURE = 1 << 6, ++ /* allocate from dma32 zone */ ++ RKNPU_MEM_DMA32 = 1 << 7, ++ /* request SRAM */ ++ RKNPU_MEM_TRY_ALLOC_SRAM = 1 << 8, ++ /* request NBUF */ ++ RKNPU_MEM_TRY_ALLOC_NBUF = 1 << 9, ++ RKNPU_MEM_MASK = RKNPU_MEM_NON_CONTIGUOUS | RKNPU_MEM_CACHEABLE | ++ RKNPU_MEM_WRITE_COMBINE | RKNPU_MEM_KERNEL_MAPPING | ++ RKNPU_MEM_IOMMU | RKNPU_MEM_ZEROING | ++ RKNPU_MEM_SECURE | RKNPU_MEM_DMA32 | ++ RKNPU_MEM_TRY_ALLOC_SRAM | RKNPU_MEM_TRY_ALLOC_NBUF ++}; ++ ++/* sync mode definitions. */ ++enum e_rknpu_mem_sync_mode { ++ RKNPU_MEM_SYNC_TO_DEVICE = 1 << 0, ++ RKNPU_MEM_SYNC_FROM_DEVICE = 1 << 1, ++ RKNPU_MEM_SYNC_MASK = ++ RKNPU_MEM_SYNC_TO_DEVICE | RKNPU_MEM_SYNC_FROM_DEVICE ++}; ++ ++/* job mode definitions. */ ++enum e_rknpu_job_mode { ++ RKNPU_JOB_SLAVE = 0 << 0, ++ RKNPU_JOB_PC = 1 << 0, ++ RKNPU_JOB_BLOCK = 0 << 1, ++ RKNPU_JOB_NONBLOCK = 1 << 1, ++ RKNPU_JOB_PINGPONG = 1 << 2, ++ RKNPU_JOB_FENCE_IN = 1 << 3, ++ RKNPU_JOB_FENCE_OUT = 1 << 4, ++ RKNPU_JOB_MASK = RKNPU_JOB_PC | RKNPU_JOB_NONBLOCK | ++ RKNPU_JOB_PINGPONG | RKNPU_JOB_FENCE_IN | ++ RKNPU_JOB_FENCE_OUT ++}; ++ ++/* action definitions */ ++enum e_rknpu_action { ++ RKNPU_GET_HW_VERSION = 0, ++ RKNPU_GET_DRV_VERSION = 1, ++ RKNPU_GET_FREQ = 2, ++ RKNPU_SET_FREQ = 3, ++ RKNPU_GET_VOLT = 4, ++ RKNPU_SET_VOLT = 5, ++ RKNPU_ACT_RESET = 6, ++ RKNPU_GET_BW_PRIORITY = 7, ++ RKNPU_SET_BW_PRIORITY = 8, ++ RKNPU_GET_BW_EXPECT = 9, ++ RKNPU_SET_BW_EXPECT = 10, ++ RKNPU_GET_BW_TW = 11, ++ RKNPU_SET_BW_TW = 12, ++ RKNPU_ACT_CLR_TOTAL_RW_AMOUNT = 13, ++ RKNPU_GET_DT_WR_AMOUNT = 14, ++ RKNPU_GET_DT_RD_AMOUNT = 15, ++ RKNPU_GET_WT_RD_AMOUNT = 16, ++ RKNPU_GET_TOTAL_RW_AMOUNT = 17, ++ RKNPU_GET_IOMMU_EN = 18, ++ RKNPU_SET_PROC_NICE = 19, ++ RKNPU_POWER_ON = 20, ++ RKNPU_POWER_OFF = 21, ++ RKNPU_GET_TOTAL_SRAM_SIZE = 22, ++ RKNPU_GET_FREE_SRAM_SIZE = 23, ++}; ++ ++/** ++ * User-desired buffer creation information structure. ++ * ++ * @handle: The handle of the created GEM object. ++ * @flags: user request for setting memory type or cache attributes. ++ * @size: user-desired memory allocation size. ++ * - this size value would be page-aligned internally. ++ * @obj_addr: address of RKNPU memory object. ++ * @dma_addr: dma address that access by rknpu. ++ * @sram_size: user-desired sram memory allocation size. ++ * - this size value would be page-aligned internally. ++ */ ++struct rknpu_mem_create { ++ __u32 handle; ++ __u32 flags; ++ __u64 size; ++ __u64 obj_addr; ++ __u64 dma_addr; ++ __u64 sram_size; ++}; ++ ++/** ++ * A structure for getting a fake-offset that can be used with mmap. ++ * ++ * @handle: handle of gem object. ++ * @reserved: just padding to be 64-bit aligned. ++ * @offset: a fake-offset of gem object. ++ */ ++struct rknpu_mem_map { ++ __u32 handle; ++ __u32 reserved; ++ __u64 offset; ++}; ++ ++/** ++ * For destroying DMA buffer ++ * ++ * @handle: handle of the buffer. ++ * @reserved: reserved for padding. ++ * @obj_addr: rknpu_mem_object addr. ++ */ ++struct rknpu_mem_destroy { ++ __u32 handle; ++ __u32 reserved; ++ __u64 obj_addr; ++}; ++ ++/** ++ * For synchronizing DMA buffer ++ * ++ * @flags: user request for setting memory type or cache attributes. ++ * @reserved: reserved for padding. ++ * @obj_addr: address of RKNPU memory object. ++ * @offset: offset in bytes from start address of buffer. ++ * @size: size of memory region. ++ * ++ */ ++struct rknpu_mem_sync { ++ __u32 flags; ++ __u32 reserved; ++ __u64 obj_addr; ++ __u64 offset; ++ __u64 size; ++}; ++ ++/** ++ * struct rknpu_task structure for task information ++ * ++ * @flags: flags for task ++ * @op_idx: operator index ++ * @enable_mask: enable mask ++ * @int_mask: interrupt mask ++ * @int_clear: interrupt clear ++ * @int_status: interrupt status ++ * @regcfg_amount: register config number ++ * @regcfg_offset: offset for register config ++ * @regcmd_addr: address for register command ++ * ++ */ ++struct rknpu_task { ++ __u32 flags; ++ __u32 op_idx; ++ __u32 enable_mask; ++ __u32 int_mask; ++ __u32 int_clear; ++ __u32 int_status; ++ __u32 regcfg_amount; ++ __u32 regcfg_offset; ++ __u64 regcmd_addr; ++} __packed; ++ ++/** ++ * struct rknpu_subcore_task structure for subcore task index ++ * ++ * @task_start: task start index ++ * @task_number: task number ++ * ++ */ ++struct rknpu_subcore_task { ++ __u32 task_start; ++ __u32 task_number; ++}; ++ ++/** ++ * struct rknpu_submit structure for job submit ++ * ++ * @flags: flags for job submit ++ * @timeout: submit timeout ++ * @task_start: task start index ++ * @task_number: task number ++ * @task_counter: task counter ++ * @priority: submit priority ++ * @task_obj_addr: address of task object ++ * @regcfg_obj_addr: address of register config object ++ * @task_base_addr: task base address ++ * @user_data: (optional) user data ++ * @core_mask: core mask of rknpu ++ * @fence_fd: dma fence fd ++ * @subcore_task: subcore task ++ * ++ */ ++struct rknpu_submit { ++ __u32 flags; ++ __u32 timeout; ++ __u32 task_start; ++ __u32 task_number; ++ __u32 task_counter; ++ __s32 priority; ++ __u64 task_obj_addr; ++ __u64 regcfg_obj_addr; ++ __u64 task_base_addr; ++ __u64 user_data; ++ __u32 core_mask; ++ __s32 fence_fd; ++ struct rknpu_subcore_task subcore_task[5]; ++}; ++ ++/** ++ * struct rknpu_task structure for action (GET, SET or ACT) ++ * ++ * @flags: flags for action ++ * @value: GET or SET value ++ * ++ */ ++struct rknpu_action { ++ __u32 flags; ++ __u32 value; ++}; ++ ++#define RKNPU_ACTION 0x00 ++#define RKNPU_SUBMIT 0x01 ++#define RKNPU_MEM_CREATE 0x02 ++#define RKNPU_MEM_MAP 0x03 ++#define RKNPU_MEM_DESTROY 0x04 ++#define RKNPU_MEM_SYNC 0x05 ++ ++#define RKNPU_IOC_MAGIC 'r' ++#define RKNPU_IOW(nr, type) _IOW(RKNPU_IOC_MAGIC, nr, type) ++#define RKNPU_IOR(nr, type) _IOR(RKNPU_IOC_MAGIC, nr, type) ++#define RKNPU_IOWR(nr, type) _IOWR(RKNPU_IOC_MAGIC, nr, type) ++ ++#include ++ ++#define DRM_IOCTL_RKNPU_ACTION \ ++ DRM_IOWR(DRM_COMMAND_BASE + RKNPU_ACTION, struct rknpu_action) ++#define DRM_IOCTL_RKNPU_SUBMIT \ ++ DRM_IOWR(DRM_COMMAND_BASE + RKNPU_SUBMIT, struct rknpu_submit) ++#define DRM_IOCTL_RKNPU_MEM_CREATE \ ++ DRM_IOWR(DRM_COMMAND_BASE + RKNPU_MEM_CREATE, struct rknpu_mem_create) ++#define DRM_IOCTL_RKNPU_MEM_MAP \ ++ DRM_IOWR(DRM_COMMAND_BASE + RKNPU_MEM_MAP, struct rknpu_mem_map) ++#define DRM_IOCTL_RKNPU_MEM_DESTROY \ ++ DRM_IOWR(DRM_COMMAND_BASE + RKNPU_MEM_DESTROY, struct rknpu_mem_destroy) ++#define DRM_IOCTL_RKNPU_MEM_SYNC \ ++ DRM_IOWR(DRM_COMMAND_BASE + RKNPU_MEM_SYNC, struct rknpu_mem_sync) ++ ++#define IOCTL_RKNPU_ACTION RKNPU_IOWR(RKNPU_ACTION, struct rknpu_action) ++#define IOCTL_RKNPU_SUBMIT RKNPU_IOWR(RKNPU_SUBMIT, struct rknpu_submit) ++#define IOCTL_RKNPU_MEM_CREATE \ ++ RKNPU_IOWR(RKNPU_MEM_CREATE, struct rknpu_mem_create) ++#define IOCTL_RKNPU_MEM_MAP RKNPU_IOWR(RKNPU_MEM_MAP, struct rknpu_mem_map) ++#define IOCTL_RKNPU_MEM_DESTROY \ ++ RKNPU_IOWR(RKNPU_MEM_DESTROY, struct rknpu_mem_destroy) ++#define IOCTL_RKNPU_MEM_SYNC RKNPU_IOWR(RKNPU_MEM_SYNC, struct rknpu_mem_sync) ++ ++#endif diff --git a/patches/50-rga.patch b/patches/50-rga.patch new file mode 100644 index 0000000..968f051 --- /dev/null +++ b/patches/50-rga.patch @@ -0,0 +1,17108 @@ +diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig +index 0adb1e2fa..954f3de7d 100644 +--- a/drivers/video/Kconfig ++++ b/drivers/video/Kconfig +@@ -46,6 +46,7 @@ source "drivers/gpu/drm/Kconfig" + + menu "Frame buffer Devices" + source "drivers/video/fbdev/Kconfig" ++source "drivers/video/rockchip/Kconfig" + endmenu + + source "drivers/video/backlight/Kconfig" +@@ -90,4 +91,5 @@ endif + + source "drivers/gpu/trace/Kconfig" + ++source "drivers/video/rockchip/Kconfig" + endmenu +diff --git a/drivers/video/Makefile b/drivers/video/Makefile +index ffbac4387..bd44d988c 100644 +--- a/drivers/video/Makefile ++++ b/drivers/video/Makefile +@@ -21,3 +21,4 @@ obj-$(CONFIG_VIDEOMODE_HELPERS) += display_timing.o videomode.o + ifeq ($(CONFIG_OF),y) + obj-$(CONFIG_VIDEOMODE_HELPERS) += of_display_timing.o of_videomode.o + endif ++obj-y += rockchip/ +diff --git a/drivers/video/rockchip/Kconfig b/drivers/video/rockchip/Kconfig +new file mode 100644 +index 000000000..39e01f133 +--- /dev/null ++++ b/drivers/video/rockchip/Kconfig +@@ -0,0 +1 @@ ++source "drivers/video/rockchip/rga3/Kconfig" +diff --git a/drivers/video/rockchip/Makefile b/drivers/video/rockchip/Makefile +new file mode 100644 +index 000000000..53958b85c +--- /dev/null ++++ b/drivers/video/rockchip/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_ROCKCHIP_MULTI_RGA) += rga3/ +diff --git a/drivers/video/rockchip/rga3/Kconfig b/drivers/video/rockchip/rga3/Kconfig +new file mode 100644 +index 000000000..c8c96b2d6 +--- /dev/null ++++ b/drivers/video/rockchip/rga3/Kconfig +@@ -0,0 +1,37 @@ ++# SPDX-License-Identifier: GPL-2.0 ++menuconfig ROCKCHIP_MULTI_RGA ++ tristate "MULTI_RGA" ++ depends on ARCH_ROCKCHIP ++ help ++ multi_rga module. ++ ++if ROCKCHIP_MULTI_RGA ++ ++config ROCKCHIP_RGA_ASYNC ++ bool "Enable async mode" ++ depends on SYNC_FILE ++ default y ++ help ++ Asynchronous calls will be supported. ++ ++config ROCKCHIP_RGA_PROC_FS ++ bool "Enable RGA procfs" ++ select ROCKCHIP_RGA_DEBUGGER ++ depends on PROC_FS ++ help ++ Enable procfs to debug multi RGA driver. ++ ++config ROCKCHIP_RGA_DEBUG_FS ++ bool "Enable RGA debugfs" ++ select ROCKCHIP_RGA_DEBUGGER ++ depends on DEBUG_FS ++ default y ++ help ++ Enable debugfs to debug multi RGA driver. ++ ++config ROCKCHIP_RGA_DEBUGGER ++ bool ++ help ++ Enabling the debugger of multi RGA, you can use procfs and debugfs for debugging. ++ ++endif +diff --git a/drivers/video/rockchip/rga3/Makefile b/drivers/video/rockchip/rga3/Makefile +new file mode 100644 +index 000000000..11f401de2 +--- /dev/null ++++ b/drivers/video/rockchip/rga3/Makefile +@@ -0,0 +1,9 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++ccflags-y += -I$(srctree)/$(src)/include ++ ++rga3-y := rga_drv.o rga_common.o rga3_reg_info.o rga_iommu.o rga_dma_buf.o rga_job.o rga_hw_config.o rga2_reg_info.o rga_policy.o rga_mm.o ++rga3-$(CONFIG_ROCKCHIP_RGA_ASYNC) += rga_fence.o ++rga3-$(CONFIG_ROCKCHIP_RGA_DEBUGGER) += rga_debugger.o ++ ++obj-$(CONFIG_ROCKCHIP_MULTI_RGA) += rga3.o +diff --git a/drivers/video/rockchip/rga3/include/rga.h b/drivers/video/rockchip/rga3/include/rga.h +new file mode 100644 +index 000000000..2a60a1ae7 +--- /dev/null ++++ b/drivers/video/rockchip/rga3/include/rga.h +@@ -0,0 +1,944 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef _RGA_DRIVER_H_ ++#define _RGA_DRIVER_H_ ++ ++#include ++#include ++ ++/* Use 'r' as magic number */ ++#define RGA_IOC_MAGIC 'r' ++#define RGA_IOW(nr, type) _IOW(RGA_IOC_MAGIC, nr, type) ++#define RGA_IOR(nr, type) _IOR(RGA_IOC_MAGIC, nr, type) ++#define RGA_IOWR(nr, type) _IOWR(RGA_IOC_MAGIC, nr, type) ++ ++#define RGA_IOC_GET_DRVIER_VERSION RGA_IOR(0x1, struct rga_version_t) ++#define RGA_IOC_GET_HW_VERSION RGA_IOR(0x2, struct rga_hw_versions_t) ++#define RGA_IOC_IMPORT_BUFFER RGA_IOWR(0x3, struct rga_buffer_pool) ++#define RGA_IOC_RELEASE_BUFFER RGA_IOW(0x4, struct rga_buffer_pool) ++#define RGA_IOC_REQUEST_CREATE RGA_IOR(0x5, uint32_t) ++#define RGA_IOC_REQUEST_SUBMIT RGA_IOWR(0x6, struct rga_user_request) ++#define RGA_IOC_REQUEST_CONFIG RGA_IOWR(0x7, struct rga_user_request) ++#define RGA_IOC_REQUEST_CANCEL RGA_IOWR(0x8, uint32_t) ++ ++#define RGA_BLIT_SYNC 0x5017 ++#define RGA_BLIT_ASYNC 0x5018 ++#define RGA_FLUSH 0x5019 ++#define RGA_GET_RESULT 0x501a ++#define RGA_GET_VERSION 0x501b ++#define RGA_CACHE_FLUSH 0x501c ++ ++#define RGA2_GET_VERSION 0x601b ++#define RGA_IMPORT_DMA 0x601d ++#define RGA_RELEASE_DMA 0x601e ++ ++#define RGA_TASK_NUM_MAX 50 ++ ++#define RGA_OUT_OF_RESOURCES -10 ++#define RGA_MALLOC_ERROR -11 ++ ++#define SCALE_DOWN_LARGE 1 ++#define SCALE_UP_LARGE 1 ++ ++#define RGA_BUFFER_POOL_SIZE_MAX 40 ++ ++#define RGA3_MAJOR_VERSION_MASK (0xF0000000) ++#define RGA3_MINOR_VERSION_MASK (0x0FF00000) ++#define RGA3_SVN_VERSION_MASK (0x000FFFFF) ++ ++#define RGA2_MAJOR_VERSION_MASK (0xFF000000) ++#define RGA2_MINOR_VERSION_MASK (0x00F00000) ++#define RGA2_SVN_VERSION_MASK (0x000FFFFF) ++ ++#define RGA_MODE_ROTATE_0 (1<<0) ++#define RGA_MODE_ROTATE_90 (1<<1) ++#define RGA_MODE_ROTATE_180 (1<<2) ++#define RGA_MODE_ROTATE_270 (1<<3) ++#define RGA_MODE_X_MIRROR (1<<4) ++#define RGA_MODE_Y_MIRROR (1<<5) ++ ++#define RGA_MODE_CSC_BT601L (1<<0) ++#define RGA_MODE_CSC_BT601F (1<<1) ++#define RGA_MODE_CSC_BT709 (1<<2) ++#define RGA_MODE_CSC_BT2020 (1<<3) ++ ++#define RGA_MODE_ROTATE_MASK (\ ++ RGA_MODE_ROTATE_0 | \ ++ RGA_MODE_ROTATE_90 | \ ++ RGA_MODE_ROTATE_180 | \ ++ RGA_MODE_ROTATE_270 | \ ++ RGA_MODE_X_MIRROR | \ ++ RGA_MODE_Y_MIRROR) ++ ++enum rga_memory_type { ++ RGA_DMA_BUFFER = 0, ++ RGA_VIRTUAL_ADDRESS, ++ RGA_PHYSICAL_ADDRESS, ++ RGA_DMA_BUFFER_PTR, ++}; ++ ++enum rga_scale_up_mode { ++ RGA_SCALE_UP_NONE = 0x0, ++ RGA_SCALE_UP_BIC = 0x1, ++}; ++ ++enum rga_scale_down_mode { ++ RGA_SCALE_DOWN_NONE = 0x0, ++ RGA_SCALE_DOWN_AVG = 0x1, ++}; ++ ++enum RGA_SCHEDULER_CORE { ++ RGA_SCHEDULER_RGA3_CORE0 = 1 << 0, ++ RGA_SCHEDULER_RGA3_CORE1 = 1 << 1, ++ RGA_SCHEDULER_RGA2_CORE0 = 1 << 2, ++}; ++ ++/* RGA process mode enum */ ++enum { ++ BITBLT_MODE = 0x0, ++ COLOR_PALETTE_MODE = 0x1, ++ COLOR_FILL_MODE = 0x2, ++ /* used by rga2 */ ++ UPDATE_PALETTE_TABLE_MODE = 0x6, ++ UPDATE_PATTEN_BUF_MODE = 0x7, ++}; /*render mode*/ ++ ++/* RGA rd_mode */ ++enum { ++ RGA_RASTER_MODE = 0x1 << 0, ++ RGA_FBC_MODE = 0x1 << 1, ++ RGA_TILE_MODE = 0x1 << 2, ++}; ++ ++enum { ++ RGA_10BIT_COMPACT = 0x0, ++ RGA_10BIT_INCOMPACT = 0x1, ++}; ++ ++enum { ++ RGA_CONTEXT_NONE = 0x0, ++ RGA_CONTEXT_SRC_FIX_ENABLE = 0x1 << 0, ++ RGA_CONTEXT_SRC_CACHE_INFO = 0x1 << 1, ++ RGA_CONTEXT_SRC_MASK = RGA_CONTEXT_SRC_FIX_ENABLE | ++ RGA_CONTEXT_SRC_CACHE_INFO, ++ RGA_CONTEXT_PAT_FIX_ENABLE = 0x1 << 2, ++ RGA_CONTEXT_PAT_CACHE_INFO = 0x1 << 3, ++ RGA_CONTEXT_PAT_MASK = RGA_CONTEXT_PAT_FIX_ENABLE | ++ RGA_CONTEXT_PAT_CACHE_INFO, ++ RGA_CONTEXT_DST_FIX_ENABLE = 0x1 << 4, ++ RGA_CONTEXT_DST_CACHE_INFO = 0x1 << 5, ++ RGA_CONTEXT_DST_MASK = RGA_CONTEXT_DST_FIX_ENABLE | ++ RGA_CONTEXT_DST_CACHE_INFO, ++}; ++ ++/* RGA feature */ ++enum { ++ RGA_COLOR_FILL = 0x1 << 0, ++ RGA_COLOR_PALETTE = 0x1 << 1, ++ RGA_COLOR_KEY = 0x1 << 2, ++ RGA_ROP_CALCULATE = 0x1 << 3, ++ RGA_NN_QUANTIZE = 0x1 << 4, ++ RGA_OSD_BLEND = 0x1 << 5, ++ RGA_DITHER = 0x1 << 6, ++ RGA_MOSAIC = 0x1 << 7, ++ RGA_YIN_YOUT = 0x1 << 8, ++ RGA_YUV_HDS = 0x1 << 9, ++ RGA_YUV_VDS = 0x1 << 10, ++ RGA_OSD = 0x1 << 11, ++ RGA_PRE_INTR = 0x1 << 12, ++ RGA_FULL_CSC = 0x1 << 13, ++}; ++ ++enum rga_surf_format { ++ RGA_FORMAT_RGBA_8888 = 0x0, ++ RGA_FORMAT_RGBX_8888 = 0x1, ++ RGA_FORMAT_RGB_888 = 0x2, ++ RGA_FORMAT_BGRA_8888 = 0x3, ++ RGA_FORMAT_RGB_565 = 0x4, ++ RGA_FORMAT_RGBA_5551 = 0x5, ++ RGA_FORMAT_RGBA_4444 = 0x6, ++ RGA_FORMAT_BGR_888 = 0x7, ++ ++ RGA_FORMAT_YCbCr_422_SP = 0x8, ++ RGA_FORMAT_YCbCr_422_P = 0x9, ++ RGA_FORMAT_YCbCr_420_SP = 0xa, ++ RGA_FORMAT_YCbCr_420_P = 0xb, ++ ++ RGA_FORMAT_YCrCb_422_SP = 0xc, ++ RGA_FORMAT_YCrCb_422_P = 0xd, ++ RGA_FORMAT_YCrCb_420_SP = 0xe, ++ RGA_FORMAT_YCrCb_420_P = 0xf, ++ ++ RGA_FORMAT_BPP1 = 0x10, ++ RGA_FORMAT_BPP2 = 0x11, ++ RGA_FORMAT_BPP4 = 0x12, ++ RGA_FORMAT_BPP8 = 0x13, ++ ++ RGA_FORMAT_Y4 = 0x14, ++ RGA_FORMAT_YCbCr_400 = 0x15, ++ ++ RGA_FORMAT_BGRX_8888 = 0x16, ++ ++ RGA_FORMAT_YVYU_422 = 0x18, ++ RGA_FORMAT_YVYU_420 = 0x19, ++ RGA_FORMAT_VYUY_422 = 0x1a, ++ RGA_FORMAT_VYUY_420 = 0x1b, ++ RGA_FORMAT_YUYV_422 = 0x1c, ++ RGA_FORMAT_YUYV_420 = 0x1d, ++ RGA_FORMAT_UYVY_422 = 0x1e, ++ RGA_FORMAT_UYVY_420 = 0x1f, ++ ++ RGA_FORMAT_YCbCr_420_SP_10B = 0x20, ++ RGA_FORMAT_YCrCb_420_SP_10B = 0x21, ++ RGA_FORMAT_YCbCr_422_SP_10B = 0x22, ++ RGA_FORMAT_YCrCb_422_SP_10B = 0x23, ++ ++ RGA_FORMAT_BGR_565 = 0x24, ++ RGA_FORMAT_BGRA_5551 = 0x25, ++ RGA_FORMAT_BGRA_4444 = 0x26, ++ ++ RGA_FORMAT_ARGB_8888 = 0x28, ++ RGA_FORMAT_XRGB_8888 = 0x29, ++ RGA_FORMAT_ARGB_5551 = 0x2a, ++ RGA_FORMAT_ARGB_4444 = 0x2b, ++ RGA_FORMAT_ABGR_8888 = 0x2c, ++ RGA_FORMAT_XBGR_8888 = 0x2d, ++ RGA_FORMAT_ABGR_5551 = 0x2e, ++ RGA_FORMAT_ABGR_4444 = 0x2f, ++ ++ RGA_FORMAT_RGBA_2BPP = 0x30, ++ ++ RGA_FORMAT_UNKNOWN = 0x100, ++}; ++ ++enum rga_alpha_mode { ++ RGA_ALPHA_STRAIGHT = 0, ++ RGA_ALPHA_INVERSE = 1, ++}; ++ ++enum rga_global_blend_mode { ++ RGA_ALPHA_GLOBAL = 0, ++ RGA_ALPHA_PER_PIXEL = 1, ++ RGA_ALPHA_PER_PIXEL_GLOBAL = 2, ++}; ++ ++enum rga_alpha_cal_mode { ++ RGA_ALPHA_SATURATION = 0, ++ RGA_ALPHA_NO_SATURATION = 1, ++}; ++ ++enum rga_factor_mode { ++ RGA_ALPHA_ZERO = 0, ++ RGA_ALPHA_ONE = 1, ++ /* ++ * When used as a factor for the SRC channel, it indicates ++ * the use of the DST channel's alpha value, and vice versa. ++ */ ++ RGA_ALPHA_OPPOSITE = 2, ++ RGA_ALPHA_OPPOSITE_INVERSE = 3, ++ RGA_ALPHA_OWN = 4, ++}; ++ ++enum rga_color_mode { ++ RGA_ALPHA_PRE_MULTIPLIED = 0, ++ RGA_ALPHA_NO_PRE_MULTIPLIED = 1, ++}; ++ ++enum rga_alpha_blend_mode { ++ RGA_ALPHA_NONE = 0, ++ RGA_ALPHA_BLEND_SRC, ++ RGA_ALPHA_BLEND_DST, ++ RGA_ALPHA_BLEND_SRC_OVER, ++ RGA_ALPHA_BLEND_DST_OVER, ++ RGA_ALPHA_BLEND_SRC_IN, ++ RGA_ALPHA_BLEND_DST_IN, ++ RGA_ALPHA_BLEND_SRC_OUT, ++ RGA_ALPHA_BLEND_DST_OUT, ++ RGA_ALPHA_BLEND_SRC_ATOP, ++ RGA_ALPHA_BLEND_DST_ATOP, ++ RGA_ALPHA_BLEND_XOR, ++ RGA_ALPHA_BLEND_CLEAR, ++}; ++ ++#define RGA_SCHED_PRIORITY_DEFAULT 0 ++#define RGA_SCHED_PRIORITY_MAX 6 ++ ++#define RGA_VERSION_SIZE 16 ++#define RGA_HW_SIZE 5 ++ ++struct rga_version_t { ++ uint32_t major; ++ uint32_t minor; ++ uint32_t revision; ++ uint8_t str[RGA_VERSION_SIZE]; ++}; ++ ++struct rga_hw_versions_t { ++ struct rga_version_t version[RGA_HW_SIZE]; ++ uint32_t size; ++}; ++ ++struct rga_memory_parm { ++ uint32_t width; ++ uint32_t height; ++ uint32_t format; ++ ++ uint32_t size; ++}; ++ ++struct rga_external_buffer { ++ uint64_t memory; ++ uint32_t type; ++ ++ uint32_t handle; ++ struct rga_memory_parm memory_parm; ++ ++ uint8_t reserve[252]; ++}; ++ ++struct rga_buffer_pool { ++ uint64_t buffers_ptr; ++ uint32_t size; ++}; ++ ++struct rga_mmu_info_t { ++ unsigned long src0_base_addr; ++ unsigned long src1_base_addr; ++ unsigned long dst_base_addr; ++ unsigned long els_base_addr; ++ ++ /* [0] mmu enable [1] flush [2] prefetch_en [3] prefetch dir */ ++ u8 src0_mmu_flag; ++ u8 src1_mmu_flag; ++ u8 dst_mmu_flag; ++ u8 els_mmu_flag; ++}; ++ ++struct rga_color_fill_t { ++ int16_t gr_x_a; ++ int16_t gr_y_a; ++ int16_t gr_x_b; ++ int16_t gr_y_b; ++ int16_t gr_x_g; ++ int16_t gr_y_g; ++ int16_t gr_x_r; ++ int16_t gr_y_r; ++}; ++ ++/***************************************/ ++/* porting from rga.h for msg convert */ ++/***************************************/ ++ ++struct rga_fading_t { ++ uint8_t b; ++ uint8_t g; ++ uint8_t r; ++ uint8_t res; ++}; ++ ++struct rga_mmu_t { ++ uint8_t mmu_en; ++ uint64_t base_addr; ++ /* ++ * [0] mmu enable [1] src_flush [2] dst_flush ++ * [3] CMD_flush [4~5] page size ++ */ ++ uint32_t mmu_flag; ++}; ++ ++struct rga_rect_t { ++ uint16_t xmin; ++ /* width - 1 */ ++ uint16_t xmax; ++ uint16_t ymin; ++ /* height - 1 */ ++ uint16_t ymax; ++}; ++ ++struct rga_point_t { ++ uint16_t x; ++ uint16_t y; ++}; ++ ++struct rga_line_draw_t { ++ /* LineDraw_start_point */ ++ struct rga_point_t start_point; ++ /* LineDraw_end_point */ ++ struct rga_point_t end_point; ++ /* LineDraw_color */ ++ uint32_t color; ++ /* (enum) LineDrawing mode sel */ ++ uint32_t flag; ++ /* range 1~16 */ ++ uint32_t line_width; ++}; ++ ++/* color space convert coefficient. */ ++struct rga_csc_coe { ++ int16_t r_v; ++ int16_t g_y; ++ int16_t b_u; ++ int32_t off; ++}; ++ ++struct rga_full_csc { ++ uint8_t flag; ++ struct rga_csc_coe coe_y; ++ struct rga_csc_coe coe_u; ++ struct rga_csc_coe coe_v; ++}; ++ ++struct rga_csc_range { ++ uint16_t max; ++ uint16_t min; ++}; ++ ++struct rga_csc_clip { ++ struct rga_csc_range y; ++ struct rga_csc_range uv; ++}; ++ ++struct rga_mosaic_info { ++ uint8_t enable; ++ uint8_t mode; ++}; ++ ++/* MAX(min, (max - channel_value)) */ ++struct rga_osd_invert_factor { ++ uint8_t alpha_max; ++ uint8_t alpha_min; ++ uint8_t yg_max; ++ uint8_t yg_min; ++ uint8_t crb_max; ++ uint8_t crb_min; ++}; ++ ++struct rga_color { ++ union { ++ struct { ++ uint8_t red; ++ uint8_t green; ++ uint8_t blue; ++ uint8_t alpha; ++ }; ++ uint32_t value; ++ }; ++}; ++ ++struct rga_osd_bpp2 { ++ uint8_t ac_swap; // ac swap flag ++ // 0: CA ++ // 1: AC ++ uint8_t endian_swap; // rgba2bpp endian swap ++ // 0: Big endian ++ // 1: Little endian ++ struct rga_color color0; ++ struct rga_color color1; ++}; ++ ++struct rga_osd_mode_ctrl { ++ uint8_t mode; // OSD cal mode: ++ // 0b'1: statistics mode ++ // 1b'1: auto inversion overlap mode ++ uint8_t direction_mode; // horizontal or vertical ++ // 0: horizontal ++ // 1: vertical ++ uint8_t width_mode; // using @fix_width or LUT width ++ // 0: fix width ++ // 1: LUT width ++ uint16_t block_fix_width; // OSD block fixed width ++ // real width = (fix_width + 1) * 2 ++ uint8_t block_num; // OSD block num ++ uint16_t flags_index; // auto invert flags index ++ ++ /* invertion config */ ++ uint8_t color_mode; // selete color ++ // 0: src1 color ++ // 1: config data color ++ uint8_t invert_flags_mode; // invert flag selete ++ // 0: use RAM flag ++ // 1: usr last result ++ uint8_t default_color_sel; // default color mode ++ // 0: default is bright ++ // 1: default is dark ++ uint8_t invert_enable; // invert channel enable ++ // 1 << 0: alpha enable ++ // 1 << 1: Y/G disable ++ // 1 << 3: C/RB disable ++ uint8_t invert_mode; // invert cal mode ++ // 0: normal(max-data) ++ // 1: swap ++ uint8_t invert_thresh; // if luma > thresh, osd_flag to be 1 ++ uint8_t unfix_index; // OSD width config index ++}; ++ ++struct rga_osd_info { ++ uint8_t enable; ++ ++ struct rga_osd_mode_ctrl mode_ctrl; ++ struct rga_osd_invert_factor cal_factor; ++ struct rga_osd_bpp2 bpp2_info; ++ ++ union { ++ struct { ++ uint32_t last_flags0; ++ uint32_t last_flags1; ++ }; ++ uint64_t last_flags; ++ }; ++ ++ union { ++ struct { ++ uint32_t cur_flags0; ++ uint32_t cur_flags1; ++ }; ++ uint64_t cur_flags; ++ }; ++}; ++ ++struct rga_pre_intr_info { ++ uint8_t enable; ++ ++ uint8_t read_intr_en; ++ uint8_t write_intr_en; ++ uint8_t read_hold_en; ++ uint32_t read_threshold; ++ uint32_t write_start; ++ uint32_t write_step; ++}; ++ ++struct rga_win_info_t { ++ /* yrgb mem addr */ ++ unsigned long yrgb_addr; ++ /* cb/cr mem addr */ ++ unsigned long uv_addr; ++ /* cr mem addr */ ++ unsigned long v_addr; ++ /* definition by RK_FORMAT */ ++ unsigned int format; ++ ++ unsigned short src_act_w; ++ unsigned short src_act_h; ++ ++ unsigned short dst_act_w; ++ unsigned short dst_act_h; ++ ++ unsigned short x_offset; ++ unsigned short y_offset; ++ ++ unsigned short vir_w; ++ unsigned short vir_h; ++ ++ unsigned short y2r_mode; ++ unsigned short r2y_mode; ++ ++ unsigned short rotate_mode; ++ /* RASTER or FBCD or TILE */ ++ unsigned short rd_mode; ++ ++ unsigned short is_10b_compact; ++ unsigned short is_10b_endian; ++ ++ unsigned short enable; ++}; ++ ++struct rga_img_info_t { ++ /* yrgb mem addr */ ++ uint64_t yrgb_addr; ++ /* cb/cr mem addr */ ++ uint64_t uv_addr; ++ /* cr mem addr */ ++ uint64_t v_addr; ++ /* definition by RK_FORMAT */ ++ uint32_t format; ++ ++ uint16_t act_w; ++ uint16_t act_h; ++ uint16_t x_offset; ++ uint16_t y_offset; ++ ++ uint16_t vir_w; ++ uint16_t vir_h; ++ ++ uint16_t endian_mode; ++ /* useless */ ++ uint16_t alpha_swap; ++ ++ /* used by RGA3 */ ++ uint16_t rotate_mode; ++ uint16_t rd_mode; ++ ++ uint16_t compact_mode; ++ uint16_t is_10b_endian; ++ ++ uint16_t enable; ++}; ++ ++struct rga_feature { ++ uint32_t global_alpha_en:1; ++ uint32_t full_csc_clip_en:1; ++ uint32_t user_close_fence:1; ++}; ++ ++struct rga_req { ++ /* (enum) process mode sel */ ++ uint8_t render_mode; ++ ++ struct rga_img_info_t src; ++ struct rga_img_info_t dst; ++ struct rga_img_info_t pat; ++ ++ /* rop4 mask addr */ ++ uint64_t rop_mask_addr; ++ /* LUT addr */ ++ uint64_t LUT_addr; ++ ++ /* dst clip window default value is dst_vir */ ++ /* value from [0, w-1] / [0, h-1]*/ ++ struct rga_rect_t clip; ++ ++ /* dst angle default value 0 16.16 scan from table */ ++ int32_t sina; ++ /* dst angle default value 0 16.16 scan from table */ ++ int32_t cosa; ++ ++ /* alpha rop process flag */ ++ /* ([0] = 1 alpha_rop_enable) */ ++ /* ([1] = 1 rop enable) */ ++ /* ([2] = 1 fading_enable) */ ++ /* ([3] = 1 PD_enable) */ ++ /* ([4] = 1 alpha cal_mode_sel) */ ++ /* ([5] = 1 dither_enable) */ ++ /* ([6] = 1 gradient fill mode sel) */ ++ /* ([7] = 1 AA_enable) */ ++ uint16_t alpha_rop_flag; ++ ++ /* 0 nearst / 1 bilnear / 2 bicubic */ ++ uint8_t scale_mode; ++ ++ /* color key max */ ++ uint32_t color_key_max; ++ /* color key min */ ++ uint32_t color_key_min; ++ ++ /* foreground color */ ++ uint32_t fg_color; ++ /* background color */ ++ uint32_t bg_color; ++ ++ /* color fill use gradient */ ++ struct rga_color_fill_t gr_color; ++ ++ struct rga_line_draw_t line_draw_info; ++ ++ struct rga_fading_t fading; ++ ++ /* porter duff alpha mode sel */ ++ uint8_t PD_mode; ++ ++ /* legacy: global alpha value */ ++ uint8_t alpha_global_value; ++ ++ /* rop2/3/4 code scan from rop code table*/ ++ uint16_t rop_code; ++ ++ /* [2] 0 blur 1 sharp / [1:0] filter_type*/ ++ uint8_t bsfilter_flag; ++ ++ /* (enum) color palette 0/1bpp, 1/2bpp 2/4bpp 3/8bpp*/ ++ uint8_t palette_mode; ++ ++ /* (enum) BT.601 MPEG / BT.601 JPEG / BT.709 */ ++ uint8_t yuv2rgb_mode; ++ ++ /* 0/big endian 1/little endian*/ ++ uint8_t endian_mode; ++ ++ /* (enum) rotate mode */ ++ /* 0x0, no rotate */ ++ /* 0x1, rotate */ ++ /* 0x2, x_mirror */ ++ /* 0x3, y_mirror */ ++ uint8_t rotate_mode; ++ ++ /* 0 solid color / 1 pattern color */ ++ uint8_t color_fill_mode; ++ ++ /* mmu information */ ++ struct rga_mmu_t mmu_info; ++ ++ /* ([0~1] alpha mode) */ ++ /* ([2~3] rop mode) */ ++ /* ([4] zero mode en) */ ++ /* ([5] dst alpha mode) */ ++ /* ([6] alpha output mode sel) 0 src / 1 dst*/ ++ uint8_t alpha_rop_mode; ++ ++ uint8_t src_trans_mode; ++ ++ uint8_t dither_mode; ++ ++ /* full color space convert */ ++ struct rga_full_csc full_csc; ++ ++ int32_t in_fence_fd; ++ uint8_t core; ++ uint8_t priority; ++ int32_t out_fence_fd; ++ ++ uint8_t handle_flag; ++ ++ /* RGA2 1106 add */ ++ struct rga_mosaic_info mosaic_info; ++ ++ uint8_t uvhds_mode; ++ uint8_t uvvds_mode; ++ ++ struct rga_osd_info osd_info; ++ ++ struct rga_pre_intr_info pre_intr_info; ++ ++ /* global alpha */ ++ uint8_t fg_global_alpha; ++ uint8_t bg_global_alpha; ++ ++ struct rga_feature feature; ++ ++ struct rga_csc_clip full_csc_clip; ++ ++ uint8_t reservr[43]; ++}; ++ ++struct rga_alpha_config { ++ bool enable; ++ bool fg_pre_multiplied; ++ bool bg_pre_multiplied; ++ bool fg_pixel_alpha_en; ++ bool bg_pixel_alpha_en; ++ bool fg_global_alpha_en; ++ bool bg_global_alpha_en; ++ uint16_t fg_global_alpha_value; ++ uint16_t bg_global_alpha_value; ++ enum rga_alpha_blend_mode mode; ++}; ++ ++struct rga2_req { ++ /* (enum) process mode sel */ ++ u8 render_mode; ++ ++ /* active window */ ++ struct rga_img_info_t src; ++ struct rga_img_info_t src1; ++ struct rga_img_info_t dst; ++ struct rga_img_info_t pat; ++ ++ /* rop4 mask addr */ ++ unsigned long rop_mask_addr; ++ /* LUT addr */ ++ unsigned long LUT_addr; ++ ++ u32 rop_mask_stride; ++ ++ /* 0: SRC + DST => DST */ ++ /* 1: SRC + SRC1 => DST */ ++ u8 bitblt_mode; ++ ++ /* [1:0] */ ++ /* 0 degree 0x0 */ ++ /* 90 degree 0x1 */ ++ /* 180 degree 0x2 */ ++ /* 270 degree 0x3 */ ++ /* [5:4] */ ++ /* none 0x0 */ ++ /* x_mirror 0x1 */ ++ /* y_mirror 0x2 */ ++ /* x_mirror + y_mirror 0x3 */ ++ u8 rotate_mode; ++ ++ /* alpha rop process flag */ ++ /* ([0] = 1 alpha_rop_enable) */ ++ /* ([1] = 1 rop enable) */ ++ /* ([2] = 1 fading_enable) */ ++ /* ([3] = 1 alpha cal_mode_sel) */ ++ /* ([4] = 1 src_dither_up_enable) */ ++ /* ([5] = 1 dst_dither_up_enable) */ ++ /* ([6] = 1 dither_down_enable) */ ++ /* ([7] = 1 gradient fill mode sel) */ ++ u16 alpha_rop_flag; ++ ++ struct rga_alpha_config alpha_config; ++ ++ /* 0 1 2 3 */ ++ u8 scale_bicu_mode; ++ ++ u32 color_key_max; ++ u32 color_key_min; ++ ++ /* foreground color */ ++ u32 fg_color; ++ /* background color */ ++ u32 bg_color; ++ ++ u8 color_fill_mode; ++ /* color fill use gradient */ ++ struct rga_color_fill_t gr_color; ++ ++ /* Fading value */ ++ u8 fading_alpha_value; ++ u8 fading_r_value; ++ u8 fading_g_value; ++ u8 fading_b_value; ++ ++ /* src global alpha value */ ++ u8 src_a_global_val; ++ /* dst global alpha value */ ++ u8 dst_a_global_val; ++ ++ /* rop mode select 0 : rop2 1 : rop3 2 : rop4 */ ++ u8 rop_mode; ++ /* rop2/3/4 code */ ++ u16 rop_code; ++ ++ /* (enum) color palette 0/1bpp, 1/2bpp 2/4bpp 3/8bpp*/ ++ u8 palette_mode; ++ ++ /* (enum) BT.601 MPEG / BT.601 JPEG / BT.709 */ ++ u8 yuv2rgb_mode; ++ ++ u8 full_csc_en; ++ ++ /* 0/little endian 1/big endian */ ++ u8 endian_mode; ++ ++ u8 CMD_fin_int_enable; ++ ++ /* mmu information */ ++ struct rga_mmu_info_t mmu_info; ++ ++ u8 alpha_zero_key; ++ u8 src_trans_mode; ++ ++ /* useless */ ++ u8 alpha_swp; ++ u8 dither_mode; ++ ++ u8 rgb2yuv_mode; ++ ++ /* RGA2 1106 add */ ++ struct rga_mosaic_info mosaic_info; ++ ++ uint8_t yin_yout_en; ++ ++ uint8_t uvhds_mode; ++ uint8_t uvvds_mode; ++ ++ struct rga_osd_info osd_info; ++}; ++ ++struct rga3_req { ++ /* (enum) process mode sel */ ++ u8 render_mode; ++ ++ struct rga_win_info_t win0; ++ struct rga_win_info_t wr; ++ struct rga_win_info_t win1; ++ ++ /* rop4 mask addr */ ++ unsigned long rop_mask_addr; ++ unsigned long LUT_addr; ++ ++ u32 rop_mask_stride; ++ ++ u8 bitblt_mode; ++ u8 rotate_mode; ++ ++ u16 alpha_rop_flag; ++ ++ struct rga_alpha_config alpha_config; ++ ++ /* for abb mode presever alpha. */ ++ bool abb_alpha_pass; ++ ++ u8 scale_bicu_mode; ++ ++ u32 color_key_max; ++ u32 color_key_min; ++ ++ u32 fg_color; ++ u32 bg_color; ++ ++ u8 color_fill_mode; ++ struct rga_color_fill_t gr_color; ++ ++ u8 fading_alpha_value; ++ u8 fading_r_value; ++ u8 fading_g_value; ++ u8 fading_b_value; ++ ++ /* win0 global alpha value */ ++ u8 win0_a_global_val; ++ /* win1 global alpha value */ ++ u8 win1_a_global_val; ++ ++ u8 rop_mode; ++ u16 rop_code; ++ ++ u8 palette_mode; ++ ++ u8 yuv2rgb_mode; ++ ++ u8 endian_mode; ++ ++ u8 CMD_fin_int_enable; ++ ++ struct rga_mmu_info_t mmu_info; ++ ++ u8 alpha_zero_key; ++ u8 src_trans_mode; ++ ++ u8 alpha_swp; ++ u8 dither_mode; ++ ++ u8 rgb2yuv_mode; ++}; ++ ++struct rga_video_frame_info { ++ uint32_t x_offset; ++ uint32_t y_offset; ++ uint32_t width; ++ uint32_t height; ++ uint32_t format; ++ uint32_t vir_w; ++ uint32_t vir_h; ++ uint32_t rd_mode; ++}; ++ ++struct rga_mpi_job_t { ++ struct dma_buf *dma_buf_src0; ++ struct dma_buf *dma_buf_src1; ++ struct dma_buf *dma_buf_dst; ++ ++ struct rga_video_frame_info *src; ++ struct rga_video_frame_info *pat; ++ struct rga_video_frame_info *dst; ++ struct rga_video_frame_info *output; ++ ++ int ctx_id; ++}; ++ ++struct rga_user_request { ++ uint64_t task_ptr; ++ uint32_t task_num; ++ uint32_t id; ++ uint32_t sync_mode; ++ uint32_t release_fence_fd; ++ ++ uint32_t mpi_config_flags; ++ ++ uint32_t acquire_fence_fd; ++ ++ uint8_t reservr[120]; ++}; ++ ++int rga_mpi_commit(struct rga_mpi_job_t *mpi_job); ++ ++#endif /*_RGA_DRIVER_H_*/ +diff --git a/drivers/video/rockchip/rga3/include/rga2_reg_info.h b/drivers/video/rockchip/rga3/include/rga2_reg_info.h +new file mode 100644 +index 000000000..add2f41bd +--- /dev/null ++++ b/drivers/video/rockchip/rga3/include/rga2_reg_info.h +@@ -0,0 +1,477 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __REG2_INFO_H__ ++#define __REG2_INFO_H__ ++ ++#include "rga_drv.h" ++ ++#define RGA2_SYS_REG_BASE 0x000 ++#define RGA2_CSC_REG_BASE 0x060 ++#define RGA2_CMD_REG_BASE 0x100 ++ ++/* sys reg */ ++#define RGA2_SYS_CTRL 0x000 ++#define RGA2_CMD_CTRL 0x004 ++#define RGA2_CMD_BASE 0x008 ++#define RGA2_STATUS1 0x00c ++#define RGA2_INT 0x010 ++#define RGA2_MMU_CTRL0 0x014 ++#define RGA2_MMU_CMD_BASE 0x018 ++#define RGA2_STATUS2 0x01c ++#define RGA2_VERSION_NUM 0x028 ++#define RGA2_READ_LINE_CNT 0x030 ++#define RGA2_WRITE_LINE_CNT 0x034 ++#define RGA2_LINE_CNT 0x038 ++#define RGA2_PERF_CTRL0 0x040 ++ ++/* full csc reg */ ++#define RGA2_DST_CSC_00 0x060 ++#define RGA2_DST_CSC_01 0x064 ++#define RGA2_DST_CSC_02 0x068 ++#define RGA2_DST_CSC_OFF0 0x06c ++#define RGA2_DST_CSC_10 0x070 ++#define RGA2_DST_CSC_11 0x074 ++#define RGA2_DST_CSC_12 0x078 ++#define RGA2_DST_CSC_OFF1 0x07c ++#define RGA2_DST_CSC_20 0x080 ++#define RGA2_DST_CSC_21 0x084 ++#define RGA2_DST_CSC_22 0x088 ++#define RGA2_DST_CSC_OFF2 0x08c ++ ++/* osd read-back reg */ ++#define RGA2_OSD_CUR_FLAGS0 0x090 ++#define RGA2_OSD_CUR_FLAGS1 0x09c ++ ++/* mode ctrl */ ++#define RGA2_MODE_CTRL_OFFSET 0x000 ++#define RGA2_SRC_INFO_OFFSET 0x004 ++#define RGA2_SRC_BASE0_OFFSET 0x008 ++#define RGA2_SRC_BASE1_OFFSET 0x00c ++#define RGA2_SRC_BASE2_OFFSET 0x010 ++#define RGA2_SRC_BASE3_OFFSET 0x014 ++#define RGA2_SRC_VIR_INFO_OFFSET 0x018 ++#define RGA2_SRC_ACT_INFO_OFFSET 0x01c ++#define RGA2_SRC_X_FACTOR_OFFSET 0x020 ++#define RGA2_OSD_CTRL0_OFFSET 0x020 // repeat ++#define RGA2_SRC_Y_FACTOR_OFFSET 0x024 ++#define RGA2_OSD_CTRL1_OFFSET 0x024 // repeat ++#define RGA2_SRC_BG_COLOR_OFFSET 0x028 ++#define RGA2_OSD_COLOR0_OFFSET 0x028 // repeat ++#define RGA2_SRC_FG_COLOR_OFFSET 0x02c ++#define RGA2_OSD_COLOR1_OFFSET 0x02c // repeat ++#define RGA2_SRC_TR_COLOR0_OFFSET 0x030 ++#define RGA2_CF_GR_A_OFFSET 0x030 // repeat ++#define RGA2_OSD_LAST_FLAGS0_OFFSET 0x030 // repeat ++#define RGA2_MOSAIC_MODE_OFFSET 0x030 // repeat ++#define RGA2_SRC_TR_COLOR1_OFFSET 0x034 ++#define RGA2_CF_GR_B_OFFSET 0x034 // repeat ++#define RGA2_OSD_LAST_FLAGS1_OFFSET 0x034 // repeat ++#define RGA2_DST_INFO_OFFSET 0x038 ++#define RGA2_DST_BASE0_OFFSET 0x03c ++#define RGA2_DST_BASE1_OFFSET 0x040 ++#define RGA2_DST_BASE2_OFFSET 0x044 ++#define RGA2_DST_VIR_INFO_OFFSET 0x048 ++#define RGA2_DST_ACT_INFO_OFFSET 0x04c ++#define RGA2_ALPHA_CTRL0_OFFSET 0x050 ++#define RGA2_ALPHA_CTRL1_OFFSET 0x054 ++#define RGA2_FADING_CTRL_OFFSET 0x058 ++#define RGA2_PAT_CON_OFFSET 0x05c ++#define RGA2_ROP_CTRL0_OFFSET 0x060 ++#define RGA2_CF_GR_G_OFFSET 0x060 // repeat ++#define RGA2_DST_Y4MAP_LUT0_OFFSET 0x060 // repeat ++#define RGA2_DST_QUANTIZE_SCALE_OFFSET 0x060 // repeat ++#define RGA2_OSD_INVERTSION_CAL0_OFFSET 0x060 // repeat ++#define RGA2_ROP_CTRL1_OFFSET 0x064 ++#define RGA2_CF_GR_R_OFFSET 0x064 // repeat ++#define RGA2_DST_Y4MAP_LUT1_OFFSET 0x064 // repeat ++#define RGA2_DST_QUANTIZE_OFFSET_OFFSET 0x064 // repeat ++#define RGA2_OSD_INVERTSION_CAL1_OFFSET 0x064 // repeat ++#define RGA2_MASK_BASE_OFFSET 0x068 ++#define RGA2_MMU_CTRL1_OFFSET 0x06c ++#define RGA2_MMU_SRC_BASE_OFFSET 0x070 ++#define RGA2_MMU_SRC1_BASE_OFFSET 0x074 ++#define RGA2_MMU_DST_BASE_OFFSET 0x078 ++#define RGA2_MMU_ELS_BASE_OFFSET 0x07c ++ ++/*RGA_SYS*/ ++#define m_RGA2_SYS_CTRL_SRC0YUV420SP_RD_OPT_DIS (0x1 << 12) ++#define m_RGA2_SYS_CTRL_DST_WR_OPT_DIS (0x1 << 11) ++#define m_RGA2_SYS_CTRL_CMD_CONTINUE_P (0x1 << 10) ++#define m_RGA2_SYS_CTRL_HOLD_MODE_EN (0x1 << 9) ++#define m_RGA2_SYS_CTRL_RST_HANDSAVE_P (0x1 << 7) ++#define m_RGA2_SYS_CTRL_RST_PROTECT_P (0x1 << 6) ++#define m_RGA2_SYS_CTRL_AUTO_RST (0x1 << 5) ++#define m_RGA2_SYS_CTRL_CCLK_SRESET_P (0x1 << 4) ++#define m_RGA2_SYS_CTRL_ACLK_SRESET_P (0x1 << 3) ++#define m_RGA2_SYS_CTRL_AUTO_CKG (0x1 << 2) ++#define m_RGA2_SYS_CTRL_CMD_MODE (0x1 << 1) ++#define m_RGA2_SYS_CTRL_CMD_OP_ST_P (0x1 << 0) ++ ++#define s_RGA2_SYS_CTRL_CMD_CONTINUE(x) ((x & 0x1) << 10) ++#define s_RGA2_SYS_CTRL_HOLD_MODE_EN(x) ((x & 0x1) << 9) ++#define s_RGA2_SYS_CTRL_CMD_MODE(x) ((x & 0x1) << 1) ++ ++/* RGA_CMD_CTRL */ ++#define m_RGA2_CMD_CTRL_INCR_NUM (0x3ff << 3) ++#define m_RGA2_CMD_CTRL_STOP (0x1 << 2) ++#define m_RGA2_CMD_CTRL_INCR_VALID_P (0x1 << 1) ++#define m_RGA2_CMD_CTRL_CMD_LINE_ST_P (0x1 << 0) ++ ++/* RGA_STATUS1 */ ++#define m_RGA2_STATUS1_SW_CMD_TOTAL_NUM (0xfff << 8) ++#define m_RGA2_STATUS1_SW_CMD_CUR_NUM (0xfff << 8) ++#define m_RGA2_STATUS1_SW_RGA_STA (0x1 << 0) ++ ++/*RGA_INT*/ ++#define m_RGA2_INT_LINE_WR_CLEAR (1 << 16) ++#define m_RGA2_INT_LINE_RD_CLEAR (1 << 15) ++#define m_RGA2_INT_LINE_WR_EN (1 << 14) ++#define m_RGA2_INT_LINE_RD_EN (1 << 13) ++#define m_RGA2_INT_WRITE_CNT_FLAG (1 << 12) ++#define m_RGA2_INT_READ_CNT_FLAG (1 << 11) ++#define m_RGA2_INT_ALL_CMD_DONE_INT_EN (1 << 10) ++#define m_RGA2_INT_MMU_INT_EN (1 << 9) ++#define m_RGA2_INT_ERROR_INT_EN (1 << 8) ++#define m_RGA2_INT_NOW_CMD_DONE_INT_CLEAR (1 << 7) ++#define m_RGA2_INT_ALL_CMD_DONE_INT_CLEAR (1 << 6) ++#define m_RGA2_INT_MMU_INT_CLEAR (1 << 5) ++#define m_RGA2_INT_ERROR_INT_CLEAR (1 << 4) ++#define m_RGA2_INT_CUR_CMD_DONE_INT_FLAG (1 << 3) ++#define m_RGA2_INT_ALL_CMD_DONE_INT_FLAG (1 << 2) ++#define m_RGA2_INT_MMU_INT_FLAG (1 << 1) ++#define m_RGA2_INT_ERROR_INT_FLAG (1 << 0) ++ ++#define m_RGA2_INT_ERROR_FLAG_MASK \ ++ ( \ ++ m_RGA2_INT_MMU_INT_FLAG | \ ++ m_RGA2_INT_ERROR_INT_FLAG \ ++ ) ++#define m_RGA2_INT_ERROR_CLEAR_MASK \ ++ ( \ ++ m_RGA2_INT_MMU_INT_CLEAR | \ ++ m_RGA2_INT_ERROR_INT_CLEAR \ ++) ++#define m_RGA2_INT_ERROR_ENABLE_MASK \ ++ ( \ ++ m_RGA2_INT_MMU_INT_EN | \ ++ m_RGA2_INT_ERROR_INT_EN \ ++ ) ++ ++#define s_RGA2_INT_LINE_WR_CLEAR(x) ((x & 0x1) << 16) ++#define s_RGA2_INT_LINE_RD_CLEAR(x) ((x & 0x1) << 15) ++#define s_RGA2_INT_LINE_WR_EN(x) ((x & 0x1) << 14) ++#define s_RGA2_INT_LINE_RD_EN(x) ((x & 0x1) << 13) ++#define s_RGA2_INT_ALL_CMD_DONE_INT_EN(x) ((x & 0x1) << 10) ++#define s_RGA2_INT_MMU_INT_EN(x) ((x & 0x1) << 9) ++#define s_RGA2_INT_ERROR_INT_EN(x) ((x & 0x1) << 8) ++#define s_RGA2_INT_NOW_CMD_DONE_INT_CLEAR(x) ((x & 0x1) << 7) ++#define s_RGA2_INT_ALL_CMD_DONE_INT_CLEAR(x) ((x & 0x1) << 6) ++#define s_RGA2_INT_MMU_INT_CLEAR(x) ((x & 0x1) << 5) ++#define s_RGA2_INT_ERROR_INT_CLEAR(x) ((x & 0x1) << 4) ++ ++/* RGA_STATUS2 hardware status */ ++#define m_RGA2_STATUS2_RPP_MKRAM_RREADY (0x2 << 11) ++#define m_RGA2_STATUS2_DSTRPP_OUTBUF_RREADY (0x1f << 6) ++#define m_RGA2_STATUS2_SRCRPP_OUTBUF_RREADY (0xf << 2) ++#define m_RGA2_STATUS2_BUS_ERROR (0x1 << 1) ++#define m_RGA2_STATUS2_RPP_ERROR (0x1 << 0) ++ ++/* RGA_READ_LINE_CNT_TH */ ++#define m_RGA2_READ_LINE_SW_INTR_LINE_RD_TH (0x1fff << 0) ++ ++#define s_RGA2_READ_LINE_SW_INTR_LINE_RD_TH(x) ((x & 0x1fff) << 0) ++ ++/* RGA_WRITE_LINE_CNT_TN */ ++#define m_RGA2_WRITE_LINE_SW_INTR_LINE_WR_START (0x1fff << 0) ++#define m_RGA2_WRITE_LINE_SW_INTR_LINE_WR_STEP (0x1fff << 16) ++ ++#define s_RGA2_WRITE_LINE_SW_INTR_LINE_WR_START(x) ((x & 0x1fff) << 0) ++#define s_RGA2_WRITE_LINE_SW_INTR_LINE_WR_STEP(x) ((x & 0x1fff) << 16) ++ ++/* RGA_MODE_CTRL */ ++#define m_RGA2_MODE_CTRL_SW_RENDER_MODE (0x7 << 0) ++#define m_RGA2_MODE_CTRL_SW_BITBLT_MODE (0x1 << 3) ++#define m_RGA2_MODE_CTRL_SW_CF_ROP4_PAT (0x1 << 4) ++#define m_RGA2_MODE_CTRL_SW_ALPHA_ZERO_KET (0x1 << 5) ++#define m_RGA2_MODE_CTRL_SW_GRADIENT_SAT (0x1 << 6) ++#define m_RGA2_MODE_CTRL_SW_INTR_CF_E (0x1 << 7) ++#define m_RGA2_MODE_CTRL_SW_OSD_E (0x1<<8) ++#define m_RGA2_MODE_CTRL_SW_MOSAIC_EN (0x1<<9) ++#define m_RGA2_MODE_CTRL_SW_YIN_YOUT_EN (0x1<<10) ++ ++#define s_RGA2_MODE_CTRL_SW_RENDER_MODE(x) ((x & 0x7) << 0) ++#define s_RGA2_MODE_CTRL_SW_BITBLT_MODE(x) ((x & 0x1) << 3) ++#define s_RGA2_MODE_CTRL_SW_CF_ROP4_PAT(x) ((x & 0x1) << 4) ++#define s_RGA2_MODE_CTRL_SW_ALPHA_ZERO_KET(x) ((x & 0x1) << 5) ++#define s_RGA2_MODE_CTRL_SW_GRADIENT_SAT(x) ((x & 0x1) << 6) ++#define s_RGA2_MODE_CTRL_SW_INTR_CF_E(x) ((x & 0x1) << 7) ++#define s_RGA2_MODE_CTRL_SW_OSD_E(x) ((x & 0x1) << 8) ++#define s_RGA2_MODE_CTRL_SW_MOSAIC_EN(x) ((x & 0x1) << 9) ++#define s_RGA2_MODE_CTRL_SW_YIN_YOUT_EN(x) ((x & 0x1) << 10) ++/* RGA_SRC_INFO */ ++#define m_RGA2_SRC_INFO_SW_SRC_FMT (0xf << 0) ++#define m_RGA2_SRC_INFO_SW_SW_SRC_RB_SWAP (0x1 << 4) ++#define m_RGA2_SRC_INFO_SW_SW_SRC_ALPHA_SWAP (0x1 << 5) ++#define m_RGA2_SRC_INFO_SW_SW_SRC_UV_SWAP (0x1 << 6) ++#define m_RGA2_SRC_INFO_SW_SW_CP_ENDIAN (0x1 << 7) ++#define m_RGA2_SRC_INFO_SW_SW_SRC_CSC_MODE (0x3 << 8) ++#define m_RGA2_SRC_INFO_SW_SW_SRC_ROT_MODE (0x3 << 10) ++#define m_RGA2_SRC_INFO_SW_SW_SRC_MIR_MODE (0x3 << 12) ++#define m_RGA2_SRC_INFO_SW_SW_SRC_HSCL_MODE (0x3 << 14) ++#define m_RGA2_SRC_INFO_SW_SW_SRC_VSCL_MODE (0x3 << 16) ++#define m_RGA2_SRC_INFO_SW_SW_SRC_TRANS_MODE (0x1 << 18) ++#define m_RGA2_SRC_INFO_SW_SW_SRC_TRANS_E (0xf << 19) ++#define m_RGA2_SRC_INFO_SW_SW_SRC_DITHER_UP_E (0x1 << 23) ++#define m_RGA2_SRC_INFO_SW_SW_SRC_SCL_FILTER (0x3 << 24) ++#define m_RGA2_SRC_INFO_SW_SW_VSP_MODE_SEL (0x1 << 26) ++#define m_RGA2_SRC_INFO_SW_SW_YUV10_E (0x1 << 27) ++#define m_RGA2_SRC_INFO_SW_SW_YUV10_ROUND_E (0x1 << 28) ++ ++ ++#define s_RGA2_SRC_INFO_SW_SRC_FMT(x) ((x & 0xf) << 0) ++#define s_RGA2_SRC_INFO_SW_SW_SRC_RB_SWAP(x) ((x & 0x1) << 4) ++#define s_RGA2_SRC_INFO_SW_SW_SRC_ALPHA_SWAP(x) ((x & 0x1) << 5) ++#define s_RGA2_SRC_INFO_SW_SW_SRC_UV_SWAP(x) ((x & 0x1) << 6) ++#define s_RGA2_SRC_INFO_SW_SW_CP_ENDAIN(x) ((x & 0x1) << 7) ++#define s_RGA2_SRC_INFO_SW_SW_SRC_CSC_MODE(x) ((x & 0x3) << 8) ++#define s_RGA2_SRC_INFO_SW_SW_SRC_ROT_MODE(x) ((x & 0x3) << 10) ++#define s_RGA2_SRC_INFO_SW_SW_SRC_MIR_MODE(x) ((x & 0x3) << 12) ++#define s_RGA2_SRC_INFO_SW_SW_SRC_HSCL_MODE(x) ((x & 0x3) << 14) ++#define s_RGA2_SRC_INFO_SW_SW_SRC_VSCL_MODE(x) ((x & 0x3) << 16) ++ ++#define s_RGA2_SRC_INFO_SW_SW_SRC_TRANS_MODE(x) ((x & 0x1) << 18) ++#define s_RGA2_SRC_INFO_SW_SW_SRC_TRANS_E(x) ((x & 0xf) << 19) ++#define s_RGA2_SRC_INFO_SW_SW_SRC_DITHER_UP_E(x) ((x & 0x1) << 23) ++#define s_RGA2_SRC_INFO_SW_SW_SRC_SCL_FILTER(x) ((x & 0x3) << 24) ++#define s_RGA2_SRC_INFO_SW_SW_VSP_MODE_SEL(x) ((x & 0x1) << 26) ++#define s_RGA2_SRC_INFO_SW_SW_YUV10_E(x) ((x & 0x1) << 27) ++#define s_RGA2_SRC_INFO_SW_SW_YUV10_ROUND_E(x) ((x & 0x1) << 28) ++ ++/* RGA_SRC_VIR_INFO */ ++#define m_RGA2_SRC_VIR_INFO_SW_SRC_VIR_STRIDE (0x7fff << 0) ++#define m_RGA2_SRC_VIR_INFO_SW_MASK_VIR_STRIDE (0x3ff << 16) ++ ++#define s_RGA2_SRC_VIR_INFO_SW_SRC_VIR_STRIDE(x) ((x & 0x7fff) << 0) ++#define s_RGA2_SRC_VIR_INFO_SW_MASK_VIR_STRIDE(x) ((x & 0x3ff) << 16) ++ ++ ++/* RGA_SRC_ACT_INFO */ ++#define m_RGA2_SRC_ACT_INFO_SW_SRC_ACT_WIDTH (0x1fff << 0) ++#define m_RGA2_SRC_ACT_INFO_SW_SRC_ACT_HEIGHT (0x1fff << 16) ++ ++#define s_RGA2_SRC_ACT_INFO_SW_SRC_ACT_WIDTH(x) ((x & 0x1fff) << 0) ++#define s_RGA2_SRC_ACT_INFO_SW_SRC_ACT_HEIGHT(x) ((x & 0x1fff) << 16) ++ ++/* RGA2_OSD_CTRL0 */ ++#define m_RGA2_OSD_CTRL0_SW_OSD_MODE (0x3 << 0) ++#define m_RGA2_OSD_CTRL0_SW_OSD_VER_MODE (0x1 << 2) ++#define m_RGA2_OSD_CTRL0_SW_OSD_WIDTH_MODE (0x1 << 3) ++#define m_RGA2_OSD_CTRL0_SW_OSD_BLK_NUM (0x1f << 4) ++#define m_RGA2_OSD_CTRL0_SW_OSD_FLAGS_INDEX (0x3f << 10) ++#define m_RGA2_OSD_CTRL0_SW_OSD_FIX_WIDTH (0x3f << 20) ++#define m_RGA2_OSD_CTRL0_SW_OSD_2BPP_MODE (0x1 << 30) ++ ++#define s_RGA2_OSD_CTRL0_SW_OSD_MODE(x) ((x & 0x3) << 0) ++#define s_RGA2_OSD_CTRL0_SW_OSD_VER_MODE(x) ((x & 0x1) << 2) ++#define s_RGA2_OSD_CTRL0_SW_OSD_WIDTH_MODE(x) ((x & 0x1) << 3) ++#define s_RGA2_OSD_CTRL0_SW_OSD_BLK_NUM(x) ((x & 0x1f) << 4) ++#define s_RGA2_OSD_CTRL0_SW_OSD_FLAGS_INDEX(x) ((x & 0x3ff) << 10) ++#define s_RGA2_OSD_CTRL0_SW_OSD_FIX_WIDTH(x) ((x & 0x3ff) << 20) ++#define s_RGA2_OSD_CTRL0_SW_OSD_2BPP_MODE(x) ((x & 0x1) << 30) ++ ++/* RGA2_OSD_CTRL1 */ ++#define m_RGA2_OSD_CTRL1_SW_OSD_COLOR_SEL (0x1 << 0) ++#define m_RGA2_OSD_CTRL1_SW_OSD_FLAG_SEL (0x1 << 1) ++#define m_RGA2_OSD_CTRL1_SW_OSD_DEFAULT_COLOR (0x1 << 2) ++#define m_RGA2_OSD_CTRL1_SW_OSD_AUTO_INVERST_MODE (0x1 << 3) ++#define m_RGA2_OSD_CTRL1_SW_OSD_THRESH (0xff << 4) ++#define m_RGA2_OSD_CTRL1_SW_OSD_INVERT_A_EN (0x1 << 12) ++#define m_RGA2_OSD_CTRL1_SW_OSD_INVERT_Y_DIS (0x1 << 13) ++#define m_RGA2_OSD_CTRL1_SW_OSD_INVERT_C_DIS (0x1 << 14) ++#define m_RGA2_OSD_CTRL1_SW_OSD_UNFIX_INDEX (0xf << 16) ++ ++#define s_RGA2_OSD_CTRL1_SW_OSD_COLOR_SEL(x) ((x & 0x1) << 0) ++#define s_RGA2_OSD_CTRL1_SW_OSD_FLAG_SEL(x) ((x & 0x1) << 1) ++#define s_RGA2_OSD_CTRL1_SW_OSD_DEFAULT_COLOR(x) ((x & 0x1) << 2) ++#define s_RGA2_OSD_CTRL1_SW_OSD_AUTO_INVERST_MODE(x) ((x & 0x1) << 3) ++#define s_RGA2_OSD_CTRL1_SW_OSD_THRESH(x) ((x & 0xff) << 4) ++#define s_RGA2_OSD_CTRL1_SW_OSD_INVERT_A_EN(x) ((x & 0x1) << 12) ++#define s_RGA2_OSD_CTRL1_SW_OSD_INVERT_Y_DIS(x) ((x & 0x1) << 13) ++#define s_RGA2_OSD_CTRL1_SW_OSD_INVERT_C_DIS(x) ((x & 0x1) << 14) ++#define s_RGA2_OSD_CTRL1_SW_OSD_UNFIX_INDEX(x) ((x & 0xf) << 16) ++ ++/* RGA_DST_INFO */ ++#define m_RGA2_DST_INFO_SW_DST_FMT (0xf << 0) ++#define m_RGA2_DST_INFO_SW_DST_RB_SWAP (0x1 << 4) ++#define m_RGA2_DST_INFO_SW_ALPHA_SWAP (0x1 << 5) ++#define m_RGA2_DST_INFO_SW_DST_UV_SWAP (0x1 << 6) ++#define m_RGA2_DST_INFO_SW_SRC1_FMT (0x7 << 7) ++#define m_RGA2_DST_INFO_SW_SRC1_RB_SWP (0x1 << 10) ++#define m_RGA2_DST_INFO_SW_SRC1_ALPHA_SWP (0x1 << 11) ++#define m_RGA2_DST_INFO_SW_DITHER_UP_E (0x1 << 12) ++#define m_RGA2_DST_INFO_SW_DITHER_DOWN_E (0x1 << 13) ++#define m_RGA2_DST_INFO_SW_DITHER_MODE (0x3 << 14) ++#define m_RGA2_DST_INFO_SW_DST_CSC_MODE (0x3 << 16) ++#define m_RGA2_DST_INFO_SW_CSC_CLIP_MODE (0x1 << 18) ++#define m_RGA2_DST_INFO_SW_DST_CSC_MODE_2 (0x1 << 19) ++#define m_RGA2_DST_INFO_SW_SRC1_CSC_MODE (0x3 << 20) ++#define m_RGA2_DST_INFO_SW_SRC1_CSC_CLIP_MODE (0x1 << 22) ++#define m_RGA2_DST_INFO_SW_DST_UVHDS_MODE (0x1 << 23) ++#define m_RGA2_DST_INFO_SW_DST_FMT_YUV400_EN (0x1 << 24) ++#define m_RGA2_DST_INFO_SW_DST_FMT_Y4_EN (0x1 << 25) ++#define m_RGA2_DST_INFO_SW_DST_NN_QUANTIZE_EN (0x1 << 26) ++#define m_RGA2_DST_INFO_SW_DST_UVVDS_MODE (0x1 << 27) ++ ++#define s_RGA2_DST_INFO_SW_DST_FMT(x) ((x & 0xf) << 0) ++#define s_RGA2_DST_INFO_SW_DST_RB_SWAP(x) ((x & 0x1) << 4) ++#define s_RGA2_DST_INFO_SW_ALPHA_SWAP(x) ((x & 0x1) << 5) ++#define s_RGA2_DST_INFO_SW_DST_UV_SWAP(x) ((x & 0x1) << 6) ++#define s_RGA2_DST_INFO_SW_SRC1_FMT(x) ((x & 0x7) << 7) ++#define s_RGA2_DST_INFO_SW_SRC1_RB_SWP(x) ((x & 0x1) << 10) ++#define s_RGA2_DST_INFO_SW_SRC1_ALPHA_SWP(x) ((x & 0x1) << 11) ++#define s_RGA2_DST_INFO_SW_DITHER_UP_E(x) ((x & 0x1) << 12) ++#define s_RGA2_DST_INFO_SW_DITHER_DOWN_E(x) ((x & 0x1) << 13) ++#define s_RGA2_DST_INFO_SW_DITHER_MODE(x) ((x & 0x3) << 14) ++#define s_RGA2_DST_INFO_SW_DST_CSC_MODE(x) ((x & 0x3) << 16) ++#define s_RGA2_DST_INFO_SW_CSC_CLIP_MODE(x) ((x & 0x1) << 18) ++#define s_RGA2_DST_INFO_SW_DST_CSC_MODE_2(x) ((x & 0x1) << 19) ++#define s_RGA2_DST_INFO_SW_SRC1_CSC_MODE(x) ((x & 0x3) << 20) ++#define s_RGA2_DST_INFO_SW_SRC1_CSC_CLIP_MODE(x) ((x & 0x1) << 22) ++#define s_RGA2_DST_INFO_SW_DST_UVHDS_MODE(x) ((x & 0x1) << 23) ++#define s_RGA2_DST_INFO_SW_DST_FMT_YUV400_EN(x) ((x & 0x1) << 24) ++#define s_RGA2_DST_INFO_SW_DST_FMT_Y4_EN(x) ((x & 0x1) << 25) ++#define s_RGA2_DST_INFO_SW_DST_NN_QUANTIZE_EN(x) ((x & 0x1) << 26) ++#define s_RGA2_DST_INFO_SW_DST_UVVDS_MODE(x) ((x & 0x1) << 27) ++ ++ ++/* RGA_ALPHA_CTRL0 */ ++#define m_RGA2_ALPHA_CTRL0_SW_ALPHA_ROP_0 (0x1 << 0) ++#define m_RGA2_ALPHA_CTRL0_SW_ALPHA_ROP_SEL (0x1 << 1) ++#define m_RGA2_ALPHA_CTRL0_SW_ROP_MODE (0x3 << 2) ++#define m_RGA2_ALPHA_CTRL0_SW_SRC_GLOBAL_ALPHA (0xff << 4) ++#define m_RGA2_ALPHA_CTRL0_SW_DST_GLOBAL_ALPHA (0xff << 12) ++#define m_RGA2_ALPHA_CTRLO_SW_MASK_ENDIAN (0x1 << 20) ++ ++#define s_RGA2_ALPHA_CTRL0_SW_ALPHA_ROP_0(x) ((x & 0x1) << 0) ++#define s_RGA2_ALPHA_CTRL0_SW_ALPHA_ROP_SEL(x) ((x & 0x1) << 1) ++#define s_RGA2_ALPHA_CTRL0_SW_ROP_MODE(x) ((x & 0x3) << 2) ++#define s_RGA2_ALPHA_CTRL0_SW_SRC_GLOBAL_ALPHA(x) ((x & 0xff) << 4) ++#define s_RGA2_ALPHA_CTRL0_SW_DST_GLOBAL_ALPHA(x) ((x & 0xff) << 12) ++#define s_RGA2_ALPHA_CTRLO_SW_MASK_ENDIAN(x) ((x & 0x1) << 20) ++ ++ ++ ++/* RGA_ALPHA_CTRL1 */ ++#define m_RGA2_ALPHA_CTRL1_SW_DST_COLOR_M0 (0x1 << 0) ++#define m_RGA2_ALPHA_CTRL1_SW_SRC_COLOR_M0 (0x1 << 1) ++#define m_RGA2_ALPHA_CTRL1_SW_DST_FACTOR_M0 (0x7 << 2) ++#define m_RGA2_ALPHA_CTRL1_SW_SRC_FACTOR_M0 (0x7 << 5) ++#define m_RGA2_ALPHA_CTRL1_SW_DST_ALPHA_CAL_M0 (0x1 << 8) ++#define m_RGA2_ALPHA_CTRL1_SW_SRC_ALPHA_CAL_M0 (0x1 << 9) ++#define m_RGA2_ALPHA_CTRL1_SW_DST_BLEND_M0 (0x3 << 10) ++#define m_RGA2_ALPHA_CTRL1_SW_SRC_BLEND_M0 (0x3 << 12) ++#define m_RGA2_ALPHA_CTRL1_SW_DST_ALPHA_M0 (0x1 << 14) ++#define m_RGA2_ALPHA_CTRL1_SW_SRC_ALPHA_M0 (0x1 << 15) ++#define m_RGA2_ALPHA_CTRL1_SW_DST_FACTOR_M1 (0x7 << 16) ++#define m_RGA2_ALPHA_CTRL1_SW_SRC_FACTOR_M1 (0x7 << 19) ++#define m_RGA2_ALPHA_CTRL1_SW_DST_ALPHA_CAL_M1 (0x1 << 22) ++#define m_RGA2_ALPHA_CTRL1_SW_SRC_ALPHA_CAL_M1 (0x1 << 23) ++#define m_RGA2_ALPHA_CTRL1_SW_DST_BLEND_M1 (0x3 << 24) ++#define m_RGA2_ALPHA_CTRL1_SW_SRC_BLEND_M1 (0x3 << 26) ++#define m_RGA2_ALPHA_CTRL1_SW_DST_ALPHA_M1 (0x1 << 28) ++#define m_RGA2_ALPHA_CTRL1_SW_SRC_ALPHA_M1 (0x1 << 29) ++ ++#define s_RGA2_ALPHA_CTRL1_SW_DST_COLOR_M0(x) ((x & 0x1) << 0) ++#define s_RGA2_ALPHA_CTRL1_SW_SRC_COLOR_M0(x) ((x & 0x1) << 1) ++#define s_RGA2_ALPHA_CTRL1_SW_DST_FACTOR_M0(x) ((x & 0x7) << 2) ++#define s_RGA2_ALPHA_CTRL1_SW_SRC_FACTOR_M0(x) ((x & 0x7) << 5) ++#define s_RGA2_ALPHA_CTRL1_SW_DST_ALPHA_CAL_M0(x) ((x & 0x1) << 8) ++#define s_RGA2_ALPHA_CTRL1_SW_SRC_ALPHA_CAL_M0(x) ((x & 0x1) << 9) ++#define s_RGA2_ALPHA_CTRL1_SW_DST_BLEND_M0(x) ((x & 0x3) << 10) ++#define s_RGA2_ALPHA_CTRL1_SW_SRC_BLEND_M0(x) ((x & 0x3) << 12) ++#define s_RGA2_ALPHA_CTRL1_SW_DST_ALPHA_M0(x) ((x & 0x1) << 14) ++#define s_RGA2_ALPHA_CTRL1_SW_SRC_ALPHA_M0(x) ((x & 0x1) << 15) ++#define s_RGA2_ALPHA_CTRL1_SW_DST_FACTOR_M1(x) ((x & 0x7) << 16) ++#define s_RGA2_ALPHA_CTRL1_SW_SRC_FACTOR_M1(x) ((x & 0x7) << 19) ++#define s_RGA2_ALPHA_CTRL1_SW_DST_ALPHA_CAL_M1(x) ((x & 0x1) << 22) ++#define s_RGA2_ALPHA_CTRL1_SW_SRC_ALPHA_CAL_M1(x) ((x & 0x1) << 23) ++#define s_RGA2_ALPHA_CTRL1_SW_DST_BLEND_M1(x) ((x & 0x3) << 24) ++#define s_RGA2_ALPHA_CTRL1_SW_SRC_BLEND_M1(x) ((x & 0x3) << 26) ++#define s_RGA2_ALPHA_CTRL1_SW_DST_ALPHA_M1(x) ((x & 0x1) << 28) ++#define s_RGA2_ALPHA_CTRL1_SW_SRC_ALPHA_M1(x) ((x & 0x1) << 29) ++ ++ ++ ++/* RGA_MMU_CTRL1 */ ++#define m_RGA2_MMU_CTRL1_SW_SRC_MMU_EN (0x1 << 0) ++#define m_RGA2_MMU_CTRL1_SW_SRC_MMU_FLUSH (0x1 << 1) ++#define m_RGA2_MMU_CTRL1_SW_SRC_MMU_PREFETCH_EN (0x1 << 2) ++#define m_RGA2_MMU_CTRL1_SW_SRC_MMU_PREFETCH_DIR (0x1 << 3) ++#define m_RGA2_MMU_CTRL1_SW_SRC1_MMU_EN (0x1 << 4) ++#define m_RGA2_MMU_CTRL1_SW_SRC1_MMU_FLUSH (0x1 << 5) ++#define m_RGA2_MMU_CTRL1_SW_SRC1_MMU_PREFETCH_EN (0x1 << 6) ++#define m_RGA2_MMU_CTRL1_SW_SRC1_MMU_PREFETCH_DIR (0x1 << 7) ++#define m_RGA2_MMU_CTRL1_SW_DST_MMU_EN (0x1 << 8) ++#define m_RGA2_MMU_CTRL1_SW_DST_MMU_FLUSH (0x1 << 9) ++#define m_RGA2_MMU_CTRL1_SW_DST_MMU_PREFETCH_EN (0x1 << 10) ++#define m_RGA2_MMU_CTRL1_SW_DST_MMU_PREFETCH_DIR (0x1 << 11) ++#define m_RGA2_MMU_CTRL1_SW_ELS_MMU_EN (0x1 << 12) ++#define m_RGA2_MMU_CTRL1_SW_ELS_MMU_FLUSH (0x1 << 13) ++ ++#define s_RGA2_MMU_CTRL1_SW_SRC_MMU_EN(x) ((x & 0x1) << 0) ++#define s_RGA2_MMU_CTRL1_SW_SRC_MMU_FLUSH(x) ((x & 0x1) << 1) ++#define s_RGA2_MMU_CTRL1_SW_SRC_MMU_PREFETCH_EN(x) ((x & 0x1) << 2) ++#define s_RGA2_MMU_CTRL1_SW_SRC_MMU_PREFETCH_DIR(x) ((x & 0x1) << 3) ++#define s_RGA2_MMU_CTRL1_SW_SRC1_MMU_EN(x) ((x & 0x1) << 4) ++#define s_RGA2_MMU_CTRL1_SW_SRC1_MMU_FLUSH(x) ((x & 0x1) << 5) ++#define s_RGA2_MMU_CTRL1_SW_SRC1_MMU_PREFETCH_EN(x) ((x & 0x1) << 6) ++#define s_RGA2_MMU_CTRL1_SW_SRC1_MMU_PREFETCH_DIR(x) ((x & 0x1) << 7) ++#define s_RGA2_MMU_CTRL1_SW_DST_MMU_EN(x) ((x & 0x1) << 8) ++#define s_RGA2_MMU_CTRL1_SW_DST_MMU_FLUSH(x) ((x & 0x1) << 9) ++#define s_RGA2_MMU_CTRL1_SW_DST_MMU_PREFETCH_EN(x) ((x & 0x1) << 10) ++#define s_RGA2_MMU_CTRL1_SW_DST_MMU_PREFETCH_DIR(x) ((x & 0x1) << 11) ++#define s_RGA2_MMU_CTRL1_SW_ELS_MMU_EN(x) ((x & 0x1) << 12) ++#define s_RGA2_MMU_CTRL1_SW_ELS_MMU_FLUSH(x) ((x & 0x1) << 13) ++ ++#define RGA2_VSP_BICUBIC_LIMIT 1996 ++ ++union rga2_color_ctrl { ++ uint32_t value; ++ struct { ++ uint32_t dst_color_mode:1; ++ uint32_t src_color_mode:1; ++ ++ uint32_t dst_factor_mode:3; ++ uint32_t src_factor_mode:3; ++ ++ uint32_t dst_alpha_cal_mode:1; ++ uint32_t src_alpha_cal_mode:1; ++ ++ uint32_t dst_blend_mode:2; ++ uint32_t src_blend_mode:2; ++ ++ uint32_t dst_alpha_mode:1; ++ uint32_t src_alpha_mode:1; ++ } bits; ++}; ++ ++union rga2_alpha_ctrl { ++ uint32_t value; ++ struct { ++ uint32_t dst_factor_mode:3; ++ uint32_t src_factor_mode:3; ++ ++ uint32_t dst_alpha_cal_mode:1; ++ uint32_t src_alpha_cal_mode:1; ++ ++ uint32_t dst_blend_mode:2; ++ uint32_t src_blend_mode:2; ++ ++ uint32_t dst_alpha_mode:1; ++ uint32_t src_alpha_mode:1; ++ } bits; ++}; ++ ++extern const struct rga_backend_ops rga2_ops; ++ ++#endif ++ +diff --git a/drivers/video/rockchip/rga3/include/rga3_reg_info.h b/drivers/video/rockchip/rga3/include/rga3_reg_info.h +new file mode 100644 +index 000000000..4db80cfb0 +--- /dev/null ++++ b/drivers/video/rockchip/rga3/include/rga3_reg_info.h +@@ -0,0 +1,521 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __REG3_INFO_H__ ++#define __REG3_INFO_H__ ++ ++#include "rga_drv.h" ++ ++/* sys reg */ ++#define RGA3_SYS_CTRL 0x000 ++#define RGA3_CMD_CTRL 0x004 ++#define RGA3_CMD_ADDR 0x008 ++#define RGA3_MI_GROUP_CTRL 0x00c ++#define RGA3_ARQOS_CTRL 0x010 ++#define RGA3_VERSION_NUM 0x018 ++#define RGA3_VERSION_TIM 0x01c ++#define RGA3_INT_EN 0x020 ++#define RGA3_INT_RAW 0x024 ++#define RGA3_INT_MSK 0x028 ++#define RGA3_INT_CLR 0x02c ++#define RGA3_RO_SRST 0x030 ++#define RGA3_STATUS0 0x034 ++#define RGA3_SCAN_CNT 0x038 ++#define RGA3_CMD_STATE 0x040 ++ ++/* cmd reg */ ++#define RGA3_WIN0_RD_CTRL_OFFSET 0x000 ++#define RGA3_WIN0_Y_BASE_OFFSET 0x010 ++#define RGA3_WIN0_U_BASE_OFFSET 0x014 ++#define RGA3_WIN0_V_BASE_OFFSET 0x018 ++#define RGA3_WIN0_VIR_STRIDE_OFFSET 0x01c ++#define RGA3_WIN0_FBC_OFF_OFFSET 0x020 ++#define RGA3_WIN0_SRC_SIZE_OFFSET 0x024 ++#define RGA3_WIN0_ACT_OFF_OFFSET 0x028 ++#define RGA3_WIN0_ACT_SIZE_OFFSET 0x02c ++#define RGA3_WIN0_DST_SIZE_OFFSET 0x030 ++#define RGA3_WIN0_SCL_FAC_OFFSET 0x034 ++#define RGA3_WIN0_UV_VIR_STRIDE_OFFSET 0x038 ++#define RGA3_WIN1_RD_CTRL_OFFSET 0x040 ++#define RGA3_WIN1_Y_BASE_OFFSET 0x050 ++#define RGA3_WIN1_U_BASE_OFFSET 0x054 ++#define RGA3_WIN1_V_BASE_OFFSET 0x058 ++#define RGA3_WIN1_VIR_STRIDE_OFFSET 0x05c ++#define RGA3_WIN1_FBC_OFF_OFFSET 0x060 ++#define RGA3_WIN1_SRC_SIZE_OFFSET 0x064 ++#define RGA3_WIN1_ACT_OFF_OFFSET 0x068 ++#define RGA3_WIN1_ACT_SIZE_OFFSET 0x06c ++#define RGA3_WIN1_DST_SIZE_OFFSET 0x070 ++#define RGA3_WIN1_SCL_FAC_OFFSET 0x074 ++#define RGA3_WIN1_UV_VIR_STRIDE_OFFSET 0x078 ++#define RGA3_OVLP_CTRL_OFFSET 0x080 ++#define RGA3_OVLP_OFF_OFFSET 0x084 ++#define RGA3_OVLP_TOP_KEY_MIN_OFFSET 0x088 ++#define RGA3_OVLP_TOP_KEY_MAX_OFFSET 0x08c ++#define RGA3_OVLP_TOP_CTRL_OFFSET 0x090 ++#define RGA3_OVLP_BOT_CTRL_OFFSET 0x094 ++#define RGA3_OVLP_TOP_ALPHA_OFFSET 0x098 ++#define RGA3_OVLP_BOT_ALPHA_OFFSET 0x09c ++#define RGA3_WR_CTRL_OFFSET 0x0a0 ++#define RGA3_WR_FBCE_CTRL_OFFSET 0x0a4 ++#define RGA3_WR_VIR_STRIDE_OFFSET 0x0a8 ++#define RGA3_WR_PL_VIR_STRIDE_OFFSET 0x0ac ++#define RGA3_WR_Y_BASE_OFFSET 0x0b0 ++#define RGA3_WR_U_BASE_OFFSET 0x0b4 ++#define RGA3_WR_V_BASE_OFFSET 0x0b8 ++ ++/* RGA3_SYS_CTRL */ ++#define m_RGA3_SYS_CTRL_FRMEND_AUTO_RSTN_EN (0x1 << 11) ++#define m_RGA3_SYS_CTRL_RGA_BIC_MODE (0x3 << 9) ++#define m_RGA3_SYS_CTRL_RGA_RAM_CLK_ON (0x1 << 8) ++#define m_RGA3_SYS_CTRL_CCLK_SRESET (0x1 << 4) ++#define m_RGA3_SYS_CTRL_ACLK_SRESET (0x1 << 3) ++#define m_RGA3_SYS_CTRL_RGA_LGC_CLK_ON (0x1 << 2) ++#define m_RGA3_SYS_CTRL_CMD_MODE (0x1 << 1) ++#define m_RGA3_SYS_CTRL_RGA_SART (0x1 << 0) ++ ++#define s_RGA3_SYS_CTRL_RGA_BIC_MODE(x) ((x & 0x3) << 9) ++#define s_RGA3_SYS_CTRL_CCLK_SRESET(x) ((x & 0x1) << 4) ++#define s_RGA3_SYS_CTRL_ACLK_SRESET(x) ((x & 0x1) << 3) ++#define s_RGA3_SYS_CTRL_CMD_MODE(x) ((x & 0x1) << 1) ++ ++/* TODO: RGA3_INT_EN/RGA3_INT_RAW/RGA3_INT_MSK/RGA3_INT_CLR */ ++#define m_RGA3_INT_WIN1_VOR_FIFO_REN_ERR (0x1 << 29) ++#define m_RGA3_INT_WIN1_VOR_FIFO_WEN_ERR (0x1 << 28) ++#define m_RGA3_INT_WIN1_HOR_FIFO_REN_ERR (0x1 << 27) ++#define m_RGA3_INT_WIN1_HOR_FIFO_WEN_ERR (0x1 << 26) ++#define m_RGA3_INT_WIN1_IN_FIFO_REB_ERR (0x1 << 25) ++#define m_RGA3_INT_WIN1_IN_FIFO_WEN_ERR (0x1 << 24) ++#define m_RGA3_INT_WIN0_VOR_FIFO_REN_ERR (0x1 << 21) ++#define m_RGA3_INT_WIN0_VOR_FIFO_WEN_ERR (0x1 << 20) ++#define m_RGA3_INT_WIN0_HOR_FIFO_REN_ERR (0x1 << 19) ++#define m_RGA3_INT_WIN0_HOR_FIFO_WEN_ERR (0x1 << 18) ++#define m_RGA3_INT_WIN0_IN_FIFO_REB_ERR (0x1 << 17) ++#define m_RGA3_INT_WIN0_IN_FIFO_WEN_ERR (0x1 << 16) ++#define m_RGA3_INT_RGA_MI_WR_BUS_ERR (0x1 << 15) ++#define m_RGA3_INT_RGA_MI_WR_IN_HERR (0x1 << 14) ++//The signal is invalid, it will be pulled up every time, no need to care. ++// #define m_RGA3_INT_RGA_MI_WR_IN_VERR (0x1 << 13) ++#define m_RGA3_INT_WIN1_V_ERR (0x1 << 11) ++#define m_RGA3_INT_WIN1_H_ERR (0x1 << 10) ++#define m_RGA3_INT_WIN1_FBCD_DEC_ERR (0x1 << 9) ++#define m_RGA3_INT_WIN1_RD_FRM_END (0x1 << 8) //not error ++#define m_RGA3_INT_WIN0_V_ERR (0x1 << 7) ++#define m_RGA3_INT_WIN0_H_ERR (0x1 << 6) ++#define m_RGA3_INT_WIN0_FBCD_DEC_ERR (0x1 << 5) ++#define m_RGA3_INT_WIN0_RD_FRM_END (0x1 << 4) //not error ++#define m_RGA3_INT_CMD_LINE_FINISH (0x1 << 3) //not error ++#define m_RGA3_INT_RAG_MI_RD_BUS_ERR (0x1 << 2) ++#define m_RGA3_INT_RGA_MMU_INTR (0x1 << 1) ++#define m_RGA3_INT_FRM_DONE (0x1 << 0) //not error ++ ++#define m_RGA3_INT_ERROR_MASK \ ++ ( \ ++ m_RGA3_INT_RGA_MMU_INTR | \ ++ m_RGA3_INT_RAG_MI_RD_BUS_ERR | \ ++ m_RGA3_INT_WIN0_FBCD_DEC_ERR | \ ++ m_RGA3_INT_WIN0_H_ERR | \ ++ m_RGA3_INT_WIN0_V_ERR | \ ++ m_RGA3_INT_WIN1_FBCD_DEC_ERR | \ ++ m_RGA3_INT_WIN1_H_ERR | \ ++ m_RGA3_INT_WIN1_V_ERR | \ ++ m_RGA3_INT_RGA_MI_WR_IN_HERR | \ ++ m_RGA3_INT_RGA_MI_WR_BUS_ERR | \ ++ m_RGA3_INT_WIN0_IN_FIFO_WEN_ERR | \ ++ m_RGA3_INT_WIN0_IN_FIFO_REB_ERR | \ ++ m_RGA3_INT_WIN0_HOR_FIFO_WEN_ERR | \ ++ m_RGA3_INT_WIN0_HOR_FIFO_REN_ERR| \ ++ m_RGA3_INT_WIN0_VOR_FIFO_WEN_ERR | \ ++ m_RGA3_INT_WIN0_VOR_FIFO_REN_ERR | \ ++ m_RGA3_INT_WIN1_IN_FIFO_WEN_ERR | \ ++ m_RGA3_INT_WIN1_IN_FIFO_REB_ERR | \ ++ m_RGA3_INT_WIN1_HOR_FIFO_WEN_ERR | \ ++ m_RGA3_INT_WIN1_HOR_FIFO_REN_ERR| \ ++ m_RGA3_INT_WIN1_VOR_FIFO_WEN_ERR | \ ++ m_RGA3_INT_WIN1_VOR_FIFO_REN_ERR \ ++ ) ++ ++/* RGA3_CMD_CTRL */ ++#define m_RGA3_CMD_CTRL_CMD_INCR_NUM (0x3ff << 3) ++#define m_RGA3_CMD_CTRL_CMD_STOP_MODE (0x1 << 2) ++#define m_RGA3_CMD_CTRL_CMD_INCR_VALID_P (0x1 << 1) ++#define m_RGA3_CMD_CTRL_CMD_LINE_ST_P (0x1 << 0) ++ ++/* RGA3_RO_SRST */ ++#define m_RGA3_RO_SRST_RO_RST_DONE (0x3f << 0) ++ ++/* RGA3_CMD_STATE */ ++#define m_RGA3_CMD_STATE_CMD_CNT_CUR (0xfff << 16) ++#define m_RGA3_CMD_STATE_CMD_WORKING (0x1 << 0) ++ ++/* RGA3_WIN0_RD_CTRL */ ++#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_ENABLE (0x1 << 0) ++#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_RD_MODE (0x3 << 1) ++#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_PIC_FORMAT (0xf << 4) ++#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_RD_FORMAT (0x3 << 8) ++#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_YUV10B_COMPACT (0x1 << 10) ++#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_ENDIAN_MODE (0x1 << 11) ++#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_PIX_SWAP (0x1 << 12) ++#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_YC_SWAP (0x1 << 13) ++#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_ROT (0x1 << 16) ++#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_XMIRROR (0x1 << 17) ++#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_YMIRROR (0x1 << 18) ++#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_HOR_BY (0x1 << 20) ++#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_HOR_UP (0x1 << 21) ++#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_VER_BY (0x1 << 22) ++#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_VER_UP (0x1 << 23) ++#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_Y2R_EN (0x1 << 24) ++#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_R2Y_EN (0x1 << 25) ++#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_CSC_MODE (0x3 << 26) ++#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_PERF_OPT_DIS (0x1 << 29) ++#define m_RGA3_WIN0_RD_CTRL_SW_WIN0_RD_ALIGN_DIS (0x1 << 30) ++ ++#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_ENABLE(x) ((x & 0x1) << 0) ++#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_RD_MODE(x) ((x & 0x3) << 1) ++#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_PIC_FORMAT(x) ((x & 0xf) << 4) ++#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_RD_FORMAT(x) ((x & 0x3) << 8) ++#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_YUV10B_COMPACT(x) ((x & 0x1) << 10) ++#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_ENDIAN_MODE(x) ((x & 0x1) << 11) ++#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_PIX_SWAP(x) ((x & 0x1) << 12) ++#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_YC_SWAP(x) ((x & 0x1) << 13) ++#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_ROT(x) ((x & 0x1) << 16) ++#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_XMIRROR(x) ((x & 0x1) << 17) ++#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_YMIRROR(x) ((x & 0x1) << 18) ++#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_HOR_BY(x) ((x & 0x1) << 20) ++#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_HOR_UP(x) ((x & 0x1) << 21) ++#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_VER_BY(x) ((x & 0x1) << 22) ++#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_VER_UP(x) ((x & 0x1) << 23) ++#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_Y2R_EN(x) ((x & 0x1) << 24) ++#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_R2Y_EN(x) ((x & 0x1) << 25) ++#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_CSC_MODE(x) ((x & 0x3) << 26) ++#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_PERF_OPT_DIS(x) ((x & 0x1) << 29) ++#define s_RGA3_WIN0_RD_CTRL_SW_WIN0_RD_ALIGN_DIS(x) ((x & 0x1) << 30) ++ ++/* RGA3_WIN0_FBC_OFF */ ++#define m_RGA3_WIN0_FBC_OFF_SW_WIN0_FBC_XOFF (0x1fff << 0) ++#define m_RGA3_WIN0_FBC_OFF_SW_WIN0_FBC_YOFF (0x1fff << 16) ++ ++#define s_RGA3_WIN0_FBC_OFF_SW_WIN0_FBC_XOFF(x) ((x & 0x1fff) << 0) ++#define s_RGA3_WIN0_FBC_OFF_SW_WIN0_FBC_YOFF(x) ((x & 0x1fff) << 16) ++ ++/* RGA3_WIN0_SRC_SIZE */ ++#define m_RGA3_WIN0_SRC_SIZE_SW_WIN0_SRC_WIDTH (0x1fff << 0) ++#define m_RGA3_WIN0_SRC_SIZE_SW_WIN0_SRC_HEIGHT (0x1fff << 16) ++ ++#define s_RGA3_WIN0_SRC_OFF_SW_WIN0_SRC_WIDTH(x) ((x & 0x1fff) << 0) ++#define s_RGA3_WIN0_SRC_OFF_SW_WIN0_SRC_HEIGHT(x) ((x & 0x1fff) << 16) ++ ++/* RGA3_WIN0_ACT_OFF */ ++#define m_RGA3_WIN0_ACT_OFF_SW_WIN0_ACT_XOFF (0x1fff << 0) ++#define m_RGA3_WIN0_ACT_OFF_SW_WIN0_ACT_YOFF (0x1fff << 16) ++ ++#define s_RGA3_WIN0_ACT_OFF_SW_WIN0_ACT_XOFF(x) ((x & 0x1fff) << 0) ++#define s_RGA3_WIN0_ACT_OFF_SW_WIN0_ACT_YOFF(x) ((x & 0x1fff) << 16) ++ ++/* RGA3_WIN0_ACT_SIZE */ ++#define m_RGA3_WIN0_ACT_SIZE_SW_WIN0_ACT_WIDTH (0x1fff << 0) ++#define m_RGA3_WIN0_ACT_SIZE_SW_WIN0_ACT_HEIGHT (0x1fff << 16) ++ ++#define s_RGA3_WIN0_ACT_SIZE_SW_WIN0_ACT_WIDTH(x) ((x & 0x1fff) << 0) ++#define s_RGA3_WIN0_ACT_SIZE_SW_WIN0_ACT_HEIGHT(x) ((x & 0x1fff) << 16) ++ ++/* RGA3_WIN0_DST_SIZE */ ++#define m_RGA3_WIN0_DST_SIZE_SW_WIN0_DST_WIDTH (0x1fff << 0) ++#define m_RGA3_WIN0_DST_SIZE_SW_WIN0_DST_HEIGHT (0x1fff << 16) ++ ++#define s_RGA3_WIN0_DST_SIZE_SW_WIN0_DST_WIDTH(x) ((x & 0x1fff) << 0) ++#define s_RGA3_WIN0_DST_SIZE_SW_WIN0_DST_HEIGHT(x) ((x & 0x1fff) << 16) ++ ++/* RGA3_WIN0_SCL_FAC */ ++#define m_RGA3_WIN0_SCL_FAC_SW_WIN0_VER_FAC (0xffff << 0) ++#define m_RGA3_WIN0_SCL_FAC_SW_WIN0_HOR_FAC (0xffff << 16) ++ ++#define s_RGA3_WIN0_SCL_FAC_SW_WIN0_VER_FAC(x) ((x & 0xffff) << 0) ++#define s_RGA3_WIN0_SCL_FAC_SW_WIN0_HOR_FAC(x) ((x & 0xffff) << 16) ++ ++/* RGA3_WIN1_RD_CTRL */ ++#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_ENABLE (0x1 << 0) ++#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_RD_MODE (0x3 << 1) ++#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_PIC_FORMAT (0xf << 4) ++#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_RD_FORMAT (0x3 << 8) ++#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_YUV10B_COMPACT (0x1 << 10) ++#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_ENDIAN_MODE (0x1 << 11) ++#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_PIX_SWAP (0x1 << 12) ++#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_YC_SWAP (0x1 << 13) ++#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_ROT (0x1 << 16) ++#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_XMIRROR (0x1 << 17) ++#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_YMIRROR (0x1 << 18) ++#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_HOR_BY (0x1 << 20) ++#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_HOR_UP (0x1 << 21) ++#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_VER_BY (0x1 << 22) ++#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_VER_UP (0x1 << 23) ++#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_Y2R_EN (0x1 << 24) ++#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_R2Y_EN (0x1 << 25) ++#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_CSC_MODE (0x3 << 26) ++#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_PERF_OPT_DIS (0x1 << 29) ++#define m_RGA3_WIN1_RD_CTRL_SW_WIN1_RD_ALIGN_DIS (0x1 << 30) ++ ++#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_ENABLE(x) ((x & 0x1) << 0) ++#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_RD_MODE(x) ((x & 0x3) << 1) ++#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_PIC_FORMAT(x) ((x & 0xf) << 4) ++#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_RD_FORMAT(x) ((x & 0x3) << 8) ++#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_YUV10B_COMPACT(x) ((x & 0x1) << 10) ++#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_ENDIAN_MODE(x) ((x & 0x1) << 11) ++#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_PIX_SWAP(x) ((x & 0x1) << 12) ++#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_YC_SWAP(x) ((x & 0x1) << 13) ++#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_ROT(x) ((x & 0x1) << 16) ++#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_XMIRROR(x) ((x & 0x1) << 17) ++#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_YMIRROR(x) ((x & 0x1) << 18) ++#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_HOR_BY(x) ((x & 0x1) << 20) ++#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_HOR_UP(x) ((x & 0x1) << 21) ++#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_VER_BY(x) ((x & 0x1) << 22) ++#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_VER_UP(x) ((x & 0x1) << 23) ++#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_Y2R_EN(x) ((x & 0x1) << 24) ++#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_R2Y_EN(x) ((x & 0x1) << 25) ++#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_CSC_MODE(x) ((x & 0x3) << 26) ++#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_PERF_OPT_DIS(x) ((x & 0x1) << 29) ++#define s_RGA3_WIN1_RD_CTRL_SW_WIN1_RD_ALIGN_DIS(x) ((x & 0x1) << 30) ++ ++/* RGA3_WIN1_FBC_OFF */ ++#define m_RGA3_WIN1_FBC_OFF_SW_WIN1_FBC_XOFF (0x1fff << 0) ++#define m_RGA3_WIN1_FBC_OFF_SW_WIN1_FBC_YOFF (0x1fff << 16) ++ ++#define s_RGA3_WIN1_FBC_OFF_SW_WIN1_FBC_XOFF(x) ((x & 0x1fff) << 0) ++#define s_RGA3_WIN1_FBC_OFF_SW_WIN1_FBC_YOFF(x) ((x & 0x1fff) << 16) ++ ++/* RGA3_WIN1_SRC_SIZE */ ++#define m_RGA3_WIN1_SRC_SIZE_SW_WIN1_SRC_WIDTH (0x1fff << 0) ++#define m_RGA3_WIN1_SRC_SIZE_SW_WIN1_SRC_HEIGHT (0x1fff << 16) ++ ++#define s_RGA3_WIN1_SRC_OFF_SW_WIN1_SRC_WIDTH(x) ((x & 0x1fff) << 0) ++#define s_RGA3_WIN1_SRC_OFF_SW_WIN1_SRC_HEIGHT(x) ((x & 0x1fff) << 16) ++ ++/* RGA3_WIN1_ACT_OFF */ ++#define m_RGA3_WIN1_ACT_OFF_SW_WIN1_ACT_XOFF (0x1fff << 0) ++#define m_RGA3_WIN1_ACT_OFF_SW_WIN1_ACT_YOFF (0x1fff << 16) ++ ++#define s_RGA3_WIN1_ACT_OFF_SW_WIN1_ACT_XOFF(x) ((x & 0x1fff) << 0) ++#define s_RGA3_WIN1_ACT_OFF_SW_WIN1_ACT_YOFF(x) ((x & 0x1fff) << 16) ++ ++/* RGA3_WIN1_ACT_SIZE */ ++#define m_RGA3_WIN1_ACT_SIZE_SW_WIN1_ACT_WIDTH (0x1fff << 0) ++#define m_RGA3_WIN1_ACT_SIZE_SW_WIN1_ACT_HEIGHT (0x1fff << 16) ++ ++#define s_RGA3_WIN1_ACT_SIZE_SW_WIN1_ACT_WIDTH(x) ((x & 0x1fff) << 0) ++#define s_RGA3_WIN1_ACT_SIZE_SW_WIN1_ACT_HEIGHT(x) ((x & 0x1fff) << 16) ++ ++/* RGA3_WIN1_DST_SIZE */ ++#define m_RGA3_WIN1_DST_SIZE_SW_WIN1_DST_WIDTH (0x1fff << 0) ++#define m_RGA3_WIN1_DST_SIZE_SW_WIN1_DST_HEIGHT (0x1fff << 16) ++ ++#define s_RGA3_WIN1_DST_SIZE_SW_WIN1_DST_WIDTH(x) ((x & 0x1fff) << 0) ++#define s_RGA3_WIN1_DST_SIZE_SW_WIN1_DST_HEIGHT(x) ((x & 0x1fff) << 16) ++ ++/* RGA3_WIN1_SCL_FAC */ ++#define m_RGA3_WIN1_SCL_FAC_SW_WIN1_VER_FAC (0xffff << 0) ++#define m_RGA3_WIN1_SCL_FAC_SW_WIN1_HOR_FAC (0xffff << 16) ++ ++#define s_RGA3_WIN1_SCL_FAC_SW_WIN1_VER_FAC(x) ((x & 0xffff) << 0) ++#define s_RGA3_WIN1_SCL_FAC_SW_WIN1_HOR_FAC(x) ((x & 0xffff) << 16) ++ ++/* RGA3_OVLP_CTRL */ ++#define m_RGA3_OVLP_CTRL_SW_OVLP_MODE (0x3 << 0) ++#define m_RGA3_OVLP_CTRL_SW_OVLP_FIELD (0x1 << 2) ++#define m_RGA3_OVLP_CTRL_SW_TOP_SWAP (0x1 << 3) ++#define m_RGA3_OVLP_CTRL_SW_TOP_ALPHA_EN (0x1 << 4) ++#define m_RGA3_OVLP_CTRL_SW_TOP_KEY_EN (0x7FFF << 5) ++#define m_RGA3_OVLP_CTRL_SW_OVLP_Y2R_EN (0x1 << 20) ++#define m_RGA3_OVLP_CTRL_SW_OVLP_R2Y_EN (0x1 << 21) ++#define m_RGA3_OVLP_CTRL_SW_OVLP_CSC_MODE (0x3 << 22) ++ ++#define s_RGA3_OVLP_CTRL_SW_OVLP_MODE(x) ((x & 0x3) << 0) ++#define s_RGA3_OVLP_CTRL_SW_OVLP_FIELD(x) ((x & 0x1) << 2) ++#define s_RGA3_OVLP_CTRL_SW_TOP_SWAP(x) ((x & 0x1) << 3) ++#define s_RGA3_OVLP_CTRL_SW_TOP_ALPHA_EN(x) ((x & 0x1) << 4) ++#define s_RGA3_OVLP_CTRL_SW_TOP_KEY_EN(x) ((x & 0x7FFF) << 5) ++#define s_RGA3_OVLP_CTRL_SW_OVLP_Y2R_EN(x) ((x & 0x1) << 20) ++#define s_RGA3_OVLP_CTRL_SW_OVLP_R2Y_EN(x) ((x & 0x1) << 21) ++#define s_RGA3_OVLP_CTRL_SW_OVLP_CSC_MODE(x) ((x & 0x3) << 22) ++ ++/* RGA3_OVLP_OFF */ ++#define m_RGA3_OVLP_OFF_SW_OVLP_XOFF (0x1fff << 0) ++#define m_RGA3_OVLP_OFF_SW_OVLP_YOFF (0x1fff << 16) ++ ++#define s_RGA3_OVLP_OFF_SW_OVLP_XOFF(x) ((x & 0x1fff) << 0) ++#define s_RGA3_OVLP_OFF_SW_OVLP_YOFF(x) ((x & 0x1fff) << 16) ++ ++/* RGA3_OVLP_TOP_KEY_MIN */ ++#define m_RGA3_OVLP_TOP_KEY_MIN_SW_TOP_KEY_YG_MIN (0x3ff << 0) ++#define m_RGA3_OVLP_TOP_KEY_MIN_SW_TOP_KEY_UB_MIN (0x3ff << 10) ++#define m_RGA3_OVLP_TOP_KEY_MIN_SW_TOP_KEY_VR_MIN (0x3ff << 20) ++ ++#define s_RGA3_OVLP_TOP_KEY_MIN_SW_TOP_KEY_YG_MIN(x) ((x & 0x3f)f << 0) ++#define s_RGA3_OVLP_TOP_KEY_MIN_SW_TOP_KEY_UB_MIN(x) ((x & 0x3ff) << 10) ++#define s_RGA3_OVLP_TOP_KEY_MIN_SW_TOP_KEY_VR_MIN(x) ((x & 0x3ff) << 20) ++ ++/* RGA3_OVLP_TOP_KEY_MAX */ ++#define m_RGA3_OVLP_TOP_KEY_MAX_SW_TOP_KEY_YG_MAX (0x3ff << 0) ++#define m_RGA3_OVLP_TOP_KEY_MAX_SW_TOP_KEY_UB_MAX (0x3ff << 10) ++#define m_RGA3_OVLP_TOP_KEY_MAX_SW_TOP_KEY_VR_MAX (0x3ff << 20) ++ ++#define s_RGA3_OVLP_TOP_KEY_MAX_SW_TOP_KEY_YG_MAX(x) ((x & 0x3ff) << 0) ++#define s_RGA3_OVLP_TOP_KEY_MAX_SW_TOP_KEY_UB_MAX(x) ((x & 0x3ff) << 10) ++#define s_RGA3_OVLP_TOP_KEY_MAX_SW_TOP_KEY_VR_MAX(x) ((x & 0x3ff) << 20) ++ ++/* RGA3_OVLP_TOP_CTRL */ ++#define m_RGA3_OVLP_TOP_CTRL_SW_TOP_COLOR_M0 (0x1 << 0) ++#define m_RGA3_OVLP_TOP_CTRL_SW_TOP_ALPHA_M0 (0x1 << 1) ++#define m_RGA3_OVLP_TOP_CTRL_SW_TOP_BLEND_M0 (0x3 << 2) ++#define m_RGA3_OVLP_TOP_CTRL_SW_TOP_ALPHA_CAL_M0 (0x1 << 4) ++#define m_RGA3_OVLP_TOP_CTRL_SW_TOP_FACTOR_M0 (0x7 << 5) ++#define m_RGA3_OVLP_TOP_CTRL_SW_TOP_GLOBAL_ALPHA (0xff << 16) ++ ++#define s_RGA3_OVLP_TOP_CTRL_SW_TOP_COLOR_M0(x) ((x & 0x1) << 0) ++#define s_RGA3_OVLP_TOP_CTRL_SW_TOP_ALPHA_M0(x) ((x & 0x1) << 1) ++#define s_RGA3_OVLP_TOP_CTRL_SW_TOP_BLEND_M0(x) ((x & 0x3) << 2) ++#define s_RGA3_OVLP_TOP_CTRL_SW_TOP_ALPHA_CAL_M0(x) ((x & 0x1) << 4) ++#define s_RGA3_OVLP_TOP_CTRL_SW_TOP_FACTOR_M0(x) ((x & 0x7) << 5) ++#define s_RGA3_OVLP_TOP_CTRL_SW_TOP_GLOBAL_ALPHA(x) ((x & 0xff) << 16) ++ ++/* RGA3_OVLP_BOT_CTRL */ ++#define m_RGA3_OVLP_BOT_CTRL_SW_BOT_COLOR_M0 (0x1 << 0) ++#define m_RGA3_OVLP_BOT_CTRL_SW_BOT_ALPHA_M0 (0x1 << 1) ++#define m_RGA3_OVLP_BOT_CTRL_SW_BOT_BLEND_M0 (0x3 << 2) ++#define m_RGA3_OVLP_BOT_CTRL_SW_BOT_ALPHA_CAL_M0 (0x1 << 4) ++#define m_RGA3_OVLP_BOT_CTRL_SW_BOT_FACTOR_M0 (0x7 << 5) ++#define m_RGA3_OVLP_BOT_CTRL_SW_BOT_GLOBAL_ALPHA (0xff << 16) ++ ++#define s_RGA3_OVLP_BOT_CTRL_SW_BOT_COLOR_M0(x) ((x & 0x1) << 0) ++#define s_RGA3_OVLP_BOT_CTRL_SW_BOT_ALPHA_M0(x) ((x & 0x1) << 1) ++#define s_RGA3_OVLP_BOT_CTRL_SW_BOT_BLEND_M0(x) ((x & 0x3) << 2) ++#define s_RGA3_OVLP_BOT_CTRL_SW_BOT_ALPHA_CAL_M0(x) ((x & 0x1) << 4) ++#define s_RGA3_OVLP_BOT_CTRL_SW_BOT_FACTOR_M0(x) ((x & 0x7) << 5) ++#define s_RGA3_OVLP_BOT_CTRL_SW_BOT_GLOBAL_ALPHA(x) ((x & 0xff) << 16) ++ ++/* RGA3_OVLP_TOP_ALPHA */ ++#define m_RGA3_OVLP_TOP_ALPHA_SW_TOP_ALPHA_M1 (0x1 << 1) ++#define m_RGA3_OVLP_TOP_ALPHA_SW_TOP_BLEND_M1 (0x3 << 2) ++#define m_RGA3_OVLP_TOP_ALPHA_SW_TOP_ALPHA_CAL_M1 (0x1 << 4) ++#define m_RGA3_OVLP_TOP_ALPHA_SW_TOP_FACTOR_M1 (0x7 << 5) ++ ++#define s_RGA3_OVLP_TOP_ALPHA_SW_TOP_ALPHA_M1(x) ((x & 0x1) << 1) ++#define s_RGA3_OVLP_TOP_ALPHA_SW_TOP_BLEND_M1(x) ((x & 0x3) << 2) ++#define s_RGA3_OVLP_TOP_ALPHA_SW_TOP_ALPHA_CAL_M1(x) ((x & 0x1) << 4) ++#define s_RGA3_OVLP_TOP_ALPHA_SW_TOP_FACTOR_M1(x) ((x & 0x7) << 5) ++ ++/* RGA3_OVLP_BOT_ALPHA */ ++#define m_RGA3_OVLP_BOT_ALPHA_SW_BOT_ALPHA_M1 (0x1 << 1) ++#define m_RGA3_OVLP_BOT_ALPHA_SW_BOT_BLEND_M1 (0x3 << 2) ++#define m_RGA3_OVLP_BOT_ALPHA_SW_BOT_ALPHA_CAL_M1 (0x1 << 4) ++#define m_RGA3_OVLP_BOT_ALPHA_SW_BOT_FACTOR_M1 (0x7 << 5) ++ ++#define s_RGA3_OVLP_BOT_ALPHA_SW_BOT_ALPHA_M1(x) ((x & 0x1) << 1) ++#define s_RGA3_OVLP_BOT_ALPHA_SW_BOT_BLEND_M1(x) ((x & 0x3) << 2) ++#define s_RGA3_OVLP_BOT_ALPHA_SW_BOT_ALPHA_CAL_M1(x) ((x & 0x1) << 4) ++#define s_RGA3_OVLP_BOT_ALPHA_SW_BOT_FACTOR_M1(x) ((x & 0x7) << 5) ++ ++/* RGA3_WR_CTRL */ ++#define m_RGA3_WR_CTRL_SW_WR_MODE (0x3 << 0) ++#define m_RGA3_WR_CTRL_SW_WR_FBCE_SPARSE_EN (0x1 << 2) ++#define m_RGA3_WR_CTRL_SW_WR_PIC_FORMAT (0xf << 4) ++#define m_RGA3_WR_CTRL_SW_WR_FORMAT (0x3 << 8) ++#define m_RGA3_WR_CTRL_SW_WR_YUV10B_COMPACT (0x1 << 10) ++#define m_RGA3_WR_CTRL_SW_WR_ENDIAN_MODE (0x1 << 11) ++#define m_RGA3_WR_CTRL_SW_WR_PIX_SWAP (0x1 << 12) ++#define m_RGA3_WR_CTRL_SW_OUTSTANDING_MAX (0x3f << 13) ++#define m_RGA3_WR_CTRL_SW_WR_YC_SWAP (0x1 << 20) ++ ++#define s_RGA3_WR_CTRL_SW_WR_MODE(x) ((x & 0x3) << 0) ++#define s_RGA3_WR_CTRL_SW_WR_FBCE_SPARSE_EN(x) ((x & 0x1) << 2) ++#define s_RGA3_WR_CTRL_SW_WR_PIC_FORMAT(x) ((x & 0xf) << 4) ++#define s_RGA3_WR_CTRL_SW_WR_FORMAT(x) ((x & 0x3) << 8) ++#define s_RGA3_WR_CTRL_SW_WR_YUV10B_COMPACT(x) ((x & 0x1) << 10) ++#define s_RGA3_WR_CTRL_SW_WR_ENDIAN_MODE(x) ((x & 0x1) << 11) ++#define s_RGA3_WR_CTRL_SW_WR_PIX_SWAP(x) ((x & 0x1) << 12) ++#define s_RGA3_WR_CTRL_SW_OUTSTANDING_MAX(x) ((x & 0x3f) << 13) ++#define s_RGA3_WR_CTRL_SW_WR_YC_SWAP(x) ((x & 0x1) << 20) ++ ++/* RGA3_WR_FBCE_CTRL */ ++#define m_RGA3_WR_FBCE_CTRL_SW_WR_FBCE_BLKBD_OPT_DIS (0x1 << 0) ++#define m_RGA3_WR_FBCE_CTRL_SW_WR_FBCE_HOFF_DISS (0x1 << 1) ++#define m_RGA3_WR_FBCE_CTRL_SW_WR_FBCE_PL_FIFO0_WATERMARK (0x3f << 2) ++#define m_RGA3_WR_FBCE_CTRL_SW_WR_FBCE_PL_FIFO1_WATERMARK (0x3f << 8) ++#define m_RGA3_WR_FBCE_CTRL_SW_WR_FBCE_SIZE_ALIGN_DIS (0x1 << 31) ++ ++#define s_RGA3_WR_FBCE_CTRL_SW_WR_FBCE_BLKBD_OPT_DIS(x) ((x & 0x1) << 0) ++#define s_RGA3_WR_FBCE_CTRL_SW_WR_FBCE_HOFF_DISS(x) ((x & 0x1) << 1) ++#define s_RGA3_WR_FBCE_CTRL_SW_WR_FBCE_PL_FIFO0_WATERMARK(x) ((x & 0x3f) << 2) ++#define s_RGA3_WR_FBCE_CTRL_SW_WR_FBCE_PL_FIFO1_WATERMARK(x) ((x & 0x3f) << 8) ++#define s_RGA3_WR_FBCE_CTRL_SW_WR_FBCE_SIZE_ALIGN_DIS(x) ((x & 0x1) << 31) ++ ++/* RGA3_MMU_STATUS read_only */ ++#define m_RGA3_MMU_STATUS_PAGING_ENABLED (0x1 << 0) ++#define m_RGA3_MMU_STATUS_PAGE_FAULT_ACTIVE (0x1 << 1) ++#define m_RGA3_MMU_STATUS_STAIL_ACTIVE (0x1 << 2) ++#define m_RGA3_MMU_STATUS_MMU_IDLE (0x1 << 3) ++#define m_RGA3_MMU_STATUS_REPLAY_BUFFER_EMPTY (0x1 << 4) ++#define m_RGA3_MMU_STATUS_PAGE_FAULT_IS_WRITE (0x1 << 5) ++#define m_RGA3_MMU_STATUS_PAGE_FAULT_BUS_ID (0x1f << 6) ++ ++/* RGA3_MMU_INT_RAWSTAT read_only */ ++#define m_RGA3_MMU_INT_RAWSTAT_READ_BUS_ERROR (0x1 << 0) ++#define m_RGA3_MMU_INT_RAWSTAT_PAGE_FAULT (0x1 << 1) ++ ++/* RGA3_MMU_INT_CLEAR write_only */ ++#define m_RGA3_MMU_INT_CLEAR_READ_BUS_ERROR (0x1 << 0) ++#define m_RGA3_MMU_INT_CLEAR_PAGE_FAULT (0x1 << 1) ++ ++#define s_RGA3_MMU_INT_CLEAR_READ_BUS_ERROR(x) ((x & 0x1) << 0) ++#define s_RGA3_MMU_INT_CLEAR_PAGE_FAULT(x) ((x & 0x1) << 1) ++ ++/* RGA3_MMU_INT_MASK */ ++#define m_RGA3_MMU_INT_MASK_READ_BUS_ERROR (0x1 << 0) ++#define m_RGA3_MMU_INT_MASK_PAGE_FAULT (0x1 << 1) ++ ++#define s_RGA3_MMU_INT_MASK_READ_BUS_ERROR(x) ((x & 0x1) << 0) ++#define s_RGA3_MMU_INT_MASK_PAGE_FAULT(x) ((x & 0x1) << 1) ++ ++/* RGA3_MMU_INT_STATUS read_only */ ++#define m_RGA3_MMU_INT_STATUS_READ_BUS_ERROR (0x1 << 0) ++#define m_RGA3_MMU_INT_STATUS_PAGE_FAULT (0x1 << 1) ++ ++/* RGA3_MMU_AUTO_GATING */ ++#define m_RGA3_MMU_AUTO_GATING_MMU_AUTO_GATING (0x1 << 1) ++#define m_RGA3_MMU_AUTO_GATING_MMU_CFG_MODE (0x1 << 1) ++#define m_RGA3_MMU_AUTO_GATING_MMU_BUG_FIXED_DISABLE (0x1 << 31) ++ ++#define s_RGA3_MMU_AUTO_GATING_MMU_AUTO_GATING(x) ((x & 0x1) << 1) ++#define s_RGA3_MMU_AUTO_GATING_MMU_BUG_FIXED_DISABLE(x) ((x & 0x1) << 31) ++ ++#define RGA3_ROT_BIT_ROT_90 BIT(0) ++#define RGA3_ROT_BIT_X_MIRROR BIT(1) ++#define RGA3_ROT_BIT_Y_MIRROR BIT(2) ++ ++union rga3_color_ctrl { ++ uint32_t value; ++ struct { ++ uint32_t color_mode:1; ++ uint32_t alpha_mode:1; ++ uint32_t blend_mode:2; ++ uint32_t alpha_cal_mode:1; ++ uint32_t factor_mode:3; ++ ++ uint32_t reserved:8; ++ ++ uint32_t global_alpha:8; ++ } bits; ++}; ++ ++union rga3_alpha_ctrl { ++ uint32_t value; ++ struct { ++ uint32_t reserved:1; ++ uint32_t alpha_mode:1; ++ uint32_t blend_mode:2; ++ uint32_t alpha_cal_mode:1; ++ uint32_t factor_mode:3; ++ } bits; ++}; ++ ++extern const struct rga_backend_ops rga3_ops; ++ ++#endif ++ +diff --git a/drivers/video/rockchip/rga3/include/rga_common.h b/drivers/video/rockchip/rga3/include/rga_common.h +new file mode 100644 +index 000000000..32e83cc9c +--- /dev/null ++++ b/drivers/video/rockchip/rga3/include/rga_common.h +@@ -0,0 +1,49 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) Rockchip Electronics Co., Ltd. ++ * ++ * Author: ++ * Cerf Yu ++ */ ++ ++#ifndef __LINUX_RKRGA_COMMON_H_ ++#define __LINUX_RKRGA_COMMON_H_ ++ ++#include "rga_drv.h" ++#include "rga_hw_config.h" ++ ++#define RGA_GET_PAGE_COUNT(size) (((size) >> PAGE_SHIFT) + (((size) & (~PAGE_MASK)) ? 1 : 0)) ++ ++bool rga_is_rgb_format(uint32_t format); ++bool rga_is_yuv_format(uint32_t format); ++bool rga_is_alpha_format(uint32_t format); ++bool rga_is_yuv420_packed_format(uint32_t format); ++bool rga_is_yuv420_planar_format(uint32_t format); ++bool rga_is_yuv420_semi_planar_format(uint32_t format); ++bool rga_is_yuv422_packed_format(uint32_t format); ++bool rga_is_yuv422_planar_format(uint32_t format); ++bool rga_is_yuv422_semi_planar_format(uint32_t format); ++bool rga_is_yuv8bit_format(uint32_t format); ++bool rga_is_yuv10bit_format(uint32_t format); ++bool rga_is_yuv422p_format(uint32_t format); ++bool rga_is_only_y_format(uint32_t format); ++ ++int rga_get_format_bits(uint32_t format); ++int rga_get_pixel_stride_from_format(uint32_t format); ++ ++const char *rga_get_format_name(uint32_t format); ++const char *rga_get_render_mode_str(uint8_t mode); ++const char *rga_get_rotate_mode_str(uint8_t mode); ++const char *rga_get_blend_mode_str(enum rga_alpha_blend_mode mode); ++const char *rga_get_memory_type_str(uint8_t type); ++const char *rga_get_mmu_type_str(enum rga_mmu mmu_type); ++const char *rga_get_core_name(enum RGA_SCHEDULER_CORE core); ++ ++void rga_convert_addr(struct rga_img_info_t *img, bool before_vir_get_channel); ++void rga_swap_pd_mode(struct rga_req *req_rga); ++int rga_image_size_cal(int w, int h, int format, ++ int *yrgb_size, int *uv_size, int *v_size); ++void rga_dump_memory_parm(struct rga_memory_parm *parm); ++void rga_dump_external_buffer(struct rga_external_buffer *buffer); ++ ++#endif +diff --git a/drivers/video/rockchip/rga3/include/rga_debugger.h b/drivers/video/rockchip/rga3/include/rga_debugger.h +new file mode 100644 +index 000000000..c274fe87f +--- /dev/null ++++ b/drivers/video/rockchip/rga3/include/rga_debugger.h +@@ -0,0 +1,145 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) Rockchip Electronics Co., Ltd. ++ * ++ * Author: ++ * Cerf Yu ++ * Huang Lee ++ */ ++ ++#ifndef _RGA_DEBUGGER_H_ ++#define _RGA_DEBUGGER_H_ ++ ++#include "rga_drv.h" ++ ++#ifdef CONFIG_ROCKCHIP_RGA_DEBUGGER ++ ++extern int RGA_DEBUG_REG; ++extern int RGA_DEBUG_MSG; ++extern int RGA_DEBUG_TIME; ++extern int RGA_DEBUG_INT_FLAG; ++extern int RGA_DEBUG_MM; ++extern int RGA_DEBUG_CHECK_MODE; ++extern int RGA_DEBUG_NONUSE; ++extern int RGA_DEBUG_DUMP_IMAGE; ++ ++#define DEBUGGER_EN(name) (unlikely(RGA_DEBUG_##name ? true : false)) ++ ++/* ++ * struct rga_debugger - RGA debugger information ++ * ++ * This structure represents a debugger to be created by the rga driver ++ * or core. ++ */ ++struct rga_debugger { ++#ifdef CONFIG_ROCKCHIP_RGA_DEBUG_FS ++ /* Directory of debugfs file */ ++ struct dentry *debugfs_dir; ++ struct list_head debugfs_entry_list; ++ struct mutex debugfs_lock; ++#endif ++ ++#ifdef CONFIG_ROCKCHIP_RGA_PROC_FS ++ /* Directory of procfs file */ ++ struct proc_dir_entry *procfs_dir; ++ struct list_head procfs_entry_list; ++ struct mutex procfs_lock; ++#endif ++}; ++ ++/* ++ * struct rga_debugger_list - debugfs/procfs info list entry ++ * ++ * This structure represents a debugfs/procfs file to be created by the rga ++ * driver or core. ++ */ ++struct rga_debugger_list { ++ /* File name */ ++ const char *name; ++ /* ++ * Show callback. &seq_file->private will be set to the &struct ++ * rga_debugger_node corresponding to the instance of this info ++ * on a given &struct rga_debugger. ++ */ ++ int (*show)(struct seq_file *seq, void *data); ++ /* ++ * Write callback. &seq_file->private will be set to the &struct ++ * rga_debugger_node corresponding to the instance of this info ++ * on a given &struct rga_debugger. ++ */ ++ ssize_t (*write)(struct file *file, const char __user *ubuf, ++ size_t len, loff_t *offp); ++ /* Procfs/Debugfs private data. */ ++ void *data; ++}; ++ ++/* ++ * struct rga_debugger_node - Nodes for debugfs/procfs ++ * ++ * This structure represents each instance of procfs/debugfs created from the ++ * template. ++ */ ++struct rga_debugger_node { ++ struct rga_debugger *debugger; ++ ++ /* template for this node. */ ++ const struct rga_debugger_list *info_ent; ++ ++ /* Each Procfs/Debugfs file. */ ++#ifdef CONFIG_ROCKCHIP_RGA_DEBUG_FS ++ struct dentry *dent; ++#endif ++ ++#ifdef CONFIG_ROCKCHIP_RGA_PROC_FS ++ struct proc_dir_entry *pent; ++#endif ++ ++ struct list_head list; ++}; ++ ++#ifdef CONFIG_ROCKCHIP_RGA_DEBUG_FS ++int rga_debugfs_init(void); ++int rga_debugfs_remove(void); ++#else ++static inline int rga_debugfs_remove(void) ++{ ++ return 0; ++} ++static inline int rga_debugfs_init(void) ++{ ++ return 0; ++} ++#endif /* #ifdef CONFIG_ROCKCHIP_RGA_DEBUG_FS */ ++ ++#ifdef CONFIG_ROCKCHIP_RGA_PROC_FS ++int rga_procfs_remove(void); ++int rga_procfs_init(void); ++#else ++static inline int rga_procfs_remove(void) ++{ ++ return 0; ++} ++static inline int rga_procfs_init(void) ++{ ++ return 0; ++} ++#endif /* #ifdef CONFIG_ROCKCHIP_RGA_PROC_FS */ ++ ++#else ++ ++#define DEBUGGER_EN(name) (unlikely(false)) ++ ++#endif /* #ifdef CONFIG_ROCKCHIP_RGA_DEBUGGER */ ++ ++void rga_cmd_print_debug_info(struct rga_req *req); ++void rga_request_task_debug_info(struct seq_file *m, struct rga_req *req); ++#ifdef CONFIG_NO_GKI ++void rga_dump_job_image(struct rga_job *dump_job); ++#else ++static inline void rga_dump_job_image(struct rga_job *dump_job) ++{ ++} ++#endif /* #ifdef CONFIG_NO_GKI */ ++ ++#endif /* #ifndef _RGA_DEBUGGER_H_ */ ++ +diff --git a/drivers/video/rockchip/rga3/include/rga_dma_buf.h b/drivers/video/rockchip/rga3/include/rga_dma_buf.h +new file mode 100644 +index 000000000..2ff0857a6 +--- /dev/null ++++ b/drivers/video/rockchip/rga3/include/rga_dma_buf.h +@@ -0,0 +1,46 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) Rockchip Electronics Co., Ltd. ++ * ++ * Author: ++ * Cerf Yu ++ * Huang Lee ++ */ ++#ifndef __RGA3_DMA_BUF_H__ ++#define __RGA3_DMA_BUF_H__ ++ ++#include "rga_drv.h" ++ ++#ifndef for_each_sgtable_sg ++/* ++ * Loop over each sg element in the given sg_table object. ++ */ ++#define for_each_sgtable_sg(sgt, sg, i) \ ++ for_each_sg((sgt)->sgl, sg, (sgt)->orig_nents, i) ++#endif ++ ++int rga_buf_size_cal(unsigned long yrgb_addr, unsigned long uv_addr, ++ unsigned long v_addr, int format, uint32_t w, ++ uint32_t h, unsigned long *StartAddr, unsigned long *size); ++ ++int rga_virtual_memory_check(void *vaddr, u32 w, u32 h, u32 format, int fd); ++int rga_dma_memory_check(struct rga_dma_buffer *rga_dma_buffer, struct rga_img_info_t *img); ++ ++int rga_iommu_map_sgt(struct sg_table *sgt, size_t size, ++ struct rga_dma_buffer *buffer, ++ struct device *rga_dev); ++int rga_iommu_map(phys_addr_t paddr, size_t size, ++ struct rga_dma_buffer *buffer, ++ struct device *rga_dev); ++void rga_iommu_unmap(struct rga_dma_buffer *buffer); ++ ++int rga_dma_map_buf(struct dma_buf *dma_buf, struct rga_dma_buffer *rga_dma_buffer, ++ enum dma_data_direction dir, struct device *rga_dev); ++int rga_dma_map_fd(int fd, struct rga_dma_buffer *rga_dma_buffer, ++ enum dma_data_direction dir, struct device *rga_dev); ++void rga_dma_unmap_buf(struct rga_dma_buffer *rga_dma_buffer); ++ ++void rga_dma_sync_flush_range(void *pstart, void *pend, struct rga_scheduler_t *scheduler); ++ ++#endif /* #ifndef __RGA3_DMA_BUF_H__ */ ++ +diff --git a/drivers/video/rockchip/rga3/include/rga_drv.h b/drivers/video/rockchip/rga3/include/rga_drv.h +new file mode 100644 +index 000000000..c9d28387a +--- /dev/null ++++ b/drivers/video/rockchip/rga3/include/rga_drv.h +@@ -0,0 +1,468 @@ ++/* 6.18 renamed MAX_ORDER (exclusive) to MAX_PAGE_ORDER (inclusive) */ ++#include ++#ifndef MAX_ORDER ++#define MAX_ORDER (MAX_PAGE_ORDER + 1) ++#endif ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) Rockchip Electronics Co., Ltd. ++ * ++ * Author: Huang Lee ++ */ ++ ++#ifndef __LINUX_RGA_DRV_H_ ++#define __LINUX_RGA_DRV_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++ ++#ifdef CONFIG_DMABUF_CACHE ++#include ++#else ++#include ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) ++#include ++#endif ++ ++#include ++ ++#include "rga.h" ++ ++#define RGA_CORE_REG_OFFSET 0x10000 ++ ++/* load interval: 1000ms */ ++#define RGA_LOAD_INTERVAL_US 1000000 ++ ++/* timer interval: 1000ms */ ++#define RGA_TIMER_INTERVAL_NS 1000000000 ++ ++#if ((defined(CONFIG_RK_IOMMU) || defined(CONFIG_ROCKCHIP_IOMMU)) \ ++ && defined(CONFIG_ION_ROCKCHIP)) ++#define CONFIG_RGA_IOMMU ++#endif ++ ++/* Driver information */ ++#define DRIVER_DESC "RGA multicore Device Driver" ++#define DRIVER_NAME "rga_multicore" ++ ++#define STR_HELPER(x) #x ++#define STR(x) STR_HELPER(x) ++ ++#define DRIVER_MAJOR_VERISON 1 ++#define DRIVER_MINOR_VERSION 3 ++#define DRIVER_REVISION_VERSION 1 ++#define DRIVER_PATCH_VERSION ++ ++#define DRIVER_VERSION (STR(DRIVER_MAJOR_VERISON) "." STR(DRIVER_MINOR_VERSION) \ ++ "." STR(DRIVER_REVISION_VERSION) STR(DRIVER_PATCH_VERSION)) ++ ++/* time limit */ ++#define RGA_JOB_TIMEOUT_DELAY HZ ++#define RGA_RESET_TIMEOUT 1000 ++ ++#define RGA_MAX_SCHEDULER RGA_HW_SIZE ++#define RGA_MAX_BUS_CLK 10 ++ ++#define RGA_BUFFER_POOL_MAX_SIZE 64 ++ ++#ifndef ABS ++#define ABS(X) (((X) < 0) ? (-(X)) : (X)) ++#endif ++ ++#ifndef CLIP ++#define CLIP(x, a, b) (((x) < (a)) \ ++ ? (a) : (((x) > (b)) ? (b) : (x))) ++#endif ++ ++extern struct rga_drvdata_t *rga_drvdata; ++ ++enum { ++ RGA3_SCHEDULER_CORE0 = 1 << 0, ++ RGA3_SCHEDULER_CORE1 = 1 << 1, ++ RGA2_SCHEDULER_CORE0 = 1 << 2, ++ RGA_CORE_MASK = 0x7, ++ RGA_NONE_CORE = 0x0, ++}; ++ ++enum { ++ RGA_CMD_SLAVE = 1, ++ RGA_CMD_MASTER = 2, ++}; ++ ++enum iommu_dma_cookie_type { ++ IOMMU_DMA_IOVA_COOKIE, ++ IOMMU_DMA_MSI_COOKIE, ++}; ++ ++enum rga_scheduler_status { ++ RGA_SCHEDULER_IDLE = 0, ++ RGA_SCHEDULER_WORKING, ++ RGA_SCHEDULER_ABORT, ++}; ++ ++enum rga_job_state { ++ RGA_JOB_STATE_PENDING = 0, ++ RGA_JOB_STATE_PREPARE, ++ RGA_JOB_STATE_RUNNING, ++ RGA_JOB_STATE_FINISH, ++ RGA_JOB_STATE_DONE, ++ RGA_JOB_STATE_INTR_ERR, ++ RGA_JOB_STATE_HW_TIMEOUT, ++ RGA_JOB_STATE_ABORT, ++}; ++ ++struct rga_iommu_dma_cookie { ++ enum iommu_dma_cookie_type type; ++ ++ /* Full allocator for IOMMU_DMA_IOVA_COOKIE */ ++ struct iova_domain iovad; ++}; ++ ++struct rga_iommu_info { ++ struct device *dev; ++ struct device *default_dev; /* for dma-buf_api */ ++ struct iommu_domain *domain; ++ struct iommu_group *group; ++}; ++ ++struct rga_dma_buffer { ++ /* DMABUF information */ ++ struct dma_buf *dma_buf; ++ struct dma_buf_attachment *attach; ++ struct sg_table *sgt; ++ void *vmap_ptr; ++ ++ struct iommu_domain *domain; ++ ++ enum dma_data_direction dir; ++ ++ dma_addr_t iova; ++ unsigned long size; ++ /* ++ * The offset of the first page of the sgt. ++ * Since alloc iova must be page aligned, the offset of the first page is ++ * identified separately. ++ */ ++ size_t offset; ++ ++ /* The scheduler of the mapping */ ++ struct rga_scheduler_t *scheduler; ++}; ++ ++struct rga_virt_addr { ++ uint64_t addr; ++ ++ struct page **pages; ++ int pages_order; ++ int page_count; ++ unsigned long size; ++ ++ /* The offset of the first page of the virtual address */ ++ size_t offset; ++ ++ int result; ++}; ++ ++struct rga_internal_buffer { ++ /* DMA buffer */ ++ struct rga_dma_buffer *dma_buffer; ++ ++ /* virtual address */ ++ struct rga_virt_addr *virt_addr; ++ ++ /* physical address */ ++ uint64_t phys_addr; ++ ++ /* buffer size */ ++ unsigned long size; ++ ++ struct rga_memory_parm memory_parm; ++ ++ ++ struct mm_struct *current_mm; ++ ++ /* memory type. */ ++ uint32_t type; ++ ++ uint32_t handle; ++ ++ uint32_t mm_flag; ++ ++ struct kref refcount; ++ struct rga_session *session; ++}; ++ ++struct rga_scheduler_t; ++ ++struct rga_session { ++ int id; ++ ++ pid_t tgid; ++ ++ char *pname; ++}; ++ ++struct rga_job_buffer { ++ union { ++ struct { ++ struct rga_external_buffer *ex_y_addr; ++ struct rga_external_buffer *ex_uv_addr; ++ struct rga_external_buffer *ex_v_addr; ++ }; ++ struct rga_external_buffer *ex_addr; ++ }; ++ ++ union { ++ struct { ++ struct rga_internal_buffer *y_addr; ++ struct rga_internal_buffer *uv_addr; ++ struct rga_internal_buffer *v_addr; ++ }; ++ struct rga_internal_buffer *addr; ++ }; ++ ++ uint32_t *page_table; ++ int order; ++ int page_count; ++}; ++ ++struct rga_job { ++ struct list_head head; ++ ++ struct rga_scheduler_t *scheduler; ++ struct rga_session *session; ++ ++ struct rga_req rga_command_base; ++ uint32_t cmd_reg[32 * 8]; ++ struct rga_full_csc full_csc; ++ struct rga_csc_clip full_csc_clip; ++ struct rga_pre_intr_info pre_intr_info; ++ ++ struct rga_job_buffer src_buffer; ++ struct rga_job_buffer src1_buffer; ++ struct rga_job_buffer dst_buffer; ++ /* used by rga2 */ ++ struct rga_job_buffer els_buffer; ++ ++ /* for rga2 virtual_address */ ++ struct mm_struct *mm; ++ ++ /* job time stamp */ ++ ktime_t timestamp; ++ /* The time when the job is actually executed on the hardware */ ++ ktime_t hw_running_time; ++ /* The time only for hrtimer to calculate the load */ ++ ktime_t hw_recoder_time; ++ unsigned int flags; ++ int request_id; ++ int priority; ++ int core; ++ int ret; ++ pid_t pid; ++ bool use_batch_mode; ++ ++ struct kref refcount; ++ unsigned long state; ++ uint32_t intr_status; ++ uint32_t hw_status; ++ uint32_t cmd_status; ++}; ++ ++struct rga_backend_ops { ++ int (*get_version)(struct rga_scheduler_t *scheduler); ++ int (*set_reg)(struct rga_job *job, struct rga_scheduler_t *scheduler); ++ int (*init_reg)(struct rga_job *job); ++ void (*soft_reset)(struct rga_scheduler_t *scheduler); ++ int (*read_back_reg)(struct rga_job *job, struct rga_scheduler_t *scheduler); ++ int (*irq)(struct rga_scheduler_t *scheduler); ++ int (*isr_thread)(struct rga_job *job, struct rga_scheduler_t *scheduler); ++}; ++ ++struct rga_timer { ++ u32 busy_time; ++ u32 busy_time_record; ++}; ++ ++struct rga_scheduler_t { ++ struct device *dev; ++ void __iomem *rga_base; ++ struct rga_iommu_info *iommu_info; ++ ++ struct clk *clks[RGA_MAX_BUS_CLK]; ++ int num_clks; ++ ++ enum rga_scheduler_status status; ++ int pd_refcount; ++ ++ struct rga_job *running_job; ++ struct list_head todo_list; ++ spinlock_t irq_lock; ++ wait_queue_head_t job_done_wq; ++ const struct rga_backend_ops *ops; ++ const struct rga_hw_data *data; ++ int job_count; ++ int irq; ++ struct rga_version_t version; ++ int core; ++ ++ struct rga_timer timer; ++}; ++ ++struct rga_request { ++ struct rga_req *task_list; ++ int task_count; ++ uint32_t finished_task_count; ++ uint32_t failed_task_count; ++ ++ bool use_batch_mode; ++ bool is_running; ++ bool is_done; ++ int ret; ++ uint32_t sync_mode; ++ ++ int32_t acquire_fence_fd; ++ int32_t release_fence_fd; ++ struct dma_fence *release_fence; ++ spinlock_t fence_lock; ++ ++ wait_queue_head_t finished_wq; ++ ++ int flags; ++ uint8_t mpi_config_flags; ++ int id; ++ struct rga_session *session; ++ ++ spinlock_t lock; ++ struct kref refcount; ++ ++ pid_t pid; ++ ++ /* ++ * The mapping of virtual addresses to obtain physical addresses requires ++ * the memory mapping information of the current process. ++ */ ++ struct mm_struct *current_mm; ++ ++ struct rga_feature feature; ++ /* TODO: add some common work */ ++}; ++ ++struct rga_pending_request_manager { ++ struct mutex lock; ++ ++ /* ++ * @request_idr: ++ * ++ * Mapping of request id to object pointers. Used by the GEM ++ * subsystem. Protected by @lock. ++ */ ++ struct idr request_idr; ++ ++ int request_count; ++}; ++ ++struct rga_session_manager { ++ struct mutex lock; ++ ++ struct idr ctx_id_idr; ++ ++ int session_cnt; ++}; ++ ++struct rga_drvdata_t { ++ /* used by rga2's mmu lock */ ++ struct mutex lock; ++ ++ struct rga_scheduler_t *scheduler[RGA_MAX_SCHEDULER]; ++ int num_of_scheduler; ++ /* The scheduler_index used by default for memory mapping. */ ++ int map_scheduler_index; ++ struct rga_mmu_base *mmu_base; ++ ++ struct delayed_work power_off_work; ++ ++ struct rga_mm *mm; ++ ++ /* rga_job pending manager, import by RGA_START_CONFIG */ ++ struct rga_pending_request_manager *pend_request_manager; ++ ++ struct rga_session_manager *session_manager; ++ ++#ifdef CONFIG_ROCKCHIP_RGA_ASYNC ++ struct rga_fence_context *fence_ctx; ++#endif ++ ++#ifdef CONFIG_ROCKCHIP_RGA_DEBUGGER ++ struct rga_debugger *debugger; ++#endif ++}; ++ ++struct rga_irqs_data_t { ++ const char *name; ++ irqreturn_t (*irq_hdl)(int irq, void *ctx); ++ irqreturn_t (*irq_thread)(int irq, void *ctx); ++}; ++ ++struct rga_match_data_t { ++ const char * const *clks; ++ int num_clks; ++}; ++ ++static inline int rga_read(int offset, struct rga_scheduler_t *scheduler) ++{ ++ return readl(scheduler->rga_base + offset); ++} ++ ++static inline void rga_write(int value, int offset, struct rga_scheduler_t *scheduler) ++{ ++ writel(value, scheduler->rga_base + offset); ++} ++ ++int rga_power_enable(struct rga_scheduler_t *scheduler); ++int rga_power_disable(struct rga_scheduler_t *scheduler); ++ ++int rga_kernel_commit(struct rga_req *cmd); ++ ++#endif /* __LINUX_RGA_FENCE_H_ */ +diff --git a/drivers/video/rockchip/rga3/include/rga_fence.h b/drivers/video/rockchip/rga3/include/rga_fence.h +new file mode 100644 +index 000000000..7e3bbeebb +--- /dev/null ++++ b/drivers/video/rockchip/rga3/include/rga_fence.h +@@ -0,0 +1,101 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) Rockchip Electronics Co., Ltd. ++ * ++ * Author: Huang Lee ++ */ ++ ++#ifndef __LINUX_RGA_FENCE_H_ ++#define __LINUX_RGA_FENCE_H_ ++ ++struct rga_fence_context { ++ unsigned int context; ++ unsigned int seqno; ++ spinlock_t spinlock; ++}; ++ ++struct rga_fence_waiter { ++ /* Base sync driver waiter structure */ ++ struct dma_fence_cb waiter; ++ ++ void *private; ++}; ++ ++#ifdef CONFIG_ROCKCHIP_RGA_ASYNC ++int rga_fence_context_init(struct rga_fence_context **ctx); ++void rga_fence_context_remove(struct rga_fence_context **ctx); ++ ++struct dma_fence *rga_dma_fence_alloc(void); ++int rga_dma_fence_get_fd(struct dma_fence *fence); ++struct dma_fence *rga_get_dma_fence_from_fd(int fence_fd); ++int rga_dma_fence_wait(struct dma_fence *fence); ++int rga_dma_fence_add_callback(struct dma_fence *fence, dma_fence_func_t func, void *private); ++ ++ ++static inline void rga_dma_fence_put(struct dma_fence *fence) ++{ ++ if (fence) ++ dma_fence_put(fence); ++} ++ ++static inline void rga_dma_fence_signal(struct dma_fence *fence, int error) ++{ ++ if (fence) { ++ if (error != 0) ++ dma_fence_set_error(fence, error); ++ dma_fence_signal(fence); ++ } ++} ++ ++static inline int rga_dma_fence_get_status(struct dma_fence *fence) ++{ ++ if (fence) ++ return dma_fence_get_status(fence); ++ else ++ return 1; ++} ++ ++#else ++static inline struct dma_fence *rga_dma_fence_alloc(void) ++{ ++ return NULL; ++} ++ ++static inline int rga_dma_fence_get_fd(struct dma_fence *fence) ++{ ++ return 0; ++} ++ ++static inline struct dma_fence *rga_get_dma_fence_from_fd(int fence_fd) ++{ ++ return NULL; ++} ++ ++static inline int rga_dma_fence_wait(struct dma_fence *fence) ++{ ++ return 0; ++} ++ ++static inline int rga_dma_fence_add_callback(struct dma_fence *fence, ++ dma_fence_func_t func, ++ void *private) ++{ ++ return 0; ++} ++ ++static inline void rga_dma_fence_put(struct dma_fence *fence) ++{ ++} ++ ++static inline void rga_dma_fence_signal(struct dma_fence *fence, int error) ++{ ++} ++ ++static inline int rga_dma_fence_get_status(struct dma_fence *fence) ++{ ++ return 0; ++} ++ ++#endif /* #ifdef CONFIG_SYNC_FILE */ ++ ++#endif /* __LINUX_RGA_FENCE_H_ */ +diff --git a/drivers/video/rockchip/rga3/include/rga_hw_config.h b/drivers/video/rockchip/rga3/include/rga_hw_config.h +new file mode 100644 +index 000000000..46f7531aa +--- /dev/null ++++ b/drivers/video/rockchip/rga3/include/rga_hw_config.h +@@ -0,0 +1,81 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) Rockchip Electronics Co., Ltd. ++ * ++ * Author: Huang Lee ++ */ ++ ++#ifndef __LINUX_RGA_HW_CONFIG_H_ ++#define __LINUX_RGA_HW_CONFIG_H_ ++ ++#include "rga_drv.h" ++ ++enum rga_mmu { ++ RGA_NONE_MMU = 0, ++ RGA_MMU = 1, ++ RGA_IOMMU = 2, ++}; ++ ++enum rga_hw_support_format_index { ++ RGA_RASTER_INDEX, ++ RGA_AFBC16x16_INDEX, ++ RGA_TILE8x8_INDEX, ++ RGA_FORMAT_INDEX_BUTT, ++}; ++ ++struct rga_win_data { ++ const char *name; ++ const uint32_t *formats[RGA_FORMAT_INDEX_BUTT]; ++ uint32_t formats_count[RGA_FORMAT_INDEX_BUTT]; ++ ++ uint32_t supported_rotations; ++ uint32_t scale_up_mode; ++ uint32_t scale_down_mode; ++ uint32_t rd_mode; ++}; ++ ++struct rga_rect { ++ int width; ++ int height; ++}; ++ ++struct rga_rect_range { ++ struct rga_rect min; ++ struct rga_rect max; ++}; ++ ++struct rga_hw_data { ++ uint32_t version; ++ uint32_t feature; ++ ++ uint32_t csc_r2y_mode; ++ uint32_t csc_y2r_mode; ++ ++ struct rga_rect_range input_range; ++ struct rga_rect_range output_range; ++ ++ unsigned int max_upscale_factor; ++ unsigned int max_downscale_factor; ++ ++ uint32_t byte_stride_align; ++ uint32_t max_byte_stride; ++ ++ const struct rga_win_data *win; ++ unsigned int win_size; ++ ++ enum rga_mmu mmu; ++}; ++ ++extern const struct rga_hw_data rga3_data; ++extern const struct rga_hw_data rga2e_data; ++extern const struct rga_hw_data rga2e_1106_data; ++extern const struct rga_hw_data rga2e_iommu_data; ++ ++/* Returns false if in range, true otherwise */ ++static inline bool rga_hw_out_of_range(const struct rga_rect_range *range, int width, int height) ++{ ++ return (width > range->max.width || height > range->max.height || ++ width < range->min.width || height < range->min.height); ++} ++ ++#endif /* __LINUX_RGA_HW_CONFIG_H_ */ +diff --git a/drivers/video/rockchip/rga3/include/rga_iommu.h b/drivers/video/rockchip/rga3/include/rga_iommu.h +new file mode 100644 +index 000000000..b80a1f48b +--- /dev/null ++++ b/drivers/video/rockchip/rga3/include/rga_iommu.h +@@ -0,0 +1,79 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __RGA_MMU_INFO_H__ ++#define __RGA_MMU_INFO_H__ ++ ++#include "rga_drv.h" ++ ++/* RGA_IOMMU register offsets */ ++#define RGA_IOMMU_BASE 0xf00 ++#define RGA_IOMMU_DTE_ADDR (RGA_IOMMU_BASE + 0x00) /* Directory table address */ ++#define RGA_IOMMU_STATUS (RGA_IOMMU_BASE + 0x04) ++#define RGA_IOMMU_COMMAND (RGA_IOMMU_BASE + 0x08) ++#define RGA_IOMMU_PAGE_FAULT_ADDR (RGA_IOMMU_BASE + 0x0C) /* IOVA of last page fault */ ++#define RGA_IOMMU_ZAP_ONE_LINE (RGA_IOMMU_BASE + 0x10) /* Shootdown one IOTLB entry */ ++#define RGA_IOMMU_INT_RAWSTAT (RGA_IOMMU_BASE + 0x14) /* IRQ status ignoring mask */ ++#define RGA_IOMMU_INT_CLEAR (RGA_IOMMU_BASE + 0x18) /* Acknowledge and re-arm irq */ ++#define RGA_IOMMU_INT_MASK (RGA_IOMMU_BASE + 0x1C) /* IRQ enable */ ++#define RGA_IOMMU_INT_STATUS (RGA_IOMMU_BASE + 0x20) /* IRQ status after masking */ ++#define RGA_IOMMU_AUTO_GATING (RGA_IOMMU_BASE + 0x24) ++ ++/* RGA_IOMMU_STATUS fields */ ++#define RGA_IOMMU_STATUS_PAGING_ENABLED BIT(0) ++#define RGA_IOMMU_STATUS_PAGE_FAULT_ACTIVE BIT(1) ++#define RGA_IOMMU_STATUS_STALL_ACTIVE BIT(2) ++#define RGA_IOMMU_STATUS_IDLE BIT(3) ++#define RGA_IOMMU_STATUS_REPLAY_BUFFER_EMPTY BIT(4) ++#define RGA_IOMMU_STATUS_PAGE_FAULT_IS_WRITE BIT(5) ++#define RGA_IOMMU_STATUS_STALL_NOT_ACTIVE BIT(31) ++ ++/* RGA_IOMMU_COMMAND command values */ ++#define RGA_IOMMU_CMD_ENABLE_PAGING 0 /* Enable memory translation */ ++#define RGA_IOMMU_CMD_DISABLE_PAGING 1 /* Disable memory translation */ ++#define RGA_IOMMU_CMD_ENABLE_STALL 2 /* Stall paging to allow other cmds */ ++#define RGA_IOMMU_CMD_DISABLE_STALL 3 /* Stop stall re-enables paging */ ++#define RGA_IOMMU_CMD_ZAP_CACHE 4 /* Shoot down entire IOTLB */ ++#define RGA_IOMMU_CMD_PAGE_FAULT_DONE 5 /* Clear page fault */ ++#define RGA_IOMMU_CMD_FORCE_RESET 6 /* Reset all registers */ ++ ++/* RGA_IOMMU_INT_* register fields */ ++#define RGA_IOMMU_IRQ_PAGE_FAULT 0x01 /* page fault */ ++#define RGA_IOMMU_IRQ_BUS_ERROR 0x02 /* bus read error */ ++#define RGA_IOMMU_IRQ_MASK (RGA_IOMMU_IRQ_PAGE_FAULT | RGA_IOMMU_IRQ_BUS_ERROR) ++ ++/* ++ * The maximum input is 8192*8192, the maximum output is 4096*4096 ++ * The size of physical pages requested is: ++ * (( maximum_input_value * ++ * maximum_input_value * format_bpp ) / 4K_page_size) + 1 ++ */ ++#define RGA2_PHY_PAGE_SIZE (((8192 * 8192 * 4) / 4096) + 1) ++ ++struct rga_mmu_base { ++ unsigned int *buf_virtual; ++ struct page **pages; ++ u8 buf_order; ++ u8 pages_order; ++ ++ int32_t front; ++ int32_t back; ++ int32_t size; ++ int32_t curr; ++}; ++ ++int rga_user_memory_check(struct page **pages, u32 w, u32 h, u32 format, int flag); ++int rga_set_mmu_base(struct rga_job *job, struct rga2_req *req); ++unsigned int *rga_mmu_buf_get(struct rga_mmu_base *mmu_base, uint32_t size); ++ ++struct rga_mmu_base *rga_mmu_base_init(size_t size); ++void rga_mmu_base_free(struct rga_mmu_base **mmu_base); ++ ++int rga_iommu_detach(struct rga_iommu_info *info); ++int rga_iommu_attach(struct rga_iommu_info *info); ++struct rga_iommu_info *rga_iommu_probe(struct device *dev); ++int rga_iommu_remove(struct rga_iommu_info *info); ++ ++int rga_iommu_bind(void); ++void rga_iommu_unbind(void); ++ ++#endif ++ +diff --git a/drivers/video/rockchip/rga3/include/rga_job.h b/drivers/video/rockchip/rga3/include/rga_job.h +new file mode 100644 +index 000000000..0fc776173 +--- /dev/null ++++ b/drivers/video/rockchip/rga3/include/rga_job.h +@@ -0,0 +1,53 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) Rockchip Electronics Co., Ltd. ++ * ++ * Author: Huang Lee ++ */ ++ ++#ifndef __LINUX_RKRGA_JOB_H_ ++#define __LINUX_RKRGA_JOB_H_ ++ ++#include ++#include ++ ++#include "rga_drv.h" ++ ++enum job_flags { ++ RGA_JOB_DONE = 1 << 0, ++ RGA_JOB_ASYNC = 1 << 1, ++ RGA_JOB_SYNC = 1 << 2, ++ RGA_JOB_USE_HANDLE = 1 << 3, ++ RGA_JOB_UNSUPPORT_RGA_MMU = 1 << 4, ++}; ++ ++void rga_job_scheduler_dump_info(struct rga_scheduler_t *scheduler); ++void rga_job_next(struct rga_scheduler_t *scheduler); ++struct rga_job *rga_job_done(struct rga_scheduler_t *scheduler); ++struct rga_job *rga_job_commit(struct rga_req *rga_command_base, struct rga_request *request); ++int rga_job_mpi_commit(struct rga_req *rga_command_base, struct rga_request *request); ++ ++int rga_job_assign(struct rga_job *job); ++ ++ ++int rga_request_check(struct rga_user_request *req); ++struct rga_request *rga_request_lookup(struct rga_pending_request_manager *request_manager, ++ uint32_t id); ++ ++int rga_request_commit(struct rga_request *user_request); ++void rga_request_session_destroy_abort(struct rga_session *session); ++int rga_request_put(struct rga_request *request); ++void rga_request_get(struct rga_request *request); ++int rga_request_free(struct rga_request *request); ++int rga_request_alloc(uint32_t flags, struct rga_session *session); ++ ++struct rga_request *rga_request_config(struct rga_user_request *user_request); ++struct rga_request *rga_request_kernel_config(struct rga_user_request *user_request); ++int rga_request_submit(struct rga_request *request); ++int rga_request_mpi_submit(struct rga_req *req, struct rga_request *request); ++int rga_request_release_signal(struct rga_scheduler_t *scheduler, struct rga_job *job); ++ ++int rga_request_manager_init(struct rga_pending_request_manager **request_manager_session); ++int rga_request_manager_remove(struct rga_pending_request_manager **request_manager_session); ++ ++#endif /* __LINUX_RKRGA_JOB_H_ */ +diff --git a/drivers/video/rockchip/rga3/include/rga_mm.h b/drivers/video/rockchip/rga3/include/rga_mm.h +new file mode 100644 +index 000000000..d68fd75dc +--- /dev/null ++++ b/drivers/video/rockchip/rga3/include/rga_mm.h +@@ -0,0 +1,67 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) Rockchip Electronics Co., Ltd. ++ * ++ * Author: ++ * Cerf Yu ++ */ ++ ++#ifndef __LINUX_RKRGA_MM_H_ ++#define __LINUX_RKRGA_MM_H_ ++ ++#include "rga_drv.h" ++ ++enum rga_mm_flag { ++ /* It will identify whether the buffer is within 0 ~ 4G. */ ++ RGA_MEM_UNDER_4G = 1 << 0, ++ /* Logo enable IOMMU */ ++ RGA_MEM_NEED_USE_IOMMU = 1 << 1, ++ /* Flag this is a physical contiguous memory. */ ++ RGA_MEM_PHYSICAL_CONTIGUOUS = 1 << 2, ++ /* need force flush cache */ ++ RGA_MEM_FORCE_FLUSH_CACHE = 1 << 3, ++}; ++ ++struct rga_mm { ++ struct mutex lock; ++ ++ /* ++ * @memory_idr: ++ * ++ * Mapping of memory object handles to object pointers. Used by the GEM ++ * subsystem. Protected by @memory_lock. ++ */ ++ struct idr memory_idr; ++ ++ /* the count of buffer in the cached_list */ ++ int buffer_count; ++}; ++ ++static inline bool rga_mm_is_invalid_dma_buffer(struct rga_dma_buffer *buffer) ++{ ++ if (buffer == NULL) ++ return true; ++ ++ return buffer->scheduler == NULL ? true : false; ++} ++ ++struct rga_internal_buffer *rga_mm_lookup_handle(struct rga_mm *mm_session, uint32_t handle); ++int rga_mm_lookup_flag(struct rga_mm *mm_session, uint64_t handle); ++dma_addr_t rga_mm_lookup_iova(struct rga_internal_buffer *buffer); ++struct sg_table *rga_mm_lookup_sgt(struct rga_internal_buffer *buffer); ++ ++void rga_mm_dump_buffer(struct rga_internal_buffer *dump_buffer); ++void rga_mm_dump_info(struct rga_mm *session); ++ ++int rga_mm_map_job_info(struct rga_job *job); ++void rga_mm_unmap_job_info(struct rga_job *job); ++ ++int rga_mm_import_buffer(struct rga_external_buffer *external_buffer, ++ struct rga_session *session); ++int rga_mm_release_buffer(uint32_t handle); ++int rga_mm_session_release_buffer(struct rga_session *session); ++ ++int rga_mm_init(struct rga_mm **session); ++int rga_mm_remove(struct rga_mm **session); ++ ++#endif +diff --git a/drivers/video/rockchip/rga3/rga2_reg_info.c b/drivers/video/rockchip/rga3/rga2_reg_info.c +new file mode 100644 +index 000000000..8792e8d64 +--- /dev/null ++++ b/drivers/video/rockchip/rga3/rga2_reg_info.c +@@ -0,0 +1,2742 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) Rockchip Electronics Co., Ltd. ++ * ++ * Author: Huang Lee ++ */ ++ ++#define pr_fmt(fmt) "rga2_reg: " fmt ++ ++#include "rga2_reg_info.h" ++#include "rga_dma_buf.h" ++#include "rga_iommu.h" ++#include "rga_common.h" ++#include "rga_hw_config.h" ++#include "rga_debugger.h" ++ ++unsigned int rga2_rop_code[256] = { ++ 0x00000007, 0x00000451, 0x00006051, 0x00800051, ++ 0x00007041, 0x00800041, 0x00804830, 0x000004f0,//0 ++ 0x00800765, 0x000004b0, 0x00000065, 0x000004f4, ++ 0x00000075, 0x000004e6, 0x00804850, 0x00800005, ++ ++ 0x00006850, 0x00800050, 0x00805028, 0x00000568, ++ 0x00804031, 0x00000471, 0x002b6071, 0x018037aa,//1 ++ 0x008007aa, 0x00036071, 0x00002c6a, 0x00803631, ++ 0x00002d68, 0x00802721, 0x008002d0, 0x000006d0, ++ ++ 0x0080066e, 0x00000528, 0x00000066, 0x0000056c, ++ 0x018007aa, 0x0002e06a, 0x00003471, 0x00834031,//2 ++ 0x00800631, 0x0002b471, 0x00006071, 0x008037aa, ++ 0x000036d0, 0x008002d4, 0x00002d28, 0x000006d4, ++ ++ 0x0000006e, 0x00000565, 0x00003451, 0x00800006, ++ 0x000034f0, 0x00834830, 0x00800348, 0x00000748,//3 ++ 0x00002f48, 0x0080034c, 0x000034b0, 0x0000074c, ++ 0x00000031, 0x00834850, 0x000034e6, 0x00800071, ++ ++ 0x008006f4, 0x00000431, 0x018007a1, 0x00b6e870, ++ 0x00000074, 0x0000046e, 0x00002561, 0x00802f28,//4 ++ 0x00800728, 0x0002a561, 0x000026c2, 0x008002c6, ++ 0x00007068, 0x018035aa, 0x00002c2a, 0x000006c6, ++ ++ 0x0000006c, 0x00000475, 0x000024e2, 0x008036b0, ++ 0x00804051, 0x00800004, 0x00800251, 0x00000651, ++ 0x00002e4a, 0x0080024e, 0x00000028, 0x00824842, ++ 0x000024a2, 0x0000064e, 0x000024f4, 0x00800068,//5 ++ ++ 0x008006b0, 0x000234f0, 0x00002741, 0x00800345, ++ 0x00003651, 0x00800255, 0x00000030, 0x00834051, ++ 0x00a34842, 0x000002b0, 0x00800271, 0x0002b651, ++ 0x00800368, 0x0002a741, 0x0000364e, 0x00806830,//6 ++ ++ 0x00006870, 0x008037a2, 0x00003431, 0x00000745, ++ 0x00002521, 0x00000655, 0x0000346e, 0x00800062, ++ 0x008002f0, 0x000236d0, 0x000026d4, 0x00807028, ++ 0x000036c6, 0x00806031, 0x008005aa, 0x00000671,//7 ++ ++ 0x00800671, 0x000005aa, 0x00006031, 0x008036c6, ++ 0x00007028, 0x00802e55, 0x008236d0, 0x000002f0, ++ 0x00000070, 0x0080346e, 0x00800655, 0x00802521, ++ 0x00800745, 0x00803431, 0x000037a2, 0x00806870,//8 ++ ++ 0x00006830, 0x0080364e, 0x00822f48, 0x00000361, ++ 0x0082b651, 0x00000271, 0x00800231, 0x002b4051, ++ 0x00034051, 0x00800030, 0x0080026e, 0x00803651, ++ 0x0080036c, 0x00802741, 0x008234f0, 0x000006b0,//9 ++ ++ 0x00000068, 0x00802c75, 0x0080064e, 0x008024a2, ++ 0x0002c04a, 0x00800021, 0x00800275, 0x00802e51, ++ 0x00800651, 0x00000251, 0x00800000, 0x00004051, ++ 0x000036b0, 0x008024e2, 0x00800475, 0x00000045,//a ++ ++ 0x008006c6, 0x00802c2a, 0x000035aa, 0x00807068, ++ 0x008002f4, 0x008026c2, 0x00822d68, 0x00000728, ++ 0x00002f28, 0x00802561, 0x0080046e, 0x00000046, ++ 0x00836870, 0x000007a2, 0x00800431, 0x00004071,//b ++ ++ 0x00000071, 0x008034e6, 0x00034850, 0x00800031, ++ 0x0080074c, 0x008034b0, 0x00800365, 0x00802f48, ++ 0x00800748, 0x00000341, 0x000026a2, 0x008034f0, ++ 0x00800002, 0x00005048, 0x00800565, 0x00000055,//c ++ ++ 0x008006d4, 0x00802d28, 0x008002e6, 0x008036d0, ++ 0x000037aa, 0x00806071, 0x0082b471, 0x00000631, ++ 0x00002e2a, 0x00803471, 0x00826862, 0x010007aa, ++ 0x0080056c, 0x00000054, 0x00800528, 0x00005068,//d ++ ++ 0x008006d0, 0x000002d0, 0x00002721, 0x00802d68, ++ 0x00003631, 0x00802c6a, 0x00836071, 0x000007aa, ++ 0x010037aa, 0x00a36870, 0x00800471, 0x00004031, ++ 0x00800568, 0x00005028, 0x00000050, 0x00800545,//e ++ ++ 0x00800001, 0x00004850, 0x008004e6, 0x0000004e, ++ 0x008004f4, 0x0000004c, 0x008004b0, 0x00004870, ++ 0x008004f0, 0x00004830, 0x00000048, 0x0080044e, ++ 0x00000051, 0x008004d4, 0x00800451, 0x00800007,//f ++}; ++ ++static void RGA2_reg_get_param(unsigned char *base, struct rga2_req *msg) ++{ ++ u32 *bRGA_SRC_X_FACTOR; ++ u32 *bRGA_SRC_Y_FACTOR; ++ u32 sw, sh; ++ u32 dw, dh; ++ u32 param_x, param_y; ++ ++ bRGA_SRC_X_FACTOR = (u32 *) (base + RGA2_SRC_X_FACTOR_OFFSET); ++ bRGA_SRC_Y_FACTOR = (u32 *) (base + RGA2_SRC_Y_FACTOR_OFFSET); ++ ++ if (((msg->rotate_mode & 0x3) == 1) || ++ ((msg->rotate_mode & 0x3) == 3)) { ++ dw = msg->dst.act_h; ++ dh = msg->dst.act_w; ++ } else { ++ dw = msg->dst.act_w; ++ dh = msg->dst.act_h; ++ } ++ ++ sw = msg->src.act_w; ++ sh = msg->src.act_h; ++ ++ if (sw > dw) { ++#if SCALE_DOWN_LARGE ++ param_x = ((dw) << 16) / (sw) + 1; ++#else ++ param_x = ((dw) << 16) / (sw); ++#endif ++ *bRGA_SRC_X_FACTOR |= ((param_x & 0xffff) << 0); ++ } else if (sw < dw) { ++#if SCALE_UP_LARGE ++ param_x = ((sw - 1) << 16) / (dw - 1); ++#else ++ param_x = ((sw) << 16) / (dw); ++#endif ++ *bRGA_SRC_X_FACTOR |= ((param_x & 0xffff) << 16); ++ } else { ++ *bRGA_SRC_X_FACTOR = 0; //((1 << 14) << 16) | (1 << 14); ++ } ++ ++ if (sh > dh) { ++#if SCALE_DOWN_LARGE ++ param_y = ((dh) << 16) / (sh) + 1; ++#else ++ param_y = ((dh) << 16) / (sh); ++#endif ++ *bRGA_SRC_Y_FACTOR |= ((param_y & 0xffff) << 0); ++ } else if (sh < dh) { ++#if SCALE_UP_LARGE ++ param_y = ((sh - 1) << 16) / (dh - 1); ++#else ++ param_y = ((sh) << 16) / (dh); ++#endif ++ *bRGA_SRC_Y_FACTOR |= ((param_y & 0xffff) << 16); ++ } else { ++ *bRGA_SRC_Y_FACTOR = 0; //((1 << 14) << 16) | (1 << 14); ++ } ++} ++ ++static void RGA2_set_mode_ctrl(u8 *base, struct rga2_req *msg) ++{ ++ u32 *bRGA_MODE_CTL; ++ u32 reg = 0; ++ u32 render_mode = msg->render_mode; ++ ++ bRGA_MODE_CTL = (u32 *) (base + RGA2_MODE_CTRL_OFFSET); ++ ++ if (msg->render_mode == UPDATE_PALETTE_TABLE_MODE) ++ render_mode = 0x3; ++ ++ reg = ++ ((reg & (~m_RGA2_MODE_CTRL_SW_RENDER_MODE)) | ++ (s_RGA2_MODE_CTRL_SW_RENDER_MODE(render_mode))); ++ reg = ++ ((reg & (~m_RGA2_MODE_CTRL_SW_BITBLT_MODE)) | ++ (s_RGA2_MODE_CTRL_SW_BITBLT_MODE(msg->bitblt_mode))); ++ reg = ++ ((reg & (~m_RGA2_MODE_CTRL_SW_CF_ROP4_PAT)) | ++ (s_RGA2_MODE_CTRL_SW_CF_ROP4_PAT(msg->color_fill_mode))); ++ reg = ++ ((reg & (~m_RGA2_MODE_CTRL_SW_ALPHA_ZERO_KET)) | ++ (s_RGA2_MODE_CTRL_SW_ALPHA_ZERO_KET(msg->alpha_zero_key))); ++ reg = ++ ((reg & (~m_RGA2_MODE_CTRL_SW_GRADIENT_SAT)) | ++ (s_RGA2_MODE_CTRL_SW_GRADIENT_SAT(msg->alpha_rop_flag >> 7))); ++ reg = ++ ((reg & (~m_RGA2_MODE_CTRL_SW_INTR_CF_E)) | ++ (s_RGA2_MODE_CTRL_SW_INTR_CF_E(msg->CMD_fin_int_enable))); ++ ++ reg = ((reg & (~m_RGA2_MODE_CTRL_SW_MOSAIC_EN)) | ++ (s_RGA2_MODE_CTRL_SW_MOSAIC_EN(msg->mosaic_info.enable))); ++ ++ reg = ((reg & (~m_RGA2_MODE_CTRL_SW_YIN_YOUT_EN)) | ++ (s_RGA2_MODE_CTRL_SW_YIN_YOUT_EN(msg->yin_yout_en))); ++ ++ reg = ((reg & (~m_RGA2_MODE_CTRL_SW_OSD_E)) | ++ (s_RGA2_MODE_CTRL_SW_OSD_E(msg->osd_info.enable))); ++ ++ *bRGA_MODE_CTL = reg; ++} ++ ++static void RGA2_set_reg_src_info(u8 *base, struct rga2_req *msg) ++{ ++ u32 *bRGA_SRC_INFO; ++ u32 *bRGA_SRC_BASE0, *bRGA_SRC_BASE1, *bRGA_SRC_BASE2; ++ u32 *bRGA_SRC_VIR_INFO; ++ u32 *bRGA_SRC_ACT_INFO; ++ u32 *bRGA_MASK_ADDR; ++ u32 *bRGA_SRC_TR_COLOR0, *bRGA_SRC_TR_COLOR1; ++ ++ u8 disable_uv_channel_en = 0; ++ ++ u32 reg = 0; ++ u8 src0_format = 0; ++ ++ u8 src0_rb_swp = 0; ++ u8 src0_alpha_swp = 0; ++ ++ u8 src0_cbcr_swp = 0; ++ u8 pixel_width = 1; ++ u32 stride = 0; ++ u32 uv_stride = 0; ++ u32 mask_stride = 0; ++ u32 ydiv = 1, xdiv = 2; ++ u8 yuv10 = 0; ++ ++ u32 sw, sh; ++ u32 dw, dh; ++ u8 rotate_mode; ++ u8 vsp_scale_mode = 0; ++ u8 scale_w_flag, scale_h_flag; ++ ++ bRGA_SRC_INFO = (u32 *) (base + RGA2_SRC_INFO_OFFSET); ++ ++ bRGA_SRC_BASE0 = (u32 *) (base + RGA2_SRC_BASE0_OFFSET); ++ bRGA_SRC_BASE1 = (u32 *) (base + RGA2_SRC_BASE1_OFFSET); ++ bRGA_SRC_BASE2 = (u32 *) (base + RGA2_SRC_BASE2_OFFSET); ++ ++ bRGA_SRC_VIR_INFO = (u32 *) (base + RGA2_SRC_VIR_INFO_OFFSET); ++ bRGA_SRC_ACT_INFO = (u32 *) (base + RGA2_SRC_ACT_INFO_OFFSET); ++ ++ bRGA_MASK_ADDR = (u32 *) (base + RGA2_MASK_BASE_OFFSET); ++ ++ bRGA_SRC_TR_COLOR0 = (u32 *) (base + RGA2_SRC_TR_COLOR0_OFFSET); ++ bRGA_SRC_TR_COLOR1 = (u32 *) (base + RGA2_SRC_TR_COLOR1_OFFSET); ++ ++ if (msg->src.format == RGA_FORMAT_YCbCr_420_SP_10B || ++ msg->src.format == RGA_FORMAT_YCrCb_420_SP_10B) { ++ if ((msg->src.act_w == msg->dst.act_w) && ++ (msg->src.act_h == msg->dst.act_h) && ++ (msg->rotate_mode == 0)) ++ msg->rotate_mode = 1 << 6; ++ } ++ ++ { ++ rotate_mode = msg->rotate_mode & 0x3; ++ ++ sw = msg->src.act_w; ++ sh = msg->src.act_h; ++ ++ if ((rotate_mode == 1) | (rotate_mode == 3)) { ++ dw = msg->dst.act_h; ++ dh = msg->dst.act_w; ++ } else { ++ dw = msg->dst.act_w; ++ dh = msg->dst.act_h; ++ } ++ ++ if (sw > dw) ++ scale_w_flag = 1; ++ else if (sw < dw) ++ scale_w_flag = 2; ++ else { ++ scale_w_flag = 0; ++ if (msg->rotate_mode >> 6) ++ scale_w_flag = 3; ++ } ++ ++ if (sh > dh) ++ scale_h_flag = 1; ++ else if (sh < dh) ++ scale_h_flag = 2; ++ else { ++ scale_h_flag = 0; ++ if (msg->rotate_mode >> 6) ++ scale_h_flag = 3; ++ } ++ ++ /* uvvds need to force tile mode. */ ++ if (msg->uvvds_mode && scale_w_flag == 0) ++ scale_w_flag = 3; ++ } ++ ++ /* VSP scale mode select, HSD > VSD > VSP > HSP */ ++ if (scale_h_flag == 0x2) { ++ /* After HSD, VSP needs to check dst_width */ ++ if ((scale_w_flag == 0x1) && (dw < RGA2_VSP_BICUBIC_LIMIT)) ++ vsp_scale_mode = 0x0; ++ else if (sw < RGA2_VSP_BICUBIC_LIMIT) ++ vsp_scale_mode = 0x0; ++ else ++ /* default select bilinear */ ++ vsp_scale_mode = 0x1; ++ } ++ ++ switch (msg->src.format) { ++ case RGA_FORMAT_RGBA_8888: ++ src0_format = 0x0; ++ pixel_width = 4; ++ break; ++ case RGA_FORMAT_BGRA_8888: ++ src0_format = 0x0; ++ src0_rb_swp = 0x1; ++ pixel_width = 4; ++ break; ++ case RGA_FORMAT_RGBX_8888: ++ src0_format = 0x1; ++ pixel_width = 4; ++ msg->src_trans_mode &= 0x07; ++ break; ++ case RGA_FORMAT_BGRX_8888: ++ src0_format = 0x1; ++ src0_rb_swp = 0x1; ++ pixel_width = 4; ++ msg->src_trans_mode &= 0x07; ++ break; ++ case RGA_FORMAT_RGB_888: ++ src0_format = 0x2; ++ pixel_width = 3; ++ msg->src_trans_mode &= 0x07; ++ break; ++ case RGA_FORMAT_BGR_888: ++ src0_format = 0x2; ++ src0_rb_swp = 1; ++ pixel_width = 3; ++ msg->src_trans_mode &= 0x07; ++ break; ++ case RGA_FORMAT_RGB_565: ++ src0_format = 0x4; ++ pixel_width = 2; ++ msg->src_trans_mode &= 0x07; ++ break; ++ case RGA_FORMAT_RGBA_5551: ++ src0_format = 0x5; ++ pixel_width = 2; ++ break; ++ case RGA_FORMAT_RGBA_4444: ++ src0_format = 0x6; ++ pixel_width = 2; ++ break; ++ case RGA_FORMAT_BGR_565: ++ src0_format = 0x4; ++ pixel_width = 2; ++ msg->src_trans_mode &= 0x07; ++ src0_rb_swp = 0x1; ++ break; ++ case RGA_FORMAT_BGRA_5551: ++ src0_format = 0x5; ++ pixel_width = 2; ++ src0_rb_swp = 0x1; ++ break; ++ case RGA_FORMAT_BGRA_4444: ++ src0_format = 0x6; ++ pixel_width = 2; ++ src0_rb_swp = 0x1; ++ break; ++ ++ /* ARGB */ ++ /* ++ * In colorkey mode, xrgb/xbgr does not ++ * need to enable the alpha channel ++ */ ++ case RGA_FORMAT_ARGB_8888: ++ src0_format = 0x0; ++ pixel_width = 4; ++ src0_alpha_swp = 1; ++ break; ++ case RGA_FORMAT_ABGR_8888: ++ src0_format = 0x0; ++ pixel_width = 4; ++ src0_alpha_swp = 1; ++ src0_rb_swp = 0x1; ++ break; ++ case RGA_FORMAT_XRGB_8888: ++ src0_format = 0x1; ++ pixel_width = 4; ++ src0_alpha_swp = 1; ++ msg->src_trans_mode &= 0x07; ++ break; ++ case RGA_FORMAT_XBGR_8888: ++ src0_format = 0x1; ++ pixel_width = 4; ++ src0_alpha_swp = 1; ++ src0_rb_swp = 0x1; ++ msg->src_trans_mode &= 0x07; ++ break; ++ case RGA_FORMAT_ARGB_5551: ++ src0_format = 0x5; ++ pixel_width = 2; ++ src0_alpha_swp = 1; ++ break; ++ case RGA_FORMAT_ABGR_5551: ++ src0_format = 0x5; ++ pixel_width = 2; ++ src0_alpha_swp = 1; ++ src0_rb_swp = 0x1; ++ break; ++ case RGA_FORMAT_ARGB_4444: ++ src0_format = 0x6; ++ pixel_width = 2; ++ src0_alpha_swp = 1; ++ break; ++ case RGA_FORMAT_ABGR_4444: ++ src0_format = 0x6; ++ pixel_width = 2; ++ src0_alpha_swp = 1; ++ src0_rb_swp = 0x1; ++ break; ++ ++ case RGA_FORMAT_YVYU_422: ++ src0_format = 0x7; ++ pixel_width = 2; ++ src0_cbcr_swp = 1; ++ src0_rb_swp = 0x1; ++ break; //rbswap=ycswap ++ case RGA_FORMAT_VYUY_422: ++ src0_format = 0x7; ++ pixel_width = 2; ++ src0_cbcr_swp = 1; ++ src0_rb_swp = 0x0; ++ break; ++ case RGA_FORMAT_YUYV_422: ++ src0_format = 0x7; ++ pixel_width = 2; ++ src0_cbcr_swp = 0; ++ src0_rb_swp = 0x1; ++ break; ++ case RGA_FORMAT_UYVY_422: ++ src0_format = 0x7; ++ pixel_width = 2; ++ src0_cbcr_swp = 0; ++ src0_rb_swp = 0x0; ++ break; ++ ++ case RGA_FORMAT_YCbCr_422_SP: ++ src0_format = 0x8; ++ xdiv = 1; ++ ydiv = 1; ++ break; ++ case RGA_FORMAT_YCbCr_422_P: ++ src0_format = 0x9; ++ xdiv = 2; ++ ydiv = 1; ++ break; ++ case RGA_FORMAT_YCbCr_420_SP: ++ src0_format = 0xa; ++ xdiv = 1; ++ ydiv = 2; ++ break; ++ case RGA_FORMAT_YCbCr_420_P: ++ src0_format = 0xb; ++ xdiv = 2; ++ ydiv = 2; ++ break; ++ case RGA_FORMAT_YCrCb_422_SP: ++ src0_format = 0x8; ++ xdiv = 1; ++ ydiv = 1; ++ src0_cbcr_swp = 1; ++ break; ++ case RGA_FORMAT_YCrCb_422_P: ++ src0_format = 0x9; ++ xdiv = 2; ++ ydiv = 1; ++ src0_cbcr_swp = 1; ++ break; ++ case RGA_FORMAT_YCrCb_420_SP: ++ src0_format = 0xa; ++ xdiv = 1; ++ ydiv = 2; ++ src0_cbcr_swp = 1; ++ break; ++ case RGA_FORMAT_YCrCb_420_P: ++ src0_format = 0xb; ++ xdiv = 2; ++ ydiv = 2; ++ src0_cbcr_swp = 1; ++ break; ++ ++ case RGA_FORMAT_YCbCr_420_SP_10B: ++ src0_format = 0xa; ++ xdiv = 1; ++ ydiv = 2; ++ yuv10 = 1; ++ break; ++ case RGA_FORMAT_YCrCb_420_SP_10B: ++ src0_format = 0xa; ++ xdiv = 1; ++ ydiv = 2; ++ src0_cbcr_swp = 1; ++ yuv10 = 1; ++ break; ++ case RGA_FORMAT_YCbCr_422_SP_10B: ++ src0_format = 0x8; ++ xdiv = 1; ++ ydiv = 1; ++ yuv10 = 1; ++ break; ++ case RGA_FORMAT_YCrCb_422_SP_10B: ++ src0_format = 0x8; ++ xdiv = 1; ++ ydiv = 1; ++ src0_cbcr_swp = 1; ++ yuv10 = 1; ++ break; ++ ++ case RGA_FORMAT_YCbCr_400: ++ src0_format = 0x8; ++ /* When Yin_Yout is enabled, no need to go through the software. */ ++ disable_uv_channel_en = msg->yin_yout_en ? false : true; ++ xdiv = 1; ++ ydiv = 1; ++ break; ++ }; ++ ++ reg = ++ ((reg & (~m_RGA2_SRC_INFO_SW_SRC_FMT)) | ++ (s_RGA2_SRC_INFO_SW_SRC_FMT(src0_format))); ++ reg = ++ ((reg & (~m_RGA2_SRC_INFO_SW_SW_SRC_RB_SWAP)) | ++ (s_RGA2_SRC_INFO_SW_SW_SRC_RB_SWAP(src0_rb_swp))); ++ reg = ++ ((reg & (~m_RGA2_SRC_INFO_SW_SW_SRC_ALPHA_SWAP)) | ++ (s_RGA2_SRC_INFO_SW_SW_SRC_ALPHA_SWAP(src0_alpha_swp))); ++ reg = ++ ((reg & (~m_RGA2_SRC_INFO_SW_SW_SRC_UV_SWAP)) | ++ (s_RGA2_SRC_INFO_SW_SW_SRC_UV_SWAP(src0_cbcr_swp))); ++ ++ if (msg->src1.format == RGA_FORMAT_RGBA_2BPP) ++ reg = ((reg & (~m_RGA2_SRC_INFO_SW_SW_CP_ENDIAN)) | ++ (s_RGA2_SRC_INFO_SW_SW_CP_ENDAIN(msg->osd_info.bpp2_info.endian_swap & 1))); ++ ++ reg = ++ ((reg & (~m_RGA2_SRC_INFO_SW_SW_SRC_CSC_MODE)) | ++ (s_RGA2_SRC_INFO_SW_SW_SRC_CSC_MODE(msg->yuv2rgb_mode))); ++ ++ reg = ++ ((reg & (~m_RGA2_SRC_INFO_SW_SW_SRC_ROT_MODE)) | ++ (s_RGA2_SRC_INFO_SW_SW_SRC_ROT_MODE(msg->rotate_mode & 0x3))); ++ reg = ++ ((reg & (~m_RGA2_SRC_INFO_SW_SW_SRC_MIR_MODE)) | ++ (s_RGA2_SRC_INFO_SW_SW_SRC_MIR_MODE ++ ((msg->rotate_mode >> 4) & 0x3))); ++ reg = ++ ((reg & (~m_RGA2_SRC_INFO_SW_SW_SRC_HSCL_MODE)) | ++ (s_RGA2_SRC_INFO_SW_SW_SRC_HSCL_MODE((scale_w_flag)))); ++ reg = ++ ((reg & (~m_RGA2_SRC_INFO_SW_SW_SRC_VSCL_MODE)) | ++ (s_RGA2_SRC_INFO_SW_SW_SRC_VSCL_MODE((scale_h_flag)))); ++ reg = ++ ((reg & (~m_RGA2_SRC_INFO_SW_SW_SRC_SCL_FILTER)) | ++ (s_RGA2_SRC_INFO_SW_SW_SRC_SCL_FILTER(( ++ msg->scale_bicu_mode)))); ++ reg = ++ ((reg & (~m_RGA2_SRC_INFO_SW_SW_SRC_TRANS_MODE)) | ++ (s_RGA2_SRC_INFO_SW_SW_SRC_TRANS_MODE(msg->src_trans_mode))); ++ reg = ++ ((reg & (~m_RGA2_SRC_INFO_SW_SW_SRC_TRANS_E)) | ++ (s_RGA2_SRC_INFO_SW_SW_SRC_TRANS_E(msg->src_trans_mode >> 1))); ++ reg = ++ ((reg & (~m_RGA2_SRC_INFO_SW_SW_SRC_DITHER_UP_E)) | ++ (s_RGA2_SRC_INFO_SW_SW_SRC_DITHER_UP_E ++ ((msg->alpha_rop_flag >> 4) & 0x1))); ++ reg = ++ ((reg & (~m_RGA2_SRC_INFO_SW_SW_VSP_MODE_SEL)) | ++ (s_RGA2_SRC_INFO_SW_SW_VSP_MODE_SEL((vsp_scale_mode)))); ++ reg = ++ ((reg & (~m_RGA2_SRC_INFO_SW_SW_YUV10_E)) | ++ (s_RGA2_SRC_INFO_SW_SW_YUV10_E((yuv10)))); ++ ++ reg = ++ ((reg & (~m_RGA2_SRC_INFO_SW_SW_YUV10_ROUND_E)) | ++ (s_RGA2_SRC_INFO_SW_SW_YUV10_ROUND_E((yuv10)))); ++ ++ RGA2_reg_get_param(base, msg); ++ ++ stride = (((msg->src.vir_w * pixel_width) + 3) & ~3) >> 2; ++ uv_stride = ((msg->src.vir_w / xdiv + 3) & ~3); ++ ++ if (disable_uv_channel_en == 1) { ++ /* ++ * When Y400 as the input format, because the current ++ * RGA does not support closing ++ * the access of the UV channel, the address of the UV ++ * channel access is equal to ++ * the address of the Y channel access to ensure that ++ * the UV channel can access, ++ * preventing the RGA hardware from reporting errors. ++ */ ++ *bRGA_SRC_BASE0 = ++ (u32) (msg->src.yrgb_addr + ++ msg->src.y_offset * (stride << 2) + ++ msg->src.x_offset * pixel_width); ++ *bRGA_SRC_BASE1 = *bRGA_SRC_BASE0; ++ *bRGA_SRC_BASE2 = *bRGA_SRC_BASE0; ++ } else { ++ *bRGA_SRC_BASE0 = ++ (u32) (msg->src.yrgb_addr + ++ msg->src.y_offset * (stride << 2) + ++ msg->src.x_offset * pixel_width); ++ *bRGA_SRC_BASE1 = ++ (u32) (msg->src.uv_addr + ++ (msg->src.y_offset / ydiv) * uv_stride + ++ (msg->src.x_offset / xdiv)); ++ *bRGA_SRC_BASE2 = ++ (u32) (msg->src.v_addr + ++ (msg->src.y_offset / ydiv) * uv_stride + ++ (msg->src.x_offset / xdiv)); ++ } ++ ++ //mask_stride = ((msg->src0_act.width + 31) & ~31) >> 5; ++ mask_stride = msg->rop_mask_stride; ++ ++ *bRGA_SRC_VIR_INFO = stride | (mask_stride << 16); ++ ++ *bRGA_SRC_ACT_INFO = ++ (msg->src.act_w - 1) | ((msg->src.act_h - 1) << 16); ++ ++ *bRGA_MASK_ADDR = (u32) msg->rop_mask_addr; ++ ++ *bRGA_SRC_INFO = reg; ++ ++ *bRGA_SRC_TR_COLOR0 = msg->color_key_min; ++ *bRGA_SRC_TR_COLOR1 = msg->color_key_max; ++} ++ ++static void RGA2_set_reg_dst_info(u8 *base, struct rga2_req *msg) ++{ ++ u32 *bRGA_DST_INFO; ++ u32 *bRGA_DST_BASE0, *bRGA_DST_BASE1, *bRGA_DST_BASE2, ++ *bRGA_SRC_BASE3; ++ u32 *bRGA_DST_VIR_INFO; ++ u32 *bRGA_DST_ACT_INFO; ++ ++ u32 *RGA_DST_Y4MAP_LUT0; //Y4 LUT0 ++ u32 *RGA_DST_Y4MAP_LUT1; //Y4 LUT1 ++ u32 *RGA_DST_NN_QUANTIZE_SCALE; ++ u32 *RGA_DST_NN_QUANTIZE_OFFSET; ++ ++ u32 line_width_real; ++ ++ u8 ydither_en = 0; ++ ++ u8 src1_format = 0; ++ u8 src1_rb_swp = 0; ++ u8 src1_alpha_swp = 0; ++ ++ u8 dst_format = 0; ++ u8 dst_rb_swp = 0; ++ u8 dst_cbcr_swp = 0; ++ u8 dst_alpha_swp = 0; ++ ++ u8 dst_fmt_yuv400_en = 0; ++ u8 dst_fmt_y4_en = 0; ++ u8 dst_nn_quantize_en = 0; ++ ++ u32 reg = 0; ++ u8 spw, dpw; ++ u8 bbp_shift = 0; ++ u32 s_stride, d_stride; ++ u32 x_mirr, y_mirr, rot_90_flag; ++ u32 yrgb_addr, u_addr, v_addr, s_yrgb_addr; ++ u32 d_uv_stride, x_div, y_div; ++ u32 y_lt_addr, y_ld_addr, y_rt_addr, y_rd_addr; ++ u32 u_lt_addr, u_ld_addr, u_rt_addr, u_rd_addr; ++ u32 v_lt_addr, v_ld_addr, v_rt_addr, v_rd_addr; ++ ++ dpw = 1; ++ x_div = y_div = 1; ++ ++ dst_nn_quantize_en = (msg->alpha_rop_flag >> 8) & 0x1; ++ ++ bRGA_DST_INFO = (u32 *) (base + RGA2_DST_INFO_OFFSET); ++ bRGA_DST_BASE0 = (u32 *) (base + RGA2_DST_BASE0_OFFSET); ++ bRGA_DST_BASE1 = (u32 *) (base + RGA2_DST_BASE1_OFFSET); ++ bRGA_DST_BASE2 = (u32 *) (base + RGA2_DST_BASE2_OFFSET); ++ ++ bRGA_SRC_BASE3 = (u32 *) (base + RGA2_SRC_BASE3_OFFSET); ++ ++ bRGA_DST_VIR_INFO = (u32 *) (base + RGA2_DST_VIR_INFO_OFFSET); ++ bRGA_DST_ACT_INFO = (u32 *) (base + RGA2_DST_ACT_INFO_OFFSET); ++ ++ RGA_DST_Y4MAP_LUT0 = (u32 *) (base + RGA2_DST_Y4MAP_LUT0_OFFSET); ++ RGA_DST_Y4MAP_LUT1 = (u32 *) (base + RGA2_DST_Y4MAP_LUT1_OFFSET); ++ RGA_DST_NN_QUANTIZE_SCALE = ++ (u32 *) (base + RGA2_DST_QUANTIZE_SCALE_OFFSET); ++ RGA_DST_NN_QUANTIZE_OFFSET = ++ (u32 *) (base + RGA2_DST_QUANTIZE_OFFSET_OFFSET); ++ ++ switch (msg->src1.format) { ++ case RGA_FORMAT_RGBA_8888: ++ src1_format = 0x0; ++ spw = 4; ++ break; ++ case RGA_FORMAT_BGRA_8888: ++ src1_format = 0x0; ++ src1_rb_swp = 0x1; ++ spw = 4; ++ break; ++ case RGA_FORMAT_RGBX_8888: ++ src1_format = 0x1; ++ spw = 4; ++ break; ++ case RGA_FORMAT_BGRX_8888: ++ src1_format = 0x1; ++ src1_rb_swp = 0x1; ++ spw = 4; ++ break; ++ case RGA_FORMAT_RGB_888: ++ src1_format = 0x2; ++ spw = 3; ++ break; ++ case RGA_FORMAT_BGR_888: ++ src1_format = 0x2; ++ src1_rb_swp = 1; ++ spw = 3; ++ break; ++ case RGA_FORMAT_RGB_565: ++ src1_format = 0x4; ++ spw = 2; ++ break; ++ case RGA_FORMAT_RGBA_5551: ++ src1_format = 0x5; ++ spw = 2; ++ break; ++ case RGA_FORMAT_RGBA_4444: ++ src1_format = 0x6; ++ spw = 2; ++ break; ++ case RGA_FORMAT_BGR_565: ++ src1_format = 0x4; ++ spw = 2; ++ src1_rb_swp = 0x1; ++ break; ++ case RGA_FORMAT_BGRA_5551: ++ src1_format = 0x5; ++ spw = 2; ++ src1_rb_swp = 0x1; ++ break; ++ case RGA_FORMAT_BGRA_4444: ++ src1_format = 0x6; ++ spw = 2; ++ src1_rb_swp = 0x1; ++ break; ++ ++ /* ARGB */ ++ case RGA_FORMAT_ARGB_8888: ++ src1_format = 0x0; ++ spw = 4; ++ src1_alpha_swp = 1; ++ break; ++ case RGA_FORMAT_ABGR_8888: ++ src1_format = 0x0; ++ spw = 4; ++ src1_alpha_swp = 1; ++ src1_rb_swp = 0x1; ++ break; ++ case RGA_FORMAT_XRGB_8888: ++ src1_format = 0x1; ++ spw = 4; ++ src1_alpha_swp = 1; ++ break; ++ case RGA_FORMAT_XBGR_8888: ++ src1_format = 0x1; ++ spw = 4; ++ src1_alpha_swp = 1; ++ src1_rb_swp = 0x1; ++ break; ++ case RGA_FORMAT_ARGB_5551: ++ src1_format = 0x5; ++ spw = 2; ++ src1_alpha_swp = 1; ++ break; ++ case RGA_FORMAT_ABGR_5551: ++ src1_format = 0x5; ++ spw = 2; ++ src1_alpha_swp = 1; ++ src1_rb_swp = 0x1; ++ break; ++ case RGA_FORMAT_ARGB_4444: ++ src1_format = 0x6; ++ spw = 2; ++ src1_alpha_swp = 1; ++ break; ++ case RGA_FORMAT_ABGR_4444: ++ src1_format = 0x6; ++ spw = 2; ++ src1_alpha_swp = 1; ++ src1_rb_swp = 0x1; ++ break; ++ case RGA_FORMAT_RGBA_2BPP: ++ src1_format = 0x0; ++ spw = 1; ++ /* 2BPP = 8 >> 2 = 2bit */ ++ bbp_shift = 2; ++ src1_alpha_swp = msg->osd_info.bpp2_info.ac_swap; ++ break; ++ default: ++ spw = 4; ++ break; ++ }; ++ ++ reg = ++ ((reg & (~m_RGA2_DST_INFO_SW_SRC1_FMT)) | ++ (s_RGA2_DST_INFO_SW_SRC1_FMT(src1_format))); ++ reg = ++ ((reg & (~m_RGA2_DST_INFO_SW_SRC1_RB_SWP)) | ++ (s_RGA2_DST_INFO_SW_SRC1_RB_SWP(src1_rb_swp))); ++ reg = ++ ((reg & (~m_RGA2_DST_INFO_SW_SRC1_ALPHA_SWP)) | ++ (s_RGA2_DST_INFO_SW_SRC1_ALPHA_SWP(src1_alpha_swp))); ++ ++ switch (msg->dst.format) { ++ case RGA_FORMAT_RGBA_8888: ++ dst_format = 0x0; ++ dpw = 4; ++ break; ++ case RGA_FORMAT_BGRA_8888: ++ dst_format = 0x0; ++ dst_rb_swp = 0x1; ++ dpw = 4; ++ break; ++ case RGA_FORMAT_RGBX_8888: ++ dst_format = 0x1; ++ dpw = 4; ++ break; ++ case RGA_FORMAT_BGRX_8888: ++ dst_format = 0x1; ++ dst_rb_swp = 0x1; ++ dpw = 4; ++ break; ++ case RGA_FORMAT_RGB_888: ++ dst_format = 0x2; ++ dpw = 3; ++ break; ++ case RGA_FORMAT_BGR_888: ++ dst_format = 0x2; ++ dst_rb_swp = 1; ++ dpw = 3; ++ break; ++ case RGA_FORMAT_RGB_565: ++ dst_format = 0x4; ++ dpw = 2; ++ break; ++ case RGA_FORMAT_RGBA_5551: ++ dst_format = 0x5; ++ dpw = 2; ++ break; ++ case RGA_FORMAT_RGBA_4444: ++ dst_format = 0x6; ++ dpw = 2; ++ break; ++ case RGA_FORMAT_BGR_565: ++ dst_format = 0x4; ++ dpw = 2; ++ dst_rb_swp = 0x1; ++ break; ++ case RGA_FORMAT_BGRA_5551: ++ dst_format = 0x5; ++ dpw = 2; ++ dst_rb_swp = 0x1; ++ break; ++ case RGA_FORMAT_BGRA_4444: ++ dst_format = 0x6; ++ dpw = 2; ++ dst_rb_swp = 0x1; ++ break; ++ ++ /* ARGB */ ++ case RGA_FORMAT_ARGB_8888: ++ dst_format = 0x0; ++ dpw = 4; ++ dst_alpha_swp = 1; ++ break; ++ case RGA_FORMAT_ABGR_8888: ++ dst_format = 0x0; ++ dpw = 4; ++ dst_alpha_swp = 1; ++ dst_rb_swp = 0x1; ++ break; ++ case RGA_FORMAT_XRGB_8888: ++ dst_format = 0x1; ++ dpw = 4; ++ dst_alpha_swp = 1; ++ break; ++ case RGA_FORMAT_XBGR_8888: ++ dst_format = 0x1; ++ dpw = 4; ++ dst_alpha_swp = 1; ++ dst_rb_swp = 0x1; ++ break; ++ case RGA_FORMAT_ARGB_5551: ++ dst_format = 0x5; ++ dpw = 2; ++ dst_alpha_swp = 1; ++ break; ++ case RGA_FORMAT_ABGR_5551: ++ dst_format = 0x5; ++ dpw = 2; ++ dst_alpha_swp = 1; ++ dst_rb_swp = 0x1; ++ break; ++ case RGA_FORMAT_ARGB_4444: ++ dst_format = 0x6; ++ dpw = 2; ++ dst_alpha_swp = 1; ++ break; ++ case RGA_FORMAT_ABGR_4444: ++ dst_format = 0x6; ++ dpw = 2; ++ dst_alpha_swp = 1; ++ dst_rb_swp = 0x1; ++ break; ++ ++ case RGA_FORMAT_YCbCr_422_SP: ++ dst_format = 0x8; ++ x_div = 1; ++ y_div = 1; ++ break; ++ case RGA_FORMAT_YCbCr_422_P: ++ dst_format = 0x9; ++ x_div = 2; ++ y_div = 1; ++ break; ++ case RGA_FORMAT_YCbCr_420_SP: ++ dst_format = 0xa; ++ x_div = 1; ++ y_div = 2; ++ break; ++ case RGA_FORMAT_YCbCr_420_P: ++ dst_format = 0xb; ++ dst_cbcr_swp = 1; ++ x_div = 2; ++ y_div = 2; ++ break; ++ case RGA_FORMAT_YCrCb_422_SP: ++ dst_format = 0x8; ++ dst_cbcr_swp = 1; ++ x_div = 1; ++ y_div = 1; ++ break; ++ case RGA_FORMAT_YCrCb_422_P: ++ dst_format = 0x9; ++ dst_cbcr_swp = 1; ++ x_div = 2; ++ y_div = 1; ++ break; ++ case RGA_FORMAT_YCrCb_420_SP: ++ dst_format = 0xa; ++ dst_cbcr_swp = 1; ++ x_div = 1; ++ y_div = 2; ++ break; ++ case RGA_FORMAT_YCrCb_420_P: ++ dst_format = 0xb; ++ x_div = 2; ++ y_div = 2; ++ break; ++ ++ case RGA_FORMAT_YCbCr_400: ++ dst_format = 0x8; ++ dst_fmt_yuv400_en = 1; ++ x_div = 1; ++ y_div = 1; ++ break; ++ case RGA_FORMAT_Y4: ++ dst_format = 0x8; ++ dst_fmt_y4_en = 1; ++ dst_fmt_yuv400_en = 1; ++ x_div = 1; ++ y_div = 1; ++ break; ++ ++ case RGA_FORMAT_YUYV_422: ++ dst_format = 0xe; ++ dpw = 2; ++ dst_cbcr_swp = 1; ++ break; ++ case RGA_FORMAT_YVYU_422: ++ dst_format = 0xe; ++ dpw = 2; ++ break; ++ case RGA_FORMAT_YUYV_420: ++ dst_format = 0xf; ++ dpw = 2; ++ dst_cbcr_swp = 1; ++ break; ++ case RGA_FORMAT_YVYU_420: ++ dst_format = 0xf; ++ dpw = 2; ++ break; ++ case RGA_FORMAT_UYVY_422: ++ dst_format = 0xc; ++ dpw = 2; ++ dst_cbcr_swp = 1; ++ break; ++ case RGA_FORMAT_VYUY_422: ++ dst_format = 0xc; ++ dpw = 2; ++ break; ++ case RGA_FORMAT_UYVY_420: ++ dst_format = 0xd; ++ dpw = 2; ++ dst_cbcr_swp = 1; ++ break; ++ case RGA_FORMAT_VYUY_420: ++ dst_format = 0xd; ++ dpw = 2; ++ break; ++ }; ++ ++ reg = ++ ((reg & (~m_RGA2_DST_INFO_SW_DST_FMT)) | ++ (s_RGA2_DST_INFO_SW_DST_FMT(dst_format))); ++ reg = ++ ((reg & (~m_RGA2_DST_INFO_SW_DST_RB_SWAP)) | ++ (s_RGA2_DST_INFO_SW_DST_RB_SWAP(dst_rb_swp))); ++ reg = ++ ((reg & (~m_RGA2_DST_INFO_SW_ALPHA_SWAP)) | ++ (s_RGA2_DST_INFO_SW_ALPHA_SWAP(dst_alpha_swp))); ++ reg = ++ ((reg & (~m_RGA2_DST_INFO_SW_DST_UV_SWAP)) | ++ (s_RGA2_DST_INFO_SW_DST_UV_SWAP(dst_cbcr_swp))); ++ ++ reg = ++ ((reg & (~m_RGA2_DST_INFO_SW_DST_FMT_YUV400_EN)) | ++ (s_RGA2_DST_INFO_SW_DST_FMT_YUV400_EN(dst_fmt_yuv400_en))); ++ reg = ++ ((reg & (~m_RGA2_DST_INFO_SW_DST_FMT_Y4_EN)) | ++ (s_RGA2_DST_INFO_SW_DST_FMT_Y4_EN(dst_fmt_y4_en))); ++ reg = ++ ((reg & (~m_RGA2_DST_INFO_SW_DST_NN_QUANTIZE_EN)) | ++ (s_RGA2_DST_INFO_SW_DST_NN_QUANTIZE_EN(dst_nn_quantize_en))); ++ reg = ++ ((reg & (~m_RGA2_DST_INFO_SW_DITHER_UP_E)) | ++ (s_RGA2_DST_INFO_SW_DITHER_UP_E(msg->alpha_rop_flag >> 5))); ++ reg = ++ ((reg & (~m_RGA2_DST_INFO_SW_DITHER_DOWN_E)) | ++ (s_RGA2_DST_INFO_SW_DITHER_DOWN_E(msg->alpha_rop_flag >> 6))); ++ reg = ++ ((reg & (~m_RGA2_DST_INFO_SW_DITHER_MODE)) | ++ (s_RGA2_DST_INFO_SW_DITHER_MODE(msg->dither_mode))); ++ reg = ++ ((reg & (~m_RGA2_DST_INFO_SW_DST_CSC_MODE)) | ++ (s_RGA2_DST_INFO_SW_DST_CSC_MODE(msg->yuv2rgb_mode >> 2))); ++ reg = ++ ((reg & (~m_RGA2_DST_INFO_SW_CSC_CLIP_MODE)) | ++ (s_RGA2_DST_INFO_SW_CSC_CLIP_MODE(msg->yuv2rgb_mode >> 4))); ++ /* full csc enable */ ++ reg = ++ ((reg & (~m_RGA2_DST_INFO_SW_DST_CSC_MODE_2)) | ++ (s_RGA2_DST_INFO_SW_DST_CSC_MODE_2(msg->full_csc_en))); ++ /* ++ * Some older chips do not support src1 csc mode, ++ * they do not have these two registers. ++ */ ++ reg = ++ ((reg & (~m_RGA2_DST_INFO_SW_SRC1_CSC_MODE)) | ++ (s_RGA2_DST_INFO_SW_SRC1_CSC_MODE(msg->yuv2rgb_mode >> 5))); ++ reg = ++ ((reg & (~m_RGA2_DST_INFO_SW_SRC1_CSC_CLIP_MODE)) | ++ (s_RGA2_DST_INFO_SW_SRC1_CSC_CLIP_MODE( ++ msg->yuv2rgb_mode >> 7))); ++ ++ reg = ((reg & (~m_RGA2_DST_INFO_SW_DST_UVHDS_MODE)) | ++ (s_RGA2_DST_INFO_SW_DST_UVHDS_MODE(msg->uvhds_mode))); ++ reg = ((reg & (~m_RGA2_DST_INFO_SW_DST_UVVDS_MODE)) | ++ (s_RGA2_DST_INFO_SW_DST_UVVDS_MODE(msg->uvvds_mode))); ++ ++ ydither_en = (msg->dst.format == RGA_FORMAT_Y4) ++ && ((msg->alpha_rop_flag >> 6) & 0x1); ++ ++ *bRGA_DST_INFO = reg; ++ ++ s_stride = (((msg->src1.vir_w * spw >> bbp_shift) + 3) & ~3) >> 2; ++ d_stride = ((msg->dst.vir_w * dpw + 3) & ~3) >> 2; ++ ++ if (dst_fmt_y4_en) { ++ /* Y4 output will HALF */ ++ d_stride = ((d_stride + 1) & ~1) >> 1; ++ } ++ ++ d_uv_stride = (d_stride << 2) / x_div; ++ ++ *bRGA_DST_VIR_INFO = d_stride | (s_stride << 16); ++ if ((msg->dst.vir_w % 2 != 0) && ++ (msg->dst.act_w == msg->src.act_w) ++ && (msg->dst.act_h == msg->src.act_h) ++ && (msg->dst.format == RGA_FORMAT_BGR_888 ++ || msg->dst.format == RGA_FORMAT_RGB_888)) ++ *bRGA_DST_ACT_INFO = ++ (msg->dst.act_w) | ((msg->dst.act_h - 1) << 16); ++ else ++ *bRGA_DST_ACT_INFO = ++ (msg->dst.act_w - 1) | ((msg->dst.act_h - 1) << 16); ++ s_stride <<= 2; ++ d_stride <<= 2; ++ ++ if (((msg->rotate_mode & 0xf) == 0) || ++ ((msg->rotate_mode & 0xf) == 1)) { ++ x_mirr = 0; ++ y_mirr = 0; ++ } else { ++ x_mirr = 1; ++ y_mirr = 1; ++ } ++ ++ rot_90_flag = msg->rotate_mode & 1; ++ x_mirr = (x_mirr + ((msg->rotate_mode >> 4) & 1)) & 1; ++ y_mirr = (y_mirr + ((msg->rotate_mode >> 5) & 1)) & 1; ++ ++ if (ydither_en) { ++ if (x_mirr && y_mirr) { ++ pr_err("ydither mode do not support rotate x_mirr=%d,y_mirr=%d\n", ++ x_mirr, y_mirr); ++ } ++ ++ if (msg->dst.act_w != msg->src.act_w) ++ pr_err("ydither mode do not support x dir scale\n"); ++ ++ if (msg->dst.act_h != msg->src.act_h) ++ pr_err("ydither mode do not support y dir scale\n"); ++ } ++ ++ if (dst_fmt_y4_en) { ++ *RGA_DST_Y4MAP_LUT0 = (msg->gr_color.gr_x_r & 0xffff) | ++ (msg->gr_color.gr_x_g << 16); ++ *RGA_DST_Y4MAP_LUT1 = (msg->gr_color.gr_y_r & 0xffff) | ++ (msg->gr_color.gr_y_g << 16); ++ } ++ ++ if (dst_nn_quantize_en) { ++ *RGA_DST_NN_QUANTIZE_SCALE = (msg->gr_color.gr_x_r & 0xffff) | ++ (msg->gr_color.gr_x_g << 10) | ++ (msg->gr_color.gr_x_b << 20); ++ *RGA_DST_NN_QUANTIZE_OFFSET = (msg->gr_color.gr_y_r & 0xffff) | ++ (msg->gr_color.gr_y_g << 10) | ++ (msg->gr_color.gr_y_b << 20); ++ } ++ ++ s_yrgb_addr = ++ (u32) msg->src1.yrgb_addr + (msg->src1.y_offset * s_stride) + ++ (msg->src1.x_offset * spw >> bbp_shift); ++ ++ *bRGA_SRC_BASE3 = s_yrgb_addr; ++ ++ if (dst_fmt_y4_en) { ++ yrgb_addr = (u32) msg->dst.yrgb_addr + ++ (msg->dst.y_offset * d_stride) + ++ ((msg->dst.x_offset * dpw) >> 1); ++ } else { ++ yrgb_addr = (u32) msg->dst.yrgb_addr + ++ (msg->dst.y_offset * d_stride) + ++ (msg->dst.x_offset * dpw); ++ } ++ u_addr = (u32) msg->dst.uv_addr + ++ (msg->dst.y_offset / y_div) * d_uv_stride + ++ msg->dst.x_offset / x_div; ++ v_addr = (u32) msg->dst.v_addr + ++ (msg->dst.y_offset / y_div) * d_uv_stride + ++ msg->dst.x_offset / x_div; ++ ++ y_lt_addr = yrgb_addr; ++ u_lt_addr = u_addr; ++ v_lt_addr = v_addr; ++ ++ /* Warning */ ++ line_width_real = ++ dst_fmt_y4_en ? ((msg->dst.act_w) >> 1) : msg->dst.act_w; ++ ++ /* ++ * YUV packet mode is a new format, and the write behavior during ++ * rotation is different from the old format. ++ */ ++ if (rga_is_yuv422_packed_format(msg->dst.format)) { ++ y_ld_addr = yrgb_addr + (msg->dst.act_h - 1) * (d_stride); ++ y_rt_addr = yrgb_addr + (msg->dst.act_w * 2 - 1); ++ y_rd_addr = y_ld_addr + (msg->dst.act_w * 2 - 1); ++ } else if (rga_is_yuv420_packed_format(msg->dst.format)) { ++ y_ld_addr = (u32)msg->dst.yrgb_addr + ++ ((msg->dst.y_offset + (msg->dst.act_h - 1)) * d_stride) + ++ msg->dst.x_offset; ++ y_rt_addr = yrgb_addr + (msg->dst.act_w * 2 - 1); ++ y_rd_addr = y_ld_addr + (msg->dst.act_w - 1); ++ } else { ++ /* 270 degree & Mirror V */ ++ y_ld_addr = yrgb_addr + (msg->dst.act_h - 1) * (d_stride); ++ /* 90 degree & Mirror H */ ++ y_rt_addr = yrgb_addr + (line_width_real - 1) * dpw; ++ /* 180 degree */ ++ y_rd_addr = y_ld_addr + (line_width_real - 1) * dpw; ++ } ++ ++ u_ld_addr = u_addr + ((msg->dst.act_h / y_div) - 1) * (d_uv_stride); ++ v_ld_addr = v_addr + ((msg->dst.act_h / y_div) - 1) * (d_uv_stride); ++ ++ u_rt_addr = u_addr + (msg->dst.act_w / x_div) - 1; ++ v_rt_addr = v_addr + (msg->dst.act_w / x_div) - 1; ++ ++ u_rd_addr = u_ld_addr + (msg->dst.act_w / x_div) - 1; ++ v_rd_addr = v_ld_addr + (msg->dst.act_w / x_div) - 1; ++ ++ if (rot_90_flag == 0) { ++ if (y_mirr == 1) { ++ if (x_mirr == 1) { ++ yrgb_addr = y_rd_addr; ++ u_addr = u_rd_addr; ++ v_addr = v_rd_addr; ++ } else { ++ yrgb_addr = y_ld_addr; ++ u_addr = u_ld_addr; ++ v_addr = v_ld_addr; ++ } ++ } else { ++ if (x_mirr == 1) { ++ yrgb_addr = y_rt_addr; ++ u_addr = u_rt_addr; ++ v_addr = v_rt_addr; ++ } else { ++ yrgb_addr = y_lt_addr; ++ u_addr = u_lt_addr; ++ v_addr = v_lt_addr; ++ } ++ } ++ } else { ++ if (y_mirr == 1) { ++ if (x_mirr == 1) { ++ yrgb_addr = y_ld_addr; ++ u_addr = u_ld_addr; ++ v_addr = v_ld_addr; ++ } else { ++ yrgb_addr = y_rd_addr; ++ u_addr = u_rd_addr; ++ v_addr = v_rd_addr; ++ } ++ } else { ++ if (x_mirr == 1) { ++ yrgb_addr = y_lt_addr; ++ u_addr = u_lt_addr; ++ v_addr = v_lt_addr; ++ } else { ++ yrgb_addr = y_rt_addr; ++ u_addr = u_rt_addr; ++ v_addr = v_rt_addr; ++ } ++ } ++ } ++ ++ *bRGA_DST_BASE0 = (u32) yrgb_addr; ++ ++ if ((msg->dst.format == RGA_FORMAT_YCbCr_420_P) ++ || (msg->dst.format == RGA_FORMAT_YCrCb_420_P)) { ++ if (dst_cbcr_swp == 0) { ++ *bRGA_DST_BASE1 = (u32) v_addr; ++ *bRGA_DST_BASE2 = (u32) u_addr; ++ } else { ++ *bRGA_DST_BASE1 = (u32) u_addr; ++ *bRGA_DST_BASE2 = (u32) v_addr; ++ } ++ } else { ++ *bRGA_DST_BASE1 = (u32) u_addr; ++ *bRGA_DST_BASE2 = (u32) v_addr; ++ } ++} ++ ++static void RGA2_set_reg_alpha_info(u8 *base, struct rga2_req *msg) ++{ ++ u32 *bRGA_ALPHA_CTRL0; ++ u32 *bRGA_ALPHA_CTRL1; ++ u32 *bRGA_FADING_CTRL; ++ u32 reg = 0; ++ union rga2_color_ctrl color_ctrl; ++ union rga2_alpha_ctrl alpha_ctrl; ++ struct rga_alpha_config *config; ++ ++ bRGA_ALPHA_CTRL0 = (u32 *) (base + RGA2_ALPHA_CTRL0_OFFSET); ++ bRGA_ALPHA_CTRL1 = (u32 *) (base + RGA2_ALPHA_CTRL1_OFFSET); ++ bRGA_FADING_CTRL = (u32 *) (base + RGA2_FADING_CTRL_OFFSET); ++ ++ color_ctrl.value = 0; ++ alpha_ctrl.value = 0; ++ config = &msg->alpha_config; ++ ++ color_ctrl.bits.src_color_mode = ++ config->fg_pre_multiplied ? RGA_ALPHA_PRE_MULTIPLIED : RGA_ALPHA_NO_PRE_MULTIPLIED; ++ color_ctrl.bits.dst_color_mode = ++ config->bg_pre_multiplied ? RGA_ALPHA_PRE_MULTIPLIED : RGA_ALPHA_NO_PRE_MULTIPLIED; ++ ++ if (config->fg_pixel_alpha_en) ++ color_ctrl.bits.src_blend_mode = ++ config->fg_global_alpha_en ? RGA_ALPHA_PER_PIXEL_GLOBAL : ++ RGA_ALPHA_PER_PIXEL; ++ else ++ color_ctrl.bits.src_blend_mode = RGA_ALPHA_GLOBAL; ++ ++ if (config->bg_pixel_alpha_en) ++ color_ctrl.bits.dst_blend_mode = ++ config->bg_global_alpha_en ? RGA_ALPHA_PER_PIXEL_GLOBAL : ++ RGA_ALPHA_PER_PIXEL; ++ else ++ color_ctrl.bits.dst_blend_mode = RGA_ALPHA_GLOBAL; ++ ++ /* ++ * Since the hardware uses 256 as 1, the original alpha value needs to ++ * be + (alpha >> 7). ++ */ ++ color_ctrl.bits.src_alpha_cal_mode = RGA_ALPHA_SATURATION; ++ color_ctrl.bits.dst_alpha_cal_mode = RGA_ALPHA_SATURATION; ++ ++ /* porter duff alpha enable */ ++ switch (config->mode) { ++ case RGA_ALPHA_BLEND_SRC: ++ /* ++ * SRC mode: ++ * Sf = 1, Df = 0; ++ * [Rc,Ra] = [Sc,Sa]; ++ */ ++ color_ctrl.bits.src_alpha_mode = RGA_ALPHA_STRAIGHT; ++ color_ctrl.bits.src_factor_mode = RGA_ALPHA_ONE; ++ ++ color_ctrl.bits.dst_alpha_mode = RGA_ALPHA_STRAIGHT; ++ color_ctrl.bits.dst_factor_mode = RGA_ALPHA_ZERO; ++ ++ break; ++ ++ case RGA_ALPHA_BLEND_DST: ++ /* ++ * SRC mode: ++ * Sf = 0, Df = 1; ++ * [Rc,Ra] = [Dc,Da]; ++ */ ++ color_ctrl.bits.src_alpha_mode = RGA_ALPHA_STRAIGHT; ++ color_ctrl.bits.src_factor_mode = RGA_ALPHA_ZERO; ++ ++ color_ctrl.bits.dst_alpha_mode = RGA_ALPHA_STRAIGHT; ++ color_ctrl.bits.dst_factor_mode = RGA_ALPHA_ONE; ++ ++ break; ++ ++ case RGA_ALPHA_BLEND_SRC_OVER: ++ /* ++ * SRC-OVER mode: ++ * Sf = 1, Df = (1 - Sa) ++ * [Rc,Ra] = [ Sc + (1 - Sa) * Dc, Sa + (1 - Sa) * Da ] ++ */ ++ color_ctrl.bits.src_alpha_mode = RGA_ALPHA_STRAIGHT; ++ color_ctrl.bits.src_factor_mode = RGA_ALPHA_ONE; ++ ++ color_ctrl.bits.dst_alpha_mode = RGA_ALPHA_STRAIGHT; ++ color_ctrl.bits.dst_factor_mode = RGA_ALPHA_OPPOSITE_INVERSE; ++ ++ break; ++ ++ case RGA_ALPHA_BLEND_DST_OVER: ++ /* ++ * DST-OVER mode: ++ * Sf = (1 - Da) , Df = 1 ++ * [Rc,Ra] = [ Sc * (1 - Da) + Dc, Sa * (1 - Da) + Da ] ++ */ ++ color_ctrl.bits.src_alpha_mode = RGA_ALPHA_STRAIGHT; ++ color_ctrl.bits.src_factor_mode = RGA_ALPHA_OPPOSITE_INVERSE; ++ ++ color_ctrl.bits.dst_alpha_mode = RGA_ALPHA_STRAIGHT; ++ color_ctrl.bits.dst_factor_mode = RGA_ALPHA_ONE; ++ ++ break; ++ ++ case RGA_ALPHA_BLEND_SRC_IN: ++ /* ++ * SRC-IN mode: ++ * Sf = Da , Df = 0 ++ * [Rc,Ra] = [ Sc * Da, Sa * Da ] ++ */ ++ color_ctrl.bits.src_alpha_mode = RGA_ALPHA_STRAIGHT; ++ color_ctrl.bits.src_factor_mode = RGA_ALPHA_OPPOSITE; ++ ++ color_ctrl.bits.dst_alpha_mode = RGA_ALPHA_STRAIGHT; ++ color_ctrl.bits.dst_factor_mode = RGA_ALPHA_ZERO; ++ ++ break; ++ ++ case RGA_ALPHA_BLEND_DST_IN: ++ /* ++ * DST-IN mode: ++ * Sf = 0 , Df = Sa ++ * [Rc,Ra] = [ Dc * Sa, Da * Sa ] ++ */ ++ color_ctrl.bits.src_alpha_mode = RGA_ALPHA_STRAIGHT; ++ color_ctrl.bits.src_factor_mode = RGA_ALPHA_ZERO; ++ ++ color_ctrl.bits.dst_alpha_mode = RGA_ALPHA_STRAIGHT; ++ color_ctrl.bits.dst_factor_mode = RGA_ALPHA_OPPOSITE; ++ ++ break; ++ ++ case RGA_ALPHA_BLEND_SRC_OUT: ++ /* ++ * SRC-OUT mode: ++ * Sf = (1 - Da) , Df = 0 ++ * [Rc,Ra] = [ Sc * (1 - Da), Sa * (1 - Da) ] ++ */ ++ color_ctrl.bits.src_alpha_mode = RGA_ALPHA_STRAIGHT; ++ color_ctrl.bits.src_factor_mode = RGA_ALPHA_OPPOSITE_INVERSE; ++ ++ color_ctrl.bits.dst_alpha_mode = RGA_ALPHA_STRAIGHT; ++ color_ctrl.bits.dst_factor_mode = RGA_ALPHA_ZERO; ++ ++ break; ++ ++ case RGA_ALPHA_BLEND_DST_OUT: ++ /* ++ * DST-OUT mode: ++ * Sf = 0 , Df = (1 - Sa) ++ * [Rc,Ra] = [ Dc * (1 - Sa), Da * (1 - Sa) ] ++ */ ++ color_ctrl.bits.src_alpha_mode = RGA_ALPHA_STRAIGHT; ++ color_ctrl.bits.src_factor_mode = RGA_ALPHA_ZERO; ++ ++ color_ctrl.bits.dst_alpha_mode = RGA_ALPHA_STRAIGHT; ++ color_ctrl.bits.dst_factor_mode = RGA_ALPHA_OPPOSITE_INVERSE; ++ ++ break; ++ ++ case RGA_ALPHA_BLEND_SRC_ATOP: ++ /* ++ * SRC-ATOP mode: ++ * Sf = Da , Df = (1 - Sa) ++ * [Rc,Ra] = [ Sc * Da + Dc * (1 - Sa), Sa * Da + Da * (1 - Sa) ] ++ */ ++ color_ctrl.bits.src_alpha_mode = RGA_ALPHA_STRAIGHT; ++ color_ctrl.bits.src_factor_mode = RGA_ALPHA_OPPOSITE; ++ ++ color_ctrl.bits.dst_alpha_mode = RGA_ALPHA_STRAIGHT; ++ color_ctrl.bits.dst_factor_mode = RGA_ALPHA_OPPOSITE_INVERSE; ++ ++ break; ++ ++ case RGA_ALPHA_BLEND_DST_ATOP: ++ /* ++ * DST-ATOP mode: ++ * Sf = (1 - Da) , Df = Sa ++ * [Rc,Ra] = [ Sc * (1 - Da) + Dc * Sa, Sa * (1 - Da) + Da * Sa ] ++ */ ++ color_ctrl.bits.src_alpha_mode = RGA_ALPHA_STRAIGHT; ++ color_ctrl.bits.src_factor_mode = RGA_ALPHA_OPPOSITE_INVERSE; ++ ++ color_ctrl.bits.dst_alpha_mode = RGA_ALPHA_STRAIGHT; ++ color_ctrl.bits.dst_factor_mode = RGA_ALPHA_OPPOSITE; ++ ++ break; ++ ++ case RGA_ALPHA_BLEND_XOR: ++ /* ++ * DST-XOR mode: ++ * Sf = (1 - Da) , Df = (1 - Sa) ++ * [Rc,Ra] = [ Sc * (1 - Da) + Dc * (1 - Sa), Sa * (1 - Da) + Da * (1 - Sa) ] ++ */ ++ color_ctrl.bits.src_alpha_mode = RGA_ALPHA_STRAIGHT; ++ color_ctrl.bits.src_factor_mode = RGA_ALPHA_OPPOSITE_INVERSE; ++ ++ color_ctrl.bits.dst_alpha_mode = RGA_ALPHA_STRAIGHT; ++ color_ctrl.bits.dst_factor_mode = RGA_ALPHA_OPPOSITE_INVERSE; ++ ++ break; ++ ++ case RGA_ALPHA_BLEND_CLEAR: ++ /* ++ * DST-CLEAR mode: ++ * Sf = 0 , Df = 0 ++ * [Rc,Ra] = [ 0, 0 ] ++ */ ++ color_ctrl.bits.src_alpha_mode = RGA_ALPHA_STRAIGHT; ++ color_ctrl.bits.src_factor_mode = RGA_ALPHA_ZERO; ++ ++ color_ctrl.bits.dst_alpha_mode = RGA_ALPHA_STRAIGHT; ++ color_ctrl.bits.dst_factor_mode = RGA_ALPHA_ZERO; ++ ++ break; ++ ++ default: ++ break; ++ } ++ ++ alpha_ctrl.bits.src_blend_mode = color_ctrl.bits.src_blend_mode; ++ alpha_ctrl.bits.dst_blend_mode = color_ctrl.bits.dst_blend_mode; ++ ++ alpha_ctrl.bits.src_alpha_cal_mode = color_ctrl.bits.src_alpha_cal_mode; ++ alpha_ctrl.bits.dst_alpha_cal_mode = color_ctrl.bits.dst_alpha_cal_mode; ++ ++ alpha_ctrl.bits.src_alpha_mode = color_ctrl.bits.src_alpha_mode; ++ alpha_ctrl.bits.src_factor_mode = color_ctrl.bits.src_factor_mode; ++ ++ alpha_ctrl.bits.dst_alpha_mode = color_ctrl.bits.dst_alpha_mode; ++ alpha_ctrl.bits.dst_factor_mode = color_ctrl.bits.dst_factor_mode; ++ ++ reg = ++ ((reg & (~m_RGA2_ALPHA_CTRL0_SW_ALPHA_ROP_0)) | ++ (s_RGA2_ALPHA_CTRL0_SW_ALPHA_ROP_0(msg->alpha_rop_flag))); ++ reg = ++ ((reg & (~m_RGA2_ALPHA_CTRL0_SW_ALPHA_ROP_SEL)) | ++ (s_RGA2_ALPHA_CTRL0_SW_ALPHA_ROP_SEL ++ (msg->alpha_rop_flag >> 1))); ++ reg = ++ ((reg & (~m_RGA2_ALPHA_CTRL0_SW_ROP_MODE)) | ++ (s_RGA2_ALPHA_CTRL0_SW_ROP_MODE(msg->rop_mode))); ++ reg = ++ ((reg & (~m_RGA2_ALPHA_CTRL0_SW_SRC_GLOBAL_ALPHA)) | ++ (s_RGA2_ALPHA_CTRL0_SW_SRC_GLOBAL_ALPHA ++ ((uint8_t)config->fg_global_alpha_value))); ++ reg = ++ ((reg & (~m_RGA2_ALPHA_CTRL0_SW_DST_GLOBAL_ALPHA)) | ++ (s_RGA2_ALPHA_CTRL0_SW_DST_GLOBAL_ALPHA ++ ((uint8_t)config->bg_global_alpha_value))); ++ ++ *bRGA_ALPHA_CTRL0 = reg; ++ *bRGA_ALPHA_CTRL1 = color_ctrl.value | (alpha_ctrl.value << 16); ++ ++ ++ if ((msg->alpha_rop_flag >> 2) & 1) { ++ *bRGA_FADING_CTRL = (1 << 24) | (msg->fading_b_value << 16) | ++ (msg->fading_g_value << 8) | (msg->fading_r_value); ++ } ++} ++ ++static void RGA2_set_reg_rop_info(u8 *base, struct rga2_req *msg) ++{ ++ u32 *bRGA_ALPHA_CTRL0; ++ u32 *bRGA_ROP_CTRL0; ++ u32 *bRGA_ROP_CTRL1; ++ u32 *bRGA_MASK_ADDR; ++ u32 *bRGA_FG_COLOR; ++ u32 *bRGA_PAT_CON; ++ ++ u32 rop_code0 = 0; ++ u32 rop_code1 = 0; ++ ++ bRGA_ALPHA_CTRL0 = (u32 *) (base + RGA2_ALPHA_CTRL0_OFFSET); ++ bRGA_ROP_CTRL0 = (u32 *) (base + RGA2_ROP_CTRL0_OFFSET); ++ bRGA_ROP_CTRL1 = (u32 *) (base + RGA2_ROP_CTRL1_OFFSET); ++ bRGA_MASK_ADDR = (u32 *) (base + RGA2_MASK_BASE_OFFSET); ++ bRGA_FG_COLOR = (u32 *) (base + RGA2_SRC_FG_COLOR_OFFSET); ++ bRGA_PAT_CON = (u32 *) (base + RGA2_PAT_CON_OFFSET); ++ ++ if (msg->rop_mode == 0) { ++ rop_code0 = rga2_rop_code[(msg->rop_code & 0xff)]; ++ } else if (msg->rop_mode == 1) { ++ rop_code0 = rga2_rop_code[(msg->rop_code & 0xff)]; ++ } else if (msg->rop_mode == 2) { ++ rop_code0 = rga2_rop_code[(msg->rop_code & 0xff)]; ++ rop_code1 = rga2_rop_code[(msg->rop_code & 0xff00) >> 8]; ++ } ++ ++ *bRGA_ROP_CTRL0 = rop_code0; ++ *bRGA_ROP_CTRL1 = rop_code1; ++ *bRGA_FG_COLOR = msg->fg_color; ++ *bRGA_MASK_ADDR = (u32) msg->rop_mask_addr; ++ *bRGA_PAT_CON = (msg->pat.act_w - 1) | ((msg->pat.act_h - 1) << 8) ++ | (msg->pat.x_offset << 16) | (msg->pat.y_offset << 24); ++ *bRGA_ALPHA_CTRL0 = ++ *bRGA_ALPHA_CTRL0 | (((msg->endian_mode >> 1) & 1) << 20); ++ ++} ++ ++static void RGA_set_reg_mosaic(u8 *base, struct rga2_req *msg) ++{ ++ u32 *bRGA_MOSAIC_MODE; ++ ++ bRGA_MOSAIC_MODE = (u32 *)(base + RGA2_MOSAIC_MODE_OFFSET); ++ ++ *bRGA_MOSAIC_MODE = (u32)(msg->mosaic_info.mode & 0x7); ++} ++ ++static void RGA2_set_reg_osd(u8 *base, struct rga2_req *msg) ++{ ++ u32 *bRGA_OSD_CTRL0; ++ u32 *bRGA_OSD_CTRL1; ++ u32 *bRGA_OSD_INVERTSION_CAL0; ++ u32 *bRGA_OSD_INVERTSION_CAL1; ++ u32 *bRGA_OSD_COLOR0; ++ u32 *bRGA_OSD_COLOR1; ++ u32 *bRGA_OSD_LAST_FLAGS0; ++ u32 *bRGA_OSD_LAST_FLAGS1; ++ u32 reg; ++ u8 rgba2bpp_en = 0; ++ u8 block_num; ++ u16 fix_width; ++ ++ ++ bRGA_OSD_CTRL0 = (u32 *)(base + RGA2_OSD_CTRL0_OFFSET); ++ bRGA_OSD_CTRL1 = (u32 *)(base + RGA2_OSD_CTRL1_OFFSET); ++ bRGA_OSD_INVERTSION_CAL0 = (u32 *)(base + RGA2_OSD_INVERTSION_CAL0_OFFSET); ++ bRGA_OSD_INVERTSION_CAL1 = (u32 *)(base + RGA2_OSD_INVERTSION_CAL1_OFFSET); ++ bRGA_OSD_COLOR0 = (u32 *)(base + RGA2_OSD_COLOR0_OFFSET); ++ bRGA_OSD_COLOR1 = (u32 *)(base + RGA2_OSD_COLOR1_OFFSET); ++ bRGA_OSD_LAST_FLAGS0 = (u32 *)(base + RGA2_OSD_LAST_FLAGS0_OFFSET); ++ bRGA_OSD_LAST_FLAGS1 = (u32 *)(base + RGA2_OSD_LAST_FLAGS1_OFFSET); ++ ++ /* To save the number of register bits. */ ++ fix_width = msg->osd_info.mode_ctrl.block_fix_width / 2 - 1; ++ ++ /* The register is '0' as the first. */ ++ block_num = msg->osd_info.mode_ctrl.block_num - 1; ++ ++ if (msg->src1.format == RGA_FORMAT_RGBA_2BPP) ++ rgba2bpp_en = 1; ++ ++ reg = 0; ++ reg = ((reg & (~m_RGA2_OSD_CTRL0_SW_OSD_MODE)) | ++ (s_RGA2_OSD_CTRL0_SW_OSD_MODE(msg->osd_info.mode_ctrl.mode))); ++ reg = ((reg & (~m_RGA2_OSD_CTRL0_SW_OSD_VER_MODE)) | ++ (s_RGA2_OSD_CTRL0_SW_OSD_VER_MODE(msg->osd_info.mode_ctrl.direction_mode))); ++ reg = ((reg & (~m_RGA2_OSD_CTRL0_SW_OSD_WIDTH_MODE)) | ++ (s_RGA2_OSD_CTRL0_SW_OSD_WIDTH_MODE(msg->osd_info.mode_ctrl.width_mode))); ++ reg = ((reg & (~m_RGA2_OSD_CTRL0_SW_OSD_BLK_NUM)) | ++ (s_RGA2_OSD_CTRL0_SW_OSD_BLK_NUM(block_num))); ++ reg = ((reg & (~m_RGA2_OSD_CTRL0_SW_OSD_FLAGS_INDEX)) | ++ (s_RGA2_OSD_CTRL0_SW_OSD_FLAGS_INDEX(msg->osd_info.mode_ctrl.flags_index))); ++ reg = ((reg & (~m_RGA2_OSD_CTRL0_SW_OSD_FIX_WIDTH)) | ++ (s_RGA2_OSD_CTRL0_SW_OSD_FIX_WIDTH(fix_width))); ++ reg = ((reg & (~m_RGA2_OSD_CTRL0_SW_OSD_2BPP_MODE)) | ++ (s_RGA2_OSD_CTRL0_SW_OSD_2BPP_MODE(rgba2bpp_en))); ++ *bRGA_OSD_CTRL0 = reg; ++ ++ reg = 0; ++ reg = ((reg & (~m_RGA2_OSD_CTRL1_SW_OSD_COLOR_SEL)) | ++ (s_RGA2_OSD_CTRL1_SW_OSD_COLOR_SEL(msg->osd_info.mode_ctrl.color_mode))); ++ reg = ((reg & (~m_RGA2_OSD_CTRL1_SW_OSD_FLAG_SEL)) | ++ (s_RGA2_OSD_CTRL1_SW_OSD_FLAG_SEL(msg->osd_info.mode_ctrl.invert_flags_mode))); ++ reg = ((reg & (~m_RGA2_OSD_CTRL1_SW_OSD_DEFAULT_COLOR)) | ++ (s_RGA2_OSD_CTRL1_SW_OSD_DEFAULT_COLOR(msg->osd_info.mode_ctrl.default_color_sel))); ++ reg = ((reg & (~m_RGA2_OSD_CTRL1_SW_OSD_AUTO_INVERST_MODE)) | ++ (s_RGA2_OSD_CTRL1_SW_OSD_AUTO_INVERST_MODE(msg->osd_info.mode_ctrl.invert_mode))); ++ reg = ((reg & (~m_RGA2_OSD_CTRL1_SW_OSD_THRESH)) | ++ (s_RGA2_OSD_CTRL1_SW_OSD_THRESH(msg->osd_info.mode_ctrl.invert_thresh))); ++ reg = ((reg & (~m_RGA2_OSD_CTRL1_SW_OSD_INVERT_A_EN)) | ++ (s_RGA2_OSD_CTRL1_SW_OSD_INVERT_A_EN(msg->osd_info.mode_ctrl.invert_enable))); ++ reg = ((reg & (~m_RGA2_OSD_CTRL1_SW_OSD_INVERT_Y_DIS)) | ++ (s_RGA2_OSD_CTRL1_SW_OSD_INVERT_Y_DIS(msg->osd_info.mode_ctrl.invert_enable >> 1))); ++ reg = ((reg & (~m_RGA2_OSD_CTRL1_SW_OSD_INVERT_C_DIS)) | ++ (s_RGA2_OSD_CTRL1_SW_OSD_INVERT_C_DIS(msg->osd_info.mode_ctrl.invert_enable >> 2))); ++ reg = ((reg & (~m_RGA2_OSD_CTRL1_SW_OSD_UNFIX_INDEX)) | ++ (s_RGA2_OSD_CTRL1_SW_OSD_UNFIX_INDEX(msg->osd_info.mode_ctrl.unfix_index))); ++ *bRGA_OSD_CTRL1 = reg; ++ ++ *bRGA_OSD_INVERTSION_CAL0 = ((msg->osd_info.cal_factor.crb_max) << 24) | ++ ((msg->osd_info.cal_factor.crb_min) << 16) | ++ ((msg->osd_info.cal_factor.yg_max) << 8) | ++ ((msg->osd_info.cal_factor.yg_min) << 0); ++ *bRGA_OSD_INVERTSION_CAL1 = ((msg->osd_info.cal_factor.alpha_max) << 8) | ++ ((msg->osd_info.cal_factor.alpha_min) << 0); ++ ++ *bRGA_OSD_LAST_FLAGS0 = (msg->osd_info.last_flags0); ++ *bRGA_OSD_LAST_FLAGS1 = (msg->osd_info.last_flags1); ++ ++ if (msg->osd_info.mode_ctrl.color_mode == 1) { ++ *bRGA_OSD_COLOR0 = (msg->osd_info.bpp2_info.color0.value & 0xffffff); ++ *bRGA_OSD_COLOR1 = (msg->osd_info.bpp2_info.color1.value & 0xffffff); ++ } ++ ++ if (rgba2bpp_en) { ++ *bRGA_OSD_COLOR0 = msg->osd_info.bpp2_info.color0.value; ++ *bRGA_OSD_COLOR1 = msg->osd_info.bpp2_info.color1.value; ++ } ++} ++ ++static void RGA2_set_reg_color_palette(u8 *base, struct rga2_req *msg) ++{ ++ u32 *bRGA_SRC_BASE0, *bRGA_SRC_INFO, *bRGA_SRC_VIR_INFO, ++ *bRGA_SRC_ACT_INFO, *bRGA_SRC_FG_COLOR, *bRGA_SRC_BG_COLOR; ++ u32 *p; ++ short x_off, y_off; ++ u16 src_stride; ++ u8 shift; ++ u32 sw; ++ u32 byte_num; ++ u32 reg; ++ ++ bRGA_SRC_BASE0 = (u32 *) (base + RGA2_SRC_BASE0_OFFSET); ++ bRGA_SRC_INFO = (u32 *) (base + RGA2_SRC_INFO_OFFSET); ++ bRGA_SRC_VIR_INFO = (u32 *) (base + RGA2_SRC_VIR_INFO_OFFSET); ++ bRGA_SRC_ACT_INFO = (u32 *) (base + RGA2_SRC_ACT_INFO_OFFSET); ++ bRGA_SRC_FG_COLOR = (u32 *) (base + RGA2_SRC_FG_COLOR_OFFSET); ++ bRGA_SRC_BG_COLOR = (u32 *) (base + RGA2_SRC_BG_COLOR_OFFSET); ++ ++ reg = 0; ++ ++ shift = 3 - msg->palette_mode; ++ ++ x_off = msg->src.x_offset; ++ y_off = msg->src.y_offset; ++ ++ sw = msg->src.vir_w; ++ byte_num = sw >> shift; ++ ++ src_stride = (byte_num + 3) & (~3); ++ ++ p = (u32 *) ((unsigned long)msg->src.yrgb_addr); ++ ++ p = p + (x_off >> shift) + y_off * src_stride; ++ ++ *bRGA_SRC_BASE0 = (unsigned long)p; ++ ++ reg = ++ ((reg & (~m_RGA2_SRC_INFO_SW_SRC_FMT)) | ++ (s_RGA2_SRC_INFO_SW_SRC_FMT((msg->palette_mode | 0xc)))); ++ reg = ++ ((reg & (~m_RGA2_SRC_INFO_SW_SW_CP_ENDIAN)) | ++ (s_RGA2_SRC_INFO_SW_SW_CP_ENDAIN(msg->endian_mode & 1))); ++ *bRGA_SRC_VIR_INFO = src_stride >> 2; ++ *bRGA_SRC_ACT_INFO = ++ (msg->src.act_w - 1) | ((msg->src.act_h - 1) << 16); ++ *bRGA_SRC_INFO = reg; ++ ++ *bRGA_SRC_FG_COLOR = msg->fg_color; ++ *bRGA_SRC_BG_COLOR = msg->bg_color; ++ ++} ++ ++static void RGA2_set_reg_color_fill(u8 *base, struct rga2_req *msg) ++{ ++ u32 *bRGA_CF_GR_A; ++ u32 *bRGA_CF_GR_B; ++ u32 *bRGA_CF_GR_G; ++ u32 *bRGA_CF_GR_R; ++ u32 *bRGA_SRC_FG_COLOR; ++ u32 *bRGA_MASK_ADDR; ++ u32 *bRGA_PAT_CON; ++ ++ u32 mask_stride; ++ u32 *bRGA_SRC_VIR_INFO; ++ ++ bRGA_SRC_FG_COLOR = (u32 *) (base + RGA2_SRC_FG_COLOR_OFFSET); ++ ++ bRGA_CF_GR_A = (u32 *) (base + RGA2_CF_GR_A_OFFSET); ++ bRGA_CF_GR_B = (u32 *) (base + RGA2_CF_GR_B_OFFSET); ++ bRGA_CF_GR_G = (u32 *) (base + RGA2_CF_GR_G_OFFSET); ++ bRGA_CF_GR_R = (u32 *) (base + RGA2_CF_GR_R_OFFSET); ++ ++ bRGA_MASK_ADDR = (u32 *) (base + RGA2_MASK_BASE_OFFSET); ++ bRGA_PAT_CON = (u32 *) (base + RGA2_PAT_CON_OFFSET); ++ ++ bRGA_SRC_VIR_INFO = (u32 *) (base + RGA2_SRC_VIR_INFO_OFFSET); ++ ++ mask_stride = msg->rop_mask_stride; ++ ++ if (msg->color_fill_mode == 0) { ++ /* solid color */ ++ *bRGA_CF_GR_A = (msg->gr_color.gr_x_a & 0xffff) | ++ (msg->gr_color.gr_y_a << 16); ++ *bRGA_CF_GR_B = (msg->gr_color.gr_x_b & 0xffff) | ++ (msg->gr_color.gr_y_b << 16); ++ *bRGA_CF_GR_G = (msg->gr_color.gr_x_g & 0xffff) | ++ (msg->gr_color.gr_y_g << 16); ++ *bRGA_CF_GR_R = (msg->gr_color.gr_x_r & 0xffff) | ++ (msg->gr_color.gr_y_r << 16); ++ ++ *bRGA_SRC_FG_COLOR = msg->fg_color; ++ } else { ++ /* pattern color */ ++ *bRGA_MASK_ADDR = (u32) msg->pat.yrgb_addr; ++ *bRGA_PAT_CON = ++ (msg->pat.act_w - 1) | ((msg->pat.act_h - 1) << 8) ++ | (msg->pat.x_offset << 16) | (msg->pat.y_offset << 24); ++ } ++ *bRGA_SRC_VIR_INFO = mask_stride << 16; ++} ++ ++static void RGA2_set_reg_update_palette_table(u8 *base, ++ struct rga2_req *msg) ++{ ++ u32 *bRGA_MASK_BASE; ++ u32 *bRGA_FADING_CTRL; ++ ++ bRGA_MASK_BASE = (u32 *) (base + RGA2_MASK_BASE_OFFSET); ++ bRGA_FADING_CTRL = (u32 *) (base + RGA2_FADING_CTRL_OFFSET); ++ ++ *bRGA_FADING_CTRL = msg->fading_g_value << 8; ++ *bRGA_MASK_BASE = (u32) msg->pat.yrgb_addr; ++} ++ ++static void RGA2_set_reg_update_patten_buff(u8 *base, struct rga2_req *msg) ++{ ++ u32 *bRGA_PAT_MST; ++ u32 *bRGA_PAT_CON; ++ u32 *bRGA_PAT_START_POINT; ++ u32 *bRGA_FADING_CTRL; ++ u32 reg = 0; ++ struct rga_img_info_t *pat; ++ ++ u32 num, offset; ++ ++ pat = &msg->pat; ++ ++ num = (pat->act_w * pat->act_h) - 1; ++ ++ offset = pat->act_w * pat->y_offset + pat->x_offset; ++ ++ bRGA_PAT_START_POINT = (u32 *) (base + RGA2_FADING_CTRL_OFFSET); ++ bRGA_PAT_MST = (u32 *) (base + RGA2_MASK_BASE_OFFSET); ++ bRGA_PAT_CON = (u32 *) (base + RGA2_PAT_CON_OFFSET); ++ bRGA_FADING_CTRL = (u32 *) (base + RGA2_FADING_CTRL_OFFSET); ++ ++ *bRGA_PAT_MST = (u32) msg->pat.yrgb_addr; ++ *bRGA_PAT_START_POINT = (pat->act_w * pat->y_offset) + pat->x_offset; ++ ++ reg = (pat->act_w - 1) | ((pat->act_h - 1) << 8) | ++ (pat->x_offset << 16) | (pat->y_offset << 24); ++ *bRGA_PAT_CON = reg; ++ ++ *bRGA_FADING_CTRL = (num << 8) | offset; ++} ++ ++static void RGA2_set_pat_info(u8 *base, struct rga2_req *msg) ++{ ++ u32 *bRGA_PAT_CON; ++ u32 *bRGA_FADING_CTRL; ++ u32 reg = 0; ++ struct rga_img_info_t *pat; ++ ++ u32 num, offset; ++ ++ pat = &msg->pat; ++ ++ num = ((pat->act_w * pat->act_h) - 1) & 0xff; ++ ++ offset = (pat->act_w * pat->y_offset) + pat->x_offset; ++ ++ bRGA_PAT_CON = (u32 *) (base + RGA2_PAT_CON_OFFSET); ++ bRGA_FADING_CTRL = (u32 *) (base + RGA2_FADING_CTRL_OFFSET); ++ ++ reg = (pat->act_w - 1) | ((pat->act_h - 1) << 8) | ++ (pat->x_offset << 16) | (pat->y_offset << 24); ++ *bRGA_PAT_CON = reg; ++ *bRGA_FADING_CTRL = (num << 8) | offset; ++} ++ ++static void RGA2_set_mmu_reg_info(u8 *base, struct rga2_req *msg) ++{ ++ u32 *bRGA_MMU_CTRL1; ++ u32 *bRGA_MMU_SRC_BASE; ++ u32 *bRGA_MMU_SRC1_BASE; ++ u32 *bRGA_MMU_DST_BASE; ++ u32 *bRGA_MMU_ELS_BASE; ++ ++ u32 reg; ++ ++ bRGA_MMU_CTRL1 = (u32 *) (base + RGA2_MMU_CTRL1_OFFSET); ++ bRGA_MMU_SRC_BASE = (u32 *) (base + RGA2_MMU_SRC_BASE_OFFSET); ++ bRGA_MMU_SRC1_BASE = (u32 *) (base + RGA2_MMU_SRC1_BASE_OFFSET); ++ bRGA_MMU_DST_BASE = (u32 *) (base + RGA2_MMU_DST_BASE_OFFSET); ++ bRGA_MMU_ELS_BASE = (u32 *) (base + RGA2_MMU_ELS_BASE_OFFSET); ++ ++ reg = (msg->mmu_info.src0_mmu_flag & 0xf) | ++ ((msg->mmu_info.src1_mmu_flag & 0xf) << 4) | ++ ((msg->mmu_info.dst_mmu_flag & 0xf) << 8) | ++ ((msg->mmu_info.els_mmu_flag & 0x3) << 12); ++ ++ *bRGA_MMU_CTRL1 = reg; ++ *bRGA_MMU_SRC_BASE = (u32) (msg->mmu_info.src0_base_addr) >> 4; ++ *bRGA_MMU_SRC1_BASE = (u32) (msg->mmu_info.src1_base_addr) >> 4; ++ *bRGA_MMU_DST_BASE = (u32) (msg->mmu_info.dst_base_addr) >> 4; ++ *bRGA_MMU_ELS_BASE = (u32) (msg->mmu_info.els_base_addr) >> 4; ++} ++ ++static int rga2_gen_reg_info(u8 *base, struct rga2_req *msg) ++{ ++ u8 dst_nn_quantize_en = 0; ++ ++ RGA2_set_mode_ctrl(base, msg); ++ ++ RGA2_set_pat_info(base, msg); ++ ++ switch (msg->render_mode) { ++ case BITBLT_MODE: ++ RGA2_set_reg_src_info(base, msg); ++ RGA2_set_reg_dst_info(base, msg); ++ dst_nn_quantize_en = (msg->alpha_rop_flag >> 8) & 0x1; ++ if (dst_nn_quantize_en != 1) { ++ if ((msg->dst.format != ++ RGA_FORMAT_Y4)) { ++ RGA2_set_reg_alpha_info(base, msg); ++ RGA2_set_reg_rop_info(base, msg); ++ } ++ } ++ if (msg->mosaic_info.enable) ++ RGA_set_reg_mosaic(base, msg); ++ if (msg->osd_info.enable) ++ RGA2_set_reg_osd(base, msg); ++ ++ break; ++ case COLOR_FILL_MODE: ++ RGA2_set_reg_color_fill(base, msg); ++ RGA2_set_reg_dst_info(base, msg); ++ RGA2_set_reg_alpha_info(base, msg); ++ break; ++ case COLOR_PALETTE_MODE: ++ RGA2_set_reg_color_palette(base, msg); ++ RGA2_set_reg_dst_info(base, msg); ++ break; ++ case UPDATE_PALETTE_TABLE_MODE: ++ RGA2_set_reg_update_palette_table(base, msg); ++ break; ++ case UPDATE_PATTEN_BUF_MODE: ++ RGA2_set_reg_update_patten_buff(base, msg); ++ break; ++ default: ++ pr_err("ERROR msg render mode %d\n", msg->render_mode); ++ break; ++ } ++ ++ RGA2_set_mmu_reg_info(base, msg); ++ ++ return 0; ++} ++ ++static void rga_cmd_to_rga2_cmd(struct rga_scheduler_t *scheduler, ++ struct rga_req *req_rga, struct rga2_req *req) ++{ ++ if (req_rga->render_mode == 6) ++ req->render_mode = UPDATE_PALETTE_TABLE_MODE; ++ else if (req_rga->render_mode == 7) ++ req->render_mode = UPDATE_PATTEN_BUF_MODE; ++ else if (req_rga->render_mode == 5) ++ req->render_mode = BITBLT_MODE; ++ else ++ req->render_mode = req_rga->render_mode; ++ ++ memcpy(&req->src, &req_rga->src, sizeof(req_rga->src)); ++ memcpy(&req->dst, &req_rga->dst, sizeof(req_rga->dst)); ++ /* The application will only import pat or src1. */ ++ if (req->render_mode == UPDATE_PALETTE_TABLE_MODE) ++ memcpy(&req->pat, &req_rga->pat, sizeof(req_rga->pat)); ++ else ++ memcpy(&req->src1, &req_rga->pat, sizeof(req_rga->pat)); ++ ++ req->src.format = req_rga->src.format; ++ req->dst.format = req_rga->dst.format; ++ req->src1.format = req_rga->pat.format; ++ ++ switch (req_rga->rotate_mode & 0x0F) { ++ case 1: ++ if (req_rga->sina == 0 && req_rga->cosa == 65536) { ++ /* rotate 0 */ ++ req->rotate_mode = 0; ++ } else if (req_rga->sina == 65536 && req_rga->cosa == 0) { ++ /* rotate 90 */ ++ req->rotate_mode = 1; ++ req->dst.x_offset = req_rga->dst.x_offset; ++ req->dst.act_w = req_rga->dst.act_h; ++ req->dst.act_h = req_rga->dst.act_w; ++ } else if (req_rga->sina == 0 && req_rga->cosa == -65536) { ++ /* rotate 180 */ ++ req->rotate_mode = 2; ++ req->dst.x_offset = req_rga->dst.x_offset; ++ req->dst.y_offset = req_rga->dst.y_offset; ++ } else if (req_rga->sina == -65536 && req_rga->cosa == 0) { ++ /* totate 270 */ ++ req->rotate_mode = 3; ++ req->dst.y_offset = req_rga->dst.y_offset; ++ req->dst.act_w = req_rga->dst.act_h; ++ req->dst.act_h = req_rga->dst.act_w; ++ } ++ break; ++ case 2: ++ //x_mirror ++ req->rotate_mode |= (1 << 4); ++ break; ++ case 3: ++ //y_mirror ++ req->rotate_mode |= (2 << 4); ++ break; ++ case 4: ++ //x_mirror+y_mirror ++ req->rotate_mode |= (3 << 4); ++ break; ++ default: ++ req->rotate_mode = 0; ++ break; ++ } ++ ++ switch ((req_rga->rotate_mode & 0xF0) >> 4) { ++ case 2: ++ //x_mirror ++ req->rotate_mode |= (1 << 4); ++ break; ++ case 3: ++ //y_mirror ++ req->rotate_mode |= (2 << 4); ++ break; ++ case 4: ++ //x_mirror+y_mirror ++ req->rotate_mode |= (3 << 4); ++ break; ++ } ++ ++ req->LUT_addr = req_rga->LUT_addr; ++ req->rop_mask_addr = req_rga->rop_mask_addr; ++ ++ req->bitblt_mode = req_rga->bsfilter_flag; ++ ++ req->src_a_global_val = req_rga->alpha_global_value; ++ req->dst_a_global_val = req_rga->alpha_global_value; ++ req->rop_code = req_rga->rop_code; ++ req->rop_mode = req_rga->alpha_rop_mode; ++ ++ req->color_fill_mode = req_rga->color_fill_mode; ++ req->alpha_zero_key = req_rga->alpha_rop_mode >> 4; ++ req->src_trans_mode = req_rga->src_trans_mode; ++ req->color_key_min = req_rga->color_key_min; ++ req->color_key_max = req_rga->color_key_max; ++ ++ req->fg_color = req_rga->fg_color; ++ req->bg_color = req_rga->bg_color; ++ memcpy(&req->gr_color, &req_rga->gr_color, sizeof(req_rga->gr_color)); ++ ++ req->palette_mode = req_rga->palette_mode; ++ req->yuv2rgb_mode = req_rga->yuv2rgb_mode; ++ if (req_rga->full_csc.flag & 0x1) ++ req->full_csc_en = 1; ++ req->endian_mode = req_rga->endian_mode; ++ req->rgb2yuv_mode = 0; ++ ++ req->fading_alpha_value = 0; ++ req->fading_r_value = req_rga->fading.r; ++ req->fading_g_value = req_rga->fading.g; ++ req->fading_b_value = req_rga->fading.b; ++ ++ /* alpha mode set */ ++ req->alpha_rop_flag = 0; ++ /* alpha_rop_enable */ ++ req->alpha_rop_flag |= (((req_rga->alpha_rop_flag & 1))); ++ /* rop_enable */ ++ req->alpha_rop_flag |= (((req_rga->alpha_rop_flag >> 1) & 1) << 1); ++ /* fading_enable */ ++ req->alpha_rop_flag |= (((req_rga->alpha_rop_flag >> 2) & 1) << 2); ++ /* alpha_cal_mode_sel */ ++ req->alpha_rop_flag |= (((req_rga->alpha_rop_flag >> 4) & 1) << 3); ++ /* dst_dither_down */ ++ req->alpha_rop_flag |= (((req_rga->alpha_rop_flag >> 5) & 1) << 6); ++ /* gradient fill mode sel */ ++ req->alpha_rop_flag |= (((req_rga->alpha_rop_flag >> 6) & 1) << 7); ++ /* RGA_NN_QUANTIZE */ ++ req->alpha_rop_flag |= (((req_rga->alpha_rop_flag >> 8) & 1) << 8); ++ req->dither_mode = req_rga->dither_mode; ++ ++ /* RGA2 1106 add */ ++ memcpy(&req->mosaic_info, &req_rga->mosaic_info, sizeof(req_rga->mosaic_info)); ++ ++ if ((scheduler->data->feature & RGA_YIN_YOUT) && ++ rga_is_only_y_format(req->src.format) && ++ rga_is_only_y_format(req->dst.format)) ++ req->yin_yout_en = true; ++ ++ req->uvhds_mode = req_rga->uvhds_mode; ++ req->uvvds_mode = req_rga->uvvds_mode; ++ ++ memcpy(&req->osd_info, &req_rga->osd_info, sizeof(req_rga->osd_info)); ++ ++ if (((req_rga->alpha_rop_flag) & 1)) { ++ if ((req_rga->alpha_rop_flag >> 3) & 1) { ++ req->alpha_config.enable = true; ++ ++ if ((req_rga->alpha_rop_flag >> 9) & 1) { ++ req->alpha_config.fg_pre_multiplied = false; ++ req->alpha_config.bg_pre_multiplied = false; ++ } else if (req->osd_info.enable) { ++ req->alpha_config.fg_pre_multiplied = true; ++ /* set dst(osd_block) real color mode */ ++ req->alpha_config.bg_pre_multiplied = false; ++ } else { ++ req->alpha_config.fg_pre_multiplied = true; ++ req->alpha_config.bg_pre_multiplied = true; ++ } ++ ++ req->alpha_config.fg_pixel_alpha_en = rga_is_alpha_format(req->src.format); ++ if (req->bitblt_mode) ++ req->alpha_config.bg_pixel_alpha_en = ++ rga_is_alpha_format(req->src1.format); ++ else ++ req->alpha_config.bg_pixel_alpha_en = ++ rga_is_alpha_format(req->dst.format); ++ ++ if (req_rga->feature.global_alpha_en) { ++ if (req_rga->fg_global_alpha < 0xff) { ++ req->alpha_config.fg_global_alpha_en = true; ++ req->alpha_config.fg_global_alpha_value = ++ req_rga->fg_global_alpha; ++ } else if (!req->alpha_config.fg_pixel_alpha_en) { ++ req->alpha_config.fg_global_alpha_en = true; ++ req->alpha_config.fg_global_alpha_value = 0xff; ++ } ++ ++ if (req_rga->bg_global_alpha < 0xff) { ++ req->alpha_config.bg_global_alpha_en = true; ++ req->alpha_config.bg_global_alpha_value = ++ req_rga->bg_global_alpha; ++ } else if (!req->alpha_config.bg_pixel_alpha_en) { ++ req->alpha_config.bg_global_alpha_en = true; ++ req->alpha_config.bg_global_alpha_value = 0xff; ++ } ++ } else { ++ req->alpha_config.bg_global_alpha_value = 0xff; ++ req->alpha_config.bg_global_alpha_value = 0xff; ++ } ++ ++ req->alpha_config.mode = req_rga->PD_mode; ++ } ++ } ++ ++ if (req_rga->mmu_info.mmu_en && (req_rga->mmu_info.mmu_flag & 1) == 1) { ++ req->mmu_info.src0_mmu_flag = 1; ++ req->mmu_info.dst_mmu_flag = 1; ++ ++ if (req_rga->mmu_info.mmu_flag >> 31) { ++ req->mmu_info.src0_mmu_flag = ++ ((req_rga->mmu_info.mmu_flag >> 8) & 1); ++ req->mmu_info.src1_mmu_flag = ++ ((req_rga->mmu_info.mmu_flag >> 9) & 1); ++ req->mmu_info.dst_mmu_flag = ++ ((req_rga->mmu_info.mmu_flag >> 10) & 1); ++ req->mmu_info.els_mmu_flag = ++ ((req_rga->mmu_info.mmu_flag >> 11) & 1); ++ } else { ++ if (req_rga->src.yrgb_addr >= 0xa0000000) { ++ req->mmu_info.src0_mmu_flag = 0; ++ req->src.yrgb_addr = ++ req_rga->src.yrgb_addr - 0x60000000; ++ req->src.uv_addr = ++ req_rga->src.uv_addr - 0x60000000; ++ req->src.v_addr = ++ req_rga->src.v_addr - 0x60000000; ++ } ++ ++ if (req_rga->dst.yrgb_addr >= 0xa0000000) { ++ req->mmu_info.dst_mmu_flag = 0; ++ req->dst.yrgb_addr = ++ req_rga->dst.yrgb_addr - 0x60000000; ++ } ++ ++ if (req_rga->pat.yrgb_addr >= 0xa0000000) { ++ req->mmu_info.src1_mmu_flag = 0; ++ req->src1.yrgb_addr = ++ req_rga->pat.yrgb_addr - 0x60000000; ++ } ++ } ++ } ++} ++ ++static void rga2_soft_reset(struct rga_scheduler_t *scheduler) ++{ ++ u32 i; ++ u32 reg; ++ u32 iommu_dte_addr = 0; ++ ++ if (scheduler->data->mmu == RGA_IOMMU) ++ iommu_dte_addr = rga_read(RGA_IOMMU_DTE_ADDR, scheduler); ++ ++ rga_write(m_RGA2_SYS_CTRL_ACLK_SRESET_P | m_RGA2_SYS_CTRL_CCLK_SRESET_P | ++ m_RGA2_SYS_CTRL_RST_PROTECT_P, ++ RGA2_SYS_CTRL, scheduler); ++ ++ for (i = 0; i < RGA_RESET_TIMEOUT; i++) { ++ /* RGA_SYS_CTRL */ ++ reg = rga_read(RGA2_SYS_CTRL, scheduler) & 1; ++ ++ if (reg == 0) ++ break; ++ ++ udelay(1); ++ } ++ ++ if (scheduler->data->mmu == RGA_IOMMU) { ++ rga_write(iommu_dte_addr, RGA_IOMMU_DTE_ADDR, scheduler); ++ /* enable iommu */ ++ rga_write(RGA_IOMMU_CMD_ENABLE_PAGING, RGA_IOMMU_COMMAND, scheduler); ++ } ++ ++ if (i == RGA_RESET_TIMEOUT) ++ pr_err("RAG2 core[%d] soft reset timeout.\n", scheduler->core); ++ else ++ pr_info("RGA2 core[%d] soft reset complete.\n", scheduler->core); ++ ++} ++ ++static int rga2_check_param(const struct rga_hw_data *data, const struct rga2_req *req) ++{ ++ if (!((req->render_mode == COLOR_FILL_MODE))) { ++ if (unlikely(rga_hw_out_of_range(&data->input_range, ++ req->src.act_w, req->src.act_h))) { ++ pr_err("invalid src resolution act_w = %d, act_h = %d\n", ++ req->src.act_w, req->src.act_h); ++ return -EINVAL; ++ } ++ ++ if (unlikely(req->src.vir_w * rga_get_pixel_stride_from_format(req->src.format) > ++ data->max_byte_stride * 8)) { ++ pr_err("invalid src stride, stride = %d, max_byte_stride = %d\n", ++ req->src.vir_w, data->max_byte_stride); ++ return -EINVAL; ++ } ++ ++ if (unlikely(req->src.vir_w < req->src.act_w)) { ++ pr_err("invalid src_vir_w act_w = %d, vir_w = %d\n", ++ req->src.act_w, req->src.vir_w); ++ return -EINVAL; ++ } ++ } ++ ++ if (unlikely(rga_hw_out_of_range(&data->output_range, req->dst.act_w, req->dst.act_h))) { ++ pr_err("invalid dst resolution act_w = %d, act_h = %d\n", ++ req->dst.act_w, req->dst.act_h); ++ return -EINVAL; ++ } ++ ++ if (unlikely(req->dst.vir_w * rga_get_pixel_stride_from_format(req->dst.format) > ++ data->max_byte_stride * 8)) { ++ pr_err("invalid dst stride, stride = %d, max_byte_stride = %d\n", ++ req->dst.vir_w, data->max_byte_stride); ++ return -EINVAL; ++ } ++ ++ if (unlikely(req->dst.vir_w < req->dst.act_w)) { ++ if (req->rotate_mode != 1) { ++ pr_err("invalid dst_vir_w act_h = %d, vir_h = %d\n", ++ req->dst.act_w, req->dst.vir_w); ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++static int rga2_align_check(struct rga2_req *req) ++{ ++ if (rga_is_yuv10bit_format(req->src.format)) ++ if ((req->src.vir_w % 16) || (req->src.x_offset % 2) || ++ (req->src.act_w % 2) || (req->src.y_offset % 2) || ++ (req->src.act_h % 2) || (req->src.vir_h % 2)) ++ pr_info("err src wstride, 10bit yuv\n"); ++ if (rga_is_yuv10bit_format(req->dst.format)) ++ if ((req->dst.vir_w % 16) || (req->dst.x_offset % 2) || ++ (req->dst.act_w % 2) || (req->dst.y_offset % 2) || ++ (req->dst.act_h % 2) || (req->dst.vir_h % 2)) ++ pr_info("err dst wstride, 10bit yuv\n"); ++ if (rga_is_yuv8bit_format(req->src.format)) ++ if ((req->src.vir_w % 4) || (req->src.x_offset % 2) || ++ (req->src.act_w % 2) || (req->src.y_offset % 2) || ++ (req->src.act_h % 2) || (req->src.vir_h % 2)) ++ pr_info("err src wstride, 8bit yuv\n"); ++ if (rga_is_yuv8bit_format(req->dst.format)) ++ if ((req->dst.vir_w % 4) || (req->dst.x_offset % 2) || ++ (req->dst.act_w % 2) || (req->dst.y_offset % 2) || ++ (req->dst.act_h % 2) || (req->dst.vir_h % 2)) ++ pr_info("err dst wstride, 8bit yuv\n"); ++ ++ return 0; ++} ++ ++static void print_debug_info(struct rga2_req *req) ++{ ++ pr_info("render_mode:%s,bitblit_mode=%d,rotate_mode:%s\n", ++ rga_get_render_mode_str(req->render_mode), req->bitblt_mode, ++ rga_get_rotate_mode_str(req->rotate_mode)); ++ ++ pr_info("src: y=%lx uv=%lx v=%lx aw=%d ah=%d vw=%d vh=%d\n", ++ (unsigned long)req->src.yrgb_addr, ++ (unsigned long)req->src.uv_addr, ++ (unsigned long)req->src.v_addr, ++ req->src.act_w, req->src.act_h, ++ req->src.vir_w, req->src.vir_h); ++ pr_info("src: xoff=%d yoff=%d format=%s\n", ++ req->src.x_offset, req->src.y_offset, ++ rga_get_format_name(req->src.format)); ++ ++ if (req->src1.yrgb_addr != 0 || req->src1.uv_addr != 0 ++ || req->src1.v_addr != 0) { ++ pr_info("src1: y=%lx uv=%lx v=%lx aw=%d ah=%d vw=%d vh=%d\n", ++ (unsigned long)req->src1.yrgb_addr, ++ (unsigned long)req->src1.uv_addr, ++ (unsigned long)req->src1.v_addr, ++ req->src1.act_w, req->src1.act_h, ++ req->src1.vir_w, req->src1.vir_h); ++ pr_info("src1: xoff=%d yoff=%d format=%s\n", ++ req->src1.x_offset, req->src1.y_offset, ++ rga_get_format_name(req->src1.format)); ++ } ++ ++ pr_info("dst: y=%lx uv=%lx v=%lx aw=%d ah=%d vw=%d vh=%d\n", ++ (unsigned long)req->dst.yrgb_addr, ++ (unsigned long)req->dst.uv_addr, ++ (unsigned long)req->dst.v_addr, ++ req->dst.act_w, req->dst.act_h, ++ req->dst.vir_w, req->dst.vir_h); ++ pr_info("dst: xoff=%d yoff=%d format=%s\n", ++ req->dst.x_offset, req->dst.y_offset, ++ rga_get_format_name(req->dst.format)); ++ ++ pr_info("mmu: src=%.2x src1=%.2x dst=%.2x els=%.2x\n", ++ req->mmu_info.src0_mmu_flag, req->mmu_info.src1_mmu_flag, ++ req->mmu_info.dst_mmu_flag, req->mmu_info.els_mmu_flag); ++ pr_info("alpha: flag %x mode=%s\n", ++ req->alpha_rop_flag, rga_get_blend_mode_str(req->alpha_config.mode)); ++ pr_info("alpha: pre_multi=[%d,%d] pixl=[%d,%d] glb=[%d,%d]\n", ++ req->alpha_config.fg_pre_multiplied, req->alpha_config.bg_pre_multiplied, ++ req->alpha_config.fg_pixel_alpha_en, req->alpha_config.bg_pixel_alpha_en, ++ req->alpha_config.fg_global_alpha_en, req->alpha_config.bg_global_alpha_en); ++ pr_info("alpha: fg_global_alpha=%x bg_global_alpha=%x\n", ++ req->alpha_config.fg_global_alpha_value, req->alpha_config.bg_global_alpha_value); ++ pr_info("yuv2rgb mode is %x\n", req->yuv2rgb_mode); ++} ++ ++static int rga2_init_reg(struct rga_job *job) ++{ ++ struct rga2_req req; ++ int ret = 0; ++ struct rga_scheduler_t *scheduler = NULL; ++ ktime_t timestamp = ktime_get(); ++ ++ scheduler = job->scheduler; ++ if (unlikely(scheduler == NULL)) { ++ pr_err("failed to get scheduler, %s(%d)\n", __func__, __LINE__); ++ return -EINVAL; ++ } ++ ++ memset(&req, 0x0, sizeof(req)); ++ ++ rga_cmd_to_rga2_cmd(scheduler, &job->rga_command_base, &req); ++ if (req.full_csc_en) { ++ memcpy(&job->full_csc, &job->rga_command_base.full_csc, sizeof(job->full_csc)); ++ if (job->rga_command_base.feature.full_csc_clip_en) { ++ memcpy(&job->full_csc_clip, &job->rga_command_base.full_csc_clip, ++ sizeof(job->full_csc_clip)); ++ } else { ++ job->full_csc_clip.y.max = 0xff; ++ job->full_csc_clip.y.min = 0x0; ++ job->full_csc_clip.uv.max = 0xff; ++ job->full_csc_clip.uv.min = 0x0; ++ } ++ ++ } else { ++ job->full_csc_clip.y.max = 0xff; ++ job->full_csc_clip.y.min = 0x0; ++ job->full_csc_clip.uv.max = 0xff; ++ job->full_csc_clip.uv.min = 0x0; ++ } ++ memcpy(&job->pre_intr_info, &job->rga_command_base.pre_intr_info, ++ sizeof(job->pre_intr_info)); ++ ++ /* check value if legal */ ++ ret = rga2_check_param(scheduler->data, &req); ++ if (ret == -EINVAL) { ++ pr_err("req argument is inval\n"); ++ return ret; ++ } ++ ++ rga2_align_check(&req); ++ ++ /* for debug */ ++ if (DEBUGGER_EN(MSG)) ++ print_debug_info(&req); ++ ++ /* RGA2 mmu set */ ++ if ((req.mmu_info.src0_mmu_flag & 1) || (req.mmu_info.src1_mmu_flag & 1) || ++ (req.mmu_info.dst_mmu_flag & 1) || (req.mmu_info.els_mmu_flag & 1)) { ++ if (scheduler->data->mmu != RGA_MMU) { ++ pr_err("core[%d] has no MMU, please use physically contiguous memory.\n", ++ scheduler->core); ++ pr_err("mmu_flag[src, src1, dst, els] = [0x%x, 0x%x, 0x%x, 0x%x]\n", ++ req.mmu_info.src0_mmu_flag, req.mmu_info.src1_mmu_flag, ++ req.mmu_info.dst_mmu_flag, req.mmu_info.els_mmu_flag); ++ return -EINVAL; ++ } ++ ++ ret = rga_set_mmu_base(job, &req); ++ if (ret < 0) { ++ pr_err("%s, [%d] set mmu info error\n", __func__, ++ __LINE__); ++ return -EFAULT; ++ } ++ } ++ ++ /* In slave mode, the current frame completion interrupt must be enabled. */ ++ if (scheduler->data->mmu == RGA_IOMMU) ++ req.CMD_fin_int_enable = 1; ++ ++ if (rga2_gen_reg_info((uint8_t *)job->cmd_reg, &req) == -1) { ++ pr_err("gen reg info error\n"); ++ return -EINVAL; ++ } ++ ++ if (DEBUGGER_EN(TIME)) ++ pr_info("request[%d], generate register cost time %lld us\n", ++ job->request_id, ktime_us_delta(ktime_get(), timestamp)); ++ ++ return ret; ++} ++ ++static void rga2_dump_read_back_sys_reg(struct rga_scheduler_t *scheduler) ++{ ++ int i; ++ unsigned long flags; ++ uint32_t sys_reg[24] = {0}; ++ ++ spin_lock_irqsave(&scheduler->irq_lock, flags); ++ ++ for (i = 0; i < 24; i++) ++ sys_reg[i] = rga_read(RGA2_SYS_REG_BASE + i * 4, scheduler); ++ ++ spin_unlock_irqrestore(&scheduler->irq_lock, flags); ++ ++ pr_info("SYS_READ_BACK_REG\n"); ++ for (i = 0; i < 6; i++) ++ pr_info("0x%04x : %.8x %.8x %.8x %.8x\n", ++ RGA2_SYS_REG_BASE + i * 0x10, ++ sys_reg[0 + i * 4], sys_reg[1 + i * 4], ++ sys_reg[2 + i * 4], sys_reg[3 + i * 4]); ++} ++ ++static void rga2_dump_read_back_csc_reg(struct rga_scheduler_t *scheduler) ++{ ++ int i; ++ unsigned long flags; ++ uint32_t csc_reg[12] = {0}; ++ ++ spin_lock_irqsave(&scheduler->irq_lock, flags); ++ ++ for (i = 0; i < 12; i++) ++ csc_reg[i] = rga_read(RGA2_CSC_REG_BASE + i * 4, scheduler); ++ ++ spin_unlock_irqrestore(&scheduler->irq_lock, flags); ++ ++ pr_info("CSC_READ_BACK_REG\n"); ++ for (i = 0; i < 3; i++) ++ pr_info("0x%04x : %.8x %.8x %.8x %.8x\n", ++ RGA2_CSC_REG_BASE + i * 0x10, ++ csc_reg[0 + i * 4], csc_reg[1 + i * 4], ++ csc_reg[2 + i * 4], csc_reg[3 + i * 4]); ++} ++ ++static void rga2_dump_read_back_cmd_reg(struct rga_scheduler_t *scheduler) ++{ ++ int i; ++ unsigned long flags; ++ uint32_t cmd_reg[32] = {0}; ++ ++ spin_lock_irqsave(&scheduler->irq_lock, flags); ++ ++ for (i = 0; i < 32; i++) ++ cmd_reg[i] = rga_read(RGA2_CMD_REG_BASE + i * 4, scheduler); ++ ++ spin_unlock_irqrestore(&scheduler->irq_lock, flags); ++ ++ pr_info("CMD_READ_BACK_REG\n"); ++ for (i = 0; i < 8; i++) ++ pr_info("0x%04x : %.8x %.8x %.8x %.8x\n", ++ RGA2_CMD_REG_BASE + i * 0x10, ++ cmd_reg[0 + i * 4], cmd_reg[1 + i * 4], ++ cmd_reg[2 + i * 4], cmd_reg[3 + i * 4]); ++} ++ ++static void rga2_dump_read_back_reg(struct rga_scheduler_t *scheduler) ++{ ++ rga2_dump_read_back_sys_reg(scheduler); ++ rga2_dump_read_back_csc_reg(scheduler); ++ rga2_dump_read_back_cmd_reg(scheduler); ++} ++ ++static void rga2_set_pre_intr_reg(struct rga_job *job, struct rga_scheduler_t *scheduler) ++{ ++ uint32_t reg; ++ ++ if (job->pre_intr_info.read_intr_en) { ++ reg = s_RGA2_READ_LINE_SW_INTR_LINE_RD_TH(job->pre_intr_info.read_threshold); ++ rga_write(reg, RGA2_READ_LINE_CNT, scheduler); ++ } ++ ++ if (job->pre_intr_info.write_intr_en) { ++ reg = s_RGA2_WRITE_LINE_SW_INTR_LINE_WR_START(job->pre_intr_info.write_start); ++ reg = ((reg & (~m_RGA2_WRITE_LINE_SW_INTR_LINE_WR_STEP)) | ++ (s_RGA2_WRITE_LINE_SW_INTR_LINE_WR_STEP(job->pre_intr_info.write_step))); ++ rga_write(reg, RGA2_WRITE_LINE_CNT, scheduler); ++ } ++ ++ reg = rga_read(RGA2_SYS_CTRL, scheduler); ++ reg = ((reg & (~m_RGA2_SYS_CTRL_HOLD_MODE_EN)) | ++ (s_RGA2_SYS_CTRL_HOLD_MODE_EN(job->pre_intr_info.read_hold_en))); ++ rga_write(reg, RGA2_SYS_CTRL, scheduler); ++ ++ reg = rga_read(RGA2_INT, scheduler); ++ reg = (reg | s_RGA2_INT_LINE_RD_CLEAR(0x1) | s_RGA2_INT_LINE_WR_CLEAR(0x1)); ++ reg = ((reg & (~m_RGA2_INT_LINE_RD_EN)) | ++ (s_RGA2_INT_LINE_RD_EN(job->pre_intr_info.read_intr_en))); ++ reg = ((reg & (~m_RGA2_INT_LINE_WR_EN)) | ++ (s_RGA2_INT_LINE_WR_EN(job->pre_intr_info.write_intr_en))); ++ rga_write(reg, RGA2_INT, scheduler); ++} ++ ++static void rga2_set_reg_full_csc(struct rga_job *job, struct rga_scheduler_t *scheduler) ++{ ++ /* full csc coefficient */ ++ /* Y coefficient */ ++ rga_write(job->full_csc.coe_y.r_v | ++ (job->full_csc_clip.y.max << 16) | (job->full_csc_clip.y.min << 24), ++ RGA2_DST_CSC_00, scheduler); ++ rga_write(job->full_csc.coe_y.g_y | ++ (job->full_csc_clip.uv.max << 16) | (job->full_csc_clip.uv.min << 24), ++ RGA2_DST_CSC_01, scheduler); ++ rga_write(job->full_csc.coe_y.b_u, RGA2_DST_CSC_02, scheduler); ++ rga_write(job->full_csc.coe_y.off, RGA2_DST_CSC_OFF0, scheduler); ++ ++ /* U coefficient */ ++ rga_write(job->full_csc.coe_u.r_v, RGA2_DST_CSC_10, scheduler); ++ rga_write(job->full_csc.coe_u.g_y, RGA2_DST_CSC_11, scheduler); ++ rga_write(job->full_csc.coe_u.b_u, RGA2_DST_CSC_12, scheduler); ++ rga_write(job->full_csc.coe_u.off, RGA2_DST_CSC_OFF1, scheduler); ++ ++ /* V coefficient */ ++ rga_write(job->full_csc.coe_v.r_v, RGA2_DST_CSC_20, scheduler); ++ rga_write(job->full_csc.coe_v.g_y, RGA2_DST_CSC_21, scheduler); ++ rga_write(job->full_csc.coe_v.b_u, RGA2_DST_CSC_22, scheduler); ++ rga_write(job->full_csc.coe_v.off, RGA2_DST_CSC_OFF2, scheduler); ++} ++ ++static int rga2_set_reg(struct rga_job *job, struct rga_scheduler_t *scheduler) ++{ ++ int i; ++ bool master_mode_en; ++ uint32_t sys_ctrl; ++ ktime_t now = ktime_get(); ++ ++ /* ++ * Currently there is no iova allocated for storing cmd for the IOMMU device, ++ * so the iommu device needs to use the slave mode. ++ */ ++ if (scheduler->data->mmu != RGA_IOMMU) ++ master_mode_en = true; ++ else ++ master_mode_en = false; ++ ++ if (job->pre_intr_info.enable) ++ rga2_set_pre_intr_reg(job, scheduler); ++ ++ if (job->full_csc.flag) ++ rga2_set_reg_full_csc(job, scheduler); ++ ++ if (DEBUGGER_EN(REG)) { ++ uint32_t *p; ++ ++ rga2_dump_read_back_sys_reg(scheduler); ++ rga2_dump_read_back_csc_reg(scheduler); ++ ++ p = job->cmd_reg; ++ pr_info("CMD_REG\n"); ++ for (i = 0; i < 8; i++) ++ pr_info("i = %x : %.8x %.8x %.8x %.8x\n", i, ++ p[0 + i * 4], p[1 + i * 4], ++ p[2 + i * 4], p[3 + i * 4]); ++ } ++ ++ /* All CMD finish int */ ++ rga_write(rga_read(RGA2_INT, scheduler) | ++ m_RGA2_INT_ERROR_ENABLE_MASK | m_RGA2_INT_ALL_CMD_DONE_INT_EN, ++ RGA2_INT, scheduler); ++ ++ /* sys_reg init */ ++ sys_ctrl = m_RGA2_SYS_CTRL_AUTO_CKG | m_RGA2_SYS_CTRL_AUTO_RST | ++ m_RGA2_SYS_CTRL_RST_PROTECT_P | m_RGA2_SYS_CTRL_DST_WR_OPT_DIS | ++ m_RGA2_SYS_CTRL_SRC0YUV420SP_RD_OPT_DIS; ++ ++ if (master_mode_en) { ++ /* master mode */ ++ sys_ctrl |= s_RGA2_SYS_CTRL_CMD_MODE(1); ++ ++ /* cmd buffer flush cache to ddr */ ++ rga_dma_sync_flush_range(&job->cmd_reg[0], &job->cmd_reg[32], scheduler); ++ ++ /* set cmd_addr */ ++ rga_write(virt_to_phys(job->cmd_reg), RGA2_CMD_BASE, scheduler); ++ rga_write(sys_ctrl, RGA2_SYS_CTRL, scheduler); ++ rga_write(m_RGA2_CMD_CTRL_CMD_LINE_ST_P, RGA2_CMD_CTRL, scheduler); ++ } else { ++ /* slave mode */ ++ sys_ctrl |= s_RGA2_SYS_CTRL_CMD_MODE(0) | m_RGA2_SYS_CTRL_CMD_OP_ST_P; ++ ++ /* set cmd_reg */ ++ for (i = 0; i <= 32; i++) ++ rga_write(job->cmd_reg[i], 0x100 + i * 4, scheduler); ++ ++ rga_write(sys_ctrl, RGA2_SYS_CTRL, scheduler); ++ } ++ ++ if (DEBUGGER_EN(REG)) ++ pr_info("sys_ctrl = %x, int = %x\n", ++ rga_read(RGA2_SYS_CTRL, scheduler), ++ rga_read(RGA2_INT, scheduler)); ++ ++ if (DEBUGGER_EN(TIME)) ++ pr_info("request[%d], set register cost time %lld us\n", ++ job->request_id, ktime_us_delta(now, job->timestamp)); ++ ++ job->hw_running_time = now; ++ job->hw_recoder_time = now; ++ ++ if (DEBUGGER_EN(REG)) ++ rga2_dump_read_back_reg(scheduler); ++ ++ return 0; ++} ++ ++static int rga2_get_version(struct rga_scheduler_t *scheduler) ++{ ++ u32 major_version, minor_version, svn_version; ++ u32 reg_version; ++ ++ if (!scheduler) { ++ pr_err("scheduler is null\n"); ++ return -EINVAL; ++ } ++ ++ reg_version = rga_read(RGA2_VERSION_NUM, scheduler); ++ ++ major_version = (reg_version & RGA2_MAJOR_VERSION_MASK) >> 24; ++ minor_version = (reg_version & RGA2_MINOR_VERSION_MASK) >> 20; ++ svn_version = (reg_version & RGA2_SVN_VERSION_MASK); ++ ++ /* ++ * some old rga ip has no rga version register, so force set to 2.00 ++ */ ++ if (!major_version && !minor_version) ++ major_version = 2; ++ ++ snprintf(scheduler->version.str, 10, "%x.%01x.%05x", major_version, ++ minor_version, svn_version); ++ ++ scheduler->version.major = major_version; ++ scheduler->version.minor = minor_version; ++ scheduler->version.revision = svn_version; ++ ++ return 0; ++} ++ ++static int rga2_read_back_reg(struct rga_job *job, struct rga_scheduler_t *scheduler) ++{ ++ if (job->rga_command_base.osd_info.enable) { ++ job->rga_command_base.osd_info.cur_flags0 = rga_read(RGA2_OSD_CUR_FLAGS0, ++ scheduler); ++ job->rga_command_base.osd_info.cur_flags1 = rga_read(RGA2_OSD_CUR_FLAGS1, ++ scheduler); ++ } ++ ++ return 0; ++} ++ ++static int rga2_irq(struct rga_scheduler_t *scheduler) ++{ ++ struct rga_job *job = scheduler->running_job; ++ ++ /* The hardware interrupt top-half don't need to lock the scheduler. */ ++ if (job == NULL) ++ return IRQ_HANDLED; ++ ++ if (test_bit(RGA_JOB_STATE_INTR_ERR, &job->state)) ++ return IRQ_WAKE_THREAD; ++ ++ job->intr_status = rga_read(RGA2_INT, scheduler); ++ job->hw_status = rga_read(RGA2_STATUS2, scheduler); ++ job->cmd_status = rga_read(RGA2_STATUS1, scheduler); ++ ++ if (DEBUGGER_EN(INT_FLAG)) ++ pr_info("irq handler, INTR[0x%x], HW_STATUS[0x%x], CMD_STATUS[0x%x]\n", ++ job->intr_status, job->hw_status, job->cmd_status); ++ ++ if (job->intr_status & ++ (m_RGA2_INT_CUR_CMD_DONE_INT_FLAG | m_RGA2_INT_ALL_CMD_DONE_INT_FLAG)) { ++ set_bit(RGA_JOB_STATE_FINISH, &job->state); ++ } else if (job->intr_status & m_RGA2_INT_ERROR_FLAG_MASK) { ++ set_bit(RGA_JOB_STATE_INTR_ERR, &job->state); ++ ++ pr_err("irq handler err! INTR[0x%x], HW_STATUS[0x%x], CMD_STATUS[0x%x]\n", ++ job->intr_status, job->hw_status, job->cmd_status); ++ scheduler->ops->soft_reset(scheduler); ++ } ++ ++ /*clear INTR */ ++ rga_write(rga_read(RGA2_INT, scheduler) | ++ (m_RGA2_INT_ERROR_CLEAR_MASK | ++ m_RGA2_INT_ALL_CMD_DONE_INT_CLEAR | m_RGA2_INT_NOW_CMD_DONE_INT_CLEAR | ++ m_RGA2_INT_LINE_RD_CLEAR | m_RGA2_INT_LINE_WR_CLEAR), ++ RGA2_INT, scheduler); ++ ++ return IRQ_WAKE_THREAD; ++} ++ ++static int rga2_isr_thread(struct rga_job *job, struct rga_scheduler_t *scheduler) ++{ ++ if (DEBUGGER_EN(INT_FLAG)) ++ pr_info("isr thread, INTR[0x%x], HW_STATUS[0x%x], CMD_STATUS[0x%x]\n", ++ rga_read(RGA2_INT, scheduler), ++ rga_read(RGA2_STATUS2, scheduler), ++ rga_read(RGA2_STATUS1, scheduler)); ++ ++ if (test_bit(RGA_JOB_STATE_INTR_ERR, &job->state)) { ++ if (job->hw_status & m_RGA2_STATUS2_RPP_ERROR) ++ pr_err("RGA current status: rpp error!\n"); ++ if (job->hw_status & m_RGA2_STATUS2_BUS_ERROR) ++ pr_err("RGA current status: bus error!\n"); ++ ++ if (job->intr_status & m_RGA2_INT_ERROR_INT_FLAG) { ++ pr_err("RGA bus error intr, please check your configuration and buffer.\n"); ++ job->ret = -EFAULT; ++ } else if (job->intr_status & m_RGA2_INT_MMU_INT_FLAG) { ++ pr_err("mmu failed, please check size of the buffer or whether the buffer has been freed.\n"); ++ job->ret = -EACCES; ++ } ++ ++ if (job->ret == 0) { ++ pr_err("rga intr error[0x%x]!\n", job->intr_status); ++ job->ret = -EFAULT; ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++const struct rga_backend_ops rga2_ops = { ++ .get_version = rga2_get_version, ++ .set_reg = rga2_set_reg, ++ .init_reg = rga2_init_reg, ++ .soft_reset = rga2_soft_reset, ++ .read_back_reg = rga2_read_back_reg, ++ .irq = rga2_irq, ++ .isr_thread = rga2_isr_thread, ++}; +diff --git a/drivers/video/rockchip/rga3/rga3_reg_info.c b/drivers/video/rockchip/rga3/rga3_reg_info.c +new file mode 100644 +index 000000000..2b61833aa +--- /dev/null ++++ b/drivers/video/rockchip/rga3/rga3_reg_info.c +@@ -0,0 +1,2191 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) Rockchip Electronics Co., Ltd. ++ * ++ * Author: Huang Lee ++ */ ++ ++#define pr_fmt(fmt) "rga3_reg: " fmt ++ ++#include "rga3_reg_info.h" ++#include "rga_dma_buf.h" ++#include "rga_iommu.h" ++#include "rga_common.h" ++#include "rga_debugger.h" ++#include "rga_hw_config.h" ++ ++#define FACTOR_MAX ((int)(2 << 15)) ++ ++static void RGA3_set_reg_win0_info(u8 *base, struct rga3_req *msg) ++{ ++ u32 *bRGA3_WIN0_RD_CTRL; ++ u32 *bRGA3_WIN0_Y_BASE, *bRGA3_WIN0_U_BASE, *bRGA3_WIN0_V_BASE; ++ u32 *bRGA3_WIN0_VIR_STRIDE; ++ u32 *bRGA3_WIN0_UV_VIR_STRIDE; ++ u32 *bRGA3_WIN0_SRC_SIZE; ++ u32 *bRGA3_WIN0_ACT_OFF; ++ u32 *bRGA3_WIN0_ACT_SIZE; ++ u32 *bRGA3_WIN0_DST_SIZE; ++ ++ u32 *bRGA3_WIN0_SCL_FAC; ++ /* Not used yet. */ ++ // u32 *bRGA3_WIN0_FBC_OFF; ++ ++ u32 sw = 0, sh = 0; ++ u32 dw = 0, dh = 0; ++ u32 param_x = 0, param_y = 0; ++ u8 x_up = 0, y_up = 0, x_by = 0, y_by = 0; ++ ++ u32 reg = 0; ++ ++ u8 win_format = 0; ++ u8 win_yc_swp = 0; ++ ++ /* rb swap on RGB, uv swap on YUV */ ++ u8 win_pix_swp = 0; ++ ++ /* ++ * 1: Semi planar, for yuv 4:2:x ++ * 2: Interleaved (yuyv), for yuv422 8bit only ,RGB ++ */ ++ u8 win_interleaved = 1; ++ ++ /* enable r2y or y2r */ ++ u8 win_r2y = 0; ++ u8 win_y2r = 0; ++ ++ u8 rotate_mode = 0; ++ u8 xmirror = 0; ++ u8 ymirror = 0; ++ ++ u8 pixel_width = 1; ++ u8 yuv10 = 0; ++ ++ u32 stride = 0; ++ u32 uv_stride = 0; ++ ++ bRGA3_WIN0_RD_CTRL = (u32 *) (base + RGA3_WIN0_RD_CTRL_OFFSET); ++ ++ bRGA3_WIN0_Y_BASE = (u32 *) (base + RGA3_WIN0_Y_BASE_OFFSET); ++ bRGA3_WIN0_U_BASE = (u32 *) (base + RGA3_WIN0_U_BASE_OFFSET); ++ bRGA3_WIN0_V_BASE = (u32 *) (base + RGA3_WIN0_V_BASE_OFFSET); ++ ++ bRGA3_WIN0_VIR_STRIDE = (u32 *) (base + RGA3_WIN0_VIR_STRIDE_OFFSET); ++ bRGA3_WIN0_UV_VIR_STRIDE = ++ (u32 *) (base + RGA3_WIN0_UV_VIR_STRIDE_OFFSET); ++ ++ /* Not used yet. */ ++ // bRGA3_WIN0_FBC_OFF = (u32 *) (base + RGA3_WIN0_FBC_OFF_OFFSET); ++ bRGA3_WIN0_ACT_OFF = (u32 *) (base + RGA3_WIN0_ACT_OFF_OFFSET); ++ bRGA3_WIN0_SRC_SIZE = (u32 *) (base + RGA3_WIN0_SRC_SIZE_OFFSET); ++ bRGA3_WIN0_ACT_SIZE = (u32 *) (base + RGA3_WIN0_ACT_SIZE_OFFSET); ++ bRGA3_WIN0_DST_SIZE = (u32 *) (base + RGA3_WIN0_DST_SIZE_OFFSET); ++ ++ bRGA3_WIN0_SCL_FAC = (u32 *) (base + RGA3_WIN0_SCL_FAC_OFFSET); ++ ++ if (msg->win0.rotate_mode != 0) { ++ rotate_mode = msg->rotate_mode & RGA3_ROT_BIT_ROT_90 ? 1 : 0; ++ xmirror = msg->rotate_mode & RGA3_ROT_BIT_X_MIRROR ? 1 : 0; ++ ymirror = msg->rotate_mode & RGA3_ROT_BIT_Y_MIRROR ? 1 : 0; ++ } ++ ++ /* scale */ ++ dw = msg->win0.dst_act_w; ++ dh = msg->win0.dst_act_h; ++ ++ if (rotate_mode) { ++ sh = msg->win0.src_act_w; ++ sw = msg->win0.src_act_h; ++ } else { ++ sw = msg->win0.src_act_w; ++ sh = msg->win0.src_act_h; ++ } ++ ++ if (sw > dw) { ++ x_up = 0; ++ x_by = 0; ++ } else if (sw < dw) { ++ x_up = 1; ++ x_by = 0; ++ } else { ++ x_up = 0; ++ x_by = 1; ++ } ++ ++ if (sh > dh) { ++ y_up = 0; ++ y_by = 0; ++ } else if (sh < dh) { ++ y_up = 1; ++ y_by = 0; ++ } else { ++ y_up = 0; ++ y_by = 1; ++ } ++ ++ if (x_by == 1 && x_up == 0) ++ param_x = 0; ++ else if (x_up == 1 && x_by == 0) { ++ param_x = FACTOR_MAX * (sw - 1) / (dw - 1); ++ /* even multiples of 128 require a scaling factor -1 */ ++ if ((FACTOR_MAX * (sw - 1)) % (dw - 1) == 0) ++ param_x = param_x - 1; ++ } else ++ param_x = FACTOR_MAX * (dw - 1) / (sw - 1) + 1; ++ ++ if (y_by == 1 && y_up == 0) ++ param_y = 0; ++ else if (y_up == 1 && y_by == 0) { ++ param_y = FACTOR_MAX * (sh - 1) / (dh - 1); ++ /* even multiples of 128 require a scaling factor -1 */ ++ if ((FACTOR_MAX * (sh - 1)) % (dh - 1) == 0) ++ param_y = param_y - 1; ++ } else ++ param_y = FACTOR_MAX * (dh - 1) / (sh - 1) + 1; ++ ++ switch (msg->win0.format) { ++ case RGA_FORMAT_RGBA_8888: ++ win_format = 0x8; ++ pixel_width = 4; ++ win_interleaved = 2; ++ break; ++ case RGA_FORMAT_BGRA_8888: ++ win_format = 0x6; ++ pixel_width = 4; ++ win_interleaved = 2; ++ break; ++ case RGA_FORMAT_ARGB_8888: ++ win_format = 0x9; ++ pixel_width = 4; ++ win_interleaved = 2; ++ break; ++ case RGA_FORMAT_ABGR_8888: ++ win_format = 0x7; ++ pixel_width = 4; ++ win_interleaved = 2; ++ break; ++ case RGA_FORMAT_RGB_888: ++ win_format = 0x5; ++ pixel_width = 3; ++ win_interleaved = 2; ++ win_pix_swp = 1; ++ break; ++ case RGA_FORMAT_BGR_888: ++ win_format = 0x5; ++ pixel_width = 3; ++ win_interleaved = 2; ++ break; ++ case RGA_FORMAT_RGB_565: ++ win_format = 0x4; ++ pixel_width = 2; ++ win_interleaved = 2; ++ win_pix_swp = 1; ++ break; ++ case RGA_FORMAT_BGR_565: ++ win_format = 0x4; ++ pixel_width = 2; ++ win_interleaved = 2; ++ break; ++ ++ case RGA_FORMAT_YVYU_422: ++ win_format = 0x1; ++ pixel_width = 2; ++ win_pix_swp = 1; ++ win_yc_swp = 1; ++ win_interleaved = 2; ++ break; ++ case RGA_FORMAT_VYUY_422: ++ win_format = 0x1; ++ pixel_width = 2; ++ win_pix_swp = 1; ++ win_yc_swp = 0; ++ win_interleaved = 2; ++ break; ++ case RGA_FORMAT_YUYV_422: ++ win_format = 0x1; ++ pixel_width = 2; ++ win_pix_swp = 0; ++ win_yc_swp = 1; ++ win_interleaved = 2; ++ break; ++ case RGA_FORMAT_UYVY_422: ++ win_format = 0x1; ++ pixel_width = 2; ++ win_pix_swp = 0; ++ win_yc_swp = 0; ++ win_interleaved = 2; ++ break; ++ ++ case RGA_FORMAT_YCbCr_422_SP: ++ win_format = 0x1; ++ break; ++ case RGA_FORMAT_YCbCr_420_SP: ++ win_format = 0x0; ++ break; ++ case RGA_FORMAT_YCrCb_422_SP: ++ win_format = 0x1; ++ win_pix_swp = 1; ++ break; ++ case RGA_FORMAT_YCrCb_420_SP: ++ win_format = 0x0; ++ win_pix_swp = 1; ++ break; ++ ++ case RGA_FORMAT_YCbCr_420_SP_10B: ++ win_format = 0x2; ++ yuv10 = 1; ++ break; ++ case RGA_FORMAT_YCrCb_420_SP_10B: ++ win_format = 0x2; ++ yuv10 = 1; ++ win_pix_swp = 1; ++ break; ++ case RGA_FORMAT_YCbCr_422_SP_10B: ++ win_format = 0x3; ++ yuv10 = 1; ++ break; ++ case RGA_FORMAT_YCrCb_422_SP_10B: ++ win_format = 0x3; ++ yuv10 = 1; ++ win_pix_swp = 1; ++ break; ++ }; ++ ++ if (rga_is_rgb_format(msg->win0.format) && ++ rga_is_yuv_format(msg->wr.format)) ++ win_r2y = 1; ++ if (rga_is_yuv_format(msg->win0.format) && ++ rga_is_rgb_format(msg->wr.format)) ++ win_y2r = 1; ++ ++ reg = ++ ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_R2Y_EN)) | ++ (s_RGA3_WIN0_RD_CTRL_SW_WIN0_R2Y_EN(win_r2y))); ++ reg = ++ ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_Y2R_EN)) | ++ (s_RGA3_WIN0_RD_CTRL_SW_WIN0_Y2R_EN(win_y2r))); ++ ++ reg = ++ ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_PIC_FORMAT)) | ++ (s_RGA3_WIN0_RD_CTRL_SW_WIN0_PIC_FORMAT(win_format))); ++ reg = ++ ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_PIX_SWAP)) | ++ (s_RGA3_WIN0_RD_CTRL_SW_WIN0_PIX_SWAP(win_pix_swp))); ++ reg = ++ ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_YC_SWAP)) | ++ (s_RGA3_WIN0_RD_CTRL_SW_WIN0_YC_SWAP(win_yc_swp))); ++ reg = ++ ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_RD_FORMAT)) | ++ (s_RGA3_WIN0_RD_CTRL_SW_WIN0_RD_FORMAT(win_interleaved))); ++ ++ if (win_r2y == 1) { ++ reg = ++ ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_CSC_MODE)) | ++ (s_RGA3_WIN0_RD_CTRL_SW_WIN0_CSC_MODE(msg->win0.r2y_mode))); ++ } else if (win_y2r == 1) { ++ reg = ++ ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_CSC_MODE)) | ++ (s_RGA3_WIN0_RD_CTRL_SW_WIN0_CSC_MODE(msg->win0.y2r_mode))); ++ } ++ ++ /* rotate & mirror */ ++ if (msg->win0.rotate_mode == 1) { ++ reg = ++ ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_ROT)) | ++ (s_RGA3_WIN0_RD_CTRL_SW_WIN0_ROT(rotate_mode))); ++ reg = ++ ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_XMIRROR)) | ++ (s_RGA3_WIN0_RD_CTRL_SW_WIN0_XMIRROR(xmirror))); ++ reg = ++ ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_YMIRROR)) | ++ (s_RGA3_WIN0_RD_CTRL_SW_WIN0_YMIRROR(ymirror))); ++ } ++ ++ /* scale */ ++ *bRGA3_WIN0_SCL_FAC = param_x | param_y << 16; ++ ++ reg = ++ ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_HOR_BY)) | ++ (s_RGA3_WIN0_RD_CTRL_SW_WIN0_HOR_BY(x_by))); ++ reg = ++ ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_HOR_UP)) | ++ (s_RGA3_WIN0_RD_CTRL_SW_WIN0_HOR_UP(x_up))); ++ reg = ++ ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_VER_BY)) | ++ (s_RGA3_WIN0_RD_CTRL_SW_WIN0_VER_BY(y_by))); ++ reg = ++ ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_VER_UP)) | ++ (s_RGA3_WIN0_RD_CTRL_SW_WIN0_VER_UP(y_up))); ++ ++ /* rd_mode */ ++ reg = ++ ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_RD_MODE)) | ++ (s_RGA3_WIN0_RD_CTRL_SW_WIN0_RD_MODE(msg->win0.rd_mode))); ++ /* win0 enable */ ++ reg = ++ ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_ENABLE)) | ++ (s_RGA3_WIN0_RD_CTRL_SW_WIN0_ENABLE(msg->win0.enable))); ++ ++ reg = ++ ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_YUV10B_COMPACT)) | ++ (s_RGA3_WIN0_RD_CTRL_SW_WIN0_YUV10B_COMPACT(1))); ++ ++ /* Only on raster mode, yuv 10bit can change to compact or set endian */ ++ if (msg->win0.rd_mode == RGA_RASTER_MODE && yuv10 == 1) { ++ reg = ++ ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_YUV10B_COMPACT)) | ++ (s_RGA3_WIN0_RD_CTRL_SW_WIN0_YUV10B_COMPACT ++ (msg->win0.is_10b_compact))); ++ reg = ++ ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_ENDIAN_MODE)) | ++ (s_RGA3_WIN0_RD_CTRL_SW_WIN0_ENDIAN_MODE ++ (msg->win0.is_10b_endian))); ++ } ++ ++ *bRGA3_WIN0_RD_CTRL = reg; ++ ++ switch (msg->win0.rd_mode) { ++ case 0: /* raster */ ++ stride = (((msg->win0.vir_w * pixel_width) + 15) & ~15) >> 2; ++ if (rga_is_yuv420_semi_planar_format(msg->win0.format)) ++ uv_stride = ((msg->win0.vir_w + 15) & ~15) >> 2; ++ else ++ uv_stride = stride; ++ break; ++ ++ case 1: /* fbc */ ++ stride = ((msg->win0.vir_w + 15) & ~15) >> 2; ++ if (rga_is_yuv420_semi_planar_format(msg->win0.format)) ++ uv_stride = ((msg->win0.vir_w + 15) & ~15) >> 2; ++ else ++ uv_stride = stride; ++ break; ++ ++ case 2: /* tile 8*8 */ ++ /* ++ * tile 8*8 mode 8 lines of data are read/written at one time, ++ * so stride needs * 8. YUV420 only has 4 lines of UV data, so ++ * it needs to >>1. ++ */ ++ stride = (((msg->win0.vir_w * pixel_width * 8) + 15) & ~15) >> 2; ++ if (rga_is_yuv420_semi_planar_format(msg->win0.format)) ++ uv_stride = ((((msg->win0.vir_w * 8) + 15) & ~15) >> 1) >> 2; ++ else ++ uv_stride = stride; ++ break; ++ } ++ ++ *bRGA3_WIN0_Y_BASE = (u32) msg->win0.yrgb_addr; ++ *bRGA3_WIN0_U_BASE = (u32) msg->win0.uv_addr; ++ *bRGA3_WIN0_V_BASE = (u32) msg->win0.v_addr; ++ ++ *bRGA3_WIN0_VIR_STRIDE = stride; ++ *bRGA3_WIN0_UV_VIR_STRIDE = uv_stride; ++ ++ *bRGA3_WIN0_ACT_OFF = msg->win0.x_offset | (msg->win0.y_offset << 16); ++ /* fbcd offset */ ++ /* ++ * *bRGA3_WIN0_FBC_OFF = msg->win0.fbc_x_offset | ++ * (msg->win0.fbc_y_offset << 16); ++ */ ++ ++ /* do not use win0 src size except fbcd */ ++ /* in FBCD, src_width needs to be aligned at 16 */ ++ *bRGA3_WIN0_SRC_SIZE = ALIGN(msg->win0.src_act_w + msg->win0.x_offset, 16) | ++ (ALIGN(msg->win0.y_offset + msg->win0.src_act_h, 16) << 16); ++ *bRGA3_WIN0_ACT_SIZE = ++ msg->win0.src_act_w | (msg->win0.src_act_h << 16); ++ *bRGA3_WIN0_DST_SIZE = ++ msg->win0.dst_act_w | (msg->win0.dst_act_h << 16); ++} ++ ++static void RGA3_set_reg_win1_info(u8 *base, struct rga3_req *msg) ++{ ++ u32 *bRGA3_WIN1_RD_CTRL; ++ u32 *bRGA3_WIN1_Y_BASE, *bRGA3_WIN1_U_BASE, *bRGA3_WIN1_V_BASE; ++ u32 *bRGA3_WIN1_VIR_STRIDE; ++ u32 *bRGA3_WIN1_UV_VIR_STRIDE; ++ u32 *bRGA3_WIN1_SRC_SIZE; ++ u32 *bRGA3_WIN1_ACT_OFF; ++ u32 *bRGA3_WIN1_ACT_SIZE; ++ u32 *bRGA3_WIN1_DST_SIZE; ++ ++ u32 *bRGA3_WIN1_SCL_FAC; ++ /* Not used yet. */ ++ // u32 *bRGA3_WIN1_FBC_OFF; ++ ++ u32 sw = 0, sh = 0; ++ u32 dw = 0, dh = 0; ++ u32 param_x = 0, param_y = 0; ++ u8 x_up = 0, y_up = 0, x_by = 0, y_by = 0; ++ ++ u32 reg = 0; ++ ++ u8 win_format = 0; ++ u8 win_yc_swp = 0; ++ ++ /* rb swap on RGB, uv swap on YUV */ ++ u8 win_pix_swp = 0; ++ ++ /* ++ * 1: Semi planar, for yuv 4:2:x ++ * 2: Interleaved (yuyv), for yuv422 8bit only ,RGB ++ */ ++ u8 win_interleaved = 1; ++ ++ u8 pixel_width = 1; ++ u8 yuv10 = 0; ++ ++ /* enable r2y or y2r */ ++ u8 win_r2y = 0; ++ u8 win_y2r = 0; ++ ++ u8 rotate_mode = 0; ++ u8 xmirror = 0; ++ u8 ymirror = 0; ++ ++ u32 stride = 0; ++ u32 uv_stride = 0; ++ ++ bRGA3_WIN1_RD_CTRL = (u32 *) (base + RGA3_WIN1_RD_CTRL_OFFSET); ++ ++ bRGA3_WIN1_Y_BASE = (u32 *) (base + RGA3_WIN1_Y_BASE_OFFSET); ++ bRGA3_WIN1_U_BASE = (u32 *) (base + RGA3_WIN1_U_BASE_OFFSET); ++ bRGA3_WIN1_V_BASE = (u32 *) (base + RGA3_WIN1_V_BASE_OFFSET); ++ ++ bRGA3_WIN1_VIR_STRIDE = (u32 *) (base + RGA3_WIN1_VIR_STRIDE_OFFSET); ++ bRGA3_WIN1_UV_VIR_STRIDE = ++ (u32 *) (base + RGA3_WIN1_UV_VIR_STRIDE_OFFSET); ++ ++ /* Not used yet. */ ++ // bRGA3_WIN1_FBC_OFF = (u32 *) (base + RGA3_WIN1_FBC_OFF_OFFSET); ++ bRGA3_WIN1_ACT_OFF = (u32 *) (base + RGA3_WIN1_ACT_OFF_OFFSET); ++ bRGA3_WIN1_SRC_SIZE = (u32 *) (base + RGA3_WIN1_SRC_SIZE_OFFSET); ++ bRGA3_WIN1_ACT_SIZE = (u32 *) (base + RGA3_WIN1_ACT_SIZE_OFFSET); ++ bRGA3_WIN1_DST_SIZE = (u32 *) (base + RGA3_WIN1_DST_SIZE_OFFSET); ++ ++ bRGA3_WIN1_SCL_FAC = (u32 *) (base + RGA3_WIN1_SCL_FAC_OFFSET); ++ ++ if (msg->win1.rotate_mode != 0) { ++ rotate_mode = msg->rotate_mode & RGA3_ROT_BIT_ROT_90 ? 1 : 0; ++ xmirror = msg->rotate_mode & RGA3_ROT_BIT_X_MIRROR ? 1 : 0; ++ ymirror = msg->rotate_mode & RGA3_ROT_BIT_Y_MIRROR ? 1 : 0; ++ } ++ ++ /* scale */ ++ dw = msg->win1.dst_act_w; ++ dh = msg->win1.dst_act_h; ++ ++ if (rotate_mode) { ++ sh = msg->win1.src_act_w; ++ sw = msg->win1.src_act_h; ++ } else { ++ sw = msg->win1.src_act_w; ++ sh = msg->win1.src_act_h; ++ } ++ ++ if (sw > dw) { ++ x_up = 0; ++ x_by = 0; ++ } else if (sw < dw) { ++ x_up = 1; ++ x_by = 0; ++ } else { ++ x_up = 0; ++ x_by = 1; ++ } ++ ++ if (sh > dh) { ++ y_up = 0; ++ y_by = 0; ++ } else if (sh < dh) { ++ y_up = 1; ++ y_by = 0; ++ } else { ++ y_up = 0; ++ y_by = 1; ++ } ++ ++ if (x_by == 1) ++ param_x = 0; ++ else if (x_up == 1) { ++ param_x = (FACTOR_MAX * (sw - 1)) / (dw - 1); ++ /* even multiples of 128 require a scaling factor -1 */ ++ if ((FACTOR_MAX * (sw - 1)) % (dw - 1) == 0) ++ param_x = param_x - 1; ++ } else ++ param_x = (FACTOR_MAX * (dw - 1)) / (sw - 1) + 1; ++ ++ if (y_by == 1) ++ param_y = 0; ++ else if (y_up == 1) { ++ param_y = (FACTOR_MAX * (sh - 1)) / (dh - 1); ++ /* even multiples of 128 require a scaling factor -1 */ ++ if ((FACTOR_MAX * (sh - 1)) % (dh - 1) == 0) ++ param_y = param_y - 1; ++ } else ++ param_y = (FACTOR_MAX * (dh - 1)) / (sh - 1) + 1; ++ ++ switch (msg->win1.format) { ++ case RGA_FORMAT_RGBA_8888: ++ win_format = 0x8; ++ pixel_width = 4; ++ win_interleaved = 2; ++ break; ++ case RGA_FORMAT_BGRA_8888: ++ win_format = 0x6; ++ pixel_width = 4; ++ win_interleaved = 2; ++ break; ++ case RGA_FORMAT_ARGB_8888: ++ win_format = 0x9; ++ pixel_width = 4; ++ win_interleaved = 2; ++ break; ++ case RGA_FORMAT_ABGR_8888: ++ win_format = 0x7; ++ pixel_width = 4; ++ win_interleaved = 2; ++ break; ++ case RGA_FORMAT_RGB_888: ++ win_format = 0x5; ++ pixel_width = 3; ++ win_interleaved = 2; ++ win_pix_swp = 1; ++ break; ++ case RGA_FORMAT_BGR_888: ++ win_format = 0x5; ++ pixel_width = 3; ++ win_interleaved = 2; ++ break; ++ case RGA_FORMAT_RGB_565: ++ win_format = 0x4; ++ pixel_width = 2; ++ win_interleaved = 2; ++ win_pix_swp = 1; ++ break; ++ case RGA_FORMAT_BGR_565: ++ win_format = 0x4; ++ pixel_width = 2; ++ win_interleaved = 2; ++ break; ++ ++ case RGA_FORMAT_YVYU_422: ++ win_format = 0x1; ++ pixel_width = 2; ++ win_pix_swp = 1; ++ win_yc_swp = 1; ++ win_interleaved = 2; ++ break; ++ case RGA_FORMAT_VYUY_422: ++ win_format = 0x1; ++ pixel_width = 2; ++ win_pix_swp = 1; ++ win_yc_swp = 0; ++ win_interleaved = 2; ++ break; ++ case RGA_FORMAT_YUYV_422: ++ win_format = 0x1; ++ pixel_width = 2; ++ win_pix_swp = 0; ++ win_yc_swp = 1; ++ win_interleaved = 2; ++ break; ++ case RGA_FORMAT_UYVY_422: ++ win_format = 0x1; ++ pixel_width = 2; ++ win_pix_swp = 0; ++ win_yc_swp = 0; ++ win_interleaved = 2; ++ break; ++ ++ case RGA_FORMAT_YCbCr_422_SP: ++ win_format = 0x1; ++ break; ++ case RGA_FORMAT_YCbCr_420_SP: ++ win_format = 0x0; ++ break; ++ case RGA_FORMAT_YCrCb_422_SP: ++ win_format = 0x1; ++ win_pix_swp = 1; ++ break; ++ case RGA_FORMAT_YCrCb_420_SP: ++ win_format = 0x0; ++ win_pix_swp = 1; ++ break; ++ ++ case RGA_FORMAT_YCbCr_420_SP_10B: ++ win_format = 0x2; ++ yuv10 = 1; ++ break; ++ case RGA_FORMAT_YCrCb_420_SP_10B: ++ win_format = 0x2; ++ win_pix_swp = 1; ++ yuv10 = 1; ++ break; ++ case RGA_FORMAT_YCbCr_422_SP_10B: ++ win_format = 0x3; ++ yuv10 = 1; ++ break; ++ case RGA_FORMAT_YCrCb_422_SP_10B: ++ win_format = 0x3; ++ win_pix_swp = 1; ++ yuv10 = 1; ++ break; ++ }; ++ ++ if (rga_is_rgb_format(msg->win1.format) && ++ rga_is_yuv_format(msg->wr.format)) ++ win_r2y = 1; ++ if (rga_is_yuv_format(msg->win1.format) && ++ rga_is_rgb_format(msg->wr.format)) ++ win_y2r = 1; ++ ++ reg = ++ ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_R2Y_EN)) | ++ (s_RGA3_WIN1_RD_CTRL_SW_WIN1_R2Y_EN(win_r2y))); ++ reg = ++ ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_Y2R_EN)) | ++ (s_RGA3_WIN1_RD_CTRL_SW_WIN1_Y2R_EN(win_y2r))); ++ ++ reg = ++ ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_PIC_FORMAT)) | ++ (s_RGA3_WIN1_RD_CTRL_SW_WIN1_PIC_FORMAT(win_format))); ++ reg = ++ ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_PIX_SWAP)) | ++ (s_RGA3_WIN1_RD_CTRL_SW_WIN1_PIX_SWAP(win_pix_swp))); ++ reg = ++ ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_YC_SWAP)) | ++ (s_RGA3_WIN1_RD_CTRL_SW_WIN1_YC_SWAP(win_yc_swp))); ++ reg = ++ ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_RD_FORMAT)) | ++ (s_RGA3_WIN1_RD_CTRL_SW_WIN1_RD_FORMAT(win_interleaved))); ++ ++ if (win_r2y == 1) { ++ reg = ++ ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_CSC_MODE)) | ++ (s_RGA3_WIN0_RD_CTRL_SW_WIN0_CSC_MODE(msg->win1.r2y_mode))); ++ } else if (win_y2r == 1) { ++ reg = ++ ((reg & (~m_RGA3_WIN0_RD_CTRL_SW_WIN0_CSC_MODE)) | ++ (s_RGA3_WIN0_RD_CTRL_SW_WIN0_CSC_MODE(msg->win1.y2r_mode))); ++ } ++ ++ /* rotate & mirror */ ++ reg = ++ ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_ROT)) | ++ (s_RGA3_WIN1_RD_CTRL_SW_WIN1_ROT(rotate_mode))); ++ reg = ++ ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_XMIRROR)) | ++ (s_RGA3_WIN1_RD_CTRL_SW_WIN1_XMIRROR(xmirror))); ++ reg = ++ ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_YMIRROR)) | ++ (s_RGA3_WIN1_RD_CTRL_SW_WIN1_YMIRROR(ymirror))); ++ //warning: TRM not complete ++ /* scale */ ++ *bRGA3_WIN1_SCL_FAC = param_x | param_y << 16; ++ ++ reg = ++ ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_HOR_BY)) | ++ (s_RGA3_WIN1_RD_CTRL_SW_WIN1_HOR_BY(x_by))); ++ reg = ++ ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_HOR_UP)) | ++ (s_RGA3_WIN1_RD_CTRL_SW_WIN1_HOR_UP(x_up))); ++ reg = ++ ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_VER_BY)) | ++ (s_RGA3_WIN1_RD_CTRL_SW_WIN1_VER_BY(y_by))); ++ reg = ++ ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_VER_UP)) | ++ (s_RGA3_WIN1_RD_CTRL_SW_WIN1_VER_UP(y_up))); ++ ++ reg = ++ ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_YUV10B_COMPACT)) | ++ (s_RGA3_WIN1_RD_CTRL_SW_WIN1_YUV10B_COMPACT(1))); ++ ++ /* Only on roster mode, yuv 10bit can change to compact or set endian */ ++ if (msg->win1.rd_mode == RGA_RASTER_MODE && yuv10 == 1) { ++ reg = ++ ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_YUV10B_COMPACT)) | ++ (s_RGA3_WIN1_RD_CTRL_SW_WIN1_YUV10B_COMPACT ++ (msg->win1.is_10b_compact))); ++ reg = ++ ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_ENDIAN_MODE)) | ++ (s_RGA3_WIN1_RD_CTRL_SW_WIN1_ENDIAN_MODE ++ (msg->win1.is_10b_endian))); ++ } ++ ++ /* rd_mode */ ++ reg = ++ ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_RD_MODE)) | ++ (s_RGA3_WIN1_RD_CTRL_SW_WIN1_RD_MODE(msg->win1.rd_mode))); ++ /* win1 enable */ ++ reg = ++ ((reg & (~m_RGA3_WIN1_RD_CTRL_SW_WIN1_ENABLE)) | ++ (s_RGA3_WIN1_RD_CTRL_SW_WIN1_ENABLE(msg->win1.enable))); ++ ++ *bRGA3_WIN1_RD_CTRL = reg; ++ ++ switch (msg->win1.rd_mode) { ++ case 0: /* raster */ ++ stride = (((msg->win1.vir_w * pixel_width) + 15) & ~15) >> 2; ++ if (rga_is_yuv420_semi_planar_format(msg->win1.format)) ++ uv_stride = ((msg->win1.vir_w + 15) & ~15) >> 2; ++ else ++ uv_stride = stride; ++ break; ++ ++ case 1: /* fbc */ ++ stride = ((msg->win1.vir_w + 15) & ~15) >> 2; ++ if (rga_is_yuv420_semi_planar_format(msg->win1.format)) ++ uv_stride = ((msg->win1.vir_w + 15) & ~15) >> 2; ++ else ++ uv_stride = stride; ++ break; ++ ++ case 2: /* tile 8*8 */ ++ stride = (((msg->win1.vir_w * pixel_width * 8) + 15) & ~15) >> 2; ++ if (rga_is_yuv420_semi_planar_format(msg->win1.format)) ++ uv_stride = ((((msg->win1.vir_w * 8) + 15) & ~15) >> 1) >> 2; ++ else ++ uv_stride = stride; ++ break; ++ } ++ ++ *bRGA3_WIN1_Y_BASE = (u32) msg->win1.yrgb_addr; ++ *bRGA3_WIN1_U_BASE = (u32) msg->win1.uv_addr; ++ *bRGA3_WIN1_V_BASE = (u32) msg->win1.v_addr; ++ ++ *bRGA3_WIN1_VIR_STRIDE = stride; ++ *bRGA3_WIN1_UV_VIR_STRIDE = uv_stride; ++ ++ *bRGA3_WIN1_ACT_OFF = msg->win1.x_offset | (msg->win1.y_offset << 16); ++ /* fbcd offset */ ++ /* ++ * *bRGA3_WIN1_FBC_OFF = msg->win1.fbc_x_offset | ++ * (msg->win1.fbc_y_offset << 16); ++ */ ++ ++ /* do not use win1 src size except fbcd */ ++ *bRGA3_WIN1_SRC_SIZE = (msg->win1.src_act_w + ++ msg->win1.x_offset) | ((msg->win1.src_act_h + ++ msg->win1.y_offset) << 16); ++ *bRGA3_WIN1_ACT_SIZE = ++ msg->win1.src_act_w | (msg->win1.src_act_h << 16); ++ *bRGA3_WIN1_DST_SIZE = ++ msg->win1.dst_act_w | (msg->win1.dst_act_h << 16); ++} ++ ++static void RGA3_set_reg_wr_info(u8 *base, struct rga3_req *msg) ++{ ++ u32 *bRGA3_WR_RD_CTRL; ++ u32 *bRGA3_WR_Y_BASE, *bRGA3_WR_U_BASE, *bRGA3_WR_V_BASE; ++ u32 *bRGA3_WR_VIR_STRIDE; ++ u32 *bRGA3_WR_PL_VIR_STRIDE; ++ u32 *bRGA3_WR_FBCD_CTRL; ++ ++ u32 reg = 0; ++ u32 fbcd_reg = 0; ++ ++ u8 wr_format = 0; ++ u8 wr_yc_swp = 0; ++ ++ /* rb swap on RGB, uv swap on YUV */ ++ u8 wr_pix_swp = 0; ++ ++ u8 pixel_width = 1; ++ u8 yuv10 = 0; ++ ++ /* ++ * 1: Semi planar, for yuv 4:2:x ++ * 2: Interleaved (yuyv), for yuv422 8bit only ,RGB ++ */ ++ u8 wr_interleaved = 1; ++ ++ u32 stride = 0; ++ u32 uv_stride = 0; ++ ++ u32 vir_h = 0; ++ ++ bRGA3_WR_RD_CTRL = (u32 *) (base + RGA3_WR_CTRL_OFFSET); ++ bRGA3_WR_FBCD_CTRL = (u32 *) (base + RGA3_WR_FBCE_CTRL_OFFSET); ++ ++ bRGA3_WR_Y_BASE = (u32 *) (base + RGA3_WR_Y_BASE_OFFSET); ++ bRGA3_WR_U_BASE = (u32 *) (base + RGA3_WR_U_BASE_OFFSET); ++ bRGA3_WR_V_BASE = (u32 *) (base + RGA3_WR_V_BASE_OFFSET); ++ ++ bRGA3_WR_VIR_STRIDE = (u32 *) (base + RGA3_WR_VIR_STRIDE_OFFSET); ++ bRGA3_WR_PL_VIR_STRIDE = ++ (u32 *) (base + RGA3_WR_PL_VIR_STRIDE_OFFSET); ++ ++ switch (msg->wr.format) { ++ case RGA_FORMAT_RGBA_8888: ++ wr_format = 0x6; ++ pixel_width = 4; ++ wr_interleaved = 2; ++ wr_pix_swp = 1; ++ break; ++ case RGA_FORMAT_BGRA_8888: ++ wr_format = 0x6; ++ pixel_width = 4; ++ wr_interleaved = 2; ++ break; ++ case RGA_FORMAT_RGB_888: ++ wr_format = 0x5; ++ pixel_width = 3; ++ wr_interleaved = 2; ++ wr_pix_swp = 1; ++ break; ++ case RGA_FORMAT_BGR_888: ++ wr_format = 0x5; ++ pixel_width = 3; ++ wr_interleaved = 2; ++ break; ++ case RGA_FORMAT_RGB_565: ++ wr_format = 0x4; ++ pixel_width = 2; ++ wr_interleaved = 2; ++ wr_pix_swp = 1; ++ break; ++ case RGA_FORMAT_BGR_565: ++ wr_format = 0x4; ++ pixel_width = 2; ++ wr_interleaved = 2; ++ break; ++ ++ case RGA_FORMAT_YVYU_422: ++ wr_format = 0x1; ++ pixel_width = 2; ++ wr_pix_swp = 1; ++ wr_yc_swp = 1; ++ wr_interleaved = 2; ++ break; ++ case RGA_FORMAT_VYUY_422: ++ wr_format = 0x1; ++ pixel_width = 2; ++ wr_pix_swp = 1; ++ wr_yc_swp = 0; ++ wr_interleaved = 2; ++ break; ++ case RGA_FORMAT_YUYV_422: ++ wr_format = 0x1; ++ pixel_width = 2; ++ wr_pix_swp = 0; ++ wr_yc_swp = 1; ++ wr_interleaved = 2; ++ break; ++ case RGA_FORMAT_UYVY_422: ++ wr_format = 0x1; ++ pixel_width = 2; ++ wr_pix_swp = 0; ++ wr_yc_swp = 0; ++ wr_interleaved = 2; ++ break; ++ ++ case RGA_FORMAT_YCbCr_422_SP: ++ wr_format = 0x1; ++ break; ++ case RGA_FORMAT_YCbCr_420_SP: ++ wr_format = 0x0; ++ break; ++ case RGA_FORMAT_YCrCb_422_SP: ++ wr_format = 0x1; ++ wr_pix_swp = 1; ++ break; ++ case RGA_FORMAT_YCrCb_420_SP: ++ wr_format = 0x0; ++ wr_pix_swp = 1; ++ break; ++ ++ case RGA_FORMAT_YCbCr_420_SP_10B: ++ wr_format = 0x2; ++ yuv10 = 1; ++ break; ++ case RGA_FORMAT_YCrCb_420_SP_10B: ++ wr_format = 0x2; ++ wr_pix_swp = 1; ++ yuv10 = 1; ++ break; ++ case RGA_FORMAT_YCbCr_422_SP_10B: ++ wr_format = 0x3; ++ yuv10 = 1; ++ break; ++ case RGA_FORMAT_YCrCb_422_SP_10B: ++ wr_format = 0x3; ++ wr_pix_swp = 1; ++ yuv10 = 1; ++ break; ++ }; ++ ++ reg = ++ ((reg & (~m_RGA3_WR_CTRL_SW_WR_PIC_FORMAT)) | ++ (s_RGA3_WR_CTRL_SW_WR_PIC_FORMAT(wr_format))); ++ reg = ++ ((reg & (~m_RGA3_WR_CTRL_SW_WR_PIX_SWAP)) | ++ (s_RGA3_WR_CTRL_SW_WR_PIX_SWAP(wr_pix_swp))); ++ reg = ++ ((reg & (~m_RGA3_WR_CTRL_SW_WR_YC_SWAP)) | ++ (s_RGA3_WR_CTRL_SW_WR_YC_SWAP(wr_yc_swp))); ++ reg = ++ ((reg & (~m_RGA3_WR_CTRL_SW_WR_FORMAT)) | ++ (s_RGA3_WR_CTRL_SW_WR_FORMAT(wr_interleaved))); ++ reg = ++ ((reg & (~m_RGA3_WR_CTRL_SW_WR_FBCE_SPARSE_EN)) | ++ (s_RGA3_WR_CTRL_SW_WR_FBCE_SPARSE_EN(1))); ++ ++ reg = ++ ((reg & (~m_RGA3_WR_CTRL_SW_OUTSTANDING_MAX)) | ++ (s_RGA3_WR_CTRL_SW_OUTSTANDING_MAX(0xf))); ++ ++ reg = ++ ((reg & (~m_RGA3_WR_CTRL_SW_WR_YUV10B_COMPACT)) | ++ (s_RGA3_WR_CTRL_SW_WR_YUV10B_COMPACT(1))); ++ ++ /* Only on roster mode, yuv 10bit can change to compact or set endian */ ++ if (msg->wr.rd_mode == 0 && yuv10 == 1) { ++ reg = ++ ((reg & (~m_RGA3_WR_CTRL_SW_WR_YUV10B_COMPACT)) | ++ (s_RGA3_WR_CTRL_SW_WR_YUV10B_COMPACT ++ (msg->wr.is_10b_compact))); ++ reg = ++ ((reg & (~m_RGA3_WR_CTRL_SW_WR_ENDIAN_MODE)) | ++ (s_RGA3_WR_CTRL_SW_WR_ENDIAN_MODE ++ (msg->wr.is_10b_endian))); ++ } ++ ++ /* rd_mode */ ++ reg = ++ ((reg & (~m_RGA3_WR_CTRL_SW_WR_MODE)) | ++ (s_RGA3_WR_CTRL_SW_WR_MODE(msg->wr.rd_mode))); ++ ++ fbcd_reg = ((fbcd_reg & (~m_RGA3_WR_FBCE_CTRL_SW_WR_FBCE_HOFF_DISS)) | ++ (s_RGA3_WR_FBCE_CTRL_SW_WR_FBCE_HOFF_DISS(0))); ++ ++ *bRGA3_WR_RD_CTRL = reg; ++ *bRGA3_WR_FBCD_CTRL = fbcd_reg; ++ ++ switch (msg->wr.rd_mode) { ++ case 0: /* raster */ ++ stride = (((msg->wr.vir_w * pixel_width) + 15) & ~15) >> 2; ++ uv_stride = ((msg->wr.vir_w + 15) & ~15) >> 2; ++ ++ *bRGA3_WR_U_BASE = (u32) msg->wr.uv_addr; ++ ++ break; ++ ++ case 1: /* fbc */ ++ stride = ((msg->wr.vir_w + 15) & ~15) >> 2; ++ /* need to calculate fbcd header size */ ++ vir_h = ((msg->wr.vir_h + 15) & ~15); ++ ++ /* RGBA8888 */ ++ if (wr_format == 0x6) ++ uv_stride = ((msg->wr.vir_w + 15) & ~15); ++ /* RGB888 */ ++ else if (wr_format == 0x5) ++ uv_stride = (((msg->wr.vir_w + 15) & ~15) >> 2) * 3; ++ /* RGB565, yuv422 8bit, yuv420 10bit */ ++ else if (wr_format == 0x4 || wr_format == 0x1 || wr_format == 0x2) ++ uv_stride = ((msg->wr.vir_w + 15) & ~15) >> 1; ++ /* yuv420 8bit */ ++ else if (wr_format == 0x0) ++ uv_stride = (((msg->wr.vir_w + 15) & ~15) >> 3) * 3; ++ /* yuv422 10bit */ ++ else if (wr_format == 0x3) ++ uv_stride = (((msg->wr.vir_w + 15) & ~15) >> 3) * 5; ++ ++ *bRGA3_WR_U_BASE = (u32) (msg->wr.uv_addr + ((stride * vir_h)>>2)); ++ ++ break; ++ ++ case 2: /* tile 8*8 */ ++ stride = (((msg->wr.vir_w * pixel_width * 8) + 15) & ~15) >> 2; ++ if (rga_is_yuv420_semi_planar_format(msg->win0.format)) ++ uv_stride = ((((msg->wr.vir_w * 8) + 15) & ~15) >> 1) >> 2; ++ else ++ uv_stride = stride; ++ ++ *bRGA3_WR_U_BASE = (u32) msg->wr.uv_addr; ++ break; ++ } ++ ++ *bRGA3_WR_Y_BASE = (u32) msg->wr.yrgb_addr; ++ *bRGA3_WR_V_BASE = (u32) msg->wr.v_addr; ++ ++ *bRGA3_WR_VIR_STRIDE = stride; ++ *bRGA3_WR_PL_VIR_STRIDE = uv_stride; ++} ++ ++static void RGA3_set_reg_overlap_info(u8 *base, struct rga3_req *msg) ++{ ++ u32 *bRGA_OVERLAP_TOP_CTRL; ++ u32 *bRGA_OVERLAP_BOT_CTRL; ++ u32 *bRGA_OVERLAP_TOP_ALPHA; ++ u32 *bRGA_OVERLAP_BOT_ALPHA; ++ u32 *bRGA_OVERLAP_TOP_KEY_MIN; ++ u32 *bRGA_OVERLAP_TOP_KEY_MAX; ++ ++ u32 *bRGA_OVERLAP_CTRL; ++ u32 *bRGA3_OVLP_OFF; ++ ++ u32 reg; ++ union rga3_color_ctrl top_color_ctrl, bottom_color_ctrl; ++ union rga3_alpha_ctrl top_alpha_ctrl, bottom_alpha_ctrl; ++ struct rga_alpha_config *config; ++ ++ bRGA_OVERLAP_TOP_CTRL = (u32 *) (base + RGA3_OVLP_TOP_CTRL_OFFSET); ++ bRGA_OVERLAP_BOT_CTRL = (u32 *) (base + RGA3_OVLP_BOT_CTRL_OFFSET); ++ bRGA_OVERLAP_TOP_ALPHA = (u32 *) (base + RGA3_OVLP_TOP_ALPHA_OFFSET); ++ bRGA_OVERLAP_BOT_ALPHA = (u32 *) (base + RGA3_OVLP_BOT_ALPHA_OFFSET); ++ ++ bRGA_OVERLAP_CTRL = (u32 *) (base + RGA3_OVLP_CTRL_OFFSET); ++ bRGA3_OVLP_OFF = (u32 *) (base + RGA3_OVLP_OFF_OFFSET); ++ ++ /* Alpha blend */ ++ /*bot -> win0(dst), top -> win1(src). */ ++ top_color_ctrl.value = 0; ++ bottom_color_ctrl.value = 0; ++ top_alpha_ctrl.value = 0; ++ bottom_alpha_ctrl.value = 0; ++ config = &msg->alpha_config; ++ ++ if (config->fg_pixel_alpha_en) ++ top_color_ctrl.bits.blend_mode = ++ config->fg_global_alpha_en ? RGA_ALPHA_PER_PIXEL_GLOBAL : ++ RGA_ALPHA_PER_PIXEL; ++ else ++ top_color_ctrl.bits.blend_mode = RGA_ALPHA_GLOBAL; ++ ++ if (config->bg_pixel_alpha_en) ++ bottom_color_ctrl.bits.blend_mode = ++ config->bg_global_alpha_en ? RGA_ALPHA_PER_PIXEL_GLOBAL : ++ RGA_ALPHA_PER_PIXEL; ++ else ++ bottom_color_ctrl.bits.blend_mode = RGA_ALPHA_GLOBAL; ++ ++ /* ++ * Since the hardware uses 256 as 1, the original alpha value needs to ++ * be + (alpha >> 7). ++ */ ++ top_color_ctrl.bits.alpha_cal_mode = RGA_ALPHA_SATURATION; ++ bottom_color_ctrl.bits.alpha_cal_mode = RGA_ALPHA_SATURATION; ++ ++ top_color_ctrl.bits.global_alpha = config->fg_global_alpha_value; ++ bottom_color_ctrl.bits.global_alpha = config->bg_global_alpha_value; ++ ++ /* porter duff alpha enable */ ++ switch (config->mode) { ++ case RGA_ALPHA_BLEND_SRC: ++ /* ++ * SRC mode: ++ * Sf = 1, Df = 0; ++ * [Rc,Ra] = [Sc,Sa]; ++ */ ++ top_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; ++ top_color_ctrl.bits.factor_mode = RGA_ALPHA_ONE; ++ ++ bottom_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; ++ bottom_color_ctrl.bits.factor_mode = RGA_ALPHA_ZERO; ++ ++ break; ++ ++ case RGA_ALPHA_BLEND_DST: ++ /* ++ * SRC mode: ++ * Sf = 0, Df = 1; ++ * [Rc,Ra] = [Dc,Da]; ++ */ ++ top_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; ++ top_color_ctrl.bits.factor_mode = RGA_ALPHA_ZERO; ++ ++ bottom_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; ++ bottom_color_ctrl.bits.factor_mode = RGA_ALPHA_ONE; ++ ++ break; ++ ++ case RGA_ALPHA_BLEND_SRC_OVER: ++ /* ++ * SRC-OVER mode: ++ * Sf = 1, Df = (1 - Sa) ++ * [Rc,Ra] = [ Sc + (1 - Sa) * Dc, Sa + (1 - Sa) * Da ] ++ */ ++ top_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; ++ top_color_ctrl.bits.factor_mode = RGA_ALPHA_ONE; ++ ++ bottom_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; ++ bottom_color_ctrl.bits.factor_mode = RGA_ALPHA_OPPOSITE_INVERSE; ++ ++ break; ++ ++ case RGA_ALPHA_BLEND_DST_OVER: ++ /* ++ * DST-OVER mode: ++ * Sf = (1 - Da) , Df = 1 ++ * [Rc,Ra] = [ Sc * (1 - Da) + Dc, Sa * (1 - Da) + Da ] ++ */ ++ top_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; ++ top_color_ctrl.bits.factor_mode = RGA_ALPHA_OPPOSITE_INVERSE; ++ ++ bottom_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; ++ bottom_color_ctrl.bits.factor_mode = RGA_ALPHA_ONE; ++ ++ break; ++ ++ case RGA_ALPHA_BLEND_SRC_IN: ++ /* ++ * SRC-IN mode: ++ * Sf = Da , Df = 0 ++ * [Rc,Ra] = [ Sc * Da, Sa * Da ] ++ */ ++ top_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; ++ top_color_ctrl.bits.factor_mode = RGA_ALPHA_OPPOSITE; ++ ++ bottom_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; ++ bottom_color_ctrl.bits.factor_mode = RGA_ALPHA_ZERO; ++ ++ break; ++ ++ case RGA_ALPHA_BLEND_DST_IN: ++ /* ++ * DST-IN mode: ++ * Sf = 0 , Df = Sa ++ * [Rc,Ra] = [ Dc * Sa, Da * Sa ] ++ */ ++ top_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; ++ top_color_ctrl.bits.factor_mode = RGA_ALPHA_ZERO; ++ ++ bottom_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; ++ bottom_color_ctrl.bits.factor_mode = RGA_ALPHA_OPPOSITE; ++ ++ break; ++ ++ case RGA_ALPHA_BLEND_SRC_OUT: ++ /* ++ * SRC-OUT mode: ++ * Sf = (1 - Da) , Df = 0 ++ * [Rc,Ra] = [ Sc * (1 - Da), Sa * (1 - Da) ] ++ */ ++ top_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; ++ top_color_ctrl.bits.factor_mode = RGA_ALPHA_OPPOSITE_INVERSE; ++ ++ bottom_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; ++ bottom_color_ctrl.bits.factor_mode = RGA_ALPHA_ZERO; ++ ++ break; ++ ++ case RGA_ALPHA_BLEND_DST_OUT: ++ /* ++ * DST-OUT mode: ++ * Sf = 0 , Df = (1 - Sa) ++ * [Rc,Ra] = [ Dc * (1 - Sa), Da * (1 - Sa) ] ++ */ ++ top_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; ++ top_color_ctrl.bits.factor_mode = RGA_ALPHA_ZERO; ++ ++ bottom_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; ++ bottom_color_ctrl.bits.factor_mode = RGA_ALPHA_OPPOSITE_INVERSE; ++ ++ break; ++ ++ case RGA_ALPHA_BLEND_SRC_ATOP: ++ /* ++ * SRC-ATOP mode: ++ * Sf = Da , Df = (1 - Sa) ++ * [Rc,Ra] = [ Sc * Da + Dc * (1 - Sa), Sa * Da + Da * (1 - Sa) ] ++ */ ++ top_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; ++ top_color_ctrl.bits.factor_mode = RGA_ALPHA_OPPOSITE; ++ ++ bottom_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; ++ bottom_color_ctrl.bits.factor_mode = RGA_ALPHA_OPPOSITE_INVERSE; ++ ++ break; ++ ++ case RGA_ALPHA_BLEND_DST_ATOP: ++ /* ++ * DST-ATOP mode: ++ * Sf = (1 - Da) , Df = Sa ++ * [Rc,Ra] = [ Sc * (1 - Da) + Dc * Sa, Sa * (1 - Da) + Da * Sa ] ++ */ ++ top_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; ++ top_color_ctrl.bits.factor_mode = RGA_ALPHA_OPPOSITE_INVERSE; ++ ++ bottom_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; ++ bottom_color_ctrl.bits.factor_mode = RGA_ALPHA_OPPOSITE; ++ ++ break; ++ ++ case RGA_ALPHA_BLEND_XOR: ++ /* ++ * DST-XOR mode: ++ * Sf = (1 - Da) , Df = (1 - Sa) ++ * [Rc,Ra] = [ Sc * (1 - Da) + Dc * (1 - Sa), Sa * (1 - Da) + Da * (1 - Sa) ] ++ */ ++ top_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; ++ top_color_ctrl.bits.factor_mode = RGA_ALPHA_OPPOSITE_INVERSE; ++ ++ bottom_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; ++ bottom_color_ctrl.bits.factor_mode = RGA_ALPHA_OPPOSITE_INVERSE; ++ ++ break; ++ ++ case RGA_ALPHA_BLEND_CLEAR: ++ /* ++ * DST-CLEAR mode: ++ * Sf = 0 , Df = 0 ++ * [Rc,Ra] = [ 0, 0 ] ++ */ ++ top_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; ++ top_color_ctrl.bits.factor_mode = RGA_ALPHA_ZERO; ++ ++ bottom_color_ctrl.bits.alpha_mode = RGA_ALPHA_STRAIGHT; ++ bottom_color_ctrl.bits.factor_mode = RGA_ALPHA_ZERO; ++ ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (!config->enable && msg->abb_alpha_pass) { ++ /* ++ * enabled by default bot_blend_m1 && bot_alpha_cal_m1 for src channel(win0) ++ * In ABB mode, the number will be fetched according to 16*16, so it needs to ++ * be enabled top_blend_m1 && top_alpha_cal_m1 for dst channel(wr). ++ */ ++ top_color_ctrl.bits.color_mode = RGA_ALPHA_PRE_MULTIPLIED; ++ ++ top_alpha_ctrl.bits.blend_mode = RGA_ALPHA_PER_PIXEL; ++ top_alpha_ctrl.bits.alpha_cal_mode = RGA_ALPHA_NO_SATURATION; ++ ++ bottom_color_ctrl.bits.color_mode = RGA_ALPHA_PRE_MULTIPLIED; ++ ++ bottom_alpha_ctrl.bits.blend_mode = RGA_ALPHA_PER_PIXEL; ++ bottom_alpha_ctrl.bits.alpha_cal_mode = RGA_ALPHA_NO_SATURATION; ++ } else { ++ top_color_ctrl.bits.color_mode = ++ config->fg_pre_multiplied ? ++ RGA_ALPHA_PRE_MULTIPLIED : RGA_ALPHA_NO_PRE_MULTIPLIED; ++ ++ top_alpha_ctrl.bits.blend_mode = top_color_ctrl.bits.blend_mode; ++ top_alpha_ctrl.bits.alpha_cal_mode = top_color_ctrl.bits.alpha_cal_mode; ++ top_alpha_ctrl.bits.alpha_mode = top_color_ctrl.bits.alpha_mode; ++ top_alpha_ctrl.bits.factor_mode = top_color_ctrl.bits.factor_mode; ++ ++ bottom_color_ctrl.bits.color_mode = ++ config->bg_pre_multiplied ? ++ RGA_ALPHA_PRE_MULTIPLIED : RGA_ALPHA_NO_PRE_MULTIPLIED; ++ ++ bottom_alpha_ctrl.bits.blend_mode = bottom_color_ctrl.bits.blend_mode; ++ bottom_alpha_ctrl.bits.alpha_cal_mode = bottom_color_ctrl.bits.alpha_cal_mode; ++ bottom_alpha_ctrl.bits.alpha_mode = bottom_color_ctrl.bits.alpha_mode; ++ bottom_alpha_ctrl.bits.factor_mode = bottom_color_ctrl.bits.factor_mode; ++ } ++ ++ *bRGA_OVERLAP_TOP_CTRL = top_color_ctrl.value; ++ *bRGA_OVERLAP_BOT_CTRL = bottom_color_ctrl.value; ++ *bRGA_OVERLAP_TOP_ALPHA = top_alpha_ctrl.value; ++ *bRGA_OVERLAP_BOT_ALPHA = bottom_alpha_ctrl.value; ++ ++ /* set RGA_OVERLAP_CTRL */ ++ reg = 0; ++ /* color key */ ++ bRGA_OVERLAP_TOP_KEY_MIN = ++ (u32 *) (base + RGA3_OVLP_TOP_KEY_MIN_OFFSET); ++ bRGA_OVERLAP_TOP_KEY_MAX = ++ (u32 *) (base + RGA3_OVLP_TOP_KEY_MAX_OFFSET); ++ ++ /* ++ * YG : value (0:9) ++ * UB : value >> 10 (10:19) ++ * VG : value >> 20 (20:29) ++ */ ++ if (msg->color_key_min > 0 || msg->color_key_max > 0) { ++ *bRGA_OVERLAP_TOP_KEY_MIN = msg->color_key_min; ++ *bRGA_OVERLAP_TOP_KEY_MAX = msg->color_key_max; ++ reg = ((reg & (~m_RGA3_OVLP_CTRL_SW_TOP_KEY_EN)) | ++ (s_RGA3_OVLP_CTRL_SW_TOP_KEY_EN(1))); ++ } ++ ++ /* 1: ABB mode, 0: ABC mode, ABB cannot support fbc in&out */ ++ if (msg->win0.yrgb_addr == msg->wr.yrgb_addr) ++ reg = ((reg & (~m_RGA3_OVLP_CTRL_SW_OVLP_MODE)) | ++ (s_RGA3_OVLP_CTRL_SW_OVLP_MODE(1))); ++ ++ /* 1: yuv field, 0: rgb field */ ++ if (rga_is_yuv_format(msg->wr.format)) ++ reg = ((reg & (~m_RGA3_OVLP_CTRL_SW_OVLP_FIELD)) | ++ (s_RGA3_OVLP_CTRL_SW_OVLP_FIELD(1))); ++ ++ /* ++ * warning: if m1 & m0 need config split,need to redesign ++ * this judge, which consider RGBA8888 format ++ */ ++ reg = ((reg & (~m_RGA3_OVLP_CTRL_SW_TOP_ALPHA_EN)) | ++ (s_RGA3_OVLP_CTRL_SW_TOP_ALPHA_EN(config->enable))); ++ ++ *bRGA_OVERLAP_CTRL = reg; ++ ++ *bRGA3_OVLP_OFF = msg->wr.x_offset | (msg->wr.y_offset << 16); ++} ++ ++static int rga3_gen_reg_info(u8 *base, struct rga3_req *msg) ++{ ++ switch (msg->render_mode) { ++ case BITBLT_MODE: ++ RGA3_set_reg_win0_info(base, msg); ++ RGA3_set_reg_win1_info(base, msg); ++ RGA3_set_reg_overlap_info(base, msg); ++ RGA3_set_reg_wr_info(base, msg); ++ break; ++ default: ++ pr_err("error msg render mode %d\n", msg->render_mode); ++ break; ++ } ++ ++ return 0; ++} ++ ++static void addr_copy(struct rga_win_info_t *win, struct rga_img_info_t *img) ++{ ++ win->yrgb_addr = img->yrgb_addr; ++ win->uv_addr = img->uv_addr; ++ win->v_addr = img->v_addr; ++ win->enable = 1; ++} ++ ++static void set_win_info(struct rga_win_info_t *win, struct rga_img_info_t *img) ++{ ++ win->x_offset = img->x_offset; ++ win->y_offset = img->y_offset; ++ win->src_act_w = img->act_w; ++ win->src_act_h = img->act_h; ++ win->vir_w = img->vir_w; ++ win->vir_h = img->vir_h; ++ if (img->rd_mode == RGA_RASTER_MODE) ++ win->rd_mode = 0; ++ else if (img->rd_mode == RGA_FBC_MODE) ++ win->rd_mode = 1; ++ else if (img->rd_mode == RGA_TILE_MODE) ++ win->rd_mode = 2; ++ ++ switch (img->compact_mode) { ++ case RGA_10BIT_INCOMPACT: ++ win->is_10b_compact = 0; ++ break; ++ case RGA_10BIT_COMPACT: ++ default: ++ win->is_10b_compact = 1; ++ break; ++ } ++ ++ win->is_10b_endian = img->is_10b_endian; ++} ++ ++static void set_wr_info(struct rga_req *req_rga, struct rga3_req *req) ++{ ++ /* The output w/h are bound to the dst_act_w/h of win0. */ ++ req->wr.dst_act_w = req->win0.dst_act_w; ++ req->wr.dst_act_h = req->win0.dst_act_h; ++ ++ /* Some configurations need to be all equal to the output w/h. */ ++ req->wr.vir_w = req_rga->dst.vir_w; ++ req->wr.vir_h = req_rga->dst.vir_h; ++ ++ if (req_rga->dst.rd_mode == RGA_RASTER_MODE) ++ req->wr.rd_mode = 0; ++ else if (req_rga->dst.rd_mode == RGA_FBC_MODE) ++ req->wr.rd_mode = 1; ++ else if (req_rga->dst.rd_mode == RGA_TILE_MODE) ++ req->wr.rd_mode = 2; ++ ++ switch (req_rga->dst.compact_mode) { ++ case RGA_10BIT_INCOMPACT: ++ req->wr.is_10b_compact = 0; ++ break; ++ case RGA_10BIT_COMPACT: ++ default: ++ req->wr.is_10b_compact = 1; ++ break; ++ } ++ ++ req->wr.is_10b_endian = req_rga->dst.is_10b_endian; ++} ++ ++/* TODO: common part */ ++static void rga_cmd_to_rga3_cmd(struct rga_req *req_rga, struct rga3_req *req) ++{ ++ struct rga_img_info_t tmp; ++ ++ req->render_mode = BITBLT_MODE; ++ ++ /* rotate & mirror */ ++ switch (req_rga->rotate_mode & 0x0f) { ++ case 0x1: ++ if (req_rga->sina == 65536 && req_rga->cosa == 0) { ++ /* rot-90 */ ++ req->rotate_mode = RGA3_ROT_BIT_ROT_90; ++ } else if (req_rga->sina == 0 && req_rga->cosa == -65536) { ++ /* rot-180 = X-mirror + Y-mirror */ ++ req->rotate_mode = RGA3_ROT_BIT_X_MIRROR | RGA3_ROT_BIT_Y_MIRROR; ++ } else if (req_rga->sina == -65536 && req_rga->cosa == 0) { ++ /* rot-270 or -90 = rot-90 + X-mirror + Y-mirror */ ++ req->rotate_mode = RGA3_ROT_BIT_X_MIRROR | RGA3_ROT_BIT_Y_MIRROR | ++ RGA3_ROT_BIT_ROT_90; ++ } else if (req_rga->sina == 0 && req_rga->cosa == 65536) { ++ /* bypass */ ++ req->rotate_mode = 0; ++ } ++ break; ++ case 0x2: ++ /* X-mirror */ ++ req->rotate_mode = RGA3_ROT_BIT_X_MIRROR; ++ break; ++ case 0x3: ++ /* Y-mirror */ ++ req->rotate_mode = RGA3_ROT_BIT_Y_MIRROR; ++ break; ++ case 0x4: ++ /* X-mirror + Y-mirror */ ++ req->rotate_mode = RGA3_ROT_BIT_X_MIRROR | RGA3_ROT_BIT_Y_MIRROR; ++ break; ++ default: ++ req->rotate_mode = 0; ++ break; ++ } ++ ++ /* The upper four bits are only allowed to configure the mirror. */ ++ switch ((req_rga->rotate_mode & 0xf0) >> 4) { ++ case 2: ++ /* X-mirror */ ++ req->rotate_mode ^= RGA3_ROT_BIT_X_MIRROR; ++ break; ++ case 3: ++ /* Y-mirror */ ++ req->rotate_mode ^= RGA3_ROT_BIT_Y_MIRROR; ++ break; ++ case 0x4: ++ /* X-mirror + Y-mirror */ ++ req->rotate_mode ^= RGA3_ROT_BIT_X_MIRROR | RGA3_ROT_BIT_Y_MIRROR; ++ break; ++ } ++ ++ req->win0_a_global_val = req_rga->alpha_global_value; ++ req->win1_a_global_val = req_rga->alpha_global_value; ++ ++ /* fixup yuv/rgb convert to rgba missing alpha channel */ ++ if (!(req_rga->alpha_rop_flag & 1)) { ++ if (!rga_is_alpha_format(req_rga->src.format) && ++ rga_is_alpha_format(req_rga->dst.format)) { ++ req->alpha_config.fg_global_alpha_value = 0xff; ++ req->alpha_config.bg_global_alpha_value = 0xff; ++ } ++ } ++ ++ /* simple win can not support dst offset */ ++ if ((!((req_rga->alpha_rop_flag) & 1)) && ++ (req_rga->dst.x_offset == 0 && req_rga->dst.y_offset == 0) && ++ (req_rga->src.yrgb_addr != req_rga->dst.yrgb_addr)) { ++ /* ++ * ABB mode Layer binding: ++ * src => win0 ++ * dst => wr ++ */ ++ ++ /* ++ * enabled by default bot_blend_m1 && bot_alpha_cal_m1 for src channel(win0) ++ * In ABB mode, the number will be fetched according to 16*16, so it needs to ++ * be enabled top_blend_m1 && top_alpha_cal_m1 for dst channel(wr). ++ */ ++ if (rga_is_alpha_format(req_rga->src.format)) ++ req->abb_alpha_pass = true; ++ ++ set_win_info(&req->win0, &req_rga->src); ++ ++ /* enable win0 rotate */ ++ req->win0.rotate_mode = 1; ++ ++ /* set win dst size */ ++ req->win0.dst_act_w = req_rga->dst.act_w; ++ req->win0.dst_act_h = req_rga->dst.act_h; ++ ++ addr_copy(&req->win0, &req_rga->src); ++ addr_copy(&req->wr, &req_rga->dst); ++ ++ req->win0.format = req_rga->src.format; ++ req->wr.format = req_rga->dst.format; ++ } else { ++ /* ++ * ABC mode Layer binding: ++ * src => win1 ++ * src1/dst => win0 ++ * dst => wr ++ */ ++ ++ /* ++ * enabled by default top_blend_m1 && top_alpha_cal_m1 for src channel(win1) ++ * In ABB mode, the number will be fetched according to 16*16, so it needs to ++ * be enabled bot_blend_m1 && bot_alpha_cal_m1 for src1/dst channel(win0). ++ */ ++ if (rga_is_alpha_format(req_rga->src.format)) ++ req->abb_alpha_pass = true; ++ ++ if (req_rga->pat.yrgb_addr != 0) { ++ if (req_rga->src.yrgb_addr == req_rga->dst.yrgb_addr) { ++ /* Convert ABC mode to ABB mode. */ ++ memcpy(&req_rga->src, &req_rga->pat, sizeof(req_rga->src)); ++ memset(&req_rga->pat, 0x0, sizeof(req_rga->pat)); ++ req_rga->bsfilter_flag = 0; ++ ++ rga_swap_pd_mode(req_rga); ++ } else if ((req_rga->dst.x_offset + req_rga->src.act_w > ++ req_rga->pat.act_w) || ++ (req_rga->dst.y_offset + req_rga->src.act_h > ++ req_rga->pat.act_h)) { ++ /* wr_offset + win1.act_size need > win0.act_size */ ++ memcpy(&tmp, &req_rga->src, sizeof(tmp)); ++ memcpy(&req_rga->src, &req_rga->pat, sizeof(req_rga->src)); ++ memcpy(&req_rga->pat, &tmp, sizeof(req_rga->pat)); ++ ++ rga_swap_pd_mode(req_rga); ++ } ++ } ++ ++ set_win_info(&req->win1, &req_rga->src); ++ ++ /* enable win1 rotate */ ++ req->win1.rotate_mode = 1; ++ ++ addr_copy(&req->win1, &req_rga->src); ++ addr_copy(&req->wr, &req_rga->dst); ++ ++ req->win1.format = req_rga->src.format; ++ req->wr.format = req_rga->dst.format; ++ ++ if (req_rga->pat.yrgb_addr != 0) { ++ /* A+B->C mode */ ++ set_win_info(&req->win0, &req_rga->pat); ++ addr_copy(&req->win0, &req_rga->pat); ++ req->win0.format = req_rga->pat.format; ++ ++ /* set win0 dst size */ ++ if (req->win0.x_offset || req->win0.y_offset) { ++ req->win0.src_act_w = req->win0.src_act_w + req->win0.x_offset; ++ req->win0.src_act_h = req->win0.src_act_h + req->win0.y_offset; ++ req->win0.dst_act_w = req_rga->dst.act_w + req->win0.x_offset; ++ req->win0.dst_act_h = req_rga->dst.act_h + req->win0.y_offset; ++ ++ req->win0.x_offset = 0; ++ req->win0.y_offset = 0; ++ } else { ++ req->win0.dst_act_w = req_rga->dst.act_w; ++ req->win0.dst_act_h = req_rga->dst.act_h; ++ } ++ /* set win1 dst size */ ++ req->win1.dst_act_w = req_rga->dst.act_w; ++ req->win1.dst_act_h = req_rga->dst.act_h; ++ } else { ++ /* A+B->B mode */ ++ set_win_info(&req->win0, &req_rga->dst); ++ addr_copy(&req->win0, &req_rga->dst); ++ req->win0.format = req_rga->dst.format; ++ ++ /* only win1 && wr support fbcd, win0 default raster */ ++ req->win0.rd_mode = 0; ++ ++ /* set win0 dst size */ ++ req->win0.dst_act_w = req_rga->dst.act_w; ++ req->win0.dst_act_h = req_rga->dst.act_h; ++ /* set win1 dst size */ ++ req->win1.dst_act_w = req_rga->dst.act_w; ++ req->win1.dst_act_h = req_rga->dst.act_h; ++ } ++ ++ /* dst offset need to config overlap offset */ ++ req->wr.x_offset = req_rga->dst.x_offset; ++ req->wr.y_offset = req_rga->dst.y_offset; ++ } ++ set_wr_info(req_rga, req); ++ ++ if (req->rotate_mode & RGA3_ROT_BIT_ROT_90) { ++ if (req->win1.yrgb_addr != 0) { ++ /* ABB */ ++ if (req->win0.yrgb_addr == req->wr.yrgb_addr) { ++ req->win1.dst_act_w = req_rga->dst.act_h; ++ req->win1.dst_act_h = req_rga->dst.act_w; ++ ++ /* win0 do not need rotate, but net equal to wr */ ++ req->win0.dst_act_w = req_rga->dst.act_h; ++ req->win0.dst_act_h = req_rga->dst.act_w; ++ req->win0.src_act_w = req_rga->dst.act_h; ++ req->win0.src_act_h = req_rga->dst.act_w; ++ } ++ } else { ++ req->win0.rotate_mode = 1; ++ req->win0.dst_act_w = req_rga->dst.act_h; ++ req->win0.dst_act_h = req_rga->dst.act_w; ++ } ++ } ++ ++ /* overlap */ ++ /* Alpha blend mode */ ++ if (((req_rga->alpha_rop_flag) & 1)) { ++ if ((req_rga->alpha_rop_flag >> 3) & 1) { ++ req->alpha_config.enable = true; ++ ++ if ((req_rga->alpha_rop_flag >> 9) & 1) { ++ req->alpha_config.fg_pre_multiplied = false; ++ req->alpha_config.bg_pre_multiplied = false; ++ } else { ++ req->alpha_config.fg_pre_multiplied = true; ++ req->alpha_config.bg_pre_multiplied = true; ++ } ++ ++ req->alpha_config.fg_pixel_alpha_en = rga_is_alpha_format(req->win1.format); ++ req->alpha_config.bg_pixel_alpha_en = rga_is_alpha_format(req->win0.format); ++ ++ if (req_rga->feature.global_alpha_en) { ++ if (req_rga->fg_global_alpha < 0xff) { ++ req->alpha_config.fg_global_alpha_en = true; ++ req->alpha_config.fg_global_alpha_value = ++ req_rga->fg_global_alpha; ++ } else if (!req->alpha_config.fg_pixel_alpha_en) { ++ req->alpha_config.fg_global_alpha_en = true; ++ req->alpha_config.fg_global_alpha_value = 0xff; ++ } ++ ++ if (req_rga->bg_global_alpha < 0xff) { ++ req->alpha_config.bg_global_alpha_en = true; ++ req->alpha_config.bg_global_alpha_value = ++ req_rga->bg_global_alpha; ++ } else if (!req->alpha_config.bg_pixel_alpha_en) { ++ req->alpha_config.bg_global_alpha_en = true; ++ req->alpha_config.bg_global_alpha_value = 0xff; ++ } ++ } else { ++ req->alpha_config.bg_global_alpha_value = 0xff; ++ req->alpha_config.bg_global_alpha_value = 0xff; ++ } ++ ++ req->alpha_config.mode = req_rga->PD_mode; ++ } ++ } ++ ++ /* yuv to rgb */ ++ /* 601 limit */ ++ if (req_rga->yuv2rgb_mode == 1) { ++ req->win0.y2r_mode = 0; ++ req->win1.y2r_mode = 0; ++ /* 601 full */ ++ } else if (req_rga->yuv2rgb_mode == 2) { ++ req->win0.y2r_mode = 2; ++ req->win1.y2r_mode = 2; ++ /* 709 limit */ ++ } else if (req_rga->yuv2rgb_mode == 3) { ++ req->win0.y2r_mode = 1; ++ req->win1.y2r_mode = 1; ++ } ++ ++ /* rgb to yuv */ ++ /* 601 limit */ ++ if ((req_rga->yuv2rgb_mode >> 2) == 2) { ++ req->win0.r2y_mode = 0; ++ req->win1.r2y_mode = 0; ++ /* 601 full */ ++ } else if ((req_rga->yuv2rgb_mode >> 2) == 1) { ++ req->win0.r2y_mode = 2; ++ req->win1.r2y_mode = 2; ++ /* 709 limit */ ++ } else if ((req_rga->yuv2rgb_mode >> 2) == 3) { ++ req->win0.r2y_mode = 1; ++ req->win1.r2y_mode = 1; ++ } ++ ++ /* color key: 8bit->10bit */ ++ req->color_key_min = (req_rga->color_key_min & 0xff) << 22 | ++ ((req_rga->color_key_min >> 8) & 0xff) << 2 | ++ ((req_rga->color_key_min >> 16) & 0xff) << 12; ++ req->color_key_max = (req_rga->color_key_max & 0xff) << 22 | ++ ((req_rga->color_key_max >> 8) & 0xff) << 2 | ++ ((req_rga->color_key_max >> 16) & 0xff) << 12; ++ ++ if (req_rga->mmu_info.mmu_en && (req_rga->mmu_info.mmu_flag & 1) == 1) { ++ req->mmu_info.src0_mmu_flag = 1; ++ req->mmu_info.src1_mmu_flag = 1; ++ req->mmu_info.dst_mmu_flag = 1; ++ } ++} ++ ++static void rga3_soft_reset(struct rga_scheduler_t *scheduler) ++{ ++ u32 i; ++ u32 iommu_dte_addr = 0; ++ ++ if (scheduler->data->mmu == RGA_IOMMU) ++ iommu_dte_addr = rga_read(RGA_IOMMU_DTE_ADDR, scheduler); ++ ++ rga_write(s_RGA3_SYS_CTRL_CCLK_SRESET(1) | s_RGA3_SYS_CTRL_ACLK_SRESET(1), ++ RGA3_SYS_CTRL, scheduler); ++ ++ for (i = 0; i < RGA_RESET_TIMEOUT; i++) { ++ if (rga_read(RGA3_RO_SRST, scheduler) & m_RGA3_RO_SRST_RO_RST_DONE) ++ break; ++ ++ udelay(1); ++ } ++ ++ rga_write(s_RGA3_SYS_CTRL_CCLK_SRESET(0) | s_RGA3_SYS_CTRL_ACLK_SRESET(0), ++ RGA3_SYS_CTRL, scheduler); ++ ++ if (scheduler->data->mmu == RGA_IOMMU) { ++ rga_write(iommu_dte_addr, RGA_IOMMU_DTE_ADDR, scheduler); ++ /* enable iommu */ ++ rga_write(RGA_IOMMU_CMD_ENABLE_PAGING, RGA_IOMMU_COMMAND, scheduler); ++ } ++ ++ if (i == RGA_RESET_TIMEOUT) ++ pr_err("RGA3 core[%d] soft reset timeout. SYS_CTRL[0x%x], RO_SRST[0x%x]\n", ++ scheduler->core, rga_read(RGA3_SYS_CTRL, scheduler), ++ rga_read(RGA3_RO_SRST, scheduler)); ++ else ++ pr_info("RGA3 core[%d] soft reset complete.\n", scheduler->core); ++} ++ ++static int rga3_scale_check(const struct rga3_req *req) ++{ ++ u32 win0_saw, win0_sah, win0_daw, win0_dah; ++ u32 win1_saw, win1_sah, win1_daw, win1_dah; ++ ++ win0_saw = req->win0.src_act_w; ++ win0_sah = req->win0.src_act_h; ++ win0_daw = req->win0.dst_act_w; ++ win0_dah = req->win0.dst_act_h; ++ ++ if (((win0_saw >> 3) > win0_daw) || ((win0_sah >> 3) > win0_dah)) { ++ pr_info("win0 unsupported to scaling less than 1/8 times.\n"); ++ return -EINVAL; ++ } ++ if (((win0_daw >> 3) > win0_saw) || ((win0_dah >> 3) > win0_sah)) { ++ pr_info("win0 unsupported to scaling more than 8 times.\n"); ++ return -EINVAL; ++ } ++ ++ if (req->win1.yrgb_addr != 0) { ++ win1_saw = req->win1.src_act_w; ++ win1_sah = req->win1.src_act_h; ++ win1_daw = req->win1.dst_act_w; ++ win1_dah = req->win1.dst_act_h; ++ ++ if (((win1_saw >> 3) > win1_daw) || ((win1_sah >> 3) > win1_dah)) { ++ pr_info("win1 unsupported to scaling less than 1/8 times.\n"); ++ return -EINVAL; ++ } ++ if (((win1_daw >> 3) > win1_saw) || ((win1_dah >> 3) > win1_sah)) { ++ pr_info("win1 unsupported to scaling more than 8 times.\n"); ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++static int rga3_check_param(const struct rga_hw_data *data, const struct rga3_req *req) ++{ ++ if (unlikely(rga_hw_out_of_range(&(data->input_range), ++ req->win0.src_act_w, req->win0.src_act_h) || ++ rga_hw_out_of_range(&(data->input_range), ++ req->win0.dst_act_w, req->win0.dst_act_h) || ++ rga_hw_out_of_range(&(data->input_range), ++ req->win0.src_act_w + req->win0.x_offset, ++ req->win0.src_act_h + req->win0.y_offset))) { ++ pr_err("invalid win0, src[w,h] = [%d, %d], dst[w,h] = [%d, %d], off[x,y] = [%d,%d]\n", ++ req->win0.src_act_w, req->win0.src_act_h, ++ req->win0.dst_act_w, req->win0.dst_act_h, ++ req->win0.x_offset, req->win0.y_offset); ++ return -EINVAL; ++ } ++ ++ if (unlikely(req->win0.vir_w * rga_get_pixel_stride_from_format(req->win0.format) > ++ data->max_byte_stride * 8)) { ++ pr_err("invalid win0 stride, stride = %d, pixel_stride = %d, max_byte_stride = %d\n", ++ req->win0.vir_w, rga_get_pixel_stride_from_format(req->win0.format), ++ data->max_byte_stride); ++ return -EINVAL; ++ } ++ ++ if (unlikely(rga_hw_out_of_range(&(data->output_range), ++ req->wr.dst_act_w, req->wr.dst_act_h))) { ++ pr_err("invalid wr, [w,h] = [%d, %d]\n", req->wr.dst_act_w, req->wr.dst_act_h); ++ return -EINVAL; ++ } ++ ++ if (unlikely(req->wr.vir_w * rga_get_pixel_stride_from_format(req->wr.format) > ++ data->max_byte_stride * 8)) { ++ pr_err("invalid wr stride, stride = %d, pixel_stride = %d, max_byte_stride = %d\n", ++ req->wr.vir_w, rga_get_pixel_stride_from_format(req->wr.format), ++ data->max_byte_stride); ++ return -EINVAL; ++ } ++ ++ if (req->win1.yrgb_addr != 0) { ++ if (unlikely(rga_hw_out_of_range(&(data->input_range), ++ req->win1.src_act_w, req->win1.src_act_h) || ++ rga_hw_out_of_range(&(data->input_range), ++ req->win1.dst_act_w, req->win1.dst_act_h) || ++ rga_hw_out_of_range(&(data->input_range), ++ req->win1.src_act_w + req->win1.x_offset, ++ req->win1.src_act_h + req->win1.y_offset))) { ++ pr_err("invalid win1, src[w,h] = [%d, %d], dst[w,h] = [%d, %d], off[x,y] = [%d,%d]\n", ++ req->win1.src_act_w, req->win1.src_act_h, ++ req->win1.dst_act_w, req->win1.dst_act_h, ++ req->win1.x_offset, req->win1.y_offset); ++ return -EINVAL; ++ } ++ ++ if (unlikely(req->win1.vir_w * rga_get_pixel_stride_from_format(req->win1.format) > ++ data->max_byte_stride * 8)) { ++ pr_err("invalid win1 stride, stride = %d, pixel_stride = %d, max_byte_stride = %d\n", ++ req->win1.vir_w, rga_get_pixel_stride_from_format(req->win1.format), ++ data->max_byte_stride); ++ return -EINVAL; ++ } ++ ++ /* warning: rotate mode skip this judge */ ++ if (req->rotate_mode == 0) { ++ /* check win0 dst size > win1 dst size */ ++ if (unlikely((req->win1.dst_act_w > req->win0.dst_act_w) || ++ (req->win1.dst_act_h > req->win0.dst_act_h))) { ++ pr_err("invalid output param win0[w,h] = [%d, %d], win1[w,h] = [%d, %d]\n", ++ req->win0.dst_act_w, req->win0.dst_act_h, ++ req->win1.dst_act_w, req->win1.dst_act_h); ++ return -EINVAL; ++ } ++ } ++ } ++ ++ if (rga3_scale_check(req) < 0) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static void print_debug_info(struct rga3_req *req) ++{ ++ pr_info("render_mode:%s, bitblit_mode=%d, rotate_mode:%x\n", ++ rga_get_render_mode_str(req->render_mode), req->bitblt_mode, ++ req->rotate_mode); ++ pr_info("win0: y = %lx uv = %lx v = %lx src_w = %d src_h = %d\n", ++ req->win0.yrgb_addr, req->win0.uv_addr, req->win0.v_addr, ++ req->win0.src_act_w, req->win0.src_act_h); ++ pr_info("win0: vw = %d vh = %d xoff = %d yoff = %d format = %s\n", ++ req->win0.vir_w, req->win0.vir_h, ++ req->win0.x_offset, req->win0.y_offset, ++ rga_get_format_name(req->win0.format)); ++ pr_info("win0: dst_w = %d, dst_h = %d, rd_mode = %d\n", ++ req->win0.dst_act_w, req->win0.dst_act_h, req->win0.rd_mode); ++ pr_info("win0: rot_mode = %d, en = %d, compact = %d, endian = %d\n", ++ req->win0.rotate_mode, req->win0.enable, ++ req->win0.is_10b_compact, req->win0.is_10b_endian); ++ ++ if (req->win1.yrgb_addr != 0 || req->win1.uv_addr != 0 ++ || req->win1.v_addr != 0) { ++ pr_info("win1: y = %lx uv = %lx v = %lx src_w = %d src_h = %d\n", ++ req->win1.yrgb_addr, req->win1.uv_addr, ++ req->win1.v_addr, req->win1.src_act_w, ++ req->win1.src_act_h); ++ pr_info("win1: vw = %d vh = %d xoff = %d yoff = %d format = %s\n", ++ req->win1.vir_w, req->win1.vir_h, ++ req->win1.x_offset, req->win1.y_offset, ++ rga_get_format_name(req->win1.format)); ++ pr_info("win1: dst_w = %d, dst_h = %d, rd_mode = %d\n", ++ req->win1.dst_act_w, req->win1.dst_act_h, ++ req->win1.rd_mode); ++ pr_info("win1: rot_mode = %d, en = %d, compact = %d, endian = %d\n", ++ req->win1.rotate_mode, req->win1.enable, ++ req->win1.is_10b_compact, req->win1.is_10b_endian); ++ } ++ ++ pr_info("wr: y = %lx uv = %lx v = %lx vw = %d vh = %d\n", ++ req->wr.yrgb_addr, req->wr.uv_addr, req->wr.v_addr, ++ req->wr.vir_w, req->wr.vir_h); ++ pr_info("wr: ovlp_xoff = %d ovlp_yoff = %d format = %s rdmode = %d\n", ++ req->wr.x_offset, req->wr.y_offset, ++ rga_get_format_name(req->wr.format), req->wr.rd_mode); ++ ++ pr_info("mmu: win0 = %.2x win1 = %.2x wr = %.2x\n", ++ req->mmu_info.src0_mmu_flag, req->mmu_info.src1_mmu_flag, ++ req->mmu_info.dst_mmu_flag); ++ pr_info("alpha: flag %x mode=%s\n", ++ req->alpha_rop_flag, rga_get_blend_mode_str(req->alpha_config.mode)); ++ pr_info("alpha: pre_multi=[%d,%d] pixl=[%d,%d] glb=[%d,%d]\n", ++ req->alpha_config.fg_pre_multiplied, req->alpha_config.bg_pre_multiplied, ++ req->alpha_config.fg_pixel_alpha_en, req->alpha_config.bg_pixel_alpha_en, ++ req->alpha_config.fg_global_alpha_en, req->alpha_config.bg_global_alpha_en); ++ pr_info("alpha: fg_global_alpha=%x bg_global_alpha=%x\n", ++ req->alpha_config.fg_global_alpha_value, req->alpha_config.bg_global_alpha_value); ++ pr_info("yuv2rgb mode is %x\n", req->yuv2rgb_mode); ++} ++ ++static int rga3_align_check(struct rga3_req *req) ++{ ++ if (rga_is_yuv10bit_format(req->win0.format)) ++ if ((req->win0.vir_w % 64) || (req->win0.x_offset % 4) || ++ (req->win0.src_act_w % 4) || (req->win0.y_offset % 4) || ++ (req->win0.src_act_h % 4) || (req->win0.vir_h % 2)) ++ pr_info("yuv10bit err win0 wstride is not align\n"); ++ if (rga_is_yuv10bit_format(req->win1.format)) ++ if ((req->win1.vir_w % 64) || (req->win1.x_offset % 4) || ++ (req->win1.src_act_w % 4) || (req->win1.y_offset % 4) || ++ (req->win1.src_act_h % 4) || (req->win1.vir_h % 2)) ++ pr_info("yuv10bit err win1 wstride is not align\n"); ++ if (rga_is_yuv8bit_format(req->win0.format)) ++ if ((req->win0.vir_w % 16) || (req->win0.x_offset % 2) || ++ (req->win0.src_act_w % 2) || (req->win0.y_offset % 2) || ++ (req->win0.src_act_h % 2) || (req->win0.vir_h % 2)) ++ pr_info("yuv8bit err win0 wstride is not align\n"); ++ if (rga_is_yuv8bit_format(req->win1.format)) ++ if ((req->win1.vir_w % 16) || (req->win1.x_offset % 2) || ++ (req->win1.src_act_w % 2) || (req->win1.y_offset % 2) || ++ (req->win1.src_act_h % 2) || (req->win1.vir_h % 2)) ++ pr_info("yuv8bit err win1 wstride is not align\n"); ++ return 0; ++} ++ ++static int rga3_init_reg(struct rga_job *job) ++{ ++ struct rga3_req req; ++ int ret = 0; ++ struct rga_scheduler_t *scheduler = NULL; ++ ktime_t timestamp = ktime_get(); ++ ++ scheduler = job->scheduler; ++ if (unlikely(scheduler == NULL)) { ++ pr_err("failed to get scheduler, %s(%d)\n", __func__, __LINE__); ++ return -EINVAL; ++ } ++ ++ memset(&req, 0x0, sizeof(req)); ++ ++ rga_cmd_to_rga3_cmd(&job->rga_command_base, &req); ++ ++ /* check value if legal */ ++ ret = rga3_check_param(scheduler->data, &req); ++ if (ret == -EINVAL) { ++ pr_err("req argument is inval\n"); ++ return ret; ++ } ++ ++ rga3_align_check(&req); ++ ++ /* for debug */ ++ if (DEBUGGER_EN(MSG)) ++ print_debug_info(&req); ++ ++ if (rga3_gen_reg_info((uint8_t *) job->cmd_reg, &req) == -1) { ++ pr_err("RKA: gen reg info error\n"); ++ return -EINVAL; ++ } ++ ++ if (DEBUGGER_EN(TIME)) ++ pr_info("request[%d], generate register cost time %lld us\n", ++ job->request_id, ktime_us_delta(ktime_get(), timestamp)); ++ ++ return ret; ++} ++ ++static void rga3_dump_read_back_reg(struct rga_scheduler_t *scheduler) ++{ ++ int i; ++ unsigned long flags; ++ uint32_t cmd_reg[48] = {0}; ++ ++ spin_lock_irqsave(&scheduler->irq_lock, flags); ++ ++ for (i = 0; i < 48; i++) ++ cmd_reg[i] = rga_read(0x100 + i * 4, scheduler); ++ ++ spin_unlock_irqrestore(&scheduler->irq_lock, flags); ++ ++ pr_info("CMD_READ_BACK_REG\n"); ++ for (i = 0; i < 12; i++) ++ pr_info("i = %x : %.8x %.8x %.8x %.8x\n", i, ++ cmd_reg[0 + i * 4], cmd_reg[1 + i * 4], ++ cmd_reg[2 + i * 4], cmd_reg[3 + i * 4]); ++} ++ ++static int rga3_set_reg(struct rga_job *job, struct rga_scheduler_t *scheduler) ++{ ++ int i; ++ bool master_mode_en; ++ uint32_t sys_ctrl; ++ ktime_t now = ktime_get(); ++ ++ /* ++ * Currently there is no iova allocated for storing cmd for the IOMMU device, ++ * so the iommu device needs to use the slave mode. ++ */ ++ if (scheduler->data->mmu != RGA_IOMMU) ++ master_mode_en = true; ++ else ++ master_mode_en = false; ++ ++ if (DEBUGGER_EN(REG)) { ++ uint32_t *p; ++ ++ p = job->cmd_reg; ++ pr_info("CMD_REG\n"); ++ for (i = 0; i < 12; i++) ++ pr_info("i = %x : %.8x %.8x %.8x %.8x\n", i, ++ p[0 + i * 4], p[1 + i * 4], ++ p[2 + i * 4], p[3 + i * 4]); ++ } ++ ++ /* All CMD finish int */ ++ rga_write(m_RGA3_INT_FRM_DONE | m_RGA3_INT_CMD_LINE_FINISH | m_RGA3_INT_ERROR_MASK, ++ RGA3_INT_EN, scheduler); ++ ++ if (master_mode_en) { ++ /* master mode */ ++ sys_ctrl = s_RGA3_SYS_CTRL_CMD_MODE(1); ++ ++ /* cmd buffer flush cache to ddr */ ++ rga_dma_sync_flush_range(&job->cmd_reg[0], &job->cmd_reg[50], scheduler); ++ ++ rga_write(virt_to_phys(job->cmd_reg), RGA3_CMD_ADDR, scheduler); ++ rga_write(sys_ctrl, RGA3_SYS_CTRL, scheduler); ++ rga_write(m_RGA3_CMD_CTRL_CMD_LINE_ST_P, RGA3_CMD_CTRL, scheduler); ++ } else { ++ /* slave mode */ ++ sys_ctrl = s_RGA3_SYS_CTRL_CMD_MODE(0) | m_RGA3_SYS_CTRL_RGA_SART; ++ ++ for (i = 0; i <= 50; i++) ++ rga_write(job->cmd_reg[i], 0x100 + i * 4, scheduler); ++ ++ rga_write(sys_ctrl, RGA3_SYS_CTRL, scheduler); ++ } ++ ++ if (DEBUGGER_EN(REG)) { ++ pr_info("sys_ctrl = 0x%x, int_en = 0x%x, int_raw = 0x%x\n", ++ rga_read(RGA3_SYS_CTRL, scheduler), ++ rga_read(RGA3_INT_EN, scheduler), ++ rga_read(RGA3_INT_RAW, scheduler)); ++ ++ pr_info("hw_status = 0x%x, cmd_status = 0x%x\n", ++ rga_read(RGA3_STATUS0, scheduler), ++ rga_read(RGA3_CMD_STATE, scheduler)); ++ } ++ ++ if (DEBUGGER_EN(TIME)) ++ pr_info("request[%d], set register cost time %lld us\n", ++ job->request_id, ktime_us_delta(now, job->timestamp)); ++ ++ job->hw_running_time = now; ++ job->hw_recoder_time = now; ++ ++ if (DEBUGGER_EN(REG)) ++ rga3_dump_read_back_reg(scheduler); ++ ++ return 0; ++} ++ ++static int rga3_get_version(struct rga_scheduler_t *scheduler) ++{ ++ u32 major_version, minor_version, svn_version; ++ u32 reg_version; ++ ++ if (!scheduler) { ++ pr_err("scheduler is null\n"); ++ return -EINVAL; ++ } ++ ++ reg_version = rga_read(RGA3_VERSION_NUM, scheduler); ++ ++ major_version = (reg_version & RGA3_MAJOR_VERSION_MASK) >> 28; ++ minor_version = (reg_version & RGA3_MINOR_VERSION_MASK) >> 20; ++ svn_version = (reg_version & RGA3_SVN_VERSION_MASK); ++ ++ snprintf(scheduler->version.str, 10, "%x.%01x.%05x", major_version, ++ minor_version, svn_version); ++ ++ scheduler->version.major = major_version; ++ scheduler->version.minor = minor_version; ++ scheduler->version.revision = svn_version; ++ ++ return 0; ++} ++ ++static int rga3_irq(struct rga_scheduler_t *scheduler) ++{ ++ struct rga_job *job = scheduler->running_job; ++ ++ if (job == NULL) ++ return IRQ_HANDLED; ++ ++ if (test_bit(RGA_JOB_STATE_INTR_ERR, &job->state)) ++ return IRQ_WAKE_THREAD; ++ ++ job->intr_status = rga_read(RGA3_INT_RAW, scheduler); ++ job->hw_status = rga_read(RGA3_STATUS0, scheduler); ++ job->cmd_status = rga_read(RGA3_CMD_STATE, scheduler); ++ ++ if (DEBUGGER_EN(INT_FLAG)) ++ pr_info("irq handler, INTR[0x%x], HW_STATUS[0x%x], CMD_STATUS[0x%x]\n", ++ job->intr_status, job->hw_status, job->cmd_status); ++ ++ if (job->intr_status & (m_RGA3_INT_FRM_DONE | m_RGA3_INT_CMD_LINE_FINISH)) { ++ set_bit(RGA_JOB_STATE_FINISH, &job->state); ++ } else if (job->intr_status & m_RGA3_INT_ERROR_MASK) { ++ set_bit(RGA_JOB_STATE_INTR_ERR, &job->state); ++ ++ pr_err("irq handler err! INTR[0x%x], HW_STATUS[0x%x], CMD_STATUS[0x%x]\n", ++ job->intr_status, job->hw_status, job->cmd_status); ++ scheduler->ops->soft_reset(scheduler); ++ } ++ ++ /*clear INTR */ ++ rga_write(m_RGA3_INT_FRM_DONE | m_RGA3_INT_CMD_LINE_FINISH | m_RGA3_INT_ERROR_MASK, ++ RGA3_INT_CLR, scheduler); ++ ++ return IRQ_WAKE_THREAD; ++} ++ ++static int rga3_isr_thread(struct rga_job *job, struct rga_scheduler_t *scheduler) ++{ ++ if (DEBUGGER_EN(INT_FLAG)) ++ pr_info("isr thread, INTR[0x%x], HW_STATUS[0x%x], CMD_STATUS[0x%x]\n", ++ rga_read(RGA3_INT_RAW, scheduler), ++ rga_read(RGA3_STATUS0, scheduler), ++ rga_read(RGA3_CMD_STATE, scheduler)); ++ ++ if (test_bit(RGA_JOB_STATE_INTR_ERR, &job->state)) { ++ if (job->intr_status & m_RGA3_INT_RAG_MI_RD_BUS_ERR) { ++ pr_err("DMA read bus error, please check size of the input_buffer or whether the buffer has been freed.\n"); ++ job->ret = -EFAULT; ++ } else if (job->intr_status & m_RGA3_INT_WIN0_FBCD_DEC_ERR) { ++ pr_err("win0 FBC decoder error, please check the fbc image of the source.\n"); ++ job->ret = -EFAULT; ++ } else if (job->intr_status & m_RGA3_INT_WIN1_FBCD_DEC_ERR) { ++ pr_err("win1 FBC decoder error, please check the fbc image of the source.\n"); ++ job->ret = -EFAULT; ++ } else if (job->intr_status & m_RGA3_INT_RGA_MI_WR_BUS_ERR) { ++ pr_err("wr buss error, please check size of the output_buffer or whether the buffer has been freed.\n"); ++ job->ret = -EFAULT; ++ } ++ ++ if (job->ret == 0) { ++ pr_err("rga intr error[0x%x]!\n", job->intr_status); ++ job->ret = -EFAULT; ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++const struct rga_backend_ops rga3_ops = { ++ .get_version = rga3_get_version, ++ .set_reg = rga3_set_reg, ++ .init_reg = rga3_init_reg, ++ .soft_reset = rga3_soft_reset, ++ .read_back_reg = NULL, ++ .irq = rga3_irq, ++ .isr_thread = rga3_isr_thread, ++}; +diff --git a/drivers/video/rockchip/rga3/rga_common.c b/drivers/video/rockchip/rga3/rga_common.c +new file mode 100644 +index 000000000..80d4821fb +--- /dev/null ++++ b/drivers/video/rockchip/rga3/rga_common.c +@@ -0,0 +1,772 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) Rockchip Electronics Co., Ltd. ++ * ++ * Author: Cerf Yu ++ */ ++ ++#define pr_fmt(fmt) "rga_common: " fmt ++ ++#include "rga.h" ++#include "rga_common.h" ++ ++bool rga_is_rgb_format(uint32_t format) ++{ ++ switch (format) { ++ case RGA_FORMAT_RGBA_8888: ++ case RGA_FORMAT_RGBX_8888: ++ case RGA_FORMAT_RGB_888: ++ case RGA_FORMAT_BGRA_8888: ++ case RGA_FORMAT_BGRX_8888: ++ case RGA_FORMAT_BGR_888: ++ case RGA_FORMAT_RGB_565: ++ case RGA_FORMAT_RGBA_5551: ++ case RGA_FORMAT_RGBA_4444: ++ case RGA_FORMAT_BGR_565: ++ case RGA_FORMAT_BGRA_5551: ++ case RGA_FORMAT_BGRA_4444: ++ case RGA_FORMAT_ARGB_8888: ++ case RGA_FORMAT_XRGB_8888: ++ case RGA_FORMAT_ARGB_5551: ++ case RGA_FORMAT_ARGB_4444: ++ case RGA_FORMAT_ABGR_8888: ++ case RGA_FORMAT_XBGR_8888: ++ case RGA_FORMAT_ABGR_5551: ++ case RGA_FORMAT_ABGR_4444: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++bool rga_is_yuv_format(uint32_t format) ++{ ++ switch (format) { ++ case RGA_FORMAT_Y4: ++ case RGA_FORMAT_YCbCr_400: ++ ++ case RGA_FORMAT_YCbCr_422_SP: ++ case RGA_FORMAT_YCbCr_422_P: ++ case RGA_FORMAT_YCbCr_420_SP: ++ case RGA_FORMAT_YCbCr_420_P: ++ case RGA_FORMAT_YCrCb_422_SP: ++ case RGA_FORMAT_YCrCb_422_P: ++ case RGA_FORMAT_YCrCb_420_SP: ++ case RGA_FORMAT_YCrCb_420_P: ++ ++ case RGA_FORMAT_YVYU_422: ++ case RGA_FORMAT_YVYU_420: ++ case RGA_FORMAT_VYUY_422: ++ case RGA_FORMAT_VYUY_420: ++ case RGA_FORMAT_YUYV_422: ++ case RGA_FORMAT_YUYV_420: ++ case RGA_FORMAT_UYVY_422: ++ case RGA_FORMAT_UYVY_420: ++ ++ case RGA_FORMAT_YCbCr_420_SP_10B: ++ case RGA_FORMAT_YCrCb_420_SP_10B: ++ case RGA_FORMAT_YCbCr_422_SP_10B: ++ case RGA_FORMAT_YCrCb_422_SP_10B: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++bool rga_is_alpha_format(uint32_t format) ++{ ++ switch (format) { ++ case RGA_FORMAT_RGBA_8888: ++ case RGA_FORMAT_BGRA_8888: ++ case RGA_FORMAT_RGBA_5551: ++ case RGA_FORMAT_RGBA_4444: ++ case RGA_FORMAT_BGRA_5551: ++ case RGA_FORMAT_BGRA_4444: ++ case RGA_FORMAT_ARGB_8888: ++ case RGA_FORMAT_ARGB_5551: ++ case RGA_FORMAT_ARGB_4444: ++ case RGA_FORMAT_ABGR_8888: ++ case RGA_FORMAT_ABGR_5551: ++ case RGA_FORMAT_ABGR_4444: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++bool rga_is_yuv420_packed_format(uint32_t format) ++{ ++ switch (format) { ++ case RGA_FORMAT_YVYU_420: ++ case RGA_FORMAT_VYUY_420: ++ case RGA_FORMAT_YUYV_420: ++ case RGA_FORMAT_UYVY_420: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++bool rga_is_yuv420_planar_format(uint32_t format) ++{ ++ switch (format) { ++ case RGA_FORMAT_YCbCr_420_P: ++ case RGA_FORMAT_YCrCb_420_P: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++bool rga_is_yuv420_semi_planar_format(uint32_t format) ++{ ++ switch (format) { ++ case RGA_FORMAT_YCbCr_420_SP: ++ case RGA_FORMAT_YCrCb_420_SP: ++ case RGA_FORMAT_YCbCr_420_SP_10B: ++ case RGA_FORMAT_YCrCb_420_SP_10B: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++bool rga_is_yuv422_packed_format(uint32_t format) ++{ ++ switch (format) { ++ case RGA_FORMAT_YVYU_422: ++ case RGA_FORMAT_VYUY_422: ++ case RGA_FORMAT_YUYV_422: ++ case RGA_FORMAT_UYVY_422: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++bool rga_is_yuv422_planar_format(uint32_t format) ++{ ++ switch (format) { ++ case RGA_FORMAT_YCbCr_422_P: ++ case RGA_FORMAT_YCrCb_422_P: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++bool rga_is_yuv422_semi_planar_format(uint32_t format) ++{ ++ switch (format) { ++ case RGA_FORMAT_YCbCr_422_SP: ++ case RGA_FORMAT_YCrCb_422_SP: ++ case RGA_FORMAT_YCbCr_422_SP_10B: ++ case RGA_FORMAT_YCrCb_422_SP_10B: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++bool rga_is_yuv8bit_format(uint32_t format) ++{ ++ switch (format) { ++ case RGA_FORMAT_Y4: ++ case RGA_FORMAT_YCbCr_400: ++ ++ case RGA_FORMAT_YCbCr_422_SP: ++ case RGA_FORMAT_YCbCr_422_P: ++ case RGA_FORMAT_YCbCr_420_SP: ++ case RGA_FORMAT_YCbCr_420_P: ++ case RGA_FORMAT_YCrCb_422_SP: ++ case RGA_FORMAT_YCrCb_422_P: ++ case RGA_FORMAT_YCrCb_420_SP: ++ case RGA_FORMAT_YCrCb_420_P: ++ ++ case RGA_FORMAT_YVYU_422: ++ case RGA_FORMAT_YVYU_420: ++ case RGA_FORMAT_VYUY_422: ++ case RGA_FORMAT_VYUY_420: ++ case RGA_FORMAT_YUYV_422: ++ case RGA_FORMAT_YUYV_420: ++ case RGA_FORMAT_UYVY_422: ++ case RGA_FORMAT_UYVY_420: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++bool rga_is_yuv10bit_format(uint32_t format) ++{ ++ switch (format) { ++ case RGA_FORMAT_YCbCr_420_SP_10B: ++ case RGA_FORMAT_YCrCb_420_SP_10B: ++ case RGA_FORMAT_YCbCr_422_SP_10B: ++ case RGA_FORMAT_YCrCb_422_SP_10B: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++bool rga_is_yuv422p_format(uint32_t format) ++{ ++ switch (format) { ++ case RGA_FORMAT_YCbCr_422_P: ++ case RGA_FORMAT_YCrCb_422_P: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++bool rga_is_only_y_format(uint32_t format) ++{ ++ switch (format) { ++ case RGA_FORMAT_YCbCr_400: ++ case RGA_FORMAT_Y4: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++const char *rga_get_format_name(uint32_t format) ++{ ++ switch (format) { ++ case RGA_FORMAT_RGBA_8888: ++ return "RGBA8888"; ++ case RGA_FORMAT_RGBX_8888: ++ return "RGBX8888"; ++ case RGA_FORMAT_RGB_888: ++ return "RGB888"; ++ case RGA_FORMAT_BGRA_8888: ++ return "BGRA8888"; ++ case RGA_FORMAT_BGRX_8888: ++ return "BGRX8888"; ++ case RGA_FORMAT_BGR_888: ++ return "BGR888"; ++ case RGA_FORMAT_RGB_565: ++ return "RGB565"; ++ case RGA_FORMAT_RGBA_5551: ++ return "RGBA5551"; ++ case RGA_FORMAT_RGBA_4444: ++ return "RGBA4444"; ++ case RGA_FORMAT_BGR_565: ++ return "BGR565"; ++ case RGA_FORMAT_BGRA_5551: ++ return "BGRA5551"; ++ case RGA_FORMAT_BGRA_4444: ++ return "BGRA4444"; ++ ++ case RGA_FORMAT_YCbCr_422_SP: ++ return "YCbCr422SP"; ++ case RGA_FORMAT_YCbCr_422_P: ++ return "YCbCr422P"; ++ case RGA_FORMAT_YCbCr_420_SP: ++ return "YCbCr420SP"; ++ case RGA_FORMAT_YCbCr_420_P: ++ return "YCbCr420P"; ++ case RGA_FORMAT_YCrCb_422_SP: ++ return "YCrCb422SP"; ++ case RGA_FORMAT_YCrCb_422_P: ++ return "YCrCb422P"; ++ case RGA_FORMAT_YCrCb_420_SP: ++ return "YCrCb420SP"; ++ case RGA_FORMAT_YCrCb_420_P: ++ return "YCrCb420P"; ++ ++ case RGA_FORMAT_YVYU_422: ++ return "YVYU422"; ++ case RGA_FORMAT_YVYU_420: ++ return "YVYU420"; ++ case RGA_FORMAT_VYUY_422: ++ return "VYUY422"; ++ case RGA_FORMAT_VYUY_420: ++ return "VYUY420"; ++ case RGA_FORMAT_YUYV_422: ++ return "YUYV422"; ++ case RGA_FORMAT_YUYV_420: ++ return "YUYV420"; ++ case RGA_FORMAT_UYVY_422: ++ return "UYVY422"; ++ case RGA_FORMAT_UYVY_420: ++ return "UYVY420"; ++ ++ case RGA_FORMAT_YCbCr_420_SP_10B: ++ return "YCrCb420SP10B"; ++ case RGA_FORMAT_YCrCb_420_SP_10B: ++ return "YCbCr420SP10B"; ++ case RGA_FORMAT_YCbCr_422_SP_10B: ++ return "YCbCr422SP10B"; ++ case RGA_FORMAT_YCrCb_422_SP_10B: ++ return "YCrCb422SP10B"; ++ case RGA_FORMAT_BPP1: ++ return "BPP1"; ++ case RGA_FORMAT_BPP2: ++ return "BPP2"; ++ case RGA_FORMAT_BPP4: ++ return "BPP4"; ++ case RGA_FORMAT_BPP8: ++ return "BPP8"; ++ case RGA_FORMAT_YCbCr_400: ++ return "YCbCr400"; ++ case RGA_FORMAT_Y4: ++ return "y4"; ++ ++ case RGA_FORMAT_ARGB_8888: ++ return "ARGB8888"; ++ case RGA_FORMAT_XRGB_8888: ++ return "XRGB8888"; ++ case RGA_FORMAT_ARGB_5551: ++ return "ARGB5551"; ++ case RGA_FORMAT_ARGB_4444: ++ return "ARGB4444"; ++ case RGA_FORMAT_ABGR_8888: ++ return "ABGR8888"; ++ case RGA_FORMAT_XBGR_8888: ++ return "XBGR8888"; ++ case RGA_FORMAT_ABGR_5551: ++ return "ABGR5551"; ++ case RGA_FORMAT_ABGR_4444: ++ return "ABGR4444"; ++ ++ case RGA_FORMAT_RGBA_2BPP: ++ return "RGBA2BPP"; ++ ++ default: ++ return "UNF"; ++ } ++} ++ ++int rga_get_format_bits(uint32_t format) ++{ ++ int bits = 0; ++ ++ switch (format) { ++ case RGA_FORMAT_RGBA_8888: ++ case RGA_FORMAT_RGBX_8888: ++ case RGA_FORMAT_BGRA_8888: ++ case RGA_FORMAT_BGRX_8888: ++ case RGA_FORMAT_ARGB_8888: ++ case RGA_FORMAT_XRGB_8888: ++ case RGA_FORMAT_ABGR_8888: ++ case RGA_FORMAT_XBGR_8888: ++ bits = 32; ++ break; ++ case RGA_FORMAT_RGB_888: ++ case RGA_FORMAT_BGR_888: ++ bits = 24; ++ break; ++ case RGA_FORMAT_RGB_565: ++ case RGA_FORMAT_RGBA_5551: ++ case RGA_FORMAT_RGBA_4444: ++ case RGA_FORMAT_BGR_565: ++ case RGA_FORMAT_BGRA_5551: ++ case RGA_FORMAT_BGRA_4444: ++ case RGA_FORMAT_ARGB_5551: ++ case RGA_FORMAT_ARGB_4444: ++ case RGA_FORMAT_ABGR_5551: ++ case RGA_FORMAT_ABGR_4444: ++ case RGA_FORMAT_YCbCr_422_SP: ++ case RGA_FORMAT_YCbCr_422_P: ++ case RGA_FORMAT_YCrCb_422_SP: ++ case RGA_FORMAT_YCrCb_422_P: ++ case RGA_FORMAT_YUYV_422: ++ case RGA_FORMAT_YVYU_422: ++ case RGA_FORMAT_UYVY_422: ++ case RGA_FORMAT_VYUY_422: ++ /* YUV 420 packed according to the arrangement of YUV422 packed. */ ++ case RGA_FORMAT_YUYV_420: ++ case RGA_FORMAT_YVYU_420: ++ case RGA_FORMAT_UYVY_420: ++ case RGA_FORMAT_VYUY_420: ++ bits = 16; ++ break; ++ case RGA_FORMAT_YCbCr_420_SP: ++ case RGA_FORMAT_YCbCr_420_P: ++ case RGA_FORMAT_YCrCb_420_SP: ++ case RGA_FORMAT_YCrCb_420_P: ++ bits = 12; ++ break; ++ case RGA_FORMAT_YCbCr_420_SP_10B: ++ case RGA_FORMAT_YCrCb_420_SP_10B: ++ case RGA_FORMAT_YCbCr_422_SP_10B: ++ case RGA_FORMAT_YCrCb_422_SP_10B: ++ bits = 15; ++ break; ++ case RGA_FORMAT_YCbCr_400: ++ case RGA_FORMAT_BPP8: ++ bits = 8; ++ break; ++ case RGA_FORMAT_Y4: ++ case RGA_FORMAT_BPP4: ++ bits = 4; ++ break; ++ case RGA_FORMAT_BPP2: ++ bits = 2; ++ break; ++ case RGA_FORMAT_BPP1: ++ bits = 1; ++ break; ++ default: ++ pr_err("unknown format [0x%x]\n", format); ++ return -1; ++ } ++ ++ return bits; ++} ++ ++int rga_get_pixel_stride_from_format(uint32_t format) ++{ ++ int pixel_stride = 0; ++ ++ switch (format) { ++ case RGA_FORMAT_RGBA_8888: ++ case RGA_FORMAT_RGBX_8888: ++ case RGA_FORMAT_BGRA_8888: ++ case RGA_FORMAT_BGRX_8888: ++ case RGA_FORMAT_ARGB_8888: ++ case RGA_FORMAT_XRGB_8888: ++ case RGA_FORMAT_ABGR_8888: ++ case RGA_FORMAT_XBGR_8888: ++ pixel_stride = 32; ++ break; ++ case RGA_FORMAT_RGB_888: ++ case RGA_FORMAT_BGR_888: ++ pixel_stride = 24; ++ break; ++ case RGA_FORMAT_RGB_565: ++ case RGA_FORMAT_RGBA_5551: ++ case RGA_FORMAT_RGBA_4444: ++ case RGA_FORMAT_BGR_565: ++ case RGA_FORMAT_BGRA_5551: ++ case RGA_FORMAT_BGRA_4444: ++ case RGA_FORMAT_ARGB_5551: ++ case RGA_FORMAT_ARGB_4444: ++ case RGA_FORMAT_ABGR_5551: ++ case RGA_FORMAT_ABGR_4444: ++ case RGA_FORMAT_YVYU_422: ++ case RGA_FORMAT_YVYU_420: ++ case RGA_FORMAT_VYUY_422: ++ case RGA_FORMAT_VYUY_420: ++ case RGA_FORMAT_YUYV_422: ++ case RGA_FORMAT_YUYV_420: ++ case RGA_FORMAT_UYVY_422: ++ case RGA_FORMAT_UYVY_420: ++ pixel_stride = 16; ++ break; ++ case RGA_FORMAT_YCbCr_420_SP_10B: ++ case RGA_FORMAT_YCrCb_420_SP_10B: ++ case RGA_FORMAT_YCbCr_422_SP_10B: ++ case RGA_FORMAT_YCrCb_422_SP_10B: ++ pixel_stride = 10; ++ break; ++ case RGA_FORMAT_BPP1: ++ case RGA_FORMAT_BPP2: ++ case RGA_FORMAT_BPP4: ++ case RGA_FORMAT_BPP8: ++ case RGA_FORMAT_YCbCr_400: ++ case RGA_FORMAT_YCbCr_420_SP: ++ case RGA_FORMAT_YCbCr_420_P: ++ case RGA_FORMAT_YCrCb_420_SP: ++ case RGA_FORMAT_YCrCb_420_P: ++ case RGA_FORMAT_YCbCr_422_SP: ++ case RGA_FORMAT_YCbCr_422_P: ++ case RGA_FORMAT_YCrCb_422_SP: ++ case RGA_FORMAT_YCrCb_422_P: ++ pixel_stride = 8; ++ break; ++ case RGA_FORMAT_Y4: ++ pixel_stride = 4; ++ break; ++ default: ++ pr_err("unknown format [0x%x]\n", format); ++ return -1; ++ } ++ ++ return pixel_stride; ++} ++ ++const char *rga_get_render_mode_str(uint8_t mode) ++{ ++ switch (mode) { ++ case 0x0: ++ return "bitblt"; ++ case 0x1: ++ return "RGA_COLOR_PALETTE"; ++ case 0x2: ++ return "RGA_COLOR_FILL"; ++ case 0x3: ++ return "update_palette_table"; ++ case 0x4: ++ return "update_patten_buff"; ++ default: ++ return "UNF"; ++ } ++} ++ ++const char *rga_get_rotate_mode_str(uint8_t mode) ++{ ++ switch (mode) { ++ case 0x0: ++ return "0"; ++ case 0x1: ++ return "90 degree"; ++ case 0x2: ++ return "180 degree"; ++ case 0x3: ++ return "270 degree"; ++ case 0x10: ++ return "xmirror"; ++ case 0x20: ++ return "ymirror"; ++ case 0x30: ++ return "xymirror"; ++ default: ++ return "UNF"; ++ } ++} ++ ++const char *rga_get_blend_mode_str(enum rga_alpha_blend_mode mode) ++{ ++ switch (mode) { ++ case RGA_ALPHA_NONE: ++ return "no blend"; ++ ++ case RGA_ALPHA_BLEND_SRC: ++ return "src"; ++ ++ case RGA_ALPHA_BLEND_DST: ++ return "dst"; ++ ++ case RGA_ALPHA_BLEND_SRC_OVER: ++ return "src-over"; ++ ++ case RGA_ALPHA_BLEND_DST_OVER: ++ return "dst-over"; ++ ++ case RGA_ALPHA_BLEND_SRC_IN: ++ return "src-in"; ++ ++ case RGA_ALPHA_BLEND_DST_IN: ++ return "dst-in"; ++ ++ case RGA_ALPHA_BLEND_SRC_OUT: ++ return "src-out"; ++ ++ case RGA_ALPHA_BLEND_DST_OUT: ++ return "dst-out"; ++ ++ case RGA_ALPHA_BLEND_SRC_ATOP: ++ return "src-atop"; ++ ++ case RGA_ALPHA_BLEND_DST_ATOP: ++ return "dst-atop"; ++ ++ case RGA_ALPHA_BLEND_XOR: ++ return "xor"; ++ ++ case RGA_ALPHA_BLEND_CLEAR: ++ return "clear"; ++ ++ default: ++ return "check reg for more imformation"; ++ } ++} ++ ++const char *rga_get_memory_type_str(uint8_t type) ++{ ++ switch (type) { ++ case RGA_DMA_BUFFER: ++ return "dma_fd"; ++ case RGA_VIRTUAL_ADDRESS: ++ return "virt_addr"; ++ case RGA_PHYSICAL_ADDRESS: ++ return "phys_addr"; ++ case RGA_DMA_BUFFER_PTR: ++ return "dma_buf_ptr"; ++ default: ++ return "UNF"; ++ } ++} ++ ++const char *rga_get_mmu_type_str(enum rga_mmu mmu_type) ++{ ++ switch (mmu_type) { ++ case RGA_MMU: ++ return "RGA_MMU"; ++ case RGA_IOMMU: ++ return "RK_IOMMU"; ++ default: ++ return "NONE_MMU"; ++ } ++} ++ ++const char *rga_get_core_name(enum RGA_SCHEDULER_CORE core) ++{ ++ switch (core) { ++ case RGA_SCHEDULER_RGA3_CORE0: ++ return "RGA3_core0"; ++ case RGA_SCHEDULER_RGA3_CORE1: ++ return "RGA3_core1"; ++ case RGA_SCHEDULER_RGA2_CORE0: ++ return "RGA2_core0"; ++ default: ++ return "unknown_core"; ++ } ++} ++ ++void rga_convert_addr(struct rga_img_info_t *img, bool before_vir_get_channel) ++{ ++ /* ++ * If it is not using dma fd, the virtual/phyical address is assigned ++ * to the address of the corresponding channel. ++ */ ++ ++ //img->yrgb_addr = img->uv_addr; ++ ++ /* ++ * if before_vir_get_channel is true, then convert addr by default ++ * when has iova (before_vir_get_channel is false), ++ * need to consider whether fbc case ++ */ ++ if (img->rd_mode != RGA_FBC_MODE || before_vir_get_channel) { ++ img->uv_addr = img->yrgb_addr + (img->vir_w * img->vir_h); ++ ++ //warning: rga3 may need /2 for all ++ if (rga_is_yuv422p_format(img->format)) ++ img->v_addr = ++ img->uv_addr + (img->vir_w * img->vir_h) / 2; ++ else ++ img->v_addr = ++ img->uv_addr + (img->vir_w * img->vir_h) / 4; ++ } else { ++ img->uv_addr = img->yrgb_addr; ++ img->v_addr = 0; ++ } ++} ++ ++void rga_swap_pd_mode(struct rga_req *req_rga) ++{ ++ if (((req_rga->alpha_rop_flag) & 1)) { ++ if ((req_rga->alpha_rop_flag >> 3) & 1) { ++ if (req_rga->PD_mode == 1) ++ req_rga->PD_mode = 2; ++ else if (req_rga->PD_mode == 2) ++ req_rga->PD_mode = 1; ++ else if (req_rga->PD_mode == 3) ++ req_rga->PD_mode = 4; ++ else if (req_rga->PD_mode == 4) ++ req_rga->PD_mode = 3; ++ } ++ } ++} ++ ++int rga_image_size_cal(int w, int h, int format, ++ int *yrgb_size, int *uv_size, int *v_size) ++{ ++ int yrgb = 0; ++ int uv = 0; ++ int v = 0; ++ ++ switch (format) { ++ case RGA_FORMAT_RGBA_8888: ++ case RGA_FORMAT_RGBX_8888: ++ case RGA_FORMAT_BGRA_8888: ++ case RGA_FORMAT_BGRX_8888: ++ case RGA_FORMAT_ARGB_8888: ++ case RGA_FORMAT_XRGB_8888: ++ case RGA_FORMAT_ABGR_8888: ++ case RGA_FORMAT_XBGR_8888: ++ yrgb = w * h * 4; ++ break; ++ case RGA_FORMAT_RGB_888: ++ case RGA_FORMAT_BGR_888: ++ yrgb = w * h * 3; ++ break; ++ case RGA_FORMAT_RGB_565: ++ case RGA_FORMAT_RGBA_5551: ++ case RGA_FORMAT_RGBA_4444: ++ case RGA_FORMAT_BGR_565: ++ case RGA_FORMAT_BGRA_5551: ++ case RGA_FORMAT_BGRA_4444: ++ case RGA_FORMAT_ARGB_5551: ++ case RGA_FORMAT_ARGB_4444: ++ case RGA_FORMAT_ABGR_5551: ++ case RGA_FORMAT_ABGR_4444: ++ case RGA_FORMAT_YVYU_422: ++ case RGA_FORMAT_VYUY_422: ++ case RGA_FORMAT_YUYV_422: ++ case RGA_FORMAT_UYVY_422: ++ /* YUV 420 packed according to the arrangement of YUV422 packed. */ ++ case RGA_FORMAT_YVYU_420: ++ case RGA_FORMAT_VYUY_420: ++ case RGA_FORMAT_YUYV_420: ++ case RGA_FORMAT_UYVY_420: ++ yrgb = w * h * 2; ++ break; ++ /* YUV FORMAT */ ++ case RGA_FORMAT_YCbCr_422_SP: ++ case RGA_FORMAT_YCrCb_422_SP: ++ /* 10bit format stride is externally configured. */ ++ case RGA_FORMAT_YCbCr_422_SP_10B: ++ case RGA_FORMAT_YCrCb_422_SP_10B: ++ yrgb = w * h; ++ uv = w * h; ++ break; ++ case RGA_FORMAT_YCbCr_422_P: ++ case RGA_FORMAT_YCrCb_422_P: ++ yrgb = w * h; ++ uv = (w * h) >> 1; ++ v = uv; ++ break; ++ case RGA_FORMAT_YCbCr_420_SP: ++ case RGA_FORMAT_YCrCb_420_SP: ++ /* 10bit format stride is externally configured. */ ++ case RGA_FORMAT_YCbCr_420_SP_10B: ++ case RGA_FORMAT_YCrCb_420_SP_10B: ++ yrgb = w * h; ++ uv = (w * h) >> 1; ++ break; ++ case RGA_FORMAT_YCbCr_420_P: ++ case RGA_FORMAT_YCrCb_420_P: ++ yrgb = w * h; ++ uv = (w * h) >> 2; ++ v = uv; ++ break; ++ case RGA_FORMAT_YCbCr_400: ++ yrgb = w * h; ++ break; ++ case RGA_FORMAT_Y4: ++ yrgb = (w * h) >> 1; ++ break; ++ default: ++ pr_err("Unsuport format [0x%x]\n", format); ++ return -EFAULT; ++ } ++ ++ if (yrgb_size != NULL) ++ *yrgb_size = yrgb; ++ if (uv_size != NULL) ++ *uv_size = uv; ++ if (v_size != NULL) ++ *v_size = v; ++ ++ return (yrgb + uv + v); ++} ++ ++void rga_dump_memory_parm(struct rga_memory_parm *parm) ++{ ++ pr_info("memory param: w = %d, h = %d, f = %s(0x%x), size = %d\n", ++ parm->width, parm->height, rga_get_format_name(parm->format), ++ parm->format, parm->size); ++} ++ ++void rga_dump_external_buffer(struct rga_external_buffer *buffer) ++{ ++ pr_info("external: memory = 0x%lx, type = %s\n", ++ (unsigned long)buffer->memory, rga_get_memory_type_str(buffer->type)); ++ rga_dump_memory_parm(&buffer->memory_parm); ++} +diff --git a/drivers/video/rockchip/rga3/rga_debugger.c b/drivers/video/rockchip/rga3/rga_debugger.c +new file mode 100644 +index 000000000..fe2103147 +--- /dev/null ++++ b/drivers/video/rockchip/rga3/rga_debugger.c +@@ -0,0 +1,970 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) Rockchip Electronics Co., Ltd. ++ * ++ * Author: ++ * Cerf Yu ++ * Huang Lee ++ */ ++ ++#define pr_fmt(fmt) "rga_debugger: " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rga.h" ++#include "rga_debugger.h" ++#include "rga_drv.h" ++#include "rga_mm.h" ++#include "rga_common.h" ++ ++#define RGA_DEBUGGER_ROOT_NAME "rkrga" ++ ++#define STR_ENABLE(en) (en ? "EN" : "DIS") ++ ++int RGA_DEBUG_REG; ++int RGA_DEBUG_MSG; ++int RGA_DEBUG_TIME; ++int RGA_DEBUG_INT_FLAG; ++int RGA_DEBUG_MM; ++int RGA_DEBUG_CHECK_MODE; ++int RGA_DEBUG_NONUSE; ++int RGA_DEBUG_DEBUG_MODE; ++int RGA_DEBUG_DUMP_IMAGE; ++ ++#ifdef CONFIG_NO_GKI ++static char g_dump_path[100] = "/data"; ++#endif ++ ++static int rga_debug_show(struct seq_file *m, void *data) ++{ ++ seq_printf(m, "REG [%s]\n" ++ "MSG [%s]\n" ++ "TIME [%s]\n" ++ "INT [%s]\n" ++ "MM [%s]\n" ++ "CHECK [%s]\n" ++ "STOP [%s]\n", ++ STR_ENABLE(RGA_DEBUG_REG), ++ STR_ENABLE(RGA_DEBUG_MSG), ++ STR_ENABLE(RGA_DEBUG_TIME), ++ STR_ENABLE(RGA_DEBUG_INT_FLAG), ++ STR_ENABLE(RGA_DEBUG_MM), ++ STR_ENABLE(RGA_DEBUG_CHECK_MODE), ++ STR_ENABLE(RGA_DEBUG_NONUSE)); ++ ++ seq_puts(m, "\nhelp:\n"); ++ seq_puts(m, " 'echo reg > debug' to enable/disable register log printing.\n"); ++ seq_puts(m, " 'echo msg > debug' to enable/disable message log printing.\n"); ++ seq_puts(m, " 'echo time > debug' to enable/disable time log printing.\n"); ++ seq_puts(m, " 'echo int > debug' to enable/disable interruppt log printing.\n"); ++ seq_puts(m, " 'echo mm > debug' to enable/disable memory manager log printing.\n"); ++ seq_puts(m, " 'echo check > debug' to enable/disable check mode.\n"); ++ seq_puts(m, " 'echo stop > debug' to enable/disable stop using hardware\n"); ++ ++ return 0; ++} ++ ++static ssize_t rga_debug_write(struct file *file, const char __user *ubuf, ++ size_t len, loff_t *offp) ++{ ++ char buf[14]; ++ ++ if (len > sizeof(buf) - 1) ++ return -EINVAL; ++ if (copy_from_user(buf, ubuf, len)) ++ return -EFAULT; ++ buf[len - 1] = '\0'; ++ ++ if (strncmp(buf, "reg", 4) == 0) { ++ if (RGA_DEBUG_REG) { ++ RGA_DEBUG_REG = 0; ++ pr_info("close rga reg!\n"); ++ } else { ++ RGA_DEBUG_REG = 1; ++ pr_info("open rga reg!\n"); ++ } ++ } else if (strncmp(buf, "msg", 3) == 0) { ++ if (RGA_DEBUG_MSG) { ++ RGA_DEBUG_MSG = 0; ++ pr_info("close rga test MSG!\n"); ++ } else { ++ RGA_DEBUG_MSG = 1; ++ pr_info("open rga test MSG!\n"); ++ } ++ } else if (strncmp(buf, "time", 4) == 0) { ++ if (RGA_DEBUG_TIME) { ++ RGA_DEBUG_TIME = 0; ++ pr_info("close rga test time!\n"); ++ } else { ++ RGA_DEBUG_TIME = 1; ++ pr_info("open rga test time!\n"); ++ } ++ } else if (strncmp(buf, "int", 3) == 0) { ++ if (RGA_DEBUG_INT_FLAG) { ++ RGA_DEBUG_INT_FLAG = 0; ++ pr_info("close inturrupt MSG!\n"); ++ } else { ++ RGA_DEBUG_INT_FLAG = 1; ++ pr_info("open inturrupt MSG!\n"); ++ } ++ } else if (strncmp(buf, "mm", 2) == 0) { ++ if (RGA_DEBUG_MM) { ++ RGA_DEBUG_MM = 0; ++ pr_info("close rga mm log!\n"); ++ } else { ++ RGA_DEBUG_MM = 1; ++ pr_info("open rga mm log!\n"); ++ } ++ } else if (strncmp(buf, "check", 5) == 0) { ++ if (RGA_DEBUG_CHECK_MODE) { ++ RGA_DEBUG_CHECK_MODE = 0; ++ pr_info("close rga check flag!\n"); ++ } else { ++ RGA_DEBUG_CHECK_MODE = 1; ++ pr_info("open rga check flag!\n"); ++ } ++ } else if (strncmp(buf, "stop", 4) == 0) { ++ if (RGA_DEBUG_NONUSE) { ++ RGA_DEBUG_NONUSE = 0; ++ pr_info("using rga hardware!\n"); ++ } else { ++ RGA_DEBUG_NONUSE = 1; ++ pr_info("stop using rga hardware!\n"); ++ } ++ } else if (strncmp(buf, "debug", 3) == 0) { ++ if (RGA_DEBUG_DEBUG_MODE) { ++ RGA_DEBUG_REG = 0; ++ RGA_DEBUG_MSG = 0; ++ RGA_DEBUG_TIME = 0; ++ RGA_DEBUG_INT_FLAG = 0; ++ ++ RGA_DEBUG_DEBUG_MODE = 0; ++ pr_info("close debug mode!\n"); ++ } else { ++ RGA_DEBUG_REG = 1; ++ RGA_DEBUG_MSG = 1; ++ RGA_DEBUG_TIME = 1; ++ RGA_DEBUG_INT_FLAG = 1; ++ ++ RGA_DEBUG_DEBUG_MODE = 1; ++ pr_info("open debug mode!\n"); ++ } ++ } else if (strncmp(buf, "slt", 3) == 0) { ++ pr_err("Null"); ++ } ++ ++ return len; ++} ++ ++static int rga_version_show(struct seq_file *m, void *data) ++{ ++ seq_printf(m, "%s: v%s\n", DRIVER_DESC, DRIVER_VERSION); ++ ++ return 0; ++} ++ ++static int rga_load_show(struct seq_file *m, void *data) ++{ ++ struct rga_scheduler_t *scheduler = NULL; ++ struct rga_session_manager *session_manager = NULL; ++ struct rga_session *session = NULL; ++ unsigned long flags; ++ int id = 0; ++ int i; ++ int load; ++ u32 busy_time_total; ++ ++ session_manager = rga_drvdata->session_manager; ++ ++ seq_printf(m, "num of scheduler = %d\n", rga_drvdata->num_of_scheduler); ++ seq_printf(m, "================= load ==================\n"); ++ ++ for (i = 0; i < rga_drvdata->num_of_scheduler; i++) { ++ scheduler = rga_drvdata->scheduler[i]; ++ ++ seq_printf(m, "scheduler[%d]: %s\n", ++ i, dev_driver_string(scheduler->dev)); ++ ++ spin_lock_irqsave(&scheduler->irq_lock, flags); ++ ++ busy_time_total = scheduler->timer.busy_time_record; ++ ++ spin_unlock_irqrestore(&scheduler->irq_lock, flags); ++ ++ load = (busy_time_total * 100 / RGA_LOAD_INTERVAL_US); ++ if (load > 100) ++ load = 100; ++ ++ seq_printf(m, "\t load = %d%%\n", load); ++ seq_printf(m, "-----------------------------------\n"); ++ } ++ ++ mutex_lock(&session_manager->lock); ++ ++ idr_for_each_entry(&session_manager->ctx_id_idr, session, id) ++ seq_printf(m, "\t process %d: pid = %d, name: %s\n", id, ++ session->tgid, session->pname); ++ ++ mutex_unlock(&session_manager->lock); ++ ++ return 0; ++} ++ ++static int rga_scheduler_show(struct seq_file *m, void *data) ++{ ++ struct rga_scheduler_t *scheduler = NULL; ++ int i; ++ ++ seq_printf(m, "num of scheduler = %d\n", rga_drvdata->num_of_scheduler); ++ seq_printf(m, "===================================\n"); ++ ++ for (i = 0; i < rga_drvdata->num_of_scheduler; i++) { ++ scheduler = rga_drvdata->scheduler[i]; ++ ++ seq_printf(m, "scheduler[%d]: %s\n", ++ i, dev_driver_string(scheduler->dev)); ++ seq_printf(m, "-----------------------------------\n"); ++ seq_printf(m, "pd_ref = %d\n", scheduler->pd_refcount); ++ } ++ ++ return 0; ++} ++ ++static int rga_mm_session_show(struct seq_file *m, void *data) ++{ ++ int id; ++ struct rga_mm *mm_session = NULL; ++ struct rga_internal_buffer *dump_buffer; ++ ++ mm_session = rga_drvdata->mm; ++ ++ mutex_lock(&mm_session->lock); ++ ++ seq_puts(m, "rga_mm dump:\n"); ++ seq_printf(m, "buffer count = %d\n", mm_session->buffer_count); ++ seq_puts(m, "===============================================================\n"); ++ ++ idr_for_each_entry(&mm_session->memory_idr, dump_buffer, id) { ++ seq_printf(m, "handle = %d refcount = %d mm_flag = 0x%x tgid = %d\n", ++ dump_buffer->handle, kref_read(&dump_buffer->refcount), ++ dump_buffer->mm_flag, dump_buffer->session->tgid); ++ ++ switch (dump_buffer->type) { ++ case RGA_DMA_BUFFER: ++ case RGA_DMA_BUFFER_PTR: ++ if (rga_mm_is_invalid_dma_buffer(dump_buffer->dma_buffer)) ++ break; ++ ++ seq_puts(m, "dma_buffer:\n"); ++ seq_printf(m, "\t dma_buf = %p, iova = 0x%lxsgt = 0x%p, size = %ld, map_core = 0x%x\n", ++ dump_buffer->dma_buffer->dma_buf, ++ (unsigned long)dump_buffer->dma_buffer->iova, ++ dump_buffer->dma_buffer->sgt, ++ dump_buffer->dma_buffer->size, ++ dump_buffer->dma_buffer->scheduler->core); ++ ++ if (dump_buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS) ++ seq_printf(m, "\t is contiguous, pa = 0x%lx\n", ++ (unsigned long)dump_buffer->phys_addr); ++ ++ break; ++ case RGA_VIRTUAL_ADDRESS: ++ if (dump_buffer->virt_addr == NULL) ++ break; ++ seq_puts(m, "virtual address:\n"); ++ seq_printf(m, "\t va = 0x%lx, pages = 0x%p, size = %ld\n", ++ (unsigned long)dump_buffer->virt_addr->addr, ++ dump_buffer->virt_addr->pages, ++ dump_buffer->virt_addr->size); ++ ++ if (rga_mm_is_invalid_dma_buffer(dump_buffer->dma_buffer)) ++ break; ++ ++ seq_printf(m, "\t iova = 0x%lx, offset = 0x%lx, sgt = 0x%p, size = %ld, map_core = 0x%x\n", ++ (unsigned long)dump_buffer->dma_buffer->iova, ++ (unsigned long)dump_buffer->dma_buffer->offset, ++ dump_buffer->dma_buffer->sgt, ++ dump_buffer->dma_buffer->size, ++ dump_buffer->dma_buffer->scheduler->core); ++ ++ if (dump_buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS) ++ seq_printf(m, "\t is contiguous, pa = 0x%lx\n", ++ (unsigned long)dump_buffer->phys_addr); ++ ++ break; ++ case RGA_PHYSICAL_ADDRESS: ++ seq_puts(m, "physical address:\n"); ++ seq_printf(m, "\t pa = 0x%lx\n", (unsigned long)dump_buffer->phys_addr); ++ break; ++ default: ++ seq_puts(m, "Illegal external buffer!\n"); ++ break; ++ } ++ ++ seq_puts(m, "---------------------------------------------------------------\n"); ++ } ++ mutex_unlock(&mm_session->lock); ++ ++ return 0; ++} ++ ++static int rga_request_manager_show(struct seq_file *m, void *data) ++{ ++ int id, i; ++ struct rga_pending_request_manager *request_manager; ++ struct rga_request *request; ++ struct rga_req *task_list; ++ unsigned long flags; ++ int task_count = 0; ++ int finished_task_count = 0, failed_task_count = 0; ++ ++ request_manager = rga_drvdata->pend_request_manager; ++ ++ seq_puts(m, "rga internal request dump:\n"); ++ seq_printf(m, "request count = %d\n", request_manager->request_count); ++ seq_puts(m, "===============================================================\n"); ++ ++ mutex_lock(&request_manager->lock); ++ ++ idr_for_each_entry(&request_manager->request_idr, request, id) { ++ seq_printf(m, "------------------ request: %d ------------------\n", request->id); ++ ++ spin_lock_irqsave(&request->lock, flags); ++ ++ task_count = request->task_count; ++ finished_task_count = request->finished_task_count; ++ failed_task_count = request->failed_task_count; ++ task_list = request->task_list; ++ ++ spin_unlock_irqrestore(&request->lock, flags); ++ ++ if (task_list == NULL) { ++ seq_puts(m, "\t can not find task list from id\n"); ++ continue; ++ } ++ ++ seq_printf(m, "\t set cmd num: %d, finish job: %d, failed job: %d, flags = 0x%x, ref = %d\n", ++ task_count, finished_task_count, failed_task_count, ++ request->flags, kref_read(&request->refcount)); ++ ++ seq_puts(m, "\t cmd dump:\n\n"); ++ ++ for (i = 0; i < request->task_count; i++) ++ rga_request_task_debug_info(m, &(task_list[i])); ++ } ++ ++ mutex_unlock(&request_manager->lock); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_NO_GKI ++static int rga_dump_path_show(struct seq_file *m, void *data) ++{ ++ seq_printf(m, "dump path: %s\n", g_dump_path); ++ ++ return 0; ++} ++ ++static ssize_t rga_dump_path_write(struct file *file, const char __user *ubuf, ++ size_t len, loff_t *offp) ++{ ++ char buf[100]; ++ ++ if (len > sizeof(buf) - 1) ++ return -EINVAL; ++ if (copy_from_user(buf, ubuf, len)) ++ return -EFAULT; ++ buf[len - 1] = '\0'; ++ ++ snprintf(g_dump_path, sizeof(buf), "%s", buf); ++ pr_info("dump path change to: %s\n", g_dump_path); ++ ++ return len; ++} ++ ++static int rga_dump_image_show(struct seq_file *m, void *data) ++{ ++ seq_printf(m, "dump image count: %d\n", RGA_DEBUG_DUMP_IMAGE); ++ ++ return 0; ++} ++ ++static ssize_t rga_dump_image_write(struct file *file, const char __user *ubuf, ++ size_t len, loff_t *offp) ++{ ++ int ret; ++ int dump_count = 0; ++ char buf[14]; ++ ++ if (len > sizeof(buf) - 1) ++ return -EINVAL; ++ if (copy_from_user(buf, ubuf, len)) ++ return -EFAULT; ++ buf[len - 1] = '\0'; ++ ++ ret = kstrtoint(buf, 10, &dump_count); ++ if (ret) { ++ pr_err("Failed to parse str[%s]\n", buf); ++ return -EFAULT; ++ } ++ ++ if (dump_count <= 0) { ++ pr_err("dump_image count is invalid [%d]!\n", dump_count); ++ return -EINVAL; ++ } ++ ++ RGA_DEBUG_DUMP_IMAGE = dump_count; ++ pr_info("dump image %d\n", RGA_DEBUG_DUMP_IMAGE); ++ ++ return len; ++} ++#endif /* #ifdef CONFIG_NO_GKI */ ++ ++static int rga_hardware_show(struct seq_file *m, void *data) ++{ ++ struct rga_scheduler_t *scheduler = NULL; ++ const struct rga_hw_data *hw_data = NULL; ++ int i; ++ ++ seq_puts(m, "===================================\n"); ++ ++ for (i = 0; i < rga_drvdata->num_of_scheduler; i++) { ++ scheduler = rga_drvdata->scheduler[i]; ++ hw_data = scheduler->data; ++ ++ seq_printf(m, "%s, core %d: version: %s\n", ++ dev_driver_string(scheduler->dev), ++ scheduler->core, scheduler->version.str); ++ seq_printf(m, "input range: %dx%d ~ %dx%d\n", ++ hw_data->input_range.min.width, hw_data->input_range.min.height, ++ hw_data->input_range.max.width, hw_data->input_range.max.height); ++ seq_printf(m, "output range: %dx%d ~ %dx%d\n", ++ hw_data->output_range.min.width, hw_data->output_range.min.height, ++ hw_data->output_range.max.width, hw_data->output_range.max.height); ++ seq_printf(m, "scale limit: 1/%d ~ %d\n", ++ (1 << hw_data->max_downscale_factor), ++ (1 << hw_data->max_upscale_factor)); ++ seq_printf(m, "byte_stride_align: %d\n", hw_data->byte_stride_align); ++ seq_printf(m, "max_byte_stride: %d\n", hw_data->max_byte_stride); ++ seq_printf(m, "csc: RGB2YUV 0x%x YUV2RGB 0x%x\n", ++ hw_data->csc_r2y_mode, hw_data->csc_y2r_mode); ++ seq_printf(m, "feature: 0x%x\n", hw_data->feature); ++ seq_printf(m, "mmu: %s\n", rga_get_mmu_type_str(hw_data->mmu)); ++ seq_puts(m, "-----------------------------------\n"); ++ } ++ ++ return 0; ++} ++ ++static struct rga_debugger_list rga_debugger_root_list[] = { ++ {"debug", rga_debug_show, rga_debug_write, NULL}, ++ {"driver_version", rga_version_show, NULL, NULL}, ++ {"load", rga_load_show, NULL, NULL}, ++ {"scheduler_status", rga_scheduler_show, NULL, NULL}, ++ {"mm_session", rga_mm_session_show, NULL, NULL}, ++ {"request_manager", rga_request_manager_show, NULL, NULL}, ++#ifdef CONFIG_NO_GKI ++ {"dump_path", rga_dump_path_show, rga_dump_path_write, NULL}, ++ {"dump_image", rga_dump_image_show, rga_dump_image_write, NULL}, ++#endif ++ {"hardware", rga_hardware_show, NULL, NULL}, ++}; ++ ++static ssize_t rga_debugger_write(struct file *file, const char __user *ubuf, ++ size_t len, loff_t *offp) ++{ ++ struct seq_file *priv = file->private_data; ++ struct rga_debugger_node *node = priv->private; ++ ++ if (node->info_ent->write) ++ return node->info_ent->write(file, ubuf, len, offp); ++ else ++ return len; ++} ++ ++#ifdef CONFIG_ROCKCHIP_RGA_DEBUG_FS ++static int rga_debugfs_open(struct inode *inode, struct file *file) ++{ ++ struct rga_debugger_node *node = inode->i_private; ++ ++ return single_open(file, node->info_ent->show, node); ++} ++ ++static const struct file_operations rga_debugfs_fops = { ++ .owner = THIS_MODULE, ++ .open = rga_debugfs_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++ .write = rga_debugger_write, ++}; ++ ++static int rga_debugfs_remove_files(struct rga_debugger *debugger) ++{ ++ struct rga_debugger_node *pos, *q; ++ struct list_head *entry_list; ++ ++ mutex_lock(&debugger->debugfs_lock); ++ ++ /* Delete debugfs entry list */ ++ entry_list = &debugger->debugfs_entry_list; ++ list_for_each_entry_safe(pos, q, entry_list, list) { ++ if (pos->dent == NULL) ++ continue; ++ list_del(&pos->list); ++ kfree(pos); ++ pos = NULL; ++ } ++ ++ /* Delete all debugfs node in this directory */ ++ debugfs_remove_recursive(debugger->debugfs_dir); ++ debugger->debugfs_dir = NULL; ++ ++ mutex_unlock(&debugger->debugfs_lock); ++ ++ return 0; ++} ++ ++static int rga_debugfs_create_files(const struct rga_debugger_list *files, ++ int count, struct dentry *root, ++ struct rga_debugger *debugger) ++{ ++ int i; ++ struct dentry *ent; ++ struct rga_debugger_node *tmp; ++ ++ for (i = 0; i < count; i++) { ++ tmp = kmalloc(sizeof(struct rga_debugger_node), GFP_KERNEL); ++ if (tmp == NULL) { ++ pr_err("Cannot alloc node path /sys/kernel/debug/%pd/%s\n", ++ root, files[i].name); ++ goto MALLOC_FAIL; ++ } ++ ++ tmp->info_ent = &files[i]; ++ tmp->debugger = debugger; ++ ++ ent = debugfs_create_file(files[i].name, S_IFREG | S_IRUGO, ++ root, tmp, &rga_debugfs_fops); ++ if (!ent) { ++ pr_err("Cannot create /sys/kernel/debug/%pd/%s\n", root, ++ files[i].name); ++ goto CREATE_FAIL; ++ } ++ ++ tmp->dent = ent; ++ ++ mutex_lock(&debugger->debugfs_lock); ++ list_add_tail(&tmp->list, &debugger->debugfs_entry_list); ++ mutex_unlock(&debugger->debugfs_lock); ++ } ++ ++ return 0; ++ ++CREATE_FAIL: ++ kfree(tmp); ++MALLOC_FAIL: ++ rga_debugfs_remove_files(debugger); ++ ++ return -1; ++} ++ ++int rga_debugfs_remove(void) ++{ ++ struct rga_debugger *debugger; ++ ++ debugger = rga_drvdata->debugger; ++ ++ rga_debugfs_remove_files(debugger); ++ ++ return 0; ++} ++ ++int rga_debugfs_init(void) ++{ ++ int ret; ++ struct rga_debugger *debugger; ++ ++ debugger = rga_drvdata->debugger; ++ ++ debugger->debugfs_dir = ++ debugfs_create_dir(RGA_DEBUGGER_ROOT_NAME, NULL); ++ if (IS_ERR_OR_NULL(debugger->debugfs_dir)) { ++ pr_err("failed on mkdir /sys/kernel/debug/%s\n", ++ RGA_DEBUGGER_ROOT_NAME); ++ debugger->debugfs_dir = NULL; ++ return -EIO; ++ } ++ ++ ret = rga_debugfs_create_files(rga_debugger_root_list, ARRAY_SIZE(rga_debugger_root_list), ++ debugger->debugfs_dir, debugger); ++ if (ret) { ++ pr_err("Could not install rga_debugger_root_list debugfs\n"); ++ goto CREATE_FAIL; ++ } ++ ++ return 0; ++ ++CREATE_FAIL: ++ rga_debugfs_remove(); ++ ++ return ret; ++} ++#endif /* #ifdef CONFIG_ROCKCHIP_RGA_DEBUG_FS */ ++ ++#ifdef CONFIG_ROCKCHIP_RGA_PROC_FS ++static int rga_procfs_open(struct inode *inode, struct file *file) ++{ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) ++ struct rga_debugger_node *node = pde_data(inode); ++#else ++ struct rga_debugger_node *node = PDE_DATA(inode); ++#endif ++ ++ return single_open(file, node->info_ent->show, node); ++} ++ ++static const struct proc_ops rga_procfs_fops = { ++ .proc_open = rga_procfs_open, ++ .proc_read = seq_read, ++ .proc_lseek = seq_lseek, ++ .proc_release = single_release, ++ .proc_write = rga_debugger_write, ++}; ++ ++static int rga_procfs_remove_files(struct rga_debugger *debugger) ++{ ++ struct rga_debugger_node *pos, *q; ++ struct list_head *entry_list; ++ ++ mutex_lock(&debugger->procfs_lock); ++ ++ /* Delete procfs entry list */ ++ entry_list = &debugger->procfs_entry_list; ++ list_for_each_entry_safe(pos, q, entry_list, list) { ++ if (pos->pent == NULL) ++ continue; ++ list_del(&pos->list); ++ kfree(pos); ++ pos = NULL; ++ } ++ ++ /* Delete all procfs node in this directory */ ++ proc_remove(debugger->procfs_dir); ++ debugger->procfs_dir = NULL; ++ ++ mutex_unlock(&debugger->procfs_lock); ++ ++ return 0; ++} ++ ++static int rga_procfs_create_files(const struct rga_debugger_list *files, ++ int count, struct proc_dir_entry *root, ++ struct rga_debugger *debugger) ++{ ++ int i; ++ struct proc_dir_entry *ent; ++ struct rga_debugger_node *tmp; ++ ++ for (i = 0; i < count; i++) { ++ tmp = kmalloc(sizeof(struct rga_debugger_node), GFP_KERNEL); ++ if (tmp == NULL) { ++ pr_err("Cannot alloc node path for /proc/%s/%s\n", ++ RGA_DEBUGGER_ROOT_NAME, files[i].name); ++ goto MALLOC_FAIL; ++ } ++ ++ tmp->info_ent = &files[i]; ++ tmp->debugger = debugger; ++ ++ ent = proc_create_data(files[i].name, S_IFREG | S_IRUGO, ++ root, &rga_procfs_fops, tmp); ++ if (!ent) { ++ pr_err("Cannot create /proc/%s/%s\n", ++ RGA_DEBUGGER_ROOT_NAME, files[i].name); ++ goto CREATE_FAIL; ++ } ++ ++ tmp->pent = ent; ++ ++ mutex_lock(&debugger->procfs_lock); ++ list_add_tail(&tmp->list, &debugger->procfs_entry_list); ++ mutex_unlock(&debugger->procfs_lock); ++ } ++ ++ return 0; ++ ++CREATE_FAIL: ++ kfree(tmp); ++MALLOC_FAIL: ++ rga_procfs_remove_files(debugger); ++ return -1; ++} ++ ++int rga_procfs_remove(void) ++{ ++ struct rga_debugger *debugger; ++ ++ debugger = rga_drvdata->debugger; ++ ++ rga_procfs_remove_files(debugger); ++ ++ return 0; ++} ++ ++int rga_procfs_init(void) ++{ ++ int ret; ++ struct rga_debugger *debugger; ++ ++ debugger = rga_drvdata->debugger; ++ ++ debugger->procfs_dir = proc_mkdir(RGA_DEBUGGER_ROOT_NAME, NULL); ++ if (IS_ERR_OR_NULL(debugger->procfs_dir)) { ++ pr_err("failed on mkdir /proc/%s\n", RGA_DEBUGGER_ROOT_NAME); ++ debugger->procfs_dir = NULL; ++ return -EIO; ++ } ++ ++ ret = rga_procfs_create_files(rga_debugger_root_list, ARRAY_SIZE(rga_debugger_root_list), ++ debugger->procfs_dir, debugger); ++ if (ret) { ++ pr_err("Could not install rga_debugger_root_list procfs\n"); ++ goto CREATE_FAIL; ++ } ++ ++ return 0; ++ ++CREATE_FAIL: ++ rga_procfs_remove(); ++ ++ return ret; ++} ++#endif /* #ifdef CONFIG_ROCKCHIP_RGA_PROC_FS */ ++ ++void rga_request_task_debug_info(struct seq_file *m, struct rga_req *req) ++{ ++ seq_printf(m, "\t\t rotate_mode = %d\n", req->rotate_mode); ++ seq_printf(m, "\t\t src: y = %lx uv = %lx v = %lx aw = %d ah = %d vw = %d vh = %d\n", ++ (unsigned long)req->src.yrgb_addr, (unsigned long)req->src.uv_addr, ++ (unsigned long)req->src.v_addr, req->src.act_w, req->src.act_h, ++ req->src.vir_w, req->src.vir_h); ++ seq_printf(m, "\t\t src: xoff = %d, yoff = %d, format = 0x%x, rd_mode = %d\n", ++ req->src.x_offset, req->src.y_offset, req->src.format, req->src.rd_mode); ++ ++ if (req->pat.yrgb_addr != 0 || req->pat.uv_addr != 0 ++ || req->pat.v_addr != 0) { ++ seq_printf(m, "\t\t pat: y=%lx uv=%lx v=%lx aw=%d ah=%d vw=%d vh=%d\n", ++ (unsigned long)req->pat.yrgb_addr, (unsigned long)req->pat.uv_addr, ++ (unsigned long)req->pat.v_addr, req->pat.act_w, req->pat.act_h, ++ req->pat.vir_w, req->pat.vir_h); ++ seq_printf(m, "\t\t xoff = %d yoff = %d, format = 0x%x, rd_mode = %d\n", ++ req->pat.x_offset, req->pat.y_offset, req->pat.format, req->pat.rd_mode); ++ } ++ ++ seq_printf(m, "\t\t dst: y=%lx uv=%lx v=%lx aw=%d ah=%d vw=%d vh=%d\n", ++ (unsigned long)req->dst.yrgb_addr, (unsigned long)req->dst.uv_addr, ++ (unsigned long)req->dst.v_addr, req->dst.act_w, req->dst.act_h, ++ req->dst.vir_w, req->dst.vir_h); ++ seq_printf(m, "\t\t dst: xoff = %d, yoff = %d, format = 0x%x, rd_mode = %d\n", ++ req->dst.x_offset, req->dst.y_offset, req->dst.format, req->dst.rd_mode); ++ ++ seq_printf(m, "\t\t mmu: mmu_flag=%x en=%x\n", ++ req->mmu_info.mmu_flag, req->mmu_info.mmu_en); ++ seq_printf(m, "\t\t alpha: rop_mode = %x\n", req->alpha_rop_mode); ++ seq_printf(m, "\t\t yuv2rgb mode is %x\n", req->yuv2rgb_mode); ++ seq_printf(m, "\t\t set core = %d, priority = %d, in_fence_fd = %d\n", ++ req->core, req->priority, req->in_fence_fd); ++} ++ ++void rga_cmd_print_debug_info(struct rga_req *req) ++{ ++ pr_info("render_mode = %d, bitblit_mode=%d, rotate_mode = %d\n", ++ req->render_mode, req->bsfilter_flag, ++ req->rotate_mode); ++ ++ pr_info("src: y = %lx uv = %lx v = %lx aw = %d ah = %d vw = %d vh = %d\n", ++ (unsigned long)req->src.yrgb_addr, ++ (unsigned long)req->src.uv_addr, ++ (unsigned long)req->src.v_addr, ++ req->src.act_w, req->src.act_h, ++ req->src.vir_w, req->src.vir_h); ++ pr_info("src: xoff = %d, yoff = %d, format = 0x%x, rd_mode = %d\n", ++ req->src.x_offset, req->src.y_offset, ++ req->src.format, req->src.rd_mode); ++ ++ if (req->pat.yrgb_addr != 0 || req->pat.uv_addr != 0 ++ || req->pat.v_addr != 0) { ++ pr_info("pat: y=%lx uv=%lx v=%lx aw=%d ah=%d vw=%d vh=%d\n", ++ (unsigned long)req->pat.yrgb_addr, ++ (unsigned long)req->pat.uv_addr, ++ (unsigned long)req->pat.v_addr, ++ req->pat.act_w, req->pat.act_h, ++ req->pat.vir_w, req->pat.vir_h); ++ pr_info("pat: xoff = %d yoff = %d, format = 0x%x, rd_mode = %d\n", ++ req->pat.x_offset, req->pat.y_offset, ++ req->pat.format, req->pat.rd_mode); ++ } ++ ++ pr_info("dst: y=%lx uv=%lx v=%lx aw=%d ah=%d vw=%d vh=%d\n", ++ (unsigned long)req->dst.yrgb_addr, ++ (unsigned long)req->dst.uv_addr, ++ (unsigned long)req->dst.v_addr, ++ req->dst.act_w, req->dst.act_h, ++ req->dst.vir_w, req->dst.vir_h); ++ pr_info("dst: xoff = %d, yoff = %d, format = 0x%x, rd_mode = %d\n", ++ req->dst.x_offset, req->dst.y_offset, ++ req->dst.format, req->dst.rd_mode); ++ ++ pr_info("mmu: mmu_flag=%x en=%x\n", ++ req->mmu_info.mmu_flag, req->mmu_info.mmu_en); ++ pr_info("alpha: rop_mode = %x\n", req->alpha_rop_mode); ++ pr_info("yuv2rgb mode is %x\n", req->yuv2rgb_mode); ++ pr_info("set core = %d, priority = %d, in_fence_fd = %d\n", ++ req->core, req->priority, req->in_fence_fd); ++} ++ ++#ifdef CONFIG_NO_GKI ++static int rga_dump_image_to_file(struct rga_internal_buffer *dump_buffer, ++ const char *channel_name, ++ int plane_id, ++ int core) ++{ ++ char file_name[100]; ++ struct file *file; ++ size_t size = 0; ++ loff_t pos = 0; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) ++ int ret; ++ struct iosys_map map; ++#endif ++ void *kvaddr = NULL; ++ void *kvaddr_origin = NULL; ++ ++ switch (dump_buffer->type) { ++ case RGA_DMA_BUFFER: ++ case RGA_DMA_BUFFER_PTR: ++ if (IS_ERR_OR_NULL(dump_buffer->dma_buffer->dma_buf)) { ++ pr_err("Failed to dump dma_buf 0x%px\n", ++ dump_buffer->dma_buffer->dma_buf); ++ return -EINVAL; ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) ++ ret = dma_buf_vmap(dump_buffer->dma_buffer->dma_buf, &map); ++ kvaddr = ret ? NULL : map.vaddr; ++#else ++ kvaddr = dma_buf_vmap(dump_buffer->dma_buffer->dma_buf); ++#endif ++ if (!kvaddr) { ++ pr_err("can't vmap the dma buffer!\n"); ++ return -EINVAL; ++ } ++ ++ kvaddr_origin = kvaddr; ++ kvaddr += dump_buffer->dma_buffer->offset; ++ break; ++ case RGA_VIRTUAL_ADDRESS: ++ kvaddr = vmap(dump_buffer->virt_addr->pages, dump_buffer->virt_addr->page_count, ++ VM_MAP, pgprot_writecombine(PAGE_KERNEL)); ++ if (!kvaddr) { ++ pr_err("dump_vaddr vmap error!, 0x%lx\n", ++ (unsigned long)dump_buffer->virt_addr->addr); ++ return -EFAULT; ++ } ++ ++ kvaddr_origin = kvaddr; ++ kvaddr += dump_buffer->virt_addr->offset; ++ break; ++ case RGA_PHYSICAL_ADDRESS: ++ kvaddr = phys_to_virt(dump_buffer->phys_addr); ++ break; ++ default: ++ pr_err("unsupported memory type[%x]\n", dump_buffer->type); ++ return -EINVAL; ++ } ++ ++ size = dump_buffer->size; ++ ++ if (kvaddr == NULL) { ++ pr_err("dump addr is NULL!\n"); ++ return -EFAULT; ++ } ++ ++ if (size <= 0) { ++ pr_err("dump buffer size[%lx] is invalid!\n", (unsigned long)size); ++ return -EFAULT; ++ } ++ ++ if (dump_buffer->memory_parm.width == 0 && ++ dump_buffer->memory_parm.height == 0) ++ snprintf(file_name, 100, "%s/%d_core%d_%s_plane%d_%s_size%zu_%s.bin", ++ g_dump_path, ++ RGA_DEBUG_DUMP_IMAGE, core, channel_name, plane_id, ++ rga_get_memory_type_str(dump_buffer->type), ++ size, ++ rga_get_format_name(dump_buffer->memory_parm.format)); ++ else ++ snprintf(file_name, 100, "%s/%d_core%d_%s_plane%d_%s_w%d_h%d_%s.bin", ++ g_dump_path, ++ RGA_DEBUG_DUMP_IMAGE, core, channel_name, plane_id, ++ rga_get_memory_type_str(dump_buffer->type), ++ dump_buffer->memory_parm.width, ++ dump_buffer->memory_parm.height, ++ rga_get_format_name(dump_buffer->memory_parm.format)); ++ ++ file = filp_open(file_name, O_RDWR | O_CREAT | O_TRUNC, 0600); ++ if (!IS_ERR(file)) { ++ kernel_write(file, kvaddr, size, &pos); ++ pr_info("dump image to: %s\n", file_name); ++ fput(file); ++ } else { ++ pr_info("open %s failed\n", file_name); ++ } ++ ++ switch (dump_buffer->type) { ++ case RGA_DMA_BUFFER: ++ case RGA_DMA_BUFFER_PTR: ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) ++ dma_buf_vunmap(dump_buffer->dma_buffer->dma_buf, &map); ++#else ++ dma_buf_vunmap(dump_buffer->dma_buffer->dma_buf, kvaddr_origin); ++#endif ++ break; ++ case RGA_VIRTUAL_ADDRESS: ++ vunmap(kvaddr_origin); ++ break; ++ } ++ ++ return 0; ++} ++ ++static inline void rga_dump_channel_image(struct rga_job_buffer *job_buffer, ++ const char *channel_name, ++ int core) ++{ ++ if (job_buffer->y_addr) ++ rga_dump_image_to_file(job_buffer->y_addr, channel_name, 0, core); ++ if (job_buffer->uv_addr) ++ rga_dump_image_to_file(job_buffer->uv_addr, channel_name, 1, core); ++ if (job_buffer->v_addr) ++ rga_dump_image_to_file(job_buffer->v_addr, channel_name, 2, core); ++} ++ ++void rga_dump_job_image(struct rga_job *dump_job) ++{ ++ rga_dump_channel_image(&dump_job->src_buffer, "src", dump_job->core); ++ rga_dump_channel_image(&dump_job->src1_buffer, "src1", dump_job->core); ++ rga_dump_channel_image(&dump_job->dst_buffer, "dst", dump_job->core); ++ rga_dump_channel_image(&dump_job->els_buffer, "els", dump_job->core); ++ ++ if (RGA_DEBUG_DUMP_IMAGE > 0) ++ RGA_DEBUG_DUMP_IMAGE--; ++} ++#endif /* #ifdef CONFIG_NO_GKI */ +diff --git a/drivers/video/rockchip/rga3/rga_dma_buf.c b/drivers/video/rockchip/rga3/rga_dma_buf.c +new file mode 100644 +index 000000000..3032ad475 +--- /dev/null ++++ b/drivers/video/rockchip/rga3/rga_dma_buf.c +@@ -0,0 +1,546 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) Rockchip Electronics Co., Ltd. ++ * ++ * Author: Huang Lee ++ */ ++ ++#define pr_fmt(fmt) "rga_dma_buf: " fmt ++ ++#include "rga_dma_buf.h" ++#include "rga.h" ++#include "rga_common.h" ++#include "rga_job.h" ++#include "rga_debugger.h" ++ ++static int rga_dma_info_to_prot(enum dma_data_direction dir) ++{ ++ switch (dir) { ++ case DMA_BIDIRECTIONAL: ++ return IOMMU_READ | IOMMU_WRITE; ++ case DMA_TO_DEVICE: ++ return IOMMU_READ; ++ case DMA_FROM_DEVICE: ++ return IOMMU_WRITE; ++ default: ++ return 0; ++ } ++} ++ ++int rga_buf_size_cal(unsigned long yrgb_addr, unsigned long uv_addr, ++ unsigned long v_addr, int format, uint32_t w, ++ uint32_t h, unsigned long *StartAddr, unsigned long *size) ++{ ++ uint32_t size_yrgb = 0; ++ uint32_t size_uv = 0; ++ uint32_t size_v = 0; ++ uint32_t stride = 0; ++ unsigned long start, end; ++ uint32_t pageCount; ++ ++ switch (format) { ++ case RGA_FORMAT_RGBA_8888: ++ case RGA_FORMAT_RGBX_8888: ++ case RGA_FORMAT_BGRA_8888: ++ case RGA_FORMAT_BGRX_8888: ++ case RGA_FORMAT_ARGB_8888: ++ case RGA_FORMAT_XRGB_8888: ++ case RGA_FORMAT_ABGR_8888: ++ case RGA_FORMAT_XBGR_8888: ++ stride = (w * 4 + 3) & (~3); ++ size_yrgb = stride * h; ++ start = yrgb_addr >> PAGE_SHIFT; ++ end = yrgb_addr + size_yrgb; ++ end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT; ++ pageCount = end - start; ++ break; ++ case RGA_FORMAT_RGB_888: ++ case RGA_FORMAT_BGR_888: ++ stride = (w * 3 + 3) & (~3); ++ size_yrgb = stride * h; ++ start = yrgb_addr >> PAGE_SHIFT; ++ end = yrgb_addr + size_yrgb; ++ end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT; ++ pageCount = end - start; ++ break; ++ case RGA_FORMAT_RGB_565: ++ case RGA_FORMAT_RGBA_5551: ++ case RGA_FORMAT_RGBA_4444: ++ case RGA_FORMAT_BGR_565: ++ case RGA_FORMAT_BGRA_5551: ++ case RGA_FORMAT_BGRA_4444: ++ case RGA_FORMAT_ARGB_5551: ++ case RGA_FORMAT_ARGB_4444: ++ case RGA_FORMAT_ABGR_5551: ++ case RGA_FORMAT_ABGR_4444: ++ stride = (w * 2 + 3) & (~3); ++ size_yrgb = stride * h; ++ start = yrgb_addr >> PAGE_SHIFT; ++ end = yrgb_addr + size_yrgb; ++ end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT; ++ pageCount = end - start; ++ break; ++ ++ /* YUV FORMAT */ ++ case RGA_FORMAT_YCbCr_422_SP: ++ case RGA_FORMAT_YCrCb_422_SP: ++ stride = (w + 3) & (~3); ++ size_yrgb = stride * h; ++ size_uv = stride * h; ++ start = min(yrgb_addr, uv_addr); ++ start >>= PAGE_SHIFT; ++ end = max((yrgb_addr + size_yrgb), (uv_addr + size_uv)); ++ end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT; ++ pageCount = end - start; ++ break; ++ case RGA_FORMAT_YCbCr_422_P: ++ case RGA_FORMAT_YCrCb_422_P: ++ stride = (w + 3) & (~3); ++ size_yrgb = stride * h; ++ size_uv = ((stride >> 1) * h); ++ size_v = ((stride >> 1) * h); ++ start = min3(yrgb_addr, uv_addr, v_addr); ++ start = start >> PAGE_SHIFT; ++ end = ++ max3((yrgb_addr + size_yrgb), (uv_addr + size_uv), ++ (v_addr + size_v)); ++ end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT; ++ pageCount = end - start; ++ break; ++ case RGA_FORMAT_YCbCr_420_SP: ++ case RGA_FORMAT_YCrCb_420_SP: ++ stride = (w + 3) & (~3); ++ size_yrgb = stride * h; ++ size_uv = (stride * (h >> 1)); ++ start = min(yrgb_addr, uv_addr); ++ start >>= PAGE_SHIFT; ++ end = max((yrgb_addr + size_yrgb), (uv_addr + size_uv)); ++ end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT; ++ pageCount = end - start; ++ break; ++ case RGA_FORMAT_YCbCr_420_P: ++ case RGA_FORMAT_YCrCb_420_P: ++ stride = (w + 3) & (~3); ++ size_yrgb = stride * h; ++ size_uv = ((stride >> 1) * (h >> 1)); ++ size_v = ((stride >> 1) * (h >> 1)); ++ start = min3(yrgb_addr, uv_addr, v_addr); ++ start >>= PAGE_SHIFT; ++ end = ++ max3((yrgb_addr + size_yrgb), (uv_addr + size_uv), ++ (v_addr + size_v)); ++ end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT; ++ pageCount = end - start; ++ break; ++ case RGA_FORMAT_YCbCr_400: ++ stride = (w + 3) & (~3); ++ size_yrgb = stride * h; ++ start = yrgb_addr >> PAGE_SHIFT; ++ end = yrgb_addr + size_yrgb; ++ end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT; ++ pageCount = end - start; ++ break; ++ case RGA_FORMAT_Y4: ++ stride = ((w + 3) & (~3)) >> 1; ++ size_yrgb = stride * h; ++ start = yrgb_addr >> PAGE_SHIFT; ++ end = yrgb_addr + size_yrgb; ++ end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT; ++ pageCount = end - start; ++ break; ++ case RGA_FORMAT_YVYU_422: ++ case RGA_FORMAT_VYUY_422: ++ case RGA_FORMAT_YUYV_422: ++ case RGA_FORMAT_UYVY_422: ++ stride = (w + 3) & (~3); ++ size_yrgb = stride * h; ++ size_uv = stride * h; ++ start = min(yrgb_addr, uv_addr); ++ start >>= PAGE_SHIFT; ++ end = max((yrgb_addr + size_yrgb), (uv_addr + size_uv)); ++ end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT; ++ pageCount = end - start; ++ break; ++ case RGA_FORMAT_YVYU_420: ++ case RGA_FORMAT_VYUY_420: ++ case RGA_FORMAT_YUYV_420: ++ case RGA_FORMAT_UYVY_420: ++ stride = (w + 3) & (~3); ++ size_yrgb = stride * h; ++ size_uv = (stride * (h >> 1)); ++ start = min(yrgb_addr, uv_addr); ++ start >>= PAGE_SHIFT; ++ end = max((yrgb_addr + size_yrgb), (uv_addr + size_uv)); ++ end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT; ++ pageCount = end - start; ++ break; ++ case RGA_FORMAT_YCbCr_420_SP_10B: ++ case RGA_FORMAT_YCrCb_420_SP_10B: ++ stride = (w + 3) & (~3); ++ size_yrgb = stride * h; ++ size_uv = (stride * (h >> 1)); ++ start = min(yrgb_addr, uv_addr); ++ start >>= PAGE_SHIFT; ++ end = max((yrgb_addr + size_yrgb), (uv_addr + size_uv)); ++ end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT; ++ pageCount = end - start; ++ break; ++ default: ++ pageCount = 0; ++ start = 0; ++ break; ++ } ++ ++ *StartAddr = start; ++ ++ if (size != NULL) ++ *size = size_yrgb + size_uv + size_v; ++ ++ return pageCount; ++} ++ ++static dma_addr_t rga_iommu_dma_alloc_iova(struct iommu_domain *domain, ++ size_t size, u64 dma_limit, ++ struct device *dev) ++{ ++ struct rga_iommu_dma_cookie *cookie = (void *)domain->iova_cookie; ++ struct iova_domain *iovad = &cookie->iovad; ++ unsigned long shift, iova_len, iova = 0; ++ ++ shift = iova_shift(iovad); ++ iova_len = size >> shift; ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)) ++ /* ++ * Freeing non-power-of-two-sized allocations back into the IOVA caches ++ * will come back to bite us badly, so we have to waste a bit of space ++ * rounding up anything cacheable to make sure that can't happen. The ++ * order of the unadjusted size will still match upon freeing. ++ */ ++ if (iova_len < (1 << (IOVA_RANGE_CACHE_MAX_SIZE - 1))) ++ iova_len = roundup_pow_of_two(iova_len); ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) ++ dma_limit = min_not_zero(dma_limit, dev->bus_dma_limit); ++#else ++ if (dev->bus_dma_mask) ++ dma_limit &= dev->bus_dma_mask; ++#endif ++ ++ if (domain->geometry.force_aperture) ++ dma_limit = min(dma_limit, (u64)domain->geometry.aperture_end); ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 19, 111) && \ ++ LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0)) ++ iova = alloc_iova_fast(iovad, iova_len, ++ min_t(dma_addr_t, dma_limit >> shift, iovad->end_pfn), ++ true); ++#else ++ iova = alloc_iova_fast(iovad, iova_len, dma_limit >> shift, true); ++#endif ++ ++ return (dma_addr_t)iova << shift; ++} ++ ++static void rga_iommu_dma_free_iova(struct iommu_domain *domain, ++ dma_addr_t iova, size_t size) ++{ ++ struct rga_iommu_dma_cookie *cookie = (void *)domain->iova_cookie; ++ struct iova_domain *iovad = &cookie->iovad; ++ ++ free_iova_fast(iovad, iova_pfn(iovad, iova), size >> iova_shift(iovad)); ++} ++ ++static inline struct iommu_domain *rga_iommu_get_dma_domain(struct device *dev) ++{ ++ return iommu_get_domain_for_dev(dev); ++} ++ ++void rga_iommu_unmap(struct rga_dma_buffer *buffer) ++{ ++ if (buffer == NULL) ++ return; ++ if (buffer->iova == 0) ++ return; ++ ++ iommu_unmap(buffer->domain, buffer->iova, buffer->size); ++ rga_iommu_dma_free_iova(buffer->domain, buffer->iova, buffer->size); ++} ++ ++int rga_iommu_map_sgt(struct sg_table *sgt, size_t size, ++ struct rga_dma_buffer *buffer, ++ struct device *rga_dev) ++{ ++ struct iommu_domain *domain = NULL; ++ struct rga_iommu_dma_cookie *cookie; ++ struct iova_domain *iovad; ++ dma_addr_t iova; ++ size_t map_size; ++ unsigned long align_size; ++ ++ if (sgt == NULL) { ++ pr_err("can not map iommu, because sgt is null!\n"); ++ return -EINVAL; ++ } ++ ++ domain = rga_iommu_get_dma_domain(rga_dev); ++ cookie = (void *)domain->iova_cookie; ++ iovad = &cookie->iovad; ++ align_size = iova_align(iovad, size); ++ ++ if (DEBUGGER_EN(MSG)) ++ pr_info("iova_align size = %ld", align_size); ++ ++ iova = rga_iommu_dma_alloc_iova(domain, align_size, rga_dev->coherent_dma_mask, rga_dev); ++ if (!iova) { ++ pr_err("rga_iommu_dma_alloc_iova failed"); ++ return -ENOMEM; ++ } ++ ++ map_size = iommu_map_sg(domain, iova, sgt->sgl, sgt->orig_nents, ++ rga_dma_info_to_prot(DMA_BIDIRECTIONAL), GFP_KERNEL); ++ if (map_size < align_size) { ++ pr_err("iommu can not map sgt to iova"); ++ rga_iommu_dma_free_iova(domain, iova, align_size); ++ return -EINVAL; ++ } ++ ++ buffer->domain = domain; ++ buffer->iova = iova; ++ buffer->size = align_size; ++ ++ return 0; ++} ++ ++int rga_iommu_map(phys_addr_t paddr, size_t size, ++ struct rga_dma_buffer *buffer, ++ struct device *rga_dev) ++{ ++ int ret; ++ struct iommu_domain *domain = NULL; ++ struct rga_iommu_dma_cookie *cookie; ++ struct iova_domain *iovad; ++ dma_addr_t iova; ++ unsigned long align_size; ++ ++ if (paddr == 0) { ++ pr_err("can not map iommu, because phys_addr is 0!\n"); ++ return -EINVAL; ++ } ++ ++ domain = rga_iommu_get_dma_domain(rga_dev); ++ cookie = (void *)domain->iova_cookie; ++ iovad = &cookie->iovad; ++ align_size = iova_align(iovad, size); ++ ++ if (DEBUGGER_EN(MSG)) ++ pr_info("iova_align size = %ld", align_size); ++ ++ iova = rga_iommu_dma_alloc_iova(domain, align_size, rga_dev->coherent_dma_mask, rga_dev); ++ if (!iova) { ++ pr_err("rga_iommu_dma_alloc_iova failed"); ++ return -ENOMEM; ++ } ++ ++ ret = iommu_map(domain, iova, paddr, align_size, ++ rga_dma_info_to_prot(DMA_BIDIRECTIONAL), GFP_KERNEL); ++ if (ret) { ++ pr_err("iommu can not map phys_addr to iova"); ++ rga_iommu_dma_free_iova(domain, iova, align_size); ++ return ret; ++ } ++ ++ buffer->domain = domain; ++ buffer->iova = iova; ++ buffer->size = align_size; ++ ++ return 0; ++} ++ ++int rga_virtual_memory_check(void *vaddr, u32 w, u32 h, u32 format, int fd) ++{ ++ int bits = 32; ++ int temp_data = 0; ++ void *one_line = NULL; ++ ++ bits = rga_get_format_bits(format); ++ if (bits < 0) ++ return -1; ++ ++ one_line = kzalloc(w * 4, GFP_KERNEL); ++ if (!one_line) { ++ pr_err("kzalloc fail %s[%d]\n", __func__, __LINE__); ++ return 0; ++ } ++ ++ temp_data = w * (h - 1) * bits >> 3; ++ if (fd > 0) { ++ pr_info("vaddr is%p, bits is %d, fd check\n", vaddr, bits); ++ memcpy(one_line, (char *)vaddr + temp_data, w * bits >> 3); ++ pr_info("fd check ok\n"); ++ } else { ++ pr_info("vir addr memory check.\n"); ++ memcpy((void *)((char *)vaddr + temp_data), one_line, ++ w * bits >> 3); ++ pr_info("vir addr check ok.\n"); ++ } ++ ++ kfree(one_line); ++ return 0; ++} ++ ++int rga_dma_memory_check(struct rga_dma_buffer *rga_dma_buffer, struct rga_img_info_t *img) ++{ ++ int ret = 0; ++ void *vaddr; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) ++ struct iosys_map map; ++#endif ++ struct dma_buf *dma_buf; ++ ++ dma_buf = rga_dma_buffer->dma_buf; ++ ++ if (!IS_ERR_OR_NULL(dma_buf)) { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) ++ ret = dma_buf_vmap(dma_buf, &map); ++ vaddr = ret ? NULL : map.vaddr; ++#else ++ vaddr = dma_buf_vmap(dma_buf); ++#endif ++ if (vaddr) { ++ ret = rga_virtual_memory_check(vaddr, img->vir_w, ++ img->vir_h, img->format, img->yrgb_addr); ++ } else { ++ pr_err("can't vmap the dma buffer!\n"); ++ return -EINVAL; ++ } ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) ++ dma_buf_vunmap(dma_buf, &map); ++#else ++ dma_buf_vunmap(dma_buf, vaddr); ++#endif ++ } ++ ++ return ret; ++} ++ ++int rga_dma_map_buf(struct dma_buf *dma_buf, struct rga_dma_buffer *rga_dma_buffer, ++ enum dma_data_direction dir, struct device *rga_dev) ++{ ++ struct dma_buf_attachment *attach = NULL; ++ struct sg_table *sgt = NULL; ++ struct scatterlist *sg = NULL; ++ int i, ret = 0; ++ ++ if (dma_buf != NULL) { ++ get_dma_buf(dma_buf); ++ } else { ++ pr_err("dma_buf is invalid[%p]\n", dma_buf); ++ return -EINVAL; ++ } ++ ++ attach = dma_buf_attach(dma_buf, rga_dev); ++ if (IS_ERR(attach)) { ++ ret = PTR_ERR(attach); ++ pr_err("Failed to attach dma_buf, ret[%d]\n", ret); ++ goto err_get_attach; ++ } ++ ++ sgt = dma_buf_map_attachment(attach, dir); ++ if (IS_ERR(sgt)) { ++ ret = PTR_ERR(sgt); ++ pr_err("Failed to map attachment, ret[%d]\n", ret); ++ goto err_get_sgt; ++ } ++ ++ rga_dma_buffer->dma_buf = dma_buf; ++ rga_dma_buffer->attach = attach; ++ rga_dma_buffer->sgt = sgt; ++ rga_dma_buffer->iova = sg_dma_address(sgt->sgl); ++ rga_dma_buffer->dir = dir; ++ rga_dma_buffer->size = 0; ++ for_each_sgtable_sg(sgt, sg, i) ++ rga_dma_buffer->size += sg_dma_len(sg); ++ ++ return ret; ++ ++err_get_sgt: ++ if (attach) ++ dma_buf_detach(dma_buf, attach); ++err_get_attach: ++ if (dma_buf) ++ dma_buf_put(dma_buf); ++ ++ return ret; ++} ++ ++int rga_dma_map_fd(int fd, struct rga_dma_buffer *rga_dma_buffer, ++ enum dma_data_direction dir, struct device *rga_dev) ++{ ++ struct dma_buf *dma_buf = NULL; ++ struct dma_buf_attachment *attach = NULL; ++ struct sg_table *sgt = NULL; ++ struct scatterlist *sg = NULL; ++ int i, ret = 0; ++ ++ dma_buf = dma_buf_get(fd); ++ if (IS_ERR(dma_buf)) { ++ ret = PTR_ERR(dma_buf); ++ pr_err("Fail to get dma_buf from fd[%d], ret[%d]\n", fd, ret); ++ return ret; ++ } ++ ++ attach = dma_buf_attach(dma_buf, rga_dev); ++ if (IS_ERR(attach)) { ++ ret = PTR_ERR(attach); ++ pr_err("Failed to attach dma_buf, ret[%d]\n", ret); ++ goto err_get_attach; ++ } ++ ++ sgt = dma_buf_map_attachment(attach, dir); ++ if (IS_ERR(sgt)) { ++ ret = PTR_ERR(sgt); ++ pr_err("Failed to map attachment, ret[%d]\n", ret); ++ goto err_get_sgt; ++ } ++ ++ rga_dma_buffer->dma_buf = dma_buf; ++ rga_dma_buffer->attach = attach; ++ rga_dma_buffer->sgt = sgt; ++ rga_dma_buffer->iova = sg_dma_address(sgt->sgl); ++ rga_dma_buffer->dir = dir; ++ rga_dma_buffer->size = 0; ++ for_each_sgtable_sg(sgt, sg, i) ++ rga_dma_buffer->size += sg_dma_len(sg); ++ ++ return ret; ++ ++err_get_sgt: ++ if (attach) ++ dma_buf_detach(dma_buf, attach); ++err_get_attach: ++ if (dma_buf) ++ dma_buf_put(dma_buf); ++ ++ return ret; ++} ++ ++void rga_dma_unmap_buf(struct rga_dma_buffer *rga_dma_buffer) ++{ ++ if (rga_dma_buffer->attach && rga_dma_buffer->sgt) ++ dma_buf_unmap_attachment(rga_dma_buffer->attach, ++ rga_dma_buffer->sgt, ++ rga_dma_buffer->dir); ++ ++ if (rga_dma_buffer->attach) { ++ dma_buf_detach(rga_dma_buffer->dma_buf, rga_dma_buffer->attach); ++ dma_buf_put(rga_dma_buffer->dma_buf); ++ } ++} ++ ++void rga_dma_sync_flush_range(void *pstart, void *pend, struct rga_scheduler_t *scheduler) ++{ ++ dma_sync_single_for_device(scheduler->dev, virt_to_phys(pstart), ++ pend - pstart, DMA_TO_DEVICE); ++} +diff --git a/drivers/video/rockchip/rga3/rga_drv.c b/drivers/video/rockchip/rga3/rga_drv.c +new file mode 100644 +index 000000000..351f5db27 +--- /dev/null ++++ b/drivers/video/rockchip/rga3/rga_drv.c +@@ -0,0 +1,1612 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) Rockchip Electronics Co., Ltd. ++ * ++ * Author: Huang Lee ++ */ ++ ++#define pr_fmt(fmt) "rga: " fmt ++ ++#include "rga2_reg_info.h" ++#include "rga3_reg_info.h" ++#include "rga_dma_buf.h" ++#include "rga_mm.h" ++ ++#include "rga_job.h" ++#include "rga_fence.h" ++#include "rga_hw_config.h" ++ ++#include "rga_iommu.h" ++#include "rga_debugger.h" ++#include "rga_common.h" ++ ++struct rga_drvdata_t *rga_drvdata; ++ ++/* set hrtimer */ ++static struct hrtimer timer; ++static ktime_t kt; ++ ++static struct rga_session *rga_session_init(void); ++static int rga_session_deinit(struct rga_session *session); ++ ++static int rga_mpi_set_channel_buffer(struct dma_buf *dma_buf, ++ struct rga_img_info_t *channel_info, ++ struct rga_session *session) ++{ ++ struct rga_external_buffer buffer; ++ ++ memset(&buffer, 0x0, sizeof(buffer)); ++ buffer.memory = (unsigned long)dma_buf; ++ buffer.type = RGA_DMA_BUFFER_PTR; ++ buffer.memory_parm.width = channel_info->vir_w; ++ buffer.memory_parm.height = channel_info->vir_h; ++ buffer.memory_parm.format = channel_info->format; ++ ++ buffer.handle = rga_mm_import_buffer(&buffer, session); ++ if (buffer.handle == 0) { ++ pr_err("can not import dma_buf %p\n", dma_buf); ++ return -EFAULT; ++ } ++ channel_info->yrgb_addr = buffer.handle; ++ ++ return 0; ++} ++ ++static void rga_mpi_set_channel_info(uint32_t flags_mask, uint32_t flags, ++ struct rga_video_frame_info *mpi_frame, ++ struct rga_img_info_t *channel_info, ++ struct rga_img_info_t *cache_info) ++{ ++ uint32_t fix_enable_flag, cache_info_flag; ++ ++ switch (flags_mask) { ++ case RGA_CONTEXT_SRC_MASK: ++ fix_enable_flag = RGA_CONTEXT_SRC_FIX_ENABLE; ++ cache_info_flag = RGA_CONTEXT_SRC_CACHE_INFO; ++ break; ++ case RGA_CONTEXT_PAT_MASK: ++ fix_enable_flag = RGA_CONTEXT_PAT_FIX_ENABLE; ++ cache_info_flag = RGA_CONTEXT_PAT_CACHE_INFO; ++ break; ++ case RGA_CONTEXT_DST_MASK: ++ fix_enable_flag = RGA_CONTEXT_DST_FIX_ENABLE; ++ cache_info_flag = RGA_CONTEXT_DST_CACHE_INFO; ++ break; ++ default: ++ return; ++ } ++ ++ if (flags & fix_enable_flag) { ++ channel_info->x_offset = mpi_frame->x_offset; ++ channel_info->y_offset = mpi_frame->y_offset; ++ channel_info->act_w = mpi_frame->width; ++ channel_info->act_h = mpi_frame->height; ++ channel_info->vir_w = mpi_frame->vir_w; ++ channel_info->vir_h = mpi_frame->vir_h; ++ channel_info->rd_mode = mpi_frame->rd_mode; ++ channel_info->format = mpi_frame->format; ++ ++ if (flags & cache_info_flag) { ++ /* Replace the config of src in ctx with the config of mpi src. */ ++ cache_info->x_offset = mpi_frame->x_offset; ++ cache_info->y_offset = mpi_frame->y_offset; ++ cache_info->act_w = mpi_frame->width; ++ cache_info->act_h = mpi_frame->height; ++ cache_info->vir_w = mpi_frame->vir_w; ++ cache_info->vir_h = mpi_frame->vir_h; ++ cache_info->rd_mode = mpi_frame->rd_mode; ++ cache_info->format = mpi_frame->format; ++ ++ } ++ } ++} ++ ++int rga_mpi_commit(struct rga_mpi_job_t *mpi_job) ++{ ++ int ret = 0; ++ struct rga_pending_request_manager *request_manager; ++ struct rga_request *request; ++ struct rga_req *cached_cmd; ++ struct rga_req mpi_cmd; ++ unsigned long flags; ++ ++ request_manager = rga_drvdata->pend_request_manager; ++ ++ mutex_lock(&request_manager->lock); ++ request = rga_request_lookup(request_manager, mpi_job->ctx_id); ++ if (IS_ERR_OR_NULL(request)) { ++ pr_err("can not find request from id[%d]", mpi_job->ctx_id); ++ mutex_unlock(&request_manager->lock); ++ return -EINVAL; ++ } ++ ++ if (request->task_count > 1) { ++ /* TODO */ ++ pr_err("Currently request does not support multiple tasks!"); ++ mutex_unlock(&request_manager->lock); ++ return -EINVAL; ++ } ++ ++ /* ++ * The mpi commit will use the request repeatedly, so an additional ++ * get() is added here. ++ */ ++ rga_request_get(request); ++ mutex_unlock(&request_manager->lock); ++ ++ spin_lock_irqsave(&request->lock, flags); ++ ++ /* TODO: batch mode need mpi async mode */ ++ request->sync_mode = RGA_BLIT_SYNC; ++ ++ cached_cmd = request->task_list; ++ memcpy(&mpi_cmd, cached_cmd, sizeof(mpi_cmd)); ++ ++ spin_unlock_irqrestore(&request->lock, flags); ++ ++ /* set channel info */ ++ if ((mpi_job->src != NULL) && (request->flags & RGA_CONTEXT_SRC_MASK)) ++ rga_mpi_set_channel_info(RGA_CONTEXT_SRC_MASK, ++ request->flags, ++ mpi_job->src, ++ &mpi_cmd.src, ++ &cached_cmd->src); ++ ++ if ((mpi_job->pat != NULL) && (request->flags & RGA_CONTEXT_PAT_MASK)) ++ rga_mpi_set_channel_info(RGA_CONTEXT_PAT_MASK, ++ request->flags, ++ mpi_job->pat, ++ &mpi_cmd.pat, ++ &cached_cmd->pat); ++ ++ if ((mpi_job->dst != NULL) && (request->flags & RGA_CONTEXT_DST_MASK)) ++ rga_mpi_set_channel_info(RGA_CONTEXT_DST_MASK, ++ request->flags, ++ mpi_job->dst, ++ &mpi_cmd.dst, ++ &cached_cmd->dst); ++ ++ /* set buffer handle */ ++ if (mpi_job->dma_buf_src0 != NULL) { ++ ret = rga_mpi_set_channel_buffer(mpi_job->dma_buf_src0, ++ &mpi_cmd.src, ++ request->session); ++ if (ret < 0) { ++ pr_err("src channel set buffer handle failed!\n"); ++ goto err_put_request; ++ } ++ } ++ ++ if (mpi_job->dma_buf_src1 != NULL) { ++ ret = rga_mpi_set_channel_buffer(mpi_job->dma_buf_src1, ++ &mpi_cmd.pat, ++ request->session); ++ if (ret < 0) { ++ pr_err("src1 channel set buffer handle failed!\n"); ++ goto err_put_request; ++ } ++ } ++ ++ if (mpi_job->dma_buf_dst != NULL) { ++ ret = rga_mpi_set_channel_buffer(mpi_job->dma_buf_dst, ++ &mpi_cmd.dst, ++ request->session); ++ if (ret < 0) { ++ pr_err("dst channel set buffer handle failed!\n"); ++ goto err_put_request; ++ } ++ } ++ ++ mpi_cmd.handle_flag = 1; ++ mpi_cmd.mmu_info.mmu_en = 0; ++ mpi_cmd.mmu_info.mmu_flag = 0; ++ ++ if (DEBUGGER_EN(MSG)) ++ rga_cmd_print_debug_info(&mpi_cmd); ++ ++ ret = rga_request_mpi_submit(&mpi_cmd, request); ++ if (ret < 0) { ++ if (ret == -ERESTARTSYS) { ++ if (DEBUGGER_EN(MSG)) ++ pr_err("%s, commit mpi job failed, by a software interrupt.\n", ++ __func__); ++ } else { ++ pr_err("%s, commit mpi job failed\n", __func__); ++ } ++ ++ goto err_put_request; ++ } ++ ++ if ((mpi_job->dma_buf_src0 != NULL) && (mpi_cmd.src.yrgb_addr > 0)) ++ rga_mm_release_buffer(mpi_cmd.src.yrgb_addr); ++ if ((mpi_job->dma_buf_src1 != NULL) && (mpi_cmd.pat.yrgb_addr > 0)) ++ rga_mm_release_buffer(mpi_cmd.pat.yrgb_addr); ++ if ((mpi_job->dma_buf_dst != NULL) && (mpi_cmd.dst.yrgb_addr > 0)) ++ rga_mm_release_buffer(mpi_cmd.dst.yrgb_addr); ++ ++ /* copy dst info to mpi job for next node */ ++ if (mpi_job->output != NULL) { ++ mpi_job->output->x_offset = mpi_cmd.dst.x_offset; ++ mpi_job->output->y_offset = mpi_cmd.dst.y_offset; ++ mpi_job->output->width = mpi_cmd.dst.act_w; ++ mpi_job->output->height = mpi_cmd.dst.act_h; ++ mpi_job->output->vir_w = mpi_cmd.dst.vir_w; ++ mpi_job->output->vir_h = mpi_cmd.dst.vir_h; ++ mpi_job->output->rd_mode = mpi_cmd.dst.rd_mode; ++ mpi_job->output->format = mpi_cmd.dst.format; ++ } ++ ++ return 0; ++ ++err_put_request: ++ mutex_lock(&request_manager->lock); ++ rga_request_put(request); ++ mutex_unlock(&request_manager->lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(rga_mpi_commit); ++ ++int rga_kernel_commit(struct rga_req *cmd) ++{ ++ int ret = 0; ++ int request_id; ++ struct rga_user_request kernel_request; ++ struct rga_request *request = NULL; ++ struct rga_session *session = NULL; ++ struct rga_pending_request_manager *request_manager = rga_drvdata->pend_request_manager; ++ ++ session = rga_session_init(); ++ if (IS_ERR(session)) ++ return PTR_ERR(session); ++ ++ request_id = rga_request_alloc(0, session); ++ if (request_id < 0) { ++ pr_err("request alloc error!\n"); ++ ret = request_id; ++ return ret; ++ } ++ ++ memset(&kernel_request, 0, sizeof(kernel_request)); ++ kernel_request.id = request_id; ++ kernel_request.task_ptr = (uint64_t)(unsigned long)cmd; ++ kernel_request.task_num = 1; ++ kernel_request.sync_mode = RGA_BLIT_SYNC; ++ ++ ret = rga_request_check(&kernel_request); ++ if (ret < 0) { ++ pr_err("user request check error!\n"); ++ goto err_free_request_by_id; ++ } ++ ++ request = rga_request_kernel_config(&kernel_request); ++ if (IS_ERR(request)) { ++ pr_err("request[%d] config failed!\n", kernel_request.id); ++ ret = -EFAULT; ++ goto err_free_request_by_id; ++ } ++ ++ if (DEBUGGER_EN(MSG)) { ++ pr_info("kernel blit mode: request id = %d", kernel_request.id); ++ rga_cmd_print_debug_info(cmd); ++ } ++ ++ ret = rga_request_submit(request); ++ if (ret < 0) { ++ pr_err("request[%d] submit failed!\n", kernel_request.id); ++ goto err_put_request; ++ } ++ ++err_put_request: ++ mutex_lock(&request_manager->lock); ++ rga_request_put(request); ++ mutex_unlock(&request_manager->lock); ++ ++ rga_session_deinit(session); ++ ++ return ret; ++ ++err_free_request_by_id: ++ mutex_lock(&request_manager->lock); ++ ++ request = rga_request_lookup(request_manager, request_id); ++ if (IS_ERR_OR_NULL(request)) { ++ pr_err("can not find request from id[%d]", request_id); ++ mutex_unlock(&request_manager->lock); ++ return -EINVAL; ++ } ++ ++ rga_request_free(request); ++ ++ mutex_unlock(&request_manager->lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(rga_kernel_commit); ++ ++static enum hrtimer_restart hrtimer_handler(struct hrtimer *timer) ++{ ++ struct rga_drvdata_t *rga = rga_drvdata; ++ struct rga_scheduler_t *scheduler = NULL; ++ struct rga_job *job = NULL; ++ unsigned long flags; ++ int i; ++ ++ ktime_t now = ktime_get(); ++ ++ for (i = 0; i < rga->num_of_scheduler; i++) { ++ scheduler = rga->scheduler[i]; ++ ++ spin_lock_irqsave(&scheduler->irq_lock, flags); ++ ++ /* if timer action on job running */ ++ job = scheduler->running_job; ++ if (job) { ++ scheduler->timer.busy_time += ktime_us_delta(now, job->hw_recoder_time); ++ job->hw_recoder_time = now; ++ } ++ ++ scheduler->timer.busy_time_record = scheduler->timer.busy_time; ++ scheduler->timer.busy_time = 0; ++ ++ spin_unlock_irqrestore(&scheduler->irq_lock, flags); ++ } ++ ++ hrtimer_forward_now(timer, kt); ++ return HRTIMER_RESTART; ++} ++ ++static void rga_init_timer(void) ++{ ++ kt = ktime_set(0, RGA_TIMER_INTERVAL_NS); ++ hrtimer_setup(&timer, hrtimer_handler, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ++ ++ hrtimer_start(&timer, kt, HRTIMER_MODE_REL); ++} ++ ++static void rga_cancel_timer(void) ++{ ++ hrtimer_cancel(&timer); ++} ++ ++#ifndef RGA_DISABLE_PM ++int rga_power_enable(struct rga_scheduler_t *scheduler) ++{ ++ int ret = -EINVAL; ++ int i; ++ unsigned long flags; ++ ++ pm_runtime_get_sync(scheduler->dev); ++ pm_stay_awake(scheduler->dev); ++ ++ for (i = 0; i < scheduler->num_clks; i++) { ++ if (!IS_ERR(scheduler->clks[i])) { ++ ret = clk_prepare_enable(scheduler->clks[i]); ++ if (ret < 0) ++ goto err_enable_clk; ++ } ++ } ++ ++ spin_lock_irqsave(&scheduler->irq_lock, flags); ++ ++ scheduler->pd_refcount++; ++ if (scheduler->status == RGA_SCHEDULER_IDLE) ++ scheduler->status = RGA_SCHEDULER_WORKING; ++ ++ spin_unlock_irqrestore(&scheduler->irq_lock, flags); ++ ++ return 0; ++ ++err_enable_clk: ++ for (--i; i >= 0; --i) ++ if (!IS_ERR(scheduler->clks[i])) ++ clk_disable_unprepare(scheduler->clks[i]); ++ ++ pm_relax(scheduler->dev); ++ pm_runtime_put_sync_suspend(scheduler->dev); ++ ++ return ret; ++} ++ ++int rga_power_disable(struct rga_scheduler_t *scheduler) ++{ ++ int i; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&scheduler->irq_lock, flags); ++ ++ if (scheduler->status == RGA_SCHEDULER_IDLE || ++ scheduler->pd_refcount == 0) { ++ spin_unlock_irqrestore(&scheduler->irq_lock, flags); ++ WARN(true, "%s already idle!\n", dev_driver_string(scheduler->dev)); ++ return -1; ++ } ++ ++ scheduler->pd_refcount--; ++ if (scheduler->pd_refcount == 0) ++ scheduler->status = RGA_SCHEDULER_IDLE; ++ ++ spin_unlock_irqrestore(&scheduler->irq_lock, flags); ++ ++ for (i = scheduler->num_clks - 1; i >= 0; i--) ++ if (!IS_ERR(scheduler->clks[i])) ++ clk_disable_unprepare(scheduler->clks[i]); ++ ++ pm_relax(scheduler->dev); ++ pm_runtime_put_sync_suspend(scheduler->dev); ++ ++ return 0; ++} ++ ++static void rga_power_enable_all(void) ++{ ++ struct rga_scheduler_t *scheduler = NULL; ++ int ret = 0; ++ int i; ++ ++ for (i = 0; i < rga_drvdata->num_of_scheduler; i++) { ++ scheduler = rga_drvdata->scheduler[i]; ++ ret = rga_power_enable(scheduler); ++ if (ret < 0) ++ pr_err("power enable failed"); ++ } ++} ++ ++static void rga_power_disable_all(void) ++{ ++ struct rga_scheduler_t *scheduler = NULL; ++ int i; ++ ++ for (i = 0; i < rga_drvdata->num_of_scheduler; i++) { ++ scheduler = rga_drvdata->scheduler[i]; ++ rga_power_disable(scheduler); ++ } ++} ++ ++#else ++int rga_power_enable(struct rga_scheduler_t *scheduler) ++{ ++ return 0; ++} ++ ++int rga_power_disable(struct rga_scheduler_t *scheduler) ++{ ++ return 0; ++} ++ ++static inline void rga_power_enable_all(void) {} ++static inline void rga_power_disable_all(void) {} ++#endif /* #ifndef RGA_DISABLE_PM */ ++ ++static int rga_session_manager_init(struct rga_session_manager **session_manager_ptr) ++{ ++ struct rga_session_manager *session_manager = NULL; ++ ++ *session_manager_ptr = kzalloc(sizeof(struct rga_session_manager), GFP_KERNEL); ++ if (*session_manager_ptr == NULL) { ++ pr_err("can not kzalloc for rga_session_manager\n"); ++ return -ENOMEM; ++ } ++ ++ session_manager = *session_manager_ptr; ++ ++ mutex_init(&session_manager->lock); ++ ++ idr_init_base(&session_manager->ctx_id_idr, 1); ++ ++ return 0; ++} ++ ++/* ++ * Called at driver close to release the rga session's id references. ++ */ ++static int rga_session_free_remove_idr_cb(int id, void *ptr, void *data) ++{ ++ struct rga_session *session = ptr; ++ ++ idr_remove(&rga_drvdata->session_manager->ctx_id_idr, session->id); ++ kfree(session); ++ ++ return 0; ++} ++ ++static int rga_session_free_remove_idr(struct rga_session *session) ++{ ++ struct rga_session_manager *session_manager; ++ ++ session_manager = rga_drvdata->session_manager; ++ ++ mutex_lock(&session_manager->lock); ++ ++ session_manager->session_cnt--; ++ idr_remove(&session_manager->ctx_id_idr, session->id); ++ ++ mutex_unlock(&session_manager->lock); ++ ++ return 0; ++} ++ ++static int rga_session_manager_remove(struct rga_session_manager **session_manager_ptr) ++{ ++ struct rga_session_manager *session_manager = *session_manager_ptr; ++ ++ mutex_lock(&session_manager->lock); ++ ++ idr_for_each(&session_manager->ctx_id_idr, &rga_session_free_remove_idr_cb, session_manager); ++ idr_destroy(&session_manager->ctx_id_idr); ++ ++ mutex_unlock(&session_manager->lock); ++ ++ kfree(*session_manager_ptr); ++ ++ *session_manager_ptr = NULL; ++ ++ return 0; ++} ++ ++static struct rga_session *rga_session_init(void) ++{ ++ int new_id; ++ ++ struct rga_session_manager *session_manager = NULL; ++ struct rga_session *session = NULL; ++ ++ session_manager = rga_drvdata->session_manager; ++ if (session_manager == NULL) { ++ pr_err("rga_session_manager is null!\n"); ++ return ERR_PTR(-EFAULT); ++ } ++ ++ session = kzalloc(sizeof(*session), GFP_KERNEL); ++ if (!session) { ++ pr_err("rga_session alloc failed\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ mutex_lock(&session_manager->lock); ++ ++ idr_preload(GFP_KERNEL); ++ new_id = idr_alloc_cyclic(&session_manager->ctx_id_idr, session, 1, 0, GFP_NOWAIT); ++ idr_preload_end(); ++ if (new_id < 0) { ++ mutex_unlock(&session_manager->lock); ++ ++ pr_err("rga_session alloc id failed!\n"); ++ kfree(session); ++ return ERR_PTR(new_id); ++ } ++ ++ session->id = new_id; ++ session_manager->session_cnt++; ++ ++ mutex_unlock(&session_manager->lock); ++ ++ session->tgid = current->tgid; ++ session->pname = kstrdup_quotable_cmdline(current, GFP_KERNEL); ++ ++ return session; ++} ++ ++static int rga_session_deinit(struct rga_session *session) ++{ ++ rga_request_session_destroy_abort(session); ++ rga_mm_session_release_buffer(session); ++ ++ rga_session_free_remove_idr(session); ++ ++ kfree(session->pname); ++ kfree(session); ++ ++ return 0; ++} ++ ++static long rga_ioctl_import_buffer(unsigned long arg, struct rga_session *session) ++{ ++ int i; ++ int ret = 0; ++ struct rga_buffer_pool buffer_pool; ++ struct rga_external_buffer *external_buffer = NULL; ++ ++ if (unlikely(copy_from_user(&buffer_pool, ++ (struct rga_buffer_pool *)arg, ++ sizeof(buffer_pool)))) { ++ pr_err("rga_buffer_pool copy_from_user failed!\n"); ++ return -EFAULT; ++ } ++ ++ if (buffer_pool.size > RGA_BUFFER_POOL_SIZE_MAX) { ++ pr_err("Cannot import more than %d buffers at a time!\n", ++ RGA_BUFFER_POOL_SIZE_MAX); ++ return -EFBIG; ++ } ++ ++ if (buffer_pool.buffers_ptr == 0) { ++ pr_err("Import buffers is NULL!\n"); ++ return -EFAULT; ++ } ++ ++ external_buffer = kmalloc(sizeof(struct rga_external_buffer) * buffer_pool.size, ++ GFP_KERNEL); ++ if (external_buffer == NULL) { ++ pr_err("external buffer list alloc error!\n"); ++ return -ENOMEM; ++ } ++ ++ if (unlikely(copy_from_user(external_buffer, ++ u64_to_user_ptr(buffer_pool.buffers_ptr), ++ sizeof(struct rga_external_buffer) * buffer_pool.size))) { ++ pr_err("rga_buffer_pool external_buffer list copy_from_user failed\n"); ++ ret = -EFAULT; ++ ++ goto err_free_external_buffer; ++ } ++ ++ for (i = 0; i < buffer_pool.size; i++) { ++ if (DEBUGGER_EN(MSG)) { ++ pr_info("import buffer info:\n"); ++ rga_dump_external_buffer(&external_buffer[i]); ++ } ++ ++ ret = rga_mm_import_buffer(&external_buffer[i], session); ++ if (ret <= 0) { ++ pr_err("buffer[%d] mm import buffer failed! memory = 0x%lx, type = %s(0x%x)\n", ++ i, (unsigned long)external_buffer[i].memory, ++ rga_get_memory_type_str(external_buffer[i].type), ++ external_buffer[i].type); ++ ++ goto err_free_external_buffer; ++ } ++ ++ external_buffer[i].handle = ret; ++ } ++ ++ if (unlikely(copy_to_user(u64_to_user_ptr(buffer_pool.buffers_ptr), ++ external_buffer, ++ sizeof(struct rga_external_buffer) * buffer_pool.size))) { ++ pr_err("rga_buffer_pool external_buffer list copy_to_user failed\n"); ++ ret = -EFAULT; ++ ++ goto err_free_external_buffer; ++ } ++ ++err_free_external_buffer: ++ kfree(external_buffer); ++ return ret; ++} ++ ++static long rga_ioctl_release_buffer(unsigned long arg) ++{ ++ int i; ++ int ret = 0; ++ struct rga_buffer_pool buffer_pool; ++ struct rga_external_buffer *external_buffer = NULL; ++ ++ if (unlikely(copy_from_user(&buffer_pool, ++ (struct rga_buffer_pool *)arg, ++ sizeof(buffer_pool)))) { ++ pr_err("rga_buffer_pool copy_from_user failed!\n"); ++ return -EFAULT; ++ } ++ ++ if (buffer_pool.size > RGA_BUFFER_POOL_SIZE_MAX) { ++ pr_err("Cannot release more than %d buffers at a time!\n", ++ RGA_BUFFER_POOL_SIZE_MAX); ++ return -EFBIG; ++ } ++ ++ if (buffer_pool.buffers_ptr == 0) { ++ pr_err("Release buffers is NULL!\n"); ++ return -EFAULT; ++ } ++ ++ external_buffer = kmalloc(sizeof(struct rga_external_buffer) * buffer_pool.size, ++ GFP_KERNEL); ++ if (external_buffer == NULL) { ++ pr_err("external buffer list alloc error!\n"); ++ return -ENOMEM; ++ } ++ ++ if (unlikely(copy_from_user(external_buffer, ++ u64_to_user_ptr(buffer_pool.buffers_ptr), ++ sizeof(struct rga_external_buffer) * buffer_pool.size))) { ++ pr_err("rga_buffer_pool external_buffer list copy_from_user failed\n"); ++ ret = -EFAULT; ++ ++ goto err_free_external_buffer; ++ } ++ ++ for (i = 0; i < buffer_pool.size; i++) { ++ if (DEBUGGER_EN(MSG)) ++ pr_info("release buffer handle[%d]\n", external_buffer[i].handle); ++ ++ ret = rga_mm_release_buffer(external_buffer[i].handle); ++ if (ret < 0) { ++ pr_err("buffer[%d] mm release buffer failed! handle = %d\n", ++ i, external_buffer[i].handle); ++ ++ goto err_free_external_buffer; ++ } ++ } ++ ++err_free_external_buffer: ++ kfree(external_buffer); ++ return ret; ++} ++ ++static long rga_ioctl_request_create(unsigned long arg, struct rga_session *session) ++{ ++ uint32_t id; ++ uint32_t flags; ++ ++ if (copy_from_user(&flags, (void *)arg, sizeof(uint32_t))) { ++ pr_err("%s failed to copy from usrer!\n", __func__); ++ return -EFAULT; ++ } ++ ++ id = rga_request_alloc(flags, session); ++ ++ if (copy_to_user((void *)arg, &id, sizeof(uint32_t))) { ++ pr_err("%s failed to copy to usrer!\n", __func__); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++static long rga_ioctl_request_submit(unsigned long arg, bool run_enbale) ++{ ++ int ret = 0; ++ struct rga_pending_request_manager *request_manager = NULL; ++ struct rga_user_request user_request; ++ struct rga_request *request = NULL; ++ ++ request_manager = rga_drvdata->pend_request_manager; ++ ++ if (unlikely(copy_from_user(&user_request, ++ (struct rga_user_request *)arg, ++ sizeof(user_request)))) { ++ pr_err("%s copy_from_user failed!\n", __func__); ++ return -EFAULT; ++ } ++ ++ ret = rga_request_check(&user_request); ++ if (ret < 0) { ++ pr_err("user request check error!\n"); ++ return ret; ++ } ++ ++ if (DEBUGGER_EN(MSG)) ++ pr_info("config request id = %d", user_request.id); ++ ++ request = rga_request_config(&user_request); ++ if (IS_ERR_OR_NULL(request)) { ++ pr_err("request[%d] config failed!\n", user_request.id); ++ return -EFAULT; ++ } ++ ++ if (run_enbale) { ++ ret = rga_request_submit(request); ++ if (ret < 0) { ++ pr_err("request[%d] submit failed!\n", user_request.id); ++ return -EFAULT; ++ } ++ ++ if (request->sync_mode == RGA_BLIT_ASYNC) { ++ user_request.release_fence_fd = request->release_fence_fd; ++ if (copy_to_user((struct rga_req *)arg, ++ &user_request, sizeof(user_request))) { ++ pr_err("copy_to_user failed\n"); ++ return -EFAULT; ++ } ++ } ++ } ++ ++ mutex_lock(&request_manager->lock); ++ rga_request_put(request); ++ mutex_unlock(&request_manager->lock); ++ ++ return 0; ++} ++ ++static long rga_ioctl_request_cancel(unsigned long arg) ++{ ++ uint32_t id; ++ struct rga_pending_request_manager *request_manager; ++ struct rga_request *request; ++ ++ request_manager = rga_drvdata->pend_request_manager; ++ if (request_manager == NULL) { ++ pr_err("rga_pending_request_manager is null!\n"); ++ return -EFAULT; ++ } ++ ++ if (unlikely(copy_from_user(&id, (uint32_t *)arg, sizeof(uint32_t)))) { ++ pr_err("request id copy_from_user failed!\n"); ++ return -EFAULT; ++ } ++ ++ if (DEBUGGER_EN(MSG)) ++ pr_info("config cancel request id = %d", id); ++ ++ mutex_lock(&request_manager->lock); ++ ++ request = rga_request_lookup(request_manager, id); ++ if (IS_ERR_OR_NULL(request)) { ++ pr_err("can not find request from id[%d]", id); ++ mutex_unlock(&request_manager->lock); ++ return -EINVAL; ++ } ++ ++ rga_request_put(request); ++ ++ mutex_unlock(&request_manager->lock); ++ ++ return 0; ++} ++ ++static long rga_ioctl_blit(unsigned long arg, uint32_t cmd, struct rga_session *session) ++{ ++ int ret = 0; ++ int request_id; ++ struct rga_user_request user_request; ++ struct rga_req *rga_req; ++ struct rga_request *request = NULL; ++ struct rga_pending_request_manager *request_manager = rga_drvdata->pend_request_manager; ++ ++ request_id = rga_request_alloc(0, session); ++ if (request_id < 0) { ++ pr_err("request alloc error!\n"); ++ ret = request_id; ++ return ret; ++ } ++ ++ memset(&user_request, 0, sizeof(user_request)); ++ user_request.id = request_id; ++ user_request.task_ptr = arg; ++ user_request.task_num = 1; ++ user_request.sync_mode = cmd; ++ ++ ret = rga_request_check(&user_request); ++ if (ret < 0) { ++ pr_err("user request check error!\n"); ++ goto err_free_request_by_id; ++ } ++ ++ request = rga_request_config(&user_request); ++ if (IS_ERR(request)) { ++ pr_err("request[%d] config failed!\n", user_request.id); ++ ret = -EFAULT; ++ goto err_free_request_by_id; ++ } ++ ++ rga_req = request->task_list; ++ /* In the BLIT_SYNC/BLIT_ASYNC command, in_fence_fd needs to be set. */ ++ request->acquire_fence_fd = rga_req->in_fence_fd; ++ ++ ret = rga_request_submit(request); ++ if (ret < 0) { ++ pr_err("request[%d] submit failed!\n", user_request.id); ++ goto err_put_request; ++ } ++ ++ if (request->sync_mode == RGA_BLIT_ASYNC) { ++ rga_req->out_fence_fd = request->release_fence_fd; ++ if (copy_to_user((struct rga_req *)arg, rga_req, sizeof(struct rga_req))) { ++ pr_err("copy_to_user failed\n"); ++ ret = -EFAULT; ++ goto err_put_request; ++ } ++ } ++ ++err_put_request: ++ mutex_lock(&request_manager->lock); ++ rga_request_put(request); ++ mutex_unlock(&request_manager->lock); ++ ++ return ret; ++ ++err_free_request_by_id: ++ mutex_lock(&request_manager->lock); ++ ++ request = rga_request_lookup(request_manager, request_id); ++ if (IS_ERR_OR_NULL(request)) { ++ pr_err("can not find request from id[%d]", request_id); ++ mutex_unlock(&request_manager->lock); ++ return -EINVAL; ++ } ++ ++ rga_request_free(request); ++ ++ mutex_unlock(&request_manager->lock); ++ ++ return ret; ++} ++ ++static long rga_ioctl(struct file *file, uint32_t cmd, unsigned long arg) ++{ ++ int ret = 0; ++ int i = 0; ++ int major_version = 0, minor_version = 0; ++ char version[16] = { 0 }; ++ struct rga_version_t driver_version; ++ struct rga_hw_versions_t hw_versions; ++ struct rga_drvdata_t *rga = rga_drvdata; ++ struct rga_session *session = file->private_data; ++ ++ if (!rga) { ++ pr_err("rga_drvdata is null, rga is not init\n"); ++ return -ENODEV; ++ } ++ ++ if (DEBUGGER_EN(NONUSE)) ++ return 0; ++ ++ switch (cmd) { ++ case RGA_BLIT_SYNC: ++ case RGA_BLIT_ASYNC: ++ ret = rga_ioctl_blit(arg, cmd, session); ++ ++ break; ++ case RGA_CACHE_FLUSH: ++ case RGA_FLUSH: ++ case RGA_GET_RESULT: ++ break; ++ case RGA_GET_VERSION: ++ sscanf(rga->scheduler[i]->version.str, "%x.%x.%*x", ++ &major_version, &minor_version); ++ snprintf(version, 5, "%x.%02x", major_version, minor_version); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) ++ /* TODO: userspcae to get version */ ++ if (copy_to_user((void *)arg, version, sizeof(version))) ++ ret = -EFAULT; ++#else ++ if (copy_to_user((void *)arg, RGA3_VERSION, ++ sizeof(RGA3_VERSION))) ++ ret = -EFAULT; ++#endif ++ break; ++ case RGA2_GET_VERSION: ++ for (i = 0; i < rga->num_of_scheduler; i++) { ++ if (rga->scheduler[i]->ops == &rga2_ops) { ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) ++ if (copy_to_user((void *)arg, rga->scheduler[i]->version.str, ++ sizeof(rga->scheduler[i]->version.str))) ++ ret = -EFAULT; ++#else ++ if (copy_to_user((void *)arg, RGA3_VERSION, ++ sizeof(RGA3_VERSION))) ++ ret = -EFAULT; ++#endif ++ else ++ ret = true; ++ ++ break; ++ } ++ } ++ ++ /* This will indicate that the RGA2 version number cannot be obtained. */ ++ if (ret != true) ++ ret = -EFAULT; ++ ++ break; ++ ++ case RGA_IOC_GET_HW_VERSION: ++ /* RGA hardware version */ ++ hw_versions.size = rga->num_of_scheduler > RGA_HW_SIZE ? ++ RGA_HW_SIZE : rga->num_of_scheduler; ++ ++ for (i = 0; i < hw_versions.size; i++) { ++ memcpy(&hw_versions.version[i], &rga->scheduler[i]->version, ++ sizeof(rga->scheduler[i]->version)); ++ } ++ ++ if (copy_to_user((void *)arg, &hw_versions, sizeof(hw_versions))) ++ ret = -EFAULT; ++ else ++ ret = true; ++ ++ break; ++ ++ case RGA_IOC_GET_DRVIER_VERSION: ++ /* Driver version */ ++ driver_version.major = DRIVER_MAJOR_VERISON; ++ driver_version.minor = DRIVER_MINOR_VERSION; ++ driver_version.revision = DRIVER_REVISION_VERSION; ++ strncpy((char *)driver_version.str, DRIVER_VERSION, sizeof(driver_version.str)); ++ ++ if (copy_to_user((void *)arg, &driver_version, sizeof(driver_version))) ++ ret = -EFAULT; ++ else ++ ret = true; ++ ++ break; ++ ++ case RGA_IOC_IMPORT_BUFFER: ++ rga_power_enable_all(); ++ ++ ret = rga_ioctl_import_buffer(arg, session); ++ ++ rga_power_disable_all(); ++ ++ break; ++ ++ case RGA_IOC_RELEASE_BUFFER: ++ rga_power_enable_all(); ++ ++ ret = rga_ioctl_release_buffer(arg); ++ ++ rga_power_disable_all(); ++ ++ break; ++ ++ case RGA_IOC_REQUEST_CREATE: ++ ret = rga_ioctl_request_create(arg, session); ++ ++ break; ++ ++ case RGA_IOC_REQUEST_SUBMIT: ++ ret = rga_ioctl_request_submit(arg, true); ++ ++ break; ++ ++ case RGA_IOC_REQUEST_CONFIG: ++ ret = rga_ioctl_request_submit(arg, false); ++ ++ break; ++ ++ case RGA_IOC_REQUEST_CANCEL: ++ ret = rga_ioctl_request_cancel(arg); ++ ++ break; ++ ++ case RGA_IMPORT_DMA: ++ case RGA_RELEASE_DMA: ++ default: ++ pr_err("unknown ioctl cmd!\n"); ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++#ifdef CONFIG_ROCKCHIP_RGA_DEBUGGER ++static int rga_debugger_init(struct rga_debugger **debugger_p) ++{ ++ struct rga_debugger *debugger; ++ ++ *debugger_p = kzalloc(sizeof(struct rga_debugger), GFP_KERNEL); ++ if (*debugger_p == NULL) { ++ pr_err("can not alloc for rga debugger\n"); ++ return -ENOMEM; ++ } ++ ++ debugger = *debugger_p; ++ ++#ifdef CONFIG_ROCKCHIP_RGA_DEBUG_FS ++ mutex_init(&debugger->debugfs_lock); ++ INIT_LIST_HEAD(&debugger->debugfs_entry_list); ++#endif ++ ++#ifdef CONFIG_ROCKCHIP_RGA_PROC_FS ++ mutex_init(&debugger->procfs_lock); ++ INIT_LIST_HEAD(&debugger->procfs_entry_list); ++#endif ++ ++ rga_debugfs_init(); ++ rga_procfs_init(); ++ ++ return 0; ++} ++ ++static int rga_debugger_remove(struct rga_debugger **debugger_p) ++{ ++ rga_debugfs_remove(); ++ rga_procfs_remove(); ++ ++ kfree(*debugger_p); ++ *debugger_p = NULL; ++ ++ return 0; ++} ++#endif ++ ++static int rga_open(struct inode *inode, struct file *file) ++{ ++ struct rga_session *session = NULL; ++ ++ session = rga_session_init(); ++ if (IS_ERR(session)) ++ return PTR_ERR(session); ++ ++ file->private_data = (void *)session; ++ ++ return nonseekable_open(inode, file); ++} ++ ++static int rga_release(struct inode *inode, struct file *file) ++{ ++ struct rga_session *session = file->private_data; ++ ++ rga_session_deinit(session); ++ ++ return 0; ++} ++ ++static irqreturn_t rga_irq_handler(int irq, void *data) ++{ ++ irqreturn_t irq_ret = IRQ_NONE; ++ struct rga_scheduler_t *scheduler = data; ++ ++ if (scheduler->ops->irq) ++ irq_ret = scheduler->ops->irq(scheduler); ++ ++ return irq_ret; ++} ++ ++static irqreturn_t rga_isr_thread(int irq, void *data) ++{ ++ irqreturn_t irq_ret = IRQ_NONE; ++ struct rga_scheduler_t *scheduler = data; ++ struct rga_job *job; ++ ++ job = rga_job_done(scheduler); ++ if (job == NULL) { ++ pr_err("isr thread invalid job!\n"); ++ return IRQ_HANDLED; ++ } ++ ++ if (scheduler->ops->isr_thread) ++ irq_ret = scheduler->ops->isr_thread(job, scheduler); ++ ++ rga_request_release_signal(scheduler, job); ++ ++ rga_job_next(scheduler); ++ ++ rga_power_disable(scheduler); ++ ++ return irq_ret; ++} ++ ++const struct file_operations rga_fops = { ++ .owner = THIS_MODULE, ++ .open = rga_open, ++ .release = rga_release, ++ .unlocked_ioctl = rga_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = rga_ioctl, ++#endif ++}; ++ ++static struct miscdevice rga_dev = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = "rga", ++ .fops = &rga_fops, ++}; ++ ++static const char *const old_rga2_clks[] = { ++ "aclk_rga", ++ "hclk_rga", ++ "clk_rga", ++}; ++ ++static const char *const rk3588_rga2_clks[] = { ++ "aclk_rga2", ++ "hclk_rga2", ++ "clk_rga2", ++}; ++ ++static const char *const rga3_core_0_clks[] = { ++ "aclk_rga3_0", ++ "hclk_rga3_0", ++ "clk_rga3_0", ++}; ++ ++static const char *const rga3_core_1_clks[] = { ++ "aclk_rga3_1", ++ "hclk_rga3_1", ++ "clk_rga3_1", ++}; ++ ++static const struct rga_match_data_t old_rga2_match_data = { ++ .clks = old_rga2_clks, ++ .num_clks = ARRAY_SIZE(old_rga2_clks), ++}; ++ ++static const struct rga_match_data_t rk3588_rga2_match_data = { ++ .clks = rk3588_rga2_clks, ++ .num_clks = ARRAY_SIZE(rk3588_rga2_clks), ++}; ++ ++static const struct rga_match_data_t rga3_core0_match_data = { ++ .clks = rga3_core_0_clks, ++ .num_clks = ARRAY_SIZE(rga3_core_0_clks), ++}; ++ ++static const struct rga_match_data_t rga3_core1_match_data = { ++ .clks = rga3_core_1_clks, ++ .num_clks = ARRAY_SIZE(rga3_core_1_clks), ++}; ++ ++static const struct of_device_id rga3_core0_dt_ids[] = { ++ { ++ .compatible = "rockchip,rga3_core0", ++ .data = &rga3_core0_match_data, ++ }, ++ {}, ++}; ++ ++static const struct of_device_id rga3_core1_dt_ids[] = { ++ { ++ .compatible = "rockchip,rga3_core1", ++ .data = &rga3_core1_match_data, ++ }, ++ {}, ++}; ++ ++static const struct of_device_id rga2_dt_ids[] = { ++ { ++ .compatible = "rockchip,rga2_core0", ++ .data = &rk3588_rga2_match_data, ++ }, ++ { ++ .compatible = "rockchip,rga2", ++ .data = &old_rga2_match_data, ++ }, ++ {}, ++}; ++ ++static void init_scheduler(struct rga_scheduler_t *scheduler, ++ const char *name) ++{ ++ spin_lock_init(&scheduler->irq_lock); ++ INIT_LIST_HEAD(&scheduler->todo_list); ++ init_waitqueue_head(&scheduler->job_done_wq); ++ ++ if (!strcmp(name, "rga3_core0")) { ++ scheduler->ops = &rga3_ops; ++ /* TODO: get by hw version */ ++ scheduler->core = RGA3_SCHEDULER_CORE0; ++ } else if (!strcmp(name, "rga3_core1")) { ++ scheduler->ops = &rga3_ops; ++ scheduler->core = RGA3_SCHEDULER_CORE1; ++ } else if (!strcmp(name, "rga2")) { ++ scheduler->ops = &rga2_ops; ++ scheduler->core = RGA2_SCHEDULER_CORE0; ++ } ++} ++ ++static int rga_drv_probe(struct platform_device *pdev) ++{ ++#ifndef RGA_DISABLE_PM ++ int i; ++#endif ++ int ret = 0; ++ int irq; ++ struct resource *res; ++ const struct rga_match_data_t *match_data; ++ const struct of_device_id *match; ++ struct rga_scheduler_t *scheduler; ++ struct device *dev = &pdev->dev; ++ struct rga_drvdata_t *data = rga_drvdata; ++ ++ if (!dev->of_node) ++ return -EINVAL; ++ ++ if (!strcmp(dev_driver_string(dev), "rga3_core0")) ++ match = of_match_device(rga3_core0_dt_ids, dev); ++ else if (!strcmp(dev_driver_string(dev), "rga3_core1")) ++ match = of_match_device(rga3_core1_dt_ids, dev); ++ else if (!strcmp(dev_driver_string(dev), "rga2")) ++ match = of_match_device(rga2_dt_ids, dev); ++ else ++ match = NULL; ++ ++ if (!match) { ++ dev_err(dev, "%s missing DT entry!\n", dev_driver_string(dev)); ++ return -EINVAL; ++ } ++ ++ scheduler = devm_kzalloc(dev, sizeof(struct rga_scheduler_t), GFP_KERNEL); ++ if (scheduler == NULL) { ++ pr_err("failed to allocate scheduler. dev name = %s\n", dev_driver_string(dev)); ++ return -ENOMEM; ++ } ++ ++ init_scheduler(scheduler, dev_driver_string(dev)); ++ ++ scheduler->dev = dev; ++ ++ /* map the registers */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ pr_err("get memory resource failed.\n"); ++ return -ENXIO; ++ } ++ ++ scheduler->rga_base = devm_ioremap(dev, res->start, resource_size(res)); ++ if (!scheduler->rga_base) { ++ pr_err("ioremap failed\n"); ++ ret = -ENOENT; ++ return ret; ++ } ++ ++ /* get the IRQ */ ++ match_data = match->data; ++ ++ /* there are irq names in dts */ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ dev_err(dev, "no irq %s in dts\n", dev_driver_string(dev)); ++ return irq; ++ } ++ ++ scheduler->irq = irq; ++ ++ pr_info("%s, irq = %d, match scheduler\n", dev_driver_string(dev), irq); ++ ++ ret = devm_request_threaded_irq(dev, irq, ++ rga_irq_handler, ++ rga_isr_thread, ++ IRQF_SHARED, ++ dev_driver_string(dev), scheduler); ++ if (ret < 0) { ++ pr_err("request irq name: %s failed: %d\n", dev_driver_string(dev), ret); ++ return ret; ++ } ++ ++ ++#ifndef RGA_DISABLE_PM ++ /* clk init */ ++ for (i = 0; i < match_data->num_clks; i++) { ++ struct clk *clk = devm_clk_get(dev, match_data->clks[i]); ++ ++ if (IS_ERR(clk)) ++ pr_err("failed to get %s\n", match_data->clks[i]); ++ ++ scheduler->clks[i] = clk; ++ } ++ scheduler->num_clks = match_data->num_clks; ++ ++ /* PM init */ ++ device_init_wakeup(dev, true); ++ pm_runtime_enable(scheduler->dev); ++ ++ ret = pm_runtime_get_sync(scheduler->dev); ++ if (ret < 0) { ++ pr_err("failed to get pm runtime, ret = %d\n", ret); ++ goto pm_disable; ++ } ++ ++ for (i = 0; i < scheduler->num_clks; i++) { ++ if (!IS_ERR(scheduler->clks[i])) { ++ ret = clk_prepare_enable(scheduler->clks[i]); ++ if (ret < 0) { ++ pr_err("failed to enable clk\n"); ++ goto pm_disable; ++ } ++ } ++ } ++#endif /* #ifndef RGA_DISABLE_PM */ ++ ++ scheduler->ops->get_version(scheduler); ++ pr_info("%s hardware loaded successfully, hw_version:%s.\n", ++ dev_driver_string(dev), scheduler->version.str); ++ ++ /* TODO: get by hw version, Currently only supports judgment 1106. */ ++ if (scheduler->core == RGA3_SCHEDULER_CORE0 || ++ scheduler->core == RGA3_SCHEDULER_CORE1) { ++ scheduler->data = &rga3_data; ++ } else if (scheduler->core == RGA2_SCHEDULER_CORE0) { ++ if (!strcmp(scheduler->version.str, "3.3.87975")) ++ scheduler->data = &rga2e_1106_data; ++ else if (!strcmp(scheduler->version.str, "3.6.92812") || ++ !strcmp(scheduler->version.str, "3.7.93215")) ++ scheduler->data = &rga2e_iommu_data; ++ else ++ scheduler->data = &rga2e_data; ++ } ++ ++ data->scheduler[data->num_of_scheduler] = scheduler; ++ ++ data->num_of_scheduler++; ++ ++#ifndef RGA_DISABLE_PM ++ for (i = scheduler->num_clks - 1; i >= 0; i--) ++ if (!IS_ERR(scheduler->clks[i])) ++ clk_disable_unprepare(scheduler->clks[i]); ++ ++ pm_runtime_put_sync(dev); ++#endif /* #ifndef RGA_DISABLE_PM */ ++ ++ if (scheduler->data->mmu == RGA_IOMMU) { ++ scheduler->iommu_info = rga_iommu_probe(dev); ++ if (IS_ERR(scheduler->iommu_info)) { ++ dev_err(dev, "failed to attach iommu\n"); ++ scheduler->iommu_info = NULL; ++ } ++ } ++ ++ platform_set_drvdata(pdev, scheduler); ++ ++ pr_info("%s probe successfully\n", dev_driver_string(dev)); ++ ++ return 0; ++ ++#ifndef RGA_DISABLE_PM ++pm_disable: ++ device_init_wakeup(dev, false); ++ pm_runtime_disable(dev); ++#endif /* #ifndef RGA_DISABLE_PM */ ++ ++ return ret; ++} ++ ++static void rga_drv_remove(struct platform_device *pdev) ++{ ++#ifndef RGA_DISABLE_PM ++ device_init_wakeup(&pdev->dev, false); ++ pm_runtime_disable(&pdev->dev); ++#endif /* #ifndef RGA_DISABLE_PM */ ++ ++ return; ++} ++ ++static struct platform_driver rga3_core0_driver = { ++ .probe = rga_drv_probe, ++ .remove = rga_drv_remove, ++ .driver = { ++ .name = "rga3_core0", ++ .of_match_table = of_match_ptr(rga3_core0_dt_ids), ++ }, ++}; ++ ++static struct platform_driver rga3_core1_driver = { ++ .probe = rga_drv_probe, ++ .remove = rga_drv_remove, ++ .driver = { ++ .name = "rga3_core1", ++ .of_match_table = of_match_ptr(rga3_core1_dt_ids), ++ }, ++}; ++ ++static struct platform_driver rga2_driver = { ++ .probe = rga_drv_probe, ++ .remove = rga_drv_remove, ++ .driver = { ++ .name = "rga2", ++ .of_match_table = of_match_ptr(rga2_dt_ids), ++ }, ++}; ++ ++static int __init rga_init(void) ++{ ++ int ret; ++ ++ rga_drvdata = kzalloc(sizeof(struct rga_drvdata_t), GFP_KERNEL); ++ if (rga_drvdata == NULL) { ++ pr_err("failed to allocate driver data.\n"); ++ return -ENOMEM; ++ } ++ ++ mutex_init(&rga_drvdata->lock); ++ ++ ret = platform_driver_register(&rga3_core0_driver); ++ if (ret != 0) { ++ pr_err("Platform device rga3_core0_driver register failed (%d).\n", ret); ++ goto err_free_drvdata; ++ } ++ ++ ret = platform_driver_register(&rga3_core1_driver); ++ if (ret != 0) { ++ pr_err("Platform device rga3_core1_driver register failed (%d).\n", ret); ++ goto err_unregister_rga3_core0; ++ } ++ ++ ret = platform_driver_register(&rga2_driver); ++ if (ret != 0) { ++ pr_err("Platform device rga2_driver register failed (%d).\n", ret); ++ goto err_unregister_rga3_core1; ++ } ++ ++ ret = rga_iommu_bind(); ++ if (ret < 0) { ++ pr_err("rga iommu bind failed!\n"); ++ goto err_unregister_rga2; ++ } ++ ++ ret = misc_register(&rga_dev); ++ if (ret) { ++ pr_err("cannot register miscdev (%d)\n", ret); ++ goto err_unbind_iommu; ++ } ++ ++ rga_init_timer(); ++ ++ rga_mm_init(&rga_drvdata->mm); ++ ++ rga_request_manager_init(&rga_drvdata->pend_request_manager); ++ ++ rga_session_manager_init(&rga_drvdata->session_manager); ++ ++#ifdef CONFIG_ROCKCHIP_RGA_ASYNC ++ rga_fence_context_init(&rga_drvdata->fence_ctx); ++#endif ++ ++#ifdef CONFIG_ROCKCHIP_RGA_DEBUGGER ++ rga_debugger_init(&rga_drvdata->debugger); ++#endif ++ ++ pr_info("Module initialized. v%s\n", DRIVER_VERSION); ++ ++ return 0; ++ ++err_unbind_iommu: ++ rga_iommu_unbind(); ++ ++err_unregister_rga2: ++ platform_driver_unregister(&rga2_driver); ++ ++err_unregister_rga3_core1: ++ platform_driver_unregister(&rga3_core1_driver); ++ ++err_unregister_rga3_core0: ++ platform_driver_unregister(&rga3_core0_driver); ++ ++err_free_drvdata: ++ kfree(rga_drvdata); ++ ++ return ret; ++} ++ ++static void __exit rga_exit(void) ++{ ++#ifdef CONFIG_ROCKCHIP_RGA_DEBUGGER ++ rga_debugger_remove(&rga_drvdata->debugger); ++#endif ++ ++#ifdef CONFIG_ROCKCHIP_RGA_ASYNC ++ rga_fence_context_remove(&rga_drvdata->fence_ctx); ++#endif ++ ++ rga_mm_remove(&rga_drvdata->mm); ++ ++ rga_request_manager_remove(&rga_drvdata->pend_request_manager); ++ ++ rga_session_manager_remove(&rga_drvdata->session_manager); ++ ++ rga_cancel_timer(); ++ ++ rga_iommu_unbind(); ++ ++ platform_driver_unregister(&rga3_core0_driver); ++ platform_driver_unregister(&rga3_core1_driver); ++ platform_driver_unregister(&rga2_driver); ++ ++ misc_deregister(&rga_dev); ++ ++ kfree(rga_drvdata); ++ ++ pr_info("Module exited. v%s\n", DRIVER_VERSION); ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) ++#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT ++module_init(rga_init); ++#elif defined CONFIG_VIDEO_REVERSE_IMAGE ++fs_initcall(rga_init); ++#else ++late_initcall(rga_init); ++#endif ++#else ++fs_initcall(rga_init); ++#endif ++module_exit(rga_exit); ++ ++/* Module information */ ++MODULE_AUTHOR("putin.li@rock-chips.com"); ++MODULE_DESCRIPTION("Driver for rga device"); ++MODULE_LICENSE("GPL"); ++#ifdef MODULE_IMPORT_NS ++MODULE_IMPORT_NS("DMA_BUF"); ++#endif +diff --git a/drivers/video/rockchip/rga3/rga_fence.c b/drivers/video/rockchip/rga3/rga_fence.c +new file mode 100644 +index 000000000..7d831d55d +--- /dev/null ++++ b/drivers/video/rockchip/rga3/rga_fence.c +@@ -0,0 +1,146 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) Rockchip Electronics Co., Ltd. ++ * ++ * Author: Huang Lee ++ */ ++ ++#define pr_fmt(fmt) "rga_fence: " fmt ++ ++#include ++#include ++#include ++ ++#include "rga_drv.h" ++#include "rga_fence.h" ++ ++static const char *rga_fence_get_name(struct dma_fence *fence) ++{ ++ return DRIVER_NAME; ++} ++ ++static const struct dma_fence_ops rga_fence_ops = { ++ .get_driver_name = rga_fence_get_name, ++ .get_timeline_name = rga_fence_get_name, ++}; ++ ++int rga_fence_context_init(struct rga_fence_context **ctx) ++{ ++ struct rga_fence_context *fence_ctx = NULL; ++ ++ fence_ctx = kzalloc(sizeof(struct rga_fence_context), GFP_KERNEL); ++ if (!fence_ctx) { ++ pr_err("can not kzalloc for rga_fence_context!\n"); ++ return -ENOMEM; ++ } ++ ++ fence_ctx->context = dma_fence_context_alloc(1); ++ spin_lock_init(&fence_ctx->spinlock); ++ ++ *ctx = fence_ctx; ++ ++ return 0; ++} ++ ++void rga_fence_context_remove(struct rga_fence_context **ctx) ++{ ++ if (*ctx == NULL) ++ return; ++ ++ kfree(*ctx); ++ *ctx = NULL; ++} ++ ++struct dma_fence *rga_dma_fence_alloc(void) ++{ ++ struct rga_fence_context *fence_ctx = rga_drvdata->fence_ctx; ++ struct dma_fence *fence = NULL; ++ ++ if (fence_ctx == NULL) { ++ pr_err("fence_context is NULL!\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ fence = kzalloc(sizeof(*fence), GFP_KERNEL); ++ if (!fence) ++ return ERR_PTR(-ENOMEM); ++ ++ dma_fence_init(fence, &rga_fence_ops, &fence_ctx->spinlock, ++ fence_ctx->context, ++fence_ctx->seqno); ++ ++ return fence; ++} ++ ++int rga_dma_fence_get_fd(struct dma_fence *fence) ++{ ++ struct sync_file *sync_file = NULL; ++ int fence_fd = -1; ++ ++ if (!fence) ++ return -EINVAL; ++ ++ fence_fd = get_unused_fd_flags(O_CLOEXEC); ++ if (fence_fd < 0) ++ return fence_fd; ++ ++ sync_file = sync_file_create(fence); ++ if (!sync_file) { ++ put_unused_fd(fence_fd); ++ return -ENOMEM; ++ } ++ ++ fd_install(fence_fd, sync_file->file); ++ ++ return fence_fd; ++} ++ ++struct dma_fence *rga_get_dma_fence_from_fd(int fence_fd) ++{ ++ struct dma_fence *fence; ++ ++ fence = sync_file_get_fence(fence_fd); ++ if (!fence) ++ pr_err("can not get fence from fd\n"); ++ ++ return fence; ++} ++ ++int rga_dma_fence_wait(struct dma_fence *fence) ++{ ++ int ret = 0; ++ ++ ret = dma_fence_wait(fence, true); ++ ++ dma_fence_put(fence); ++ ++ return ret; ++} ++ ++int rga_dma_fence_add_callback(struct dma_fence *fence, dma_fence_func_t func, void *private) ++{ ++ int ret; ++ struct rga_fence_waiter *waiter = NULL; ++ ++ waiter = kmalloc(sizeof(*waiter), GFP_KERNEL); ++ if (!waiter) { ++ pr_err("%s: Failed to allocate waiter\n", __func__); ++ return -ENOMEM; ++ } ++ ++ waiter->private = private; ++ ++ ret = dma_fence_add_callback(fence, &waiter->waiter, func); ++ if (ret == -ENOENT) { ++ pr_err("'input fence' has been already signaled."); ++ goto err_free_waiter; ++ } else if (ret == -EINVAL) { ++ pr_err("%s: failed to add callback to dma_fence, err: %d\n", __func__, ret); ++ goto err_free_waiter; ++ } ++ ++ return ret; ++ ++err_free_waiter: ++ kfree(waiter); ++ return ret; ++} +diff --git a/drivers/video/rockchip/rga3/rga_hw_config.c b/drivers/video/rockchip/rga3/rga_hw_config.c +new file mode 100644 +index 000000000..0cf2599b9 +--- /dev/null ++++ b/drivers/video/rockchip/rga3/rga_hw_config.c +@@ -0,0 +1,352 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) Rockchip Electronics Co., Ltd. ++ * ++ * Author: ++ * Huang Lee ++ */ ++ ++#include "rga_hw_config.h" ++ ++/* RGA 1Word = 4Byte */ ++#define WORD_TO_BYTE(w) ((w) * 4) ++ ++const uint32_t rga3_input_raster_format[] = { ++ RGA_FORMAT_RGBA_8888, ++ RGA_FORMAT_BGRA_8888, ++ RGA_FORMAT_RGB_888, ++ RGA_FORMAT_BGR_888, ++ RGA_FORMAT_RGB_565, ++ RGA_FORMAT_BGR_565, ++ RGA_FORMAT_YCbCr_422_SP, ++ RGA_FORMAT_YCbCr_420_SP, ++ RGA_FORMAT_YCrCb_422_SP, ++ RGA_FORMAT_YCrCb_420_SP, ++ RGA_FORMAT_YVYU_422, ++ RGA_FORMAT_VYUY_422, ++ RGA_FORMAT_YUYV_422, ++ RGA_FORMAT_UYVY_422, ++ RGA_FORMAT_YCbCr_420_SP_10B, ++ RGA_FORMAT_YCrCb_420_SP_10B, ++ RGA_FORMAT_YCbCr_422_SP_10B, ++ RGA_FORMAT_YCrCb_422_SP_10B, ++ RGA_FORMAT_ARGB_8888, ++ RGA_FORMAT_ABGR_8888, ++}; ++ ++const uint32_t rga3_output_raster_format[] = { ++ RGA_FORMAT_RGBA_8888, ++ RGA_FORMAT_BGRA_8888, ++ RGA_FORMAT_RGB_888, ++ RGA_FORMAT_BGR_888, ++ RGA_FORMAT_RGB_565, ++ RGA_FORMAT_BGR_565, ++ RGA_FORMAT_YCbCr_422_SP, ++ RGA_FORMAT_YCbCr_420_SP, ++ RGA_FORMAT_YCrCb_422_SP, ++ RGA_FORMAT_YCrCb_420_SP, ++ RGA_FORMAT_YVYU_422, ++ RGA_FORMAT_VYUY_422, ++ RGA_FORMAT_YUYV_422, ++ RGA_FORMAT_UYVY_422, ++ RGA_FORMAT_YCbCr_420_SP_10B, ++ RGA_FORMAT_YCrCb_420_SP_10B, ++ RGA_FORMAT_YCbCr_422_SP_10B, ++ RGA_FORMAT_YCrCb_422_SP_10B, ++}; ++ ++const uint32_t rga3_fbcd_format[] = { ++ RGA_FORMAT_RGBA_8888, ++ RGA_FORMAT_BGRA_8888, ++ RGA_FORMAT_RGB_888, ++ RGA_FORMAT_BGR_888, ++ RGA_FORMAT_RGB_565, ++ RGA_FORMAT_BGR_565, ++ RGA_FORMAT_YCbCr_422_SP, ++ RGA_FORMAT_YCbCr_420_SP, ++ RGA_FORMAT_YCrCb_422_SP, ++ RGA_FORMAT_YCrCb_420_SP, ++ RGA_FORMAT_YCbCr_420_SP_10B, ++ RGA_FORMAT_YCrCb_420_SP_10B, ++ RGA_FORMAT_YCbCr_422_SP_10B, ++ RGA_FORMAT_YCrCb_422_SP_10B, ++}; ++ ++const uint32_t rga3_tile_format[] = { ++ RGA_FORMAT_YCbCr_422_SP, ++ RGA_FORMAT_YCbCr_420_SP, ++ RGA_FORMAT_YCrCb_422_SP, ++ RGA_FORMAT_YCrCb_420_SP, ++ RGA_FORMAT_YCbCr_420_SP_10B, ++ RGA_FORMAT_YCrCb_420_SP_10B, ++ RGA_FORMAT_YCbCr_422_SP_10B, ++ RGA_FORMAT_YCrCb_422_SP_10B, ++}; ++ ++const uint32_t rga2e_input_raster_format[] = { ++ RGA_FORMAT_RGBA_8888, ++ RGA_FORMAT_RGBX_8888, ++ RGA_FORMAT_BGRA_8888, ++ RGA_FORMAT_BGRX_8888, ++ RGA_FORMAT_RGB_888, ++ RGA_FORMAT_BGR_888, ++ RGA_FORMAT_RGB_565, ++ RGA_FORMAT_BGR_565, ++ RGA_FORMAT_YCbCr_422_P, ++ RGA_FORMAT_YCbCr_420_P, ++ RGA_FORMAT_YCrCb_422_P, ++ RGA_FORMAT_YCrCb_420_P, ++ RGA_FORMAT_YCbCr_422_SP, ++ RGA_FORMAT_YCbCr_420_SP, ++ RGA_FORMAT_YCrCb_422_SP, ++ RGA_FORMAT_YCrCb_420_SP, ++ RGA_FORMAT_YVYU_422, ++ RGA_FORMAT_VYUY_422, ++ RGA_FORMAT_YUYV_422, ++ RGA_FORMAT_UYVY_422, ++ RGA_FORMAT_YCbCr_420_SP_10B, ++ RGA_FORMAT_YCrCb_420_SP_10B, ++ RGA_FORMAT_YCbCr_422_SP_10B, ++ RGA_FORMAT_YCrCb_422_SP_10B, ++ RGA_FORMAT_YCbCr_400, ++ RGA_FORMAT_RGBA_5551, ++ RGA_FORMAT_BGRA_5551, ++ RGA_FORMAT_RGBA_4444, ++ RGA_FORMAT_BGRA_4444, ++ RGA_FORMAT_XRGB_8888, ++ RGA_FORMAT_XBGR_8888, ++ RGA_FORMAT_BPP1, ++ RGA_FORMAT_BPP2, ++ RGA_FORMAT_BPP4, ++ RGA_FORMAT_BPP8, ++ RGA_FORMAT_ARGB_8888, ++ RGA_FORMAT_ARGB_5551, ++ RGA_FORMAT_ARGB_4444, ++ RGA_FORMAT_ABGR_8888, ++ RGA_FORMAT_ABGR_5551, ++ RGA_FORMAT_ABGR_4444, ++}; ++ ++const uint32_t rga2e_output_raster_format[] = { ++ RGA_FORMAT_RGBA_8888, ++ RGA_FORMAT_RGBX_8888, ++ RGA_FORMAT_BGRA_8888, ++ RGA_FORMAT_BGRX_8888, ++ RGA_FORMAT_RGB_888, ++ RGA_FORMAT_BGR_888, ++ RGA_FORMAT_RGB_565, ++ RGA_FORMAT_BGR_565, ++ RGA_FORMAT_YCbCr_422_P, ++ RGA_FORMAT_YCbCr_420_P, ++ RGA_FORMAT_YCrCb_422_P, ++ RGA_FORMAT_YCrCb_420_P, ++ RGA_FORMAT_YCbCr_422_SP, ++ RGA_FORMAT_YCbCr_420_SP, ++ RGA_FORMAT_YCrCb_422_SP, ++ RGA_FORMAT_YCrCb_420_SP, ++ RGA_FORMAT_YVYU_420, ++ RGA_FORMAT_VYUY_420, ++ RGA_FORMAT_YUYV_420, ++ RGA_FORMAT_UYVY_420, ++ RGA_FORMAT_YVYU_422, ++ RGA_FORMAT_VYUY_422, ++ RGA_FORMAT_YUYV_422, ++ RGA_FORMAT_UYVY_422, ++ RGA_FORMAT_YCbCr_420_SP_10B, ++ RGA_FORMAT_YCrCb_420_SP_10B, ++ RGA_FORMAT_YCbCr_422_SP_10B, ++ RGA_FORMAT_YCrCb_422_SP_10B, ++ RGA_FORMAT_Y4, ++ RGA_FORMAT_YCbCr_400, ++ RGA_FORMAT_RGBA_5551, ++ RGA_FORMAT_BGRA_5551, ++ RGA_FORMAT_RGBA_4444, ++ RGA_FORMAT_BGRA_4444, ++ RGA_FORMAT_XRGB_8888, ++ RGA_FORMAT_XBGR_8888, ++ RGA_FORMAT_ARGB_8888, ++ RGA_FORMAT_ARGB_5551, ++ RGA_FORMAT_ARGB_4444, ++ RGA_FORMAT_ABGR_8888, ++ RGA_FORMAT_ABGR_5551, ++ RGA_FORMAT_ABGR_4444, ++}; ++ ++const struct rga_win_data rga3_win_data[] = { ++ { ++ .name = "rga3-win0", ++ .formats[RGA_RASTER_INDEX] = rga3_input_raster_format, ++ .formats_count[RGA_RASTER_INDEX] = ARRAY_SIZE(rga3_input_raster_format), ++ .formats[RGA_AFBC16x16_INDEX] = rga3_fbcd_format, ++ .formats_count[RGA_AFBC16x16_INDEX] = ARRAY_SIZE(rga3_fbcd_format), ++ .formats[RGA_TILE8x8_INDEX] = rga3_tile_format, ++ .formats_count[RGA_TILE8x8_INDEX] = ARRAY_SIZE(rga3_tile_format), ++ .supported_rotations = RGA_MODE_ROTATE_MASK, ++ .scale_up_mode = RGA_SCALE_UP_BIC, ++ .scale_down_mode = RGA_SCALE_DOWN_AVG, ++ .rd_mode = RGA_RASTER_MODE | RGA_FBC_MODE | RGA_TILE_MODE, ++ ++ }, ++ ++ { ++ .name = "rga3-win1", ++ .formats[RGA_RASTER_INDEX] = rga3_input_raster_format, ++ .formats_count[RGA_RASTER_INDEX] = ARRAY_SIZE(rga3_input_raster_format), ++ .formats[RGA_AFBC16x16_INDEX] = rga3_fbcd_format, ++ .formats_count[RGA_AFBC16x16_INDEX] = ARRAY_SIZE(rga3_fbcd_format), ++ .formats[RGA_TILE8x8_INDEX] = rga3_tile_format, ++ .formats_count[RGA_TILE8x8_INDEX] = ARRAY_SIZE(rga3_tile_format), ++ .supported_rotations = RGA_MODE_ROTATE_MASK, ++ .scale_up_mode = RGA_SCALE_UP_BIC, ++ .scale_down_mode = RGA_SCALE_DOWN_AVG, ++ .rd_mode = RGA_RASTER_MODE | RGA_FBC_MODE | RGA_TILE_MODE, ++ ++ }, ++ ++ { ++ .name = "rga3-wr", ++ .formats[RGA_RASTER_INDEX] = rga3_output_raster_format, ++ .formats_count[RGA_RASTER_INDEX] = ARRAY_SIZE(rga3_output_raster_format), ++ .formats[RGA_AFBC16x16_INDEX] = rga3_fbcd_format, ++ .formats_count[RGA_AFBC16x16_INDEX] = ARRAY_SIZE(rga3_fbcd_format), ++ .formats[RGA_TILE8x8_INDEX] = rga3_tile_format, ++ .formats_count[RGA_TILE8x8_INDEX] = ARRAY_SIZE(rga3_tile_format), ++ .supported_rotations = 0, ++ .scale_up_mode = RGA_SCALE_UP_NONE, ++ .scale_down_mode = RGA_SCALE_DOWN_NONE, ++ .rd_mode = RGA_RASTER_MODE | RGA_FBC_MODE | RGA_TILE_MODE, ++ ++ }, ++}; ++ ++const struct rga_win_data rga2e_win_data[] = { ++ { ++ .name = "rga2e-src0", ++ .formats[RGA_RASTER_INDEX] = rga2e_input_raster_format, ++ .formats_count[RGA_RASTER_INDEX] = ARRAY_SIZE(rga2e_input_raster_format), ++ .supported_rotations = RGA_MODE_ROTATE_MASK, ++ .scale_up_mode = RGA_SCALE_UP_BIC, ++ .scale_down_mode = RGA_SCALE_DOWN_AVG, ++ .rd_mode = RGA_RASTER_MODE, ++ ++ }, ++ ++ { ++ .name = "rga2e-src1", ++ .formats[RGA_RASTER_INDEX] = rga2e_input_raster_format, ++ .formats_count[RGA_RASTER_INDEX] = ARRAY_SIZE(rga2e_input_raster_format), ++ .supported_rotations = RGA_MODE_ROTATE_MASK, ++ .scale_up_mode = RGA_SCALE_UP_BIC, ++ .scale_down_mode = RGA_SCALE_DOWN_AVG, ++ .rd_mode = RGA_RASTER_MODE, ++ ++ }, ++ ++ { ++ .name = "rga2-dst", ++ .formats[RGA_RASTER_INDEX] = rga2e_output_raster_format, ++ .formats_count[RGA_RASTER_INDEX] = ARRAY_SIZE(rga2e_output_raster_format), ++ .supported_rotations = 0, ++ .scale_up_mode = RGA_SCALE_UP_NONE, ++ .scale_down_mode = RGA_SCALE_DOWN_NONE, ++ .rd_mode = RGA_RASTER_MODE, ++ ++ }, ++}; ++ ++const struct rga_hw_data rga3_data = { ++ .version = 0, ++ .input_range = {{68, 2}, {8176, 8176}}, ++ .output_range = {{68, 2}, {8128, 8128}}, ++ ++ .win = rga3_win_data, ++ .win_size = ARRAY_SIZE(rga3_win_data), ++ /* 1 << factor mean real factor */ ++ .max_upscale_factor = 3, ++ .max_downscale_factor = 3, ++ ++ .byte_stride_align = 16, ++ .max_byte_stride = WORD_TO_BYTE(8192), ++ ++ .feature = RGA_COLOR_KEY, ++ .csc_r2y_mode = RGA_MODE_CSC_BT601L | RGA_MODE_CSC_BT601F | ++ RGA_MODE_CSC_BT709 | RGA_MODE_CSC_BT2020, ++ .csc_y2r_mode = RGA_MODE_CSC_BT601L | RGA_MODE_CSC_BT601F | ++ RGA_MODE_CSC_BT709 | RGA_MODE_CSC_BT2020, ++ .mmu = RGA_IOMMU, ++}; ++ ++const struct rga_hw_data rga2e_data = { ++ .version = 0, ++ .input_range = {{2, 2}, {8192, 8192}}, ++ .output_range = {{2, 2}, {4096, 4096}}, ++ ++ .win = rga2e_win_data, ++ .win_size = ARRAY_SIZE(rga2e_win_data), ++ /* 1 << factor mean real factor */ ++ .max_upscale_factor = 4, ++ .max_downscale_factor = 4, ++ ++ .byte_stride_align = 4, ++ .max_byte_stride = WORD_TO_BYTE(8192), ++ ++ .feature = RGA_COLOR_FILL | RGA_COLOR_PALETTE | ++ RGA_COLOR_KEY | RGA_ROP_CALCULATE | ++ RGA_NN_QUANTIZE | RGA_DITHER | RGA_FULL_CSC, ++ .csc_r2y_mode = RGA_MODE_CSC_BT601L | RGA_MODE_CSC_BT601F, ++ .csc_y2r_mode = RGA_MODE_CSC_BT601L | RGA_MODE_CSC_BT601F | ++ RGA_MODE_CSC_BT709, ++ .mmu = RGA_MMU, ++}; ++ ++const struct rga_hw_data rga2e_1106_data = { ++ .version = 0, ++ .input_range = {{2, 2}, {8192, 8192}}, ++ .output_range = {{2, 2}, {4096, 4096}}, ++ ++ .win = rga2e_win_data, ++ .win_size = ARRAY_SIZE(rga2e_win_data), ++ /* 1 << factor mean real factor */ ++ .max_upscale_factor = 4, ++ .max_downscale_factor = 4, ++ ++ .byte_stride_align = 4, ++ .max_byte_stride = WORD_TO_BYTE(8192), ++ ++ .feature = RGA_COLOR_FILL | RGA_COLOR_PALETTE | ++ RGA_COLOR_KEY | RGA_ROP_CALCULATE | ++ RGA_NN_QUANTIZE | RGA_DITHER | RGA_MOSAIC | ++ RGA_YIN_YOUT | RGA_YUV_HDS | RGA_YUV_VDS | ++ RGA_OSD | RGA_PRE_INTR | RGA_FULL_CSC, ++ .csc_r2y_mode = RGA_MODE_CSC_BT601L | RGA_MODE_CSC_BT601F | ++ RGA_MODE_CSC_BT709, ++ .csc_y2r_mode = RGA_MODE_CSC_BT601L | RGA_MODE_CSC_BT601F | ++ RGA_MODE_CSC_BT709, ++ .mmu = RGA_NONE_MMU, ++}; ++ ++const struct rga_hw_data rga2e_iommu_data = { ++ .version = 0, ++ .input_range = {{2, 2}, {8192, 8192}}, ++ .output_range = {{2, 2}, {4096, 4096}}, ++ ++ .win = rga2e_win_data, ++ .win_size = ARRAY_SIZE(rga2e_win_data), ++ /* 1 << factor mean real factor */ ++ .max_upscale_factor = 4, ++ .max_downscale_factor = 4, ++ ++ .byte_stride_align = 4, ++ .max_byte_stride = WORD_TO_BYTE(8192), ++ ++ .feature = RGA_COLOR_FILL | RGA_COLOR_PALETTE | ++ RGA_COLOR_KEY | RGA_ROP_CALCULATE | ++ RGA_NN_QUANTIZE | RGA_DITHER | RGA_MOSAIC | ++ RGA_YIN_YOUT | RGA_YUV_HDS | RGA_YUV_VDS | ++ RGA_OSD | RGA_PRE_INTR | RGA_FULL_CSC, ++ .csc_r2y_mode = RGA_MODE_CSC_BT601L | RGA_MODE_CSC_BT601F | ++ RGA_MODE_CSC_BT709, ++ .csc_y2r_mode = RGA_MODE_CSC_BT601L | RGA_MODE_CSC_BT601F | ++ RGA_MODE_CSC_BT709, ++ .mmu = RGA_IOMMU, ++}; +diff --git a/drivers/video/rockchip/rga3/rga_iommu.c b/drivers/video/rockchip/rga3/rga_iommu.c +new file mode 100644 +index 000000000..6ef9cbc0d +--- /dev/null ++++ b/drivers/video/rockchip/rga3/rga_iommu.c +@@ -0,0 +1,425 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) Rockchip Electronics Co., Ltd. ++ * ++ * Author: Huang Lee ++ */ ++ ++#define pr_fmt(fmt) "rga_iommu: " fmt ++ ++#include "rga_iommu.h" ++#include "rga_dma_buf.h" ++#include "rga_mm.h" ++#include "rga_job.h" ++#include "rga_common.h" ++#include "rga_hw_config.h" ++ ++int rga_user_memory_check(struct page **pages, u32 w, u32 h, u32 format, int flag) ++{ ++ int bits; ++ void *vaddr = NULL; ++ int taipage_num; ++ int taidata_num; ++ int *tai_vaddr = NULL; ++ ++ bits = rga_get_format_bits(format); ++ if (bits < 0) ++ return -1; ++ ++ taipage_num = w * h * bits / 8 / (1024 * 4); ++ taidata_num = w * h * bits / 8 % (1024 * 4); ++ if (taidata_num == 0) { ++ vaddr = kmap(pages[taipage_num - 1]); ++ tai_vaddr = (int *)vaddr + 1023; ++ } else { ++ vaddr = kmap(pages[taipage_num]); ++ tai_vaddr = (int *)vaddr + taidata_num / 4 - 1; ++ } ++ ++ if (flag == 1) { ++ pr_info("src user memory check\n"); ++ pr_info("tai data is %d\n", *tai_vaddr); ++ } else { ++ pr_info("dst user memory check\n"); ++ pr_info("tai data is %d\n", *tai_vaddr); ++ } ++ ++ if (taidata_num == 0) ++ kunmap(pages[taipage_num - 1]); ++ else ++ kunmap(pages[taipage_num]); ++ ++ return 0; ++} ++ ++int rga_set_mmu_base(struct rga_job *job, struct rga2_req *req) ++{ ++ if (job->src_buffer.page_table) { ++ rga_dma_sync_flush_range(job->src_buffer.page_table, ++ (job->src_buffer.page_table + ++ job->src_buffer.page_count), ++ job->scheduler); ++ req->mmu_info.src0_base_addr = virt_to_phys(job->src_buffer.page_table); ++ } ++ ++ if (job->src1_buffer.page_table) { ++ rga_dma_sync_flush_range(job->src1_buffer.page_table, ++ (job->src1_buffer.page_table + ++ job->src1_buffer.page_count), ++ job->scheduler); ++ req->mmu_info.src1_base_addr = virt_to_phys(job->src1_buffer.page_table); ++ } ++ ++ if (job->dst_buffer.page_table) { ++ rga_dma_sync_flush_range(job->dst_buffer.page_table, ++ (job->dst_buffer.page_table + ++ job->dst_buffer.page_count), ++ job->scheduler); ++ req->mmu_info.dst_base_addr = virt_to_phys(job->dst_buffer.page_table); ++ ++ if (((req->alpha_rop_flag & 1) == 1) && (req->bitblt_mode == 0)) { ++ req->mmu_info.src1_base_addr = req->mmu_info.dst_base_addr; ++ req->mmu_info.src1_mmu_flag = req->mmu_info.dst_mmu_flag; ++ } ++ } ++ ++ if (job->els_buffer.page_table) { ++ rga_dma_sync_flush_range(job->els_buffer.page_table, ++ (job->els_buffer.page_table + ++ job->els_buffer.page_count), ++ job->scheduler); ++ req->mmu_info.els_base_addr = virt_to_phys(job->els_buffer.page_table); ++ } ++ ++ return 0; ++} ++ ++static int rga_mmu_buf_get_try(struct rga_mmu_base *t, uint32_t size) ++{ ++ int ret = 0; ++ ++ if ((t->back - t->front) > t->size) { ++ if (t->front + size > t->back - t->size) { ++ pr_info("front %d, back %d dsize %d size %d", ++ t->front, t->back, t->size, size); ++ ret = -ENOMEM; ++ goto out; ++ } ++ } else { ++ if ((t->front + size) > t->back) { ++ pr_info("front %d, back %d dsize %d size %d", ++ t->front, t->back, t->size, size); ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ if (t->front + size > t->size) { ++ if (size > (t->back - t->size)) { ++ pr_info("front %d, back %d dsize %d size %d", ++ t->front, t->back, t->size, size); ++ ret = -ENOMEM; ++ goto out; ++ } ++ t->front = 0; ++ } ++ } ++out: ++ return ret; ++} ++ ++unsigned int *rga_mmu_buf_get(struct rga_mmu_base *mmu_base, uint32_t size) ++{ ++ int ret; ++ unsigned int *buf = NULL; ++ ++ WARN_ON(!mutex_is_locked(&rga_drvdata->lock)); ++ ++ size = ALIGN(size, 16); ++ ++ ret = rga_mmu_buf_get_try(mmu_base, size); ++ if (ret < 0) { ++ pr_err("Get MMU mem failed\n"); ++ return NULL; ++ } ++ ++ buf = mmu_base->buf_virtual + mmu_base->front; ++ ++ mmu_base->front += size; ++ ++ if (mmu_base->back + size > 2 * mmu_base->size) ++ mmu_base->back = size + mmu_base->size; ++ else ++ mmu_base->back += size; ++ ++ return buf; ++} ++ ++struct rga_mmu_base *rga_mmu_base_init(size_t size) ++{ ++ int order = 0; ++ struct rga_mmu_base *mmu_base; ++ ++ mmu_base = kzalloc(sizeof(*mmu_base), GFP_KERNEL); ++ if (mmu_base == NULL) { ++ pr_err("Cannot alloc mmu_base!\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ /* ++ * malloc pre scale mid buf mmu table: ++ * size * channel_num * address_size ++ */ ++ order = get_order(size * 3 * sizeof(*mmu_base->buf_virtual)); ++ if (order >= MAX_ORDER) { ++ pr_err("Can not alloc pages with order[%d] for mmu_page_table, max_order = %d\n", ++ order, MAX_ORDER); ++ goto err_free_mmu_base; ++ } ++ ++ mmu_base->buf_virtual = (uint32_t *) __get_free_pages(GFP_KERNEL | GFP_DMA32, order); ++ if (mmu_base->buf_virtual == NULL) { ++ pr_err("Can not alloc pages for mmu_page_table\n"); ++ goto err_free_mmu_base; ++ } ++ mmu_base->buf_order = order; ++ ++ order = get_order(size * sizeof(*mmu_base->pages)); ++ if (order >= MAX_ORDER) { ++ pr_err("Can not alloc pages with order[%d] for mmu_base->pages, max_order = %d\n", ++ order, MAX_ORDER); ++ goto err_free_buf_virtual; ++ } ++ ++ mmu_base->pages = (struct page **)__get_free_pages(GFP_KERNEL | GFP_DMA32, order); ++ if (mmu_base->pages == NULL) { ++ pr_err("Can not alloc pages for mmu_base->pages\n"); ++ goto err_free_buf_virtual; ++ } ++ mmu_base->pages_order = order; ++ ++ mmu_base->front = 0; ++ mmu_base->back = RGA2_PHY_PAGE_SIZE * 3; ++ mmu_base->size = RGA2_PHY_PAGE_SIZE * 3; ++ ++ return mmu_base; ++ ++err_free_buf_virtual: ++ free_pages((unsigned long)mmu_base->buf_virtual, mmu_base->buf_order); ++ mmu_base->buf_order = 0; ++ ++err_free_mmu_base: ++ kfree(mmu_base); ++ ++ return ERR_PTR(-ENOMEM); ++} ++ ++void rga_mmu_base_free(struct rga_mmu_base **mmu_base) ++{ ++ struct rga_mmu_base *base = *mmu_base; ++ ++ if (base->buf_virtual != NULL) { ++ free_pages((unsigned long)base->buf_virtual, base->buf_order); ++ base->buf_virtual = NULL; ++ base->buf_order = 0; ++ } ++ ++ if (base->pages != NULL) { ++ free_pages((unsigned long)base->pages, base->pages_order); ++ base->pages = NULL; ++ base->pages_order = 0; ++ } ++ ++ kfree(base); ++ *mmu_base = NULL; ++} ++ ++static int rga_iommu_intr_fault_handler(struct iommu_domain *iommu, struct device *iommu_dev, ++ unsigned long iova, int status, void *arg) ++{ ++ struct rga_scheduler_t *scheduler = (struct rga_scheduler_t *)arg; ++ struct rga_job *job = scheduler->running_job; ++ ++ if (job == NULL) ++ return 0; ++ ++ pr_err("IOMMU intr fault, IOVA[0x%lx], STATUS[0x%x]\n", iova, status); ++ if (scheduler->ops->irq) ++ scheduler->ops->irq(scheduler); ++ ++ /* iommu interrupts on rga2 do not affect rga2 itself. */ ++ if (!test_bit(RGA_JOB_STATE_INTR_ERR, &job->state)) { ++ set_bit(RGA_JOB_STATE_INTR_ERR, &job->state); ++ scheduler->ops->soft_reset(scheduler); ++ } ++ ++ if (status & RGA_IOMMU_IRQ_PAGE_FAULT) { ++ pr_err("RGA IOMMU: page fault! Please check the memory size.\n"); ++ job->ret = -EACCES; ++ } else if (status & RGA_IOMMU_IRQ_BUS_ERROR) { ++ pr_err("RGA IOMMU: bus error! Please check if the memory is invalid or has been freed.\n"); ++ job->ret = -EACCES; ++ } else { ++ pr_err("RGA IOMMU: Wrong IOMMU interrupt signal!\n"); ++ } ++ ++ return 0; ++} ++ ++int rga_iommu_detach(struct rga_iommu_info *info) ++{ ++ if (!info) ++ return 0; ++ ++ iommu_detach_group(info->domain, info->group); ++ return 0; ++} ++ ++int rga_iommu_attach(struct rga_iommu_info *info) ++{ ++ if (!info) ++ return 0; ++ ++ return iommu_attach_group(info->domain, info->group); ++} ++ ++struct rga_iommu_info *rga_iommu_probe(struct device *dev) ++{ ++ int ret = 0; ++ struct rga_iommu_info *info = NULL; ++ struct iommu_domain *domain = NULL; ++ struct iommu_group *group = NULL; ++ ++ group = iommu_group_get(dev); ++ if (!group) ++ return ERR_PTR(-EINVAL); ++ ++ domain = iommu_get_domain_for_dev(dev); ++ if (!domain) { ++ ret = -EINVAL; ++ goto err_put_group; ++ } ++ ++ info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); ++ if (!info) { ++ ret = -ENOMEM; ++ goto err_put_group; ++ } ++ ++ info->dev = dev; ++ info->default_dev = info->dev; ++ info->group = group; ++ info->domain = domain; ++ ++ return info; ++ ++err_put_group: ++ if (group) ++ iommu_group_put(group); ++ ++ return ERR_PTR(ret); ++} ++ ++int rga_iommu_remove(struct rga_iommu_info *info) ++{ ++ if (!info) ++ return 0; ++ ++ iommu_group_put(info->group); ++ ++ return 0; ++} ++ ++int rga_iommu_bind(void) ++{ ++ int i; ++ int ret; ++ struct rga_scheduler_t *scheduler = NULL; ++ struct rga_iommu_info *main_iommu = NULL; ++ int main_iommu_index = -1; ++ int main_mmu_index = -1; ++ int another_index = -1; ++ ++ for (i = 0; i < rga_drvdata->num_of_scheduler; i++) { ++ scheduler = rga_drvdata->scheduler[i]; ++ ++ switch (scheduler->data->mmu) { ++ case RGA_IOMMU: ++ if (scheduler->iommu_info == NULL) ++ continue; ++ ++ if (main_iommu == NULL) { ++ main_iommu = scheduler->iommu_info; ++ main_iommu_index = i; ++ iommu_set_fault_handler(main_iommu->domain, ++ rga_iommu_intr_fault_handler, ++ (void *)scheduler); ++ } else { ++ scheduler->iommu_info->domain = main_iommu->domain; ++ scheduler->iommu_info->default_dev = main_iommu->default_dev; ++ rga_iommu_attach(scheduler->iommu_info); ++ } ++ ++ break; ++ ++ case RGA_MMU: ++ if (rga_drvdata->mmu_base != NULL) ++ continue; ++ ++ rga_drvdata->mmu_base = rga_mmu_base_init(RGA2_PHY_PAGE_SIZE); ++ if (IS_ERR(rga_drvdata->mmu_base)) { ++ dev_err(scheduler->dev, "rga mmu base init failed!\n"); ++ ret = PTR_ERR(rga_drvdata->mmu_base); ++ rga_drvdata->mmu_base = NULL; ++ ++ return ret; ++ } ++ ++ main_mmu_index = i; ++ ++ break; ++ default: ++ if (another_index != RGA_NONE_CORE) ++ another_index = i; ++ ++ break; ++ } ++ } ++ ++ /* ++ * priority order: iommu > mmu > another ++ * The scheduler core with IOMMU will be used preferentially as the ++ * default memory-mapped core. This ensures that all cores can obtain ++ * the required memory data when they are equipped with different ++ * versions of cores. ++ */ ++ if (main_iommu_index >= 0) { ++ rga_drvdata->map_scheduler_index = main_iommu_index; ++ } else if (main_mmu_index >= 0) { ++ rga_drvdata->map_scheduler_index = main_mmu_index; ++ } else if (another_index >= 0) { ++ rga_drvdata->map_scheduler_index = another_index; ++ } else { ++ rga_drvdata->map_scheduler_index = -1; ++ pr_err("%s, binding map scheduler failed!\n", __func__); ++ return -EFAULT; ++ } ++ ++ pr_info("IOMMU binding successfully, default mapping core[0x%x]\n", ++ rga_drvdata->scheduler[rga_drvdata->map_scheduler_index]->core); ++ ++ return 0; ++} ++ ++void rga_iommu_unbind(void) ++{ ++ int i; ++ ++ for (i = 0; i < rga_drvdata->num_of_scheduler; i++) ++ if (rga_drvdata->scheduler[i]->iommu_info != NULL) ++ rga_iommu_detach(rga_drvdata->scheduler[i]->iommu_info); ++ ++ if (rga_drvdata->mmu_base) ++ rga_mmu_base_free(&rga_drvdata->mmu_base); ++ ++ rga_drvdata->map_scheduler_index = -1; ++} +diff --git a/drivers/video/rockchip/rga3/rga_job.c b/drivers/video/rockchip/rga3/rga_job.c +new file mode 100644 +index 000000000..fae613bbf +--- /dev/null ++++ b/drivers/video/rockchip/rga3/rga_job.c +@@ -0,0 +1,1423 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) Rockchip Electronics Co., Ltd. ++ * ++ * Author: Huang Lee ++ */ ++ ++#define pr_fmt(fmt) "rga_job: " fmt ++ ++#include "rga_job.h" ++#include "rga_fence.h" ++#include "rga_dma_buf.h" ++#include "rga_mm.h" ++#include "rga_iommu.h" ++#include "rga_debugger.h" ++#include "rga_common.h" ++ ++static void rga_job_free(struct rga_job *job) ++{ ++ free_page((unsigned long)job); ++} ++ ++static void rga_job_kref_release(struct kref *ref) ++{ ++ struct rga_job *job; ++ ++ job = container_of(ref, struct rga_job, refcount); ++ ++ rga_job_free(job); ++} ++ ++static int rga_job_put(struct rga_job *job) ++{ ++ return kref_put(&job->refcount, rga_job_kref_release); ++} ++ ++static void rga_job_get(struct rga_job *job) ++{ ++ kref_get(&job->refcount); ++} ++ ++static int rga_job_cleanup(struct rga_job *job) ++{ ++ rga_job_put(job); ++ ++ if (DEBUGGER_EN(TIME)) ++ pr_info("request[%d], job cleanup total cost time %lld us\n", ++ job->request_id, ++ ktime_us_delta(ktime_get(), job->timestamp)); ++ ++ return 0; ++} ++ ++static int rga_job_judgment_support_core(struct rga_job *job) ++{ ++ int ret = 0; ++ uint32_t mm_flag; ++ struct rga_req *req; ++ struct rga_mm *mm; ++ ++ req = &job->rga_command_base; ++ mm = rga_drvdata->mm; ++ if (mm == NULL) { ++ pr_err("rga mm is null!\n"); ++ return -EFAULT; ++ } ++ ++ mutex_lock(&mm->lock); ++ ++ if (likely(req->src.yrgb_addr > 0)) { ++ ret = rga_mm_lookup_flag(mm, req->src.yrgb_addr); ++ if (ret < 0) ++ goto out_finish; ++ else ++ mm_flag = (uint32_t)ret; ++ ++ if (~mm_flag & RGA_MEM_UNDER_4G) { ++ job->flags |= RGA_JOB_UNSUPPORT_RGA_MMU; ++ goto out_finish; ++ } ++ } ++ ++ if (likely(req->dst.yrgb_addr > 0)) { ++ ret = rga_mm_lookup_flag(mm, req->dst.yrgb_addr); ++ if (ret < 0) ++ goto out_finish; ++ else ++ mm_flag = (uint32_t)ret; ++ ++ if (~mm_flag & RGA_MEM_UNDER_4G) { ++ job->flags |= RGA_JOB_UNSUPPORT_RGA_MMU; ++ goto out_finish; ++ } ++ } ++ ++ if (req->pat.yrgb_addr > 0) { ++ ret = rga_mm_lookup_flag(mm, req->pat.yrgb_addr); ++ if (ret < 0) ++ goto out_finish; ++ else ++ mm_flag = (uint32_t)ret; ++ ++ if (~mm_flag & RGA_MEM_UNDER_4G) { ++ job->flags |= RGA_JOB_UNSUPPORT_RGA_MMU; ++ goto out_finish; ++ } ++ } ++ ++out_finish: ++ mutex_unlock(&mm->lock); ++ ++ return ret; ++} ++ ++static struct rga_job *rga_job_alloc(struct rga_req *rga_command_base) ++{ ++ struct rga_job *job = NULL; ++ ++ job = (struct rga_job *)get_zeroed_page(GFP_KERNEL | GFP_DMA32); ++ if (!job) ++ return NULL; ++ ++ INIT_LIST_HEAD(&job->head); ++ kref_init(&job->refcount); ++ ++ job->timestamp = ktime_get(); ++ job->pid = current->pid; ++ ++ job->rga_command_base = *rga_command_base; ++ ++ if (rga_command_base->priority > 0) { ++ if (rga_command_base->priority > RGA_SCHED_PRIORITY_MAX) ++ job->priority = RGA_SCHED_PRIORITY_MAX; ++ else ++ job->priority = rga_command_base->priority; ++ } ++ ++ if (job->rga_command_base.handle_flag & 1) { ++ job->flags |= RGA_JOB_USE_HANDLE; ++ ++ rga_job_judgment_support_core(job); ++ } ++ ++ return job; ++} ++ ++static void rga_job_dump_info(struct rga_job *job) ++{ ++ pr_info("job: reqeust_id = %d, priority = %d, core = %d\n", ++ job->request_id, job->priority, job->core); ++} ++ ++void rga_job_scheduler_dump_info(struct rga_scheduler_t *scheduler) ++{ ++ struct rga_job *job_pos; ++ ++ lockdep_assert_held(&scheduler->irq_lock); ++ ++ pr_info("===============================================================\n"); ++ pr_info("%s core = %d job_count = %d status = %d\n", ++ dev_driver_string(scheduler->dev), ++ scheduler->core, scheduler->job_count, scheduler->status); ++ ++ if (scheduler->running_job) ++ rga_job_dump_info(scheduler->running_job); ++ ++ list_for_each_entry(job_pos, &scheduler->todo_list, head) { ++ rga_job_dump_info(job_pos); ++ } ++ ++ pr_info("===============================================================\n"); ++} ++ ++static int rga_job_run(struct rga_job *job, struct rga_scheduler_t *scheduler) ++{ ++ int ret = 0; ++ ++ /* enable power */ ++ ret = rga_power_enable(scheduler); ++ if (ret < 0) { ++ pr_err("power enable failed"); ++ return ret; ++ } ++ ++ ret = scheduler->ops->set_reg(job, scheduler); ++ if (ret < 0) { ++ pr_err("set reg failed"); ++ rga_power_disable(scheduler); ++ return ret; ++ } ++ ++ set_bit(RGA_JOB_STATE_RUNNING, &job->state); ++ ++ /* for debug */ ++ if (DEBUGGER_EN(MSG)) ++ rga_job_dump_info(job); ++ ++ return ret; ++} ++ ++void rga_job_next(struct rga_scheduler_t *scheduler) ++{ ++ int ret; ++ struct rga_job *job = NULL; ++ unsigned long flags; ++ ++next_job: ++ spin_lock_irqsave(&scheduler->irq_lock, flags); ++ ++ if (scheduler->running_job || ++ list_empty(&scheduler->todo_list)) { ++ spin_unlock_irqrestore(&scheduler->irq_lock, flags); ++ return; ++ } ++ ++ job = list_first_entry(&scheduler->todo_list, struct rga_job, head); ++ ++ list_del_init(&job->head); ++ ++ scheduler->job_count--; ++ ++ scheduler->running_job = job; ++ set_bit(RGA_JOB_STATE_PREPARE, &job->state); ++ rga_job_get(job); ++ ++ spin_unlock_irqrestore(&scheduler->irq_lock, flags); ++ ++ ret = rga_job_run(job, scheduler); ++ /* If some error before hw run */ ++ if (ret < 0) { ++ pr_err("some error on rga_job_run before hw start, %s(%d)\n", __func__, __LINE__); ++ ++ spin_lock_irqsave(&scheduler->irq_lock, flags); ++ ++ scheduler->running_job = NULL; ++ rga_job_put(job); ++ ++ spin_unlock_irqrestore(&scheduler->irq_lock, flags); ++ ++ job->ret = ret; ++ rga_request_release_signal(scheduler, job); ++ ++ goto next_job; ++ } ++ ++ rga_job_put(job); ++} ++ ++struct rga_job *rga_job_done(struct rga_scheduler_t *scheduler) ++{ ++ struct rga_job *job; ++ unsigned long flags; ++ ktime_t now = ktime_get(); ++ ++ spin_lock_irqsave(&scheduler->irq_lock, flags); ++ ++ job = scheduler->running_job; ++ if (job == NULL) { ++ pr_err("core[0x%x] running job has been cleanup.\n", scheduler->core); ++ ++ spin_unlock_irqrestore(&scheduler->irq_lock, flags); ++ return NULL; ++ } ++ scheduler->running_job = NULL; ++ ++ scheduler->timer.busy_time += ktime_us_delta(now, job->hw_recoder_time); ++ set_bit(RGA_JOB_STATE_DONE, &job->state); ++ ++ spin_unlock_irqrestore(&scheduler->irq_lock, flags); ++ ++ if (scheduler->ops->read_back_reg) ++ scheduler->ops->read_back_reg(job, scheduler); ++ ++ if (DEBUGGER_EN(DUMP_IMAGE)) ++ rga_dump_job_image(job); ++ ++ if (DEBUGGER_EN(TIME)) ++ pr_info("request[%d], hardware[%s] cost time %lld us\n", ++ job->request_id, ++ rga_get_core_name(scheduler->core), ++ ktime_us_delta(now, job->hw_running_time)); ++ ++ rga_mm_unmap_job_info(job); ++ ++ return job; ++} ++ ++static void rga_job_scheduler_timeout_clean(struct rga_scheduler_t *scheduler) ++{ ++ unsigned long flags; ++ struct rga_job *job = NULL; ++ ++ spin_lock_irqsave(&scheduler->irq_lock, flags); ++ ++ if (scheduler->running_job == NULL || scheduler->running_job->hw_running_time == 0) { ++ spin_unlock_irqrestore(&scheduler->irq_lock, flags); ++ return; ++ } ++ ++ job = scheduler->running_job; ++ if (ktime_ms_delta(ktime_get(), job->hw_running_time) >= RGA_JOB_TIMEOUT_DELAY) { ++ scheduler->running_job = NULL; ++ scheduler->status = RGA_SCHEDULER_ABORT; ++ scheduler->ops->soft_reset(scheduler); ++ ++ spin_unlock_irqrestore(&scheduler->irq_lock, flags); ++ ++ rga_mm_unmap_job_info(job); ++ ++ job->ret = -EBUSY; ++ rga_request_release_signal(scheduler, job); ++ ++ rga_power_disable(scheduler); ++ } else { ++ spin_unlock_irqrestore(&scheduler->irq_lock, flags); ++ } ++} ++ ++static void rga_job_insert_todo_list(struct rga_job *job) ++{ ++ bool first_match = 0; ++ unsigned long flags; ++ struct rga_job *job_pos; ++ struct rga_scheduler_t *scheduler = job->scheduler; ++ ++ spin_lock_irqsave(&scheduler->irq_lock, flags); ++ ++ /* priority policy set by userspace */ ++ if (list_empty(&scheduler->todo_list) ++ || (job->priority == RGA_SCHED_PRIORITY_DEFAULT)) { ++ list_add_tail(&job->head, &scheduler->todo_list); ++ } else { ++ list_for_each_entry(job_pos, &scheduler->todo_list, head) { ++ if (job->priority > job_pos->priority && ++ (!first_match)) { ++ list_add(&job->head, &job_pos->head); ++ first_match = true; ++ } ++ ++ /* ++ * Increase the priority of subsequent tasks ++ * after inserting into the list ++ */ ++ if (first_match) ++ job_pos->priority++; ++ } ++ ++ if (!first_match) ++ list_add_tail(&job->head, &scheduler->todo_list); ++ } ++ ++ scheduler->job_count++; ++ set_bit(RGA_JOB_STATE_PENDING, &job->state); ++ ++ spin_unlock_irqrestore(&scheduler->irq_lock, flags); ++} ++ ++static struct rga_scheduler_t *rga_job_schedule(struct rga_job *job) ++{ ++ int i; ++ struct rga_scheduler_t *scheduler = NULL; ++ ++ for (i = 0; i < rga_drvdata->num_of_scheduler; i++) { ++ scheduler = rga_drvdata->scheduler[i]; ++ rga_job_scheduler_timeout_clean(scheduler); ++ } ++ ++ if (rga_drvdata->num_of_scheduler > 1) { ++ job->core = rga_job_assign(job); ++ if (job->core <= 0) { ++ pr_err("job assign failed"); ++ job->ret = -EINVAL; ++ return NULL; ++ } ++ } else { ++ job->core = rga_drvdata->scheduler[0]->core; ++ job->scheduler = rga_drvdata->scheduler[0]; ++ } ++ ++ scheduler = job->scheduler; ++ if (scheduler == NULL) { ++ pr_err("failed to get scheduler, %s(%d)\n", __func__, __LINE__); ++ job->ret = -EFAULT; ++ return NULL; ++ } ++ ++ return scheduler; ++} ++ ++struct rga_job *rga_job_commit(struct rga_req *rga_command_base, struct rga_request *request) ++{ ++ int ret; ++ struct rga_job *job = NULL; ++ struct rga_scheduler_t *scheduler = NULL; ++ ++ job = rga_job_alloc(rga_command_base); ++ if (!job) { ++ pr_err("failed to alloc rga job!\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ job->use_batch_mode = request->use_batch_mode; ++ job->request_id = request->id; ++ job->session = request->session; ++ job->mm = request->current_mm; ++ ++ scheduler = rga_job_schedule(job); ++ if (scheduler == NULL) { ++ pr_err("failed to get scheduler, %s(%d)\n", __func__, __LINE__); ++ goto err_free_job; ++ } ++ ++ /* Memory mapping needs to keep pd enabled. */ ++ if (rga_power_enable(scheduler) < 0) { ++ pr_err("power enable failed"); ++ job->ret = -EFAULT; ++ goto err_free_job; ++ } ++ ++ ret = rga_mm_map_job_info(job); ++ if (ret < 0) { ++ pr_err("%s: failed to map job info\n", __func__); ++ job->ret = ret; ++ goto err_power_disable; ++ } ++ ++ ret = scheduler->ops->init_reg(job); ++ if (ret < 0) { ++ pr_err("%s: init reg failed", __func__); ++ job->ret = ret; ++ goto err_unmap_job_info; ++ } ++ ++ rga_job_insert_todo_list(job); ++ ++ rga_job_next(scheduler); ++ ++ rga_power_disable(scheduler); ++ ++ return job; ++ ++err_unmap_job_info: ++ rga_mm_unmap_job_info(job); ++ ++err_power_disable: ++ rga_power_disable(scheduler); ++ ++err_free_job: ++ ret = job->ret; ++ rga_request_release_signal(scheduler, job); ++ ++ return ERR_PTR(ret); ++} ++ ++static bool rga_is_need_current_mm(struct rga_req *req) ++{ ++ int mmu_flag; ++ struct rga_img_info_t *src0 = NULL; ++ struct rga_img_info_t *src1 = NULL; ++ struct rga_img_info_t *dst = NULL; ++ struct rga_img_info_t *els = NULL; ++ ++ src0 = &req->src; ++ dst = &req->dst; ++ if (req->render_mode != UPDATE_PALETTE_TABLE_MODE) ++ src1 = &req->pat; ++ else ++ els = &req->pat; ++ ++ if (likely(src0 != NULL)) { ++ mmu_flag = ((req->mmu_info.mmu_flag >> 8) & 1); ++ if (mmu_flag && src0->uv_addr) ++ return true; ++ } ++ ++ if (likely(dst != NULL)) { ++ mmu_flag = ((req->mmu_info.mmu_flag >> 10) & 1); ++ if (mmu_flag && dst->uv_addr) ++ return true; ++ } ++ ++ if (src1 != NULL) { ++ mmu_flag = ((req->mmu_info.mmu_flag >> 9) & 1); ++ if (mmu_flag && src1->uv_addr) ++ return true; ++ } ++ ++ if (els != NULL) { ++ mmu_flag = ((req->mmu_info.mmu_flag >> 11) & 1); ++ if (mmu_flag && els->uv_addr) ++ return true; ++ } ++ ++ return false; ++} ++ ++static struct mm_struct *rga_request_get_current_mm(struct rga_request *request) ++{ ++ int i; ++ ++ for (i = 0; i < request->task_count; i++) { ++ if (rga_is_need_current_mm(&(request->task_list[i]))) { ++ mmgrab(current->mm); ++ mmget(current->mm); ++ ++ return current->mm; ++ } ++ } ++ ++ return NULL; ++} ++ ++static void rga_request_put_current_mm(struct mm_struct *mm) ++{ ++ if (mm == NULL) ++ return; ++ ++ mmput(mm); ++ mmdrop(mm); ++} ++ ++static int rga_request_add_acquire_fence_callback(int acquire_fence_fd, ++ struct rga_request *request, ++ dma_fence_func_t cb_func) ++{ ++ int ret; ++ struct dma_fence *acquire_fence = NULL; ++ struct rga_pending_request_manager *request_manager = rga_drvdata->pend_request_manager; ++ ++ if (DEBUGGER_EN(MSG)) ++ pr_info("acquire_fence_fd = %d", acquire_fence_fd); ++ ++ acquire_fence = rga_get_dma_fence_from_fd(acquire_fence_fd); ++ if (IS_ERR_OR_NULL(acquire_fence)) { ++ pr_err("%s: failed to get acquire dma_fence from[%d]\n", ++ __func__, acquire_fence_fd); ++ return -EINVAL; ++ } ++ ++ if (!request->feature.user_close_fence) { ++ /* close acquire fence fd */ ++#ifdef CONFIG_NO_GKI ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) ++ close_fd(acquire_fence_fd); ++#else ++ ksys_close(acquire_fence_fd); ++#endif ++#else ++ pr_err("Please update the driver to v1.2.28 to prevent acquire_fence_fd leaks."); ++ return -EFAULT; ++#endif ++ } ++ ++ ++ ret = rga_dma_fence_get_status(acquire_fence); ++ if (ret < 0) { ++ pr_err("%s: Current acquire fence unexpectedly has error status before signal\n", ++ __func__); ++ return ret; ++ } else if (ret > 0) { ++ /* has been signaled */ ++ return ret; ++ } ++ ++ /* ++ * Ensure that the request will not be free early when ++ * the callback is called. ++ */ ++ mutex_lock(&request_manager->lock); ++ rga_request_get(request); ++ mutex_unlock(&request_manager->lock); ++ ++ ret = rga_dma_fence_add_callback(acquire_fence, cb_func, (void *)request); ++ if (ret < 0) { ++ if (ret != -ENOENT) ++ pr_err("%s: failed to add fence callback\n", __func__); ++ ++ mutex_lock(&request_manager->lock); ++ rga_request_put(request); ++ mutex_unlock(&request_manager->lock); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int rga_request_check(struct rga_user_request *req) ++{ ++ if (req->id <= 0) { ++ pr_err("user request id[%d] is invalid", req->id); ++ return -EINVAL; ++ } ++ ++ if (req->task_num <= 0) { ++ pr_err("invalied user request!\n"); ++ return -EINVAL; ++ } ++ ++ if (req->task_ptr == 0) { ++ pr_err("task_ptr is NULL!\n"); ++ return -EINVAL; ++ } ++ ++ if (req->task_num > RGA_TASK_NUM_MAX) { ++ pr_err("Only supports running %d tasks, now %d\n", ++ RGA_TASK_NUM_MAX, req->task_num); ++ return -EFBIG; ++ } ++ ++ return 0; ++} ++ ++struct rga_request *rga_request_lookup(struct rga_pending_request_manager *manager, uint32_t id) ++{ ++ struct rga_request *request = NULL; ++ ++ WARN_ON(!mutex_is_locked(&manager->lock)); ++ ++ request = idr_find(&manager->request_idr, id); ++ ++ return request; ++} ++ ++static int rga_request_scheduler_job_abort(struct rga_request *request) ++{ ++ int i; ++ unsigned long flags; ++ enum rga_scheduler_status scheduler_status; ++ int running_abort_count = 0, todo_abort_count = 0; ++ struct rga_scheduler_t *scheduler = NULL; ++ struct rga_job *job, *job_q; ++ LIST_HEAD(list_to_free); ++ ++ for (i = 0; i < rga_drvdata->num_of_scheduler; i++) { ++ scheduler = rga_drvdata->scheduler[i]; ++ spin_lock_irqsave(&scheduler->irq_lock, flags); ++ ++ list_for_each_entry_safe(job, job_q, &scheduler->todo_list, head) { ++ if (request->id == job->request_id) { ++ list_move(&job->head, &list_to_free); ++ scheduler->job_count--; ++ ++ todo_abort_count++; ++ } ++ } ++ ++ job = NULL; ++ if (scheduler->running_job) { ++ if (request->id == scheduler->running_job->request_id) { ++ job = scheduler->running_job; ++ scheduler_status = scheduler->status; ++ scheduler->running_job = NULL; ++ scheduler->status = RGA_SCHEDULER_ABORT; ++ list_add_tail(&job->head, &list_to_free); ++ ++ if (job->hw_running_time != 0) { ++ scheduler->timer.busy_time += ++ ktime_us_delta(ktime_get(), job->hw_recoder_time); ++ scheduler->ops->soft_reset(scheduler); ++ } ++ ++ pr_err("reset core[%d] by request[%d] abort", ++ scheduler->core, request->id); ++ running_abort_count++; ++ } ++ } ++ ++ spin_unlock_irqrestore(&scheduler->irq_lock, flags); ++ ++ if (job && scheduler_status == RGA_SCHEDULER_WORKING) ++ rga_power_disable(scheduler); ++ } ++ ++ /* Clean up the jobs in the todo list that need to be free. */ ++ list_for_each_entry_safe(job, job_q, &list_to_free, head) { ++ rga_mm_unmap_job_info(job); ++ ++ job->ret = -EBUSY; ++ rga_job_cleanup(job); ++ } ++ ++ /* This means it has been cleaned up. */ ++ if (running_abort_count + todo_abort_count == 0) ++ return 1; ++ ++ pr_err("request[%d] abort! finished %d failed %d running_abort %d todo_abort %d\n", ++ request->id, request->finished_task_count, request->failed_task_count, ++ running_abort_count, todo_abort_count); ++ ++ return 0; ++} ++ ++static void rga_request_release_abort(struct rga_request *request, int err_code) ++{ ++ unsigned long flags; ++ struct mm_struct *current_mm; ++ struct rga_pending_request_manager *request_manager = rga_drvdata->pend_request_manager; ++ ++ if (rga_request_scheduler_job_abort(request) > 0) ++ return; ++ ++ spin_lock_irqsave(&request->lock, flags); ++ ++ if (request->is_done) { ++ spin_unlock_irqrestore(&request->lock, flags); ++ return; ++ } ++ ++ request->is_running = false; ++ request->is_done = false; ++ current_mm = request->current_mm; ++ request->current_mm = NULL; ++ ++ spin_unlock_irqrestore(&request->lock, flags); ++ ++ rga_request_put_current_mm(current_mm); ++ ++ rga_dma_fence_signal(request->release_fence, err_code); ++ ++ mutex_lock(&request_manager->lock); ++ /* current submit request put */ ++ rga_request_put(request); ++ mutex_unlock(&request_manager->lock); ++} ++ ++void rga_request_session_destroy_abort(struct rga_session *session) ++{ ++ int request_id; ++ struct rga_request *request; ++ struct rga_pending_request_manager *request_manager; ++ ++ request_manager = rga_drvdata->pend_request_manager; ++ if (request_manager == NULL) { ++ pr_err("rga_pending_request_manager is null!\n"); ++ return; ++ } ++ ++ mutex_lock(&request_manager->lock); ++ ++ idr_for_each_entry(&request_manager->request_idr, request, request_id) { ++ if (session == request->session) { ++ pr_err("[tgid:%d pid:%d] destroy request[%d] when the user exits", ++ session->tgid, current->pid, request->id); ++ rga_request_put(request); ++ } ++ } ++ ++ mutex_unlock(&request_manager->lock); ++} ++ ++static int rga_request_timeout_query_state(struct rga_request *request) ++{ ++ int i; ++ unsigned long flags; ++ struct rga_scheduler_t *scheduler = NULL; ++ struct rga_job *job = NULL; ++ ++ for (i = 0; i < rga_drvdata->num_of_scheduler; i++) { ++ scheduler = rga_drvdata->scheduler[i]; ++ ++ spin_lock_irqsave(&scheduler->irq_lock, flags); ++ ++ if (scheduler->running_job) { ++ job = scheduler->running_job; ++ if (request->id == job->request_id) { ++ if (test_bit(RGA_JOB_STATE_DONE, &job->state) && ++ test_bit(RGA_JOB_STATE_FINISH, &job->state)) { ++ spin_unlock_irqrestore(&scheduler->irq_lock, flags); ++ return request->ret; ++ } else if (!test_bit(RGA_JOB_STATE_DONE, &job->state) && ++ test_bit(RGA_JOB_STATE_FINISH, &job->state)) { ++ spin_unlock_irqrestore(&scheduler->irq_lock, flags); ++ pr_err("request[%d] hardware has finished, but the software has timeout!\n", ++ request->id); ++ return -EBUSY; ++ } else if (!test_bit(RGA_JOB_STATE_DONE, &job->state) && ++ !test_bit(RGA_JOB_STATE_FINISH, &job->state)) { ++ spin_unlock_irqrestore(&scheduler->irq_lock, flags); ++ pr_err("request[%d] hardware has timeout.\n", request->id); ++ return -EBUSY; ++ } ++ } ++ } ++ ++ spin_unlock_irqrestore(&scheduler->irq_lock, flags); ++ } ++ ++ return request->ret; ++} ++ ++static int rga_request_wait(struct rga_request *request) ++{ ++ int left_time; ++ int ret; ++ ++ left_time = wait_event_timeout(request->finished_wq, request->is_done, ++ RGA_JOB_TIMEOUT_DELAY * request->task_count); ++ ++ switch (left_time) { ++ case 0: ++ ret = rga_request_timeout_query_state(request); ++ goto err_request_abort; ++ case -ERESTARTSYS: ++ ret = -ERESTARTSYS; ++ goto err_request_abort; ++ default: ++ ret = request->ret; ++ break; ++ } ++ ++ return ret; ++ ++err_request_abort: ++ rga_request_release_abort(request, ret); ++ ++ return ret; ++} ++ ++int rga_request_commit(struct rga_request *request) ++{ ++ int ret; ++ int i = 0; ++ struct rga_job *job; ++ ++ for (i = 0; i < request->task_count; i++) { ++ struct rga_req *req = &(request->task_list[i]); ++ ++ if (DEBUGGER_EN(MSG)) { ++ pr_info("commit request[%d] task[%d]:\n", request->id, i); ++ rga_cmd_print_debug_info(req); ++ } ++ ++ job = rga_job_commit(req, request); ++ if (IS_ERR(job)) { ++ pr_err("request[%d] task[%d] job_commit failed.\n", request->id, i); ++ rga_request_release_abort(request, PTR_ERR(job)); ++ ++ return PTR_ERR(job); ++ } ++ } ++ ++ if (request->sync_mode == RGA_BLIT_SYNC) { ++ ret = rga_request_wait(request); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void rga_request_acquire_fence_signaled_cb(struct dma_fence *fence, ++ struct dma_fence_cb *_waiter) ++{ ++ int ret; ++ unsigned long flags; ++ struct mm_struct *current_mm; ++ struct rga_fence_waiter *waiter = (struct rga_fence_waiter *)_waiter; ++ struct rga_request *request = (struct rga_request *)waiter->private; ++ struct rga_pending_request_manager *request_manager = rga_drvdata->pend_request_manager; ++ ++ ret = rga_request_commit(request); ++ if (ret < 0) { ++ pr_err("acquire_fence callback: rga request[%d] commit failed!\n", request->id); ++ ++ spin_lock_irqsave(&request->lock, flags); ++ ++ request->is_running = false; ++ current_mm = request->current_mm; ++ request->current_mm = NULL; ++ ++ spin_unlock_irqrestore(&request->lock, flags); ++ ++ rga_request_put_current_mm(current_mm); ++ ++ /* ++ * Since the callback is called while holding &dma_fence.lock, ++ * the _locked API is used here. ++ */ ++ if (dma_fence_get_status_locked(request->release_fence) == 0) ++ dma_fence_signal_locked(request->release_fence); ++ } ++ ++ mutex_lock(&request_manager->lock); ++ rga_request_put(request); ++ mutex_unlock(&request_manager->lock); ++ ++ kfree(waiter); ++} ++ ++int rga_request_release_signal(struct rga_scheduler_t *scheduler, struct rga_job *job) ++{ ++ struct rga_pending_request_manager *request_manager; ++ struct rga_request *request; ++ struct mm_struct *current_mm; ++ int finished_count, failed_count; ++ bool is_finished = false; ++ unsigned long flags; ++ ++ request_manager = rga_drvdata->pend_request_manager; ++ if (request_manager == NULL) { ++ pr_err("rga_pending_request_manager is null!\n"); ++ return -EFAULT; ++ } ++ ++ mutex_lock(&request_manager->lock); ++ ++ request = rga_request_lookup(request_manager, job->request_id); ++ if (IS_ERR_OR_NULL(request)) { ++ pr_err("can not find internal request from id[%d]", job->request_id); ++ mutex_unlock(&request_manager->lock); ++ return -EINVAL; ++ } ++ ++ rga_request_get(request); ++ mutex_unlock(&request_manager->lock); ++ ++ spin_lock_irqsave(&request->lock, flags); ++ ++ if (job->ret < 0) { ++ request->failed_task_count++; ++ request->ret = job->ret; ++ } else { ++ request->finished_task_count++; ++ } ++ ++ failed_count = request->failed_task_count; ++ finished_count = request->finished_task_count; ++ ++ spin_unlock_irqrestore(&request->lock, flags); ++ ++ if ((failed_count + finished_count) >= request->task_count) { ++ spin_lock_irqsave(&request->lock, flags); ++ ++ request->is_running = false; ++ request->is_done = true; ++ current_mm = request->current_mm; ++ request->current_mm = NULL; ++ ++ spin_unlock_irqrestore(&request->lock, flags); ++ ++ rga_request_put_current_mm(current_mm); ++ ++ rga_dma_fence_signal(request->release_fence, request->ret); ++ ++ is_finished = true; ++ ++ if (DEBUGGER_EN(MSG)) ++ pr_info("request[%d] finished %d failed %d\n", ++ request->id, finished_count, failed_count); ++ ++ /* current submit request put */ ++ mutex_lock(&request_manager->lock); ++ rga_request_put(request); ++ mutex_unlock(&request_manager->lock); ++ } ++ ++ mutex_lock(&request_manager->lock); ++ ++ if (is_finished) ++ wake_up(&request->finished_wq); ++ ++ rga_request_put(request); ++ ++ mutex_unlock(&request_manager->lock); ++ ++ if (DEBUGGER_EN(TIME)) ++ pr_info("request[%d], job done total cost time %lld us\n", ++ job->request_id, ++ ktime_us_delta(ktime_get(), job->timestamp)); ++ ++ rga_job_cleanup(job); ++ ++ return 0; ++} ++ ++struct rga_request *rga_request_config(struct rga_user_request *user_request) ++{ ++ int ret; ++ unsigned long flags; ++ struct rga_pending_request_manager *request_manager; ++ struct rga_request *request; ++ struct rga_req *task_list; ++ ++ request_manager = rga_drvdata->pend_request_manager; ++ if (request_manager == NULL) { ++ pr_err("rga_pending_request_manager is null!\n"); ++ return ERR_PTR(-EFAULT); ++ } ++ ++ mutex_lock(&request_manager->lock); ++ ++ request = rga_request_lookup(request_manager, user_request->id); ++ if (IS_ERR_OR_NULL(request)) { ++ pr_err("can not find request from id[%d]", user_request->id); ++ mutex_unlock(&request_manager->lock); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ rga_request_get(request); ++ mutex_unlock(&request_manager->lock); ++ ++ task_list = kmalloc_array(user_request->task_num, sizeof(struct rga_req), GFP_KERNEL); ++ if (task_list == NULL) { ++ pr_err("task_req list alloc error!\n"); ++ ret = -ENOMEM; ++ goto err_put_request; ++ } ++ ++ if (unlikely(copy_from_user(task_list, u64_to_user_ptr(user_request->task_ptr), ++ sizeof(struct rga_req) * user_request->task_num))) { ++ pr_err("rga_user_request task list copy_from_user failed\n"); ++ ret = -EFAULT; ++ goto err_free_task_list; ++ } ++ ++ spin_lock_irqsave(&request->lock, flags); ++ ++ request->use_batch_mode = true; ++ request->task_list = task_list; ++ request->task_count = user_request->task_num; ++ request->sync_mode = user_request->sync_mode; ++ request->mpi_config_flags = user_request->mpi_config_flags; ++ request->acquire_fence_fd = user_request->acquire_fence_fd; ++ request->feature = task_list[0].feature; ++ ++ spin_unlock_irqrestore(&request->lock, flags); ++ ++ return request; ++ ++err_free_task_list: ++ kfree(task_list); ++err_put_request: ++ mutex_lock(&request_manager->lock); ++ rga_request_put(request); ++ mutex_unlock(&request_manager->lock); ++ ++ return ERR_PTR(ret); ++} ++ ++struct rga_request *rga_request_kernel_config(struct rga_user_request *user_request) ++{ ++ int ret = 0; ++ unsigned long flags; ++ struct rga_pending_request_manager *request_manager; ++ struct rga_request *request; ++ struct rga_req *task_list; ++ ++ request_manager = rga_drvdata->pend_request_manager; ++ if (request_manager == NULL) { ++ pr_err("rga_pending_request_manager is null!\n"); ++ return ERR_PTR(-EFAULT); ++ } ++ ++ mutex_lock(&request_manager->lock); ++ ++ request = rga_request_lookup(request_manager, user_request->id); ++ if (IS_ERR_OR_NULL(request)) { ++ pr_err("can not find request from id[%d]", user_request->id); ++ mutex_unlock(&request_manager->lock); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ rga_request_get(request); ++ mutex_unlock(&request_manager->lock); ++ ++ task_list = kmalloc_array(user_request->task_num, sizeof(struct rga_req), GFP_KERNEL); ++ if (task_list == NULL) { ++ pr_err("task_req list alloc error!\n"); ++ ret = -ENOMEM; ++ goto err_put_request; ++ } ++ ++ memcpy(task_list, u64_to_user_ptr(user_request->task_ptr), ++ sizeof(struct rga_req) * user_request->task_num); ++ ++ spin_lock_irqsave(&request->lock, flags); ++ ++ request->use_batch_mode = true; ++ request->task_list = task_list; ++ request->task_count = user_request->task_num; ++ request->sync_mode = user_request->sync_mode; ++ request->mpi_config_flags = user_request->mpi_config_flags; ++ request->acquire_fence_fd = user_request->acquire_fence_fd; ++ ++ spin_unlock_irqrestore(&request->lock, flags); ++ ++ return request; ++ ++err_put_request: ++ mutex_lock(&request_manager->lock); ++ rga_request_put(request); ++ mutex_unlock(&request_manager->lock); ++ ++ return ERR_PTR(ret); ++} ++ ++int rga_request_submit(struct rga_request *request) ++{ ++ int ret = 0; ++ unsigned long flags; ++ struct dma_fence *release_fence; ++ struct mm_struct *current_mm; ++ ++ current_mm = rga_request_get_current_mm(request); ++ ++ spin_lock_irqsave(&request->lock, flags); ++ ++ if (request->is_running) { ++ spin_unlock_irqrestore(&request->lock, flags); ++ ++ pr_err("can not re-config when request is running\n"); ++ ret = -EFAULT; ++ goto err_put_current_mm; ++ } ++ ++ if (request->task_list == NULL) { ++ spin_unlock_irqrestore(&request->lock, flags); ++ ++ pr_err("can not find task list from id[%d]\n", request->id); ++ ret = -EINVAL; ++ goto err_put_current_mm; ++ } ++ ++ /* Reset */ ++ request->is_running = true; ++ request->is_done = false; ++ request->finished_task_count = 0; ++ request->failed_task_count = 0; ++ request->current_mm = current_mm; ++ ++ /* Unlock after ensuring that the current request will not be resubmitted. */ ++ spin_unlock_irqrestore(&request->lock, flags); ++ ++ if (request->sync_mode == RGA_BLIT_ASYNC) { ++ release_fence = rga_dma_fence_alloc(); ++ if (IS_ERR(release_fence)) { ++ pr_err("Can not alloc release fence!\n"); ++ ret = IS_ERR(release_fence); ++ goto err_reset_request; ++ } ++ request->release_fence = release_fence; ++ ++ if (request->acquire_fence_fd > 0) { ++ ret = rga_request_add_acquire_fence_callback( ++ request->acquire_fence_fd, request, ++ rga_request_acquire_fence_signaled_cb); ++ if (ret == 0) { ++ /* acquire fence active */ ++ goto export_release_fence_fd; ++ } else if (ret > 0) { ++ /* acquire fence has been signaled */ ++ goto request_commit; ++ } else { ++ pr_err("Failed to add callback with acquire fence fd[%d]!\n", ++ request->acquire_fence_fd); ++ goto err_put_release_fence; ++ } ++ } ++ } ++ ++request_commit: ++ ret = rga_request_commit(request); ++ if (ret < 0) { ++ pr_err("rga request[%d] commit failed!\n", request->id); ++ goto err_put_release_fence; ++ } ++ ++export_release_fence_fd: ++ if (request->release_fence != NULL) { ++ ret = rga_dma_fence_get_fd(request->release_fence); ++ if (ret < 0) { ++ pr_err("Failed to alloc release fence fd!\n"); ++ rga_request_release_abort(request, ret); ++ return ret; ++ } ++ ++ request->release_fence_fd = ret; ++ } ++ ++ return 0; ++ ++err_put_release_fence: ++ if (request->release_fence != NULL) { ++ rga_dma_fence_put(request->release_fence); ++ request->release_fence = NULL; ++ } ++ ++err_reset_request: ++ spin_lock_irqsave(&request->lock, flags); ++ ++ request->current_mm = NULL; ++ request->is_running = false; ++ ++ spin_unlock_irqrestore(&request->lock, flags); ++ ++err_put_current_mm: ++ rga_request_put_current_mm(current_mm); ++ ++ return ret; ++} ++ ++int rga_request_mpi_submit(struct rga_req *req, struct rga_request *request) ++{ ++ int ret = 0; ++ struct rga_job *job = NULL; ++ unsigned long flags; ++ ++ if (request->sync_mode == RGA_BLIT_ASYNC) { ++ pr_err("mpi unsupported async mode!\n"); ++ return -EINVAL; ++ } ++ ++ spin_lock_irqsave(&request->lock, flags); ++ ++ if (request->is_running) { ++ pr_err("can not re-config when request is running"); ++ spin_unlock_irqrestore(&request->lock, flags); ++ return -EFAULT; ++ } ++ ++ if (request->task_list == NULL) { ++ pr_err("can not find task list from id[%d]", request->id); ++ spin_unlock_irqrestore(&request->lock, flags); ++ return -EINVAL; ++ } ++ ++ /* Reset */ ++ request->is_running = true; ++ request->is_done = false; ++ request->finished_task_count = 0; ++ request->failed_task_count = 0; ++ ++ spin_unlock_irqrestore(&request->lock, flags); ++ ++ job = rga_job_commit(req, request); ++ if (IS_ERR_OR_NULL(job)) { ++ pr_err("failed to commit job!\n"); ++ return job ? PTR_ERR(job) : -EFAULT; ++ } ++ ++ ret = rga_request_wait(request); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++int rga_request_free(struct rga_request *request) ++{ ++ struct rga_pending_request_manager *request_manager; ++ struct rga_req *task_list; ++ unsigned long flags; ++ ++ request_manager = rga_drvdata->pend_request_manager; ++ if (request_manager == NULL) { ++ pr_err("rga_pending_request_manager is null!\n"); ++ return -EFAULT; ++ } ++ ++ WARN_ON(!mutex_is_locked(&request_manager->lock)); ++ ++ if (IS_ERR_OR_NULL(request)) { ++ pr_err("request already freed"); ++ return -EFAULT; ++ } ++ ++ request_manager->request_count--; ++ idr_remove(&request_manager->request_idr, request->id); ++ ++ spin_lock_irqsave(&request->lock, flags); ++ ++ task_list = request->task_list; ++ ++ spin_unlock_irqrestore(&request->lock, flags); ++ ++ if (task_list != NULL) ++ kfree(task_list); ++ ++ kfree(request); ++ ++ return 0; ++} ++ ++static void rga_request_kref_release(struct kref *ref) ++{ ++ struct rga_request *request; ++ struct mm_struct *current_mm; ++ unsigned long flags; ++ ++ request = container_of(ref, struct rga_request, refcount); ++ ++ if (rga_dma_fence_get_status(request->release_fence) == 0) ++ rga_dma_fence_signal(request->release_fence, -EFAULT); ++ ++ spin_lock_irqsave(&request->lock, flags); ++ ++ rga_dma_fence_put(request->release_fence); ++ current_mm = request->current_mm; ++ request->current_mm = NULL; ++ ++ if (!request->is_running || request->is_done) { ++ spin_unlock_irqrestore(&request->lock, flags); ++ ++ rga_request_put_current_mm(current_mm); ++ ++ goto free_request; ++ } ++ ++ spin_unlock_irqrestore(&request->lock, flags); ++ ++ rga_request_put_current_mm(current_mm); ++ ++ rga_request_scheduler_job_abort(request); ++ ++free_request: ++ rga_request_free(request); ++} ++ ++/* ++ * Called at driver close to release the request's id references. ++ */ ++static int rga_request_free_cb(int id, void *ptr, void *data) ++{ ++ return rga_request_free((struct rga_request *)ptr); ++} ++ ++int rga_request_alloc(uint32_t flags, struct rga_session *session) ++{ ++ int new_id; ++ struct rga_pending_request_manager *request_manager; ++ struct rga_request *request; ++ ++ request_manager = rga_drvdata->pend_request_manager; ++ if (request_manager == NULL) { ++ pr_err("rga_pending_request_manager is null!\n"); ++ return -EFAULT; ++ } ++ ++ request = kzalloc(sizeof(*request), GFP_KERNEL); ++ if (request == NULL) { ++ pr_err("can not kzalloc for rga_request\n"); ++ return -ENOMEM; ++ } ++ ++ spin_lock_init(&request->lock); ++ init_waitqueue_head(&request->finished_wq); ++ ++ request->pid = current->pid; ++ request->flags = flags; ++ request->session = session; ++ kref_init(&request->refcount); ++ ++ /* ++ * Get the user-visible handle using idr. Preload and perform ++ * allocation under our spinlock. ++ */ ++ mutex_lock(&request_manager->lock); ++ ++ idr_preload(GFP_KERNEL); ++ new_id = idr_alloc_cyclic(&request_manager->request_idr, request, 1, 0, GFP_NOWAIT); ++ idr_preload_end(); ++ if (new_id < 0) { ++ pr_err("request alloc id failed!\n"); ++ ++ mutex_unlock(&request_manager->lock); ++ kfree(request); ++ return new_id; ++ } ++ ++ request->id = new_id; ++ request_manager->request_count++; ++ ++ mutex_unlock(&request_manager->lock); ++ ++ return request->id; ++} ++ ++int rga_request_put(struct rga_request *request) ++{ ++ return kref_put(&request->refcount, rga_request_kref_release); ++} ++ ++void rga_request_get(struct rga_request *request) ++{ ++ kref_get(&request->refcount); ++} ++ ++int rga_request_manager_init(struct rga_pending_request_manager **request_manager_session) ++{ ++ struct rga_pending_request_manager *request_manager = NULL; ++ ++ *request_manager_session = kzalloc(sizeof(struct rga_pending_request_manager), GFP_KERNEL); ++ if (*request_manager_session == NULL) { ++ pr_err("can not kzalloc for rga_pending_request_manager\n"); ++ return -ENOMEM; ++ } ++ ++ request_manager = *request_manager_session; ++ ++ mutex_init(&request_manager->lock); ++ ++ idr_init_base(&request_manager->request_idr, 1); ++ ++ return 0; ++} ++ ++int rga_request_manager_remove(struct rga_pending_request_manager **request_manager_session) ++{ ++ struct rga_pending_request_manager *request_manager = *request_manager_session; ++ ++ mutex_lock(&request_manager->lock); ++ ++ idr_for_each(&request_manager->request_idr, &rga_request_free_cb, request_manager); ++ idr_destroy(&request_manager->request_idr); ++ ++ mutex_unlock(&request_manager->lock); ++ ++ kfree(*request_manager_session); ++ ++ *request_manager_session = NULL; ++ ++ return 0; ++} +diff --git a/drivers/video/rockchip/rga3/rga_mm.c b/drivers/video/rockchip/rga3/rga_mm.c +new file mode 100644 +index 000000000..51a31f450 +--- /dev/null ++++ b/drivers/video/rockchip/rga3/rga_mm.c +@@ -0,0 +1,2229 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) Rockchip Electronics Co., Ltd. ++ * ++ * Author: Cerf Yu ++ */ ++ ++#define pr_fmt(fmt) "rga_mm: " fmt ++ ++#include "rga.h" ++#include "rga_job.h" ++#include "rga_mm.h" ++#include "rga_dma_buf.h" ++#include "rga_common.h" ++#include "rga_iommu.h" ++#include "rga_hw_config.h" ++#include "rga_debugger.h" ++ ++static void rga_current_mm_read_lock(struct mm_struct *mm) ++{ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) ++ mmap_read_lock(mm); ++#else ++ down_read(&mm->mmap_sem); ++#endif ++} ++ ++static void rga_current_mm_read_unlock(struct mm_struct *mm) ++{ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) ++ mmap_read_unlock(mm); ++#else ++ up_read(&mm->mmap_sem); ++#endif ++} ++ ++static int rga_get_user_pages_from_vma(struct page **pages, unsigned long Memory, ++ uint32_t pageCount, struct mm_struct *current_mm) ++{ ++ int ret = 0; ++ int i; ++ struct vm_area_struct *vma; ++ spinlock_t *ptl; ++ pte_t *pte; ++ pgd_t *pgd; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) ++ p4d_t *p4d; ++#endif ++ pud_t *pud; ++ pmd_t *pmd; ++ unsigned long pfn; ++ ++ for (i = 0; i < pageCount; i++) { ++ vma = find_vma(current_mm, (Memory + i) << PAGE_SHIFT); ++ if (!vma) { ++ pr_err("page[%d] failed to get vma\n", i); ++ ret = RGA_OUT_OF_RESOURCES; ++ break; ++ } ++ ++ pgd = pgd_offset(current_mm, (Memory + i) << PAGE_SHIFT); ++ if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) { ++ pr_err("page[%d] failed to get pgd\n", i); ++ ret = RGA_OUT_OF_RESOURCES; ++ break; ++ } ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) ++ /* ++ * In the four-level page table, ++ * it will do nothing and return pgd. ++ */ ++ p4d = p4d_offset(pgd, (Memory + i) << PAGE_SHIFT); ++ if (p4d_none(*p4d) || unlikely(p4d_bad(*p4d))) { ++ pr_err("page[%d] failed to get p4d\n", i); ++ ret = RGA_OUT_OF_RESOURCES; ++ break; ++ } ++ ++ pud = pud_offset(p4d, (Memory + i) << PAGE_SHIFT); ++#else ++ pud = pud_offset(pgd, (Memory + i) << PAGE_SHIFT); ++#endif ++ ++ if (pud_none(*pud) || unlikely(pud_bad(*pud))) { ++ pr_err("page[%d] failed to get pud\n", i); ++ ret = RGA_OUT_OF_RESOURCES; ++ break; ++ } ++ pmd = pmd_offset(pud, (Memory + i) << PAGE_SHIFT); ++ if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) { ++ pr_err("page[%d] failed to get pmd\n", i); ++ ret = RGA_OUT_OF_RESOURCES; ++ break; ++ } ++ pte = pte_offset_map_lock(current_mm, pmd, ++ (Memory + i) << PAGE_SHIFT, &ptl); ++ if (pte_none(*pte)) { ++ pr_err("page[%d] failed to get pte\n", i); ++ pte_unmap_unlock(pte, ptl); ++ ret = RGA_OUT_OF_RESOURCES; ++ break; ++ } ++ ++ pfn = pte_pfn(*pte); ++ pages[i] = pfn_to_page(pfn); ++ pte_unmap_unlock(pte, ptl); ++ } ++ ++ if (ret == RGA_OUT_OF_RESOURCES && i > 0) ++ pr_err("Only get buffer %d byte from vma, but current image required %d byte", ++ (int)(i * PAGE_SIZE), (int)(pageCount * PAGE_SIZE)); ++ ++ return ret; ++} ++ ++static int rga_get_user_pages(struct page **pages, unsigned long Memory, ++ uint32_t pageCount, int writeFlag, ++ struct mm_struct *current_mm) ++{ ++ uint32_t i; ++ int32_t ret = 0; ++ int32_t result; ++ ++ rga_current_mm_read_lock(current_mm); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 168) && \ ++ LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0) ++ result = get_user_pages(current, current_mm, Memory << PAGE_SHIFT, ++ pageCount, writeFlag ? FOLL_WRITE : 0, ++ pages, NULL); ++#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0) ++ result = get_user_pages(current, current_mm, Memory << PAGE_SHIFT, ++ pageCount, writeFlag ? FOLL_WRITE : 0, 0, pages, NULL); ++#elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) ++ result = get_user_pages_remote(current, current_mm, ++ Memory << PAGE_SHIFT, ++ pageCount, writeFlag ? FOLL_WRITE : 0, pages, NULL); ++#else ++ result = get_user_pages_remote(current_mm, Memory << PAGE_SHIFT, ++ pageCount, writeFlag ? FOLL_WRITE : 0, pages, NULL); ++#endif ++ ++ if (result > 0 && result >= pageCount) { ++ ret = result; ++ } else { ++ if (result > 0) ++ for (i = 0; i < result; i++) ++ put_page(pages[i]); ++ ++ ret = rga_get_user_pages_from_vma(pages, Memory, pageCount, current_mm); ++ if (ret < 0 && result > 0) { ++ pr_err("Only get buffer %d byte from user pages, but current image required %d byte\n", ++ (int)(result * PAGE_SIZE), (int)(pageCount * PAGE_SIZE)); ++ } ++ } ++ ++ rga_current_mm_read_unlock(current_mm); ++ ++ return ret; ++} ++ ++static void rga_free_sgt(struct sg_table **sgt_ptr) ++{ ++ if (sgt_ptr == NULL || *sgt_ptr == NULL) ++ return; ++ ++ sg_free_table(*sgt_ptr); ++ kfree(*sgt_ptr); ++ *sgt_ptr = NULL; ++} ++ ++static struct sg_table *rga_alloc_sgt(struct rga_virt_addr *virt_addr) ++{ ++ int ret; ++ struct sg_table *sgt = NULL; ++ ++ sgt = kzalloc(sizeof(*sgt), GFP_KERNEL); ++ if (sgt == NULL) { ++ pr_err("%s alloc sgt error!\n", __func__); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ /* get sg form pages. */ ++ /* iova requires minimum page alignment, so sgt cannot have offset */ ++ ret = sg_alloc_table_from_pages(sgt, ++ virt_addr->pages, ++ virt_addr->page_count, ++ 0, ++ virt_addr->size, ++ GFP_KERNEL); ++ if (ret) { ++ pr_err("sg_alloc_table_from_pages failed"); ++ goto out_free_sgt; ++ } ++ ++ return sgt; ++ ++out_free_sgt: ++ kfree(sgt); ++ ++ return ERR_PTR(ret); ++} ++ ++static void rga_free_virt_addr(struct rga_virt_addr **virt_addr_p) ++{ ++ int i; ++ struct rga_virt_addr *virt_addr = NULL; ++ ++ if (virt_addr_p == NULL) ++ return; ++ ++ virt_addr = *virt_addr_p; ++ if (virt_addr == NULL) ++ return; ++ ++ for (i = 0; i < virt_addr->result; i++) ++ put_page(virt_addr->pages[i]); ++ ++ free_pages((unsigned long)virt_addr->pages, virt_addr->pages_order); ++ kfree(virt_addr); ++ *virt_addr_p = NULL; ++} ++ ++static int rga_alloc_virt_addr(struct rga_virt_addr **virt_addr_p, ++ uint64_t viraddr, ++ struct rga_memory_parm *memory_parm, ++ int writeFlag, ++ struct mm_struct *mm) ++{ ++ int i; ++ int ret; ++ int result = 0; ++ int order; ++ unsigned int count; ++ int img_size; ++ size_t offset; ++ unsigned long size; ++ struct page **pages = NULL; ++ struct rga_virt_addr *virt_addr = NULL; ++ ++ if (memory_parm->size) ++ img_size = memory_parm->size; ++ else ++ img_size = rga_image_size_cal(memory_parm->width, ++ memory_parm->height, ++ memory_parm->format, ++ NULL, NULL, NULL); ++ ++ offset = viraddr & (~PAGE_MASK); ++ count = RGA_GET_PAGE_COUNT(img_size + offset); ++ size = count * PAGE_SIZE; ++ if (!size) { ++ pr_err("failed to calculating buffer size! size = %ld, count = %d, offset = %ld\n", ++ size, count, (unsigned long)offset); ++ rga_dump_memory_parm(memory_parm); ++ return -EFAULT; ++ } ++ ++ /* alloc pages and page_table */ ++ order = get_order(count * sizeof(struct page *)); ++ if (order >= MAX_ORDER) { ++ pr_err("Can not alloc pages with order[%d] for viraddr pages, max_order = %d\n", ++ order, MAX_ORDER); ++ return -ENOMEM; ++ } ++ ++ pages = (struct page **)__get_free_pages(GFP_KERNEL, order); ++ if (pages == NULL) { ++ pr_err("%s can not alloc pages for viraddr pages\n", __func__); ++ return -ENOMEM; ++ } ++ ++ /* get pages from virtual address. */ ++ ret = rga_get_user_pages(pages, viraddr >> PAGE_SHIFT, count, writeFlag, mm); ++ if (ret < 0) { ++ pr_err("failed to get pages from virtual adrees: 0x%lx\n", ++ (unsigned long)viraddr); ++ ret = -EINVAL; ++ goto out_free_pages; ++ } else if (ret > 0) { ++ /* For put pages */ ++ result = ret; ++ } ++ ++ *virt_addr_p = kzalloc(sizeof(struct rga_virt_addr), GFP_KERNEL); ++ if (*virt_addr_p == NULL) { ++ pr_err("%s alloc virt_addr error!\n", __func__); ++ ret = -ENOMEM; ++ goto out_put_and_free_pages; ++ } ++ virt_addr = *virt_addr_p; ++ ++ virt_addr->addr = viraddr; ++ virt_addr->pages = pages; ++ virt_addr->pages_order = order; ++ virt_addr->page_count = count; ++ virt_addr->size = size; ++ virt_addr->offset = offset; ++ virt_addr->result = result; ++ ++ return 0; ++ ++out_put_and_free_pages: ++ for (i = 0; i < result; i++) ++ put_page(pages[i]); ++out_free_pages: ++ free_pages((unsigned long)pages, order); ++ ++ return ret; ++} ++ ++static inline bool rga_mm_check_memory_limit(struct rga_scheduler_t *scheduler, int mm_flag) ++{ ++ if (!scheduler) ++ return false; ++ ++ if (scheduler->data->mmu == RGA_MMU && ++ !(mm_flag & RGA_MEM_UNDER_4G)) { ++ pr_err("%s unsupported memory larger than 4G!\n", ++ rga_get_mmu_type_str(scheduler->data->mmu)); ++ return false; ++ } ++ ++ return true; ++} ++ ++/* If it is within 0~4G, return 1 (true). */ ++static int rga_mm_check_range_sgt(struct sg_table *sgt) ++{ ++ int i; ++ struct scatterlist *sg; ++ phys_addr_t s_phys = 0; ++ ++ for_each_sg(sgt->sgl, sg, sgt->orig_nents, i) { ++ s_phys = sg_phys(sg); ++ if ((s_phys > 0xffffffff) || (s_phys + sg->length > 0xffffffff)) ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static inline int rga_mm_check_range_phys_addr(phys_addr_t paddr, size_t size) ++{ ++ return ((paddr + size) <= 0xffffffff); ++} ++ ++static inline bool rga_mm_check_contiguous_sgt(struct sg_table *sgt) ++{ ++ if (sgt->orig_nents == 1) ++ return true; ++ ++ return false; ++} ++ ++static void rga_mm_unmap_dma_buffer(struct rga_internal_buffer *internal_buffer) ++{ ++ if (rga_mm_is_invalid_dma_buffer(internal_buffer->dma_buffer)) ++ return; ++ ++ rga_dma_unmap_buf(internal_buffer->dma_buffer); ++ ++ if (internal_buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS && ++ internal_buffer->phys_addr > 0) ++ internal_buffer->phys_addr = 0; ++ ++ kfree(internal_buffer->dma_buffer); ++ internal_buffer->dma_buffer = NULL; ++} ++ ++static int rga_mm_map_dma_buffer(struct rga_external_buffer *external_buffer, ++ struct rga_internal_buffer *internal_buffer, ++ struct rga_job *job) ++{ ++ int ret; ++ int ex_buffer_size; ++ uint32_t mm_flag = 0; ++ phys_addr_t phys_addr = 0; ++ struct rga_dma_buffer *buffer; ++ struct device *map_dev; ++ struct rga_scheduler_t *scheduler; ++ ++ scheduler = job ? job->scheduler : ++ rga_drvdata->scheduler[rga_drvdata->map_scheduler_index]; ++ if (scheduler == NULL) { ++ pr_err("Invalid scheduler device!\n"); ++ return -EINVAL; ++ } ++ ++ if (external_buffer->memory_parm.size) ++ ex_buffer_size = external_buffer->memory_parm.size; ++ else ++ ex_buffer_size = rga_image_size_cal(external_buffer->memory_parm.width, ++ external_buffer->memory_parm.height, ++ external_buffer->memory_parm.format, ++ NULL, NULL, NULL); ++ if (ex_buffer_size <= 0) { ++ pr_err("failed to calculating buffer size!\n"); ++ rga_dump_memory_parm(&external_buffer->memory_parm); ++ return ex_buffer_size == 0 ? -EINVAL : ex_buffer_size; ++ } ++ ++ /* ++ * dma-buf api needs to use default_domain of main dev, ++ * and not IOMMU for devices without iommu_info ptr. ++ */ ++ map_dev = scheduler->iommu_info ? scheduler->iommu_info->default_dev : scheduler->dev; ++ ++ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); ++ if (buffer == NULL) { ++ pr_err("%s alloc internal_buffer error!\n", __func__); ++ return -ENOMEM; ++ } ++ ++ switch (external_buffer->type) { ++ case RGA_DMA_BUFFER: ++ ret = rga_dma_map_fd((int)external_buffer->memory, ++ buffer, DMA_BIDIRECTIONAL, ++ map_dev); ++ break; ++ case RGA_DMA_BUFFER_PTR: ++ ret = rga_dma_map_buf((struct dma_buf *)u64_to_user_ptr(external_buffer->memory), ++ buffer, DMA_BIDIRECTIONAL, ++ map_dev); ++ break; ++ default: ++ ret = -EFAULT; ++ break; ++ } ++ if (ret < 0) { ++ pr_err("%s core[%d] map dma buffer error!\n", ++ __func__, scheduler->core); ++ goto free_buffer; ++ } ++ ++ if (buffer->size < ex_buffer_size) { ++ pr_err("Only get buffer %ld byte from %s = 0x%lx, but current image required %d byte\n", ++ buffer->size, rga_get_memory_type_str(external_buffer->type), ++ (unsigned long)external_buffer->memory, ex_buffer_size); ++ rga_dump_memory_parm(&external_buffer->memory_parm); ++ ret = -EINVAL; ++ goto unmap_buffer; ++ } ++ ++ buffer->scheduler = scheduler; ++ ++ if (rga_mm_check_range_sgt(buffer->sgt)) ++ mm_flag |= RGA_MEM_UNDER_4G; ++ ++ /* ++ * If it's physically contiguous, then the RGA_MMU can ++ * directly use the physical address. ++ */ ++ if (rga_mm_check_contiguous_sgt(buffer->sgt)) { ++ phys_addr = sg_phys(buffer->sgt->sgl); ++ if (phys_addr == 0) { ++ pr_err("%s get physical address error!", __func__); ++ ret = -EFAULT; ++ goto unmap_buffer; ++ } ++ ++ mm_flag |= RGA_MEM_PHYSICAL_CONTIGUOUS; ++ } ++ ++ if (!rga_mm_check_memory_limit(scheduler, mm_flag)) { ++ pr_err("scheduler core[%d] unsupported mm_flag[0x%x]!\n", ++ scheduler->core, mm_flag); ++ ret = -EINVAL; ++ goto unmap_buffer; ++ } ++ ++ internal_buffer->dma_buffer = buffer; ++ internal_buffer->mm_flag = mm_flag; ++ internal_buffer->phys_addr = phys_addr ? phys_addr : 0; ++ ++ return 0; ++ ++unmap_buffer: ++ rga_dma_unmap_buf(buffer); ++ ++free_buffer: ++ kfree(buffer); ++ ++ return ret; ++} ++ ++static void rga_mm_unmap_virt_addr(struct rga_internal_buffer *internal_buffer) ++{ ++ WARN_ON(internal_buffer->dma_buffer == NULL || internal_buffer->virt_addr == NULL); ++ ++ if (rga_mm_is_invalid_dma_buffer(internal_buffer->dma_buffer)) ++ return; ++ ++ switch (internal_buffer->dma_buffer->scheduler->data->mmu) { ++ case RGA_IOMMU: ++ rga_iommu_unmap(internal_buffer->dma_buffer); ++ break; ++ case RGA_MMU: ++ dma_unmap_sg(internal_buffer->dma_buffer->scheduler->dev, ++ internal_buffer->dma_buffer->sgt->sgl, ++ internal_buffer->dma_buffer->sgt->orig_nents, ++ DMA_BIDIRECTIONAL); ++ break; ++ default: ++ break; ++ } ++ ++ if (internal_buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS && ++ internal_buffer->phys_addr > 0) ++ internal_buffer->phys_addr = 0; ++ ++ rga_free_sgt(&internal_buffer->dma_buffer->sgt); ++ ++ kfree(internal_buffer->dma_buffer); ++ internal_buffer->dma_buffer = NULL; ++ ++ rga_free_virt_addr(&internal_buffer->virt_addr); ++ ++ mmput(internal_buffer->current_mm); ++ mmdrop(internal_buffer->current_mm); ++ internal_buffer->current_mm = NULL; ++} ++ ++static int rga_mm_map_virt_addr(struct rga_external_buffer *external_buffer, ++ struct rga_internal_buffer *internal_buffer, ++ struct rga_job *job, int write_flag) ++{ ++ int ret; ++ uint32_t mm_flag = 0; ++ phys_addr_t phys_addr = 0; ++ struct sg_table *sgt; ++ struct rga_virt_addr *virt_addr; ++ struct rga_dma_buffer *buffer; ++ struct rga_scheduler_t *scheduler; ++ ++ scheduler = job ? job->scheduler : ++ rga_drvdata->scheduler[rga_drvdata->map_scheduler_index]; ++ if (scheduler == NULL) { ++ pr_err("Invalid scheduler device!\n"); ++ return -EINVAL; ++ } ++ ++ internal_buffer->current_mm = job ? job->mm : current->mm; ++ if (internal_buffer->current_mm == NULL) { ++ pr_err("%s, cannot get current mm!\n", __func__); ++ return -EFAULT; ++ } ++ mmgrab(internal_buffer->current_mm); ++ mmget(internal_buffer->current_mm); ++ ++ ret = rga_alloc_virt_addr(&virt_addr, ++ external_buffer->memory, ++ &internal_buffer->memory_parm, ++ write_flag, internal_buffer->current_mm); ++ if (ret < 0) { ++ pr_err("Can not alloc rga_virt_addr from 0x%lx\n", ++ (unsigned long)external_buffer->memory); ++ goto put_current_mm; ++ } ++ ++ sgt = rga_alloc_sgt(virt_addr); ++ if (IS_ERR(sgt)) { ++ pr_err("alloc sgt error!\n"); ++ ret = PTR_ERR(sgt); ++ goto free_virt_addr; ++ } ++ ++ if (rga_mm_check_range_sgt(sgt)) ++ mm_flag |= RGA_MEM_UNDER_4G; ++ ++ if (rga_mm_check_contiguous_sgt(sgt)) { ++ phys_addr = sg_phys(sgt->sgl); ++ if (phys_addr == 0) { ++ pr_err("%s get physical address error!", __func__); ++ ret = -EFAULT; ++ goto free_sgt; ++ } ++ ++ mm_flag |= RGA_MEM_PHYSICAL_CONTIGUOUS; ++ } ++ ++ /* ++ * Some userspace virtual addresses do not have an ++ * interface for flushing the cache, so it is mandatory ++ * to flush the cache when the virtual address is used. ++ */ ++ mm_flag |= RGA_MEM_FORCE_FLUSH_CACHE; ++ ++ if (!rga_mm_check_memory_limit(scheduler, mm_flag)) { ++ pr_err("scheduler core[%d] unsupported mm_flag[0x%x]!\n", ++ scheduler->core, mm_flag); ++ ret = -EINVAL; ++ goto free_sgt; ++ } ++ ++ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); ++ if (buffer == NULL) { ++ pr_err("%s alloc internal dma_buffer error!\n", __func__); ++ ret = -ENOMEM; ++ goto free_sgt; ++ } ++ ++ switch (scheduler->data->mmu) { ++ case RGA_IOMMU: ++ ret = rga_iommu_map_sgt(sgt, virt_addr->size, buffer, scheduler->dev); ++ if (ret < 0) { ++ pr_err("%s core[%d] iommu_map virtual address error!\n", ++ __func__, scheduler->core); ++ goto free_dma_buffer; ++ } ++ break; ++ case RGA_MMU: ++ ret = dma_map_sg(scheduler->dev, sgt->sgl, sgt->orig_nents, DMA_BIDIRECTIONAL); ++ if (ret == 0) { ++ pr_err("%s core[%d] dma_map_sgt error! va = 0x%lx, nents = %d\n", ++ __func__, scheduler->core, ++ (unsigned long)virt_addr->addr, sgt->orig_nents); ++ ret = -EINVAL; ++ goto free_dma_buffer; ++ } ++ break; ++ default: ++ if (mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS) ++ break; ++ ++ pr_err("Current %s[%d] cannot support physically discontinuous virtual address!\n", ++ rga_get_mmu_type_str(scheduler->data->mmu), scheduler->data->mmu); ++ ret = -EOPNOTSUPP; ++ goto free_dma_buffer; ++ } ++ ++ buffer->sgt = sgt; ++ buffer->offset = virt_addr->offset; ++ buffer->size = virt_addr->size; ++ buffer->scheduler = scheduler; ++ ++ internal_buffer->virt_addr = virt_addr; ++ internal_buffer->dma_buffer = buffer; ++ internal_buffer->mm_flag = mm_flag; ++ internal_buffer->phys_addr = phys_addr ? phys_addr + virt_addr->offset : 0; ++ ++ return 0; ++ ++free_dma_buffer: ++ kfree(buffer); ++free_sgt: ++ rga_free_sgt(&sgt); ++free_virt_addr: ++ rga_free_virt_addr(&virt_addr); ++put_current_mm: ++ mmput(internal_buffer->current_mm); ++ mmdrop(internal_buffer->current_mm); ++ internal_buffer->current_mm = NULL; ++ ++ return ret; ++} ++ ++static void rga_mm_unmap_phys_addr(struct rga_internal_buffer *internal_buffer) ++{ ++ WARN_ON(internal_buffer->dma_buffer == NULL); ++ ++ if (rga_mm_is_invalid_dma_buffer(internal_buffer->dma_buffer)) ++ return; ++ ++ if (internal_buffer->dma_buffer->scheduler->data->mmu == RGA_IOMMU) ++ rga_iommu_unmap(internal_buffer->dma_buffer); ++ ++ kfree(internal_buffer->dma_buffer); ++ internal_buffer->dma_buffer = NULL; ++ internal_buffer->phys_addr = 0; ++ internal_buffer->size = 0; ++} ++ ++static int rga_mm_map_phys_addr(struct rga_external_buffer *external_buffer, ++ struct rga_internal_buffer *internal_buffer, ++ struct rga_job *job) ++{ ++ int ret; ++ phys_addr_t phys_addr; ++ int buffer_size; ++ uint32_t mm_flag = 0; ++ struct rga_dma_buffer *buffer; ++ struct rga_scheduler_t *scheduler; ++ ++ scheduler = job ? job->scheduler : ++ rga_drvdata->scheduler[rga_drvdata->map_scheduler_index]; ++ if (scheduler == NULL) { ++ pr_err("Invalid scheduler device!\n"); ++ return -EINVAL; ++ } ++ ++ if (internal_buffer->memory_parm.size) ++ buffer_size = internal_buffer->memory_parm.size; ++ else ++ buffer_size = rga_image_size_cal(internal_buffer->memory_parm.width, ++ internal_buffer->memory_parm.height, ++ internal_buffer->memory_parm.format, ++ NULL, NULL, NULL); ++ if (buffer_size <= 0) { ++ pr_err("Failed to get phys addr size!\n"); ++ rga_dump_memory_parm(&internal_buffer->memory_parm); ++ return buffer_size == 0 ? -EINVAL : buffer_size; ++ } ++ ++ phys_addr = external_buffer->memory; ++ mm_flag |= RGA_MEM_PHYSICAL_CONTIGUOUS; ++ if (rga_mm_check_range_phys_addr(phys_addr, buffer_size)) ++ mm_flag |= RGA_MEM_UNDER_4G; ++ ++ if (!rga_mm_check_memory_limit(scheduler, mm_flag)) { ++ pr_err("scheduler core[%d] unsupported mm_flag[0x%x]!\n", ++ scheduler->core, mm_flag); ++ return -EINVAL; ++ } ++ ++ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); ++ if (buffer == NULL) { ++ pr_err("%s alloc internal dma buffer error!\n", __func__); ++ return -ENOMEM; ++ } ++ ++ if (scheduler->data->mmu == RGA_IOMMU) { ++ ret = rga_iommu_map(phys_addr, buffer_size, buffer, scheduler->dev); ++ if (ret < 0) { ++ pr_err("%s core[%d] map phys_addr error!\n", __func__, scheduler->core); ++ goto free_dma_buffer; ++ } ++ } ++ ++ buffer->scheduler = scheduler; ++ ++ internal_buffer->phys_addr = phys_addr; ++ internal_buffer->size = buffer_size; ++ internal_buffer->mm_flag = mm_flag; ++ internal_buffer->dma_buffer = buffer; ++ ++ return 0; ++ ++free_dma_buffer: ++ kfree(buffer); ++ ++ return ret; ++} ++ ++static int rga_mm_unmap_buffer(struct rga_internal_buffer *internal_buffer) ++{ ++ switch (internal_buffer->type) { ++ case RGA_DMA_BUFFER: ++ case RGA_DMA_BUFFER_PTR: ++ rga_mm_unmap_dma_buffer(internal_buffer); ++ break; ++ case RGA_VIRTUAL_ADDRESS: ++ rga_mm_unmap_virt_addr(internal_buffer); ++ break; ++ case RGA_PHYSICAL_ADDRESS: ++ rga_mm_unmap_phys_addr(internal_buffer); ++ break; ++ default: ++ pr_err("Illegal external buffer!\n"); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++static int rga_mm_map_buffer(struct rga_external_buffer *external_buffer, ++ struct rga_internal_buffer *internal_buffer, ++ struct rga_job *job, int write_flag) ++{ ++ int ret; ++ ++ memcpy(&internal_buffer->memory_parm, &external_buffer->memory_parm, ++ sizeof(internal_buffer->memory_parm)); ++ ++ switch (external_buffer->type) { ++ case RGA_DMA_BUFFER: ++ case RGA_DMA_BUFFER_PTR: ++ internal_buffer->type = external_buffer->type; ++ ++ ret = rga_mm_map_dma_buffer(external_buffer, internal_buffer, job); ++ if (ret < 0) { ++ pr_err("%s map dma_buf error!\n", __func__); ++ return ret; ++ } ++ ++ internal_buffer->size = internal_buffer->dma_buffer->size - ++ internal_buffer->dma_buffer->offset; ++ internal_buffer->mm_flag |= RGA_MEM_NEED_USE_IOMMU; ++ break; ++ case RGA_VIRTUAL_ADDRESS: ++ internal_buffer->type = RGA_VIRTUAL_ADDRESS; ++ ++ ret = rga_mm_map_virt_addr(external_buffer, internal_buffer, job, write_flag); ++ if (ret < 0) { ++ pr_err("%s map virtual address error!\n", __func__); ++ return ret; ++ } ++ ++ internal_buffer->size = internal_buffer->virt_addr->size - ++ internal_buffer->virt_addr->offset; ++ internal_buffer->mm_flag |= RGA_MEM_NEED_USE_IOMMU; ++ break; ++ case RGA_PHYSICAL_ADDRESS: ++ internal_buffer->type = RGA_PHYSICAL_ADDRESS; ++ ++ ret = rga_mm_map_phys_addr(external_buffer, internal_buffer, job); ++ if (ret < 0) { ++ pr_err("%s map physical address error!\n", __func__); ++ return ret; ++ } ++ ++ internal_buffer->mm_flag |= RGA_MEM_NEED_USE_IOMMU; ++ break; ++ default: ++ pr_err("Illegal external buffer!\n"); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++static void rga_mm_kref_release_buffer(struct kref *ref) ++{ ++ struct rga_internal_buffer *internal_buffer; ++ ++ internal_buffer = container_of(ref, struct rga_internal_buffer, refcount); ++ rga_mm_unmap_buffer(internal_buffer); ++ ++ idr_remove(&rga_drvdata->mm->memory_idr, internal_buffer->handle); ++ kfree(internal_buffer); ++ rga_drvdata->mm->buffer_count--; ++} ++ ++/* ++ * Called at driver close to release the memory's handle references. ++ */ ++static int rga_mm_handle_remove(int id, void *ptr, void *data) ++{ ++ struct rga_internal_buffer *internal_buffer = ptr; ++ ++ rga_mm_kref_release_buffer(&internal_buffer->refcount); ++ ++ return 0; ++} ++ ++static void rga_mm_buffer_destroy(struct rga_internal_buffer *buffer) ++{ ++ rga_mm_kref_release_buffer(&buffer->refcount); ++} ++ ++static struct rga_internal_buffer * ++rga_mm_lookup_external(struct rga_mm *mm_session, ++ struct rga_external_buffer *external_buffer, ++ struct mm_struct *current_mm) ++{ ++ int id; ++ struct dma_buf *dma_buf = NULL; ++ struct rga_internal_buffer *temp_buffer = NULL; ++ struct rga_internal_buffer *output_buffer = NULL; ++ ++ WARN_ON(!mutex_is_locked(&mm_session->lock)); ++ ++ switch (external_buffer->type) { ++ case RGA_DMA_BUFFER: ++ dma_buf = dma_buf_get((int)external_buffer->memory); ++ if (IS_ERR(dma_buf)) ++ return (struct rga_internal_buffer *)dma_buf; ++ ++ idr_for_each_entry(&mm_session->memory_idr, temp_buffer, id) { ++ if (temp_buffer->dma_buffer == NULL) ++ continue; ++ ++ if (temp_buffer->dma_buffer[0].dma_buf == dma_buf) { ++ output_buffer = temp_buffer; ++ break; ++ } ++ } ++ ++ dma_buf_put(dma_buf); ++ break; ++ case RGA_VIRTUAL_ADDRESS: ++ idr_for_each_entry(&mm_session->memory_idr, temp_buffer, id) { ++ if (temp_buffer->virt_addr == NULL) ++ continue; ++ ++ if (temp_buffer->virt_addr->addr == external_buffer->memory) { ++ if (temp_buffer->current_mm == current_mm) { ++ output_buffer = temp_buffer; ++ break; ++ } ++ ++ continue; ++ } ++ } ++ ++ break; ++ case RGA_PHYSICAL_ADDRESS: ++ idr_for_each_entry(&mm_session->memory_idr, temp_buffer, id) { ++ if (temp_buffer->phys_addr == external_buffer->memory) { ++ output_buffer = temp_buffer; ++ break; ++ } ++ } ++ ++ break; ++ case RGA_DMA_BUFFER_PTR: ++ idr_for_each_entry(&mm_session->memory_idr, temp_buffer, id) { ++ if (temp_buffer->dma_buffer == NULL) ++ continue; ++ ++ if ((unsigned long)temp_buffer->dma_buffer[0].dma_buf == ++ external_buffer->memory) { ++ output_buffer = temp_buffer; ++ break; ++ } ++ } ++ ++ break; ++ ++ default: ++ pr_err("Illegal external buffer!\n"); ++ return NULL; ++ } ++ ++ return output_buffer; ++} ++ ++struct rga_internal_buffer *rga_mm_lookup_handle(struct rga_mm *mm_session, uint32_t handle) ++{ ++ struct rga_internal_buffer *output_buffer; ++ ++ WARN_ON(!mutex_is_locked(&mm_session->lock)); ++ ++ output_buffer = idr_find(&mm_session->memory_idr, handle); ++ ++ return output_buffer; ++} ++ ++int rga_mm_lookup_flag(struct rga_mm *mm_session, uint64_t handle) ++{ ++ struct rga_internal_buffer *output_buffer; ++ ++ output_buffer = rga_mm_lookup_handle(mm_session, handle); ++ if (output_buffer == NULL) { ++ pr_err("This handle[%ld] is illegal.\n", (unsigned long)handle); ++ return -EINVAL; ++ } ++ ++ return output_buffer->mm_flag; ++} ++ ++dma_addr_t rga_mm_lookup_iova(struct rga_internal_buffer *buffer) ++{ ++ if (rga_mm_is_invalid_dma_buffer(buffer->dma_buffer)) ++ return 0; ++ ++ return buffer->dma_buffer->iova + buffer->dma_buffer->offset; ++} ++ ++struct sg_table *rga_mm_lookup_sgt(struct rga_internal_buffer *buffer) ++{ ++ if (rga_mm_is_invalid_dma_buffer(buffer->dma_buffer)) ++ return NULL; ++ ++ return buffer->dma_buffer->sgt; ++} ++ ++void rga_mm_dump_buffer(struct rga_internal_buffer *dump_buffer) ++{ ++ pr_info("handle = %d refcount = %d mm_flag = 0x%x\n", ++ dump_buffer->handle, kref_read(&dump_buffer->refcount), ++ dump_buffer->mm_flag); ++ ++ switch (dump_buffer->type) { ++ case RGA_DMA_BUFFER: ++ case RGA_DMA_BUFFER_PTR: ++ if (rga_mm_is_invalid_dma_buffer(dump_buffer->dma_buffer)) ++ break; ++ ++ pr_info("dma_buffer:\n"); ++ pr_info("dma_buf = %p, iova = 0x%lx, sgt = %p, size = %ld, map_core = 0x%x\n", ++ dump_buffer->dma_buffer->dma_buf, ++ (unsigned long)dump_buffer->dma_buffer->iova, ++ dump_buffer->dma_buffer->sgt, ++ dump_buffer->dma_buffer->size, ++ dump_buffer->dma_buffer->scheduler->core); ++ ++ if (dump_buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS) ++ pr_info("is contiguous, pa = 0x%lx\n", ++ (unsigned long)dump_buffer->phys_addr); ++ break; ++ case RGA_VIRTUAL_ADDRESS: ++ if (dump_buffer->virt_addr == NULL) ++ break; ++ ++ pr_info("virtual address:\n"); ++ pr_info("va = 0x%lx, pages = %p, size = %ld\n", ++ (unsigned long)dump_buffer->virt_addr->addr, ++ dump_buffer->virt_addr->pages, ++ dump_buffer->virt_addr->size); ++ ++ if (rga_mm_is_invalid_dma_buffer(dump_buffer->dma_buffer)) ++ break; ++ ++ pr_info("iova = 0x%lx, offset = 0x%lx, sgt = %p, size = %ld, map_core = 0x%x\n", ++ (unsigned long)dump_buffer->dma_buffer->iova, ++ (unsigned long)dump_buffer->dma_buffer->offset, ++ dump_buffer->dma_buffer->sgt, ++ dump_buffer->dma_buffer->size, ++ dump_buffer->dma_buffer->scheduler->core); ++ ++ if (dump_buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS) ++ pr_info("is contiguous, pa = 0x%lx\n", ++ (unsigned long)dump_buffer->phys_addr); ++ break; ++ case RGA_PHYSICAL_ADDRESS: ++ pr_info("physical address: pa = 0x%lx\n", (unsigned long)dump_buffer->phys_addr); ++ break; ++ default: ++ pr_err("Illegal external buffer!\n"); ++ break; ++ } ++} ++ ++void rga_mm_dump_info(struct rga_mm *mm_session) ++{ ++ int id; ++ struct rga_internal_buffer *dump_buffer; ++ ++ WARN_ON(!mutex_is_locked(&mm_session->lock)); ++ ++ pr_info("rga mm info:\n"); ++ ++ pr_info("buffer count = %d\n", mm_session->buffer_count); ++ pr_info("===============================================================\n"); ++ ++ idr_for_each_entry(&mm_session->memory_idr, dump_buffer, id) { ++ rga_mm_dump_buffer(dump_buffer); ++ ++ pr_info("---------------------------------------------------------------\n"); ++ } ++} ++ ++static bool rga_mm_is_need_mmu(struct rga_job *job, struct rga_internal_buffer *buffer) ++{ ++ if (buffer == NULL || job == NULL || job->scheduler == NULL) ++ return false; ++ ++ /* RK_IOMMU no need to configure enable or not in the driver. */ ++ if (job->scheduler->data->mmu == RGA_IOMMU) ++ return false; ++ ++ /* RK_MMU need to configure enable or not in the driver. */ ++ if (buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS) ++ return false; ++ else if (buffer->mm_flag & RGA_MEM_NEED_USE_IOMMU) ++ return true; ++ ++ return false; ++} ++ ++static int rga_mm_set_mmu_flag(struct rga_job *job) ++{ ++ struct rga_mmu_t *mmu_info; ++ int src_mmu_en; ++ int src1_mmu_en; ++ int dst_mmu_en; ++ int els_mmu_en; ++ ++ src_mmu_en = rga_mm_is_need_mmu(job, job->src_buffer.addr); ++ src1_mmu_en = rga_mm_is_need_mmu(job, job->src1_buffer.addr); ++ dst_mmu_en = rga_mm_is_need_mmu(job, job->dst_buffer.addr); ++ els_mmu_en = rga_mm_is_need_mmu(job, job->els_buffer.addr); ++ ++ mmu_info = &job->rga_command_base.mmu_info; ++ memset(mmu_info, 0x0, sizeof(*mmu_info)); ++ if (src_mmu_en) ++ mmu_info->mmu_flag |= (0x1 << 8); ++ if (src1_mmu_en) ++ mmu_info->mmu_flag |= (0x1 << 9); ++ if (dst_mmu_en) ++ mmu_info->mmu_flag |= (0x1 << 10); ++ if (els_mmu_en) ++ mmu_info->mmu_flag |= (0x1 << 11); ++ ++ if (mmu_info->mmu_flag & (0xf << 8)) { ++ mmu_info->mmu_flag |= 1; ++ mmu_info->mmu_flag |= 1 << 31; ++ mmu_info->mmu_en = 1; ++ } ++ ++ return 0; ++} ++ ++static int rga_mm_sgt_to_page_table(struct sg_table *sg, ++ uint32_t *page_table, ++ int32_t pageCount, ++ int32_t use_dma_address) ++{ ++ uint32_t i; ++ unsigned long Address; ++ uint32_t mapped_size = 0; ++ uint32_t len; ++ struct scatterlist *sgl = sg->sgl; ++ uint32_t sg_num = 0; ++ uint32_t break_flag = 0; ++ ++ do { ++ /* ++ * The length of each sgl is expected to be obtained here, not ++ * the length of the entire dma_buf, so sg_dma_len() is not used. ++ */ ++ len = sgl->length >> PAGE_SHIFT; ++ ++ if (use_dma_address) ++ /* ++ * The fd passed by user space gets sg through ++ * dma_buf_map_attachment, so dma_address can ++ * be use here. ++ * When the mapped device does not have iommu, it will ++ * return the first address of the real physical page ++ * when it meets the requirements of the current device, ++ * and will trigger swiotlb when it does not meet the ++ * requirements to obtain a software-mapped physical ++ * address that is mapped to meet the device address ++ * requirements. ++ */ ++ Address = sg_dma_address(sgl); ++ else ++ Address = sg_phys(sgl); ++ ++ for (i = 0; i < len; i++) { ++ if (mapped_size + i >= pageCount) { ++ break_flag = 1; ++ break; ++ } ++ page_table[mapped_size + i] = (uint32_t)(Address + (i << PAGE_SHIFT)); ++ } ++ if (break_flag) ++ break; ++ mapped_size += len; ++ sg_num += 1; ++ } while ((sgl = sg_next(sgl)) && (mapped_size < pageCount) && (sg_num < sg->orig_nents)); ++ ++ return 0; ++} ++ ++static int rga_mm_set_mmu_base(struct rga_job *job, ++ struct rga_img_info_t *img, ++ struct rga_job_buffer *job_buf) ++{ ++ int ret; ++ int yrgb_count = 0; ++ int uv_count = 0; ++ int v_count = 0; ++ int page_count = 0; ++ int order = 0; ++ uint32_t *page_table = NULL; ++ struct sg_table *sgt = NULL; ++ ++ int img_size, yrgb_size, uv_size, v_size; ++ int img_offset = 0; ++ int yrgb_offset = 0; ++ int uv_offset = 0; ++ int v_offset = 0; ++ ++ img_size = rga_image_size_cal(img->vir_w, img->vir_h, img->format, ++ &yrgb_size, &uv_size, &v_size); ++ if (img_size <= 0) { ++ pr_err("Image size cal error! width = %d, height = %d, format = %s\n", ++ img->vir_w, img->vir_h, rga_get_format_name(img->format)); ++ return -EINVAL; ++ } ++ ++ /* using third-address */ ++ if (job_buf->uv_addr) { ++ if (job_buf->y_addr->virt_addr != NULL) ++ yrgb_offset = job_buf->y_addr->virt_addr->offset; ++ if (job_buf->uv_addr->virt_addr != NULL) ++ uv_offset = job_buf->uv_addr->virt_addr->offset; ++ if (job_buf->v_addr->virt_addr != NULL) ++ v_offset = job_buf->v_addr->virt_addr->offset; ++ ++ yrgb_count = RGA_GET_PAGE_COUNT(yrgb_size + yrgb_offset); ++ uv_count = RGA_GET_PAGE_COUNT(uv_size + uv_offset); ++ v_count = RGA_GET_PAGE_COUNT(v_size + v_offset); ++ page_count = yrgb_count + uv_count + v_count; ++ ++ if (page_count <= 0) { ++ pr_err("page count cal error! yrba = %d, uv = %d, v = %d\n", ++ yrgb_count, uv_count, v_count); ++ return -EFAULT; ++ } ++ ++ if (job->flags & RGA_JOB_USE_HANDLE) { ++ order = get_order(page_count * sizeof(uint32_t *)); ++ if (order >= MAX_ORDER) { ++ pr_err("Can not alloc pages with order[%d] for page_table, max_order = %d\n", ++ order, MAX_ORDER); ++ return -ENOMEM; ++ } ++ ++ page_table = (uint32_t *)__get_free_pages(GFP_KERNEL | GFP_DMA32, order); ++ if (page_table == NULL) { ++ pr_err("%s can not alloc pages for page_table, order = %d\n", ++ __func__, order); ++ return -ENOMEM; ++ } ++ } else { ++ mutex_lock(&rga_drvdata->lock); ++ ++ page_table = rga_mmu_buf_get(rga_drvdata->mmu_base, page_count); ++ if (page_table == NULL) { ++ pr_err("mmu_buf get error!\n"); ++ mutex_unlock(&rga_drvdata->lock); ++ return -EFAULT; ++ } ++ ++ mutex_unlock(&rga_drvdata->lock); ++ } ++ ++ sgt = rga_mm_lookup_sgt(job_buf->y_addr); ++ if (sgt == NULL) { ++ pr_err("rga2 cannot get sgt from internal buffer!\n"); ++ ret = -EINVAL; ++ goto err_free_page_table; ++ } ++ rga_mm_sgt_to_page_table(sgt, page_table, yrgb_count, false); ++ ++ sgt = rga_mm_lookup_sgt(job_buf->uv_addr); ++ if (sgt == NULL) { ++ pr_err("rga2 cannot get sgt from internal buffer!\n"); ++ ret = -EINVAL; ++ goto err_free_page_table; ++ } ++ rga_mm_sgt_to_page_table(sgt, page_table + yrgb_count, uv_count, false); ++ ++ sgt = rga_mm_lookup_sgt(job_buf->v_addr); ++ if (sgt == NULL) { ++ pr_err("rga2 cannot get sgt from internal buffer!\n"); ++ ret = -EINVAL; ++ goto err_free_page_table; ++ } ++ rga_mm_sgt_to_page_table(sgt, page_table + yrgb_count + uv_count, v_count, false); ++ ++ img->yrgb_addr = yrgb_offset; ++ img->uv_addr = (yrgb_count << PAGE_SHIFT) + uv_offset; ++ img->v_addr = ((yrgb_count + uv_count) << PAGE_SHIFT) + v_offset; ++ } else { ++ if (job_buf->addr->virt_addr != NULL) ++ img_offset = job_buf->addr->virt_addr->offset; ++ ++ page_count = RGA_GET_PAGE_COUNT(img_size + img_offset); ++ if (page_count < 0) { ++ pr_err("page count cal error! yrba = %d, uv = %d, v = %d\n", ++ yrgb_count, uv_count, v_count); ++ return -EFAULT; ++ } ++ ++ if (job->flags & RGA_JOB_USE_HANDLE) { ++ order = get_order(page_count * sizeof(uint32_t *)); ++ if (order >= MAX_ORDER) { ++ pr_err("Can not alloc pages with order[%d] for page_table, max_order = %d\n", ++ order, MAX_ORDER); ++ return -ENOMEM; ++ } ++ ++ page_table = (uint32_t *)__get_free_pages(GFP_KERNEL | GFP_DMA32, order); ++ if (page_table == NULL) { ++ pr_err("%s can not alloc pages for page_table, order = %d\n", ++ __func__, order); ++ return -ENOMEM; ++ } ++ } else { ++ mutex_lock(&rga_drvdata->lock); ++ ++ page_table = rga_mmu_buf_get(rga_drvdata->mmu_base, page_count); ++ if (page_table == NULL) { ++ pr_err("mmu_buf get error!\n"); ++ mutex_unlock(&rga_drvdata->lock); ++ return -EFAULT; ++ } ++ ++ mutex_unlock(&rga_drvdata->lock); ++ } ++ ++ sgt = rga_mm_lookup_sgt(job_buf->addr); ++ if (sgt == NULL) { ++ pr_err("rga2 cannot get sgt from internal buffer!\n"); ++ ret = -EINVAL; ++ goto err_free_page_table; ++ } ++ rga_mm_sgt_to_page_table(sgt, page_table, page_count, false); ++ ++ img->yrgb_addr = img_offset; ++ rga_convert_addr(img, false); ++ } ++ ++ job_buf->page_table = page_table; ++ job_buf->order = order; ++ job_buf->page_count = page_count; ++ ++ return 0; ++ ++err_free_page_table: ++ if (job->flags & RGA_JOB_USE_HANDLE) ++ free_pages((unsigned long)page_table, order); ++ return ret; ++} ++ ++static int rga_mm_sync_dma_sg_for_device(struct rga_internal_buffer *buffer, ++ struct rga_job *job, ++ enum dma_data_direction dir) ++{ ++ struct sg_table *sgt; ++ struct rga_scheduler_t *scheduler; ++ ++ scheduler = buffer->dma_buffer->scheduler; ++ if (scheduler == NULL) { ++ pr_err("%s(%d), failed to get scheduler, core = 0x%x\n", ++ __func__, __LINE__, job->core); ++ return -EFAULT; ++ } ++ ++ if (buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS && ++ scheduler->data->mmu != RGA_IOMMU) { ++ dma_sync_single_for_device(scheduler->dev, buffer->phys_addr, buffer->size, dir); ++ } else { ++ sgt = rga_mm_lookup_sgt(buffer); ++ if (sgt == NULL) { ++ pr_err("%s(%d), failed to get sgt, core = 0x%x\n", ++ __func__, __LINE__, job->core); ++ return -EINVAL; ++ } ++ ++ dma_sync_sg_for_device(scheduler->dev, sgt->sgl, sgt->orig_nents, dir); ++ } ++ ++ return 0; ++} ++ ++static int rga_mm_sync_dma_sg_for_cpu(struct rga_internal_buffer *buffer, ++ struct rga_job *job, ++ enum dma_data_direction dir) ++{ ++ struct sg_table *sgt; ++ struct rga_scheduler_t *scheduler; ++ ++ scheduler = buffer->dma_buffer->scheduler; ++ if (scheduler == NULL) { ++ pr_err("%s(%d), failed to get scheduler, core = 0x%x\n", ++ __func__, __LINE__, job->core); ++ return -EFAULT; ++ } ++ ++ if (buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS && ++ scheduler->data->mmu != RGA_IOMMU) { ++ dma_sync_single_for_cpu(scheduler->dev, buffer->phys_addr, buffer->size, dir); ++ } else { ++ sgt = rga_mm_lookup_sgt(buffer); ++ if (sgt == NULL) { ++ pr_err("%s(%d), failed to get sgt, core = 0x%x\n", ++ __func__, __LINE__, job->core); ++ return -EINVAL; ++ } ++ ++ dma_sync_sg_for_cpu(scheduler->dev, sgt->sgl, sgt->orig_nents, dir); ++ } ++ ++ return 0; ++} ++ ++static int rga_mm_get_buffer_info(struct rga_job *job, ++ struct rga_internal_buffer *internal_buffer, ++ uint64_t *channel_addr) ++{ ++ uint64_t addr; ++ ++ switch (job->scheduler->data->mmu) { ++ case RGA_IOMMU: ++ addr = rga_mm_lookup_iova(internal_buffer); ++ if (addr == 0) { ++ pr_err("core[%d] lookup buffer_type[0x%x] iova error!\n", ++ job->core, internal_buffer->type); ++ return -EINVAL; ++ } ++ break; ++ case RGA_MMU: ++ default: ++ if (internal_buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS) { ++ addr = internal_buffer->phys_addr; ++ break; ++ } ++ ++ switch (internal_buffer->type) { ++ case RGA_DMA_BUFFER: ++ case RGA_DMA_BUFFER_PTR: ++ addr = 0; ++ break; ++ case RGA_VIRTUAL_ADDRESS: ++ addr = internal_buffer->virt_addr->addr; ++ break; ++ case RGA_PHYSICAL_ADDRESS: ++ addr = internal_buffer->phys_addr; ++ break; ++ default: ++ pr_err("Illegal external buffer!\n"); ++ return -EFAULT; ++ } ++ break; ++ } ++ ++ *channel_addr = addr; ++ ++ return 0; ++} ++ ++static int rga_mm_get_buffer(struct rga_mm *mm, ++ struct rga_job *job, ++ uint64_t handle, ++ uint64_t *channel_addr, ++ struct rga_internal_buffer **buf, ++ int require_size, ++ enum dma_data_direction dir) ++{ ++ int ret = 0; ++ struct rga_internal_buffer *internal_buffer = NULL; ++ ++ if (handle == 0) { ++ pr_err("No buffer handle can be used!\n"); ++ return -EFAULT; ++ } ++ ++ mutex_lock(&mm->lock); ++ *buf = rga_mm_lookup_handle(mm, handle); ++ if (*buf == NULL) { ++ pr_err("This handle[%ld] is illegal.\n", (unsigned long)handle); ++ ++ mutex_unlock(&mm->lock); ++ return -EFAULT; ++ } ++ ++ internal_buffer = *buf; ++ kref_get(&internal_buffer->refcount); ++ ++ if (DEBUGGER_EN(MM)) { ++ pr_info("handle[%d] get info:\n", (int)handle); ++ rga_mm_dump_buffer(internal_buffer); ++ } ++ ++ mutex_unlock(&mm->lock); ++ ++ ret = rga_mm_get_buffer_info(job, internal_buffer, channel_addr); ++ if (ret < 0) { ++ pr_err("handle[%ld] failed to get internal buffer info!\n", (unsigned long)handle); ++ return ret; ++ } ++ ++ if (internal_buffer->size < require_size) { ++ ret = -EINVAL; ++ pr_err("Only get buffer %ld byte from handle[%ld], but current required %d byte\n", ++ internal_buffer->size, (unsigned long)handle, require_size); ++ ++ goto put_internal_buffer; ++ } ++ ++ if (internal_buffer->mm_flag & RGA_MEM_FORCE_FLUSH_CACHE) { ++ /* ++ * Some userspace virtual addresses do not have an ++ * interface for flushing the cache, so it is mandatory ++ * to flush the cache when the virtual address is used. ++ */ ++ ret = rga_mm_sync_dma_sg_for_device(internal_buffer, job, dir); ++ if (ret < 0) { ++ pr_err("sync sgt for device error!\n"); ++ goto put_internal_buffer; ++ } ++ } ++ ++ return 0; ++ ++put_internal_buffer: ++ mutex_lock(&mm->lock); ++ kref_put(&internal_buffer->refcount, rga_mm_kref_release_buffer); ++ mutex_unlock(&mm->lock); ++ ++ return ret; ++ ++} ++ ++static void rga_mm_put_buffer(struct rga_mm *mm, ++ struct rga_job *job, ++ struct rga_internal_buffer *internal_buffer, ++ enum dma_data_direction dir) ++{ ++ if (internal_buffer->mm_flag & RGA_MEM_FORCE_FLUSH_CACHE && dir != DMA_NONE) ++ if (rga_mm_sync_dma_sg_for_cpu(internal_buffer, job, dir)) ++ pr_err("sync sgt for cpu error!\n"); ++ ++ if (DEBUGGER_EN(MM)) { ++ pr_info("handle[%d] put info:\n", (int)internal_buffer->handle); ++ rga_mm_dump_buffer(internal_buffer); ++ } ++ ++ mutex_lock(&mm->lock); ++ kref_put(&internal_buffer->refcount, rga_mm_kref_release_buffer); ++ mutex_unlock(&mm->lock); ++} ++ ++static void rga_mm_put_channel_handle_info(struct rga_mm *mm, ++ struct rga_job *job, ++ struct rga_job_buffer *job_buf, ++ enum dma_data_direction dir) ++{ ++ if (job_buf->y_addr) ++ rga_mm_put_buffer(mm, job, job_buf->y_addr, dir); ++ if (job_buf->uv_addr) ++ rga_mm_put_buffer(mm, job, job_buf->uv_addr, dir); ++ if (job_buf->v_addr) ++ rga_mm_put_buffer(mm, job, job_buf->v_addr, dir); ++ ++ if (job_buf->page_table) ++ free_pages((unsigned long)job_buf->page_table, job_buf->order); ++} ++ ++static int rga_mm_get_channel_handle_info(struct rga_mm *mm, ++ struct rga_job *job, ++ struct rga_img_info_t *img, ++ struct rga_job_buffer *job_buf, ++ enum dma_data_direction dir) ++{ ++ int ret = 0; ++ int handle = 0; ++ int img_size, yrgb_size, uv_size, v_size; ++ ++ img_size = rga_image_size_cal(img->vir_w, img->vir_h, img->format, ++ &yrgb_size, &uv_size, &v_size); ++ if (img_size <= 0) { ++ pr_err("Image size cal error! width = %d, height = %d, format = %s\n", ++ img->vir_w, img->vir_h, rga_get_format_name(img->format)); ++ return -EINVAL; ++ } ++ ++ /* using third-address */ ++ if (img->uv_addr > 0) { ++ handle = img->yrgb_addr; ++ if (handle > 0) { ++ ret = rga_mm_get_buffer(mm, job, handle, &img->yrgb_addr, ++ &job_buf->y_addr, yrgb_size, dir); ++ if (ret < 0) { ++ pr_err("handle[%d] Can't get y/rgb address info!\n", handle); ++ return ret; ++ } ++ } ++ ++ handle = img->uv_addr; ++ if (handle > 0) { ++ ret = rga_mm_get_buffer(mm, job, handle, &img->uv_addr, ++ &job_buf->uv_addr, uv_size, dir); ++ if (ret < 0) { ++ pr_err("handle[%d] Can't get uv address info!\n", handle); ++ return ret; ++ } ++ } ++ ++ handle = img->v_addr; ++ if (handle > 0) { ++ ret = rga_mm_get_buffer(mm, job, handle, &img->v_addr, ++ &job_buf->v_addr, v_size, dir); ++ if (ret < 0) { ++ pr_err("handle[%d] Can't get uv address info!\n", handle); ++ return ret; ++ } ++ } ++ } else { ++ handle = img->yrgb_addr; ++ if (handle > 0) { ++ ret = rga_mm_get_buffer(mm, job, handle, &img->yrgb_addr, ++ &job_buf->addr, img_size, dir); ++ if (ret < 0) { ++ pr_err("handle[%d] Can't get y/rgb address info!\n", handle); ++ return ret; ++ } ++ } ++ ++ rga_convert_addr(img, false); ++ } ++ ++ if (job->scheduler->data->mmu == RGA_MMU && ++ rga_mm_is_need_mmu(job, job_buf->addr)) { ++ ret = rga_mm_set_mmu_base(job, img, job_buf); ++ if (ret < 0) { ++ pr_err("Can't set RGA2 MMU_BASE from handle!\n"); ++ ++ rga_mm_put_channel_handle_info(mm, job, job_buf, dir); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static int rga_mm_get_handle_info(struct rga_job *job) ++{ ++ int ret = 0; ++ struct rga_req *req = NULL; ++ struct rga_mm *mm = NULL; ++ enum dma_data_direction dir; ++ ++ req = &job->rga_command_base; ++ mm = rga_drvdata->mm; ++ ++ switch (req->render_mode) { ++ case BITBLT_MODE: ++ case COLOR_PALETTE_MODE: ++ if (unlikely(req->src.yrgb_addr <= 0)) { ++ pr_err("render_mode[0x%x] src0 channel handle[%ld] must is valid!", ++ req->render_mode, (unsigned long)req->src.yrgb_addr); ++ return -EINVAL; ++ } ++ ++ if (unlikely(req->dst.yrgb_addr <= 0)) { ++ pr_err("render_mode[0x%x] dst channel handle[%ld] must is valid!", ++ req->render_mode, (unsigned long)req->dst.yrgb_addr); ++ return -EINVAL; ++ } ++ ++ if (req->bsfilter_flag) { ++ if (unlikely(req->pat.yrgb_addr <= 0)) { ++ pr_err("render_mode[0x%x] src1/pat channel handle[%ld] must is valid!", ++ req->render_mode, (unsigned long)req->pat.yrgb_addr); ++ return -EINVAL; ++ } ++ } ++ ++ break; ++ case COLOR_FILL_MODE: ++ if (unlikely(req->dst.yrgb_addr <= 0)) { ++ pr_err("render_mode[0x%x] dst channel handle[%ld] must is valid!", ++ req->render_mode, (unsigned long)req->dst.yrgb_addr); ++ return -EINVAL; ++ } ++ ++ break; ++ ++ case UPDATE_PALETTE_TABLE_MODE: ++ case UPDATE_PATTEN_BUF_MODE: ++ if (unlikely(req->pat.yrgb_addr <= 0)) { ++ pr_err("render_mode[0x%x] lut/pat channel handle[%ld] must is valid!, req->render_mode", ++ req->render_mode, (unsigned long)req->pat.yrgb_addr); ++ return -EINVAL; ++ } ++ ++ break; ++ default: ++ pr_err("%s, unknown render mode!\n", __func__); ++ break; ++ } ++ ++ if (likely(req->src.yrgb_addr > 0)) { ++ ret = rga_mm_get_channel_handle_info(mm, job, &req->src, ++ &job->src_buffer, ++ DMA_TO_DEVICE); ++ if (ret < 0) { ++ pr_err("Can't get src buffer info from handle!\n"); ++ return ret; ++ } ++ } ++ ++ if (likely(req->dst.yrgb_addr > 0)) { ++ ret = rga_mm_get_channel_handle_info(mm, job, &req->dst, ++ &job->dst_buffer, ++ DMA_TO_DEVICE); ++ if (ret < 0) { ++ pr_err("Can't get dst buffer info from handle!\n"); ++ return ret; ++ } ++ } ++ ++ if (likely(req->pat.yrgb_addr > 0)) { ++ ++ if (req->render_mode != UPDATE_PALETTE_TABLE_MODE) { ++ if (req->bsfilter_flag) ++ dir = DMA_BIDIRECTIONAL; ++ else ++ dir = DMA_TO_DEVICE; ++ ++ ret = rga_mm_get_channel_handle_info(mm, job, &req->pat, ++ &job->src1_buffer, ++ dir); ++ } else { ++ ret = rga_mm_get_channel_handle_info(mm, job, &req->pat, ++ &job->els_buffer, ++ DMA_BIDIRECTIONAL); ++ } ++ if (ret < 0) { ++ pr_err("Can't get pat buffer info from handle!\n"); ++ return ret; ++ } ++ } ++ ++ rga_mm_set_mmu_flag(job); ++ ++ return 0; ++} ++ ++static void rga_mm_put_handle_info(struct rga_job *job) ++{ ++ struct rga_mm *mm = rga_drvdata->mm; ++ ++ rga_mm_put_channel_handle_info(mm, job, &job->src_buffer, DMA_NONE); ++ rga_mm_put_channel_handle_info(mm, job, &job->dst_buffer, DMA_FROM_DEVICE); ++ rga_mm_put_channel_handle_info(mm, job, &job->src1_buffer, DMA_NONE); ++ rga_mm_put_channel_handle_info(mm, job, &job->els_buffer, DMA_NONE); ++} ++ ++static void rga_mm_put_channel_external_buffer(struct rga_job_buffer *job_buffer) ++{ ++ if (job_buffer->ex_addr->type == RGA_DMA_BUFFER_PTR) ++ dma_buf_put((struct dma_buf *)(unsigned long)job_buffer->ex_addr->memory); ++ ++ kfree(job_buffer->ex_addr); ++ job_buffer->ex_addr = NULL; ++} ++ ++static int rga_mm_get_channel_external_buffer(int mmu_flag, ++ struct rga_img_info_t *img_info, ++ struct rga_job_buffer *job_buffer) ++{ ++ struct dma_buf *dma_buf = NULL; ++ struct rga_external_buffer *external_buffer = NULL; ++ ++ /* Default unsupported multi-planar format */ ++ external_buffer = kzalloc(sizeof(*external_buffer), GFP_KERNEL); ++ if (external_buffer == NULL) { ++ pr_err("Cannot alloc job_buffer!\n"); ++ return -ENOMEM; ++ } ++ ++ if (img_info->yrgb_addr) { ++ dma_buf = dma_buf_get(img_info->yrgb_addr); ++ if (IS_ERR(dma_buf)) { ++ pr_err("%s dma_buf_get fail fd[%lu]\n", ++ __func__, (unsigned long)img_info->yrgb_addr); ++ kfree(external_buffer); ++ return -EINVAL; ++ } ++ ++ external_buffer->memory = (unsigned long)dma_buf; ++ external_buffer->type = RGA_DMA_BUFFER_PTR; ++ } else if (mmu_flag && img_info->uv_addr) { ++ external_buffer->memory = (uint64_t)img_info->uv_addr; ++ external_buffer->type = RGA_VIRTUAL_ADDRESS; ++ } else if (img_info->uv_addr) { ++ external_buffer->memory = (uint64_t)img_info->uv_addr; ++ external_buffer->type = RGA_PHYSICAL_ADDRESS; ++ } else { ++ kfree(external_buffer); ++ return -EINVAL; ++ } ++ ++ external_buffer->memory_parm.width = img_info->vir_w; ++ external_buffer->memory_parm.height = img_info->vir_h; ++ external_buffer->memory_parm.format = img_info->format; ++ ++ job_buffer->ex_addr = external_buffer; ++ ++ return 0; ++} ++ ++static void rga_mm_put_external_buffer(struct rga_job *job) ++{ ++ if (job->src_buffer.ex_addr) ++ rga_mm_put_channel_external_buffer(&job->src_buffer); ++ if (job->src1_buffer.ex_addr) ++ rga_mm_put_channel_external_buffer(&job->src1_buffer); ++ if (job->dst_buffer.ex_addr) ++ rga_mm_put_channel_external_buffer(&job->dst_buffer); ++ if (job->els_buffer.ex_addr) ++ rga_mm_put_channel_external_buffer(&job->els_buffer); ++} ++ ++static int rga_mm_get_external_buffer(struct rga_job *job) ++{ ++ int ret = -EINVAL; ++ int mmu_flag; ++ ++ struct rga_img_info_t *src0 = NULL; ++ struct rga_img_info_t *src1 = NULL; ++ struct rga_img_info_t *dst = NULL; ++ struct rga_img_info_t *els = NULL; ++ ++ if (job->rga_command_base.render_mode != COLOR_FILL_MODE) ++ src0 = &job->rga_command_base.src; ++ ++ if (job->rga_command_base.render_mode != UPDATE_PALETTE_TABLE_MODE) ++ src1 = job->rga_command_base.bsfilter_flag ? ++ &job->rga_command_base.pat : NULL; ++ else ++ els = &job->rga_command_base.pat; ++ ++ dst = &job->rga_command_base.dst; ++ ++ if (likely(src0)) { ++ mmu_flag = ((job->rga_command_base.mmu_info.mmu_flag >> 8) & 1); ++ ret = rga_mm_get_channel_external_buffer(mmu_flag, src0, &job->src_buffer); ++ if (ret < 0) { ++ pr_err("Cannot get src0 channel buffer!\n"); ++ return ret; ++ } ++ } ++ ++ if (likely(dst)) { ++ mmu_flag = ((job->rga_command_base.mmu_info.mmu_flag >> 10) & 1); ++ ret = rga_mm_get_channel_external_buffer(mmu_flag, dst, &job->dst_buffer); ++ if (ret < 0) { ++ pr_err("Cannot get dst channel buffer!\n"); ++ goto error_put_buffer; ++ } ++ } ++ ++ if (src1) { ++ mmu_flag = ((job->rga_command_base.mmu_info.mmu_flag >> 9) & 1); ++ ret = rga_mm_get_channel_external_buffer(mmu_flag, src1, &job->src1_buffer); ++ if (ret < 0) { ++ pr_err("Cannot get src1 channel buffer!\n"); ++ goto error_put_buffer; ++ } ++ } ++ ++ if (els) { ++ mmu_flag = ((job->rga_command_base.mmu_info.mmu_flag >> 11) & 1); ++ ret = rga_mm_get_channel_external_buffer(mmu_flag, els, &job->els_buffer); ++ if (ret < 0) { ++ pr_err("Cannot get els channel buffer!\n"); ++ goto error_put_buffer; ++ } ++ } ++ ++ return 0; ++error_put_buffer: ++ rga_mm_put_external_buffer(job); ++ return ret; ++} ++ ++static void rga_mm_unmap_channel_job_buffer(struct rga_job *job, ++ struct rga_job_buffer *job_buffer, ++ enum dma_data_direction dir) ++{ ++ if (job_buffer->addr->mm_flag & RGA_MEM_FORCE_FLUSH_CACHE && dir != DMA_NONE) ++ if (rga_mm_sync_dma_sg_for_cpu(job_buffer->addr, job, dir)) ++ pr_err("sync sgt for cpu error!\n"); ++ ++ rga_mm_unmap_buffer(job_buffer->addr); ++ kfree(job_buffer->addr); ++ ++ job_buffer->page_table = NULL; ++} ++ ++static int rga_mm_map_channel_job_buffer(struct rga_job *job, ++ struct rga_img_info_t *img, ++ struct rga_job_buffer *job_buffer, ++ enum dma_data_direction dir, ++ int write_flag) ++{ ++ int ret; ++ struct rga_internal_buffer *buffer = NULL; ++ ++ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); ++ if (buffer == NULL) { ++ pr_err("%s alloc internal_buffer error!\n", __func__); ++ return -ENOMEM; ++ } ++ ++ ret = rga_mm_map_buffer(job_buffer->ex_addr, buffer, job, write_flag); ++ if (ret < 0) { ++ pr_err("job buffer map failed!\n"); ++ goto error_free_buffer; ++ } ++ ++ ret = rga_mm_get_buffer_info(job, buffer, &img->yrgb_addr); ++ if (ret < 0) { ++ pr_err("Failed to get internal buffer info!\n"); ++ goto error_unmap_buffer; ++ } ++ ++ if (buffer->mm_flag & RGA_MEM_FORCE_FLUSH_CACHE) { ++ ret = rga_mm_sync_dma_sg_for_device(buffer, job, dir); ++ if (ret < 0) { ++ pr_err("sync sgt for device error!\n"); ++ goto error_unmap_buffer; ++ } ++ } ++ ++ rga_convert_addr(img, false); ++ ++ job_buffer->addr = buffer; ++ ++ if (job->scheduler->data->mmu == RGA_MMU && ++ rga_mm_is_need_mmu(job, job_buffer->addr)) { ++ ret = rga_mm_set_mmu_base(job, img, job_buffer); ++ if (ret < 0) { ++ pr_err("Can't set RGA2 MMU_BASE!\n"); ++ job_buffer->addr = NULL; ++ goto error_unmap_buffer; ++ } ++ } ++ ++ return 0; ++ ++error_unmap_buffer: ++ rga_mm_unmap_buffer(buffer); ++error_free_buffer: ++ kfree(buffer); ++ ++ return ret; ++} ++ ++static void rga_mm_unmap_buffer_info(struct rga_job *job) ++{ ++ if (job->src_buffer.addr) ++ rga_mm_unmap_channel_job_buffer(job, &job->src_buffer, DMA_NONE); ++ if (job->dst_buffer.addr) ++ rga_mm_unmap_channel_job_buffer(job, &job->dst_buffer, DMA_FROM_DEVICE); ++ if (job->src1_buffer.addr) ++ rga_mm_unmap_channel_job_buffer(job, &job->src1_buffer, DMA_NONE); ++ if (job->els_buffer.addr) ++ rga_mm_unmap_channel_job_buffer(job, &job->els_buffer, DMA_NONE); ++ ++ rga_mm_put_external_buffer(job); ++} ++ ++static int rga_mm_map_buffer_info(struct rga_job *job) ++{ ++ int ret = 0; ++ struct rga_req *req = NULL; ++ enum dma_data_direction dir; ++ ++ ret = rga_mm_get_external_buffer(job); ++ if (ret < 0) { ++ pr_err("failed to get external buffer from job_cmd!\n"); ++ return ret; ++ } ++ ++ req = &job->rga_command_base; ++ ++ if (likely(job->src_buffer.ex_addr)) { ++ ret = rga_mm_map_channel_job_buffer(job, &req->src, ++ &job->src_buffer, ++ DMA_TO_DEVICE, false); ++ if (ret < 0) { ++ pr_err("src channel map job buffer failed!"); ++ goto error_unmap_buffer; ++ } ++ } ++ ++ if (likely(job->dst_buffer.ex_addr)) { ++ ret = rga_mm_map_channel_job_buffer(job, &req->dst, ++ &job->dst_buffer, ++ DMA_TO_DEVICE, true); ++ if (ret < 0) { ++ pr_err("dst channel map job buffer failed!"); ++ goto error_unmap_buffer; ++ } ++ } ++ ++ if (job->src1_buffer.ex_addr) { ++ if (req->bsfilter_flag) ++ dir = DMA_BIDIRECTIONAL; ++ else ++ dir = DMA_TO_DEVICE; ++ ++ ret = rga_mm_map_channel_job_buffer(job, &req->pat, ++ &job->src1_buffer, ++ dir, false); ++ if (ret < 0) { ++ pr_err("src1 channel map job buffer failed!"); ++ goto error_unmap_buffer; ++ } ++ } ++ ++ if (job->els_buffer.ex_addr) { ++ ret = rga_mm_map_channel_job_buffer(job, &req->pat, ++ &job->els_buffer, ++ DMA_BIDIRECTIONAL, false); ++ if (ret < 0) { ++ pr_err("els channel map job buffer failed!"); ++ goto error_unmap_buffer; ++ } ++ } ++ ++ rga_mm_set_mmu_flag(job); ++ return 0; ++ ++error_unmap_buffer: ++ rga_mm_unmap_buffer_info(job); ++ ++ return ret; ++} ++ ++int rga_mm_map_job_info(struct rga_job *job) ++{ ++ int ret; ++ ktime_t timestamp = ktime_get(); ++ ++ if (job->flags & RGA_JOB_USE_HANDLE) { ++ ret = rga_mm_get_handle_info(job); ++ if (ret < 0) { ++ pr_err("failed to get buffer from handle\n"); ++ return ret; ++ } ++ ++ if (DEBUGGER_EN(TIME)) ++ pr_info("request[%d], get buffer_handle info cost %lld us\n", ++ job->request_id, ktime_us_delta(ktime_get(), timestamp)); ++ } else { ++ ret = rga_mm_map_buffer_info(job); ++ if (ret < 0) { ++ pr_err("failed to map buffer\n"); ++ return ret; ++ } ++ ++ if (DEBUGGER_EN(TIME)) ++ pr_info("request[%d], map buffer cost %lld us\n", ++ job->request_id, ktime_us_delta(ktime_get(), timestamp)); ++ } ++ ++ return 0; ++} ++ ++void rga_mm_unmap_job_info(struct rga_job *job) ++{ ++ ktime_t timestamp = ktime_get(); ++ ++ if (job->flags & RGA_JOB_USE_HANDLE) { ++ rga_mm_put_handle_info(job); ++ ++ if (DEBUGGER_EN(TIME)) ++ pr_info("request[%d], put buffer_handle info cost %lld us\n", ++ job->request_id, ktime_us_delta(ktime_get(), timestamp)); ++ } else { ++ rga_mm_unmap_buffer_info(job); ++ ++ if (DEBUGGER_EN(TIME)) ++ pr_info("request[%d], unmap buffer cost %lld us\n", ++ job->request_id, ktime_us_delta(ktime_get(), timestamp)); ++ } ++} ++ ++/* ++ * rga_mm_import_buffer - Importing external buffer into the RGA driver ++ * ++ * @external_buffer: [in] Parameters of external buffer ++ * @session: [in] Session of the current process ++ * ++ * returns: ++ * if return value > 0, the buffer import is successful and is the generated ++ * buffer-handle, negative error code on failure. ++ */ ++int rga_mm_import_buffer(struct rga_external_buffer *external_buffer, ++ struct rga_session *session) ++{ ++ int ret = 0, new_id; ++ struct rga_mm *mm; ++ struct rga_internal_buffer *internal_buffer; ++ ++ mm = rga_drvdata->mm; ++ if (mm == NULL) { ++ pr_err("rga mm is null!\n"); ++ return -EFAULT; ++ } ++ ++ mutex_lock(&mm->lock); ++ ++ /* first, Check whether to rga_mm */ ++ internal_buffer = rga_mm_lookup_external(mm, external_buffer, current->mm); ++ if (!IS_ERR_OR_NULL(internal_buffer)) { ++ kref_get(&internal_buffer->refcount); ++ ++ mutex_unlock(&mm->lock); ++ ++ if (DEBUGGER_EN(MM)) { ++ pr_info("import existing buffer:\n"); ++ rga_mm_dump_buffer(internal_buffer); ++ } ++ ++ return internal_buffer->handle; ++ } ++ ++ /* finally, map and cached external_buffer in rga_mm */ ++ internal_buffer = kzalloc(sizeof(struct rga_internal_buffer), GFP_KERNEL); ++ if (internal_buffer == NULL) { ++ pr_err("%s alloc internal_buffer error!\n", __func__); ++ ++ mutex_unlock(&mm->lock); ++ return -ENOMEM; ++ } ++ ++ ret = rga_mm_map_buffer(external_buffer, internal_buffer, NULL, true); ++ if (ret < 0) ++ goto FREE_INTERNAL_BUFFER; ++ ++ kref_init(&internal_buffer->refcount); ++ internal_buffer->session = session; ++ ++ /* ++ * Get the user-visible handle using idr. Preload and perform ++ * allocation under our spinlock. ++ */ ++ idr_preload(GFP_KERNEL); ++ new_id = idr_alloc_cyclic(&mm->memory_idr, internal_buffer, 1, 0, GFP_NOWAIT); ++ idr_preload_end(); ++ if (new_id < 0) { ++ pr_err("internal_buffer alloc id failed!\n"); ++ ret = new_id; ++ goto FREE_INTERNAL_BUFFER; ++ } ++ ++ internal_buffer->handle = new_id; ++ mm->buffer_count++; ++ ++ if (DEBUGGER_EN(MM)) { ++ pr_info("import buffer:\n"); ++ rga_mm_dump_buffer(internal_buffer); ++ } ++ ++ mutex_unlock(&mm->lock); ++ return internal_buffer->handle; ++ ++FREE_INTERNAL_BUFFER: ++ mutex_unlock(&mm->lock); ++ kfree(internal_buffer); ++ ++ return ret; ++} ++ ++int rga_mm_release_buffer(uint32_t handle) ++{ ++ struct rga_mm *mm; ++ struct rga_internal_buffer *internal_buffer; ++ ++ mm = rga_drvdata->mm; ++ if (mm == NULL) { ++ pr_err("rga mm is null!\n"); ++ return -EFAULT; ++ } ++ ++ mutex_lock(&mm->lock); ++ ++ /* Find the buffer that has been imported */ ++ internal_buffer = rga_mm_lookup_handle(mm, handle); ++ if (IS_ERR_OR_NULL(internal_buffer)) { ++ pr_err("This is not a buffer that has been imported, handle = %d\n", (int)handle); ++ ++ mutex_unlock(&mm->lock); ++ return -ENOENT; ++ } ++ ++ if (DEBUGGER_EN(MM)) { ++ pr_info("release buffer:\n"); ++ rga_mm_dump_buffer(internal_buffer); ++ } ++ ++ kref_put(&internal_buffer->refcount, rga_mm_kref_release_buffer); ++ ++ mutex_unlock(&mm->lock); ++ return 0; ++} ++ ++int rga_mm_session_release_buffer(struct rga_session *session) ++{ ++ int i; ++ struct rga_mm *mm; ++ struct rga_internal_buffer *buffer; ++ ++ mm = rga_drvdata->mm; ++ if (mm == NULL) { ++ pr_err("rga mm is null!\n"); ++ return -EFAULT; ++ } ++ ++ mutex_lock(&mm->lock); ++ ++ idr_for_each_entry(&mm->memory_idr, buffer, i) { ++ if (session == buffer->session) { ++ pr_err("[tgid:%d] Destroy handle[%d] when the user exits\n", ++ session->tgid, buffer->handle); ++ rga_mm_buffer_destroy(buffer); ++ } ++ } ++ ++ mutex_unlock(&mm->lock); ++ return 0; ++} ++ ++int rga_mm_init(struct rga_mm **mm_session) ++{ ++ struct rga_mm *mm = NULL; ++ ++ *mm_session = kzalloc(sizeof(struct rga_mm), GFP_KERNEL); ++ if (*mm_session == NULL) { ++ pr_err("can not kzalloc for rga buffer mm_session\n"); ++ return -ENOMEM; ++ } ++ ++ mm = *mm_session; ++ ++ mutex_init(&mm->lock); ++ idr_init_base(&mm->memory_idr, 1); ++ ++ return 0; ++} ++ ++int rga_mm_remove(struct rga_mm **mm_session) ++{ ++ struct rga_mm *mm = *mm_session; ++ ++ mutex_lock(&mm->lock); ++ ++ idr_for_each(&mm->memory_idr, &rga_mm_handle_remove, mm); ++ idr_destroy(&mm->memory_idr); ++ ++ mutex_unlock(&mm->lock); ++ ++ kfree(*mm_session); ++ *mm_session = NULL; ++ ++ return 0; ++} +diff --git a/drivers/video/rockchip/rga3/rga_policy.c b/drivers/video/rockchip/rga3/rga_policy.c +new file mode 100644 +index 000000000..c87ce1881 +--- /dev/null ++++ b/drivers/video/rockchip/rga3/rga_policy.c +@@ -0,0 +1,426 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) Rockchip Electronics Co., Ltd. ++ * ++ * Author: Huang Lee ++ */ ++ ++#define pr_fmt(fmt) "rga_policy: " fmt ++ ++#include "rga_job.h" ++#include "rga_common.h" ++#include "rga_hw_config.h" ++#include "rga_debugger.h" ++ ++#define GET_GCD(n1, n2) \ ++ ({ \ ++ int i; \ ++ int gcd = 1; \ ++ for (i = 1; i <= (n1) && i <= (n2); i++) { \ ++ if ((n1) % i == 0 && (n2) % i == 0) \ ++ gcd = i; \ ++ } \ ++ gcd; \ ++ }) ++#define GET_LCM(n1, n2, gcd) (((n1) * (n2)) / gcd) ++ ++static int rga_set_feature(struct rga_req *rga_base) ++{ ++ int feature = 0; ++ ++ if (rga_base->render_mode == COLOR_FILL_MODE) ++ feature |= RGA_COLOR_FILL; ++ ++ if (rga_base->render_mode == COLOR_PALETTE_MODE) ++ feature |= RGA_COLOR_PALETTE; ++ ++ if (rga_base->color_key_max > 0 || rga_base->color_key_min > 0) ++ feature |= RGA_COLOR_KEY; ++ ++ if ((rga_base->alpha_rop_flag >> 1) & 1) ++ feature |= RGA_ROP_CALCULATE; ++ ++ if ((rga_base->alpha_rop_flag >> 8) & 1) ++ feature |= RGA_NN_QUANTIZE; ++ ++ return feature; ++} ++ ++static bool rga_check_csc_constant(const struct rga_hw_data *data, struct rga_req *rga_base, ++ uint32_t mode, uint32_t flag) ++{ ++ if (mode & flag) ++ return true; ++ ++ if ((rga_base->full_csc.flag & 0x1) && (data->feature & RGA_FULL_CSC)) ++ return true; ++ ++ return false; ++} ++ ++static bool rga_check_csc(const struct rga_hw_data *data, struct rga_req *rga_base) ++{ ++ switch (rga_base->yuv2rgb_mode) { ++ case 0x1: ++ return rga_check_csc_constant(data, rga_base, ++ data->csc_y2r_mode, RGA_MODE_CSC_BT601L); ++ case 0x2: ++ return rga_check_csc_constant(data, rga_base, ++ data->csc_y2r_mode, RGA_MODE_CSC_BT601F); ++ case 0x3: ++ return rga_check_csc_constant(data, rga_base, ++ data->csc_y2r_mode, RGA_MODE_CSC_BT709); ++ case 0x1 << 2: ++ return rga_check_csc_constant(data, rga_base, ++ data->csc_r2y_mode, RGA_MODE_CSC_BT601F); ++ case 0x2 << 2: ++ return rga_check_csc_constant(data, rga_base, ++ data->csc_r2y_mode, RGA_MODE_CSC_BT601L); ++ case 0x3 << 2: ++ return rga_check_csc_constant(data, rga_base, ++ data->csc_r2y_mode, RGA_MODE_CSC_BT709); ++ default: ++ break; ++ } ++ ++ if ((rga_base->full_csc.flag & 0x1)) { ++ if (data->feature & RGA_FULL_CSC) ++ return true; ++ else ++ return false; ++ } ++ ++ return true; ++} ++ ++static bool rga_check_resolution(const struct rga_rect_range *range, int width, int height) ++{ ++ if (width > range->max.width || height > range->max.height) ++ return false; ++ ++ if (width < range->min.width || height < range->min.height) ++ return false; ++ ++ return true; ++} ++ ++static bool rga_check_format(const struct rga_hw_data *data, ++ int rd_mode, int format, int win_num) ++{ ++ int i; ++ const uint32_t *formats; ++ uint32_t format_count; ++ ++ switch (rd_mode) { ++ case RGA_RASTER_MODE: ++ formats = data->win[win_num].formats[RGA_RASTER_INDEX]; ++ format_count = data->win[win_num].formats_count[RGA_RASTER_INDEX]; ++ break; ++ case RGA_FBC_MODE: ++ formats = data->win[win_num].formats[RGA_AFBC16x16_INDEX]; ++ format_count = data->win[win_num].formats_count[RGA_AFBC16x16_INDEX]; ++ break; ++ case RGA_TILE_MODE: ++ formats = data->win[win_num].formats[RGA_TILE8x8_INDEX]; ++ format_count = data->win[win_num].formats_count[RGA_TILE8x8_INDEX]; ++ break; ++ default: ++ return false; ++ } ++ ++ if (formats == NULL || format_count == 0) ++ return false; ++ ++ for (i = 0; i < format_count; i++) ++ if (format == formats[i]) ++ return true; ++ ++ return false; ++} ++ ++static bool rga_check_align(uint32_t byte_stride_align, uint32_t format, uint16_t w_stride) ++{ ++ int bit_stride, pixel_stride, align, gcd; ++ ++ pixel_stride = rga_get_pixel_stride_from_format(format); ++ if (pixel_stride <= 0) ++ return false; ++ ++ bit_stride = pixel_stride * w_stride; ++ ++ if (bit_stride % (byte_stride_align * 8) == 0) ++ return true; ++ ++ if (DEBUGGER_EN(MSG)) { ++ gcd = GET_GCD(pixel_stride, byte_stride_align * 8); ++ align = GET_LCM(pixel_stride, byte_stride_align * 8, gcd) / pixel_stride; ++ pr_info("unsupported width stride %d, 0x%x should be %d aligned!", ++ w_stride, format, align); ++ } ++ ++ return false; ++} ++ ++static bool rga_check_src0(const struct rga_hw_data *data, ++ struct rga_img_info_t *src0) ++{ ++ if (!rga_check_resolution(&data->input_range, src0->act_w, src0->act_h)) ++ return false; ++ ++ if (data == &rga3_data && ++ !rga_check_resolution(&data->input_range, ++ src0->act_w + src0->x_offset, ++ src0->act_h + src0->y_offset)) ++ return false; ++ ++ if (!rga_check_format(data, src0->rd_mode, src0->format, 0)) ++ return false; ++ ++ if (!rga_check_align(data->byte_stride_align, src0->format, src0->vir_w)) ++ return false; ++ ++ return true; ++} ++ ++static bool rga_check_src1(const struct rga_hw_data *data, ++ struct rga_img_info_t *src1) ++{ ++ if (!rga_check_resolution(&data->input_range, src1->act_w, src1->act_h)) ++ return false; ++ ++ if (data == &rga3_data && ++ !rga_check_resolution(&data->input_range, ++ src1->act_w + src1->x_offset, ++ src1->act_h + src1->y_offset)) ++ return false; ++ ++ if (!rga_check_format(data, src1->rd_mode, src1->format, 1)) ++ return false; ++ ++ if (!rga_check_align(data->byte_stride_align, src1->format, src1->vir_w)) ++ return false; ++ ++ return true; ++} ++ ++static bool rga_check_dst(const struct rga_hw_data *data, ++ struct rga_img_info_t *dst) ++{ ++ if (!rga_check_resolution(&data->output_range, dst->act_w, dst->act_h)) ++ return false; ++ ++ if (data == &rga3_data && ++ !rga_check_resolution(&data->output_range, ++ dst->act_w + dst->x_offset, ++ dst->act_h + dst->y_offset)) ++ return false; ++ ++ if (!rga_check_format(data, dst->rd_mode, dst->format, 2)) ++ return false; ++ ++ if (!rga_check_align(data->byte_stride_align, dst->format, dst->vir_w)) ++ return false; ++ ++ return true; ++} ++ ++static bool rga_check_scale(const struct rga_hw_data *data, ++ struct rga_req *rga_base) ++{ ++ struct rga_img_info_t *src0 = &rga_base->src; ++ struct rga_img_info_t *dst = &rga_base->dst; ++ ++ int sw, sh; ++ int dw, dh; ++ ++ sw = src0->act_w; ++ sh = src0->act_h; ++ ++ if ((rga_base->sina == 65536 && rga_base->cosa == 0) ++ || (rga_base->sina == -65536 && rga_base->cosa == 0)) { ++ dw = dst->act_h; ++ dh = dst->act_w; ++ } else { ++ dw = dst->act_w; ++ dh = dst->act_h; ++ } ++ ++ if (sw > dw) { ++ if ((sw >> data->max_downscale_factor) > dw) ++ return false; ++ } else if (sw < dw) { ++ if ((sw << data->max_upscale_factor) < dw) ++ return false; ++ } ++ ++ if (sh > dh) { ++ if ((sh >> data->max_downscale_factor) > dh) ++ return false; ++ } else if (sh < dh) { ++ if ((sh << data->max_upscale_factor) < dh) ++ return false; ++ } ++ ++ return true; ++} ++ ++int rga_job_assign(struct rga_job *job) ++{ ++ struct rga_img_info_t *src0 = &job->rga_command_base.src; ++ struct rga_img_info_t *src1 = &job->rga_command_base.pat; ++ struct rga_img_info_t *dst = &job->rga_command_base.dst; ++ ++ struct rga_req *rga_base = &job->rga_command_base; ++ const struct rga_hw_data *data; ++ struct rga_scheduler_t *scheduler = NULL; ++ ++ int feature; ++ int core = RGA_NONE_CORE; ++ int optional_cores = RGA_NONE_CORE; ++ int specified_cores = RGA_NONE_CORE; ++ int i; ++ int min_of_job_count = -1; ++ unsigned long flags; ++ ++ /* assigned by userspace */ ++ if (rga_base->core > RGA_NONE_CORE) { ++ if (rga_base->core > RGA_CORE_MASK) { ++ pr_err("invalid setting core by user\n"); ++ goto finish; ++ } else if (rga_base->core & RGA_CORE_MASK) ++ specified_cores = rga_base->core; ++ } ++ ++ feature = rga_set_feature(rga_base); ++ ++ /* function */ ++ for (i = 0; i < rga_drvdata->num_of_scheduler; i++) { ++ data = rga_drvdata->scheduler[i]->data; ++ scheduler = rga_drvdata->scheduler[i]; ++ ++ if ((specified_cores != RGA_NONE_CORE) && ++ (!(scheduler->core & specified_cores))) ++ continue; ++ ++ if (DEBUGGER_EN(MSG)) ++ pr_info("start policy on core = %d", scheduler->core); ++ ++ if (scheduler->data->mmu == RGA_MMU && ++ job->flags & RGA_JOB_UNSUPPORT_RGA_MMU) { ++ if (DEBUGGER_EN(MSG)) ++ pr_info("RGA2 only support under 4G memory!\n"); ++ continue; ++ } ++ ++ if (feature > 0) { ++ if (!(feature & data->feature)) { ++ if (DEBUGGER_EN(MSG)) ++ pr_info("core = %d, break on feature", ++ scheduler->core); ++ continue; ++ } ++ } ++ ++ /* only colorfill need single win (colorpalette?) */ ++ if (!(feature & 1)) { ++ if (src1->yrgb_addr > 0) { ++ if ((!(src0->rd_mode & data->win[0].rd_mode)) || ++ (!(src1->rd_mode & data->win[1].rd_mode)) || ++ (!(dst->rd_mode & data->win[2].rd_mode))) { ++ if (DEBUGGER_EN(MSG)) ++ pr_info("core = %d, ABC break on rd_mode", ++ scheduler->core); ++ continue; ++ } ++ } else { ++ if ((!(src0->rd_mode & data->win[0].rd_mode)) || ++ (!(dst->rd_mode & data->win[2].rd_mode))) { ++ if (DEBUGGER_EN(MSG)) ++ pr_info("core = %d, ABB break on rd_mode", ++ scheduler->core); ++ continue; ++ } ++ } ++ ++ if (!rga_check_scale(data, rga_base)) { ++ if (DEBUGGER_EN(MSG)) ++ pr_info("core = %d, break on rga_check_scale", ++ scheduler->core); ++ continue; ++ } ++ ++ if (!rga_check_src0(data, src0)) { ++ if (DEBUGGER_EN(MSG)) ++ pr_info("core = %d, break on rga_check_src0", ++ scheduler->core); ++ continue; ++ } ++ ++ if (src1->yrgb_addr > 0) { ++ if (!rga_check_src1(data, src1)) { ++ if (DEBUGGER_EN(MSG)) ++ pr_info("core = %d, break on rga_check_src1", ++ scheduler->core); ++ continue; ++ } ++ } ++ } ++ ++ if (!rga_check_dst(data, dst)) { ++ if (DEBUGGER_EN(MSG)) ++ pr_info("core = %d, break on rga_check_dst", ++ scheduler->core); ++ continue; ++ } ++ ++ if (!rga_check_csc(data, rga_base)) { ++ if (DEBUGGER_EN(MSG)) ++ pr_info("core = %d, break on rga_check_csc", ++ scheduler->core); ++ continue; ++ } ++ ++ optional_cores |= scheduler->core; ++ } ++ ++ if (DEBUGGER_EN(MSG)) ++ pr_info("optional_cores = %d\n", optional_cores); ++ ++ if (optional_cores == 0) { ++ core = -1; ++ pr_err("invalid function policy\n"); ++ goto finish; ++ } ++ ++ for (i = 0; i < rga_drvdata->num_of_scheduler; i++) { ++ scheduler = rga_drvdata->scheduler[i]; ++ ++ if (optional_cores & scheduler->core) { ++ spin_lock_irqsave(&scheduler->irq_lock, flags); ++ ++ if (scheduler->running_job == NULL) { ++ core = scheduler->core; ++ job->scheduler = scheduler; ++ spin_unlock_irqrestore(&scheduler->irq_lock, ++ flags); ++ break; ++ } else { ++ if ((min_of_job_count == -1) || ++ (min_of_job_count > scheduler->job_count)) { ++ min_of_job_count = scheduler->job_count; ++ core = scheduler->core; ++ job->scheduler = scheduler; ++ } ++ } ++ ++ spin_unlock_irqrestore(&scheduler->irq_lock, flags); ++ } ++ } ++ ++ /* TODO: need consider full load */ ++finish: ++ if (DEBUGGER_EN(MSG)) ++ pr_info("assign core: %d\n", core); ++ ++ return core; ++} diff --git a/patches/60-wifi-aic8800.patch b/patches/60-wifi-aic8800.patch new file mode 100644 index 0000000..9c53695 --- /dev/null +++ b/patches/60-wifi-aic8800.patch @@ -0,0 +1,100584 @@ +diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig +index c6599594d..8ebc5080f 100644 +--- a/drivers/net/wireless/Kconfig ++++ b/drivers/net/wireless/Kconfig +@@ -19,6 +19,7 @@ menuconfig WLAN + if WLAN + + source "drivers/net/wireless/admtek/Kconfig" ++source "drivers/net/wireless/aic8800/Kconfig" + source "drivers/net/wireless/ath/Kconfig" + source "drivers/net/wireless/atmel/Kconfig" + source "drivers/net/wireless/broadcom/Kconfig" +diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile +index e1c4141c6..490f8eb93 100644 +--- a/drivers/net/wireless/Makefile ++++ b/drivers/net/wireless/Makefile +@@ -4,6 +4,7 @@ + # + + obj-$(CONFIG_WLAN_VENDOR_ADMTEK) += admtek/ ++obj-$(CONFIG_AIC_WLAN_SUPPORT) += aic8800/ + obj-$(CONFIG_WLAN_VENDOR_ATH) += ath/ + obj-$(CONFIG_WLAN_VENDOR_ATMEL) += atmel/ + obj-$(CONFIG_WLAN_VENDOR_BROADCOM) += broadcom/ +diff --git a/drivers/net/wireless/aic8800/Kconfig b/drivers/net/wireless/aic8800/Kconfig +new file mode 100644 +index 000000000..f6bef8371 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/Kconfig +@@ -0,0 +1,36 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++# ++# AICSemi AIC8800DC SDIO WiFi+BT driver (WardenOS M5 port). ++# ++# Ported from the vendor 5.10.160 out-of-tree source ++# (flare-edge/sdk/sysdrv/drv_ko/wifi/aic8800dc/) — see ++# warden-sdk/kernel/rv1106-enablement/wifi/PORT-PLAN.md and PORT-PROGRESS.md. ++# Modules (=m), loaded late by /oem/usr/ko/insmod_wifi.sh: the AIC8800 SDIO ++# bring-up is two-stage (bsp downloads firmware, chip re-enumerates, fdrv ++# attaches). Built-in device_initcalls run BEFORE the dw_mmc/SDIO controller ++# probes — initcalls are sequential, so aicbsp_init blocks [3.3-7.5]s while the ++# mmc controller only probes at [7.9]s afterward, and the eager bring-up ++# deadlocks (it waits for a card the blocked mmc probe hasn't enumerated). ++# Late module load, after the mmc-pwrseq enumerates the card, is the ++# vendor-proven flow. See PORT-PROGRESS.md. ++ ++config AIC_WLAN_SUPPORT ++ tristate "AIC wireless Support" ++ default m ++ help ++ This is support for the AIC wireless chip (AIC8800DC SDIO combo ++ wifi+BT on the WardenOS 86-Panel). Build as a module (m); built-in ++ deadlocks the two-stage SDIO bring-up (see note above). ++ ++config AIC_FW_PATH ++ depends on AIC_WLAN_SUPPORT ++ string "Firmware & config file path" ++ default "/oem/usr/ko/aic8800dc_fw" ++ help ++ Path to the firmware & config files. The driver reads these ++ directly (not via request_firmware()) — see PORT-PLAN.md §3.8. ++ ++if AIC_WLAN_SUPPORT ++source "drivers/net/wireless/aic8800/aic8800_fdrv/Kconfig" ++source "drivers/net/wireless/aic8800/aic8800_btlpm/Kconfig" ++endif +diff --git a/drivers/net/wireless/aic8800/Makefile b/drivers/net/wireless/aic8800/Makefile +new file mode 100644 +index 000000000..b7432c6e8 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/Makefile +@@ -0,0 +1,8 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++# ++# Link order matters: bsp before fdrv before btlpm, mirroring the working ++# insmod order (insmod_wifi.sh) now that these are built-in (=y) instead of ++# modules — see PORT-PLAN.md §4.5. ++obj-$(CONFIG_AIC_WLAN_SUPPORT) += aic8800_bsp/ ++obj-$(CONFIG_AIC8800_WLAN_SUPPORT) += aic8800_fdrv/ ++obj-$(CONFIG_AIC8800_BTLPM_SUPPORT) += aic8800_btlpm/ +diff --git a/drivers/net/wireless/aic8800/aic8800_bsp/Makefile b/drivers/net/wireless/aic8800/aic8800_bsp/Makefile +new file mode 100755 +index 000000000..64f8480d1 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_bsp/Makefile +@@ -0,0 +1,33 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++# ++# aic8800_bsp — SDIO bus glue + firmware bootstrap, ported in-tree from the ++# vendor out-of-tree Makefile (flare-edge/sdk/sysdrv/drv_ko/wifi/aic8800dc/ ++# aic8800_bsp/Makefile). CONFIG_AIC_FW_PATH is now a real Kconfig string ++# symbol (see ../Kconfig) so it needs no -D here — the driver picks it up ++# from include/generated/autoconf.h directly (aicsdio.c, aic_bsp_driver.h). ++# ++# Vendor CONFIG_* build-time knobs below are preserved as fixed -D flags ++# (not full Kconfig symbols) since this port only needs the one build ++# configuration this board actually uses (SDIO, Rockchip, no USB/PCI/mesh). ++ ++ccflags-y += -DAICWF_SDIO_SUPPORT ++ccflags-y += -DCONFIG_SDIO_PWRCTRL ++ccflags-y += -DCONFIG_PLATFORM_ROCKCHIP ++ccflags-y += -DCONFIG_LINK_DET_5G ++ccflags-y += -DCONFIG_VRF_DCDC_MODE ++ccflags-y += -DCONFIG_PREALLOC_TXQ ++ccflags-y += -DCONFIG_DPD -DCONFIG_FORCE_DPD_CALIB ++ccflags-y += -DCONFIG_RESV_MEM_SUPPORT ++ccflags-y += -DCONFIG_AMSDU_RX ++ccflags-y += -Wno-unused-function ++ ++obj-$(CONFIG_AIC_WLAN_SUPPORT) += aic8800_bsp.o ++aic8800_bsp-y := \ ++ aic8800dc_compat.o \ ++ aic8800d80_compat.o \ ++ aic_bsp_main.o \ ++ aic_bsp_driver.o \ ++ aicsdio.o \ ++ aicsdio_txrxif.o \ ++ md5.o \ ++ aicwf_txq_prealloc.o +diff --git a/drivers/net/wireless/aic8800/aic8800_bsp/aic8800d80_compat.c b/drivers/net/wireless/aic8800/aic8800_bsp/aic8800d80_compat.c +new file mode 100755 +index 000000000..05a7b586f +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_bsp/aic8800d80_compat.c +@@ -0,0 +1,294 @@ ++#include "aic8800d80_compat.h" ++#include "aic_bsp_driver.h" ++ ++extern struct aicbsp_info_t aicbsp_info; ++extern int adap_test; ++ ++typedef u32 (*array2_tbl_t)[2]; ++ ++#define AIC_PATCH_MAGIG_NUM 0x48435450 // "PTCH" ++#define AIC_PATCH_MAGIG_NUM_2 0x50544348 // "HCTP" ++#define AIC_PATCH_BLOCK_MAX 4 ++ ++typedef struct { ++ uint32_t magic_num; ++ uint32_t pair_start; ++ uint32_t magic_num_2; ++ uint32_t pair_count; ++ uint32_t block_dst[AIC_PATCH_BLOCK_MAX]; ++ uint32_t block_src[AIC_PATCH_BLOCK_MAX]; ++ uint32_t block_size[AIC_PATCH_BLOCK_MAX]; // word count ++} aic_patch_t; ++ ++#define AIC_PATCH_OFST(mem) ((size_t) & ((aic_patch_t *)0)->mem) ++#define AIC_PATCH_ADDR(mem) ((u32)(aic_patch_str_base + AIC_PATCH_OFST(mem))) ++ ++u32 aicbsp_syscfg_tbl_8800d80[][2] = {}; ++ ++int aicbsp_system_config_8800d80(struct aic_sdio_dev *sdiodev) ++{ ++ int syscfg_num = sizeof(aicbsp_syscfg_tbl_8800d80) / sizeof(u32) / 2; ++ int ret, cnt; ++ for (cnt = 0; cnt < syscfg_num; cnt++) { ++ ret = aicbsp_priv_rwnx_send_dbg_mem_write_req( ++ sdiodev, aicbsp_syscfg_tbl_8800d80[cnt][0], ++ aicbsp_syscfg_tbl_8800d80[cnt][1]); ++ if (ret) { ++ printk("%x write fail: %d\n", ++ aicbsp_syscfg_tbl_8800d80[cnt][0], ret); ++ return ret; ++ } ++ } ++ return 0; ++} ++ ++u32 adaptivity_patch_tbl_8800d80[][2] = { ++ { 0x000C, 0x0000320A }, //linkloss_thd ++ { 0x009C, 0x00000000 }, //ac_param_conf ++ { 0x0168, 0x00010000 }, //tx_adaptivity_en ++}; ++ ++#define USER_PWROFST_COVER_CALIB_FLAG 0x01U ++#define USER_CHAN_MAX_TXPWR_EN_FLAG (0x01U << 1) ++#define USER_TX_USE_ANA_F_FLAG (0x01U << 2) ++#define USER_APM_PRBRSP_OFFLOAD_DISABLE_FLAG (0x01U << 3) ++ ++#define CFG_PWROFST_COVER_CALIB 1 ++#define CFG_USER_CHAN_MAX_TXPWR_EN 1 ++#define CFG_USER_TX_USE_ANA_F 0 ++#define CFG_USER_APM_PRBRSP_OFFLOAD_DISABLE 0 ++ ++#define CFG_USER_EXT_FLAGS_EN \ ++ (CFG_PWROFST_COVER_CALIB || CFG_USER_CHAN_MAX_TXPWR_EN || \ ++ CFG_USER_TX_USE_ANA_F || CFG_USER_APM_PRBRSP_OFFLOAD_DISABLE) ++ ++u32 patch_tbl_8800d80[][2] = { ++#ifdef USE_5G ++ { 0x00b4, 0xf3010001 }, ++#else ++ { 0x00b4, 0xf3010000 }, ++#endif ++#if defined(CONFIG_AMSDU_RX) ++ { 0x170, 0x0100000a }, ++#endif ++#ifdef CONFIG_IRQ_FALL ++ { 0x00000170, 0x0000010a }, //irqf ++#endif ++ ++#if CFG_USER_EXT_FLAGS_EN ++ { 0x0188, 0x00000000 ++#if CFG_PWROFST_COVER_CALIB ++ | USER_PWROFST_COVER_CALIB_FLAG ++#endif ++#if CFG_USER_CHAN_MAX_TXPWR_EN ++ | USER_CHAN_MAX_TXPWR_EN_FLAG ++#endif ++#if CFG_USER_TX_USE_ANA_F ++ | USER_TX_USE_ANA_F_FLAG ++#endif ++#if CFG_USER_APM_PRBRSP_OFFLOAD_DISABLE ++ | USER_APM_PRBRSP_OFFLOAD_DISABLE_FLAG ++#endif ++ }, // user_ext_flags ++#endif ++ ++#ifdef CONFIG_RADAR_OR_IR_DETECT ++ { 0x019c, 0x00000100 }, //enable radar detect ++#endif ++}; ++ ++#ifdef CONFIG_OOB ++// for 8800d40/d80 map data1 isr to gpiob1 ++u32 gpio_cfg_tbl_8800d40d80[][2] = { ++ { 0x40504084, 0x00000006 }, { 0x40500040, 0x00000000 }, ++ { 0x40100030, 0x00000001 }, { 0x40241020, 0x00000001 }, ++ { 0x40240030, 0x00000004 }, { 0x40240020, 0x03020700 }, ++}; ++#endif ++ ++int aicwifi_sys_config_8800d80(struct aic_sdio_dev *sdiodev) ++{ ++#ifdef CONFIG_OOB ++ int ret, cnt; ++ int gpiocfg_num = sizeof(gpio_cfg_tbl_8800d40d80) / sizeof(u32) / 2; ++ for (cnt = 0; cnt < gpiocfg_num; cnt++) { ++ ret = aicbsp_priv_rwnx_send_dbg_mem_write_req( ++ sdiodev, gpio_cfg_tbl_8800d40d80[cnt][0], ++ gpio_cfg_tbl_8800d40d80[cnt][1]); ++ if (ret) { ++ printk("%x write fail: %d\n", ++ gpio_cfg_tbl_8800d40d80[cnt][0], ret); ++ return ret; ++ } ++ } ++#endif ++ ++ return 0; ++} ++ ++#define NEW_PATCH_BUFFER_MAP 1 ++ ++int aicwifi_patch_config_8800d80(struct aic_sdio_dev *sdiodev) ++{ ++ const u32 rd_patch_addr = RAM_FMAC_FW_ADDR + 0x0198; ++ u32 aic_patch_addr; ++ u32 config_base, aic_patch_str_base; ++#if (NEW_PATCH_BUFFER_MAP) ++ u32 patch_buff_addr, patch_buff_base, rd_version_addr, rd_version_val; ++#endif ++ uint32_t start_addr = 0x0016F800; ++ u32 patch_addr = start_addr; ++ u32 patch_cnt = sizeof(patch_tbl_8800d80) / sizeof(u32) / 2; ++ struct dbg_mem_read_cfm rd_patch_addr_cfm; ++ int ret = 0; ++ int cnt = 0; ++ //adap test ++ int adap_patch_cnt = 0; ++ ++ if (adap_test) { ++ printk("%s for adaptivity test \r\n", __func__); ++ adap_patch_cnt = ++ sizeof(adaptivity_patch_tbl_8800d80) / sizeof(u32) / 2; ++ } ++ ++ aic_patch_addr = rd_patch_addr + 8; ++ ++ ret = aicbsp_priv_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 = aicbsp_priv_rwnx_send_dbg_mem_read_req(sdiodev, aic_patch_addr, ++ &rd_patch_addr_cfm); ++ if (ret) { ++ printk("patch str rd fail\n"); ++ return ret; ++ } ++ aic_patch_str_base = rd_patch_addr_cfm.memdata; ++ ++#if (NEW_PATCH_BUFFER_MAP) ++ rd_version_addr = RAM_FMAC_FW_ADDR + 0x01C; ++ if ((ret = aicbsp_priv_rwnx_send_dbg_mem_read_req(sdiodev, rd_version_addr, ++ &rd_patch_addr_cfm))) { ++ printk("version val[0x%x] rd fail: %d\n", rd_version_addr, ret); ++ return ret; ++ } ++ rd_version_val = rd_patch_addr_cfm.memdata; ++ printk("rd_version_val=%08X\n", rd_version_val); ++ sdiodev->fw_version_uint = rd_version_val; ++ if (rd_version_val > 0x06090100) { ++ patch_buff_addr = rd_patch_addr + 12; ++ ret = aicbsp_priv_rwnx_send_dbg_mem_read_req(sdiodev, patch_buff_addr, ++ &rd_patch_addr_cfm); ++ if (ret) { ++ printk("patch buf rd fail\n"); ++ return ret; ++ } ++ patch_buff_base = rd_patch_addr_cfm.memdata; ++ patch_addr = start_addr = patch_buff_base; ++ } ++#endif ++ ++ ret = aicbsp_priv_rwnx_send_dbg_mem_write_req(sdiodev, AIC_PATCH_ADDR(magic_num), ++ AIC_PATCH_MAGIG_NUM); ++ if (ret) { ++ printk("0x%x write fail\n", AIC_PATCH_ADDR(magic_num)); ++ return ret; ++ } ++ ++ ret = aicbsp_priv_rwnx_send_dbg_mem_write_req(sdiodev, AIC_PATCH_ADDR(magic_num_2), ++ AIC_PATCH_MAGIG_NUM_2); ++ if (ret) { ++ printk("0x%x write fail\n", AIC_PATCH_ADDR(magic_num_2)); ++ return ret; ++ } ++ ++ ret = aicbsp_priv_rwnx_send_dbg_mem_write_req(sdiodev, AIC_PATCH_ADDR(pair_start), ++ patch_addr); ++ if (ret) { ++ printk("0x%x write fail\n", AIC_PATCH_ADDR(pair_start)); ++ return ret; ++ } ++ ++ ret = aicbsp_priv_rwnx_send_dbg_mem_write_req(sdiodev, AIC_PATCH_ADDR(pair_count), ++ patch_cnt + adap_patch_cnt); ++ if (ret) { ++ printk("0x%x write fail\n", AIC_PATCH_ADDR(pair_count)); ++ return ret; ++ } ++ ++ for (cnt = 0; cnt < patch_cnt; cnt++) { ++ ret = aicbsp_priv_rwnx_send_dbg_mem_write_req(sdiodev, start_addr + 8 * cnt, ++ patch_tbl_8800d80[cnt][0] + ++ config_base); ++ if (ret) { ++ printk("%x write fail\n", start_addr + 8 * cnt); ++ return ret; ++ } ++ ret = aicbsp_priv_rwnx_send_dbg_mem_write_req(sdiodev, ++ start_addr + 8 * cnt + 4, ++ patch_tbl_8800d80[cnt][1]); ++ if (ret) { ++ printk("%x write fail\n", start_addr + 8 * cnt + 4); ++ return ret; ++ } ++ } ++ ++ if (adap_test) { ++ int tmp_cnt = patch_cnt + adap_patch_cnt; ++ for (cnt = patch_cnt; cnt < tmp_cnt; cnt++) { ++ int tbl_idx = cnt - patch_cnt; ++ ret = aicbsp_priv_rwnx_send_dbg_mem_write_req( ++ sdiodev, start_addr + 8 * cnt, ++ adaptivity_patch_tbl_8800d80[tbl_idx][0] + ++ config_base); ++ if (ret) { ++ printk("%x write fail\n", start_addr + 8 * cnt); ++ return ret; ++ } ++ ret = aicbsp_priv_rwnx_send_dbg_mem_write_req( ++ sdiodev, start_addr + 8 * cnt + 4, ++ adaptivity_patch_tbl_8800d80[tbl_idx][1]); ++ if (ret) { ++ printk("%x write fail\n", ++ start_addr + 8 * cnt + 4); ++ return ret; ++ } ++ } ++ } ++ ++ ret = aicbsp_priv_rwnx_send_dbg_mem_write_req(sdiodev, ++ AIC_PATCH_ADDR(block_size[0]), 0); ++ if (ret) { ++ printk("block_size[0x%x] write fail: %d\n", ++ AIC_PATCH_ADDR(block_size[0]), ret); ++ return ret; ++ } ++ ret = aicbsp_priv_rwnx_send_dbg_mem_write_req(sdiodev, ++ AIC_PATCH_ADDR(block_size[1]), 0); ++ if (ret) { ++ printk("block_size[0x%x] write fail: %d\n", ++ AIC_PATCH_ADDR(block_size[1]), ret); ++ return ret; ++ } ++ ret = aicbsp_priv_rwnx_send_dbg_mem_write_req(sdiodev, ++ AIC_PATCH_ADDR(block_size[2]), 0); ++ if (ret) { ++ printk("block_size[0x%x] write fail: %d\n", ++ AIC_PATCH_ADDR(block_size[2]), ret); ++ return ret; ++ } ++ ret = aicbsp_priv_rwnx_send_dbg_mem_write_req(sdiodev, ++ AIC_PATCH_ADDR(block_size[3]), 0); ++ if (ret) { ++ printk("block_size[0x%x] write fail: %d\n", ++ AIC_PATCH_ADDR(block_size[3]), ret); ++ return ret; ++ } ++ ++ return 0; ++} +diff --git a/drivers/net/wireless/aic8800/aic8800_bsp/aic8800d80_compat.h b/drivers/net/wireless/aic8800/aic8800_bsp/aic8800d80_compat.h +new file mode 100755 +index 000000000..d496f3a12 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_bsp/aic8800d80_compat.h +@@ -0,0 +1,20 @@ ++#ifndef _AIC8800D80_COMPAT_H_ ++#define _AIC8800D80_COMPAT_H_ ++ ++#include "aicsdio.h" ++/*typedef u32 (*array2_tbl_t)[2]; ++ ++typedef uint8_t u8_l; ++typedef int8_t s8_l; ++typedef bool bool_l; ++typedef uint16_t u16_l; ++typedef int16_t s16_l; ++typedef uint32_t u32_l; ++typedef int32_t s32_l; ++typedef uint64_t u64_l;*/ ++ ++int aicbsp_system_config_8800d80(struct aic_sdio_dev *sdiodev); ++int aicwifi_sys_config_8800d80(struct aic_sdio_dev *sdiodev); ++int aicwifi_patch_config_8800d80(struct aic_sdio_dev *sdiodev); ++ ++#endif +diff --git a/drivers/net/wireless/aic8800/aic8800_bsp/aic8800dc_compat.c b/drivers/net/wireless/aic8800/aic8800_bsp/aic8800dc_compat.c +new file mode 100755 +index 000000000..2ca4a75a6 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_bsp/aic8800dc_compat.c +@@ -0,0 +1,1995 @@ ++#include ++#include "aic8800dc_compat.h" ++#include "aic_bsp_driver.h" ++ ++u8 aicbsp_priv_chip_sub_id = 0; ++u8 aicbsp_priv_chip_mcu_id = 0; ++extern int aicbsp_priv_testmode; ++ ++u32 syscfg_tbl_8800dc[][2] = { ++ { 0x40500010, 0x00000004 }, ++ { 0x40500010, 0x00000006 }, //160m clk ++}; ++ ++u32 syscfg_tbl_8800dc_sdio_u01[][2] = { ++ { 0x40030000, 0x00036724 }, // loop forever after assert_err ++ { 0x0011E800, 0xE7FE4070 }, { 0x40030084, 0x0011E800 }, ++ { 0x40030080, 0x00000001 }, { 0x4010001C, 0x00000000 }, ++}; ++ ++u32 syscfg_tbl_8800dc_sdio_u02[][2] = { ++ { 0x40030000, 0x00036DA4 }, // loop forever after assert_err ++ { 0x0011E800, 0xE7FE4070 }, { 0x40030084, 0x0011E800 }, ++ { 0x40030080, 0x00000001 }, { 0x4010001C, 0x00000000 }, ++}; ++#ifdef CONFIG_OOB ++u32 oobcfg_tbl_8800dc_sdio_u02[][2] = { ++ { 0x40504044, 0x2 }, //oob_enable ++ { 0x40500060, 0x03020700 }, { 0x40500040, 0 }, { 0x40100030, 1 }, ++ { 0x40241020, 1 }, { 0x402400f0, 0x340022 }, ++}; ++#endif //CONFIG_OOB ++ ++u32 syscfg_tbl_masked_8800dc[][3] = { ++//#ifdef CONFIG_PMIC_SETTING ++#if defined(CONFIG_VRF_DCDC_MODE) ++ { 0x7000216C, (0x3 << 2), (0x1 << 2) }, // pmic_pmu_init ++ { 0x700021BC, (0x3 << 2), (0x1 << 2) }, ++ { 0x70002118, ((0x7 << 4) | (0x1 << 7)), ((0x2 << 4) | (0x1 << 7)) }, ++ { 0x70002104, ((0x3F << 0) | (0x1 << 6)), ((0x2 << 0) | (0x1 << 6)) }, ++ { 0x7000210C, ((0x3F << 0) | (0x1 << 6)), ((0x2 << 0) | (0x1 << 6)) }, ++ { 0x70002170, (0xF << 0), (0x1 << 0) }, ++ { 0x70002190, (0x3F << 0), (24 << 0) }, ++ { 0x700021CC, ((0x7 << 4) | (0x1 << 7)), ((0x0 << 4) | (0x0 << 7)) }, ++ { 0x700010A0, (0x1 << 11), (0x1 << 11) }, ++ { 0x70001034, ((0x1 << 20) | (0x7 << 26)), ++ ((0x0 << 20) | (0x2 << 26)) }, ++ { 0x70001038, (0x1 << 8), (0x1 << 8) }, ++ { 0x70001094, (0x3 << 2), (0x0 << 2) }, ++ { 0x700021D0, ((0x1 << 5) | (0x1 << 6)), ((0x1 << 5) | (0x1 << 6)) }, ++ { 0x70001000, ((0x1 << 0) | (0x1 << 20) | (0x1 << 22)), ++ ((0x1 << 0) | (0x1 << 20) | (0x0 << 22)) }, ++ { 0x70001028, (0xf << 2), (0x1 << 2) }, ++#else ++ { 0x7000216C, (0x3 << 2), (0x1 << 2) }, // pmic_pmu_init ++ { 0x700021BC, (0x3 << 2), (0x1 << 2) }, ++ { 0x70002118, ((0x7 << 4) | (0x1 << 7)), ((0x2 << 4) | (0x1 << 7)) }, ++ { 0x70002104, ((0x3F << 0) | (0x1 << 6)), ((0x2 << 0) | (0x1 << 6)) }, ++ { 0x7000210C, ((0x3F << 0) | (0x1 << 6)), ((0x2 << 0) | (0x1 << 6)) }, ++ { 0x70002170, (0xF << 0), (0x1 << 0) }, ++ { 0x70002190, (0x3F << 0), (24 << 0) }, ++ { 0x700021CC, ((0x7 << 4) | (0x1 << 7)), ((0x0 << 4) | (0x0 << 7)) }, ++ { 0x700010A0, (0x1 << 11), (0x1 << 11) }, ++ { 0x70001034, ((0x1 << 20) | (0x7 << 26)), ++ ((0x0 << 20) | (0x2 << 26)) }, ++ { 0x70001038, (0x1 << 8), (0x1 << 8) }, ++ { 0x70001094, (0x3 << 2), (0x0 << 2) }, ++ { 0x700021D0, ((0x1 << 5) | (0x1 << 6)), ((0x1 << 5) | (0x1 << 6)) }, ++ { 0x70001000, ((0x1 << 0) | (0x1 << 20) | (0x1 << 22)), ++ ((0x0 << 0) | (0x1 << 20) | (0x0 << 22)) }, ++ { 0x70001028, (0xf << 2), (0x1 << 2) }, ++#endif ++ //#endif /* CONFIG_PMIC_SETTING */ ++ { 0x00000000, 0x00000000, 0x00000000 }, // last one ++}; ++ ++u32 syscfg_tbl_masked_8800dc_h[][3] = { ++ { 0x7000216C, ((0x3 << 2) | (0x3 << 4)), ++ ((0x2 << 2) | (0x2 << 4)) }, // pmic_pmu_init ++ { 0x70002138, (0xFF << 0), (0xFF << 0) }, ++ { 0x7000213C, (0xFF << 0), (0xFF << 0) }, ++ { 0x70002144, (0xFF << 0), (0xFF << 0) }, ++ { 0x700021BC, (0x3 << 2), (0x1 << 2) }, ++ { 0x70002118, ((0x7 << 4) | (0x1 << 7)), ((0x2 << 4) | (0x1 << 7)) }, ++ { 0x70002104, ((0x3F << 0) | (0x1 << 6)), ((0x2 << 0) | (0x1 << 6)) }, ++ { 0x7000210C, ((0x3F << 0) | (0x1 << 6)), ((0x2 << 0) | (0x1 << 6)) }, ++ { 0x70002170, (0xF << 0), (0x1 << 0) }, ++ { 0x70002190, (0x3F << 0), (24 << 0) }, ++ { 0x700021CC, ((0x7 << 4) | (0x1 << 7)), ((0x0 << 4) | (0x0 << 7)) }, ++ { 0x700010A0, (0x1 << 11), (0x1 << 11) }, ++ //{0x70001034, ((0x1 << 20) | (0x7 << 26)), ((0x0 << 20) | (0x2 << 26))}, ++ { 0x70001038, (0x1 << 8), (0x1 << 8) }, ++ { 0x70001094, (0x3 << 2), (0x0 << 2) }, ++ { 0x700021D0, ((0x1 << 5) | (0x1 << 6)), ((0x1 << 5) | (0x1 << 6)) }, ++#if defined(CONFIG_VRF_DCDC_MODE) ++ { 0x70001000, ((0x1 << 0) | (0x1 << 20) | (0x1 << 22)), ++ ((0x1 << 0) | (0x1 << 20) | (0x0 << 22)) }, ++#else ++ { 0x70001000, ((0x1 << 0) | (0x1 << 20) | (0x1 << 22)), ++ ((0x0 << 0) | (0x1 << 20) | (0x0 << 22)) }, ++#endif ++ { 0x70001028, (0xf << 2), (0x1 << 2) }, ++ ++ { 0x00000000, 0x00000000, 0x00000000 }, // last one ++}; ++ ++u32 syscfg_tbl_masked_8800dc_u01[][3] = { ++ //#ifdef CONFIG_PMIC_SETTING ++ { 0x70001000, (0x1 << 16), (0x1 << 16) }, // for low temperature ++ { 0x70001028, (0x1 << 6), (0x1 << 6) }, ++ { 0x70001000, (0x1 << 16), (0x0 << 16) }, ++ //#endif /* CONFIG_PMIC_SETTING */ ++}; ++ ++u32 patch_tbl_wifisetting_8800dc_u01[][2] = { { 0x010c, 0x01001E01 } }; ++ ++u32 patch_tbl_wifisetting_8800dc_u02[][2] = { ++#if defined(CONFIG_SDIO_PWRCTRL) ++ { 0x0124, 0x01011E01 } ++#else ++ { 0x0124, 0x01001E01 } ++#endif ++}; ++ ++uint32_t ldpc_cfg_ram[] = { ++#if 0 //def CONFIG_FPGA_VERIFICATION ++ 0x00363638, ++ 0x1DF8F834, ++ 0x1DF8F834, ++ 0x1DF8F834, ++ 0x1DF8F834, ++ 0x002F2F31, ++ 0x1DF8F82C, ++ 0x1DF8F82C, ++ 0x1DF8F82C, ++ 0x1DF8F82C, ++ 0x00363639, ++ 0x1AA5F834, ++ 0x1AA5F834, ++ 0x1ADEF834, ++ 0x1ADEF834, ++ 0x003A3A3E, ++ 0x1578F436, ++ 0x1578F436, ++ 0x1578F436, ++ 0x15B6F436, ++ 0x003B3B40, ++ 0x1DF8F838, ++ 0x1DF8F838, ++ 0x1DF8F838, ++ 0x1DF8F838, ++ 0x003B3B41, ++ 0x1DC4F838, ++ 0x1DC4F838, ++ 0x1DF8F838, ++ 0x1DF8F838, ++ 0x003B3B40, ++ 0x1781F838, ++ 0x1781F838, ++ 0x1781F838, ++ 0x17C4F838, ++ 0x003B3B40, ++ 0x0E81F838, ++ 0x0E81F838, ++ 0x0E81F838, ++ 0x0E82F838, ++ 0x003F3F43, ++ 0x1A92F83D, ++ 0x1A92F83E, ++ 0x1A92F83D, ++ 0x1ADDF83D, ++ 0x00272729, ++ 0x1DF8F824, ++ 0x1DF8F824, ++ 0x1DF8F843, ++ 0x1DF8F843, ++ 0x00272729, ++ 0x1DF8F824, ++ 0x1DF8F824, ++ 0x1DF8F842, ++ 0x1DF8F842, ++ 0x00262628, ++ 0x1DF8F823, ++ 0x1DF8F823, ++ 0x1DF8F823, ++ 0x1DF8F823, ++ 0x00252528, ++ 0x1DF8F823, ++ 0x1DF8F823, ++ 0x1DF8F823, ++ 0x1DF8F823, ++ 0x00262628, ++ 0x1DF8F823, ++ 0x1DF8F823, ++ 0x1DF8F823, ++ 0x1DF8F823, ++ 0x00242427, ++ 0x1DF8F821, ++ 0x1DF8F821, ++ 0x1DF8F821, ++ 0x1DF8F821, ++ 0x00232326, ++ 0x1DF8F821, ++ 0x1DF8F820, ++ 0x1DF8F820, ++ 0x1DF8F820, ++ 0x00262628, ++ 0x1DF8F823, ++ 0x1DF8F823, ++ 0x1DF8F823, ++ 0x1DF8F823, ++ 0x00242427, ++ 0x1DF8F821, ++ 0x1DF8F821, ++ 0x1DF8F821, ++ 0x1DF8F821, ++ 0x001F1F21, ++ 0x1DF8F81D, ++ 0x1DF8F81D, ++ 0x1DF8F81D, ++ 0x1DF8F81D, ++ 0x00262643, ++ 0x1DF8F822, ++ 0x1DF8F821, ++ 0x1DF8F821, ++ 0x1DF8F821, ++ 0x0018182B, ++ 0x1DF8F816, ++ 0x1DBDF815, ++ 0x1DF8F815, ++ 0x1DF8F815, ++ 0x0018182A, ++ 0x1195F836, ++ 0x1195F815, ++ 0x1195F815, ++ 0x1196F815, ++ 0x0028282C, ++ 0x1DF8F824, ++ 0x1DF8F824, ++ 0x1DF8F824, ++ 0x1DF8F824, ++ 0x0027272C, ++ 0x1DF8F824, ++ 0x1DF8F823, ++ 0x1DF8F823, ++ 0x1DF8F823, ++ 0x0082824A, ++ 0x1ADFF841, ++ 0x1ADDF822, ++ 0x1ADEF822, ++ 0x1ADFF822, ++ 0x003E3E40, ++ 0x09D1F81D, ++ 0x095BF81D, ++ 0x095BF81D, ++ 0x095BF81D, ++ 0x0029292D, ++ 0x1DF8F825, ++ 0x1DF8F825, ++ 0x1DF8F825, ++ 0x1DF8F825, ++ 0x0028282C, ++ 0x1DF8F824, ++ 0x1DF8F824, ++ 0x1DF8F824, ++ 0x1DF8F824, ++ 0x0029292D, ++ 0x1DF8F825, ++ 0x1DF8F825, ++ 0x1DF8F825, ++ 0x1DF8F825, ++ 0x0028282E, ++ 0x1DF8F825, ++ 0x1DF8F824, ++ 0x1DF8F824, ++ 0x1DF8F824, ++ 0x0026262C, ++ 0x1DF8F823, ++ 0x1DF8F822, ++ 0x1DF8F822, ++ 0x1DF8F822, ++ 0x0028282D, ++ 0x1DF8F825, ++ 0x1DF8F824, ++ 0x1DF8F824, ++ 0x1DF8F824, ++ 0x00282852, ++ 0x1DF8F827, ++ 0x1DF8F824, ++ 0x1DF8F824, ++ 0x1DF8F824, ++ 0x0029294E, ++ 0x1DF8F823, ++ 0x1DF8F822, ++ 0x1DF8F822, ++ 0x1DF8F822, ++ 0x00212143, ++ 0x1DF8F821, ++ 0x1DECF81D, ++ 0x1DF4F81D, ++ 0x1DF8F81D, ++ 0x0086864D, ++ 0x1CF0F844, ++ 0x1CEDF823, ++ 0x1CEFF822, ++ 0x1CF0F822, ++ 0x0047474D, ++ 0x1BE8F823, ++ 0x1BE8F823, ++ 0x1BE9F822, ++ 0x1BEAF822, ++ 0x0018182F, ++ 0x14B0F83C, ++ 0x14B0F814, ++ 0x14B0F814, ++ 0x14B0F814, ++ 0x00404040, ++ 0x0AE1F81E, ++ 0x0A61F81D, ++ 0x0A61F81D, ++ 0x0A61F81D, ++ 0x002C2C40, ++ 0x09555526, ++ 0x09555512, ++ 0x09555513, ++ 0x09555512, ++ 0x00181840, ++ 0x06333329, ++ 0x06333314, ++ 0x06333314, ++ 0x06333314, ++ 0x002B2B2F, ++ 0x1DF8F828, ++ 0x1DF8F828, ++ 0x1DF8F828, ++ 0x1DF8F828, ++ 0x002B2B32, ++ 0x1DF8F829, ++ 0x1DF8F828, ++ 0x1DF8F828, ++ 0x1DF8F828, ++ 0x002A2A2F, ++ 0x1DF8F827, ++ 0x1DF8F827, ++ 0x1DF8F827, ++ 0x1DF8F827, ++ 0x002A2A57, ++ 0x1DF8F82B, ++ 0x1DF8F827, ++ 0x1DF8F827, ++ 0x1DF8F827, ++ 0x00919152, ++ 0x1DF8F84B, ++ 0x1DF8F825, ++ 0x1DF8F825, ++ 0x1DF8F825, ++ 0x004C4C51, ++ 0x1DF8F826, ++ 0x1DF8F825, ++ 0x1DF8F825, ++ 0x1DF8F825, ++ 0x00444440, ++ 0x0CF8F820, ++ 0x0C6EF81F, ++ 0x0C6EF81F, ++ 0x0C6EF81F, ++ 0x00424240, ++ 0x0D75753E, ++ 0x0D75751E, ++ 0x0D75751E, ++ 0x0D75751E, ++ 0x00191940, ++ 0x0539392E, ++ 0x05393914, ++ 0x05393914, ++ 0x05393914, ++ 0x002F2F32, ++ 0x1AA5F82C, ++ 0x1AA5F82C, ++ 0x1ADEF82C, ++ 0x1ADEF82C, ++ 0x002F2F40, ++ 0x0C6EDE2C, ++ 0x0C6EDE2C, ++ 0x0C6EDE2C, ++ 0x0C6EDE2C, ++ 0x00323240, ++ 0x053BB62E, ++ 0x053BB62E, ++ 0x053BB62E, ++ 0x053BB62E, ++ 0x00333339, ++ 0x1DC4F82F, ++ 0x1DC4F82F, ++ 0x1DF8F82F, ++ 0x1DF8F82F, ++ 0x00333340, ++ 0x0E81F82F, ++ 0x0E81F82F, ++ 0x0E81F82F, ++ 0x0E82F82F, ++ 0x00333340, ++ 0x063FC42F, ++ 0x063FC42F, ++ 0x063FC42F, ++ 0x063FC42F, ++ 0x00404040, ++ 0x063FC42F, ++ 0x063FC42F, ++ 0x063FC42F, ++ 0x063FC42F, ++ 0x00363640, ++ 0x0747DD33, ++ 0x0747DD33, ++ 0x0747DD33, ++ 0x0747DD33, ++ 0x00404040, ++ 0x0747DD33, ++ 0x0747DD33, ++ 0x0747DD33, ++ 0x0747DD33, ++ 0x00292940, ++ 0x07484825, ++ 0x07484812, ++ 0x07484812, ++ 0x07484812, ++ 0x00404040, ++ 0x07343428, ++ 0x07343414, ++ 0x07343414, ++ 0x07343414, ++ 0x00404040, ++ 0x0538382A, ++ 0x05383814, ++ 0x05383814, ++ 0x05383814, ++ 0x00404040, ++ 0x05292914, ++ 0x05292909, ++ 0x05292909, ++ 0x05292909, ++ 0x000B0B40, ++ 0x02111108, ++ 0x0211110E, ++ 0x02111108, ++ 0x02111108, ++ 0x00404040, ++ 0x063E3E2E, ++ 0x063E3E15, ++ 0x063E3E14, ++ 0x063E3E14, ++ 0x00404040, ++ 0x062E2E14, ++ 0x062E2E09, ++ 0x062E2E09, ++ 0x062E2E09, ++ 0x000B0B40, ++ 0x02131308, ++ 0x0213130F, ++ 0x02131308, ++ 0x02131308 ++#else ++ 0x00767679, 0x1DF8F870, 0x1DF8F870, 0x1DF8F870, 0x1DF8F870, 0x006E6E72, ++ 0x1DF8F869, 0x1DF8F869, 0x1DF8F869, 0x1DF8F869, 0x0076767B, 0x1DF8F870, ++ 0x1DF8F870, 0x1DF8F870, 0x1DF8F870, 0x007E7E85, 0x1DF4F876, 0x1DF4F876, ++ 0x1DF4F876, 0x1DF8F876, 0x0081818A, 0x1DF8F87B, 0x1DF8F87B, 0x1DF8F87B, ++ 0x1DF8F87B, 0x0081818D, 0x1DF8F87B, 0x1DF8F87B, 0x1DF8F87B, 0x1DF8F87B, ++ 0x0081818A, 0x1DF8F87B, 0x1DF8F87C, 0x1DF8F87B, 0x1DF8F87B, 0x007E7E40, ++ 0x1DF8F87B, 0x1DF8F87B, 0x1DF8F87B, 0x1DF8F87B, 0x008B8B92, 0x1DF8F887, ++ 0x1DF8F889, 0x1DF8F887, 0x1DF8F887, 0x00515155, 0x1DF8F84C, 0x1DF8F84C, ++ 0x1DF8F889, 0x1DF8F889, 0x00515154, 0x1DF8F84C, 0x1DF8F84C, 0x1DF8F888, ++ 0x1DF8F888, 0x004F4F53, 0x1DF8F84A, 0x1DF8F84A, 0x1DF8F84A, 0x1DF8F84A, ++ 0x004F4F53, 0x1DF8F84A, 0x1DF8F84A, 0x1DF8F84A, 0x1DF8F84A, 0x004F4F53, ++ 0x1DF8F84A, 0x1DF8F84A, 0x1DF8F84A, 0x1DF8F84A, 0x004E4E53, 0x1DF8F849, ++ 0x1DF8F848, 0x1DF8F848, 0x1DF8F848, 0x004D4D52, 0x1DF8F847, 0x1DF8F847, ++ 0x1DF8F847, 0x1DF8F847, 0x004F4F55, 0x1DF8F84B, 0x1DF8F84A, 0x1DF8F84A, ++ 0x1DF8F84A, 0x004E4E53, 0x1DF8F849, 0x1DF8F848, 0x1DF8F848, 0x1DF8F848, ++ 0x0049494D, 0x1DF8F844, 0x1DF8F844, 0x1DF8F844, 0x1DF8F844, 0x0051518F, ++ 0x1DF8F849, 0x1DF8F848, 0x1DF8F848, 0x1DF8F848, 0x00424277, 0x1DF8F83F, ++ 0x1DF8F83C, 0x1DF8F83C, 0x1DF8F83C, 0x00424275, 0x1DF8F89E, 0x1DF8F83C, ++ 0x1DF8F83C, 0x1DF8F83C, 0x0055555C, 0x1DF8F84C, 0x1DF8F84C, 0x1DF8F84C, ++ 0x1DF8F84C, 0x0053535C, 0x1DF8F84C, 0x1DF8F84B, 0x1DF8F84B, 0x1DF8F84B, ++ 0x00F8F89E, 0x1DF8F88C, 0x1DF8F84A, 0x1DF8F84A, 0x1DF8F84A, 0x00898940, ++ 0x18F8F846, 0x18CFF845, 0x18CFF844, 0x18CFF844, 0x0056565F, 0x1DF8F84F, ++ 0x1DF8F84F, 0x1DF8F84F, 0x1DF8F84F, 0x0055555E, 0x1DF8F84E, 0x1DF8F84E, ++ 0x1DF8F84E, 0x1DF8F84E, 0x0056565F, 0x1DF8F84F, 0x1DF8F84F, 0x1DF8F84F, ++ 0x1DF8F84F, 0x00555561, 0x1DF8F850, 0x1DF8F84E, 0x1DF8F84E, 0x1DF8F84E, ++ 0x0053535F, 0x1DF8F84D, 0x1DF8F84C, 0x1DF8F84C, 0x1DF8F84C, 0x0055555F, ++ 0x1DF8F84F, 0x1DF8F84E, 0x1DF8F84E, 0x1DF8F84E, 0x005555AA, 0x1DF8F854, ++ 0x1DF8F84E, 0x1DF8F84E, 0x1DF8F84E, 0x005959A6, 0x1DF8F84D, 0x1DF8F84C, ++ 0x1DF8F84C, 0x1DF8F84C, 0x004F4F9B, 0x1DF8F84E, 0x1DF8F846, 0x1DF8F846, ++ 0x1DF8F846, 0x00F8F8A5, 0x1DF8F894, 0x1DF8F84C, 0x1DF8F84C, 0x1DF8F84C, ++ 0x009898A4, 0x1DF8F84D, 0x1DF8F84C, 0x1DF8F84C, 0x1DF8F84C, 0x00464686, ++ 0x1DF8F8B3, 0x1DF8F83D, 0x1DF8F83D, 0x1DF8F83D, 0x008E8E40, 0x1AF8F848, ++ 0x1ADFF848, 0x1ADFF846, 0x1ADFF846, 0x007F7F40, 0x18D2D275, 0x18D2D23A, ++ 0x18D2D23A, 0x18D2D239, 0x00454540, 0x0F868664, 0x0F86863E, 0x0F86863D, ++ 0x0F86863D, 0x005C5C64, 0x1DF8F856, 0x1DF8F855, 0x1DF8F855, 0x1DF8F855, ++ 0x005B5B68, 0x1DF8F858, 0x1DF8F855, 0x1DF8F855, 0x1DF8F855, 0x005A5A64, ++ 0x1DF8F855, 0x1DF8F854, 0x1DF8F854, 0x1DF8F854, 0x005A5AB5, 0x1DF8F85B, ++ 0x1DF8F855, 0x1DF8F854, 0x1DF8F854, 0x00F8F8B0, 0x1DF8F8A3, 0x1DF8F852, ++ 0x1DF8F852, 0x1DF8F852, 0x00A4A4AE, 0x1DF8F854, 0x1DF8F852, 0x1DF8F852, ++ 0x1DF8F852, 0x009A9A40, 0x1DF8F84E, 0x1DF8F84D, 0x1DF8F84C, 0x1DF8F84C, ++ 0x009C9C40, 0x1DF8F895, 0x1DF8F849, 0x1DF8F84A, 0x1DF8F84A, 0x00494940, ++ 0x1197976F, 0x11979742, 0x11979741, 0x11979741, 0x006E6E74, 0x1DF8F869, ++ 0x1DF8F869, 0x1DF8F869, 0x1DF8F869, 0x006E6E40, 0x1ADEF869, 0x1ADEF869, ++ 0x1ADEF869, 0x1ADEF869, 0x00757540, 0x0D78F86E, 0x0D78F86E, 0x0D78F86E, ++ 0x0D79F86E, 0x00787885, 0x1DF8F873, 0x1DF8F873, 0x1DF8F873, 0x1DF8F873, ++ 0x00787840, 0x1DF8F873, 0x1DF8F873, 0x1DF8F873, 0x1DF8F873, 0x00787840, ++ 0x0E81F873, 0x0E81F873, 0x0E81F873, 0x0E82F873, 0x00404040, 0x0E82F873, ++ 0x0E82F873, 0x0E82F873, 0x0E82F873, 0x00818140, 0x1092F87E, 0x1092F87E, ++ 0x1092F87E, 0x1092F87E, 0x00404040, 0x1092F87E, 0x1092F87E, 0x1092F87E, ++ 0x1092F87E, 0x00737340, 0x14B2B26B, 0x14B2B235, 0x14B2B235, 0x14B2B235, ++ 0x00404040, 0x0E828260, 0x0E82823D, 0x0E82823C, 0x0E82823C, 0x00404040, ++ 0x0F8B8B66, 0x0F8B8B3F, 0x0F8B8B3D, 0x0F8B8B3D, 0x00404040, 0x0B68683D, ++ 0x0B68681E, 0x0B68681E, 0x0B68681E, 0x00222240, 0x06434318, 0x06434329, ++ 0x06434318, 0x06434318, 0x00404040, 0x129D9D72, 0x129D9D43, 0x129D9D41, ++ 0x129D9D41, 0x00404040, 0x0D757542, 0x0D757520, 0x0D757520, 0x0D757520, ++ 0x00232340, 0x084C4C19, 0x084C4C2C, 0x084C4C19, 0x084C4C19 ++#endif ++}; ++ ++uint32_t agc_cfg_ram[] = { ++ 0x20000000, 0x0400000E, 0x3000200E, 0x5B000000, 0x0400004B, 0x3000008E, ++ 0x32000000, 0x0400007B, 0x40000000, 0xF8000026, 0x04000011, 0x4819008E, ++ 0x9C000020, 0x08000191, 0x38008000, 0x0A000000, 0x08104411, 0x38018000, ++ 0x0C004641, 0x08D00014, 0x30000000, 0x01000000, 0x04000017, 0x30000000, ++ 0x3C000000, 0x0400001A, 0x38020000, 0x40000001, 0x0800001D, 0x3808008E, ++ 0x14000050, 0x08000020, 0x4000008E, 0xA400007B, 0x00000101, 0x3000339F, ++ 0x41000700, 0x04104420, 0x90000000, 0x49000000, 0xF00E842F, 0xEC0E842C, ++ 0xEC0E842C, 0x04000032, 0x30000000, 0x48000101, 0x04000032, 0x30000000, ++ 0x48000202, 0x04000032, 0x30000000, 0x46000000, 0x04000011, 0x58010006, ++ 0x3D040472, 0xDC204439, 0x081DD4D2, 0x480A0006, 0xDC2044DC, 0x081DD43C, ++ 0x38050004, 0x0EF1F1C3, 0x342044DC, 0x30000000, 0x01000000, 0x04000042, ++ 0x30000000, 0x33000000, 0x04104445, 0x38008000, 0x2200109C, 0x08104448, ++ 0x38008000, 0x23D4509C, 0x08104417, 0x9000A000, 0x32000000, 0x18000063, ++ 0x14000060, 0x1C000051, 0x10000057, 0x38028000, 0x0C000001, 0x08D04466, ++ 0x3000200F, 0x00000000, 0x00000000, 0x38030000, 0x0C002601, 0x08D0445A, ++ 0x30000000, 0x3D020230, 0x0400005D, 0x30000000, 0x3E000100, 0x04000066, ++ 0x38028000, 0x0C001601, 0x34204466, 0x38028000, 0x0C000A01, 0x34204466, ++ 0x38008004, 0xFF000000, 0x0800007B, 0x3800802F, 0x26000000, 0x0800006C, ++ 0x380404AF, 0x1F191010, 0x0800006F, 0x20000CAF, 0x04000071, 0x60000CAF, ++ 0x18700079, 0x14000077, 0x10000075, 0x28140CAF, 0x09B00084, 0x280A0CAF, ++ 0x09B00084, 0x28060CAF, 0x09B00084, 0x28048086, 0x0800007D, 0x38000086, ++ 0x22800000, 0x04000080, 0x30000000, 0x0EF1F101, 0x36004883, 0x28020000, ++ 0x08000085, 0x3802008E, 0x3D040431, 0x08000088, 0x3805008E, 0x1F241821, ++ 0x0800008B, 0x3000008E, 0xA0163021, 0x0400008E, 0x3000008E, 0x0EF10012, ++ 0x34000091, 0x300000CC, 0x50000000, 0x04000094, 0x380095FE, 0x32010000, ++ 0x04000097, 0x50001FFE, 0x5A010000, 0x6DC9989B, 0xFC19D4B9, 0x30000186, ++ 0x3D840373, 0x0400009E, 0x3000008E, 0x0A000000, 0x040000A1, 0x3000008E, ++ 0x22C00000, 0x040000A4, 0x9000028E, 0x32010001, 0x8E4000AA, 0xC80000B0, ++ 0x00000000, 0x00000000, 0x3000008E, 0x32010001, 0x040000CB, 0x3000008E, ++ 0x29000000, 0x94045011, 0x300019B6, 0x32010000, 0x040000B3, 0x300019B6, ++ 0x3D040431, 0x040000B6, 0x300019B6, 0x22800000, 0x04000097, 0x30000186, ++ 0x3D840473, 0x040000BC, 0x3000008E, 0x29030000, 0x040000BF, 0x9AEE028E, ++ 0x32010100, 0x7C0000C5, 0xCC0000B0, 0x080000B0, 0x00000000, 0x3000008E, ++ 0x32010100, 0x040000C8, 0x3000028E, 0x29000000, 0x94045011, 0x5000038E, ++ 0x29000000, 0x94045011, 0xC0000035, 0x38010006, 0x3D040472, 0x080000D2, ++ 0x30000004, 0x0EF1F141, 0x340000D5, 0x28040004, 0x080000D7, 0x2808000E, ++ 0x080000D9, 0x3000018E, 0x0EF10052, 0x340000DC, 0x3000038E, 0x29000000, ++ 0x94045011, 0x38020000, 0x32000000, 0x080000E2, 0x60000000, 0xD80000E6, ++ 0xD40000E9, 0x040000EC, 0x30000000, 0x0EF1F121, 0x360048EF, 0x30000000, ++ 0x0C002421, 0x360048EF, 0x30000000, 0x0C000021, 0x360048EF, 0x28020000, ++ 0x0800007B, 0x50001EFE, 0x5A010000, 0x6DC998F5, 0xFC19D4F8, 0x3000028E, ++ 0x32000040, 0x040000FB, 0x3AEE028E, 0x32000080, 0x040000FB, 0x30000000, ++ 0x0EF1F101, 0x360048FE, 0x28020000, 0x08000100, 0x3802008E, 0x3D040431, ++ 0x08000103, 0x3805008E, 0x1F241821, 0x08000106, 0x3000008E, 0xA0163021, ++ 0x04000109, 0x3000008E, 0x0EF10012, 0x3400010C, 0x300014F6, 0x32010000, ++ 0x04000114, 0x20000000, 0x04000111, 0x300000EC, 0x50000000, 0x040000F1, ++ 0x300014F6, 0x32030000, 0x04000117, 0x30001086, 0x3D840473, 0x0400011A, ++ 0x5000108E, 0x22C00000, 0x8E47C0CB, 0xCB30011E, 0x300019B6, 0x32040000, ++ 0x04000121, 0x300019B6, 0x3D040431, 0x04000124, 0x300019B6, 0x22800000, ++ 0x04000111, 0x00000000, 0x00000000, 0x00000000, 0x30000186, 0x3D840473, ++ 0x0400012D, 0x5000038E, 0x29000000, 0x94045011, 0xC0000131, 0x380C800E, ++ 0xFF000000, 0x08000134, 0x30000004, 0x0FF1F103, 0x34000137, 0x28020000, ++ 0x08000139, 0x3000038E, 0x29000000, 0x94045011, 0x00000000, 0x00000000, ++ 0x00000000, 0x58010006, 0x3D040472, 0xDC204543, 0x081DD4D2, 0x480A0006, ++ 0xDC2044DC, 0x081DD546, 0x38050004, 0x0EF1F141, 0x342044DC, 0x2802800E, ++ 0x080000DC, 0x48000035, 0x0400014A, 0x7896638F, 0x4100000F, 0x8C00014F, ++ 0x080450C4, 0x90104574, 0x88C8620F, 0xC000015A, 0x90104574, 0x08104554, ++ 0x94104557, 0x3000628F, 0x29000000, 0x9404517A, 0x3000638F, 0x29000000, ++ 0x0410457A, 0x3800E005, 0x3D010131, 0x0810455D, 0xA832600F, 0x90104574, ++ 0x08000154, 0x94104557, 0xC6104567, 0xC4185563, 0x5802E00F, 0x0FEEEA07, ++ 0x80000174, 0x3420456B, 0x5802E00F, 0x0EEEEA07, 0x80000174, 0x3420456B, ++ 0x30004000, 0x33000001, 0x0400016E, 0x38034005, 0x3D030373, 0x08000171, ++ 0x30006007, 0x33000000, 0x04000174, 0x3000608F, 0x29000000, 0x94045177, ++ 0x4000608F, 0xA010457D, 0x0410457A, 0x3000608F, 0x64000101, 0x04104411, ++ 0x3000608F, 0x64000101, 0x04104580, 0x3000618F, 0x42000001, 0x04000183, ++ 0x38028000, 0x32000000, 0x08104586, 0x280A618F, 0x08000188, 0x480A618F, ++ 0xBC00018B, 0x0800018E, 0x3000618F, 0x34000001, 0x04000005, 0x3000618F, ++ 0x34000000, 0x04000008, 0x3000008F, 0x0EEAED0F, 0x36000194, 0x38038000, ++ 0x34000000, 0x08000197, 0x38028005, 0x29010002, 0x0800019A, 0x3000028F, ++ 0x2200209C, 0x0400019D, 0x3000028F, 0x23D4509C, 0x040001A0, 0x2814028F, ++ 0x080001A2, 0x3000028F, 0x43010201, 0x040001A5, 0x3000128F, 0x32000100, ++ 0x040001A8, 0x5AEE138F, 0x4100000F, 0x7C0001AC, 0x080000F9, 0x592C138F, ++ 0x29000000, 0x8C0001B0, 0x080000F9, 0x2000138F, 0x94045011, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000 ++}; ++ ++#if !defined(CONFIG_EXT_FEM_8800DCDW) ++uint32_t txgain_map[96] = { ++#ifdef CONFIG_FPGA_VERIFICATION ++ 0x20c0c971, 0x20c0c980, 0x20c0c992, 0x20c0c9a6, 0x20c0c9bf, 0x20c0caa5, ++ 0x20c0cabd, 0x20c0cba0, 0x20c0cbb6, 0x20c0cbea, 0x20c0ccc5, 0x20c0cdac, ++ 0x20c0cdd0, 0x20c0ceb2, 0x20c0ceff, 0x20c0cfff, 0x20c0c922, 0x20c0c922, ++ 0x20c0c922, 0x20c0c922, 0x20c0c922, 0x20c0c922, 0x20c0c922, 0x20c0c927, ++ 0x20c0c92c, 0x20c0c931, 0x20c0c937, 0x20c0c93f, 0x20c0c946, 0x20c0c94f, ++ 0x20c0c959, 0x20c0c964, 0x20c0cbee, 0x20c0cce0, 0x20c0ccff, 0x20c0cde2, ++ 0x20c0cdfe, 0x20c0cede, 0x20c0cefc, 0x20c0cfd9, 0x20c0cff8, 0x20c0cfff, ++ 0x20c0cfff, 0x20c0cfff, 0x20c0cfff, 0x20c0cfff, 0x20c0cfff, 0x20c0cfff, ++ 0x20c0c97c, 0x20c0c97c, 0x20c0c97c, 0x20c0c97c, 0x20c0c97c, 0x20c0c97c, ++ 0x20c0c97c, 0x20c0c98c, 0x20c0ca79, 0x20c0ca89, 0x20c0cb74, 0x20c0cb84, ++ 0x20c0cb94, 0x20c0cba8, 0x20c0cbbb, 0x20c0cbd2, 0x20c0cbee, 0x20c0cce0, ++ 0x20c0ccff, 0x20c0cde2, 0x20c0cdfe, 0x20c0cede, 0x20c0cefc, 0x20c0cfd9, ++ 0x20c0cff8, 0x20c0cfff, 0x20c0cfff, 0x20c0cfff, 0x20c0cfff, 0x20c0cfff, ++ 0x20c0cfff, 0x20c0cfff, 0x20c0c97c, 0x20c0c97c, 0x20c0c97c, 0x20c0c97c, ++ 0x20c0c97c, 0x20c0c97c, 0x20c0c97c, 0x20c0c98c, 0x20c0ca79, 0x20c0ca89, ++ 0x20c0cb74, 0x20c0cb84, 0x20c0cb94, 0x20c0cba8, 0x20c0cbbb, 0x20c0cbd2, ++#else ++ //11b ++ 0x00ffd780, ++ 0x00ffd872, ++ 0x00ffd880, ++ 0x00ffd972, ++ 0x00ffd980, ++ 0x00ffda75, ++ 0x00ffda86, ++ 0x00ffdb77, ++ 0x00ffdb86, ++ 0x00ffdc78, ++ 0x00ffdc89, ++ 0x00ffdd79, ++ 0x00ffdd89, ++ 0x00ffde83, ++ 0x00ffdf79, ++ 0x00ffdf8b, ++ 0x00ffd072, ++ 0x00ffd072, ++ 0x00ffd080, ++ 0x00ffd172, ++ 0x00ffd180, ++ 0x00ffd272, ++ 0x00ffd280, ++ 0x00ffd36d, ++ 0x00ffd379, ++ 0x00ffd46d, ++ 0x00ffd479, ++ 0x00ffd572, ++ 0x00ffd580, ++ 0x00ffd672, ++ 0x00ffd680, ++ 0x00ffd772, ++ //high ++ 0x00ffc87d, ++ 0x00ffc88b, ++ 0x00ffc979, ++ 0x00ffc989, ++ 0x00ffcc4b, ++ 0x00ffcc54, ++ 0x00ffcc5e, ++ 0x00ffcc69, ++ 0x00ffcc78, ++ 0x00ffcc85, ++ 0x00ffcd70, ++ 0x00ffcd80, ++ 0x00ffce70, ++ 0x00ffce80, ++ 0x00ffcf7d, ++ 0x00ffcf90, ++ 0x00ffc080, ++ 0x00ffc090, ++ 0x00ffc180, ++ 0x00ffc190, ++ 0x00ffc27b, ++ 0x00ffc28b, ++ 0x00ffc37b, ++ 0x00ffc390, ++ 0x00ffc485, ++ 0x00ffc495, ++ 0x00ffc579, ++ 0x00ffc589, ++ 0x00ffc679, ++ 0x00ffc689, ++ 0x00ffc780, ++ 0x00ffc790, ++ //low ++ 0x00ffc87d, ++ 0x00ffc88b, ++ 0x00ffc979, ++ 0x00ffc989, ++ 0x00ffcc4b, ++ 0x00ffcc54, ++ 0x00ffcc5e, ++ 0x00ffcc69, ++ 0x00ffcc78, ++ 0x00ffcc85, ++ 0x00ffcd70, ++ 0x00ffcd80, ++ 0x00ffcd90, ++ 0x00ffcf68, ++ 0x00ffcf75, ++ 0x00ffcf83, ++ 0x00ffc080, ++ 0x00ffc090, ++ 0x00ffc180, ++ 0x00ffc190, ++ 0x00ffc27b, ++ 0x00ffc28b, ++ 0x00ffc37b, ++ 0x00ffc390, ++ 0x00ffc485, ++ 0x00ffc495, ++ 0x00ffc579, ++ 0x00ffc589, ++ 0x00ffc679, ++ 0x00ffc689, ++ 0x00ffc780, ++ 0x00ffc790, ++#endif ++}; ++ ++const uint32_t txgain_map_h[96] = { ++ //11b ++ 0xffd888, //11 ++ 0xffd979, //12 ++ 0xffd988, //13 ++ 0xffda79, //14 ++ 0xffda88, //15 ++ 0xffdb79, //16 ++ 0xffdb88, //17 ++ 0xffdc72, //18 ++ 0xffdc80, //19 ++ 0xffdd80, //20 ++ 0xffde66, //21 ++ 0xffde72, //22 ++ 0xffde80, //23 ++ 0xffdf79, //24 ++ 0xffdf88, //25 ++ 0xffdf98, //26 ++ 0xffd079, //-5 ++ 0xffd088, //-4 ++ 0xffd179, //-3 ++ 0xffd188, //-2 ++ 0xffd288, //-1 ++ 0xffd36c, //0 ++ 0xffd379, //1 ++ 0xffd388, //2 ++ 0xffd479, //3 ++ 0xffd488, //4 ++ 0xffd579, //5 ++ 0xffd588, //6 ++ 0xffd679, //7 ++ 0xffd688, //8 ++ 0xffd779, //9 ++ 0xffd879, //10 ++ //high ++ 0xffc879, //8 ++ 0xffc96b, //9 ++ 0xffc979, //10 ++ 0xffcc45, //11 ++ 0xffcc4d, //12 ++ 0xffcc56, //13 ++ 0xffcc60, //14 ++ 0xffcc6b, //15 ++ 0xffcc79, //16 ++ 0xffcd72, //17 ++ 0xffce60, //18 ++ 0xffce72, //19 ++ 0xffcf72, //20 ++ 0xffcf80, //21 ++ 0xffcf90, //22 ++ 0xffcf90, //23 ++ 0xffc079, //-8 ++ 0xffc16b, //-7 ++ 0xffc179, //-6 ++ 0xffc26b, //-5 ++ 0xffc279, //-4 ++ 0xffc36b, //-3 ++ 0xffc379, //-2 ++ 0xffc46b, //-1 ++ 0xffc479, //0 ++ 0xffc56b, //1 ++ 0xffc579, //2 ++ 0xffc66b, //3 ++ 0xffc679, //4 ++ 0xffc76b, //5 ++ 0xffc779, //6 ++ 0xffc86b, //7 ++ //low ++ 0xffc879, //8 ++ 0xffc96b, //9 ++ 0xffc979, //10 ++ 0xffcc45, //11 ++ 0xffcc4d, //12 ++ 0xffcc56, //13 ++ 0xffcc60, //14 ++ 0xffcc6b, //15 ++ 0xffcc79, //16 ++ 0xffcd72, //17 ++ 0xffcf5b, //18 ++ 0xffcf66, //19 ++ 0xffcf72, //20 ++ 0xffcf80, //21 ++ 0xffcf90, //22 ++ 0xffcf90, //23 ++ 0xffc079, //-8 ++ 0xffc16b, //-7 ++ 0xffc179, //-6 ++ 0xffc26b, //-5 ++ 0xffc279, //-4 ++ 0xffc36b, //-3 ++ 0xffc379, //-2 ++ 0xffc46b, //-1 ++ 0xffc479, //0 ++ 0xffc56b, //1 ++ 0xffc579, //2 ++ 0xffc66b, //3 ++ 0xffc679, //4 ++ 0xffc76b, //5 ++ 0xffc779, //6 ++ 0xffc86b, //7 ++}; ++ ++#else /* #ifdef CONFIG_EXT_FEM_8800DCDW */ ++const uint32_t txgain_map_femkct[96] = { ++ //11b ++ 0x00ffd780, //15 ++ 0x00ffd872, //16 ++ 0x00ffd880, //17 ++ 0x00ffd972, //18 ++ 0x00ffd980, //19 ++ 0x00ffda72, //20 ++ 0x00ffda80, //21 ++ 0x00ffdb72, //22 ++ 0x00ffdb80, //23 ++ 0x00ffdc72, //24 ++ 0x00ffdc80, //25 ++ 0x00ffdd72, //26 ++ 0x00ffdd80, //27 ++ 0x00ffde72, //28 ++ 0x00ffde80, //29 ++ 0x00ffdf72, //30 ++ 0x00ffd072, //-1 ++ 0x00ffd072, //0 ++ 0x00ffd080, //1 ++ 0x00ffd172, //2 ++ 0x00ffd180, //3 ++ 0x00ffd272, //4 ++ 0x00ffd280, //5 ++ 0x00ffd36d, //6 ++ 0x00ffd379, //7 ++ 0x00ffd46d, //8 ++ 0x00ffd479, //9 ++ 0x00ffd572, //10 ++ 0x00ffd580, //11 ++ 0x00ffd672, //12 ++ 0x00ffd680, //13 ++ 0x00ffd772, //14 ++ //high ++ 0x00ffc872, //11 ++ 0x00ffc880, //12 ++ 0x00ffc972, //13 ++ 0x00ffc980, //14 ++ 0x00ffca72, //15 ++ 0x00ffca80, //16 ++ 0x00ffcb72, //17 ++ 0x00ffcb80, //18 ++ 0x00ffcc72, //19 ++ 0x00ffcc80, //20 ++ 0x00ffcd72, //21 ++ 0x00ffcd80, //22 ++ 0x00ffce72, //23 ++ 0x00ffce80, //24 ++ 0x00ffcf72, //25 ++ 0x00ffcf80, //26 ++ 0x00ffc072, //-5 ++ 0x00ffc080, //-4 ++ 0x00ffc172, //-3 ++ 0x00ffc180, //-2 ++ 0x00ffc272, //-1 ++ 0x00ffc280, //0 ++ 0x00ffc372, //1 ++ 0x00ffc380, //2 ++ 0x00ffc472, //3 ++ 0x00ffc480, //4 ++ 0x00ffc572, //5 ++ 0x00ffc580, //6 ++ 0x00ffc672, //7 ++ 0x00ffc680, //8 ++ 0x00ffc772, //9 ++ 0x00ffc780, //10 ++ //low ++ 0x00ffc872, //11 ++ 0x00ffc880, //12 ++ 0x00ffc972, //13 ++ 0x00ffc980, //14 ++ 0x00ffca72, //15 ++ 0x00ffca80, //16 ++ 0x00ffcb72, //17 ++ 0x00ffcb80, //18 ++ 0x00ffcc72, //19 ++ 0x00ffcc80, //20 ++ 0x00ffcd72, //21 ++ 0x00ffcd80, //22 ++ 0x00ffce72, //23 ++ 0x00ffce80, //24 ++ 0x00ffcf72, //26 ++ 0x00ffcf80, //27 ++ 0x00ffc072, //-5 ++ 0x00ffc080, //-4 ++ 0x00ffc172, //-3 ++ 0x00ffc180, //-2 ++ 0x00ffc272, //-1 ++ 0x00ffc280, //0 ++ 0x00ffc372, //1 ++ 0x00ffc380, //2 ++ 0x00ffc472, //3 ++ 0x00ffc480, //4 ++ 0x00ffc572, //5 ++ 0x00ffc580, //6 ++ 0x00ffc672, //7 ++ 0x00ffc680, //8 ++ 0x00ffc772, //9 ++ 0x00ffc780, //10 ++}; ++ ++const uint32_t txgain_map_femkct_h[96] = { ++ //11b ++ 0x00ffd872, //15 ++ 0x00ffd880, //16 ++ 0x00ffd972, //17 ++ 0x00ffd980, //18 ++ 0x00ffd990, //19 ++ 0x00ffda72, //20 ++ 0x00ffda80, //21 ++ 0x00ffdb72, //22 ++ 0x00ffdb80, //23 ++ 0x00ffdc72, //24 ++ 0x00ffdc80, //25 ++ 0x00ffdd72, //26 ++ 0x00ffdd80, //27 ++ 0x00ffde72, //28 ++ 0x00ffde80, //29 ++ 0x00ffdf72, //30 ++ 0x00ffd072, //-1 ++ 0x00ffd072, //0 ++ 0x00ffd080, //1 ++ 0x00ffd172, //2 ++ 0x00ffd180, //3 ++ 0x00ffd272, //4 ++ 0x00ffd280, //5 ++ 0x00ffd379, //6 ++ 0x00ffd46d, //7 ++ 0x00ffd479, //8 ++ 0x00ffd572, //9 ++ 0x00ffd580, //10 ++ 0x00ffd672, //11 ++ 0x00ffd680, //12 ++ 0x00ffd772, //13 ++ 0x00ffd780, //14 ++ //high ++ 0x00ffc880, //11 ++ 0x00ffc972, //12 ++ 0x00ffc980, //13 ++ 0x00ffca72, //14 ++ 0x00ffca80, //15 ++ 0x00ffcb72, //16 ++ 0x00ffcb80, //17 ++ 0x00ffcc72, //18 ++ 0x00ffcc80, //19 ++ 0x00ffcc90, //20 ++ 0x00ffcd72, //21 ++ 0x00ffcd80, //22 ++ 0x00ffce72, //23 ++ 0x00ffce80, //24 ++ 0x00ffcf72, //25 ++ 0x00ffcf80, //26 ++ 0x00ffc080, //-5 ++ 0x00ffc172, //-4 ++ 0x00ffc180, //-3 ++ 0x00ffc272, //-2 ++ 0x00ffc280, //-1 ++ 0x00ffc372, //0 ++ 0x00ffc380, //1 ++ 0x00ffc472, //2 ++ 0x00ffc480, //3 ++ 0x00ffc572, //4 ++ 0x00ffc580, //5 ++ 0x00ffc672, //6 ++ 0x00ffc680, //7 ++ 0x00ffc772, //8 ++ 0x00ffc780, //9 ++ 0x00ffc872, //10 ++ //low ++ 0x00ffc880, //11 ++ 0x00ffc972, //12 ++ 0x00ffc980, //13 ++ 0x00ffca72, //14 ++ 0x00ffca80, //15 ++ 0x00ffcb72, //16 ++ 0x00ffcb80, //17 ++ 0x00ffcc72, //18 ++ 0x00ffcc80, //19 ++ 0x00ffcc90, //20 ++ 0x00ffcd72, //21 ++ 0x00ffcd80, //22 ++ 0x00ffce72, //23 ++ 0x00ffce80, //24 ++ 0x00ffcf72, //25 ++ 0x00ffcf80, //26 ++ 0x00ffc080, //-5 ++ 0x00ffc172, //-4 ++ 0x00ffc180, //-3 ++ 0x00ffc272, //-2 ++ 0x00ffc280, //-1 ++ 0x00ffc372, //0 ++ 0x00ffc380, //1 ++ 0x00ffc472, //2 ++ 0x00ffc480, //3 ++ 0x00ffc572, //4 ++ 0x00ffc580, //5 ++ 0x00ffc672, //6 ++ 0x00ffc680, //7 ++ 0x00ffc772, //8 ++ 0x00ffc780, //9 ++ 0x00ffc872, //10 ++}; ++#endif ++ ++u32 jump_tbl[][2] = { ++#ifndef CONFIG_FOR_IPCOM ++ { 296, 0x180001 }, { 137, 0x180011 }, { 303, 0x1810f9 }, ++ { 168, 0x18186d }, { 308, 0x181bbd }, { 288, 0x1820c1 }, ++#else ++ { 308, 0x181001 }, { 288, 0x181031 }, { 296, 0x18120d }, ++ { 137, 0x18121d }, { 303, 0x182305 }, { 168, 0x182a79 }, ++ { 258, 0x182ae1 }, ++#endif ++}; ++ ++u32 jump_tbl_u02[][2] = { { 303, 0x00180d25 }, { 168, 0x001814a5 }, ++ { 265, 0x001816b1 }, { 266, 0x00181849 }, ++ { 256, 0x001818ad }, { 288, 0x00181bf9 }, ++ { 333, 0x00182d0d }, { 26, 0x00182d45 } }; ++ ++u32 patch_tbl_func[][2] = { ++#ifndef CONFIG_FOR_IPCOM ++ { 0x00110054, 0x0018186D }, // same as jump_tbl idx 168 ++ { 0x0011005C, 0x0018186D }, // same as jump_tbl idx 168 ++#else ++ { 0x00110054, 0x00182A79 }, // same as jump_tbl idx 168 ++ { 0x0011005C, 0x00182A79 }, // same as jump_tbl idx 168 ++ { 0x001118D4, 0x00000011 }, ++#endif ++}; ++ ++u32 patch_tbl_func_u02[][2] = { ++ { 0x00110054, 0x001814a5 }, // same as jump_tbl idx 168 ++ { 0x0011005C, 0x001814a5 }, // same as jump_tbl idx 168 ++ { 0x001109c0, 0x00181e3d }, { 0x00110bb4, 0x001824e1 }, ++ { 0x00110f08, 0x00182d25 }, ++}; ++ ++u32 patch_tbl_rf_func[][2] = { ++ { 0x00110bf0, 0x00180001 }, ++}; ++ ++//adap test ++u32 adaptivity_patch_tbl_8800dc[][2] = { ++ { 0x000C, 0x0000320A }, //linkloss_thd ++ { 0x009C, 0x00000000 }, //ac_param_conf ++ { 0x0128, 0xF6140001 }, //tx_adaptivity_en ++}; ++//adap test ++ ++static u8 chip_id = 0; ++#define CHIP_ID_H_MASK 0xC0 ++#define IS_CHIP_ID_H() ((chip_id & CHIP_ID_H_MASK) == CHIP_ID_H_MASK) ++ ++//Crystal provided by CPU (start) ++int set_bbpll_config(struct aic_sdio_dev *rwnx_hw) ++{ ++ // {0x40505010, 0x7C301010},//bbpll ++ int ret = 0; ++ struct dbg_mem_read_cfm rd_mem_addr_cfm; ++ ++ //Read crystal provided by CPU or not. ++ ret = aicbsp_priv_rwnx_send_dbg_mem_read_req(rwnx_hw, 0x40500148, &rd_mem_addr_cfm); ++ if (ret) { ++ AICWFDBG(LOGERROR, "%x rd fail: %d\n", 0x40500148, ret); ++ return -1; ++ } ++ ++ AICWFDBG(LOGDEBUG, "%s rd_mem_addr_cfm.memdata:%x \r\n", __func__, ++ rd_mem_addr_cfm.memdata); ++ ++ if (!(rd_mem_addr_cfm.memdata & 0x01)) { ++ AICWFDBG(LOGINFO, "%s Crystal not provided by CPU \r\n", ++ __func__); ++ return 0; ++ } else { ++ AICWFDBG(LOGINFO, "%s Crystal provided by CPU \r\n", __func__); ++ //Read 0x40505010 value to check bbpll set or not. ++ ret = aicbsp_priv_rwnx_send_dbg_mem_read_req(rwnx_hw, 0x40505010, ++ &rd_mem_addr_cfm); ++ if (ret < 0) { ++ AICWFDBG(LOGERROR, "%s error ret_val:%d\r\n", __func__, ++ ret); ++ return -1; ++ } ++ ++ if ((rd_mem_addr_cfm.memdata >> 29) == 3) { ++ AICWFDBG(LOGERROR, "%s Not need to set \r\n", __func__); ++ return 0; ++ } else { ++ rd_mem_addr_cfm.memdata |= ((0x1 << 29) | (0x1 << 30)); ++ rd_mem_addr_cfm.memdata &= (~(0x1 << 31)); ++ aicbsp_priv_rwnx_send_dbg_mem_write_req(rwnx_hw, 0x40505010, ++ rd_mem_addr_cfm.memdata); ++ } ++ } ++ return 0; ++} ++//Crystal provided by CPU (end) ++ ++void system_config_8800dc(struct aic_sdio_dev *rwnx_hw) ++{ ++ int syscfg_num; ++ array3_tbl_t p_syscfg_msk_tbl; ++ int ret, cnt; ++ const u32 mem_addr = 0x40500000; ++ struct dbg_mem_read_cfm rd_mem_addr_cfm; ++#ifdef CONFIG_OOB ++ int oobcfg_num; ++#endif ++ ++ ret = aicbsp_priv_rwnx_send_dbg_mem_read_req(rwnx_hw, mem_addr, &rd_mem_addr_cfm); ++ if (ret) { ++ AICWFDBG(LOGERROR, "%x rd fail: %d\n", mem_addr, ret); ++ return; ++ } ++ chip_id = (u8)(rd_mem_addr_cfm.memdata >> 16); ++ //printk("%x=%x\n", rd_mem_addr_cfm.memaddr, rd_mem_addr_cfm.memdata); ++ if (((rd_mem_addr_cfm.memdata >> 25) & 0x01UL) == 0x00UL) { ++ aicbsp_priv_chip_mcu_id = 1; ++ } ++ ++ ret = aicbsp_priv_rwnx_send_dbg_mem_read_req(rwnx_hw, 0x00000020, &rd_mem_addr_cfm); ++ if (ret) { ++ AICWFDBG(LOGERROR, "[0x00000020] rd fail: %d\n", ret); ++ return; ++ } ++ aicbsp_priv_chip_sub_id = (u8)(rd_mem_addr_cfm.memdata); ++ //printk("%x=%x\n", rd_mem_addr_cfm.memaddr, rd_mem_addr_cfm.memdata); ++ AICWFDBG(LOGINFO, "chip_id=%x, aicbsp_priv_chip_sub_id=%x!!\n", chip_id, ++ aicbsp_priv_chip_sub_id); ++ ++ //Crystal provided by CPU (start) ++ ret = set_bbpll_config(rwnx_hw); ++ if (ret) { ++ AICWFDBG(LOGERROR, "set_bbpll_config fail: %d\n", ret); ++ return; ++ } ++ //Crystal provided by CPU (end) ++ ++ ret = aicbsp_priv_rwnx_send_dbg_mem_read_req(rwnx_hw, 0x40500010, &rd_mem_addr_cfm); ++ AICWFDBG(LOGDEBUG, "[0x40500010]=%x\n", rd_mem_addr_cfm.memdata); ++ if (ret) { ++ AICWFDBG(LOGERROR, "[0x40500010] rd fail: %d\n", ret); ++ return; ++ } ++ ++ syscfg_num = sizeof(syscfg_tbl_8800dc) / sizeof(uint32_t) / 2; ++ ++ for (cnt = 0; cnt < syscfg_num; cnt++) { ++ ret = aicbsp_priv_rwnx_send_dbg_mem_write_req(rwnx_hw, ++ syscfg_tbl_8800dc[cnt][0], ++ syscfg_tbl_8800dc[cnt][1]); ++ if (ret) { ++ AICWFDBG(LOGERROR, "%x write fail: %d\n", ++ syscfg_tbl_8800dc[cnt][0], ret); ++ return; ++ } ++ } ++ ++ if (aicbsp_priv_chip_mcu_id == 0) { ++ if (aicbsp_priv_chip_sub_id == 0) { ++ syscfg_num = sizeof(syscfg_tbl_8800dc_sdio_u01) / ++ sizeof(u32) / 2; ++ for (cnt = 0; cnt < syscfg_num; cnt++) { ++ ret = aicbsp_priv_rwnx_send_dbg_mem_write_req( ++ rwnx_hw, ++ syscfg_tbl_8800dc_sdio_u01[cnt][0], ++ syscfg_tbl_8800dc_sdio_u01[cnt][1]); ++ if (ret) { ++ AICWFDBG(LOGERROR, ++ "%x write fail: %d\n", ++ syscfg_tbl_8800dc_sdio_u01[cnt] ++ [0], ++ ret); ++ return; ++ } ++ } ++ } else if ((aicbsp_priv_chip_sub_id == 1) || (aicbsp_priv_chip_sub_id == 2)) { ++ syscfg_num = sizeof(syscfg_tbl_8800dc_sdio_u02) / ++ sizeof(u32) / 2; ++ for (cnt = 0; cnt < syscfg_num; cnt++) { ++ ret = aicbsp_priv_rwnx_send_dbg_mem_write_req( ++ rwnx_hw, ++ syscfg_tbl_8800dc_sdio_u02[cnt][0], ++ syscfg_tbl_8800dc_sdio_u02[cnt][1]); ++ if (ret) { ++ AICWFDBG(LOGERROR, ++ "%x write fail: %d\n", ++ syscfg_tbl_8800dc_sdio_u02[cnt] ++ [0], ++ ret); ++ return; ++ } ++ } ++ } ++ } ++#ifdef CONFIG_OOB ++ if ((aicbsp_priv_chip_sub_id == 1) || (aicbsp_priv_chip_sub_id == 2)) { ++ oobcfg_num = ++ sizeof(oobcfg_tbl_8800dc_sdio_u02) / sizeof(u32) / 2; ++ for (cnt = 0; cnt < oobcfg_num; cnt++) { ++ ret = aicbsp_priv_rwnx_send_dbg_mem_write_req( ++ rwnx_hw, oobcfg_tbl_8800dc_sdio_u02[cnt][0], ++ oobcfg_tbl_8800dc_sdio_u02[cnt][1]); ++ if (ret) { ++ AICWFDBG(LOGERROR, "%x write fail: %d\n", ++ oobcfg_tbl_8800dc_sdio_u02[cnt][0], ++ ret); ++ return; ++ } ++ } ++ } ++#endif ++ if (IS_CHIP_ID_H()) { ++ syscfg_num = ++ sizeof(syscfg_tbl_masked_8800dc_h) / sizeof(u32) / 3; ++ p_syscfg_msk_tbl = syscfg_tbl_masked_8800dc_h; ++ } else { ++ syscfg_num = sizeof(syscfg_tbl_masked_8800dc) / sizeof(u32) / 3; ++ p_syscfg_msk_tbl = syscfg_tbl_masked_8800dc; ++ } ++ ++ for (cnt = 0; cnt < syscfg_num; cnt++) { ++ if (p_syscfg_msk_tbl[cnt][0] == 0x00000000) { ++ break; ++ } else if (p_syscfg_msk_tbl[cnt][0] == 0x70001000) { ++ if (aicbsp_priv_chip_mcu_id == 0) { ++ p_syscfg_msk_tbl[cnt][1] |= ++ ((0x1 << 8) | (0x1 << 15)); // mask ++ p_syscfg_msk_tbl[cnt][2] |= ++ ((0x1 << 8) | (0x1 << 15)); ++ } ++ } ++ ++ ret = aicbsp_priv_rwnx_send_dbg_mem_mask_write_req( ++ rwnx_hw, p_syscfg_msk_tbl[cnt][0], ++ p_syscfg_msk_tbl[cnt][1], p_syscfg_msk_tbl[cnt][2]); ++ if (ret) { ++ AICWFDBG(LOGERROR, "%x mask write fail: %d\n", ++ p_syscfg_msk_tbl[cnt][0], ret); ++ return; ++ } ++ } ++ ++ if (aicbsp_priv_chip_sub_id == 0) { ++ syscfg_num = ++ sizeof(syscfg_tbl_masked_8800dc_u01) / sizeof(u32) / 3; ++ for (cnt = 0; cnt < syscfg_num; cnt++) { ++ ret = aicbsp_priv_rwnx_send_dbg_mem_mask_write_req( ++ rwnx_hw, syscfg_tbl_masked_8800dc_u01[cnt][0], ++ syscfg_tbl_masked_8800dc_u01[cnt][1], ++ syscfg_tbl_masked_8800dc_u01[cnt][2]); ++ if (ret) { ++ AICWFDBG(LOGERROR, "%x mask write fail: %d\n", ++ syscfg_tbl_masked_8800dc_u01[cnt][0], ++ ret); ++ return; ++ } ++ } ++ } ++} ++ ++extern int adap_test; ++ ++void aicwf_patch_config_8800dc(struct aic_sdio_dev *rwnx_hw) ++{ ++ int ret = 0; ++ int cnt = 0; ++ if (aicbsp_priv_testmode == 0) { ++ const u32 cfg_base = 0x10164; ++ struct dbg_mem_read_cfm cfm; ++ int i; ++ u32 wifisetting_cfg_addr; ++ u32 ldpc_cfg_addr; ++ u32 agc_cfg_addr; ++ u32 txgain_cfg_addr; ++ u32 jump_tbl_addr = 0; ++ ++ u32 patch_tbl_wifisetting_num; // = sizeof(patch_tbl_wifisetting_8800dc_u02)/sizeof(u32)/2; ++ u32 ldpc_cfg_size = sizeof(ldpc_cfg_ram); ++ u32 agc_cfg_size = sizeof(agc_cfg_ram); ++ u32 txgain_cfg_size, *txgain_cfg_array; ++ u32 jump_tbl_size = 0; ++ u32 patch_tbl_func_num = 0; ++ ++ //adap test ++ int adap_patch_num = 0; ++ //adap test ++ ++ array2_tbl_t jump_tbl_base = NULL; ++ array2_tbl_t patch_tbl_func_base = NULL; ++ array2_tbl_t patch_tbl_wifisetting_8800dc_base = NULL; ++ ++ if (aicbsp_priv_chip_sub_id == 0) { ++ jump_tbl_base = jump_tbl; ++ jump_tbl_size = sizeof(jump_tbl) / 2; ++ patch_tbl_func_base = patch_tbl_func; ++ patch_tbl_func_num = ++ sizeof(patch_tbl_func) / sizeof(u32) / 2; ++ patch_tbl_wifisetting_num = ++ sizeof(patch_tbl_wifisetting_8800dc_u01) / ++ sizeof(u32) / 2; ++ patch_tbl_wifisetting_8800dc_base = ++ patch_tbl_wifisetting_8800dc_u01; ++ } else if ((aicbsp_priv_chip_sub_id == 1) || (aicbsp_priv_chip_sub_id == 2)) { ++ patch_tbl_wifisetting_num = ++ sizeof(patch_tbl_wifisetting_8800dc_u02) / ++ sizeof(u32) / 2; ++ patch_tbl_wifisetting_8800dc_base = ++ patch_tbl_wifisetting_8800dc_u02; ++ } else { ++ printk("unsupported id: %d", aicbsp_priv_chip_sub_id); ++ return; ++ } ++ ++ //struct dbg_mem_read_cfm cfm; ++ //int i; ++ ++ if ((ret = aicbsp_priv_rwnx_send_dbg_mem_read_req(rwnx_hw, cfg_base, ++ &cfm))) { ++ AICWFDBG(LOGERROR, "setting base[0x%x] rd fail: %d\n", ++ cfg_base, ret); ++ } ++ wifisetting_cfg_addr = cfm.memdata; ++ ++ if (aicbsp_priv_chip_sub_id == 0) { ++ if ((ret = aicbsp_priv_rwnx_send_dbg_mem_read_req( ++ rwnx_hw, cfg_base + 4, &cfm))) { ++ AICWFDBG(LOGERROR, ++ "setting base[0x%x] rd fail: %d\n", ++ cfg_base + 4, ret); ++ } ++ jump_tbl_addr = cfm.memdata; ++ } ++ ++ if ((ret = aicbsp_priv_rwnx_send_dbg_mem_read_req(rwnx_hw, cfg_base + 8, ++ &cfm))) { ++ AICWFDBG(LOGERROR, "setting base[0x%x] rd fail: %d\n", ++ cfg_base + 8, ret); ++ } ++ ldpc_cfg_addr = cfm.memdata; ++ ++ if ((ret = aicbsp_priv_rwnx_send_dbg_mem_read_req(rwnx_hw, cfg_base + 0xc, ++ &cfm))) { ++ AICWFDBG(LOGERROR, "setting base[0x%x] rd fail: %d\n", ++ cfg_base + 0xc, ret); ++ } ++ agc_cfg_addr = cfm.memdata; ++ ++ if ((ret = aicbsp_priv_rwnx_send_dbg_mem_read_req(rwnx_hw, cfg_base + 0x10, ++ &cfm))) { ++ AICWFDBG(LOGERROR, "setting base[0x%x] rd fail: %d\n", ++ cfg_base + 0x10, ret); ++ } ++ txgain_cfg_addr = cfm.memdata; ++ ++ AICWFDBG( ++ LOGINFO, ++ "wifisetting_cfg_addr=%x, ldpc_cfg_addr=%x, agc_cfg_addr=%x, txgain_cfg_addr=%x\n", ++ wifisetting_cfg_addr, ldpc_cfg_addr, agc_cfg_addr, ++ txgain_cfg_addr); ++ ++ for (cnt = 0; cnt < patch_tbl_wifisetting_num; cnt++) { ++ if ((ret = aicbsp_priv_rwnx_send_dbg_mem_write_req( ++ rwnx_hw, ++ wifisetting_cfg_addr + ++ patch_tbl_wifisetting_8800dc_base ++ [cnt][0], ++ patch_tbl_wifisetting_8800dc_base[cnt] ++ [1]))) { ++ AICWFDBG(LOGERROR, ++ "wifisetting %x write fail\n", ++ patch_tbl_wifisetting_8800dc_base[cnt] ++ [0]); ++ } ++ } ++ ++ //adap test ++ if (adap_test) { ++ AICWFDBG(LOGINFO, "%s for adaptivity test \r\n", ++ __func__); ++ adap_patch_num = sizeof(adaptivity_patch_tbl_8800dc) / ++ sizeof(u32) / 2; ++ for (cnt = 0; cnt < adap_patch_num; cnt++) { ++ if ((ret = aicbsp_priv_rwnx_send_dbg_mem_write_req( ++ rwnx_hw, ++ wifisetting_cfg_addr + ++ adaptivity_patch_tbl_8800dc ++ [cnt][0], ++ adaptivity_patch_tbl_8800dc[cnt] ++ [1]))) { ++ AICWFDBG( ++ LOGERROR, "%x write fail\n", ++ wifisetting_cfg_addr + ++ adaptivity_patch_tbl_8800dc ++ [cnt][0]); ++ } ++ } ++ } ++ //adap test ++ ++ if (ldpc_cfg_size > 512) { // > 0.5KB data ++ for (i = 0; i < (ldpc_cfg_size - 512); ++ i += 512) { //each time write 0.5KB ++ ret = aicbsp_priv_rwnx_send_dbg_mem_block_write_req( ++ rwnx_hw, ldpc_cfg_addr + i, 512, ++ ldpc_cfg_ram + i / 4); ++ if (ret) { ++ AICWFDBG( ++ LOGERROR, ++ "ldpc upload fail: %x, err:%d\r\n", ++ ldpc_cfg_addr + i, ret); ++ break; ++ } ++ } ++ } ++ ++ if (!ret && (i < ldpc_cfg_size)) { // < 0.5KB data ++ ret = aicbsp_priv_rwnx_send_dbg_mem_block_write_req( ++ rwnx_hw, ldpc_cfg_addr + i, ldpc_cfg_size - i, ++ ldpc_cfg_ram + i / 4); ++ if (ret) { ++ AICWFDBG(LOGERROR, ++ "ldpc upload fail: %x, err:%d\r\n", ++ ldpc_cfg_addr + i, ret); ++ } ++ } ++ ++ if (agc_cfg_size > 512) { // > 0.5KB data ++ for (i = 0; i < (agc_cfg_size - 512); ++ i += 512) { //each time write 0.5KB ++ ret = aicbsp_priv_rwnx_send_dbg_mem_block_write_req( ++ rwnx_hw, agc_cfg_addr + i, 512, ++ agc_cfg_ram + i / 4); ++ if (ret) { ++ AICWFDBG( ++ LOGERROR, ++ "agc upload fail: %x, err:%d\r\n", ++ agc_cfg_addr + i, ret); ++ break; ++ } ++ } ++ } ++ ++ if (!ret && (i < agc_cfg_size)) { // < 0.5KB data ++ ret = aicbsp_priv_rwnx_send_dbg_mem_block_write_req( ++ rwnx_hw, agc_cfg_addr + i, agc_cfg_size - i, ++ agc_cfg_ram + i / 4); ++ if (ret) { ++ AICWFDBG(LOGERROR, ++ "agc upload fail: %x, err:%d\r\n", ++ agc_cfg_addr + i, ret); ++ } ++ } ++ ++#if !defined(CONFIG_FPGA_VERIFICATION) ++ if ((IS_CHIP_ID_H())) { ++#if defined(CONFIG_EXT_FEM_8800DCDW) ++ txgain_cfg_size = sizeof(txgain_map_femkct_h); ++ txgain_cfg_array = (u32 *)txgain_map_femkct_h; ++#else ++ txgain_cfg_size = sizeof(txgain_map_h); ++ txgain_cfg_array = (u32 *)txgain_map_h; ++#endif ++ } else { ++#if defined(CONFIG_EXT_FEM_8800DCDW) ++ txgain_cfg_size = sizeof(txgain_map_femkct); ++ txgain_cfg_array = (u32 *)txgain_map_femkct; ++#else ++ txgain_cfg_size = sizeof(txgain_map); ++ txgain_cfg_array = (u32 *)txgain_map; ++#endif ++ } ++ ret = aicbsp_priv_rwnx_send_dbg_mem_block_write_req(rwnx_hw, ++ txgain_cfg_addr, ++ txgain_cfg_size, ++ txgain_cfg_array); ++ if (ret) { ++ AICWFDBG(LOGERROR, "txgain upload fail: %x, err:%d\r\n", ++ txgain_cfg_addr, ret); ++ } ++ ++ if (aicbsp_priv_chip_sub_id == 0) { ++ for (cnt = 0; cnt < jump_tbl_size / 4; cnt += 1) { ++ AICWFDBG(LOGDEBUG, "%x = %x\n", ++ jump_tbl_base[cnt][0] * 4 + ++ jump_tbl_addr, ++ jump_tbl_base[cnt][1]); ++ if ((ret = aicbsp_priv_rwnx_send_dbg_mem_write_req( ++ rwnx_hw, ++ jump_tbl_base[cnt][0] * 4 + ++ jump_tbl_addr, ++ jump_tbl_base[cnt][1]))) { ++ AICWFDBG(LOGERROR, "%x write fail\n", ++ jump_tbl_addr + 8 * cnt); ++ } ++ } ++ for (cnt = 0; cnt < patch_tbl_func_num; cnt++) { ++ if ((ret = aicbsp_priv_rwnx_send_dbg_mem_write_req( ++ rwnx_hw, ++ patch_tbl_func_base[cnt][0], ++ patch_tbl_func_base[cnt][1]))) { ++ AICWFDBG( ++ LOGERROR, ++ "patch_tbl_func %x write fail\n", ++ patch_tbl_func_base[cnt][0]); ++ } ++ } ++ } else if (aicbsp_priv_chip_sub_id == 1) { ++ ret = aicwf_patch_table_load( ++ rwnx_hw, RWNX_MAC_PATCH_TABLE_8800DC_U02); ++ if (ret) { ++ printk("patch_tbl upload fail: err:%d\r\n", ++ ret); ++ } ++ } else if (aicbsp_priv_chip_sub_id == 2) { ++ ret = aicwf_patch_table_load( ++ rwnx_hw, RWNX_MAC_PATCH_TABLE_8800DC_H_U02); ++ if (ret) { ++ printk("patch_tbl upload fail: err:%d\r\n", ++ ret); ++ } ++ } else { ++ printk("unsupported id: %d\n", aicbsp_priv_chip_sub_id); ++ } ++ ++#endif ++ } else { ++ if (aicbsp_priv_chip_sub_id == 0) { ++ u32 patch_tbl_rf_func_num = ++ sizeof(patch_tbl_rf_func) / sizeof(u32) / 2; ++ for (cnt = 0; cnt < patch_tbl_rf_func_num; cnt++) { ++ if ((ret = aicbsp_priv_rwnx_send_dbg_mem_write_req( ++ rwnx_hw, patch_tbl_rf_func[cnt][0], ++ patch_tbl_rf_func[cnt][1]))) { ++ AICWFDBG( ++ LOGERROR, ++ "patch_tbl_rf_func %x write fail\n", ++ patch_tbl_rf_func[cnt][0]); ++ } ++ } ++ } ++ } ++} ++ ++int aicwf_misc_ram_init_8800dc(struct aic_sdio_dev *sdiodev) ++{ ++ int ret = 0; ++ uint32_t cfg_base = 0x10164; ++ struct dbg_mem_read_cfm cfm; ++ uint32_t misc_ram_addr; ++ uint32_t misc_ram_size = 12; ++ int i; ++ ++ if (aicbsp_priv_testmode == FW_RFTEST_MODE) { ++ cfg_base = RAM_LMAC_FW_ADDR + 0x0164; ++ } ++ // init misc ram ++ ret = aicbsp_priv_rwnx_send_dbg_mem_read_req(sdiodev, cfg_base + 0x14, &cfm); ++ if (ret) { ++ AICWFDBG(LOGERROR, "rf misc ram[0x%x] rd fail: %d\n", ++ cfg_base + 0x14, ret); ++ return ret; ++ } ++ misc_ram_addr = cfm.memdata; ++ AICWFDBG(LOGERROR, "misc_ram_addr=%x\n", misc_ram_addr); ++ for (i = 0; i < (misc_ram_size / 4); i++) { ++ ret = aicbsp_priv_rwnx_send_dbg_mem_write_req(sdiodev, ++ misc_ram_addr + i * 4, 0); ++ if (ret) { ++ AICWFDBG(LOGERROR, "rf misc ram[0x%x] wr fail: %d\n", ++ misc_ram_addr + i * 4, ret); ++ return ret; ++ } ++ } ++ return ret; ++} ++ ++#ifdef CONFIG_DPD ++int aicwf_dpd_calib_8800dc(struct aic_sdio_dev *sdiodev, ++ rf_misc_ram_lite_t *dpd_res) ++{ ++ int ret = 0; ++ uint32_t fw_addr, boot_type; ++ int valid_flag; ++ ++ printk("%s\n", __func__); ++ ++ ret = aicwf_misc_ram_valid_check_8800dc(sdiodev, &valid_flag); ++ if (ret) { ++ AICWFDBG(LOGINFO, "misc ram check fail: %d\n", ret); ++ return ret; ++ } ++ if (valid_flag) { ++ AICWFDBG(LOGINFO, "misc ram valid, skip calib process\n"); ++ return ret; ++ } ++ ret = aicwf_plat_calib_load_8800dc(sdiodev); ++ if (ret) { ++ AICWFDBG(LOGINFO, "load calib bin fail: %d\n", ret); ++ return ret; ++ } ++ /* fw start */ ++ fw_addr = 0x00130009; ++ boot_type = HOST_START_APP_FNCALL; ++ AICWFDBG(LOGINFO, "Start app: %08x, %d\n", fw_addr, boot_type); ++ ret = aicbsp_priv_rwnx_send_dbg_start_app_req(sdiodev, fw_addr, boot_type, NULL); ++ if (ret) { ++ AICWFDBG(LOGINFO, "start app fail: %d\n", ret); ++ return ret; ++ } ++ { // read dpd res ++ const uint32_t cfg_base = 0x10164; ++ struct dbg_mem_read_cfm cfm; ++ uint32_t misc_ram_addr; ++ uint32_t ram_base_addr, ram_word_cnt; ++ int i; ++ ret = aicbsp_priv_rwnx_send_dbg_mem_read_req(sdiodev, cfg_base + 0x14, ++ &cfm); ++ if (ret) { ++ AICWFDBG(LOGERROR, "rf misc ram[0x%x] rd fail: %d\n", ++ cfg_base + 0x14, ret); ++ return ret; ++ } ++ misc_ram_addr = cfm.memdata; ++ // bit_mask ++ ram_base_addr = ++ misc_ram_addr + offsetof(rf_misc_ram_t, bit_mask); ++ ram_word_cnt = (MEMBER_SIZE(rf_misc_ram_t, bit_mask) + ++ MEMBER_SIZE(rf_misc_ram_t, reserved)) / ++ 4; ++ for (i = 0; i < ram_word_cnt; i++) { ++ ret = aicbsp_priv_rwnx_send_dbg_mem_read_req( ++ sdiodev, ram_base_addr + i * 4, &cfm); ++ if (ret) { ++ AICWFDBG(LOGERROR, ++ "bit_mask[0x%x] rd fail: %d\n", ++ ram_base_addr + i * 4, ret); ++ return ret; ++ } ++ dpd_res->bit_mask[i] = cfm.memdata; ++ } ++ // dpd_high ++ ram_base_addr = ++ misc_ram_addr + offsetof(rf_misc_ram_t, dpd_high); ++ ram_word_cnt = MEMBER_SIZE(rf_misc_ram_t, dpd_high) / 4; ++ for (i = 0; i < ram_word_cnt; i++) { ++ ret = aicbsp_priv_rwnx_send_dbg_mem_read_req( ++ sdiodev, ram_base_addr + i * 4, &cfm); ++ if (ret) { ++ AICWFDBG(LOGERROR, ++ "bit_mask[0x%x] rd fail: %d\n", ++ ram_base_addr + i * 4, ret); ++ return ret; ++ } ++ dpd_res->dpd_high[i] = cfm.memdata; ++ } ++ // loft_res ++ ram_base_addr = ++ misc_ram_addr + offsetof(rf_misc_ram_t, loft_res); ++ ram_word_cnt = MEMBER_SIZE(rf_misc_ram_t, loft_res) / 4; ++ for (i = 0; i < ram_word_cnt; i++) { ++ ret = aicbsp_priv_rwnx_send_dbg_mem_read_req( ++ sdiodev, ram_base_addr + i * 4, &cfm); ++ if (ret) { ++ AICWFDBG(LOGERROR, ++ "bit_mask[0x%x] rd fail: %d\n", ++ ram_base_addr + i * 4, ret); ++ return ret; ++ } ++ dpd_res->loft_res[i] = cfm.memdata; ++ } ++ } ++ return ret; ++} ++ ++int aicwf_dpd_result_apply_8800dc(struct aic_sdio_dev *sdiodev, ++ rf_misc_ram_lite_t *dpd_res) ++{ ++ int ret = 0; ++ uint32_t cfg_base = 0x10164; ++ struct dbg_mem_read_cfm cfm; ++ uint32_t misc_ram_addr; ++ uint32_t ram_base_addr, ram_byte_cnt; ++ AICWFDBG(LOGINFO, "bit_mask[1]=%x\n", dpd_res->bit_mask[1]); ++ if (dpd_res->bit_mask[1] == 0) { ++ AICWFDBG(LOGERROR, "void dpd_res, bypass it.\n"); ++ return 0; ++ } ++ if (aicbsp_priv_testmode == FW_RFTEST_MODE) { ++ cfg_base = RAM_LMAC_FW_ADDR + 0x0164; ++ } ++ if ((ret = aicbsp_priv_rwnx_send_dbg_mem_read_req(sdiodev, cfg_base + 0x14, ++ &cfm))) { ++ AICWFDBG(LOGERROR, "rf misc ram[0x%x] rd fail: %d\n", ++ cfg_base + 0x14, ret); ++ return ret; ++ } ++ misc_ram_addr = cfm.memdata; ++ AICWFDBG(LOGINFO, "misc_ram_addr: %x\n", misc_ram_addr); ++ /* Copy dpd_res on the Embedded side */ ++ // bit_mask ++ AICWFDBG(LOGINFO, "bit_mask[0]=%x\n", dpd_res->bit_mask[0]); ++ ram_base_addr = misc_ram_addr + offsetof(rf_misc_ram_t, bit_mask); ++ ram_byte_cnt = MEMBER_SIZE(rf_misc_ram_t, bit_mask) + ++ MEMBER_SIZE(rf_misc_ram_t, reserved); ++ ret = aicbsp_priv_rwnx_send_dbg_mem_block_write_req(sdiodev, ram_base_addr, ++ ram_byte_cnt, ++ (u32 *)&dpd_res->bit_mask[0]); ++ if (ret) { ++ AICWFDBG(LOGERROR, "bit_mask wr fail: %x, ret:%d\r\n", ++ ram_base_addr, ret); ++ return ret; ++ } ++ // dpd_high ++ AICWFDBG(LOGINFO, "dpd_high[0]=%x\n", dpd_res->dpd_high[0]); ++ ram_base_addr = misc_ram_addr + offsetof(rf_misc_ram_t, dpd_high); ++ ram_byte_cnt = MEMBER_SIZE(rf_misc_ram_t, dpd_high); ++ ret = aicbsp_priv_rwnx_send_dbg_mem_block_write_req(sdiodev, ram_base_addr, ++ ram_byte_cnt, ++ (u32 *)&dpd_res->dpd_high[0]); ++ if (ret) { ++ AICWFDBG(LOGERROR, "dpd_high wr fail: %x, ret:%d\r\n", ++ ram_base_addr, ret); ++ return ret; ++ } ++ // loft_res ++ AICWFDBG(LOGINFO, "loft_res[0]=%x\n", dpd_res->loft_res[0]); ++ ram_base_addr = misc_ram_addr + offsetof(rf_misc_ram_t, loft_res); ++ ram_byte_cnt = MEMBER_SIZE(rf_misc_ram_t, loft_res); ++ ret = aicbsp_priv_rwnx_send_dbg_mem_block_write_req(sdiodev, ram_base_addr, ++ ram_byte_cnt, ++ (u32 *)&dpd_res->loft_res[0]); ++ if (ret) { ++ AICWFDBG(LOGERROR, "loft_res wr fail: %x, ret:%d\r\n", ++ ram_base_addr, ret); ++ return ret; ++ } ++ return ret; ++} ++ ++#ifndef CONFIG_FORCE_DPD_CALIB ++int aicwf_dpd_result_load_8800dc(struct aic_sdio_dev *sdiodev, ++ rf_misc_ram_lite_t *dpd_res) ++{ ++ int ret = 0; ++ int size; ++ u32 *dst = NULL; ++ char *filename = FW_DPDRESULT_NAME_8800DC; ++ struct device *dev = sdiodev->dev; ++ AICWFDBG(LOGINFO, "%s: dpd_res file path:%s \r\n", __func__, filename); ++ /* load file */ ++ size = rwnx_load_firmware(&dst, filename, dev); ++ if (size <= 0) { ++ AICWFDBG(LOGERROR, "wrong size of dpd_res file\n"); ++ if (dst) { ++#ifndef CONFIG_FIRMWARE_ARRAY ++ vfree(dst); ++#endif ++ dst = NULL; ++ } ++ return -1; ++ } ++ AICWFDBG(LOGINFO, "### Load file done: %s, size=%d, dst[0]=%x\n", ++ filename, size, dst[0]); ++ memcpy((u8 *)dpd_res, (u8 *)dst, sizeof(rf_misc_ram_lite_t)); ++ if (dst) { ++#ifndef CONFIG_FIRMWARE_ARRAY ++ vfree(dst); ++#endif ++ dst = NULL; ++ } ++ return ret; ++} ++ ++int aicwf_dpd_result_write_8800dc(void *buf, int buf_len) ++{ ++ int sum = 0, len = 0; ++ char *path = NULL; ++ struct file *fp = NULL; ++ loff_t pos = 0; ++ mm_segment_t fs; ++ ++ AICWFDBG(LOGINFO, "%s\n", __func__); ++ ++ path = __getname(); ++ if (!path) { ++ AICWFDBG(LOGINFO, "get path fail\n"); ++ return -1; ++ } ++ ++ len = snprintf(path, FW_PATH_MAX_LEN, "%s/%s", AICBSP_FW_PATH, ++ FW_DPDRESULT_NAME_8800DC); ++ printk("%s\n", path); ++ ++ fp = filp_open(path, O_RDWR | O_CREAT, 0644); ++ if (IS_ERR(fp)) { ++ AICWFDBG(LOGINFO, "fp open fial\n"); ++ __putname(path); ++ fp = NULL; ++ return -1; ++ } ++ ++ fs = get_fs(); ++ set_fs(KERNEL_DS); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ sum = kernel_write(fp, buf, buf_len, &pos); ++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) ++ sum = kernel_write(fp, (char *)buf, buf_len, pos); ++#else ++ sum = vfs_write(fp, (char *)buf, buf_len, &pos); ++#endif ++ ++ set_fs(fs); ++ __putname(path); ++ filp_close(fp, NULL); ++ fp = NULL; ++ ++ return 0; ++} ++#endif /* !CONFIG_FORCE_DPD_CALIB */ ++#endif ++ ++#ifdef CONFIG_LOFT_CALIB ++int aicwf_loft_calib_8800dc(struct aic_sdio_dev *sdiodev, ++ rf_misc_ram_lite_t *loft_res) ++{ ++ int ret = 0; ++ uint32_t fw_addr, boot_type; ++ int valid_flag; ++ ++ printk("%s\n", __func__); ++ ++ ret = aicwf_misc_ram_valid_check_8800dc(sdiodev, &valid_flag); ++ if (ret) { ++ AICWFDBG(LOGINFO, "misc ram check fail: %d\n", ret); ++ return ret; ++ } ++ if (valid_flag) { ++ AICWFDBG(LOGINFO, "misc ram valid, skip calib process\n"); ++ return ret; ++ } ++ ret = aicwf_plat_calib_load_8800dc(sdiodev); ++ if (ret) { ++ AICWFDBG(LOGINFO, "load calib bin fail: %d\n", ret); ++ return ret; ++ } ++ /* fw start */ ++ fw_addr = 0x00130009; ++ boot_type = HOST_START_APP_FNCALL; ++ AICWFDBG(LOGINFO, "Start app: %08x, %d\n", fw_addr, boot_type); ++ ret = aicbsp_priv_rwnx_send_dbg_start_app_req(sdiodev, fw_addr, boot_type, NULL); ++ if (ret) { ++ AICWFDBG(LOGINFO, "start app fail: %d\n", ret); ++ return ret; ++ } ++ { // read loft res ++ const uint32_t cfg_base = 0x10164; ++ struct dbg_mem_read_cfm cfm; ++ uint32_t misc_ram_addr; ++ uint32_t ram_base_addr, ram_word_cnt; ++ int i; ++ ret = aicbsp_priv_rwnx_send_dbg_mem_read_req(sdiodev, cfg_base + 0x14, ++ &cfm); ++ if (ret) { ++ AICWFDBG(LOGERROR, "rf misc ram[0x%x] rd fail: %d\n", ++ cfg_base + 0x14, ret); ++ return ret; ++ } ++ misc_ram_addr = cfm.memdata; ++ // bit_mask ++ ram_base_addr = ++ misc_ram_addr + offsetof(rf_misc_ram_t, bit_mask); ++ ram_word_cnt = (MEMBER_SIZE(rf_misc_ram_t, bit_mask) + ++ MEMBER_SIZE(rf_misc_ram_t, reserved)) / ++ 4; ++ for (i = 0; i < ram_word_cnt; i++) { ++ ret = aicbsp_priv_rwnx_send_dbg_mem_read_req( ++ sdiodev, ram_base_addr + i * 4, &cfm); ++ if (ret) { ++ AICWFDBG(LOGERROR, ++ "bit_mask[0x%x] rd fail: %d\n", ++ ram_base_addr + i * 4, ret); ++ return ret; ++ } ++ loft_res->bit_mask[i] = cfm.memdata; ++ } ++ // loft_res ++ ram_base_addr = ++ misc_ram_addr + offsetof(rf_misc_ram_t, loft_res); ++ ram_word_cnt = MEMBER_SIZE(rf_misc_ram_t, loft_res) / 4; ++ for (i = 0; i < ram_word_cnt; i++) { ++ ret = aicbsp_priv_rwnx_send_dbg_mem_read_req( ++ sdiodev, ram_base_addr + i * 4, &cfm); ++ if (ret) { ++ AICWFDBG(LOGERROR, ++ "loft_res[0x%x] rd fail: %d\n", ++ ram_base_addr + i * 4, ret); ++ return ret; ++ } ++ loft_res->loft_res[i] = cfm.memdata; ++ } ++ } ++ return ret; ++} ++ ++int aicwf_loft_result_apply_8800dc(struct aic_sdio_dev *sdiodev, ++ rf_misc_ram_lite_t *loft_res) ++{ ++ int ret = 0; ++ uint32_t cfg_base = 0x10164; ++ struct dbg_mem_read_cfm cfm; ++ uint32_t misc_ram_addr; ++ uint32_t ram_base_addr, ram_byte_cnt; ++ AICWFDBG(LOGINFO, "bit_mask[1]=%x\n", loft_res->bit_mask[1]); ++ if (loft_res->bit_mask[1] == 0) { ++ AICWFDBG(LOGERROR, "void loft_res, bypass it.\n"); ++ return 0; ++ } ++ if (aicbsp_priv_testmode == FW_RFTEST_MODE) { ++ cfg_base = RAM_LMAC_FW_ADDR + 0x0164; ++ } ++ if ((ret = aicbsp_priv_rwnx_send_dbg_mem_read_req(sdiodev, cfg_base + 0x14, ++ &cfm))) { ++ AICWFDBG(LOGERROR, "rf misc ram[0x%x] rd fail: %d\n", ++ cfg_base + 0x14, ret); ++ return ret; ++ } ++ misc_ram_addr = cfm.memdata; ++ AICWFDBG(LOGINFO, "misc_ram_addr: %x\n", misc_ram_addr); ++ /* Copy loft_res on the Embedded side */ ++ // bit_mask ++ AICWFDBG(LOGINFO, "bit_mask[0]=%x\n", loft_res->bit_mask[0]); ++ ram_base_addr = misc_ram_addr + offsetof(rf_misc_ram_t, bit_mask); ++ ram_byte_cnt = MEMBER_SIZE(rf_misc_ram_t, bit_mask) + ++ MEMBER_SIZE(rf_misc_ram_t, reserved); ++ ret = aicbsp_priv_rwnx_send_dbg_mem_block_write_req(sdiodev, ram_base_addr, ++ ram_byte_cnt, ++ (u32 *)&loft_res->bit_mask[0]); ++ if (ret) { ++ AICWFDBG(LOGERROR, "bit_mask wr fail: %x, ret:%d\r\n", ++ ram_base_addr, ret); ++ return ret; ++ } ++ // loft_res ++ AICWFDBG(LOGINFO, "loft_res[0]=%x\n", loft_res->loft_res[0]); ++ ram_base_addr = misc_ram_addr + offsetof(rf_misc_ram_t, loft_res); ++ ram_byte_cnt = MEMBER_SIZE(rf_misc_ram_t, loft_res); ++ ret = aicbsp_priv_rwnx_send_dbg_mem_block_write_req(sdiodev, ram_base_addr, ++ ram_byte_cnt, ++ (u32 *)&loft_res->loft_res[0]); ++ if (ret) { ++ AICWFDBG(LOGERROR, "loft_res wr fail: %x, ret:%d\r\n", ++ ram_base_addr, ret); ++ return ret; ++ } ++ return ret; ++} ++#endif +diff --git a/drivers/net/wireless/aic8800/aic8800_bsp/aic8800dc_compat.h b/drivers/net/wireless/aic8800/aic8800_bsp/aic8800dc_compat.h +new file mode 100755 +index 000000000..5fd367e5b +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_bsp/aic8800dc_compat.h +@@ -0,0 +1,43 @@ ++#ifndef _AIC8800DC_COMPAT_H_ ++#define _AIC8800DC_COMPAT_H_ ++ ++#include "aicsdio.h" ++typedef u32 (*array2_tbl_t)[2]; ++typedef u32 (*array3_tbl_t)[3]; ++ ++typedef uint8_t u8_l; ++typedef int8_t s8_l; ++typedef bool bool_l; ++typedef uint16_t u16_l; ++typedef int16_t s16_l; ++typedef uint32_t u32_l; ++typedef int32_t s32_l; ++typedef uint64_t u64_l; ++ ++extern u8 aicbsp_priv_chip_sub_id; ++extern u8 aicbsp_priv_chip_mcu_id; ++#define FW_PATH_MAX_LEN 200 ++ ++void aicwf_patch_config_8800dc(struct aic_sdio_dev *rwnx_hw); ++void system_config_8800dc(struct aic_sdio_dev *rwnx_hw); ++int aicwf_misc_ram_init_8800dc(struct aic_sdio_dev *sdiodev); ++ ++#ifdef CONFIG_DPD ++int aicwf_dpd_calib_8800dc(struct aic_sdio_dev *sdiodev, ++ rf_misc_ram_lite_t *dpd_res); ++int aicwf_dpd_result_apply_8800dc(struct aic_sdio_dev *sdiodev, ++ rf_misc_ram_lite_t *dpd_res); ++#ifndef CONFIG_FORCE_DPD_CALIB ++int aicwf_dpd_result_load_8800dc(struct aic_sdio_dev *sdiodev, ++ rf_misc_ram_lite_t *dpd_res); ++int aicwf_dpd_result_write_8800dc(void *buf, int buf_len); ++#endif /* !CONFIG_FORCE_DPD_CALIB */ ++#endif ++#ifdef CONFIG_LOFT_CALIB ++int aicwf_loft_calib_8800dc(struct aic_sdio_dev *sdiodev, ++ rf_misc_ram_lite_t *loft_res); ++int aicwf_loft_result_apply_8800dc(struct aic_sdio_dev *sdiodev, ++ rf_misc_ram_lite_t *loft_res); ++#endif ++ ++#endif +diff --git a/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_driver.c b/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_driver.c +new file mode 100755 +index 000000000..f1253c64d +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_driver.c +@@ -0,0 +1,2448 @@ ++/** ++ ****************************************************************************** ++ * ++ * rwnx_cmds.c ++ * ++ * Handles queueing (push to IPC, ack/cfm from IPC) of commands issued to ++ * LMAC FW ++ * ++ * Copyright (C) RivieraWaves 2014-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0) ++#include ++#endif ++#include ++#include "aicsdio_txrxif.h" ++#include "aicsdio.h" ++#include "aic_bsp_driver.h" ++#include "md5.h" ++#include "aic8800dc_compat.h" ++#include "aic8800d80_compat.h" ++#include "aicwf_firmware_array.h" ++#define FW_PATH_MAX 200 ++ ++extern int adap_test; ++extern char aicbsp_priv_aic_fw_path[FW_PATH_MAX]; ++extern struct aic_sdio_dev *aicbsp_sdiodev; ++ ++static void cmd_dump(const struct rwnx_cmd *cmd) ++{ ++ printk(KERN_CRIT ++ "tkn[%d] flags:%04x result:%3d cmd:%4d - reqcfm(%4d)\n", ++ cmd->tkn, cmd->flags, cmd->result, cmd->id, cmd->reqid); ++} ++ ++static void cmd_complete(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd) ++{ ++ //printk("cmdcmp\n"); ++ lockdep_assert_held(&cmd_mgr->lock); ++ ++ list_del(&cmd->list); ++ cmd_mgr->queue_sz--; ++ ++ cmd->flags |= RWNX_CMD_FLAG_DONE; ++ if (cmd->flags & RWNX_CMD_FLAG_NONBLOCK) { ++ kfree(cmd); ++ } else { ++ if (RWNX_CMD_WAIT_COMPLETE(cmd->flags)) { ++ cmd->result = 0; ++ complete(&cmd->complete); ++ } ++ } ++} ++ ++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); ++ ++ if (cmd_mgr->state == RWNX_CMD_MGR_STATE_CRASHED) { ++ printk(KERN_CRIT "cmd queue crashed\n"); ++ cmd->result = -EPIPE; ++ spin_unlock_bh(&cmd_mgr->lock); ++ return -EPIPE; ++ } ++ ++ if (!list_empty(&cmd_mgr->cmds)) { ++ struct rwnx_cmd *last; ++ ++ if (cmd_mgr->queue_sz == cmd_mgr->max_queue_sz) { ++ printk(KERN_CRIT "Too many cmds (%d) already queued\n", ++ cmd_mgr->max_queue_sz); ++ cmd->result = -ENOMEM; ++ spin_unlock_bh(&cmd_mgr->lock); ++ return -ENOMEM; ++ } ++ last = list_entry(cmd_mgr->cmds.prev, struct rwnx_cmd, list); ++ if (last->flags & ++ (RWNX_CMD_FLAG_WAIT_ACK | RWNX_CMD_FLAG_WAIT_PUSH)) { ++ cmd->flags |= RWNX_CMD_FLAG_WAIT_PUSH; ++ defer_push = true; ++ } ++ } ++ ++ if (cmd->flags & RWNX_CMD_FLAG_REQ_CFM) ++ cmd->flags |= RWNX_CMD_FLAG_WAIT_CFM; ++ ++ cmd->tkn = cmd_mgr->next_tkn++; ++ cmd->result = -EINTR; ++ ++ if (!(cmd->flags & RWNX_CMD_FLAG_NONBLOCK)) ++ init_completion(&cmd->complete); ++ ++ list_add_tail(&cmd->list, &cmd_mgr->cmds); ++ cmd_mgr->queue_sz++; ++ spin_unlock_bh(&cmd_mgr->lock); ++ ++ if (!defer_push) { ++ //printk("queue:id=%x, param_len=%u\n", cmd->a2e_msg->id, cmd->a2e_msg->param_len); ++ rwnx_set_cmd_tx((void *)(cmd_mgr->sdiodev), cmd->a2e_msg, ++ sizeof(struct lmac_msg) + ++ cmd->a2e_msg->param_len); ++ //rwnx_ipc_msg_push(rwnx_hw, cmd, RWNX_CMD_A2EMSG_LEN(cmd->a2e_msg)); ++ kfree(cmd->a2e_msg); ++ } else { ++ //WAKE_CMD_WORK(cmd_mgr); ++ printk("ERR: never defer push!!!!"); ++ return 0; ++ } ++ ++ 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)) { ++ printk(KERN_CRIT "cmd timed-out\n"); ++ cmd_dump(cmd); ++ spin_lock_bh(&cmd_mgr->lock); ++ cmd_mgr->state = RWNX_CMD_MGR_STATE_CRASHED; ++ if (!(cmd->flags & RWNX_CMD_FLAG_DONE)) { ++ cmd->result = -ETIMEDOUT; ++ cmd_complete(cmd_mgr, cmd); ++ } ++ spin_unlock_bh(&cmd_mgr->lock); ++ err = -ETIMEDOUT; ++ } else { ++ kfree(cmd); ++ } ++ } else { ++ cmd->result = 0; ++ } ++ ++ return err; ++} ++ ++static int cmd_mgr_run_callback(struct rwnx_cmd_mgr *cmd_mgr, ++ struct rwnx_cmd *cmd, ++ struct rwnx_cmd_e2amsg *msg, msg_cb_fct cb) ++{ ++ int res; ++ ++ if (!cb) { ++ return 0; ++ } ++ spin_lock(&cmd_mgr->cb_lock); ++ res = cb(cmd, msg); ++ spin_unlock(&cmd_mgr->cb_lock); ++ ++ return res; ++} ++ ++static int cmd_mgr_msgind(struct rwnx_cmd_mgr *cmd_mgr, ++ struct rwnx_cmd_e2amsg *msg, msg_cb_fct cb) ++{ ++ struct rwnx_cmd *cmd; ++ bool found = false; ++ ++ //printk("cmd->id=%x\n", msg->id); ++ spin_lock(&cmd_mgr->lock); ++ list_for_each_entry (cmd, &cmd_mgr->cmds, list) { ++ if (cmd->reqid == msg->id && ++ (cmd->flags & RWNX_CMD_FLAG_WAIT_CFM)) { ++ if (!cmd_mgr_run_callback(cmd_mgr, cmd, msg, cb)) { ++ found = true; ++ cmd->flags &= ~RWNX_CMD_FLAG_WAIT_CFM; ++ ++ if (WARN((msg->param_len > ++ RWNX_CMD_E2AMSG_LEN_MAX), ++ "Unexpect E2A msg len %d > %d\n", ++ msg->param_len, ++ RWNX_CMD_E2AMSG_LEN_MAX)) { ++ msg->param_len = ++ RWNX_CMD_E2AMSG_LEN_MAX; ++ } ++ ++ if (cmd->e2a_msg && msg->param_len) ++ memcpy(cmd->e2a_msg, &msg->param, ++ msg->param_len); ++ ++ if (RWNX_CMD_WAIT_COMPLETE(cmd->flags)) ++ cmd_complete(cmd_mgr, cmd); ++ ++ break; ++ } ++ } ++ } ++ spin_unlock(&cmd_mgr->lock); ++ ++ if (!found) ++ cmd_mgr_run_callback(cmd_mgr, NULL, msg, cb); ++ ++ return 0; ++} ++ ++static void cmd_mgr_print(struct rwnx_cmd_mgr *cmd_mgr) ++{ ++ struct rwnx_cmd *cur; ++ ++ spin_lock_bh(&cmd_mgr->lock); ++ list_for_each_entry (cur, &cmd_mgr->cmds, list) { ++ cmd_dump(cur); ++ } ++ spin_unlock_bh(&cmd_mgr->lock); ++} ++ ++static void cmd_mgr_drain(struct rwnx_cmd_mgr *cmd_mgr) ++{ ++ struct rwnx_cmd *cur, *nxt; ++ ++ spin_lock_bh(&cmd_mgr->lock); ++ list_for_each_entry_safe (cur, nxt, &cmd_mgr->cmds, list) { ++ list_del(&cur->list); ++ cmd_mgr->queue_sz--; ++ if (!(cur->flags & RWNX_CMD_FLAG_NONBLOCK)) ++ complete(&cur->complete); ++ } ++ spin_unlock_bh(&cmd_mgr->lock); ++} ++ ++void aicbsp_priv_rwnx_cmd_mgr_init(struct rwnx_cmd_mgr *cmd_mgr) ++{ ++ cmd_mgr->max_queue_sz = RWNX_CMD_MAX_QUEUED; ++ INIT_LIST_HEAD(&cmd_mgr->cmds); ++ cmd_mgr->state = RWNX_CMD_MGR_STATE_INITED; ++ spin_lock_init(&cmd_mgr->lock); ++ spin_lock_init(&cmd_mgr->cb_lock); ++ cmd_mgr->queue = &cmd_mgr_queue; ++ cmd_mgr->print = &cmd_mgr_print; ++ cmd_mgr->drain = &cmd_mgr_drain; ++ cmd_mgr->llind = NULL; //&cmd_mgr_llind; ++ cmd_mgr->msgind = &cmd_mgr_msgind; ++ ++#if 0 ++ INIT_WORK(&cmd_mgr->cmdWork, cmd_mgr_task_process); ++ cmd_mgr->cmd_wq = create_singlethread_workqueue("cmd_wq"); ++ if (!cmd_mgr->cmd_wq) { ++ txrx_err("insufficient memory to create cmd workqueue.\n"); ++ return; ++ } ++#endif ++} ++ ++void aicbsp_priv_rwnx_cmd_mgr_deinit(struct rwnx_cmd_mgr *cmd_mgr) ++{ ++ if (cmd_mgr->print) ++ cmd_mgr->print(cmd_mgr); ++ if (cmd_mgr->drain) ++ cmd_mgr->drain(cmd_mgr); ++ if (cmd_mgr->print) ++ cmd_mgr->print(cmd_mgr); ++ memset(cmd_mgr, 0, sizeof(*cmd_mgr)); ++} ++ ++void rwnx_set_cmd_tx(void *dev, struct lmac_msg *msg, uint len) ++{ ++ struct aic_sdio_dev *sdiodev = (struct aic_sdio_dev *)dev; ++ struct aicwf_bus *bus = sdiodev->bus_if; ++ u8 *buffer = bus->cmd_buf; ++ u16 index = 0; ++ ++ memset(buffer, 0, CMD_BUF_MAX); ++ buffer[0] = (len + 4) & 0x00ff; ++ buffer[1] = ((len + 4) >> 8) & 0x0f; ++ buffer[2] = 0x11; ++ if (sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DW) ++ buffer[3] = 0x0; ++ else if (sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) ++ buffer[3] = aicbsp_priv_crc8_ponl_107(&buffer[0], 3); // crc8 ++ index += 4; ++ //there is a dummy word ++ index += 4; ++ ++ //make sure little endian ++ put_u16(&buffer[index], msg->id); ++ index += 2; ++ put_u16(&buffer[index], msg->dest_id); ++ index += 2; ++ put_u16(&buffer[index], msg->src_id); ++ index += 2; ++ put_u16(&buffer[index], msg->param_len); ++ index += 2; ++ memcpy(&buffer[index], (u8 *)msg->param, msg->param_len); ++ ++ aicwf_bus_txmsg(bus, buffer, len + 8); ++} ++ ++static inline void *rwnx_msg_zalloc(lmac_msg_id_t const id, ++ lmac_task_id_t const dest_id, ++ lmac_task_id_t const src_id, ++ uint16_t const param_len) ++{ ++ struct lmac_msg *msg; ++ gfp_t flags; ++ ++ if (in_softirq()) ++ flags = GFP_ATOMIC; ++ else ++ flags = GFP_KERNEL; ++ ++ msg = (struct lmac_msg *)kzalloc(sizeof(struct lmac_msg) + param_len, ++ flags); ++ if (msg == NULL) { ++ printk(KERN_CRIT "%s: msg allocation failed\n", __func__); ++ return NULL; ++ } ++ msg->id = id; ++ msg->dest_id = dest_id; ++ msg->src_id = src_id; ++ msg->param_len = param_len; ++ ++ return msg->param; ++} ++ ++static void rwnx_msg_free(struct lmac_msg *msg, const void *msg_params) ++{ ++ kfree(msg); ++} ++ ++static int rwnx_send_msg(struct aic_sdio_dev *sdiodev, const void *msg_params, ++ int reqcfm, lmac_msg_id_t reqid, void *cfm) ++{ ++ struct lmac_msg *msg; ++ struct rwnx_cmd *cmd; ++ bool nonblock; ++ int ret = 0; ++ ++ msg = container_of((void *)msg_params, struct lmac_msg, param); ++ if (sdiodev->bus_if->state == BUS_DOWN_ST) { ++ rwnx_msg_free(msg, msg_params); ++ printk("bus is down\n"); ++ return 0; ++ } ++ ++ nonblock = 0; ++ cmd = kzalloc(sizeof(struct rwnx_cmd), ++ nonblock ? GFP_ATOMIC : GFP_KERNEL); ++ cmd->result = -EINTR; ++ cmd->id = msg->id; ++ cmd->reqid = reqid; ++ cmd->a2e_msg = msg; ++ cmd->e2a_msg = cfm; ++ if (nonblock) ++ cmd->flags = RWNX_CMD_FLAG_NONBLOCK; ++ if (reqcfm) ++ cmd->flags |= RWNX_CMD_FLAG_REQ_CFM; ++ ++ if (reqcfm) { ++ cmd->flags &= ++ ~RWNX_CMD_FLAG_WAIT_ACK; // we don't need ack any more ++ ret = sdiodev->cmd_mgr.queue(&sdiodev->cmd_mgr, cmd); ++ } else { ++ rwnx_set_cmd_tx((void *)(sdiodev), cmd->a2e_msg, ++ sizeof(struct lmac_msg) + ++ cmd->a2e_msg->param_len); ++ } ++ ++ if (!reqcfm) ++ kfree(cmd); ++ ++ return ret; ++} ++ ++int aicbsp_priv_rwnx_send_dbg_mem_block_write_req(struct aic_sdio_dev *sdiodev, ++ u32 mem_addr, u32 mem_size, u32 *mem_data) ++{ ++ struct dbg_mem_block_write_req *mem_blk_write_req; ++ ++ /* Build the DBG_MEM_BLOCK_WRITE_REQ message */ ++ mem_blk_write_req = ++ rwnx_msg_zalloc(DBG_MEM_BLOCK_WRITE_REQ, TASK_DBG, DRV_TASK_ID, ++ sizeof(struct dbg_mem_block_write_req)); ++ if (!mem_blk_write_req) ++ return -ENOMEM; ++ ++ /* Set parameters for the DBG_MEM_BLOCK_WRITE_REQ message */ ++ mem_blk_write_req->memaddr = mem_addr; ++ mem_blk_write_req->memsize = mem_size; ++ memcpy(mem_blk_write_req->memdata, mem_data, mem_size); ++ ++ /* Send the DBG_MEM_BLOCK_WRITE_REQ message to LMAC FW */ ++ return rwnx_send_msg(sdiodev, mem_blk_write_req, 1, ++ DBG_MEM_BLOCK_WRITE_CFM, NULL); ++} ++ ++int aicbsp_priv_rwnx_send_dbg_mem_read_req(struct aic_sdio_dev *sdiodev, u32 mem_addr, ++ struct dbg_mem_read_cfm *cfm) ++{ ++ struct dbg_mem_read_req *mem_read_req; ++ ++ /* Build the DBG_MEM_READ_REQ message */ ++ mem_read_req = rwnx_msg_zalloc(DBG_MEM_READ_REQ, TASK_DBG, DRV_TASK_ID, ++ sizeof(struct dbg_mem_read_req)); ++ if (!mem_read_req) ++ return -ENOMEM; ++ ++ /* Set parameters for the DBG_MEM_READ_REQ message */ ++ mem_read_req->memaddr = mem_addr; ++ ++ /* Send the DBG_MEM_READ_REQ message to LMAC FW */ ++ return rwnx_send_msg(sdiodev, mem_read_req, 1, DBG_MEM_READ_CFM, cfm); ++} ++ ++int aicbsp_priv_rwnx_send_dbg_mem_write_req(struct aic_sdio_dev *sdiodev, u32 mem_addr, ++ u32 mem_data) ++{ ++ struct dbg_mem_write_req *mem_write_req; ++ ++ /* Build the DBG_MEM_WRITE_REQ message */ ++ mem_write_req = ++ rwnx_msg_zalloc(DBG_MEM_WRITE_REQ, TASK_DBG, DRV_TASK_ID, ++ sizeof(struct dbg_mem_write_req)); ++ if (!mem_write_req) ++ return -ENOMEM; ++ ++ /* Set parameters for the DBG_MEM_WRITE_REQ message */ ++ mem_write_req->memaddr = mem_addr; ++ mem_write_req->memdata = mem_data; ++ ++ /* Send the DBG_MEM_WRITE_REQ message to LMAC FW */ ++ return rwnx_send_msg(sdiodev, mem_write_req, 1, DBG_MEM_WRITE_CFM, ++ NULL); ++} ++ ++int aicbsp_priv_rwnx_send_dbg_mem_mask_write_req(struct aic_sdio_dev *sdiodev, u32 mem_addr, ++ u32 mem_mask, u32 mem_data) ++{ ++ struct dbg_mem_mask_write_req *mem_mask_write_req; ++ ++ /* Build the DBG_MEM_MASK_WRITE_REQ message */ ++ mem_mask_write_req = ++ rwnx_msg_zalloc(DBG_MEM_MASK_WRITE_REQ, TASK_DBG, DRV_TASK_ID, ++ sizeof(struct dbg_mem_mask_write_req)); ++ if (!mem_mask_write_req) ++ return -ENOMEM; ++ ++ /* Set parameters for the DBG_MEM_MASK_WRITE_REQ message */ ++ mem_mask_write_req->memaddr = mem_addr; ++ mem_mask_write_req->memmask = mem_mask; ++ mem_mask_write_req->memdata = mem_data; ++ ++ /* Send the DBG_MEM_MASK_WRITE_REQ message to LMAC FW */ ++ return rwnx_send_msg(sdiodev, mem_mask_write_req, 1, ++ DBG_MEM_MASK_WRITE_CFM, NULL); ++} ++ ++int aicbsp_priv_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) { ++ 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, ++ start_app_cfm); ++} ++ ++static msg_cb_fct dbg_hdlrs[MSG_I(DBG_MAX)] = {}; ++ ++static msg_cb_fct *msg_hdlrs[] = { ++ [TASK_DBG] = dbg_hdlrs, ++}; ++ ++void aicbsp_priv_rwnx_rx_handle_msg(struct aic_sdio_dev *sdiodev, struct ipc_e2a_msg *msg) ++{ ++ sdiodev->cmd_mgr.msgind(&sdiodev->cmd_mgr, msg, ++ 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 ++ ++#define MD5(x) \ ++ x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], \ ++ x[11], x[12], x[13], x[14], x[15] ++#define MD5PINRT \ ++ "file md5:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\r\n" ++ ++int rwnx_load_firmware(u32 **fw_buf, const char *name, struct device *device) ++{ ++#ifdef CONFIG_USE_FW_REQUEST ++ const struct firmware *fw = NULL; ++ u32 *dst = NULL; ++ void *buffer = NULL; ++ MD5_CTX md5; ++ unsigned char decrypt[16]; ++ int size = 0; ++ int ret = 0; ++ ++ printk("%s: request firmware = %s \n", __func__, name); ++ ++ ret = request_firmware(&fw, name, NULL); ++ ++ if (ret < 0) { ++ printk("Load %s fail\n", name); ++ release_firmware(fw); ++ return -1; ++ } ++ ++ size = fw->size; ++ dst = (u32 *)fw->data; ++ ++ if (size <= 0) { ++ printk("wrong size of firmware file\n"); ++ release_firmware(fw); ++ return -1; ++ } ++ ++ buffer = vmalloc(size); ++ memset(buffer, 0, size); ++ memcpy(buffer, dst, size); ++ ++ *fw_buf = buffer; ++ ++ MD5Init(&md5); ++ MD5Update(&md5, (unsigned char *)buffer, size); ++ MD5Final(&md5, decrypt); ++ printk(MD5PINRT, MD5(decrypt)); ++ ++ release_firmware(fw); ++ ++ return size; ++#else ++ 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; ++ MD5_CTX md5; ++ unsigned char decrypt[16]; ++ ++#ifdef CONFIG_FIRMWARE_ARRAY ++ size = aicwf_get_firmware_array((char *)name, fw_buf); ++ printk("%s size:%d \r\n", __func__, size); ++ MD5Init(&md5); ++ MD5Update(&md5, (unsigned char *)*fw_buf, size); ++ MD5Final(&md5, decrypt); ++ printk(MD5PINRT, MD5(decrypt)); ++ ++ return size; ++#endif ++ ++ /* get the firmware path */ ++ path = __getname(); ++ if (!path) { ++ *fw_buf = NULL; ++ return -1; ++ } ++ ++ if (strlen(aicbsp_priv_aic_fw_path) > 0) { ++ len = snprintf(path, AICBSP_FW_PATH_MAX, "%s/%s", aicbsp_priv_aic_fw_path, ++ name); ++ } else { ++ 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 = vmalloc(size); ++ ++ if (!buffer) { ++ *fw_buf = NULL; ++ __putname(path); ++ filp_close(fp, NULL); ++ fp = NULL; ++ return -1; ++ } else { ++ memset(buffer, 0, size); ++ } ++ ++#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, ++ (long int)rdlen); ++ *fw_buf = NULL; ++ __putname(path); ++ filp_close(fp, NULL); ++ fp = NULL; ++ vfree(buffer); ++ buffer = NULL; ++ return -1; ++ } ++ if (rdlen > 0) { ++ fp->f_pos += rdlen; ++ } ++ ++#if 0 ++ /*start to transform the data format*/ ++ src = (u32 *)buffer; ++ dst = (u32 *)vmalloc(size); ++ ++ if (!dst) { ++ *fw_buf = NULL; ++ __putname(path); ++ filp_close(fp, NULL); ++ fp = NULL; ++ vfree(buffer); ++ buffer = NULL; ++ return -1; ++ }else{ ++ memset(dst, 0, size); ++ } ++ ++ for (i = 0; i < (size/4); i++) { ++ dst[i] = src[i]; ++ } ++#endif ++ ++ __putname(path); ++ filp_close(fp, NULL); ++ fp = NULL; ++ //vfree(buffer); ++ //buffer = NULL; ++ *fw_buf = (u32 *)buffer; ++ ++ MD5Init(&md5); ++ MD5Update(&md5, (unsigned char *)buffer, size); ++ MD5Final(&md5, decrypt); ++ ++ printk(MD5PINRT, MD5(decrypt)); ++ ++ return size; ++#endif ++} ++ ++extern int aicbsp_priv_testmode; ++ ++#ifdef CONFIG_M2D_OTA_AUTO_SUPPORT ++extern char saved_sdk_ver[64]; ++ ++int rwnx_plat_m2d_flash_ota_android(struct aic_sdio_dev *sdiodev, ++ char *filename) ++{ ++ struct device *dev = sdiodev->dev; ++ unsigned int i = 0; ++ int size; ++ u32 *dst = NULL; ++ int err = 0; ++ int ret; ++ u8 bond_id; ++ const u32 mem_addr = 0x40500000; ++ struct dbg_mem_read_cfm rd_mem_addr_cfm; ++ ++ ret = aicbsp_priv_rwnx_send_dbg_mem_read_req(sdiodev, mem_addr, &rd_mem_addr_cfm); ++ if (ret) { ++ printk("m2d %x rd fail: %d\n", mem_addr, ret); ++ return ret; ++ } ++ bond_id = (u8)(rd_mem_addr_cfm.memdata >> 24); ++ printk("%x=%x\n", rd_mem_addr_cfm.memaddr, rd_mem_addr_cfm.memdata); ++ if (bond_id & (1 << 1)) { ++ //flash is invalid ++ printk("m2d flash is invalid\n"); ++ return -1; ++ } ++ ++ /* load aic firmware */ ++ size = rwnx_load_firmware(&dst, filename, dev); ++ if (size <= 0) { ++ printk("wrong size of m2d file\n"); ++ vfree(dst); ++ dst = NULL; ++ return -1; ++ } ++ ++ /* Copy the file on the Embedded side */ ++ printk("### Upload m2d %s flash, size=%d\n", filename, size); ++ ++ /*send info first*/ ++ err = aicbsp_priv_rwnx_send_dbg_mem_block_write_req(sdiodev, AIC_M2D_OTA_INFO_ADDR, ++ 4, (u32 *)&size); ++ ++ /*send data first*/ ++ if (size > 1024) { // > 1KB data ++ for (i = 0; i < (size - 1024); ++ i += 1024) { //each time write 1KB ++ err = aicbsp_priv_rwnx_send_dbg_mem_block_write_req( ++ sdiodev, AIC_M2D_OTA_DATA_ADDR, 1024, ++ dst + i / 4); ++ if (err) { ++ printk("m2d upload fail: %x, err:%d\r\n", ++ AIC_M2D_OTA_DATA_ADDR, err); ++ break; ++ } ++ } ++ } ++ ++ if (!err && (i < size)) { // <1KB data ++ err = aicbsp_priv_rwnx_send_dbg_mem_block_write_req( ++ sdiodev, AIC_M2D_OTA_DATA_ADDR, size - i, dst + i / 4); ++ if (err) { ++ printk("m2d upload fail: %x, err:%d\r\n", ++ AIC_M2D_OTA_DATA_ADDR, err); ++ } ++ } ++ ++ if (dst) { ++ vfree(dst); ++ dst = NULL; ++ } ++ aicbsp_priv_testmode = FW_NORMAL_MODE; ++ aicbsp_info.cpmode = aicbsp_priv_testmode; ++ ++ printk("m2d flash update complete\n\n"); ++ ++ return err; ++} ++ ++int rwnx_plat_m2d_flash_ota_check(struct aic_sdio_dev *sdiodev, char *filename) ++{ ++ struct device *dev = sdiodev->dev; ++ unsigned int i = 0, j = 0; ++ int size; ++ u32 *dst = NULL; ++ int err = 0; ++ int ret = 0; ++ u8 bond_id; ++ const u32 mem_addr = 0x40500000; ++ const u32 mem_addr_code_start = AIC_M2D_OTA_CODE_START_ADDR; ++ const u32 mem_addr_sdk_ver = AIC_M2D_OTA_VER_ADDR; ++ const u32 driver_code_start_idx = ++ (AIC_M2D_OTA_CODE_START_ADDR - AIC_M2D_OTA_FLASH_ADDR) / 4; ++ const u32 driver_sdk_ver_idx = ++ (AIC_M2D_OTA_VER_ADDR - AIC_M2D_OTA_FLASH_ADDR) / 4; ++ u32 driver_sdk_ver_addr_idx = 0; ++ u32 code_start_addr = 0xffffffff; ++ u32 sdk_ver_addr = 0xffffffff; ++ u32 drv_code_start_addr = 0xffffffff; ++ u32 drv_sdk_ver_addr = 0xffffffff; ++ struct dbg_mem_read_cfm rd_mem_addr_cfm; ++ char m2d_sdk_ver[64]; ++ char flash_sdk_ver[64]; ++ u32 flash_ver[16]; ++ u32 ota_ver[16]; ++ ++ ret = aicbsp_priv_rwnx_send_dbg_mem_read_req(sdiodev, mem_addr, &rd_mem_addr_cfm); ++ if (ret) { ++ printk("m2d %x rd fail: %d\n", mem_addr, ret); ++ return ret; ++ } ++ bond_id = (u8)(rd_mem_addr_cfm.memdata >> 24); ++ printk("%x=%x\n", rd_mem_addr_cfm.memaddr, rd_mem_addr_cfm.memdata); ++ if (bond_id & (1 << 1)) { ++ //flash is invalid ++ printk("m2d flash is invalid\n"); ++ return -1; ++ } ++ ret = aicbsp_priv_rwnx_send_dbg_mem_read_req(sdiodev, mem_addr_code_start, ++ &rd_mem_addr_cfm); ++ if (ret) { ++ printk("mem_addr_code_start %x rd fail: %d\n", ++ mem_addr_code_start, ret); ++ return ret; ++ } ++ code_start_addr = rd_mem_addr_cfm.memdata; ++ ++#if !defined(CONFIG_M2D_OTA_LZMA_SUPPORT) ++ ret = aicbsp_priv_rwnx_send_dbg_mem_read_req(sdiodev, mem_addr_sdk_ver, ++ &rd_mem_addr_cfm); ++ if (ret) { ++ printk("mem_addr_sdk_ver %x rd fail: %d\n", mem_addr_code_start, ++ ret); ++ return ret; ++ } ++ sdk_ver_addr = rd_mem_addr_cfm.memdata; ++#else ++ sdk_ver_addr = mem_addr_sdk_ver; ++#endif ++ printk("code_start_addr: 0x%x, sdk_ver_addr: 0x%x\n", code_start_addr, ++ sdk_ver_addr); ++ ++ /* load aic firmware */ ++ size = rwnx_load_firmware(&dst, filename, dev); ++ if (size <= 0) { ++ printk("wrong size of m2d file\n"); ++ vfree(dst); ++ dst = NULL; ++ return -1; ++ } ++ if (code_start_addr == 0xffffffff && sdk_ver_addr == 0xffffffff) { ++ printk("########m2d flash old version , must be upgrade\n"); ++ drv_code_start_addr = dst[driver_code_start_idx]; ++ drv_sdk_ver_addr = dst[driver_sdk_ver_idx]; ++ ++ printk("drv_code_start_addr: 0x%x, drv_sdk_ver_addr: 0x%x\n", ++ drv_code_start_addr, drv_sdk_ver_addr); ++ ++ if (drv_sdk_ver_addr == 0xffffffff) { ++ printk("########driver m2d_ota.bin is old ,not need upgrade\n"); ++ return -1; ++ } ++ ++ } else { ++ for (i = 0; i < 16; i++) { ++ ret = aicbsp_priv_rwnx_send_dbg_mem_read_req(sdiodev, ++ (sdk_ver_addr + i * 4), ++ &rd_mem_addr_cfm); ++ if (ret) { ++ printk("mem_addr_sdk_ver %x rd fail: %d\n", ++ mem_addr_code_start, ret); ++ return ret; ++ } ++ flash_ver[i] = rd_mem_addr_cfm.memdata; ++ } ++ memcpy((u8 *)flash_sdk_ver, (u8 *)flash_ver, 64); ++ memcpy((u8 *)saved_sdk_ver, (u8 *)flash_sdk_ver, 64); ++ printk("flash SDK Version: %s\r\n\r\n", flash_sdk_ver); ++ ++ drv_code_start_addr = dst[driver_code_start_idx]; ++ drv_sdk_ver_addr = dst[driver_sdk_ver_idx]; ++ ++ printk("drv_code_start_addr: 0x%x, drv_sdk_ver_addr: 0x%x\n", ++ drv_code_start_addr, drv_sdk_ver_addr); ++ ++ if (drv_sdk_ver_addr == 0xffffffff) { ++ printk("########driver m2d_ota.bin is old ,not need upgrade\n"); ++ return -1; ++ } ++ ++#if !defined(CONFIG_M2D_OTA_LZMA_SUPPORT) ++ driver_sdk_ver_addr_idx = ++ (drv_sdk_ver_addr - drv_code_start_addr) / 4; ++#else ++ driver_sdk_ver_addr_idx = driver_sdk_ver_idx; ++#endif ++ printk("driver_sdk_ver_addr_idx %d\n", driver_sdk_ver_addr_idx); ++ ++ if (driver_sdk_ver_addr_idx) { ++ for (j = 0; j < 16; j++) { ++ ota_ver[j] = dst[driver_sdk_ver_addr_idx + j]; ++ } ++ memcpy((u8 *)m2d_sdk_ver, (u8 *)ota_ver, 64); ++ printk("m2d_ota SDK Version: %s\r\n\r\n", m2d_sdk_ver); ++ } else { ++ return -1; ++ } ++ ++ if (!strcmp(m2d_sdk_ver, flash_sdk_ver)) { ++ printk("######## m2d %s flash is not need upgrade\r\n", ++ filename); ++ return -1; ++ } ++ } ++ ++ /* Copy the file on the Embedded side */ ++ printk("### Upload m2d %s flash, size=%d\n", filename, size); ++ ++ /*send info first*/ ++ err = aicbsp_priv_rwnx_send_dbg_mem_block_write_req(sdiodev, AIC_M2D_OTA_INFO_ADDR, ++ 4, (u32 *)&size); ++ ++ /*send data first*/ ++ if (size > 1024) { // > 1KB data ++ for (i = 0; i < (size - 1024); ++ i += 1024) { //each time write 1KB ++ err = aicbsp_priv_rwnx_send_dbg_mem_block_write_req( ++ sdiodev, AIC_M2D_OTA_DATA_ADDR, 1024, ++ dst + i / 4); ++ if (err) { ++ printk("m2d upload fail: %x, err:%d\r\n", ++ AIC_M2D_OTA_DATA_ADDR, err); ++ break; ++ } ++ } ++ } ++ ++ if (!err && (i < size)) { // <1KB data ++ err = aicbsp_priv_rwnx_send_dbg_mem_block_write_req( ++ sdiodev, AIC_M2D_OTA_DATA_ADDR, size - i, dst + i / 4); ++ if (err) { ++ printk("m2d upload fail: %x, err:%d\r\n", ++ AIC_M2D_OTA_DATA_ADDR, err); ++ } ++ } ++ ++ if (dst) { ++ vfree(dst); ++ dst = NULL; ++ } ++ aicbsp_priv_testmode = FW_NORMAL_MODE; ++ ++ printk("m2d flash update complete\n\n"); ++ ++ return err; ++} ++#endif //CONFIG_M2D_OTA_AUTO_SUPPORT ++ ++int aicwf_patch_table_load(struct aic_sdio_dev *rwnx_hw, char *filename) ++{ ++ struct device *dev = rwnx_hw->dev; ++ int err = 0; ++ unsigned int i = 0, size; ++ u32 *dst = NULL; ++ u8 *describle; ++ u32 fmacfw_patch_tbl_8800dc_u02_describe_size = 124; ++ u32 fmacfw_patch_tbl_8800dc_u02_describe_base; //read from patch_tbl ++ ++ /* Copy the file on the Embedded side */ ++ printk("### Upload %s \n", filename); ++ ++ size = rwnx_load_firmware(&dst, filename, dev); ++ if (!dst) { ++ printk("No such file or directory\n"); ++ return -1; ++ } ++ if (size <= 0) { ++ printk("wrong size of firmware file\n"); ++ dst = NULL; ++ err = -1; ++ } ++ ++ printk("tbl size = %d \n", size); ++ ++ fmacfw_patch_tbl_8800dc_u02_describe_base = dst[0]; ++ AICWFDBG(LOGINFO, "FMACFW_PATCH_TBL_8800DC_U02_DESCRIBE_BASE = %x \n", ++ fmacfw_patch_tbl_8800dc_u02_describe_base); ++ ++ if (!err && (i < size)) { ++ err = aicbsp_priv_rwnx_send_dbg_mem_block_write_req( ++ rwnx_hw, fmacfw_patch_tbl_8800dc_u02_describe_base, ++ fmacfw_patch_tbl_8800dc_u02_describe_size + 4, dst); ++ if (err) { ++ printk("write describe information fail \n"); ++ } ++ ++ describle = kzalloc(fmacfw_patch_tbl_8800dc_u02_describe_size, ++ GFP_KERNEL); ++ memcpy(describle, &dst[1], ++ fmacfw_patch_tbl_8800dc_u02_describe_size); ++ printk("%s", describle); ++ kfree(describle); ++ describle = NULL; ++ } ++ ++ if (!err && (i < size)) { ++ for (i = (128 / 4); i < (size / 4); i += 2) { ++ printk("patch_tbl: %x %x\n", dst[i], dst[i + 1]); ++ err = aicbsp_priv_rwnx_send_dbg_mem_write_req(rwnx_hw, dst[i], ++ dst[i + 1]); ++ } ++ if (err) { ++ printk("bin upload fail: %x, err:%d\r\n", dst[i], err); ++ } ++ } ++ ++ if (dst) { ++#ifndef CONFIG_FIRMWARE_ARRAY ++ vfree(dst); ++#endif ++ dst = NULL; ++ } ++ ++ return err; ++} ++ ++extern char aicbsp_priv_aic_fw_path[200]; ++int aicwf_plat_patch_load_8800dc(struct aic_sdio_dev *sdiodev) ++{ ++ int ret = 0; ++#if !defined(CONFIG_FPGA_VERIFICATION) ++ if (aicbsp_priv_chip_sub_id == 0) { ++ printk("u01 is loaing ###############\n"); ++ ret = rwnx_plat_bin_fw_upload_android( ++ sdiodev, ROM_FMAC_PATCH_ADDR, ++ RWNX_MAC_PATCH_NAME2_8800DC); ++ } else if (aicbsp_priv_chip_sub_id == 1) { ++ printk("u02 is loaing ###############\n"); ++ ret = rwnx_plat_bin_fw_upload_android( ++ sdiodev, ROM_FMAC_PATCH_ADDR, ++ RWNX_MAC_PATCH_NAME2_8800DC_U02); ++ } else if (aicbsp_priv_chip_sub_id == 2) { ++ printk("h_u02 is loaing ###############\n"); ++ ret = rwnx_plat_bin_fw_upload_android( ++ sdiodev, ROM_FMAC_PATCH_ADDR, ++ RWNX_MAC_PATCH_NAME2_8800DC_H_U02); ++ } else { ++ printk("unsupported id: %d\n", aicbsp_priv_chip_sub_id); ++ } ++#endif ++ return ret; ++} ++ ++int aicwf_plat_rftest_load_8800dc(struct aic_sdio_dev *sdiodev) ++{ ++ int ret = 0; ++ ret = rwnx_plat_bin_fw_upload_android(sdiodev, RAM_LMAC_FW_ADDR, ++ RWNX_MAC_FW_RF_BASE_NAME_8800DC); ++ if (ret) { ++ AICWFDBG(LOGINFO, "load rftest bin fail: %d\n", ret); ++ return ret; ++ } ++ return ret; ++} ++ ++#if defined(CONFIG_DPD) || defined(CONFIG_LOFT_CALIB) ++int aicwf_misc_ram_valid_check_8800dc(struct aic_sdio_dev *sdiodev, ++ int *valid_out) ++{ ++ int ret = 0; ++ uint32_t cfg_base = 0x10164; ++ struct dbg_mem_read_cfm cfm; ++ uint32_t misc_ram_addr; ++ uint32_t ram_base_addr, ram_word_cnt; ++ uint32_t bit_mask[4]; ++ int i; ++ if (valid_out) { ++ *valid_out = 0; ++ } ++ if (aicbsp_priv_testmode == FW_RFTEST_MODE) { ++ uint32_t vect1 = 0; ++ uint32_t vect2 = 0; ++ cfg_base = RAM_LMAC_FW_ADDR + 0x0004; ++ ret = aicbsp_priv_rwnx_send_dbg_mem_read_req(sdiodev, cfg_base, &cfm); ++ if (ret) { ++ AICWFDBG(LOGERROR, "cfg_base:%x vcet1 rd fail: %d\n", ++ cfg_base, ret); ++ return ret; ++ } ++ vect1 = cfm.memdata; ++ if ((vect1 & 0xFFFF0000) != (RAM_LMAC_FW_ADDR & 0xFFFF0000)) { ++ AICWFDBG(LOGERROR, "vect1 invalid: %x\n", vect1); ++ return ret; ++ } ++ cfg_base = RAM_LMAC_FW_ADDR + 0x0008; ++ ret = aicbsp_priv_rwnx_send_dbg_mem_read_req(sdiodev, cfg_base, &cfm); ++ if (ret) { ++ AICWFDBG(LOGERROR, "cfg_base:%x vcet2 rd fail: %d\n", ++ cfg_base, ret); ++ return ret; ++ } ++ vect2 = cfm.memdata; ++ if ((vect2 & 0xFFFF0000) != (RAM_LMAC_FW_ADDR & 0xFFFF0000)) { ++ AICWFDBG(LOGERROR, "vect2 invalid: %x\n", vect2); ++ return ret; ++ } ++ ++ cfg_base = RAM_LMAC_FW_ADDR + 0x0164; ++ } ++ // init misc ram ++ ret = aicbsp_priv_rwnx_send_dbg_mem_read_req(sdiodev, cfg_base + 0x14, &cfm); ++ if (ret) { ++ AICWFDBG(LOGERROR, "rf misc ram[0x%x] rd fail: %d\n", ++ cfg_base + 0x14, ret); ++ return ret; ++ } ++ misc_ram_addr = cfm.memdata; ++ AICWFDBG(LOGERROR, "misc_ram_addr=%x\n", misc_ram_addr); ++ // bit_mask ++ ram_base_addr = misc_ram_addr + offsetof(rf_misc_ram_t, bit_mask); ++ ram_word_cnt = (MEMBER_SIZE(rf_misc_ram_t, bit_mask) + ++ MEMBER_SIZE(rf_misc_ram_t, reserved)) / ++ 4; ++ for (i = 0; i < ram_word_cnt; i++) { ++ ret = aicbsp_priv_rwnx_send_dbg_mem_read_req(sdiodev, ram_base_addr + i * 4, ++ &cfm); ++ if (ret) { ++ AICWFDBG(LOGERROR, "bit_mask[0x%x] rd fail: %d\n", ++ ram_base_addr + i * 4, ret); ++ return ret; ++ } ++ bit_mask[i] = cfm.memdata; ++ } ++ AICWFDBG(LOGTRACE, "bit_mask:%x,%x,%x,%x\n", bit_mask[0], bit_mask[1], ++ bit_mask[2], bit_mask[3]); ++ if ((bit_mask[0] == 0) && ((bit_mask[1] & 0xFFF00000) == 0x80000000) && ++ (bit_mask[2] == 0) && ((bit_mask[3] & 0xFFFFFF00) == 0x00000000)) { ++ if (valid_out) { ++ *valid_out = 1; ++ } ++ } ++ return ret; ++} ++ ++int aicwf_plat_calib_load_8800dc(struct aic_sdio_dev *sdiodev) ++{ ++ int ret = 0; ++ if (aicbsp_priv_chip_sub_id == 1) { ++ ret = rwnx_plat_bin_fw_upload_android( ++ sdiodev, ROM_FMAC_CALIB_ADDR, ++ RWNX_MAC_CALIB_NAME_8800DC_U02); ++ if (ret) { ++ AICWFDBG(LOGINFO, "load calib bin fail: %d\n", ret); ++ return ret; ++ } ++ } else if (aicbsp_priv_chip_sub_id == 2) { ++ ret = rwnx_plat_bin_fw_upload_android( ++ sdiodev, ROM_FMAC_CALIB_ADDR, ++ RWNX_MAC_CALIB_NAME_8800DC_H_U02); ++ if (ret) { ++ AICWFDBG(LOGINFO, "load calib bin fail: %d\n", ret); ++ return ret; ++ } ++ } ++ return ret; ++} ++#endif ++ ++#ifdef CONFIG_DPD ++#ifndef CONFIG_FORCE_DPD_CALIB ++int is_file_exist(char *name) ++{ ++ char *path = NULL; ++ struct file *fp = NULL; ++ int len; ++ ++ path = __getname(); ++ if (!path) { ++ AICWFDBG(LOGINFO, "%s getname fail\n", __func__); ++ return -1; ++ } ++ ++ len = snprintf(path, FW_PATH_MAX_LEN, "%s/%s", AICBSP_FW_PATH, name); ++ ++ fp = filp_open(path, O_RDONLY, 0); ++ if (IS_ERR(fp)) { ++ __putname(path); ++ fp = NULL; ++ return 0; ++ } else { ++ __putname(path); ++ filp_close(fp, NULL); ++ fp = NULL; ++ return 1; ++ } ++} ++ ++EXPORT_SYMBOL(is_file_exist); ++#endif ++#endif ++ ++#ifdef CONFIG_DPD ++rf_misc_ram_lite_t dpd_res = { ++ { 0 }, ++}; ++EXPORT_SYMBOL(dpd_res); ++#endif ++ ++#ifdef CONFIG_LOFT_CALIB ++rf_misc_ram_lite_t loft_res_local = { ++ { 0 }, ++}; ++EXPORT_SYMBOL(loft_res_local); ++#endif ++ ++static int rwnx_plat_patch_load(struct aic_sdio_dev *sdiodev) ++{ ++ int ret = 0; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ if (sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ AICWFDBG(LOGINFO, "aicbsp_priv_testmode=%d\n", aicbsp_priv_testmode); ++ if (aicbsp_priv_chip_sub_id == 0) { ++ if (aicbsp_priv_testmode == FW_NORMAL_MODE) { ++ AICWFDBG(LOGINFO, "rwnx_plat_patch_loading\n"); ++ ret = aicwf_plat_patch_load_8800dc(sdiodev); ++ if (ret) { ++ AICWFDBG(LOGINFO, ++ "load patch bin fail: %d\n", ++ ret); ++ return ret; ++ } ++ } else if (aicbsp_priv_testmode == FW_RFTEST_MODE) { ++ ret = aicwf_plat_rftest_load_8800dc(sdiodev); ++ if (ret) { ++ AICWFDBG(LOGINFO, ++ "load rftest bin fail: %d\n", ++ ret); ++ return ret; ++ } ++ } ++ } else if (aicbsp_priv_chip_sub_id >= 1) { ++ if (aicbsp_priv_testmode == FW_NORMAL_MODE) { ++ AICWFDBG(LOGINFO, "rwnx_plat_patch_loading\n"); ++ ret = aicwf_plat_patch_load_8800dc(sdiodev); ++ if (ret) { ++ AICWFDBG(LOGINFO, ++ "load patch bin fail: %d\n", ++ ret); ++ return ret; ++ } ++#ifdef CONFIG_DPD ++#ifdef CONFIG_FORCE_DPD_CALIB ++ if (1) { ++ AICWFDBG(LOGINFO, ++ "dpd calib & write\n"); ++ ret = aicwf_dpd_calib_8800dc(sdiodev, ++ &dpd_res); ++ if (ret) { ++ AICWFDBG(LOGINFO, ++ "dpd calib fail: %d\n", ++ ret); ++ return ret; ++ } ++ } ++#else ++ if (is_file_exist(FW_DPDRESULT_NAME_8800DC) == ++ 1) { ++ AICWFDBG(LOGINFO, "dpd bin load\n"); ++ ret = aicwf_dpd_result_load_8800dc( ++ sdiodev, &dpd_res); ++ if (ret) { ++ AICWFDBG( ++ LOGINFO, ++ "load dpd bin fail: %d\n", ++ ret); ++ return ret; ++ } ++ ret = aicwf_dpd_result_apply_8800dc( ++ sdiodev, &dpd_res); ++ if (ret) { ++ AICWFDBG( ++ LOGINFO, ++ "apply dpd bin fail: %d\n", ++ ret); ++ return ret; ++ } ++ } ++#endif ++ else ++#elif defined(CONFIG_LOFT_CALIB) ++ if (1) { ++ AICWFDBG(LOGINFO, "loft calib\n"); ++ ret = aicwf_loft_calib_8800dc( ++ sdiodev, &loft_res_local); ++ if (ret) { ++ AICWFDBG( ++ LOGINFO, ++ "loft calib fail: %d\n", ++ ret); ++ return ret; ++ } ++ } else ++#endif ++ { ++ ret = aicwf_misc_ram_init_8800dc( ++ sdiodev); ++ if (ret) { ++ AICWFDBG( ++ LOGINFO, ++ "misc ram init fail: %d\n", ++ ret); ++ return ret; ++ } ++ } ++ } else if (aicbsp_priv_testmode == FW_RFTEST_MODE) { ++#ifdef CONFIG_DPD ++#ifdef CONFIG_FORCE_DPD_CALIB ++ if (1) { ++ AICWFDBG(LOGINFO, "patch load\n"); ++ ret = aicwf_plat_patch_load_8800dc( ++ sdiodev); ++ if (ret) { ++ AICWFDBG( ++ LOGINFO, ++ "load patch bin fail: %d\n", ++ ret); ++ return ret; ++ } ++ AICWFDBG(LOGINFO, ++ "dpd calib & write\n"); ++ ret = aicwf_dpd_calib_8800dc(sdiodev, ++ &dpd_res); ++ if (ret) { ++ AICWFDBG(LOGINFO, ++ "dpd calib fail: %d\n", ++ ret); ++ return ret; ++ } ++ } ++#endif /*CONFIG_FORCE_DPD_CALIB*/ ++#elif defined(CONFIG_LOFT_CALIB) ++ { ++ AICWFDBG(LOGINFO, "patch load\n"); ++ ret = aicwf_plat_patch_load_8800dc( ++ sdiodev); ++ if (ret) { ++ AICWFDBG( ++ LOGINFO, ++ "load patch bin fail: %d\n", ++ ret); ++ return ret; ++ } ++ AICWFDBG(LOGINFO, "loft calib\n"); ++ ret = aicwf_loft_calib_8800dc( ++ sdiodev, &loft_res_local); ++ if (ret) { ++ AICWFDBG( ++ LOGINFO, ++ "loft calib fail: %d\n", ++ ret); ++ return ret; ++ } ++ } ++#endif /*CONFIG_DPD*/ ++ ret = aicwf_plat_rftest_load_8800dc(sdiodev); ++ if (ret) { ++ AICWFDBG(LOGINFO, ++ "load rftest bin fail: %d\n", ++ ret); ++ return ret; ++ } ++ } else if (aicbsp_priv_testmode == FW_DPDCALIB_MODE) { ++#if (defined(CONFIG_DPD) && !defined(CONFIG_FORCE_DPD_CALIB)) ++ if (is_file_exist(FW_DPDRESULT_NAME_8800DC) == ++ 0) { ++ AICWFDBG(LOGINFO, "patch load\n"); ++ ret = aicwf_plat_patch_load_8800dc( ++ sdiodev); ++ if (ret) { ++ AICWFDBG( ++ LOGINFO, ++ "load patch bin fail: %d\n", ++ ret); ++ return ret; ++ } ++ AICWFDBG(LOGINFO, ++ "dpd calib & write\n"); ++ ret = aicwf_dpd_calib_8800dc(sdiodev, ++ &dpd_res); ++ if (ret) { ++ AICWFDBG(LOGINFO, ++ "dpd calib fail: %d\n", ++ ret); ++ return ret; ++ } ++ ret = aicwf_dpd_result_write_8800dc( ++ (void *)&dpd_res, ++ DPD_RESULT_SIZE_8800DC); ++ if (ret) { ++ AICWFDBG( ++ LOGINFO, ++ "file write fail: %d\n", ++ ret); ++ return ret; ++ } ++ } ++#endif ++ return 1; // exit calib mode ++ } ++ } ++ } ++ ++ return ret; ++} ++ ++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; ++ ++ printk("%s\n", __func__); ++ ++ /* load aic firmware */ ++ size = rwnx_load_firmware(&dst, filename, dev); ++ if (size <= 0) { ++ printk("wrong size of firmware file\n"); ++#ifndef CONFIG_FIRMWARE_ARRAY ++ vfree(dst); ++#endif ++ dst = NULL; ++ return -1; ++ } ++ ++ /* Copy the file on the Embedded side */ ++ if (size > 1024) { // > 1KB data ++ for (i = 0; i < (size - 1024); ++ i += 1024) { //each time write 1KB ++ err = aicbsp_priv_rwnx_send_dbg_mem_block_write_req( ++ sdiodev, fw_addr + i, 1024, dst + i / 4); ++ if (err) { ++ printk("bin upload fail: %x, err:%d\r\n", ++ fw_addr + i, err); ++ break; ++ } ++ } ++ } ++ ++ if (!err && (i < size)) { // <1KB data ++ err = aicbsp_priv_rwnx_send_dbg_mem_block_write_req(sdiodev, fw_addr + i, ++ size - i, dst + i / 4); ++ if (err) { ++ printk("bin upload fail: %x, err:%d\r\n", fw_addr + i, ++ err); ++ } ++ } ++ ++ if (dst) { ++#ifndef CONFIG_FIRMWARE_ARRAY ++ vfree(dst); ++#endif ++ dst = NULL; ++ } ++ ++ return err; ++} ++ ++int aicbt_patch_table_free(struct aicbt_patch_table **head) ++{ ++ struct aicbt_patch_table *p = *head, *n = NULL; ++ while (p) { ++ n = p->next; ++ vfree(p->name); ++ vfree(p->data); ++ vfree(p); ++ p = n; ++ } ++ *head = NULL; ++ return 0; ++} ++ ++struct aicbt_patch_table *aicbt_patch_table_alloc(const char *filename) ++{ ++ uint8_t *rawdata = NULL, *p; ++ int size; ++ struct aicbt_patch_table *head = NULL, *new = NULL, *cur = NULL; ++ ++ /* load aic firmware */ ++ size = rwnx_load_firmware((u32 **)&rawdata, filename, NULL); ++ if (size <= 0) { ++ printk("wrong size of firmware file\n"); ++ goto err; ++ } ++ ++ p = rawdata; ++ if (memcmp(p, AICBT_PT_TAG, ++ sizeof(AICBT_PT_TAG) < 16 ? sizeof(AICBT_PT_TAG) : 16)) { ++ printk("TAG err\n"); ++ goto err; ++ } ++ p += 16; ++ ++ while (p - rawdata < size) { ++ new = (struct aicbt_patch_table *)vmalloc( ++ sizeof(struct aicbt_patch_table)); ++ memset(new, 0, sizeof(struct aicbt_patch_table)); ++ if (head == NULL) { ++ head = new; ++ cur = new; ++ } else { ++ cur->next = new; ++ cur = cur->next; ++ } ++ ++ cur->name = (char *)vmalloc(sizeof(char) * 16); ++ memset(cur->name, 0, sizeof(char) * 16); ++ memcpy(cur->name, p, 16); ++ p += 16; ++ ++ cur->type = *(uint32_t *)p; ++ p += 4; ++ ++ cur->len = *(uint32_t *)p; ++ p += 4; ++ ++ if ((cur->type) >= 1000) { //Temp Workaround ++ cur->len = 0; ++ } else { ++ if (cur->len > 0) { ++ cur->data = (uint32_t *)vmalloc( ++ sizeof(uint8_t) * cur->len * 8); ++ memset(cur->data, 0, ++ sizeof(uint8_t) * cur->len * 8); ++ memcpy(cur->data, p, cur->len * 8); ++ p += cur->len * 8; ++ } ++ } ++ } ++#ifndef CONFIG_FIRMWARE_ARRAY ++ vfree(rawdata); ++#endif ++ return head; ++ ++err: ++ aicbt_patch_table_free(&head); ++ if (rawdata) ++ vfree(rawdata); ++ return NULL; ++} ++int aicbt_patch_info_unpack(struct aicbt_patch_info_t *patch_info, ++ struct aicbt_patch_table *head_t) ++{ ++ uint8_t *patch_info_array = (uint8_t *)patch_info; ++ int base_len = 0; ++ int memcpy_len = 0; ++ ++ if (AICBT_PT_INF == head_t->type) { ++ base_len = ++ ((offsetof(struct aicbt_patch_info_t, ++ ext_patch_nb_addr) - ++ offsetof(struct aicbt_patch_info_t, adid_addrinf)) / ++ sizeof(uint32_t)) / ++ 2; ++ AICWFDBG(LOGDEBUG, "%s head_t->len:%d base_len:%d \r\n", ++ __func__, head_t->len, base_len); ++ ++ if (head_t->len > base_len) { ++ patch_info->info_len = base_len; ++ memcpy_len = ++ patch_info->info_len + 1; //include ext patch nb ++ } else { ++ patch_info->info_len = head_t->len; ++ memcpy_len = patch_info->info_len; ++ } ++ AICWFDBG(LOGDEBUG, "%s memcpy_len:%d \r\n", __func__, ++ memcpy_len); ++ ++ if (patch_info->info_len == 0) ++ return 0; ++ ++ memcpy(((patch_info_array) + sizeof(patch_info->info_len)), ++ head_t->data, memcpy_len * sizeof(uint32_t) * 2); ++ AICWFDBG(LOGDEBUG, "%s adid_addrinf:%x addr_adid:%x \r\n", ++ __func__, ++ ((struct aicbt_patch_info_t *)patch_info_array) ++ ->adid_addrinf, ++ ((struct aicbt_patch_info_t *)patch_info_array) ++ ->addr_adid); ++ ++ if (patch_info->ext_patch_nb > 0) { ++ int index = 0; ++ patch_info->ext_patch_param = ++ (uint32_t *)(head_t->data + ((memcpy_len)*2)); ++ ++ for (index = 0; index < patch_info->ext_patch_nb; ++ index++) { ++ AICWFDBG(LOGDEBUG, "%s id:%x addr:%x \r\n", ++ __func__, ++ *(patch_info->ext_patch_param + ++ (index * 2)), ++ *(patch_info->ext_patch_param + ++ (index * 2) + 1)); ++ } ++ } ++ } ++ return 0; ++} ++ ++int aicbt_ext_patch_data_load(struct aic_sdio_dev *sdiodev, ++ struct aicbt_patch_info_t *patch_info) ++{ ++ int ret = 0; ++ uint32_t ext_patch_nb = patch_info->ext_patch_nb; ++ char ext_patch_file_name[50]; ++ int index = 0; ++ uint32_t id = 0; ++ uint32_t addr = 0; ++ ++ if (ext_patch_nb > 0) { ++ if (sdiodev->chipid == PRODUCT_ID_AIC8800DC) { ++ AICWFDBG(LOGDEBUG, "[0x40506004]: 0x04318000\n"); ++ ret = aicbsp_priv_rwnx_send_dbg_mem_write_req(sdiodev, 0x40506004, ++ 0x04318000); ++ AICWFDBG(LOGDEBUG, "[0x40506004]: 0x04338000\n"); ++ ret = aicbsp_priv_rwnx_send_dbg_mem_write_req(sdiodev, 0x40506004, ++ 0x04338000); ++ } ++ for (index = 0; index < patch_info->ext_patch_nb; index++) { ++ id = *(patch_info->ext_patch_param + (index * 2)); ++ addr = *(patch_info->ext_patch_param + (index * 2) + 1); ++ memset(ext_patch_file_name, 0, ++ sizeof(ext_patch_file_name)); ++ sprintf(ext_patch_file_name, "%s%d.bin", ++ aicbsp_firmware_list[aicbsp_info.cpmode] ++ .bt_ext_patch, ++ id); ++ AICWFDBG( ++ LOGDEBUG, ++ "%s ext_patch_file_name:%s ext_patch_id:%x ext_patch_addr:%x \r\n", ++ __func__, ext_patch_file_name, id, addr); ++ ++ if (rwnx_plat_bin_fw_upload_android( ++ sdiodev, addr, ext_patch_file_name)) { ++ ret = -1; ++ break; ++ } ++ } ++ } ++ return ret; ++} ++ ++int aicbt_patch_trap_data_load(struct aic_sdio_dev *sdiodev, ++ struct aicbt_patch_table *head) ++{ ++ struct aicbt_patch_info_t patch_info = { ++ .info_len = 0, ++ .adid_addrinf = 0, ++ .addr_adid = 0, ++ .patch_addrinf = 0, ++ .addr_patch = 0, ++ .reset_addr = 0, ++ .reset_val = 0, ++ .adid_flag_addr = 0, ++ .adid_flag = 0, ++ .ext_patch_nb_addr = 0, ++ .ext_patch_nb = 0, ++ }; ++ if (head == NULL) { ++ return -1; ++ } ++ ++ if (sdiodev->chipid == PRODUCT_ID_AIC8801) { ++ patch_info.addr_adid = FW_RAM_ADID_BASE_ADDR; ++ patch_info.addr_patch = FW_RAM_PATCH_BASE_ADDR; ++ } else if (sdiodev->chipid == PRODUCT_ID_AIC8800DC) { ++ if (aicbsp_info.chip_rev == CHIP_REV_U01) { ++ patch_info.addr_adid = RAM_8800DC_U01_ADID_ADDR; ++ } else if (aicbsp_info.chip_rev == CHIP_REV_U02) { ++ patch_info.addr_adid = RAM_8800DC_U02_ADID_ADDR; ++ } ++ patch_info.addr_patch = RAM_8800DC_FW_PATCH_ADDR; ++ aicbt_patch_info_unpack(&patch_info, head); ++ if (patch_info.reset_addr == 0) { ++ patch_info.reset_addr = FW_RESET_START_ADDR; ++ patch_info.reset_val = FW_RESET_START_VAL; ++ patch_info.adid_flag_addr = FW_ADID_FLAG_ADDR; ++ patch_info.adid_flag = FW_ADID_FLAG_VAL; ++ if (aicbsp_priv_rwnx_send_dbg_mem_write_req(sdiodev, ++ patch_info.reset_addr, ++ patch_info.reset_val)) ++ return -1; ++ if (aicbsp_priv_rwnx_send_dbg_mem_write_req( ++ sdiodev, patch_info.adid_flag_addr, ++ patch_info.adid_flag)) ++ return -1; ++ } ++ } else if (sdiodev->chipid == PRODUCT_ID_AIC8800D80) { ++ if (aicbsp_info.chip_rev == CHIP_REV_U01) { ++ patch_info.addr_adid = FW_RAM_ADID_BASE_ADDR_8800D80; ++ patch_info.addr_patch = FW_RAM_PATCH_BASE_ADDR_8800D80; ++ } else if (aicbsp_info.chip_rev == CHIP_REV_U02 || ++ aicbsp_info.chip_rev == CHIP_REV_U03) { ++ patch_info.addr_adid = ++ FW_RAM_ADID_BASE_ADDR_8800D80_U02; ++ patch_info.addr_patch = ++ FW_RAM_PATCH_BASE_ADDR_8800D80_U02; ++ } ++ aicbt_patch_info_unpack(&patch_info, head); ++ if (patch_info.info_len == 0) { ++ printk("%s, aicbt_patch_info_unpack fail\n", __func__); ++ return -1; ++ } ++ } else if (sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ aicbt_patch_info_unpack(&patch_info, head); ++ if (patch_info.info_len == 0) { ++ printk("%s, aicbt_patch_info_unpack fail\n", __func__); ++ return -1; ++ } ++ } ++ ++ if (rwnx_plat_bin_fw_upload_android( ++ sdiodev, patch_info.addr_adid, ++ aicbsp_firmware_list[aicbsp_info.cpmode].bt_adid)) ++ return -1; ++ if (rwnx_plat_bin_fw_upload_android( ++ sdiodev, patch_info.addr_patch, ++ aicbsp_firmware_list[aicbsp_info.cpmode].bt_patch)) ++ return -1; ++ if (aicbt_ext_patch_data_load(sdiodev, &patch_info)) ++ 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, ++ }, //PRODUCT_ID_AIC8801 ++ { ++ .btmode = AICBT_BTMODE_BT_WIFI_COMBO, ++ .btport = AICBT_BTPORT_DEFAULT, ++ .uart_baud = AICBT_UART_BAUD_DEFAULT, ++ .uart_flowctrl = AICBT_UART_FC_DEFAULT, ++ .lpm_enable = AICBT_LPM_ENABLE_DEFAULT, ++ .txpwr_lvl = AICBT_TXPWR_LVL_DEFAULT_8800dc, ++ }, //PRODUCT_ID_AIC8800DC ++ { ++ .btmode = AICBT_BTMODE_BT_WIFI_COMBO, ++ .btport = AICBT_BTPORT_DEFAULT, ++ .uart_baud = AICBT_UART_BAUD_DEFAULT, ++ .uart_flowctrl = AICBT_UART_FC_DEFAULT, ++ .lpm_enable = AICBT_LPM_ENABLE_DEFAULT, ++ .txpwr_lvl = AICBT_TXPWR_LVL_DEFAULT_8800dc, ++ }, //PRODUCT_ID_AIC8800DW ++ { ++ .btmode = AICBT_BTMODE_DEFAULT_8800d80, ++ .btport = AICBT_BTPORT_DEFAULT, ++ .uart_baud = AICBT_UART_BAUD_DEFAULT, ++ .uart_flowctrl = AICBT_UART_FC_DEFAULT, ++ .lpm_enable = AICBT_LPM_ENABLE_DEFAULT, ++ .txpwr_lvl = AICBT_TXPWR_LVL_DEFAULT_8800d80, ++ }, //PRODUCT_ID_AIC8800D80 ++ { ++ .btmode = AICBT_BTMODE_DEFAULT_8800d80x2, ++ .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_8800d80x2, ++ } //PRODUCT_ID_AIC8800D80x2 ++ ++}; ++ ++int aicbt_patch_table_load(struct aic_sdio_dev *sdiodev, ++ struct aicbt_patch_table *head) ++{ ++ struct aicbt_patch_table *p; ++ int ret = 0, i; ++ uint32_t *data = NULL; ++ if (head == NULL) { ++ return -1; ++ } ++ ++ for (p = head; p != NULL; p = p->next) { ++ data = p->data; ++ if (AICBT_PT_BTMODE == p->type) { ++ *(data + 1) = aicbsp_info.hwinfo < 0; ++ *(data + 3) = aicbsp_info.hwinfo; ++ *(data + 5) = (sdiodev->chipid == PRODUCT_ID_AIC8800DC ? ++ aicbsp_info.cpmode : ++ 0); //0;//aicbsp_info.cpmode; ++ ++ *(data + 7) = aicbt_info[sdiodev->chipid].btmode; ++ *(data + 9) = aicbt_info[sdiodev->chipid].btport; ++ *(data + 11) = aicbt_info[sdiodev->chipid].uart_baud; ++ *(data + 13) = ++ aicbt_info[sdiodev->chipid].uart_flowctrl; ++ *(data + 15) = aicbt_info[sdiodev->chipid].lpm_enable; ++ *(data + 17) = aicbt_info[sdiodev->chipid].txpwr_lvl; ++ ++ printk("%s bt btmode[%d]:%d \r\n", __func__, ++ sdiodev->chipid, ++ aicbt_info[sdiodev->chipid].btmode); ++ printk("%s bt uart_baud[%d]:%d \r\n", __func__, ++ sdiodev->chipid, ++ aicbt_info[sdiodev->chipid].uart_baud); ++ printk("%s bt uart_flowctrl[%d]:%d \r\n", __func__, ++ sdiodev->chipid, ++ aicbt_info[sdiodev->chipid].uart_flowctrl); ++ printk("%s bt lpm_enable[%d]:%d \r\n", __func__, ++ sdiodev->chipid, ++ aicbt_info[sdiodev->chipid].lpm_enable); ++ printk("%s bt tx_pwr[%d]:%d \r\n", __func__, ++ sdiodev->chipid, ++ aicbt_info[sdiodev->chipid].txpwr_lvl); ++ } ++ ++ if (AICBT_PT_VER == p->type) { ++ printk("aicbsp: bt patch version: %s\n", ++ (char *)p->data); ++ continue; ++ } ++ ++ for (i = 0; i < p->len; i++) { ++ ret = aicbsp_priv_rwnx_send_dbg_mem_write_req(sdiodev, *data, ++ *(data + 1)); ++ if (ret != 0) ++ return ret; ++ data += 2; ++ } ++ if (p->type == AICBT_PT_PWRON) ++ udelay(500); ++ } ++ ++ ///aicbt_patch_table_free(&head); ++ return 0; ++} ++ ++int aicbt_init(struct aic_sdio_dev *sdiodev) ++{ ++ int ret = 0; ++ struct aicbt_patch_table *head = aicbt_patch_table_alloc( ++ aicbsp_firmware_list[aicbsp_info.cpmode].bt_table); ++ if (head == NULL) { ++ printk("aicbt_patch_table_alloc fail\n"); ++ return -1; ++ } ++ ++ if (aicbt_patch_trap_data_load(sdiodev, head)) { ++ printk("aicbt_patch_trap_data_load fail\n"); ++ ret = -1; ++ goto err; ++ } ++ ++ if (aicbt_patch_table_load(sdiodev, head)) { ++ printk("aicbt_patch_table_load fail\n"); ++ ret = -1; ++ goto err; ++ } ++ ++err: ++ aicbt_patch_table_free(&head); ++ return ret; ++} ++ ++static int aicwifi_start_from_bootrom(struct aic_sdio_dev *sdiodev) ++{ ++ int ret = 0; ++ ++ /* memory access */ ++ const u32 fw_addr = RAM_FMAC_FW_ADDR; ++ struct dbg_start_app_cfm start_app_cfm; ++ ++ /* fw start */ ++ ret = aicbsp_priv_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; ++} ++ ++static int start_from_bootrom_8800DC(struct aic_sdio_dev *sdiodev) ++{ ++ int ret = 0; ++ u32 rd_addr; ++ u32 fw_addr; ++ u32 boot_type; ++ struct dbg_mem_read_cfm rd_cfm; ++ ++ /* memory access */ ++ if (aicbsp_priv_testmode == 1) { ++ rd_addr = RAM_LMAC_FW_ADDR; ++ fw_addr = RAM_LMAC_FW_ADDR; ++ } else { ++ rd_addr = RAM_FMAC_FW_ADDR; ++ fw_addr = RAM_FMAC_FW_ADDR; ++ } ++ ++ AICWFDBG(LOGINFO, "Read FW mem: %08x\n", rd_addr); ++ if ((ret = aicbsp_priv_rwnx_send_dbg_mem_read_req(sdiodev, rd_addr, &rd_cfm))) { ++ return -1; ++ } ++ AICWFDBG(LOGINFO, "cfm: [%08x] = %08x\n", rd_cfm.memaddr, ++ rd_cfm.memdata); ++ ++ if (aicbsp_priv_testmode == 0) { ++ boot_type = HOST_START_APP_DUMMY; ++ } else { ++ boot_type = HOST_START_APP_AUTO; ++ } ++ /* fw start */ ++ AICWFDBG(LOGINFO, "Start app: %08x, %d\n", fw_addr, boot_type); ++ if ((ret = aicbsp_priv_rwnx_send_dbg_start_app_req(sdiodev, fw_addr, boot_type, ++ NULL))) { ++ return -1; ++ } ++ return 0; ++} ++ ++u32 adaptivity_patch_tbl[][2] = { ++ { 0x0004, 0x0000320A }, //linkloss_thd ++ { 0x0094, 0x00000000 }, //ac_param_conf ++ { 0x00F8, 0x00010138 }, //tx_adaptivity_en ++}; ++ ++u32 patch_tbl[][2] = { ++#if !defined(CONFIG_LINK_DET_5G) ++ { 0x0104, 0x00000000 }, //link_det_5g ++#endif ++#if defined(CONFIG_MCU_MESSAGE) ++ { 0x004c, 0x0000004B }, //pkt_cnt_1724=0x4B ++ { 0x0050, 0x0011FC00 }, //ipc_base_addr ++#endif ++}; ++ ++u32 syscfg_tbl_masked[][3] = { ++ { 0x40506024, 0x000000FF, 0x000000DF }, // for clk gate lp_level ++}; ++ ++u32 rf_tbl_masked[][3] = { ++ { 0x40344058, 0x00800000, 0x00000000 }, // pll trx ++}; ++ ++static int aicwifi_sys_config(struct aic_sdio_dev *sdiodev) ++{ ++ int ret, cnt; ++ int syscfg_num = sizeof(syscfg_tbl_masked) / sizeof(u32) / 3; ++ for (cnt = 0; cnt < syscfg_num; cnt++) { ++ ret = aicbsp_priv_rwnx_send_dbg_mem_mask_write_req( ++ sdiodev, 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; ++ } ++ } ++ ++ ret = aicbsp_priv_rwnx_send_dbg_mem_mask_write_req(sdiodev, 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 int aicwifi_patch_config(struct aic_sdio_dev *sdiodev) ++{ ++ const u32 rd_patch_addr = RAM_FMAC_FW_ADDR + 0x0180; ++ u32 config_base; ++ uint32_t start_addr = 0x1e6000; ++ u32 patch_addr = start_addr; ++ u32 patch_num = sizeof(patch_tbl) / 4; ++ struct dbg_mem_read_cfm rd_patch_addr_cfm; ++ u32 patch_addr_reg = 0x1e5318; ++ u32 patch_num_reg = 0x1e531c; ++ int ret = 0; ++ u16 cnt = 0; ++ int tmp_cnt = 0; ++ int adap_patch_num = 0; ++ ++ if (aicbsp_info.cpmode == AICBSP_CPMODE_TEST) { ++ patch_addr_reg = 0x1e5304; ++ patch_num_reg = 0x1e5308; ++ } ++ ++ ret = aicbsp_priv_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 = aicbsp_priv_rwnx_send_dbg_mem_write_req(sdiodev, patch_addr_reg, patch_addr); ++ if (ret) { ++ printk("0x%x write fail\n", patch_addr_reg); ++ return ret; ++ } ++ ++ if (adap_test) { ++ printk("%s for adaptivity test \r\n", __func__); ++ adap_patch_num = sizeof(adaptivity_patch_tbl) / 4; ++ ret = aicbsp_priv_rwnx_send_dbg_mem_write_req(sdiodev, patch_num_reg, ++ patch_num + adap_patch_num); ++ } else { ++ ret = aicbsp_priv_rwnx_send_dbg_mem_write_req(sdiodev, patch_num_reg, ++ patch_num); ++ } ++ if (ret) { ++ printk("0x%x write fail\n", patch_num_reg); ++ return ret; ++ } ++ ++ for (cnt = 0; cnt < patch_num / 2; cnt += 1) { ++ ret = aicbsp_priv_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 = aicbsp_priv_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; ++ } ++ } ++ ++ tmp_cnt = cnt; ++ ++ if (adap_test) { ++ for (cnt = 0; cnt < adap_patch_num / 2; cnt += 1) { ++ if ((ret = aicbsp_priv_rwnx_send_dbg_mem_write_req( ++ sdiodev, start_addr + 8 * (cnt + tmp_cnt), ++ adaptivity_patch_tbl[cnt][0] + ++ config_base))) { ++ printk("%x write fail\n", start_addr + 8 * cnt); ++ } ++ ++ if ((ret = aicbsp_priv_rwnx_send_dbg_mem_write_req( ++ sdiodev, ++ start_addr + 8 * (cnt + tmp_cnt) + 4, ++ adaptivity_patch_tbl[cnt][1]))) { ++ printk("%x write fail\n", ++ start_addr + 8 * cnt + 4); ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++int aicwifi_init(struct aic_sdio_dev *sdiodev) ++{ ++ int ret = 0; ++ if (sdiodev->chipid == PRODUCT_ID_AIC8801) { ++#ifdef CONFIG_M2D_OTA_AUTO_SUPPORT ++ if (aicbsp_priv_testmode == FW_M2D_OTA_MODE) { ++ rwnx_plat_m2d_flash_ota_android(sdiodev, ++ FW_M2D_OTA_NAME); ++ } else if (aicbsp_priv_testmode == FW_NORMAL_MODE) { ++ rwnx_plat_m2d_flash_ota_check(sdiodev, FW_M2D_OTA_NAME); ++ } ++#endif ++ 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 -1; ++ } ++ if (aicbsp_priv_testmode == FW_NORMAL_MODE) { ++ if (rwnx_plat_bin_fw_upload_android( ++ sdiodev, RAM_FMAC_FW_PATCH_ADDR, ++ RAM_FMAC_FW_PATCH_NAME)) { ++ printk("download wifi fw patch fail\n"); ++ return -1; ++ } ++ } ++ ++ if (aicwifi_patch_config(sdiodev)) { ++ printk("aicwifi_patch_config fail\n"); ++ return -1; ++ } ++ ++ 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; ++ } ++ } else if (sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ printk("############ aicwifi_init begin \n"); ++ ++ system_config_8800dc(sdiodev); ++ printk("############ system_config_8800dc done\n"); ++ ++ ret = rwnx_plat_patch_load(sdiodev); ++ if (ret) { ++ printk("patch load return %d\n", ret); ++ return ret; ++ } ++ printk("############ rwnx_plat_patch_load done\n"); ++ ++ //rwnx_plat_userconfig_load(sdiodev); ++ ++ aicwf_patch_config_8800dc(sdiodev); ++ printk("############ aicwf_patch_config_8800dc done\n"); ++ ++ start_from_bootrom_8800DC(sdiodev); ++ } else if (sdiodev->chipid == PRODUCT_ID_AIC8800D80) { ++ if (rwnx_plat_bin_fw_upload_android( ++ sdiodev, RAM_FMAC_FW_ADDR, ++ aicbsp_firmware_list[aicbsp_info.cpmode].wl_fw)) { ++ printk("8800d80 download wifi fw fail\n"); ++ return -1; ++ } ++ ++ if (aicwifi_patch_config_8800d80(sdiodev)) { ++ printk("aicwifi_patch_config_8800d80 fail\n"); ++ return -1; ++ } ++ ++ if (aicwifi_sys_config_8800d80(sdiodev)) { ++ printk("aicwifi_patch_config_8800d80 fail\n"); ++ return -1; ++ } ++ ++ if (aicwifi_start_from_bootrom(sdiodev)) { ++ printk("8800d80 wifi start fail\n"); ++ return -1; ++ } ++ } else if (sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ if (rwnx_plat_bin_fw_upload_android( ++ sdiodev, RAM_FMAC_FW_ADDR, ++ aicbsp_firmware_list[aicbsp_info.cpmode].wl_fw)) { ++ printk("8800d80x2 download wifi fw fail\n"); ++ return -1; ++ } ++ if (aicwifi_start_from_bootrom(sdiodev)) { ++ printk("8800d80x2 wifi start fail\n"); ++ return -1; ++ } ++ } ++ ++#if (defined(CONFIG_GPIO_WAKEUP) || defined(CONFIG_SDIO_PWRCTRL)) ++ if (aicbsp_priv_aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.wakeup_reg, 4)) { ++ sdio_err("reg:%d write failed!\n", ++ sdiodev->sdio_reg.wakeup_reg); ++ return -1; ++ } ++#endif ++ return 0; ++} ++ ++u32 aicbsp_syscfg_tbl[][2] = { ++ { 0x40500014, 0x00000101 }, // 1) ++ { 0x40500018, 0x00000109 }, // 2) ++ { 0x40500004, 0x00000010 }, // 3) the order should not be changed ++ ++ // def CONFIG_PMIC_SETTING ++ // U02 bootrom only ++ { 0x40040000, 0x00001AC8 }, // 1) fix panic ++ { 0x40040084, 0x00011580 }, ++ { 0x40040080, 0x00000001 }, ++ { 0x40100058, 0x00000000 }, ++ ++ { 0x50000000, 0x03220204 }, // 2) pmic interface init ++ { 0x50019150, 0x00000002 }, // 3) for 26m xtal, set div1 ++ { 0x50017008, 0x00000000 }, // 4) stop wdg ++}; ++ ++static int aicbsp_system_config(struct aic_sdio_dev *sdiodev) ++{ ++ int syscfg_num = sizeof(aicbsp_syscfg_tbl) / sizeof(u32) / 2; ++ int ret, cnt; ++ for (cnt = 0; cnt < syscfg_num; cnt++) { ++ ret = aicbsp_priv_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) ++{ ++ aicbsp_priv_rwnx_cmd_mgr_init(&sdiodev->cmd_mgr); ++ sdiodev->cmd_mgr.sdiodev = (void *)sdiodev; ++ ++ return 0; ++} ++ ++void aicbsp_platform_deinit(struct aic_sdio_dev *sdiodev) ++{ ++ (void)sdiodev; ++} ++ ++int aicbsp_driver_fw_init(struct aic_sdio_dev *sdiodev) ++{ ++ u32 mem_addr; ++ struct dbg_mem_read_cfm rd_mem_addr_cfm; ++ u32 btenable = 0; ++ u8 is_chip_id_h = 0; ++ int ret = 0; ++ ++ mem_addr = 0x40500000; ++ ++ aicbsp_priv_testmode = aicbsp_info.cpmode; ++ ++ if (sdiodev->chipid == PRODUCT_ID_AIC8801) { ++ if (aicbsp_priv_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); ++ btenable = 1; ++ ++ 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; ++ } ++ ++ if (aicbsp_info.chip_rev != CHIP_REV_U02) ++ aicbsp_firmware_list = fw_u03; ++ ++ if (aicbsp_system_config(sdiodev)) ++ return -1; ++ } else if (sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ if (aicbsp_priv_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) & 0x3F); ++ is_chip_id_h = ++ (u8)(((rd_mem_addr_cfm.memdata >> 16) & 0xC0) == 0xC0); ++ ++ btenable = ((rd_mem_addr_cfm.memdata >> 26) & 0x1); ++ AICWFDBG(LOGINFO, "btenable = %d \n", btenable); ++ ++ if (btenable == 0) { ++ sdiodev->chipid = PRODUCT_ID_AIC8800DW; ++ AICWFDBG(LOGINFO, "AIC8800DC change to AIC8800DW \n"); ++ } ++ ++ if (aicbsp_info.chip_rev != CHIP_REV_U01 && ++ 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; ++ } ++ if (is_chip_id_h) { ++ AICWFDBG(LOGINFO, "IS_CHIP_ID_H \n"); ++ aicbsp_firmware_list = fw_8800dc_h_u02; ++ } else { ++ if (aicbsp_info.chip_rev == CHIP_REV_U01) { ++ aicbsp_firmware_list = fw_8800dc_u01; ++ } else { ++ aicbsp_firmware_list = fw_8800dc_u02; ++ } ++ } ++ } else if (sdiodev->chipid == PRODUCT_ID_AIC8800D80) { ++ if (aicbsp_priv_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) & 0x3F); ++ is_chip_id_h = ++ (u8)(((rd_mem_addr_cfm.memdata >> 16) & 0xC0) == 0xC0); ++ btenable = 1; ++ if (is_chip_id_h) { ++ AICWFDBG(LOGINFO, "IS_CHIP_ID_H \n"); ++ aicbsp_firmware_list = fw_8800d80_h_u02; ++ } else { ++ if (aicbsp_info.chip_rev == CHIP_REV_U01) ++ aicbsp_firmware_list = fw_8800d80_u01; ++ if (aicbsp_info.chip_rev == CHIP_REV_U02 || ++ aicbsp_info.chip_rev == CHIP_REV_U03) ++ aicbsp_firmware_list = fw_8800d80_u02; ++ } ++ if (aicbsp_system_config_8800d80(sdiodev)) ++ return -1; ++ } else if (sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ btenable = 1; ++ if (aicbsp_priv_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) & 0x3F); ++ if (aicbsp_info.chip_rev >= (CHIP_REV_U04 + 8)) ++ aicbsp_firmware_list = fw_8800d80x2; ++ else { ++ pr_err("aicbsp: %s, unsupport chip rev: %d\n", __func__, ++ aicbsp_info.chip_rev); ++ return -1; ++ } ++ } ++ ++ AICWFDBG(LOGINFO, "aicbsp: %s, chip rev: %d\n", __func__, ++ aicbsp_info.chip_rev); ++ ++#ifndef CONFIG_MCU_MESSAGE ++ if (aicbsp_priv_testmode != 4) { ++ if (btenable == 1) { ++ if (aicbt_init(sdiodev)) ++ return -1; ++ } ++ } ++#endif ++ ++ ret = aicwifi_init(sdiodev); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++int aicbsp_get_feature(struct aicbsp_feature_t *feature, char *fw_path) ++{ ++ if (aicbsp_sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ aicbsp_sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ aicbsp_sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ feature->sdio_clock = FEATURE_SDIO_CLOCK; ++ } else if (aicbsp_sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ aicbsp_sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ feature->sdio_clock = FEATURE_SDIO_CLOCK_V3; ++ } ++ feature->sdio_phase = FEATURE_SDIO_PHASE; ++ feature->hwinfo = aicbsp_info.hwinfo; ++ feature->fwlog_en = aicbsp_info.fwlog_en; ++ feature->irqf = aicbsp_info.irqf; ++ if (fw_path != NULL) { ++ sprintf(fw_path, "%s", AICBSP_FW_PATH); ++ } ++ ++ sdio_dbg("%s, set FEATURE_SDIO_CLOCK %d MHz\n", __func__, ++ feature->sdio_clock / 1000000); ++ return 0; ++} ++ ++EXPORT_SYMBOL_GPL(aicbsp_get_feature); ++ ++#ifdef CONFIG_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; ++ printk("%s \n", __func__); ++ 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; ++ printk("%s \n", __func__); ++ 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/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_driver.h b/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_driver.h +new file mode 100755 +index 000000000..17b0f85d3 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_driver.h +@@ -0,0 +1,610 @@ ++/** ++ ****************************************************************************** ++ * ++ * rwnx_cmds.h ++ * ++ * Copyright (C) RivieraWaves 2014-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++#ifndef _AIC_BSP_DRIVER_H ++#define _AIC_BSP_DRIVER_H ++ ++#include ++#include ++#include ++#include "aic_bsp_export.h" ++ ++#define RWNX_80211_CMD_TIMEOUT_MS 6000 //500//300 ++ ++#define RWNX_CMD_FLAG_NONBLOCK BIT(0) ++#define RWNX_CMD_FLAG_REQ_CFM BIT(1) ++#define RWNX_CMD_FLAG_WAIT_PUSH BIT(2) ++#define RWNX_CMD_FLAG_WAIT_ACK BIT(3) ++#define RWNX_CMD_FLAG_WAIT_CFM BIT(4) ++#define RWNX_CMD_FLAG_DONE BIT(5) ++/* ATM IPC design makes it possible to get the CFM before the ACK, ++ * otherwise this could have simply been a state enum */ ++#define RWNX_CMD_WAIT_COMPLETE(flags) \ ++ (!(flags & (RWNX_CMD_FLAG_WAIT_ACK | RWNX_CMD_FLAG_WAIT_CFM))) ++ ++#define RWNX_CMD_MAX_QUEUED 8 ++ ++#define IPC_E2A_MSG_PARAM_SIZE 256 ++ ++#define RWNX_FN_ENTRY_STR ">>> %s()\n", __func__ ++ ++/* message levels */ ++#define LOGERROR 0x0001 ++#define LOGINFO 0x0002 ++#define LOGTRACE 0x0004 ++#define LOGDEBUG 0x0008 ++#define LOGDATA 0x0010 ++ ++extern int aicwf_dbg_level_bsp; ++ ++#define AICWF_LOG "AICWFDBG(" ++ ++#define AICWFDBG(level, args, arg...) \ ++ do { \ ++ if (aicwf_dbg_level_bsp & level) { \ ++ printk(AICWF_LOG #level ")\t" args, ##arg); \ ++ } \ ++ } while (0) ++ ++#define RWNX_DBG(fmt, ...) \ ++ do { \ ++ if (aicwf_dbg_level_bsp & LOGTRACE) { \ ++ printk(AICWF_LOG "LOGTRACE)\t" fmt, ##__VA_ARGS__); \ ++ } \ ++ } while (0) ++ ++/// Message structure for MSGs from Emb to App ++struct ipc_e2a_msg { ++ u16 id; ///< Message id. ++ u16 dummy_dest_id; ++ u16 dummy_src_id; ++ u16 param_len; ///< Parameter embedded struct length. ++ u32 pattern; ///< Used to stamp a valid MSG buffer ++ u32 param[IPC_E2A_MSG_PARAM_SIZE]; ///< Parameter embedded struct. Must be word-aligned. ++}; ++ ++typedef u16 lmac_msg_id_t; ++typedef u16 lmac_task_id_t; ++ ++struct lmac_msg { ++ lmac_msg_id_t id; ///< Message id. ++ lmac_task_id_t dest_id; ///< Destination kernel identifier. ++ lmac_task_id_t src_id; ///< Source kernel identifier. ++ u16 param_len; ///< Parameter embedded struct length. ++ u32 param[]; ///< Parameter embedded struct. Must be word-aligned. ++}; ++ ++#define rwnx_cmd_e2amsg ipc_e2a_msg ++#define rwnx_cmd_a2emsg lmac_msg ++#define RWNX_CMD_A2EMSG_LEN(m) (sizeof(struct lmac_msg) + m->param_len) ++#define RWNX_CMD_E2AMSG_LEN_MAX (IPC_E2A_MSG_PARAM_SIZE * 4) ++ ++static inline void put_u16(u8 *buf, u16 data) ++{ ++ buf[0] = (u8)(data & 0x00ff); ++ buf[1] = (u8)((data >> 8) & 0x00ff); ++} ++ ++enum rwnx_cmd_mgr_state { ++ RWNX_CMD_MGR_STATE_DEINIT, ++ RWNX_CMD_MGR_STATE_INITED, ++ RWNX_CMD_MGR_STATE_CRASHED, ++}; ++ ++struct rwnx_cmd { ++ struct list_head list; ++ lmac_msg_id_t id; ++ lmac_msg_id_t reqid; ++ struct rwnx_cmd_a2emsg *a2e_msg; ++ char *e2a_msg; ++ u32 tkn; ++ u16 flags; ++ struct completion complete; ++ u32 result; ++}; ++ ++struct aic_sdio_dev; ++struct rwnx_cmd; ++typedef int (*msg_cb_fct)(struct rwnx_cmd *cmd, struct rwnx_cmd_e2amsg *msg); ++ ++struct rwnx_cmd_mgr { ++ enum rwnx_cmd_mgr_state state; ++ spinlock_t lock; ++ u32 next_tkn; ++ u32 queue_sz; ++ u32 max_queue_sz; ++ spinlock_t cb_lock; ++ void *sdiodev; ++ ++ struct list_head cmds; ++ ++ int (*queue)(struct rwnx_cmd_mgr *, struct rwnx_cmd *); ++ int (*llind)(struct rwnx_cmd_mgr *, struct rwnx_cmd *); ++ int (*msgind)(struct rwnx_cmd_mgr *, struct rwnx_cmd_e2amsg *, ++ msg_cb_fct); ++ void (*print)(struct rwnx_cmd_mgr *); ++ void (*drain)(struct rwnx_cmd_mgr *); ++ ++ struct work_struct cmdWork; ++ struct workqueue_struct *cmd_wq; ++}; ++ ++void aicbsp_priv_rwnx_cmd_mgr_init(struct rwnx_cmd_mgr *cmd_mgr); ++void aicbsp_priv_rwnx_cmd_mgr_deinit(struct rwnx_cmd_mgr *cmd_mgr); ++int cmd_mgr_queue_force_defer(struct rwnx_cmd_mgr *cmd_mgr, ++ struct rwnx_cmd *cmd); ++void rwnx_set_cmd_tx(void *dev, struct lmac_msg *msg, uint len); ++ ++enum { ++ TASK_NONE = (u8)-1, ++ ++ // MAC Management task. ++ TASK_MM = 0, ++ // DEBUG task ++ TASK_DBG, ++ /// SCAN task ++ TASK_SCAN, ++ /// TDLS task ++ TASK_TDLS, ++ /// SCANU task ++ TASK_SCANU, ++ /// ME task ++ TASK_ME, ++ /// SM task ++ TASK_SM, ++ /// APM task ++ TASK_APM, ++ /// BAM task ++ TASK_BAM, ++ /// MESH task ++ TASK_MESH, ++ /// RXU task ++ TASK_RXU, ++ // This is used to define the last task that is running on the EMB processor ++ TASK_LAST_EMB = TASK_RXU, ++ ++ // nX API task ++ TASK_API, ++ TASK_MAX, ++}; ++ ++#define LMAC_FIRST_MSG(task) ((lmac_msg_id_t)((task) << 10)) ++#define DRV_TASK_ID 100 ++#define MSG_I(msg) ((msg) & ((1 << 10) - 1)) ++#define MSG_T(msg) ((lmac_task_id_t)((msg) >> 10)) ++ ++enum dbg_msg_tag { ++ /// Memory read request ++ DBG_MEM_READ_REQ = LMAC_FIRST_MSG(TASK_DBG), ++ /// Memory read confirm ++ DBG_MEM_READ_CFM, ++ /// Memory write request ++ DBG_MEM_WRITE_REQ, ++ /// Memory write confirm ++ DBG_MEM_WRITE_CFM, ++ /// Module filter request ++ DBG_SET_MOD_FILTER_REQ, ++ /// Module filter confirm ++ DBG_SET_MOD_FILTER_CFM, ++ /// Severity filter request ++ DBG_SET_SEV_FILTER_REQ, ++ /// Severity filter confirm ++ DBG_SET_SEV_FILTER_CFM, ++ /// LMAC/MAC HW fatal error indication ++ DBG_ERROR_IND, ++ /// Request to get system statistics ++ DBG_GET_SYS_STAT_REQ, ++ /// COnfirmation of system statistics ++ DBG_GET_SYS_STAT_CFM, ++ /// Memory block write request ++ DBG_MEM_BLOCK_WRITE_REQ, ++ /// Memory block write confirm ++ DBG_MEM_BLOCK_WRITE_CFM, ++ /// Start app request ++ DBG_START_APP_REQ, ++ /// Start app confirm ++ DBG_START_APP_CFM, ++ /// Start npc request ++ DBG_START_NPC_REQ, ++ /// Start npc confirm ++ DBG_START_NPC_CFM, ++ /// Memory mask write request ++ 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, ++ ++ DBG_CUSTOM_MSG_REQ, ++ DBG_CUSTOM_MSG_CFM, ++ DBG_CUSTOM_MSG_IND, ++ ++ DBG_GPIO_WRITE_REQ, ++ DBG_GPIO_WRITE_CFM, ++ ++ /// Max number of Debug messages ++ DBG_MAX, ++}; ++ ++#if !defined(CONFIG_M2D_OTA_LZMA_SUPPORT) ++#define FW_M2D_OTA_NAME "m2d_ota.bin" ++#else ++#define FW_M2D_OTA_NAME "m2d_ota_lzma.bin" ++#endif ++ ++enum { ++ HOST_START_APP_AUTO = 1, ++ HOST_START_APP_CUSTOM, ++ HOST_START_APP_FNCALL = 4, ++ HOST_START_APP_DUMMY = 5, ++}; ++ ++struct dbg_mem_block_write_req { ++ u32 memaddr; ++ u32 memsize; ++ u32 memdata[1024 / sizeof(u32)]; ++}; ++ ++/// Structure containing the parameters of the @ref DBG_MEM_BLOCK_WRITE_CFM message. ++struct dbg_mem_block_write_cfm { ++ u32 wstatus; ++}; ++ ++/// Structure containing the parameters of the @ref DBG_MEM_WRITE_REQ message. ++struct dbg_mem_write_req { ++ u32 memaddr; ++ u32 memdata; ++}; ++ ++/// Structure containing the parameters of the @ref DBG_MEM_WRITE_CFM message. ++struct dbg_mem_write_cfm { ++ u32 memaddr; ++ u32 memdata; ++}; ++ ++/// Structure containing the parameters of the @ref DBG_MEM_READ_REQ message. ++struct dbg_mem_read_req { ++ u32 memaddr; ++}; ++ ++/// Structure containing the parameters of the @ref DBG_MEM_READ_CFM message. ++struct dbg_mem_read_cfm { ++ u32 memaddr; ++ u32 memdata; ++}; ++ ++/// Structure containing the parameters of the @ref DBG_MEM_MASK_WRITE_REQ message. ++struct dbg_mem_mask_write_req { ++ u32 memaddr; ++ u32 memmask; ++ u32 memdata; ++}; ++ ++/// Structure containing the parameters of the @ref DBG_MEM_MASK_WRITE_CFM message. ++struct dbg_mem_mask_write_cfm { ++ u32 memaddr; ++ u32 memdata; ++}; ++ ++/// Structure containing the parameters of the @ref DBG_START_APP_REQ message. ++struct dbg_start_app_req { ++ u32 bootaddr; ++ u32 boottype; ++}; ++ ++/// Structure containing the parameters of the @ref DBG_START_APP_CFM message. ++struct dbg_start_app_cfm { ++ u32 bootstatus; ++}; ++ ++int aicwf_plat_patch_load_8800dc(struct aic_sdio_dev *sdiodev); ++int aicwf_plat_rftest_load_8800dc(struct aic_sdio_dev *sdiodev); ++#if defined(CONFIG_DPD) || defined(CONFIG_LOFT_CALIB) ++int aicwf_misc_ram_valid_check_8800dc(struct aic_sdio_dev *sdiodev, ++ int *valid_out); ++int aicwf_plat_calib_load_8800dc(struct aic_sdio_dev *sdiodev); ++#endif ++ ++int rwnx_load_firmware(u32 **fw_buf, const char *name, struct device *device); ++int aicwf_patch_table_load(struct aic_sdio_dev *rwnx_hw, char *filename); ++ ++int aicbsp_priv_rwnx_send_dbg_mem_read_req(struct aic_sdio_dev *sdiodev, u32 mem_addr, ++ struct dbg_mem_read_cfm *cfm); ++int aicbsp_priv_rwnx_send_dbg_mem_block_write_req(struct aic_sdio_dev *sdiodev, ++ u32 mem_addr, u32 mem_size, ++ u32 *mem_data); ++int aicbsp_priv_rwnx_send_dbg_mem_write_req(struct aic_sdio_dev *sdiodev, u32 mem_addr, ++ u32 mem_data); ++int aicbsp_priv_rwnx_send_dbg_mem_mask_write_req(struct aic_sdio_dev *sdiodev, u32 mem_addr, ++ u32 mem_mask, u32 mem_data); ++int aicbsp_priv_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_plat_bin_fw_upload_android(struct aic_sdio_dev *sdiodev, u32 fw_addr, ++ const char *filename); ++ ++void aicbsp_priv_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); ++int aicbsp_driver_fw_init(struct aic_sdio_dev *sdiodev); ++#if (defined(CONFIG_DPD) && !defined(CONFIG_FORCE_DPD_CALIB)) ++int is_file_exist(char *name); ++#endif ++int aicbsp_resv_mem_init(void); ++int aicbsp_resv_mem_deinit(void); ++ ++#define AICBSP_FW_PATH CONFIG_AIC_FW_PATH ++#define AICBSP_FW_PATH_MAX 200 ++ ++#define RAM_FMAC_FW_ADDR 0x00120000 ++#define RAM_FMAC_FW_PATCH_ADDR 0x00190000 ++#define FW_RAM_ADID_BASE_ADDR 0x00161928 ++#define FW_RAM_ADID_BASE_ADDR_U03 0x00161928 ++#define FW_RAM_PATCH_BASE_ADDR 0x00100000 ++#define RAM_8800DC_U01_ADID_ADDR 0x00101788 ++#define RAM_8800DC_U02_ADID_ADDR 0x001017d8 ++#define RAM_8800DC_FW_PATCH_ADDR 0x00184000 ++#define FW_RESET_START_ADDR 0x40500128 ++#define FW_RESET_START_VAL 0x40 ++#define FW_ADID_FLAG_ADDR 0x40500150 ++#define FW_ADID_FLAG_VAL 0x01 ++#define FW_RAM_ADID_BASE_ADDR_8800D80 0x002017E0 ++#define FW_RAM_PATCH_BASE_ADDR_8800D80 0x0020B2B0 ++#define FW_RAM_ADID_BASE_ADDR_8800D80_U02 0x00201940 ++#define FW_RAM_PATCH_BASE_ADDR_8800D80_U02 0x0020b43c ++ ++#define AICBT_PT_TAG "AICBT_PT_TAG" ++ ++/***************************************************************************** ++ * Addresses within RWNX_ADDR_CPU ++ *****************************************************************************/ ++#define RAM_LMAC_FW_ADDR 0x00150000 ++ ++#define ROM_FMAC_FW_ADDR 0x00010000 ++#define ROM_FMAC_PATCH_ADDR 0x00180000 ++ ++#define RAM_FMAC_FW_PATCH_NAME "fmacfw_patch.bin" ++#define RWNX_MAC_CALIB_BASE_NAME_8800DC "fmacfw_calib_8800dc" ++#define RWNX_MAC_CALIB_NAME_8800DC_U02 \ ++ RWNX_MAC_CALIB_BASE_NAME_8800DC "_u02.bin" ++#ifdef CONFIG_SDIO_BT ++#define RWNX_MAC_CALIB_NAME_8800DC_H_U02 \ ++ RWNX_MAC_CALIB_BASE_NAME_8800DC "_hbt_u02.bin" ++#else ++#define RWNX_MAC_CALIB_NAME_8800DC_H_U02 \ ++ RWNX_MAC_CALIB_BASE_NAME_8800DC "_h_u02.bin" ++#endif ++ ++#if defined(CONFIG_DPD) || defined(CONFIG_LOFT_CALIB) ++#define ROM_FMAC_CALIB_ADDR 0x00130000 ++#endif ++#ifdef CONFIG_DPD ++#ifndef CONFIG_FORCE_DPD_CALIB ++#define FW_DPDRESULT_NAME_8800DC "aic_dpdresult_lite_8800dc.bin" ++#endif ++#endif ++ ++#define RWNX_MAC_FW_RF_BASE_NAME_8800DC "lmacfw_rf_8800dc.bin" ++ ++#ifdef CONFIG_FOR_IPCOM ++#define RWNX_MAC_PATCH_BASE_NAME_8800DC "fmacfw_patch_8800dc_ipc" ++#define RWNX_MAC_PATCH_NAME2_8800DC RWNX_MAC_PATCH_BASE_NAME_8800DC ".bin" ++#else ++#define RWNX_MAC_PATCH_BASE_NAME_8800DC "fmacfw_patch_8800dc" ++#define RWNX_MAC_PATCH_NAME2_8800DC RWNX_MAC_PATCH_BASE_NAME_8800DC ".bin" ++#define RWNX_MAC_PATCH_NAME2_8800DC_U02 \ ++ RWNX_MAC_PATCH_BASE_NAME_8800DC "_u02.bin" ++#ifdef CONFIG_SDIO_BT ++#define RWNX_MAC_PATCH_NAME2_8800DC_H_U02 \ ++ RWNX_MAC_PATCH_BASE_NAME_8800DC "_hbt_u02.bin" ++#else ++#define RWNX_MAC_PATCH_NAME2_8800DC_H_U02 \ ++ RWNX_MAC_PATCH_BASE_NAME_8800DC "_h_u02.bin" ++#endif ++#endif ++ ++#define RWNX_MAC_PATCH_TABLE_NAME_8800DC "fmacfw_patch_tbl_8800dc" ++#define RWNX_MAC_PATCH_TABLE_8800DC RWNX_MAC_PATCH_TABLE_NAME_8800DC ".bin" ++#define RWNX_MAC_PATCH_TABLE_8800DC_U02 \ ++ RWNX_MAC_PATCH_TABLE_NAME_8800DC "_u02.bin" ++#ifdef CONFIG_SDIO_BT ++#define RWNX_MAC_PATCH_TABLE_8800DC_H_U02 \ ++ RWNX_MAC_PATCH_TABLE_NAME_8800DC "_hbt_u02.bin" ++#else ++#define RWNX_MAC_PATCH_TABLE_8800DC_H_U02 \ ++ RWNX_MAC_PATCH_TABLE_NAME_8800DC "_h_u02.bin" ++#endif ++ ++#define RWNX_MAC_RF_PATCH_BASE_NAME_8800DC "fmacfw_rf_patch_8800dc" ++#define RWNX_MAC_RF_PATCH_NAME_8800DC RWNX_MAC_RF_PATCH_BASE_NAME_8800DC ".bin" ++#define FW_USERCONFIG_NAME_8800DC "aic_userconfig_8800dc.txt" ++ ++enum { ++ FW_NORMAL_MODE = 0, ++ FW_RFTEST_MODE = 1, ++ FW_BLE_SCAN_WAKEUP_MODE = 2, ++ FW_M2D_OTA_MODE = 3, ++ FW_DPDCALIB_MODE = 4, ++ FW_BLE_SCAN_AD_FILTER_MODE = 5, ++}; ++ ++enum aicbt_patch_table_type { ++ AICBT_PT_INF = 0x00, ++ AICBT_PT_TRAP = 0x1, ++ AICBT_PT_B4, ++ AICBT_PT_BTMODE, ++ AICBT_PT_PWRON, ++ AICBT_PT_AF, ++ AICBT_PT_VER, ++}; ++ ++enum aicbt_btport_type { ++ AICBT_BTPORT_NULL, ++ AICBT_BTPORT_MB, ++ AICBT_BTPORT_UART, ++}; ++ ++/* btmode ++ * used for force bt mode,if not AICBSP_MODE_NULL ++ * efuse valid and vendor_info will be invalid, even has beed set valid ++*/ ++enum aicbt_btmode_type { ++ AICBT_BTMODE_BT_ONLY_SW = 0x0, // bt only mode with switch ++ AICBT_BTMODE_BT_WIFI_COMBO, // wifi/bt combo mode ++ AICBT_BTMODE_BT_ONLY, // bt only mode without switch ++ AICBT_BTMODE_BT_ONLY_TEST, // bt only test mode ++ AICBT_BTMODE_BT_WIFI_COMBO_TEST, // wifi/bt combo test mode ++ AICBT_BTMODE_BT_ONLY_COANT, // bt only mode with no external switch ++ AICBT_MODE_NULL = 0xFF, // invalid value ++}; ++ ++/* uart_baud ++ * used for config uart baud when btport set to uart, ++ * otherwise meaningless ++*/ ++enum aicbt_uart_baud_type { ++ AICBT_UART_BAUD_115200 = 115200, ++ AICBT_UART_BAUD_921600 = 921600, ++ AICBT_UART_BAUD_1_5M = 1500000, ++ AICBT_UART_BAUD_3_25M = 3250000, ++}; ++ ++enum aicbt_uart_flowctrl_type { ++ AICBT_UART_FLOWCTRL_DISABLE = 0x0, // uart without flow ctrl ++ AICBT_UART_FLOWCTRL_ENABLE, // uart with flow ctrl ++}; ++ ++enum aicbsp_cpmode_type { ++ AICBSP_CPMODE_WORK, ++ AICBSP_CPMODE_TEST, ++ AICBSP_CPMODE_MAX, ++}; ++ ++enum chip_rev { ++ CHIP_REV_U01 = 1, ++ CHIP_REV_U02 = 3, ++ CHIP_REV_U03 = 7, ++ CHIP_REV_U04 = 7, ++}; ++ ++#define AIC_M2D_OTA_INFO_ADDR 0x88000020 ++#define AIC_M2D_OTA_DATA_ADDR 0x88000040 ++#if !defined(CONFIG_M2D_OTA_LZMA_SUPPORT) ++#define AIC_M2D_OTA_FLASH_ADDR 0x08004000 ++#define AIC_M2D_OTA_CODE_START_ADDR (AIC_M2D_OTA_FLASH_ADDR + 0x0188) ++#define AIC_M2D_OTA_VER_ADDR (AIC_M2D_OTA_FLASH_ADDR + 0x018C) ++#else ++#define AIC_M2D_OTA_FLASH_ADDR 0x08005000 ++#define AIC_M2D_OTA_CODE_START_ADDR (AIC_M2D_OTA_FLASH_ADDR + 0x1188) ++#define AIC_M2D_OTA_VER_ADDR (AIC_M2D_OTA_FLASH_ADDR + 0x0010) ++#endif ++///aic bt tx pwr lvl :lsb->msb: first byte, min pwr lvl; second byte, max pwr lvl; ++///pwr lvl:20(min), 30 , 40 , 50 , 60(max) ++#define AICBT_TXPWR_LVL 0x00006020 ++#define AICBT_TXPWR_LVL_8800dc 0x00006f2f ++#define AICBT_TXPWR_LVL_8800d80 0x00006f2f ++#define AICBT_TXPWR_LVL_8800d80x2 0x00006f2f ++ ++#define AICBSP_HWINFO_DEFAULT (-1) ++#define AICBSP_CPMODE_DEFAULT AICBSP_CPMODE_WORK ++#define AICBSP_FWLOG_EN_DEFAULT 0 ++ ++#define AICBT_BTMODE_DEFAULT_8800d80x2 AICBT_BTMODE_BT_ONLY_COANT ++#define AICBT_BTMODE_DEFAULT_8800d80 AICBT_BTMODE_BT_ONLY_COANT ++#define AICBT_BTMODE_DEFAULT AICBT_BTMODE_BT_ONLY_SW ++#ifdef CONFIG_SDIO_BT ++#define AICBT_BTPORT_DEFAULT AICBT_BTPORT_MB ++#else ++#define AICBT_BTPORT_DEFAULT AICBT_BTPORT_UART ++#endif ++#define AICBT_UART_BAUD_DEFAULT AICBT_UART_BAUD_1_5M ++#define AICBT_UART_FC_DEFAULT AICBT_UART_FLOWCTRL_ENABLE ++#define AICBT_LPM_ENABLE_DEFAULT 0 ++#define AICBT_TXPWR_LVL_DEFAULT AICBT_TXPWR_LVL ++#define AICBT_TXPWR_LVL_DEFAULT_8800dc AICBT_TXPWR_LVL_8800dc ++#define AICBT_TXPWR_LVL_DEFAULT_8800d80 AICBT_TXPWR_LVL_8800d80 ++#define AICBT_TXPWR_LVL_DEFAULT_8800d80x2 AICBT_TXPWR_LVL_8800d80x2 ++ ++#define FEATURE_SDIO_CLOCK 50000000 // 0: default, other: target clock rate ++#define FEATURE_SDIO_CLOCK_V3 150000000 // 0: default, other: target clock rate ++#define FEATURE_SDIO_PHASE 2 // 0: default, 2: 180° ++ ++struct aicbt_patch_table { ++ char *name; ++ uint32_t type; ++ uint32_t *data; ++ uint32_t len; ++ struct aicbt_patch_table *next; ++}; ++ ++struct aicbt_info_t { ++ uint32_t btmode; ++ uint32_t btport; ++ uint32_t uart_baud; ++ uint32_t uart_flowctrl; ++ uint32_t lpm_enable; ++ uint32_t txpwr_lvl; ++}; ++ ++struct aicbt_patch_info_t { ++ uint32_t info_len; ++ //base len start ++ uint32_t adid_addrinf; ++ uint32_t addr_adid; ++ uint32_t patch_addrinf; ++ uint32_t addr_patch; ++ uint32_t reset_addr; ++ uint32_t reset_val; ++ uint32_t adid_flag_addr; ++ uint32_t adid_flag; ++ //base len end ++ //ext patch nb ++ uint32_t ext_patch_nb_addr; ++ uint32_t ext_patch_nb; ++ uint32_t *ext_patch_param; ++}; ++ ++struct aicbsp_firmware { ++ const char *desc; ++ const char *bt_adid; ++ const char *bt_patch; ++ const char *bt_table; ++ const char *wl_fw; ++ const char *bt_ext_patch; ++}; ++ ++struct aicbsp_info_t { ++ int hwinfo; ++ int hwinfo_r; ++ uint32_t cpmode; ++ uint32_t chip_rev; ++ bool fwlog_en; ++ uint8_t irqf; ++}; ++ ++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 fw_u02[]; ++extern const struct aicbsp_firmware fw_u03[]; ++extern const struct aicbsp_firmware fw_8800dc_u01[]; ++extern const struct aicbsp_firmware fw_8800dc_u02[]; ++extern const struct aicbsp_firmware fw_8800dc_h_u02[]; ++extern const struct aicbsp_firmware fw_8800d80_u01[]; ++extern const struct aicbsp_firmware fw_8800d80_u02[]; ++extern const struct aicbsp_firmware fw_8800d80_h_u02[]; ++extern const struct aicbsp_firmware fw_8800d80x2[]; ++ ++#endif +diff --git a/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_export.h b/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_export.h +new file mode 100755 +index 000000000..062eadb44 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_export.h +@@ -0,0 +1,71 @@ ++#ifndef __AIC_BSP_EXPORT_H ++#define __AIC_BSP_EXPORT_H ++ ++enum aicbsp_subsys { ++ AIC_BLUETOOTH, ++ AIC_WIFI, ++}; ++ ++enum aicbsp_pwr_state { ++ AIC_PWR_OFF, ++ AIC_PWR_ON, ++}; ++ ++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 { ++ int hwinfo; ++ uint32_t sdio_clock; ++ uint8_t sdio_phase; ++ bool fwlog_en; ++ uint8_t irqf; ++}; ++ ++#if defined(CONFIG_DPD) || defined(CONFIG_LOFT_CALIB) ++typedef struct { ++ uint32_t bit_mask[3]; ++ uint32_t reserved; ++ uint32_t dpd_high[96]; ++ uint32_t dpd_11b[96]; ++ uint32_t dpd_low[96]; ++ uint32_t idac_11b[48]; ++ uint32_t idac_high[48]; ++ uint32_t idac_low[48]; ++ uint32_t loft_res[18]; ++ uint32_t rx_iqim_res[16]; ++} rf_misc_ram_t; ++ ++typedef struct { ++ uint32_t bit_mask[4]; ++ uint32_t dpd_high[96]; ++ uint32_t loft_res[18]; ++} rf_misc_ram_lite_t; ++ ++#define MEMBER_SIZE(type, member) sizeof(((type *)0)->member) ++#define DPD_RESULT_SIZE_8800DC sizeof(rf_misc_ram_lite_t) ++#endif ++ ++#ifdef CONFIG_DPD ++extern rf_misc_ram_lite_t dpd_res; ++#endif ++ ++#ifdef CONFIG_LOFT_CALIB ++extern rf_misc_ram_lite_t loft_res_local; ++#endif ++ ++int aicbsp_set_subsys(int, int); ++int aicbsp_get_feature(struct aicbsp_feature_t *feature, char *fw_path); ++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/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_main.c b/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_main.c +new file mode 100755 +index 000000000..57601c6f7 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_bsp/aic_bsp_main.c +@@ -0,0 +1,434 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "aic_bsp_driver.h" ++#include "rwnx_version_gen.h" ++#include "aicwf_txq_prealloc.h" ++ ++#define DRV_DESCRIPTION "AIC BSP" ++#define DRV_COPYRIGHT "Copyright(c) 2015-2020 AICSemi" ++#define DRV_AUTHOR "AICSemi" ++#define DRV_VERS_MOD "1.0" ++ ++int aicwf_dbg_level_bsp = LOGERROR | LOGINFO | LOGDEBUG | LOGTRACE; ++ ++struct semaphore aicbsp_probe_semaphore; ++ ++static struct platform_device *aicbsp_pdev; ++ ++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", ++#ifdef CONFIG_SDIO_BT ++ .wl_fw = "fmacfwbt.bin" ++#else ++ .wl_fw = "fmacfw.bin" ++#endif ++ }, ++ [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", ++ .wl_fw = "fmacfw_rf.bin" }, ++}; ++ ++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", ++#ifdef CONFIG_MCU_MESSAGE ++ .wl_fw = "fmacfw_8800m_custmsg.bin" ++#elif defined(CONFIG_SDIO_BT) ++ .wl_fw = "fmacfwbt.bin" ++#else ++ .wl_fw = "fmacfw.bin" ++#endif ++ }, ++ ++ [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" }, ++}; ++ ++const struct aicbsp_firmware fw_8800dc_u01[] = { ++ [AICBSP_CPMODE_WORK] = { .desc = "normal work mode(sdio u01)", ++ .bt_adid = "fw_adid_8800dc.bin", ++ .bt_patch = "fw_patch_8800dc.bin", ++ .bt_table = "fw_patch_table_8800dc.bin", ++ .wl_fw = "fmacfw_8800dc.bin" }, ++ ++ [AICBSP_CPMODE_TEST] = { .desc = "rf test mode(sdio u01)", ++ .bt_adid = "fw_adid_8800dc.bin", ++ .bt_patch = "fw_patch_8800dc.bin", ++ .bt_table = "fw_patch_table_8800dc.bin", ++ .wl_fw = "fmacfw_rf_8800dc.bin" }, ++}; ++ ++const struct aicbsp_firmware fw_8800dc_u02[] = { ++ [AICBSP_CPMODE_WORK] = { ++ .desc = "normal work mode(8800dc sdio u02)", ++ .bt_adid = "fw_adid_8800dc_u02.bin", ++ .bt_patch = "fw_patch_8800dc_u02.bin", ++ .bt_table = "fw_patch_table_8800dc_u02.bin", ++ .bt_ext_patch = "fw_patch_8800dc_u02_ext", ++ .wl_fw = "fmacfw_patch_8800dc_u02.bin" ++ }, ++ ++ [AICBSP_CPMODE_TEST] = { ++ .desc = "rf test mode(8800dc sdio u02)", ++ .bt_adid = "fw_adid_8800dc_u02.bin", ++ .bt_patch = "fw_patch_8800dc_u02.bin", ++ .bt_table = "fw_patch_table_8800dc_u02.bin", ++ .bt_ext_patch = "fw_patch_8800dc_u02_ext", ++ .wl_fw = "lmacfw_rf_8800dc.bin" //u01,u02 lmacfw load same bin ++ }, ++}; ++ ++const struct aicbsp_firmware fw_8800dc_h_u02[] = { ++ [AICBSP_CPMODE_WORK] = { ++ .desc = "normal work mode(8800dc_h sdio u02)", ++ .bt_adid = "fw_adid_8800dc_u02h.bin", ++ .bt_patch = "fw_patch_8800dc_u02h.bin", ++ .bt_table = "fw_patch_table_8800dc_u02h.bin", ++ .bt_ext_patch = "fw_patch_8800dc_u02h_ext", ++ .wl_fw = "fmacfw_patch_8800dc_h_u02.bin" ++ }, ++ ++ [AICBSP_CPMODE_TEST] = { ++ .desc = "rf test mode(8800dc_h sdio u02)", ++ .bt_adid = "fw_adid_8800dc_u02h.bin", ++ .bt_patch = "fw_patch_8800dc_u02h.bin", ++ .bt_table = "fw_patch_table_8800dc_u02h.bin", ++ .bt_ext_patch = "fw_patch_8800dc_u02h_ext", ++ .wl_fw = "lmacfw_rf_8800dc.bin" //u01,u02 lmacfw load same bin ++ }, ++}; ++ ++const struct aicbsp_firmware fw_8800d80_u01[] = { ++ [AICBSP_CPMODE_WORK] = { .desc = "normal work mode(8800d80 sdio u01)", ++ .bt_adid = "fw_adid_8800d80.bin", ++ .bt_patch = "fw_patch_8800d80.bin", ++ .bt_table = "fw_patch_table_8800d80.bin", ++ .wl_fw = "fmacfw_8800d80.bin" }, ++ ++ [AICBSP_CPMODE_TEST] = { .desc = "rf test mode(8800d80 sdio u01)", ++ .bt_adid = "fw_adid_8800d80.bin", ++ .bt_patch = "fw_patch_8800d80.bin", ++ .bt_table = "fw_patch_table_8800d80.bin", ++ .wl_fw = "lmacfw_rf_8800d80.bin" }, ++}; ++ ++const struct aicbsp_firmware fw_8800d80_u02[] = { ++ [AICBSP_CPMODE_WORK] = { .desc = "normal work mode(8800d80 sdio u02)", ++ .bt_adid = "fw_adid_8800d80_u02.bin", ++ .bt_patch = "fw_patch_8800d80_u02.bin", ++ .bt_table = "fw_patch_table_8800d80_u02.bin", ++#if defined CONFIG_SDIO_BT ++ .wl_fw = "fmacfwbt_8800d80_u02.bin", ++#elif defined CONFIG_FOR_IPCAM ++ .wl_fw = "fmacfw_8800d80_u02_ipc.bin", ++#else ++ .wl_fw = "fmacfw_8800d80_u02.bin", ++#endif ++ .bt_ext_patch = "fw_patch_8800d80_u02_ext" }, ++ ++ [AICBSP_CPMODE_TEST] = { .desc = "rf test mode(8800d80 sdio u02)", ++ .bt_adid = "fw_adid_8800d80_u02.bin", ++ .bt_patch = "fw_patch_8800d80_u02.bin", ++ .bt_table = "fw_patch_table_8800d80_u02.bin", ++ .wl_fw = "lmacfw_rf_8800d80_u02.bin", ++ .bt_ext_patch = "fw_patch_8800d80_u02_ext" }, ++}; ++ ++const struct aicbsp_firmware fw_8800d80_h_u02[] = { ++ [AICBSP_CPMODE_WORK] = { .desc = "normal work mode(8800d80 sdio h_u02)", ++ .bt_adid = "fw_adid_8800d80_u02.bin", ++ .bt_patch = "fw_patch_8800d80_u02.bin", ++ .bt_table = "fw_patch_table_8800d80_u02.bin", ++#if defined CONFIG_SDIO_BT ++ .wl_fw = "fmacfwbt_8800d80_h_u02.bin", ++#elif defined CONFIG_FOR_IPCAM ++ .wl_fw = "fmacfw_8800d80_h_u02_ipc.bin", ++#else ++ .wl_fw = "fmacfw_8800d80_h_u02.bin", ++#endif ++ .bt_ext_patch = "fw_patch_8800d80_u02_ext" }, ++ ++ [AICBSP_CPMODE_TEST] = { .desc = "rf test mode(8800d80 sdio u02)", ++ .bt_adid = "fw_adid_8800d80_u02.bin", ++ .bt_patch = "fw_patch_8800d80_u02.bin", ++ .bt_table = "fw_patch_table_8800d80_u02.bin", ++ .wl_fw = "lmacfw_rf_8800d80_u02.bin", ++ .bt_ext_patch = "fw_patch_8800d80_u02_ext" }, ++}; ++ ++const struct aicbsp_firmware fw_8800d80x2[] = { ++ [AICBSP_CPMODE_WORK] = { .desc = "normal work mode(8800d80x2 sdio)", ++ .bt_adid = "fw_adid_8800d80x2_u05.bin", ++ .bt_patch = "fw_patch_8800d80x2_u05.bin", ++ .bt_table = "fw_patch_table_8800d80x2_u05.bin", ++#ifdef CONFIG_SDIO_BT ++ .wl_fw = "fmacfwbt_8800d80_h_u02.bin", ++#else ++ .wl_fw = "fmacfw_8800d80x2.bin", ++#endif ++ .bt_ext_patch = "fw_patch_8800d80x2_u05_ext" }, ++ ++ [AICBSP_CPMODE_TEST] = { .desc = "rf test mode(8800d80x2 sdio)", ++ .bt_adid = "fw_adid_8800d80x2_u05.bin", ++ .bt_patch = "fw_patch_8800d80x2_u05.bin", ++ .bt_table = "fw_patch_table_8800d80x2_u05.bin", ++ .wl_fw = "lmacfw_rf_8800d80x2.bin", ++ .bt_ext_patch = "fw_patch_8800d80x2_u05_ext" }, ++}; ++ ++struct aicbsp_info_t aicbsp_info = { ++ .hwinfo_r = AICBSP_HWINFO_DEFAULT, ++ .hwinfo = AICBSP_HWINFO_DEFAULT, ++ .cpmode = AICBSP_CPMODE_DEFAULT, ++ .fwlog_en = AICBSP_FWLOG_EN_DEFAULT, ++#ifdef CONFIG_IRQ_FALL ++ .irqf = 1, ++#else ++ .irqf = 0, ++#endif ++}; ++ ++struct mutex aicbsp_power_lock; ++ ++static struct platform_driver aicbsp_driver = { ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "aic_bsp", ++ }, ++ //.probe = aicbsp_probe, ++ //.remove = aicbsp_remove, ++}; ++ ++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 value:\n"); ++ ++ 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_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 cpmode_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ unsigned long val; ++ int err = kstrtoul(buf, 0, &val); ++ if (err) ++ return err; ++ ++ if (val >= AICBSP_CPMODE_MAX) { ++ pr_err("mode value must less than %d\n", AICBSP_CPMODE_MAX); ++ return -EINVAL; ++ } ++ ++ aicbsp_info.cpmode = val; ++ printk("%s, set mode to: %lu[%s] done\n", __func__, val, ++ aicbsp_firmware_list[val].desc); ++ ++ return count; ++} ++ ++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_cpmode.attr, ++ &dev_attr_hwinfo.attr, ++ &dev_attr_fwdebug.attr, ++ NULL, ++}; ++ ++static struct attribute_group aicbsp_attribute_group = { ++ .name = "aicbsp_info", ++ .attrs = aicbsp_attributes, ++}; ++ ++int aicbsp_priv_testmode = AICBSP_CPMODE_DEFAULT; ++int adap_test = 0; ++module_param(aicbsp_priv_testmode, int, 0660); ++module_param(adap_test, int, 0660); ++ ++static int __init aicbsp_init(void) ++{ ++ int ret; ++ printk("%s\n", __func__); ++ printk("RELEASE_DATE:%s\r\n", RELEASE_DATE); ++ ++ aicbsp_info.cpmode = aicbsp_priv_testmode; ++ ++ aicbsp_resv_mem_init(); ++ ++ sema_init(&aicbsp_probe_semaphore, 0); ++ ++ ret = platform_driver_register(&aicbsp_driver); ++ if (ret) { ++ pr_err("register platform driver failed: %d\n", ret); ++ return ret; ++ } ++ ++ 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; ++ } ++ ++ ret = sysfs_create_group(&(aicbsp_pdev->dev.kobj), ++ &aicbsp_attribute_group); ++ if (ret) { ++ pr_err("register sysfs create group failed!\n"); ++ return ret; ++ } ++ ++ mutex_init(&aicbsp_power_lock); ++#if defined CONFIG_PLATFORM_ROCKCHIP || defined CONFIG_PLATFORM_ROCKCHIP2 ++ aicbsp_set_subsys(AIC_BLUETOOTH, AIC_PWR_ON); ++#endif ++ return 0; ++} ++ ++void aicbsp_sdio_exit(void); ++extern struct aic_sdio_dev *aicbsp_sdiodev; ++ ++static void __exit aicbsp_exit(void) ++{ ++#if defined CONFIG_PLATFORM_ROCKCHIP || defined CONFIG_PLATFORM_ROCKCHIP2 ++ if (aicbsp_sdiodev) { ++ aicbsp_sdio_exit(); ++ } ++#endif ++ 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(); ++#ifdef CONFIG_PREALLOC_TXQ ++ aicwf_prealloc_txq_free(); ++#endif ++ printk("%s\n", __func__); ++} ++ ++module_init(aicbsp_init); ++module_exit(aicbsp_exit); ++ ++MODULE_DESCRIPTION(DRV_DESCRIPTION); ++MODULE_VERSION(DRV_VERS_MOD); ++MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio.c b/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio.c +new file mode 100755 +index 000000000..e29834db7 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio.c +@@ -0,0 +1,2138 @@ ++/** ++ * aicwf_sdmmc.c ++ * ++ * SDIO function declarations ++ * ++ * Copyright (C) AICSemi 2018-2020 ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "aicsdio_txrxif.h" ++#include "aicsdio.h" ++#include "aic_bsp_driver.h" ++#include ++#include ++/* flare-edge (6.18 port, PORT-PLAN.md §3.7): is a ++ * Rockchip-BSP-vendor-only header (rockchip_wifi_power()/ ++ * rockchip_wifi_set_carddetect()), not present in mainline. The call sites ++ * that use it in this file are all under CONFIG_PLATFORM_ROCKCHIP2 (unset ++ * here) or already #if 0'd out upstream; the mainline mmc-pwrseq-simple DT ++ * node does the power/reset sequencing instead. Do not include it. */ ++ ++#ifdef CONFIG_PLATFORM_ALLWINNER ++extern void sunxi_mmc_rescan_card(unsigned ids); ++extern void sunxi_wlan_set_power(int on); ++extern int sunxi_wlan_get_bus_index(void); ++static int aicbsp_bus_index = -1; ++#endif ++ ++#ifdef CONFIG_PLATFORM_AMLOGIC //for AML ++#include ++extern void sdio_reinit(void); ++extern void extern_wifi_set_enable(int is_on); ++extern void set_power_control_lock(int lock); ++#endif //for AML ++ ++static int aicbsp_platform_power_on(void); ++static void aicbsp_platform_power_off(void); ++ ++struct aic_sdio_dev *aicbsp_sdiodev = NULL; ++static struct semaphore *aicbsp_notify_semaphore; ++extern struct semaphore aicbsp_probe_semaphore; ++ ++static const struct sdio_device_id aicbsp_sdmmc_ids[]; ++static bool aicbsp_load_fw_in_fdrv = false; ++ ++#define FW_PATH_MAX 200 ++ ++//#ifdef CONFIG_PLATFORM_UBUNTU ++//static const char* aic_default_fw_path = "/lib/firmware/aic8800_sdio"; ++//#else ++static const char *aic_default_fw_path = CONFIG_AIC_FW_PATH; ++//#endif ++char aicbsp_priv_aic_fw_path[FW_PATH_MAX]; ++module_param_string(aicbsp_priv_aic_fw_path, aicbsp_priv_aic_fw_path, FW_PATH_MAX, 0660); ++#ifdef CONFIG_M2D_OTA_AUTO_SUPPORT ++char saved_sdk_ver[64]; ++module_param_string(saved_sdk_ver, saved_sdk_ver, 64, 0660); ++#endif ++ ++extern int aicbsp_priv_testmode; ++ ++#define SDIO_DEVICE_ID_AIC8801_FUNC2 0x0146 ++#define SDIO_DEVICE_ID_AIC8800D80_FUNC2 0x0182 ++ ++/* SDIO Device ID */ ++#define SDIO_VENDOR_ID_AIC8801 0x5449 ++#define SDIO_VENDOR_ID_AIC8800DC 0xc8a1 ++#define SDIO_VENDOR_ID_AIC8800D80 0xc8a1 ++#define SDIO_VENDOR_ID_AIC8800D80X2 0xc8a1 ++ ++#define SDIO_DEVICE_ID_AIC8801 0x0145 ++#define SDIO_DEVICE_ID_AIC8800DC 0xc08d ++#define SDIO_DEVICE_ID_AIC8800D80 0x0082 ++#define SDIO_DEVICE_ID_AIC8800D80X2 0x2082 ++ ++static int aicbsp_dummy_probe(struct sdio_func *func, ++ const struct sdio_device_id *id) ++{ ++ if (func && (func->num != 2)) ++ return 0; ++ ++ if (func->vendor != SDIO_VENDOR_ID_AIC8801 && ++ func->device != SDIO_DEVICE_ID_AIC8801 && ++ func->device != SDIO_DEVICE_ID_AIC8801_FUNC2 && ++ func->vendor != SDIO_VENDOR_ID_AIC8800DC && ++ func->device != SDIO_DEVICE_ID_AIC8800DC && ++ func->vendor != SDIO_VENDOR_ID_AIC8800D80 && ++ func->device != SDIO_DEVICE_ID_AIC8800D80 && ++ func->device != SDIO_DEVICE_ID_AIC8800D80_FUNC2) { ++ printk("VID:%x DID:%X \r\n", func->vendor, func->device); ++ aicbsp_load_fw_in_fdrv = true; ++ } ++ ++ if (aicbsp_notify_semaphore) ++ up(aicbsp_notify_semaphore); ++ return 0; ++} ++ ++static void aicbsp_dummy_remove(struct sdio_func *func) ++{ ++} ++ ++static struct sdio_driver aicbsp_dummy_sdmmc_driver = { ++ .probe = aicbsp_dummy_probe, ++ .remove = aicbsp_dummy_remove, ++ .name = "aicbsp_dummy_sdmmc", ++ .id_table = aicbsp_sdmmc_ids, ++}; ++ ++static int aicbsp_reg_sdio_notify(void *semaphore) ++{ ++ aicbsp_notify_semaphore = semaphore; ++ return sdio_register_driver(&aicbsp_dummy_sdmmc_driver); ++} ++ ++static void aicbsp_unreg_sdio_notify(void) ++{ ++ mdelay(15); ++ sdio_unregister_driver(&aicbsp_dummy_sdmmc_driver); ++} ++ ++static const char *aicbsp_subsys_name(int subsys) ++{ ++ switch (subsys) { ++ case AIC_BLUETOOTH: ++ return "AIC_BLUETOOTH"; ++ case AIC_WIFI: ++ return "AIC_WIFI"; ++ default: ++ return "unknown subsys"; ++ } ++} ++ ++#ifdef CONFIG_PLATFORM_ROCKCHIP ++#if 1 //FOR RK SUSPEND ++void rfkill_rk_sleep_bt(bool sleep); ++#endif ++#endif ++ ++#ifdef CONFIG_PLATFORM_ROCKCHIP2 ++#if 1 //FOR RK SUSPEND ++void rfkill_rk_sleep_bt(bool sleep); ++#endif ++#endif ++ ++int aicbsp_set_subsys(int subsys, int state) ++{ ++ static int pre_power_map; ++ int cur_power_map; ++ int pre_power_state; ++ int cur_power_state; ++ ++ mutex_lock(&aicbsp_power_lock); ++ aicbsp_load_fw_in_fdrv = false; ++ cur_power_map = pre_power_map; ++ if (state) ++ cur_power_map |= (1 << subsys); ++ else ++ 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_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_driver_fw_init(aicbsp_sdiodev)) ++ goto err2; ++#ifndef CONFIG_FDRV_NO_REG_SDIO ++ aicbsp_sdio_release(aicbsp_sdiodev); ++#endif ++ ++#if defined CONFIG_PLATFORM_ROCKCHIP || defined CONFIG_PLATFORM_ROCKCHIP2 ++#ifdef CONFIG_GPIO_WAKEUP ++ //BT_SLEEP:true,BT_WAKEUP:false ++ rfkill_rk_sleep_bt(true); ++ printk("%s BT wake default to SLEEP\r\n", __func__); ++#endif ++#endif ++ ++ //#ifndef CONFIG_PLATFORM_ROCKCHIP ++ // aicbsp_sdio_exit(); ++ //#endif ++ } else { ++#ifndef CONFIG_PLATFORM_ROCKCHIP ++ aicbsp_sdio_exit(); ++#endif ++ aicbsp_platform_power_off(); ++ } ++ } else { ++ 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_power_state; ++ ++err2: ++ aicbsp_sdio_release(aicbsp_sdiodev); ++ 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); ++ ++bool aicbsp_get_load_fw_in_fdrv(void) ++{ ++ return aicbsp_load_fw_in_fdrv; ++} ++ ++EXPORT_SYMBOL_GPL(aicbsp_get_load_fw_in_fdrv); ++ ++static int aicwf_sdio_chipmatch(struct aic_sdio_dev *sdio_dev, uint16_t vid, ++ uint16_t did) ++{ ++ if (vid == SDIO_VENDOR_ID_AIC8801 && did == SDIO_DEVICE_ID_AIC8801) { ++ sdio_dev->chipid = PRODUCT_ID_AIC8801; ++ AICWFDBG(LOGINFO, "%s USE AIC8801\r\n", __func__); ++ return 0; ++ } else if (vid == SDIO_VENDOR_ID_AIC8800DC && ++ did == SDIO_DEVICE_ID_AIC8800DC) { ++ sdio_dev->chipid = PRODUCT_ID_AIC8800DC; ++ AICWFDBG(LOGINFO, "%s USE AIC8800DC\r\n", __func__); ++ return 0; ++ } else if (vid == SDIO_VENDOR_ID_AIC8800D80 && ++ did == SDIO_DEVICE_ID_AIC8800D80) { ++ sdio_dev->chipid = PRODUCT_ID_AIC8800D80; ++ AICWFDBG(LOGINFO, "%s USE AIC8800D80\r\n", __func__); ++ return 0; ++ } else if (vid == SDIO_VENDOR_ID_AIC8800D80X2 && ++ did == SDIO_DEVICE_ID_AIC8800D80X2) { ++ sdio_dev->chipid = PRODUCT_ID_AIC8800D80X2; ++ AICWFDBG(LOGINFO, "%s USE AIC8800D80X2\r\n", __func__); ++ return 0; ++ } else { ++ return -1; ++ } ++} ++ ++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) ++{ ++ struct mmc_host *host; ++ struct aic_sdio_dev *sdiodev; ++ struct aicwf_bus *bus_if; ++ int err = -ENODEV; ++ ++ if (func == NULL) { ++ sdio_err("%s func is null\n", __func__); ++ return err; ++ } ++ ++ sdio_dbg("%s:%d vid:0x%04X did:0x%04X\n", __func__, func->num, ++ func->vendor, func->device); ++ ++ if (func->vendor != SDIO_VENDOR_ID_AIC8801 && ++ func->device != SDIO_DEVICE_ID_AIC8801 && ++ func->device != SDIO_DEVICE_ID_AIC8801_FUNC2 && ++ func->vendor != SDIO_VENDOR_ID_AIC8800DC && ++ func->device != SDIO_DEVICE_ID_AIC8800DC && ++ func->vendor != SDIO_VENDOR_ID_AIC8800D80 && ++ func->device != SDIO_DEVICE_ID_AIC8800D80 && ++ func->device != SDIO_DEVICE_ID_AIC8800D80_FUNC2) { ++ aicbsp_load_fw_in_fdrv = true; ++ return err; ++ } ++ ++ if (func->num != 2) { ++ return err; ++ } ++ ++ host = func->card->host; ++ host->caps |= MMC_CAP_NONREMOVABLE; ++ ++ func = func->card->sdio_func[1 - 1]; //replace 2 with 1 ++ ++ sdio_dbg("%s after replace:%d\n", __func__, func->num); ++ ++ bus_if = kzalloc(sizeof(struct aicwf_bus), GFP_KERNEL); ++ if (!bus_if) { ++ sdio_err("alloc bus fail\n"); ++ return -ENOMEM; ++ } ++ ++ sdiodev = kzalloc(sizeof(struct aic_sdio_dev), GFP_KERNEL); ++ if (!sdiodev) { ++ sdio_err("alloc sdiodev fail\n"); ++ kfree(bus_if); ++ return -ENOMEM; ++ } ++ aicbsp_sdiodev = sdiodev; ++ ++ err = aicwf_sdio_chipmatch(sdiodev, func->vendor, func->device); ++ ++ sdiodev->func = func; ++ if (sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ sdiodev->func_msg = func->card->sdio_func[1]; ++ } ++ sdiodev->bus_if = bus_if; ++ bus_if->bus_priv.sdio = sdiodev; ++ if (sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ dev_set_drvdata(&sdiodev->func_msg->dev, bus_if); ++ printk("the device is PRODUCT_ID_AIC8800DC \n"); ++ } ++ dev_set_drvdata(&func->dev, bus_if); ++ sdiodev->dev = &func->dev; ++ ++ if (sdiodev->chipid != PRODUCT_ID_AIC8800D80 && ++ sdiodev->chipid != PRODUCT_ID_AIC8800D80X2) { ++ err = aicbsp_priv_aicwf_sdio_func_init(sdiodev); ++ } else { ++ err = aicbsp_priv_aicwf_sdiov3_func_init(sdiodev); ++ } ++ if (err < 0) { ++ sdio_err("sdio func init fail\n"); ++ goto fail; ++ } ++ ++ if (aicbsp_priv_aicwf_sdio_bus_init(sdiodev) == NULL) { ++ sdio_err("sdio bus init err\r\n"); ++ goto fail; ++ } ++ ++ aicbsp_platform_init(sdiodev); ++ ++ up(&aicbsp_probe_semaphore); ++ ++ return 0; ++fail: ++ aicbsp_priv_aicwf_sdio_func_deinit(sdiodev); ++ dev_set_drvdata(&func->dev, NULL); ++ kfree(sdiodev); ++ kfree(bus_if); ++ return err; ++} ++ ++static void aicbsp_sdio_remove(struct sdio_func *func) ++{ ++ struct mmc_host *host; ++ struct aicwf_bus *bus_if = NULL; ++ struct aic_sdio_dev *sdiodev = NULL; ++ ++ AICWFDBG(LOGINFO, "%s\n", __func__); ++ if (aicbsp_sdiodev == NULL) { ++ AICWFDBG(LOGERROR, "%s: allready unregister\n", __func__); ++ goto done; ++ } ++ if (func == NULL) { ++ AICWFDBG(LOGERROR, "%s, sdio func is null\n", __func__); ++ goto done; ++ } ++ ++ host = func->card->host; ++ host->caps &= ~MMC_CAP_NONREMOVABLE; ++ ++ bus_if = aicbsp_get_drvdata(&func->dev); ++ ++ if (!bus_if) { ++ AICWFDBG(LOGERROR, "%s bus_if is NULL \r\n", __func__); ++ goto done; ++ } ++ ++ sdiodev = bus_if->bus_priv.sdio; ++ if (!sdiodev) { ++ AICWFDBG(LOGERROR, "%s sdiodev is NULL \r\n", __func__); ++ goto done; ++ } ++ ++ aicbsp_priv_aicwf_sdio_release(sdiodev); ++ aicbsp_priv_aicwf_sdio_func_deinit(sdiodev); ++ ++ dev_set_drvdata(&sdiodev->func->dev, NULL); ++ kfree(sdiodev); ++ ++done: ++ if (bus_if) ++ kfree(bus_if); ++ aicbsp_sdiodev = NULL; ++ sdio_dbg("%s done\n", __func__); ++} ++ ++static int aicbsp_sdio_suspend(struct device *dev) ++{ ++ struct sdio_func *func = dev_to_sdio_func(dev); ++ int err; ++ mmc_pm_flag_t sdio_flags; ++ ++#if defined(CONFIG_PLATFORM_ROCKCHIP) || defined(CONFIG_PLATFORM_ROCKCHIP2) ++#ifdef CONFIG_GPIO_WAKEUP ++ //BT_SLEEP:true,BT_WAKEUP:false ++ rfkill_rk_sleep_bt(false); ++#endif ++#endif ++ ++ sdio_dbg("%s, func->num = %d\n", __func__, func->num); ++ if (func->num != 2) ++ return 0; ++ ++ sdio_flags = sdio_get_host_pm_caps(func); ++ if (!(sdio_flags & MMC_PM_KEEP_POWER)) { ++ sdio_dbg("%s: can't keep power while host is suspended\n", ++ __func__); ++ return -EINVAL; ++ } ++ ++ /* keep power while host suspended */ ++ err = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); ++ if (err) { ++ sdio_dbg("%s: error while trying to keep power\n", __func__); ++ return err; ++ } ++ ++#if defined(CONFIG_PLATFORM_ROCKCHIP) || defined(CONFIG_PLATFORM_ROCKCHIP2) ++#ifdef CONFIG_GPIO_WAKEUP ++ //BT_SLEEP:true,BT_WAKEUP:false ++ rfkill_rk_sleep_bt(true); ++ printk("%s BT wake to SLEEP\r\n", __func__); ++#endif ++#endif ++ ++ return 0; ++} ++ ++static int aicbsp_sdio_resume(struct device *dev) ++{ ++ sdio_dbg("%s\n", __func__); ++ ++#if defined(CONFIG_PLATFORM_ROCKCHIP) || defined(CONFIG_PLATFORM_ROCKCHIP2) ++#ifdef CONFIG_GPIO_WAKEUP ++ //BT_SLEEP:true,BT_WAKEUP:false ++ rfkill_rk_sleep_bt(false); ++#endif ++#endif ++ ++ return 0; ++} ++ ++static const struct sdio_device_id aicbsp_sdmmc_ids[] = { ++ { SDIO_DEVICE_CLASS(SDIO_CLASS_WLAN) }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(sdio, aicbsp_sdmmc_ids); ++ ++static const struct dev_pm_ops aicbsp_sdio_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS( ++ aicbsp_sdio_suspend, aicbsp_sdio_resume) }; ++ ++static struct sdio_driver aicbsp_sdio_driver = { ++ .probe = aicbsp_sdio_probe, ++ .remove = aicbsp_sdio_remove, ++ .name = AICBSP_SDIO_NAME, ++ .id_table = aicbsp_sdmmc_ids, ++ .drv = { ++ .pm = &aicbsp_sdio_pm_ops, ++ }, ++}; ++ ++static int aicbsp_platform_power_on(void) ++{ ++ int ret = 0; ++ struct semaphore aic_chipup_sem; ++ sdio_dbg("%s\n", __func__); ++ ++#ifdef CONFIG_PLATFORM_ALLWINNER ++ if (aicbsp_bus_index < 0) ++ aicbsp_bus_index = sunxi_wlan_get_bus_index(); ++ if (aicbsp_bus_index < 0) ++ return aicbsp_bus_index; ++#endif //CONFIG_PLATFORM_ALLWINNER ++ ++#ifdef CONFIG_PLATFORM_AMLOGIC ++ extern_wifi_set_enable(0); ++ mdelay(200); ++ extern_wifi_set_enable(1); ++ mdelay(200); ++ sdio_reinit(); ++ set_power_control_lock(1); ++#endif ++ ++#ifdef CONFIG_PLATFORM_ROCKCHIP2 ++ rockchip_wifi_power(0); ++ mdelay(50); ++ rockchip_wifi_power(1); ++ mdelay(50); ++ rockchip_wifi_set_carddetect(1); ++#endif /*CONFIG_PLATFORM_ROCKCHIP2*/ ++ ++ sema_init(&aic_chipup_sem, 0); ++ ret = aicbsp_reg_sdio_notify(&aic_chipup_sem); ++ if (ret) { ++ sdio_dbg("%s aicbsp_reg_sdio_notify fail(%d)\n", __func__, ret); ++ return ret; ++ } ++ ++#ifdef CONFIG_PLATFORM_ALLWINNER ++ sunxi_wlan_set_power(0); ++ mdelay(50); ++ sunxi_wlan_set_power(1); ++ mdelay(50); ++ sunxi_mmc_rescan_card(aicbsp_bus_index); ++#endif //CONFIG_PLATFORM_ALLWINNER ++ ++ if (down_timeout(&aic_chipup_sem, msecs_to_jiffies(2000)) == 0) { ++ aicbsp_unreg_sdio_notify(); ++ if (aicbsp_load_fw_in_fdrv) { ++ printk("%s load fw in fdrv\r\n", __func__); ++ return -1; ++ } ++ return 0; ++ } ++ ++ aicbsp_unreg_sdio_notify(); ++#ifdef CONFIG_PLATFORM_ALLWINNER ++ sunxi_wlan_set_power(0); ++#endif //CONFIG_PLATFORM_ALLWINNER ++ ++#ifdef CONFIG_PLATFORM_AMLOGIC ++ extern_wifi_set_enable(0); ++#endif ++ ++#ifdef CONFIG_PLATFORM_ROCKCHIP2 ++ rockchip_wifi_power(0); ++#endif /*CONFIG_PLATFORM_ROCKCHIP2*/ ++ ++ return -1; ++} ++ ++static void aicbsp_platform_power_off(void) ++{ ++//TODO wifi disable and sdio card detection ++#ifdef CONFIG_PLATFORM_ALLWINNER ++ if (aicbsp_bus_index < 0) ++ aicbsp_bus_index = sunxi_wlan_get_bus_index(); ++ if (aicbsp_bus_index < 0) { ++ sdio_dbg("no aicbsp_bus_index\n"); ++ return; ++ } ++ sunxi_wlan_set_power(0); ++ mdelay(100); ++ sunxi_mmc_rescan_card(aicbsp_bus_index); ++#endif //CONFIG_PLATFORM_ALLWINNER ++ ++#ifdef CONFIG_PLATFORM_ROCKCHIP2 ++ rockchip_wifi_set_carddetect(0); ++ mdelay(200); ++ rockchip_wifi_power(0); ++ mdelay(200); ++#endif /*CONFIG_PLATFORM_ROCKCHIP*/ ++#ifdef CONFIG_PLATFORM_AMLOGIC ++ extern_wifi_set_enable(0); ++#endif ++ ++ sdio_dbg("%s\n", __func__); ++} ++ ++int aicbsp_sdio_init(void) ++{ ++ if (sdio_register_driver(&aicbsp_sdio_driver)) { ++ return -1; ++ } else { ++ //may add mmc_rescan here ++ } ++ if (down_timeout(&aicbsp_probe_semaphore, msecs_to_jiffies(2000)) != ++ 0) { ++ printk("%s aicbsp_sdio_probe fail\r\n", __func__); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++void aicbsp_sdio_exit(void) ++{ ++ sdio_unregister_driver(&aicbsp_sdio_driver); ++} ++ ++void aicbsp_sdio_release(struct aic_sdio_dev *sdiodev) ++{ ++ sdiodev->bus_if->state = BUS_DOWN_ST; ++ sdio_claim_host(sdiodev->func); ++ sdio_release_irq(sdiodev->func); ++ sdio_release_host(sdiodev->func); ++ if (sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ sdio_claim_host(sdiodev->func_msg); ++ sdio_release_irq(sdiodev->func_msg); ++ sdio_release_host(sdiodev->func_msg); ++ } ++} ++ ++int aicbsp_priv_aicwf_sdio_readb(struct aic_sdio_dev *sdiodev, uint regaddr, u8 *val) ++{ ++ int ret; ++ sdio_claim_host(sdiodev->func); ++ *val = sdio_readb(sdiodev->func, regaddr, &ret); ++ sdio_release_host(sdiodev->func); ++ return ret; ++} ++ ++int aicwf_sdio_readb_func2(struct aic_sdio_dev *sdiodev, uint regaddr, u8 *val) ++{ ++ int ret; ++ sdio_claim_host(sdiodev->func_msg); ++ *val = sdio_readb(sdiodev->func_msg, regaddr, &ret); ++ sdio_release_host(sdiodev->func_msg); ++ return ret; ++} ++ ++int aicbsp_priv_aicwf_sdio_writeb(struct aic_sdio_dev *sdiodev, uint regaddr, u8 val) ++{ ++ int ret; ++ sdio_claim_host(sdiodev->func); ++ sdio_writeb(sdiodev->func, val, regaddr, &ret); ++ sdio_release_host(sdiodev->func); ++ return ret; ++} ++ ++int aicwf_sdio_writeb_func2(struct aic_sdio_dev *sdiodev, uint regaddr, u8 val) ++{ ++ int ret; ++ sdio_claim_host(sdiodev->func_msg); ++ sdio_writeb(sdiodev->func_msg, val, regaddr, &ret); ++ sdio_release_host(sdiodev->func_msg); ++ return ret; ++} ++ ++int aicbsp_priv_aicwf_sdio_flow_ctrl(struct aic_sdio_dev *sdiodev) ++{ ++ int ret = -1; ++ u8 fc_reg = 0; ++ u32 count = 0; ++ ++ while (true) { ++ ret = aicbsp_priv_aicwf_sdio_readb(sdiodev, sdiodev->sdio_reg.flow_ctrl_reg, ++ &fc_reg); ++ if (ret) { ++ return -1; ++ } ++ ++ if (sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ fc_reg = fc_reg & SDIOWIFI_FLOWCTRL_MASK_REG; ++ } ++ ++ if (fc_reg != 0) { ++ ret = fc_reg; ++ return ret; ++ } else { ++ if (count >= FLOW_CTRL_RETRY_COUNT) { ++ ret = -fc_reg; ++ break; ++ } ++ count++; ++ if (count < 30) ++ udelay(200); ++ else if (count < 40) ++ mdelay(1); ++ else ++ mdelay(10); ++ } ++ } ++ ++ return ret; ++} ++ ++int aicwf_sdio_send_msg(struct aic_sdio_dev *sdiodev, u8 *buf, uint count) ++{ ++ int ret = 0; ++ ++ sdio_claim_host(sdiodev->func_msg); ++ ret = sdio_writesb(sdiodev->func_msg, 7, buf, count); ++ sdio_release_host(sdiodev->func_msg); ++ ++ return ret; ++} ++ ++int aicbsp_priv_aicwf_sdio_send_pkt(struct aic_sdio_dev *sdiodev, u8 *buf, uint count) ++{ ++ int ret = 0; ++ ++ sdio_claim_host(sdiodev->func); ++ ret = sdio_writesb(sdiodev->func, sdiodev->sdio_reg.wr_fifo_addr, buf, ++ count); ++ sdio_release_host(sdiodev->func); ++ ++ return ret; ++} ++ ++int aicbsp_priv_aicwf_sdio_recv_pkt(struct aic_sdio_dev *sdiodev, struct sk_buff *skbbuf, ++ u32 size, u8 msg) ++{ ++ int ret; ++ ++ if ((!skbbuf) || (!size)) { ++ return -EINVAL; ++ ; ++ } ++ ++ if (!msg) { ++ sdio_claim_host(sdiodev->func); ++ ret = sdio_readsb(sdiodev->func, skbbuf->data, ++ sdiodev->sdio_reg.rd_fifo_addr, size); ++ sdio_release_host(sdiodev->func); ++ } else { ++ sdio_claim_host(sdiodev->func_msg); ++ ret = sdio_readsb(sdiodev->func_msg, skbbuf->data, ++ sdiodev->sdio_reg.rd_fifo_addr, size); ++ sdio_release_host(sdiodev->func_msg); ++ } ++ ++ if (ret < 0) { ++ return ret; ++ } ++ skbbuf->len = size; ++ ++ return ret; ++} ++ ++#if defined(CONFIG_SDIO_PWRCTRL) ++int aicbsp_priv_aicwf_sdio_wakeup(struct aic_sdio_dev *sdiodev) ++{ ++ int ret = 0; ++ int read_retry; ++ int write_retry = 20; ++ int wakeup_reg_val = 0; ++ ++ if (sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ wakeup_reg_val = 1; ++ } else if (sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ wakeup_reg_val = 0x11; ++ } ++ ++ if (sdiodev->state == SDIO_SLEEP_ST) { ++ //if (sdiodev->rwnx_hw->vif_started) { ++ down(&sdiodev->pwrctl_wakeup_sema); ++ while (write_retry) { ++ ret = aicbsp_priv_aicwf_sdio_writeb(sdiodev, ++ sdiodev->sdio_reg.wakeup_reg, ++ wakeup_reg_val); ++ if (ret) { ++ txrx_err("sdio wakeup fail\n"); ++ ret = -1; ++ } else { ++ read_retry = 10; ++ while (read_retry) { ++ u8 val; ++ ret = aicbsp_priv_aicwf_sdio_readb( ++ sdiodev, ++ sdiodev->sdio_reg.sleep_reg, ++ &val); ++ if ((ret == 0) && (val & 0x10)) { ++ break; ++ } ++ read_retry--; ++ udelay(200); ++ } ++ if (read_retry != 0) ++ break; ++ } ++ sdio_dbg("write retry: %d \n", write_retry); ++ write_retry--; ++ udelay(100); ++ } ++ up(&sdiodev->pwrctl_wakeup_sema); ++ // } ++ } ++ ++ sdiodev->state = SDIO_ACTIVE_ST; ++ aicbsp_priv_aicwf_sdio_pwrctl_timer(sdiodev, sdiodev->active_duration); ++ ++ return ret; ++} ++ ++extern u8 dhcped; ++int aicbsp_priv_aicwf_sdio_sleep_allow(struct aic_sdio_dev *sdiodev) ++{ ++ int ret = 0; ++ struct aicwf_bus *bus_if = sdiodev->bus_if; ++ ++ if (bus_if->state == BUS_DOWN_ST) { ++ ret = aicbsp_priv_aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.sleep_reg, ++ 0x10); ++ if (ret) { ++ sdio_err("Write sleep fail!\n"); ++ } ++ aicbsp_priv_aicwf_sdio_pwrctl_timer(sdiodev, 0); ++ return ret; ++ } ++ ++ if (sdiodev->state == SDIO_ACTIVE_ST) { ++ { ++ sdio_dbg("s\n"); ++ ret = aicbsp_priv_aicwf_sdio_writeb( ++ sdiodev, sdiodev->sdio_reg.sleep_reg, 0x10); ++ if (ret) ++ sdio_err("Write sleep fail!\n"); ++ } ++ sdiodev->state = SDIO_SLEEP_ST; ++ aicbsp_priv_aicwf_sdio_pwrctl_timer(sdiodev, 0); ++ } else { ++ aicbsp_priv_aicwf_sdio_pwrctl_timer(sdiodev, sdiodev->active_duration); ++ } ++ ++ return ret; ++} ++ ++int aicbsp_priv_aicwf_sdio_pwr_stctl(struct aic_sdio_dev *sdiodev, uint target) ++{ ++ int ret = 0; ++ ++ if (sdiodev->bus_if->state == BUS_DOWN_ST) { ++ return -1; ++ } ++ ++ if (sdiodev->state == target) { ++ if (target == SDIO_ACTIVE_ST) { ++ aicbsp_priv_aicwf_sdio_pwrctl_timer(sdiodev, ++ sdiodev->active_duration); ++ } ++ return ret; ++ } ++ ++ switch (target) { ++ case SDIO_ACTIVE_ST: ++ aicbsp_priv_aicwf_sdio_wakeup(sdiodev); ++ break; ++ case SDIO_SLEEP_ST: ++ aicbsp_priv_aicwf_sdio_sleep_allow(sdiodev); ++ break; ++ } ++ ++ return ret; ++} ++#endif ++ ++int aicbsp_priv_aicwf_sdio_txpkt(struct aic_sdio_dev *sdiodev, struct sk_buff *pkt) ++{ ++ int ret = 0; ++ u8 *frame; ++ u32 len = 0; ++ struct aicwf_bus *bus_if = dev_get_drvdata(sdiodev->dev); ++ ++ if (bus_if->state == BUS_DOWN_ST) { ++ sdio_dbg("tx bus is down!\n"); ++ return -EINVAL; ++ } ++ ++ frame = (u8 *)(pkt->data); ++ len = pkt->len; ++ len = (len + SDIOWIFI_FUNC_BLOCKSIZE - 1) / SDIOWIFI_FUNC_BLOCKSIZE * ++ SDIOWIFI_FUNC_BLOCKSIZE; ++ ret = aicbsp_priv_aicwf_sdio_send_pkt(sdiodev, pkt->data, len); ++ if (ret) ++ sdio_err("aicbsp_priv_aicwf_sdio_send_pkt fail%d\n", ret); ++ ++ return ret; ++} ++ ++static int aicwf_sdio_intr_get_len_bytemode(struct aic_sdio_dev *sdiodev, ++ u8 *byte_len) ++{ ++ int ret = 0; ++ ++ if (!byte_len) ++ return -EBADE; ++ ++ if (sdiodev->bus_if->state == BUS_DOWN_ST) { ++ *byte_len = 0; ++ } else { ++ ret = aicbsp_priv_aicwf_sdio_readb( ++ sdiodev, sdiodev->sdio_reg.bytemode_len_reg, byte_len); ++ sdiodev->rx_priv->data_len = (*byte_len) * 4; ++ } ++ ++ return ret; ++} ++ ++static void aicwf_sdio_bus_stop(struct device *dev) ++{ ++ struct aicwf_bus *bus_if = aicbsp_get_drvdata(dev); ++ struct aic_sdio_dev *sdiodev = bus_if->bus_priv.sdio; ++ int ret; ++ ++#if defined(CONFIG_SDIO_PWRCTRL) ++ aicbsp_priv_aicwf_sdio_pwrctl_timer(sdiodev, 0); ++ sdio_dbg("%s\n", __func__); ++ if (sdiodev->pwrctl_tsk) { ++ complete_all(&sdiodev->pwrctrl_trgg); ++ kthread_stop(sdiodev->pwrctl_tsk); ++ sdiodev->pwrctl_tsk = NULL; ++ } ++#endif ++ bus_if->state = BUS_DOWN_ST; ++ ret = down_interruptible(&sdiodev->tx_priv->txctl_sema); ++ if (ret) ++ sdio_err("down txctl_sema fail\n"); ++ ++#if defined(CONFIG_SDIO_PWRCTRL) ++ aicbsp_priv_aicwf_sdio_pwr_stctl(sdiodev, SDIO_SLEEP_ST); ++#endif ++ if (!ret) ++ up(&sdiodev->tx_priv->txctl_sema); ++ aicbsp_priv_aicwf_frame_queue_flush(&sdiodev->tx_priv->txq); ++} ++ ++struct sk_buff *aicbsp_priv_aicwf_sdio_readframes(struct aic_sdio_dev *sdiodev, u8 msg) ++{ ++ int ret = 0; ++ u32 size = 0; ++ struct sk_buff *skb = NULL; ++ struct aicwf_bus *bus_if = dev_get_drvdata(sdiodev->dev); ++ ++ if (bus_if->state == BUS_DOWN_ST) { ++ sdio_dbg("bus down\n"); ++ return NULL; ++ } ++ ++ size = sdiodev->rx_priv->data_len; ++ skb = __dev_alloc_skb(size, GFP_KERNEL); ++ if (!skb) { ++ return NULL; ++ } ++ ++ ret = aicbsp_priv_aicwf_sdio_recv_pkt(sdiodev, skb, size, msg); ++ if (ret) { ++ dev_kfree_skb(skb); ++ skb = NULL; ++ } ++ ++ return skb; ++} ++ ++static int aicwf_sdio_tx_msg(struct aic_sdio_dev *sdiodev) ++{ ++ int err = 0; ++ u16 len; ++ u8 *payload = sdiodev->tx_priv->cmd_buf; ++ u16 payload_len = sdiodev->tx_priv->cmd_len; ++ u8 adjust_str[4] = { 0, 0, 0, 0 }; ++ int adjust_len = 0; ++ int buffer_cnt = 0; ++ u8 retry = 0; ++ ++ len = payload_len; ++ if ((len % TX_ALIGNMENT) != 0) { ++ adjust_len = roundup(len, TX_ALIGNMENT); ++ memcpy(payload + payload_len, adjust_str, (adjust_len - len)); ++ payload_len += (adjust_len - len); ++ } ++ len = payload_len; ++ ++ //link tail is necessary ++ if ((len % SDIOWIFI_FUNC_BLOCKSIZE) != 0) { ++ memset(payload + payload_len, 0, TAIL_LEN); ++ payload_len += TAIL_LEN; ++ len = (payload_len / SDIOWIFI_FUNC_BLOCKSIZE + 1) * ++ SDIOWIFI_FUNC_BLOCKSIZE; ++ } else ++ len = payload_len; ++ ++ if (sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ buffer_cnt = aicbsp_priv_aicwf_sdio_flow_ctrl(sdiodev); ++ while ((buffer_cnt <= 0 || ++ (buffer_cnt > 0 && len > (buffer_cnt * BUFFER_SIZE))) && ++ retry < 10) { ++ retry++; ++ buffer_cnt = aicbsp_priv_aicwf_sdio_flow_ctrl(sdiodev); ++ printk("buffer_cnt = %d\n", buffer_cnt); ++ } ++ } ++ down(&sdiodev->tx_priv->cmd_txsema); ++ ++ if (sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ if (buffer_cnt > 0 && len < (buffer_cnt * BUFFER_SIZE)) { ++ err = aicbsp_priv_aicwf_sdio_send_pkt(sdiodev, payload, len); ++ if (err) { ++ sdio_err("aicbsp_priv_aicwf_sdio_send_pkt fail%d\n", err); ++ } ++ } else { ++ sdio_err("tx msg fc retry fail:%d, %d\n", buffer_cnt, ++ len); ++ up(&sdiodev->tx_priv->cmd_txsema); ++ return -1; ++ } ++ } else if (sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ err = aicwf_sdio_send_msg(sdiodev, payload, len); ++ if (err) { ++ sdio_err("aicbsp_priv_aicwf_sdio_send_pkt fail%d\n", err); ++ } ++ } else { ++ sdio_err("tx msg fc retry fail:%d, %d\n", buffer_cnt, len); ++ up(&sdiodev->tx_priv->cmd_txsema); ++ return -1; ++ } ++ ++ sdiodev->tx_priv->cmd_txstate = false; ++ if (!err) ++ sdiodev->tx_priv->cmd_tx_succ = true; ++ else ++ sdiodev->tx_priv->cmd_tx_succ = false; ++ ++ up(&sdiodev->tx_priv->cmd_txsema); ++ ++ return err; ++} ++ ++static void aicwf_sdio_tx_process(struct aic_sdio_dev *sdiodev) ++{ ++ int err = 0; ++ ++ if (sdiodev->bus_if->state == BUS_DOWN_ST) { ++ sdio_err("Bus is down\n"); ++ return; ++ } ++ ++#if defined(CONFIG_SDIO_PWRCTRL) ++ aicbsp_priv_aicwf_sdio_pwr_stctl(sdiodev, SDIO_ACTIVE_ST); ++#endif ++ ++ //config ++ sdio_info("send cmd\n"); ++ if (sdiodev->tx_priv->cmd_txstate) { ++ if (down_interruptible(&sdiodev->tx_priv->txctl_sema)) { ++ txrx_err("txctl down bus->txctl_sema fail\n"); ++ return; ++ } ++ if (sdiodev->state != SDIO_ACTIVE_ST) { ++ txrx_err("state err\n"); ++ up(&sdiodev->tx_priv->txctl_sema); ++ txrx_err("txctl up bus->txctl_sema fail\n"); ++ return; ++ } ++ ++ err = aicwf_sdio_tx_msg(sdiodev); ++ up(&sdiodev->tx_priv->txctl_sema); ++ if (waitqueue_active(&sdiodev->tx_priv->cmd_txdone_wait)) ++ wake_up(&sdiodev->tx_priv->cmd_txdone_wait); ++ } ++ ++ //data ++ sdio_info("send data\n"); ++ if (down_interruptible(&sdiodev->tx_priv->txctl_sema)) { ++ txrx_err("txdata down bus->txctl_sema\n"); ++ return; ++ } ++ ++ if (sdiodev->state != SDIO_ACTIVE_ST) { ++ txrx_err("sdio state err\n"); ++ up(&sdiodev->tx_priv->txctl_sema); ++ return; ++ } ++ ++ if (!aicbsp_priv_aicwf_is_framequeue_empty(&sdiodev->tx_priv->txq)) ++ sdiodev->tx_priv->fw_avail_bufcnt = ++ aicbsp_priv_aicwf_sdio_flow_ctrl(sdiodev); ++ while (!aicbsp_priv_aicwf_is_framequeue_empty(&sdiodev->tx_priv->txq)) { ++ aicbsp_priv_aicwf_sdio_send(sdiodev->tx_priv); ++ if (sdiodev->tx_priv->cmd_txstate) ++ break; ++ } ++ ++ up(&sdiodev->tx_priv->txctl_sema); ++} ++ ++static int aicwf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt) ++{ ++ uint prio; ++ int ret = -EBADE; ++ struct aicwf_bus *bus_if = dev_get_drvdata(dev); ++ struct aic_sdio_dev *sdiodev = bus_if->bus_priv.sdio; ++ ++ prio = (pkt->priority & 0x7); ++ spin_lock_bh(&sdiodev->tx_priv->txqlock); ++ if (!aicbsp_priv_aicwf_frame_enq(sdiodev->dev, &sdiodev->tx_priv->txq, pkt, prio)) { ++ spin_unlock_bh(&sdiodev->tx_priv->txqlock); ++ return -ENOSR; ++ } else { ++ ret = 0; ++ } ++ ++ if (bus_if->state != BUS_UP_ST) { ++ sdio_err("bus_if stopped\n"); ++ spin_unlock_bh(&sdiodev->tx_priv->txqlock); ++ return -1; ++ } ++ ++ atomic_inc(&sdiodev->tx_priv->tx_pktcnt); ++ spin_unlock_bh(&sdiodev->tx_priv->txqlock); ++ complete(&bus_if->bustx_trgg); ++ ++ return ret; ++} ++ ++static int aicwf_sdio_bus_txmsg(struct device *dev, u8 *msg, uint msglen) ++{ ++ int ret = -1; ++ struct aicwf_bus *bus_if = dev_get_drvdata(dev); ++ struct aic_sdio_dev *sdiodev = bus_if->bus_priv.sdio; ++ ++ down(&sdiodev->tx_priv->cmd_txsema); ++ sdiodev->tx_priv->cmd_txstate = true; ++ sdiodev->tx_priv->cmd_tx_succ = false; ++ sdiodev->tx_priv->cmd_buf = msg; ++ sdiodev->tx_priv->cmd_len = msglen; ++ up(&sdiodev->tx_priv->cmd_txsema); ++ ++ if (bus_if->state != BUS_UP_ST) { ++ sdio_err("bus has stop\n"); ++ return -1; ++ } ++ ++ complete(&bus_if->bustx_trgg); ++ ++ if (sdiodev->tx_priv->cmd_txstate) { ++ int timeout = msecs_to_jiffies(CMD_TX_TIMEOUT); ++ ret = wait_event_timeout(sdiodev->tx_priv->cmd_txdone_wait, ++ !(sdiodev->tx_priv->cmd_txstate), ++ timeout); ++ } ++ ++ if (!sdiodev->tx_priv->cmd_txstate && sdiodev->tx_priv->cmd_tx_succ) { ++ ret = 0; ++ } else { ++ sdio_err("send faild:%d, %d,%x\n", ++ sdiodev->tx_priv->cmd_txstate, ++ sdiodev->tx_priv->cmd_tx_succ, ret); ++ ret = -EIO; ++ } ++ ++ return ret; ++} ++ ++int aicbsp_priv_aicwf_sdio_send(struct aicwf_tx_priv *tx_priv) ++{ ++ struct sk_buff *pkt; ++ struct aic_sdio_dev *sdiodev = tx_priv->sdiodev; ++ u16 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)) || ++ ((atomic_read(&tx_priv->aggr_count) != 0) && (aggr_len == 0))) { ++ if (aggr_len > 0) ++ aicbsp_priv_aicwf_sdio_aggrbuf_reset(tx_priv); ++ goto done; ++ } ++ ++ if (tx_priv->fw_avail_bufcnt <= 0) { //flow control failed ++ tx_priv->fw_avail_bufcnt = aicbsp_priv_aicwf_sdio_flow_ctrl(sdiodev); ++ while (tx_priv->fw_avail_bufcnt <= 0 && ++ retry_times < max_retry_times) { ++ retry_times++; ++ tx_priv->fw_avail_bufcnt = ++ aicbsp_priv_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) > 0) { ++ tx_priv->fw_avail_bufcnt -= ++ atomic_read(&tx_priv->aggr_count); ++ aicbsp_priv_aicwf_sdio_aggr_send( ++ tx_priv); //send and check the next pkt; ++ } ++ } else { ++ spin_lock_bh(&sdiodev->tx_priv->txqlock); ++ pkt = aicbsp_priv_aicwf_frame_dequeue(&sdiodev->tx_priv->txq); ++ if (pkt == NULL) { ++ sdio_err("txq no pkt\n"); ++ spin_unlock_bh(&sdiodev->tx_priv->txqlock); ++ goto done; ++ } ++ atomic_dec(&sdiodev->tx_priv->tx_pktcnt); ++ spin_unlock_bh(&sdiodev->tx_priv->txqlock); ++ ++ if (tx_priv == NULL || tx_priv->tail == NULL || pkt == NULL) ++ txrx_err("null error\n"); ++ if (aicbsp_priv_aicwf_sdio_aggr(tx_priv, pkt)) { ++ aicbsp_priv_aicwf_sdio_aggrbuf_reset(tx_priv); ++ sdio_err("add aggr pkts failed!\n"); ++ goto done; ++ } ++ ++ //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! ++ tx_priv->fw_avail_bufcnt -= ++ atomic_read(&tx_priv->aggr_count); ++ aicbsp_priv_aicwf_sdio_aggr_send(tx_priv); ++ } else ++ goto done; ++ } ++ ++done: ++ return 0; ++} ++ ++int aicbsp_priv_aicwf_sdio_aggr(struct aicwf_tx_priv *tx_priv, struct sk_buff *pkt) ++{ ++ //struct rwnx_txhdr *txhdr = (struct rwnx_txhdr *)pkt->data; ++ u8 *start_ptr = tx_priv->tail; ++ u8 sdio_header[4]; ++ u8 adjust_str[4] = { 0, 0, 0, 0 }; ++ u16 curr_len = 0; ++ int allign_len = 0; ++ ++ //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 ++ if (tx_priv->sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ tx_priv->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ tx_priv->sdiodev->chipid == PRODUCT_ID_AIC8800DW) ++ sdio_header[3] = 0; //reserved ++ else if (tx_priv->sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ tx_priv->sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) ++ sdio_header[3] = aicbsp_priv_crc8_ponl_107(&sdio_header[0], 3); // crc8 ++ ++ memcpy(tx_priv->tail, (u8 *)&sdio_header, sizeof(sdio_header)); ++ tx_priv->tail += sizeof(sdio_header); ++ //payload ++ //memcpy(tx_priv->tail, (u8 *)(long)&txhdr->sw_hdr->desc, sizeof(struct txdesc_api)); ++ //tx_priv->tail += sizeof(struct txdesc_api); //hostdesc ++ //memcpy(tx_priv->tail, (u8 *)((u8 *)txhdr + txhdr->sw_hdr->headroom), pkt->len-txhdr->sw_hdr->headroom); ++ //tx_priv->tail += (pkt->len - txhdr->sw_hdr->headroom); ++ ++ //word alignment ++ curr_len = tx_priv->tail - tx_priv->head; ++ if (curr_len & (TX_ALIGNMENT - 1)) { ++ allign_len = roundup(curr_len, TX_ALIGNMENT) - curr_len; ++ memcpy(tx_priv->tail, adjust_str, allign_len); ++ tx_priv->tail += allign_len; ++ } ++ ++ if (tx_priv->sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ tx_priv->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ tx_priv->sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ start_ptr[0] = ((tx_priv->tail - start_ptr - 4) & 0xff); ++ start_ptr[1] = (((tx_priv->tail - start_ptr - 4) >> 8) & 0x0f); ++ } ++ ++ tx_priv->aggr_buf->dev = pkt->dev; ++ ++#if 0 ++ if (!txhdr->sw_hdr->need_cfm) { ++ kmem_cache_free(txhdr->sw_hdr->rwnx_vif->rwnx_hw->sw_txhdr_cache, txhdr->sw_hdr); ++ skb_pull(pkt, txhdr->sw_hdr->headroom); ++ consume_skb(pkt); ++ } ++#endif ++ ++ consume_skb(pkt); ++ atomic_inc(&tx_priv->aggr_count); ++ return 0; ++} ++ ++void aicbsp_priv_aicwf_sdio_aggr_send(struct aicwf_tx_priv *tx_priv) ++{ ++ struct sk_buff *tx_buf = tx_priv->aggr_buf; ++ int ret = 0; ++ int curr_len = 0; ++ ++ //link tail is necessary ++ curr_len = tx_priv->tail - tx_priv->head; ++ if ((curr_len % TXPKT_BLOCKSIZE) != 0) { ++ memset(tx_priv->tail, 0, TAIL_LEN); ++ tx_priv->tail += TAIL_LEN; ++ } ++ ++ tx_buf->len = tx_priv->tail - tx_priv->head; ++ ret = aicbsp_priv_aicwf_sdio_txpkt(tx_priv->sdiodev, tx_buf); ++ if (ret < 0) { ++ sdio_err("fail to send aggr pkt!\n"); ++ } ++ ++ aicbsp_priv_aicwf_sdio_aggrbuf_reset(tx_priv); ++} ++ ++void aicbsp_priv_aicwf_sdio_aggrbuf_reset(struct aicwf_tx_priv *tx_priv) ++{ ++ struct sk_buff *aggr_buf = tx_priv->aggr_buf; ++ ++ tx_priv->tail = tx_priv->head; ++ aggr_buf->len = 0; ++ atomic_set(&tx_priv->aggr_count, 0); ++} ++ ++static int aicwf_sdio_bus_start(struct device *dev) ++{ ++ struct aicwf_bus *bus_if = dev_get_drvdata(dev); ++ struct aic_sdio_dev *sdiodev = bus_if->bus_priv.sdio; ++ int ret = 0; ++ ++ if (sdiodev->chipid == PRODUCT_ID_AIC8801) { ++ sdio_claim_host(sdiodev->func); ++ sdio_claim_irq(sdiodev->func, aicbsp_priv_aicwf_sdio_hal_irqhandler); ++ //enable sdio interrupt ++ ret = aicbsp_priv_aicwf_sdio_writeb( ++ sdiodev, sdiodev->sdio_reg.intr_config_reg, 0x07); ++ if (ret != 0) ++ sdio_err("intr register failed:%d\n", ret); ++ sdio_release_host(sdiodev->func); ++ } else if (sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ sdio_claim_host(sdiodev->func); ++ ++ //since we have func2 we don't register irq handler ++ sdio_claim_irq(sdiodev->func, NULL); ++ sdio_claim_irq(sdiodev->func_msg, NULL); ++ ++ sdiodev->func->irq_handler = ++ (sdio_irq_handler_t *)aicbsp_priv_aicwf_sdio_hal_irqhandler; ++ sdiodev->func_msg->irq_handler = ++ (sdio_irq_handler_t *)aicwf_sdio_hal_irqhandler_func2; ++ sdio_release_host(sdiodev->func); ++ ++ //enable sdio interrupt ++ ret = aicbsp_priv_aicwf_sdio_writeb( ++ sdiodev, sdiodev->sdio_reg.intr_config_reg, 0x07); ++ ++ if (ret != 0) ++ sdio_err("intr register failed:%d\n", ret); ++ ++ //enable sdio interrupt ++ ret = aicwf_sdio_writeb_func2( ++ sdiodev, sdiodev->sdio_reg.intr_config_reg, 0x07); ++ ++ if (ret != 0) ++ sdio_err("func2 intr register failed:%d\n", ret); ++ } else if (sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ sdio_claim_host(sdiodev->func); ++ sdio_claim_irq(sdiodev->func, aicbsp_priv_aicwf_sdio_hal_irqhandler); ++ ++ sdio_f0_writeb(sdiodev->func, 0x07, 0x04, &ret); ++ if (ret) { ++ sdio_err("set func0 int en fail %d\n", ret); ++ } ++ sdio_release_host(sdiodev->func); ++ //enable sdio interrupt ++ ret = aicbsp_priv_aicwf_sdio_writeb( ++ sdiodev, sdiodev->sdio_reg.intr_config_reg, 0x07); ++ if (ret != 0) ++ sdio_err("intr register failed:%d\n", ret); ++ } ++ ++ bus_if->state = BUS_UP_ST; ++ return ret; ++} ++ ++int aicwf_sdio_bustx_thread(void *data) ++{ ++ struct aicwf_bus *bus = (struct aicwf_bus *)data; ++ struct aic_sdio_dev *sdiodev = bus->bus_priv.sdio; ++ ++ while (1) { ++ if (kthread_should_stop()) { ++ sdio_err("sdio bustx thread stop\n"); ++ break; ++ } ++ if (!wait_for_completion_interruptible(&bus->bustx_trgg)) { ++ if ((int)(atomic_read(&sdiodev->tx_priv->tx_pktcnt) > ++ 0) || ++ (sdiodev->tx_priv->cmd_txstate == true)) ++ aicwf_sdio_tx_process(sdiodev); ++ } ++ } ++ ++ return 0; ++} ++ ++int aicwf_sdio_busrx_thread(void *data) ++{ ++ struct aicwf_rx_priv *rx_priv = (struct aicwf_rx_priv *)data; ++ struct aicwf_bus *bus_if = rx_priv->sdiodev->bus_if; ++ ++ while (1) { ++ if (kthread_should_stop()) { ++ sdio_err("sdio busrx thread stop\n"); ++ break; ++ } ++ if (!wait_for_completion_interruptible(&bus_if->busrx_trgg)) { ++ aicbsp_priv_aicwf_process_rxframes(rx_priv); ++ } ++ } ++ ++ return 0; ++} ++ ++#if defined(CONFIG_SDIO_PWRCTRL) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++static void aicwf_sdio_bus_pwrctl(struct timer_list *t) ++{ ++ struct aic_sdio_dev *sdiodev = timer_container_of(sdiodev, t, timer); ++#else ++static void aicwf_sdio_bus_pwrctl(ulong data) ++{ ++ struct aic_sdio_dev *sdiodev = (struct aic_sdio_dev *)data; ++#endif ++ if (sdiodev->bus_if->state == BUS_DOWN_ST) { ++ sdio_err("bus down\n"); ++ return; ++ } ++ ++ if (sdiodev->pwrctl_tsk) { ++ complete(&sdiodev->pwrctrl_trgg); ++ } ++} ++#endif ++ ++static void aicwf_sdio_enq_rxpkt(struct aic_sdio_dev *sdiodev, ++ struct sk_buff *pkt) ++{ ++ struct aicwf_rx_priv *rx_priv = sdiodev->rx_priv; ++ unsigned long flags = 0; ++ ++ spin_lock_irqsave(&rx_priv->rxqlock, flags); ++ if (!aicbsp_priv_aicwf_rxframe_enqueue(sdiodev->dev, &rx_priv->rxq, pkt)) { ++ spin_unlock_irqrestore(&rx_priv->rxqlock, flags); ++ aicbsp_priv_aicwf_dev_skb_free(pkt); ++ return; ++ } ++ spin_unlock_irqrestore(&rx_priv->rxqlock, flags); ++ ++ atomic_inc(&rx_priv->rx_cnt); ++} ++ ++#define SDIO_OTHER_INTERRUPT (0x1ul << 7) ++ ++void aicbsp_priv_aicwf_sdio_hal_irqhandler(struct sdio_func *func) ++{ ++ struct aicwf_bus *bus_if = dev_get_drvdata(&func->dev); ++ struct aic_sdio_dev *sdiodev = bus_if->bus_priv.sdio; ++ u8 intstatus = 0; ++ u8 byte_len = 0; ++ struct sk_buff *pkt = NULL; ++ int ret; ++ ++ //AICWFDBG(LOGDEBUG,"%s bsp enter \r\n", __func__); ++ ++ if (aicbsp_sdiodev->sdio_hal_irqhandler) { ++ aicbsp_sdiodev->sdio_hal_irqhandler(func); ++ return; ++ } ++ ++ if (!bus_if || bus_if->state == BUS_DOWN_ST) { ++ sdio_err("bus err\n"); ++ return; ++ } ++ ++ if (sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ ret = aicbsp_priv_aicwf_sdio_readb(sdiodev, sdiodev->sdio_reg.block_cnt_reg, ++ &intstatus); ++ ++ while (intstatus) { ++ sdiodev->rx_priv->data_len = ++ intstatus * SDIOWIFI_FUNC_BLOCKSIZE; ++ if (intstatus > 0) { ++ if (intstatus < 64) { ++ pkt = aicbsp_priv_aicwf_sdio_readframes(sdiodev, 0); ++ } else { ++ aicwf_sdio_intr_get_len_bytemode( ++ sdiodev, ++ &byte_len); //byte_len must<= 128 ++ sdio_info("byte mode len=%d\r\n", ++ byte_len); ++ pkt = aicbsp_priv_aicwf_sdio_readframes(sdiodev, 0); ++ } ++ } else { ++#ifndef CONFIG_PLATFORM_ALLWINNER ++ sdio_err("Interrupt but no data\n"); ++#endif ++ } ++ ++ if (pkt) ++ aicwf_sdio_enq_rxpkt(sdiodev, pkt); ++ ++ ret = aicbsp_priv_aicwf_sdio_readb(sdiodev, ++ sdiodev->sdio_reg.block_cnt_reg, ++ &intstatus); ++ } ++ } else if (sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ do { ++ ret = aicbsp_priv_aicwf_sdio_readb( ++ sdiodev, sdiodev->sdio_reg.misc_int_status_reg, ++ &intstatus); ++ if (!ret) { ++ break; ++ } ++ sdio_err("ret=%d, intstatus=%x\r\n", ret, intstatus); ++ } while (1); ++ if (intstatus & SDIO_OTHER_INTERRUPT) { ++ u8 int_pending; ++ ret = aicbsp_priv_aicwf_sdio_readb(sdiodev, ++ sdiodev->sdio_reg.sleep_reg, ++ &int_pending); ++ if (ret < 0) { ++ sdio_err("reg:%d read failed!\n", ++ sdiodev->sdio_reg.sleep_reg); ++ } ++ int_pending &= ~0x01; // dev to host soft irq ++ ret = aicbsp_priv_aicwf_sdio_writeb(sdiodev, ++ sdiodev->sdio_reg.sleep_reg, ++ int_pending); ++ if (ret < 0) { ++ sdio_err("reg:%d write failed!\n", ++ sdiodev->sdio_reg.sleep_reg); ++ } ++ } ++ ++ if (intstatus > 0) { ++ uint8_t intmaskf2 = intstatus | (0x1UL << 3); ++ if (intmaskf2 > 120U) { // func2 ++ if (intmaskf2 == 127U) { // byte mode ++ //aicwf_sdio_intr_get_len_bytemode(sdiodev, &byte_len, 1);//byte_len must<= 128 ++ aicwf_sdio_intr_get_len_bytemode( ++ sdiodev, ++ &byte_len); //byte_len must<= 128 ++ sdio_info("byte mode len=%d\r\n", ++ byte_len); ++ pkt = aicbsp_priv_aicwf_sdio_readframes(sdiodev, 1); ++ } else { // block mode ++ sdiodev->rx_priv->data_len = ++ (intstatus & 0x7U) * ++ SDIOWIFI_FUNC_BLOCKSIZE; ++ pkt = aicbsp_priv_aicwf_sdio_readframes(sdiodev, 1); ++ } ++ } else { // func1 ++ if (intstatus == 120U) { // byte mode ++ //aicwf_sdio_intr_get_len_bytemode(sdiodev, &byte_len, 0);//byte_len must<= 128 ++ aicwf_sdio_intr_get_len_bytemode( ++ sdiodev, ++ &byte_len); //byte_len must<= 128 ++ sdio_info("byte mode len=%d\r\n", ++ byte_len); ++ pkt = aicbsp_priv_aicwf_sdio_readframes(sdiodev, 0); ++ } else { // block mode ++ sdiodev->rx_priv->data_len = ++ (intstatus & 0x7FU) * ++ SDIOWIFI_FUNC_BLOCKSIZE; ++ pkt = aicbsp_priv_aicwf_sdio_readframes(sdiodev, 0); ++ } ++ } ++ } else { ++#ifndef CONFIG_PLATFORM_ALLWINNER ++ sdio_err("Interrupt but no data\n"); ++#endif ++ } ++ ++ if (pkt) ++ aicwf_sdio_enq_rxpkt(sdiodev, pkt); ++ } ++ ++ complete(&bus_if->busrx_trgg); ++} ++ ++void aicwf_sdio_hal_irqhandler_func2(struct sdio_func *func) ++{ ++ struct aicwf_bus *bus_if = dev_get_drvdata(&func->dev); ++ struct aic_sdio_dev *sdiodev = bus_if->bus_priv.sdio; ++ u8 intstatus = 0; ++ u8 byte_len = 0; ++#ifdef CONFIG_PREALLOC_RX_SKB ++ struct rx_buff *pkt = NULL; ++#else ++ struct sk_buff *pkt = NULL; ++#endif ++ int ret; ++ ++ if (!bus_if || bus_if->state == BUS_DOWN_ST) { ++ sdio_err("bus err\n"); ++ return; ++ } ++ ++#ifdef CONFIG_PREALLOC_RX_SKB ++ if (list_empty(&aic_rx_buff_list.rxbuff_list)) { ++ printk("%s %d, rxbuff list is empty\n", __func__, __LINE__); ++ return; ++ } ++#endif ++ ++ ret = aicwf_sdio_readb_func2(sdiodev, sdiodev->sdio_reg.block_cnt_reg, ++ &intstatus); ++ ++ while (intstatus) { ++ sdiodev->rx_priv->data_len = ++ intstatus * SDIOWIFI_FUNC_BLOCKSIZE; ++ if (intstatus > 0) { ++ if (intstatus < 64) { ++ pkt = aicbsp_priv_aicwf_sdio_readframes(sdiodev, 1); ++ } else { ++ sdio_info("byte mode len=%d\r\n", byte_len); ++ ++ aicwf_sdio_intr_get_len_bytemode( ++ sdiodev, ++ &byte_len); //byte_len must<= 128 ++ pkt = aicbsp_priv_aicwf_sdio_readframes(sdiodev, 1); ++ } ++ } else { ++#ifndef CONFIG_PLATFORM_ALLWINNER ++ sdio_err("Interrupt but no data\n"); ++#endif ++ } ++ ++ if (pkt) { ++ aicwf_sdio_enq_rxpkt(sdiodev, pkt); ++ } ++ ret = aicwf_sdio_readb_func2( ++ sdiodev, sdiodev->sdio_reg.block_cnt_reg, &intstatus); ++ } ++ ++ complete(&bus_if->busrx_trgg); ++} ++ ++#if defined(CONFIG_SDIO_PWRCTRL) ++void aicbsp_priv_aicwf_sdio_pwrctl_timer(struct aic_sdio_dev *sdiodev, uint duration) ++{ ++ uint timeout; ++ ++ if (sdiodev->bus_if->state == BUS_DOWN_ST && duration) ++ return; ++ ++ spin_lock_bh(&sdiodev->pwrctl_lock); ++ if (!duration) { ++ if (timer_pending(&sdiodev->timer)) ++ timer_delete_sync(&sdiodev->timer); ++ } else { ++ sdiodev->active_duration = duration; ++ timeout = msecs_to_jiffies(sdiodev->active_duration); ++ mod_timer(&sdiodev->timer, jiffies + timeout); ++ } ++ spin_unlock_bh(&sdiodev->pwrctl_lock); ++} ++#endif ++ ++static struct aicwf_bus_ops aicwf_sdio_bus_ops = { ++ .stop = aicwf_sdio_bus_stop, ++ .start = aicwf_sdio_bus_start, ++ .txdata = aicwf_sdio_bus_txdata, ++ .txmsg = aicwf_sdio_bus_txmsg, ++}; ++ ++void aicwf_sdio_release_func2(struct aic_sdio_dev *sdiodev) ++{ ++ int ret = 0; ++ sdio_dbg("%s\n", __func__); ++ sdio_claim_host(sdiodev->func_msg); ++ //disable sdio interrupt ++ ret = aicwf_sdio_writeb_func2(sdiodev, ++ sdiodev->sdio_reg.intr_config_reg, 0x0); ++ if (ret < 0) { ++ sdio_err("reg:%d write failed!\n", ++ sdiodev->sdio_reg.intr_config_reg); ++ } ++ sdio_release_irq(sdiodev->func_msg); ++ sdio_release_host(sdiodev->func_msg); ++} ++ ++void aicbsp_priv_aicwf_sdio_release(struct aic_sdio_dev *sdiodev) ++{ ++ struct aicwf_bus *bus_if = NULL; ++ struct aicwf_bus *bus_if_t = NULL; ++ int ret = 0; ++ ++ sdio_dbg("%s\n", __func__); ++ if (sdiodev->func == NULL) { ++ printk("%s, NULL sdio func\n", __func__); ++ return; ++ } ++ ++ bus_if = aicbsp_get_drvdata(sdiodev->dev); ++ if (bus_if) ++ bus_if->state = BUS_DOWN_ST; ++ ++ bus_if_t = dev_get_drvdata(sdiodev->dev); ++ ++ if ((bus_if_t != NULL) && (sdiodev->bus_if == bus_if_t)) { ++ sdio_dbg("%s bsp release\n", __func__); ++ sdio_claim_host(sdiodev->func); ++ //disable sdio interrupt ++ ret = aicbsp_priv_aicwf_sdio_writeb(sdiodev, ++ sdiodev->sdio_reg.intr_config_reg, 0x0); ++ if (ret < 0) { ++ sdio_err("reg:%d write failed!, ret=%d\n", ++ sdiodev->sdio_reg.intr_config_reg, ret); ++ } ++ sdio_release_irq(sdiodev->func); ++ sdio_release_host(sdiodev->func); ++ } ++ ++ if (sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ aicwf_sdio_release_func2(sdiodev); ++ } ++ ++ if (sdiodev->dev) ++ aicbsp_priv_aicwf_bus_deinit(sdiodev->dev); ++ ++ if (sdiodev->tx_priv) ++ aicbsp_priv_aicwf_tx_deinit(sdiodev->tx_priv); ++ ++ if (sdiodev->rx_priv) ++ aicbsp_priv_aicwf_rx_deinit(sdiodev->rx_priv); ++ ++ aicbsp_priv_rwnx_cmd_mgr_deinit(&sdiodev->cmd_mgr); ++} ++ ++void aicbsp_priv_aicwf_sdio_reg_init(struct aic_sdio_dev *sdiodev) ++{ ++ sdio_dbg("%s\n", __func__); ++ ++ if (sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ sdiodev->sdio_reg.bytemode_len_reg = SDIOWIFI_BYTEMODE_LEN_REG; ++ sdiodev->sdio_reg.intr_config_reg = SDIOWIFI_INTR_CONFIG_REG; ++ sdiodev->sdio_reg.sleep_reg = SDIOWIFI_SLEEP_REG; ++ sdiodev->sdio_reg.wakeup_reg = SDIOWIFI_WAKEUP_REG; ++ sdiodev->sdio_reg.flow_ctrl_reg = SDIOWIFI_FLOW_CTRL_REG; ++ sdiodev->sdio_reg.register_block = SDIOWIFI_REGISTER_BLOCK; ++ sdiodev->sdio_reg.bytemode_enable_reg = ++ SDIOWIFI_BYTEMODE_ENABLE_REG; ++ sdiodev->sdio_reg.block_cnt_reg = SDIOWIFI_BLOCK_CNT_REG; ++ sdiodev->sdio_reg.rd_fifo_addr = SDIOWIFI_RD_FIFO_ADDR; ++ sdiodev->sdio_reg.wr_fifo_addr = SDIOWIFI_WR_FIFO_ADDR; ++ } else if (sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ sdiodev->sdio_reg.bytemode_len_reg = ++ SDIOWIFI_BYTEMODE_LEN_REG_V3; ++ sdiodev->sdio_reg.intr_config_reg = SDIOWIFI_INTR_ENABLE_REG_V3; ++ sdiodev->sdio_reg.sleep_reg = SDIOWIFI_INTR_PENDING_REG_V3; ++ sdiodev->sdio_reg.wakeup_reg = SDIOWIFI_INTR_TO_DEVICE_REG_V3; ++ sdiodev->sdio_reg.flow_ctrl_reg = SDIOWIFI_FLOW_CTRL_Q1_REG_V3; ++ sdiodev->sdio_reg.bytemode_enable_reg = ++ SDIOWIFI_BYTEMODE_ENABLE_REG_V3; ++ sdiodev->sdio_reg.misc_int_status_reg = ++ SDIOWIFI_MISC_INT_STATUS_REG_V3; ++ sdiodev->sdio_reg.rd_fifo_addr = SDIOWIFI_RD_FIFO_ADDR_V3; ++ sdiodev->sdio_reg.wr_fifo_addr = SDIOWIFI_WR_FIFO_ADDR_V3; ++ } ++} ++ ++int aicbsp_priv_aicwf_sdio_func_init(struct aic_sdio_dev *sdiodev) ++{ ++ struct mmc_host *host; ++ u8 block_bit0 = 0x1; ++ u8 byte_mode_disable = 0x1; //1: no byte mode ++ int ret = 0; ++ struct aicbsp_feature_t feature; ++ ++ aicbsp_get_feature(&feature, NULL); ++ aicbsp_priv_aicwf_sdio_reg_init(sdiodev); ++ ++ host = sdiodev->func->card->host; ++ ++ sdio_claim_host(sdiodev->func); ++#if 0 //SDIO PHASE SETTING ++ sdiodev->func->card->quirks |= MMC_QUIRK_LENIENT_FN0; ++ sdio_f0_writeb(sdiodev->func, feature.sdio_phase, 0x13, &ret); ++ if (ret < 0) { ++ sdio_err("write func0 fail %d\n", ret); ++ sdio_release_host(sdiodev->func); ++ return ret; ++ } ++#endif ++ ++ ret = sdio_set_block_size(sdiodev->func, SDIOWIFI_FUNC_BLOCKSIZE); ++ if (ret < 0) { ++ sdio_err("set blocksize fail %d\n", ret); ++ sdio_release_host(sdiodev->func); ++ return ret; ++ } ++ ret = sdio_enable_func(sdiodev->func); ++ if (ret < 0) { ++ sdio_err("enable func fail %d.\n", ret); ++ sdio_release_host(sdiodev->func); ++ return ret; ++ } ++ udelay(100); ++#if 1 //SDIO CLOCK SETTING ++ if (feature.sdio_clock > 0) { ++ host->ios.clock = feature.sdio_clock; ++ host->ops->set_ios(host, &host->ios); ++ sdio_dbg("Set SDIO Clock %d MHz\n", host->ios.clock / 1000000); ++ } ++#endif ++ sdio_release_host(sdiodev->func); ++ ++ if (sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ sdio_claim_host(sdiodev->func_msg); ++ ++ //set sdio blocksize ++ ret = sdio_set_block_size(sdiodev->func_msg, ++ SDIOWIFI_FUNC_BLOCKSIZE); ++ if (ret < 0) { ++ AICWFDBG(LOGERROR, "set func2 blocksize fail %d\n", ++ ret); ++ sdio_release_host(sdiodev->func_msg); ++ return ret; ++ } ++ ++ //set sdio enable func ++ ret = sdio_enable_func(sdiodev->func_msg); ++ if (ret < 0) { ++ AICWFDBG(LOGERROR, "enable func2 fail %d.\n", ret); ++ } ++ ++ sdio_release_host(sdiodev->func_msg); ++ ++ ret = aicwf_sdio_writeb_func2( ++ sdiodev, sdiodev->sdio_reg.register_block, block_bit0); ++ if (ret < 0) { ++ AICWFDBG(LOGERROR, "reg:%d write failed!\n", ++ sdiodev->sdio_reg.register_block); ++ return ret; ++ } ++ ++ //1: no byte mode ++ ret = aicwf_sdio_writeb_func2( ++ sdiodev, sdiodev->sdio_reg.bytemode_enable_reg, ++ byte_mode_disable); ++ if (ret < 0) { ++ AICWFDBG(LOGERROR, "reg:%d write failed!\n", ++ sdiodev->sdio_reg.bytemode_enable_reg); ++ return ret; ++ } ++ } ++ ++ ret = aicbsp_priv_aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.register_block, ++ block_bit0); ++ if (ret < 0) { ++ sdio_err("reg:%d write failed!\n", ++ sdiodev->sdio_reg.register_block); ++ return ret; ++ } ++ ++ //1: no byte mode ++ ret = aicbsp_priv_aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.bytemode_enable_reg, ++ byte_mode_disable); ++ if (ret < 0) { ++ sdio_err("reg:%d write failed!\n", ++ sdiodev->sdio_reg.bytemode_enable_reg); ++ return ret; ++ } ++ ++ return ret; ++} ++ ++int aicbsp_priv_aicwf_sdiov3_func_init(struct aic_sdio_dev *sdiodev) ++{ ++ struct mmc_host *host; ++ u8 byte_mode_disable = 0x1; //1: no byte mode ++ int ret = 0; ++ //u8 val; ++ struct aicbsp_feature_t feature; ++ ++ aicbsp_get_feature(&feature, NULL); ++ aicbsp_priv_aicwf_sdio_reg_init(sdiodev); ++ ++ host = sdiodev->func->card->host; ++ ++ sdio_claim_host(sdiodev->func); ++ sdiodev->func->card->quirks |= MMC_QUIRK_LENIENT_FN0; ++ ++ ret = sdio_set_block_size(sdiodev->func, SDIOWIFI_FUNC_BLOCKSIZE); ++ if (ret < 0) { ++ sdio_err("set blocksize fail %d\n", ret); ++ sdio_release_host(sdiodev->func); ++ return ret; ++ } ++ ret = sdio_enable_func(sdiodev->func); ++ if (ret < 0) { ++ sdio_err("enable func fail %d.\n", ret); ++ sdio_release_host(sdiodev->func); ++ return ret; ++ } ++ ++ sdio_f0_writeb(sdiodev->func, 0x7F, 0xF2, &ret); ++ if (ret) { ++ sdio_err("set fn0 0xF2 fail %d\n", ret); ++ sdio_release_host(sdiodev->func); ++ return ret; ++ } ++#if 0 ++ if (host->ios.timing == MMC_TIMING_UHS_DDR50) { ++ val = 0x21;//0x1D;//0x5; ++ } else { ++ val = 0x01;//0x19;//0x1; ++ } ++ val |= SDIOCLK_FREE_RUNNING_BIT; ++ sdio_f0_writeb(sdiodev->func, val, 0xF0, &ret); ++ if (ret) { ++ sdio_err("set iopad ctrl fail %d\n", ret); ++ sdio_release_host(sdiodev->func); ++ return ret; ++ } ++ sdio_f0_writeb(sdiodev->func, 0x0, 0xF8, &ret); ++ if (ret) { ++ sdio_err("set iopad delay2 fail %d\n", ret); ++ sdio_release_host(sdiodev->func); ++ return ret; ++ } ++ sdio_f0_writeb(sdiodev->func, 0x40, 0xF1, &ret); ++ if (ret) { ++ sdio_err("set iopad delay1 fail %d\n", ret); ++ sdio_release_host(sdiodev->func); ++ return ret; ++ } ++ msleep(1); ++#if 1 //SDIO CLOCK SETTING ++ if ((feature.sdio_clock > 0) && (host->ios.timing != MMC_TIMING_UHS_DDR50)) { ++ host->ios.clock = feature.sdio_clock; ++ host->ops->set_ios(host, &host->ios); ++ sdio_dbg("Set SDIO Clock %d MHz\n", host->ios.clock/1000000); ++ } ++#endif ++#endif ++ sdio_release_host(sdiodev->func); ++ ++ //1: no byte mode ++ ret = aicbsp_priv_aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.bytemode_enable_reg, ++ byte_mode_disable); ++ if (ret < 0) { ++ sdio_err("reg:%d write failed!\n", ++ sdiodev->sdio_reg.bytemode_enable_reg); ++ return ret; ++ } ++ ++ return ret; ++} ++ ++void aicbsp_priv_aicwf_sdio_func_deinit(struct aic_sdio_dev *sdiodev) ++{ ++ struct aicwf_bus *bus_if = NULL; ++ ++ if (sdiodev->func == NULL) { ++ sdio_err("%s, NULL sdio func\n", __func__); ++ return; ++ } ++ ++ bus_if = dev_get_drvdata(sdiodev->dev); ++ if (bus_if == NULL) { ++ sdio_err("%s, bus_if is null\n", __func__); ++ return; ++ } ++ ++ if (sdiodev->bus_if == bus_if) { ++ sdio_dbg("%s bsp disable\n", __func__); ++ sdio_claim_host(sdiodev->func); ++ sdio_disable_func(sdiodev->func); ++ sdio_release_host(sdiodev->func); ++ } ++ ++ if (sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ sdio_claim_host(sdiodev->func_msg); ++ sdio_disable_func(sdiodev->func_msg); ++ sdio_release_host(sdiodev->func_msg); ++ } ++} ++ ++void *aicbsp_priv_aicwf_sdio_bus_init(struct aic_sdio_dev *sdiodev) ++{ ++ int ret; ++ struct aicwf_bus *bus_if; ++ struct aicwf_rx_priv *rx_priv; ++ struct aicwf_tx_priv *tx_priv; ++ ++#if defined(CONFIG_SDIO_PWRCTRL) ++ spin_lock_init(&sdiodev->pwrctl_lock); ++ sema_init(&sdiodev->pwrctl_wakeup_sema, 1); ++#endif ++ ++ bus_if = sdiodev->bus_if; ++ bus_if->dev = sdiodev->dev; ++ bus_if->ops = &aicwf_sdio_bus_ops; ++ bus_if->state = BUS_DOWN_ST; ++#if defined(CONFIG_SDIO_PWRCTRL) ++ sdiodev->state = SDIO_SLEEP_ST; ++ sdiodev->active_duration = SDIOWIFI_PWR_CTRL_INTERVAL; ++#else ++ sdiodev->state = SDIO_ACTIVE_ST; ++#endif ++ ++ rx_priv = aicbsp_priv_aicwf_rx_init(sdiodev); ++ if (!rx_priv) { ++ sdio_err("rx init fail\n"); ++ goto fail; ++ } ++ sdiodev->rx_priv = rx_priv; ++ ++ tx_priv = aicbsp_priv_aicwf_tx_init(sdiodev); ++ if (!tx_priv) { ++ sdio_err("tx init fail\n"); ++ goto fail; ++ } ++ sdiodev->tx_priv = tx_priv; ++ aicbsp_priv_aicwf_frame_queue_init(&tx_priv->txq, 8, TXQLEN); ++ spin_lock_init(&tx_priv->txqlock); ++ sema_init(&tx_priv->txctl_sema, 1); ++ sema_init(&tx_priv->cmd_txsema, 1); ++ init_waitqueue_head(&tx_priv->cmd_txdone_wait); ++ atomic_set(&tx_priv->tx_pktcnt, 0); ++ ++#if defined(CONFIG_SDIO_PWRCTRL) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ timer_setup(&sdiodev->timer, aicwf_sdio_bus_pwrctl, 0); ++#else ++ init_timer(&sdiodev->timer); ++ sdiodev->timer.data = (ulong)sdiodev; ++ sdiodev->timer.function = aicwf_sdio_bus_pwrctl; ++#endif ++ init_completion(&sdiodev->pwrctrl_trgg); ++#endif ++ ret = aicbsp_priv_aicwf_bus_init(0, sdiodev->dev); ++ if (ret < 0) { ++ sdio_err("bus init fail\n"); ++ goto fail; ++ } ++ ++ ret = aicwf_bus_start(bus_if); ++ if (ret != 0) { ++ sdio_err("bus start fail\n"); ++ goto fail; ++ } ++ ++ return sdiodev; ++ ++fail: ++ aicbsp_priv_aicwf_sdio_release(sdiodev); ++ return NULL; ++} ++ ++void get_fw_path(char *fw_path) ++{ ++ if (strlen(aicbsp_priv_aic_fw_path) > 0) { ++ memcpy(fw_path, aicbsp_priv_aic_fw_path, strlen(aicbsp_priv_aic_fw_path)); ++ } else { ++ memcpy(fw_path, aic_default_fw_path, ++ strlen(aic_default_fw_path)); ++ } ++} ++ ++int get_testmode(void) ++{ ++ return aicbsp_priv_testmode; ++} ++ ++struct sdio_func *get_sdio_func(void) ++{ ++ return aicbsp_sdiodev->func; ++} ++ ++void set_irq_handler(void *fn) ++{ ++ aicbsp_sdiodev->sdio_hal_irqhandler = (sdio_irq_handler_t *)fn; ++} ++ ++uint8_t aicbsp_priv_crc8_ponl_107(uint8_t *p_buffer, uint16_t cal_size) ++{ ++ uint8_t i; ++ uint8_t crc = 0; ++ if (cal_size == 0) { ++ return crc; ++ } ++ while (cal_size--) { ++ for (i = 0x80; i > 0; i /= 2) { ++ if (crc & 0x80) { ++ crc *= 2; ++ crc ^= 0x07; //polynomial X8 + X2 + X + 1,(0x107) ++ } else { ++ crc *= 2; ++ } ++ if ((*p_buffer) & i) { ++ crc ^= 0x07; ++ } ++ } ++ p_buffer++; ++ } ++ return crc; ++} ++ ++EXPORT_SYMBOL(get_fw_path); ++EXPORT_SYMBOL(get_testmode); ++EXPORT_SYMBOL(get_sdio_func); ++EXPORT_SYMBOL(set_irq_handler); +diff --git a/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio.h b/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio.h +new file mode 100755 +index 000000000..0aa8c867a +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio.h +@@ -0,0 +1,150 @@ ++/** ++ * aicwf_sdio.h ++ * ++ * SDIO function declarations ++ * ++ * Copyright (C) AICSemi 2018-2020 ++ */ ++ ++#ifndef _AICWF_SDMMC_H_ ++#define _AICWF_SDMMC_H_ ++ ++#ifdef AICWF_SDIO_SUPPORT ++#include ++#include ++#include ++#include ++#include "aic_bsp_driver.h" ++ ++#define AICBSP_SDIO_NAME "aicbsp_sdio" ++#define SDIOWIFI_FUNC_BLOCKSIZE 512 ++ ++#define SDIO_VENDOR_ID_AIC 0x8800 ++#define SDIO_DEVICE_ID_AIC 0x0001 ++#define SDIOWIFI_BYTEMODE_LEN_REG 0x02 ++#define SDIOWIFI_INTR_CONFIG_REG 0x04 ++#define SDIOWIFI_SLEEP_REG 0x05 ++#define SDIOWIFI_WAKEUP_REG 0x09 ++#define SDIOWIFI_FLOW_CTRL_REG 0x0A ++#define SDIOWIFI_REGISTER_BLOCK 0x0B ++#define SDIOWIFI_BYTEMODE_ENABLE_REG 0x11 ++#define SDIOWIFI_BLOCK_CNT_REG 0x12 ++#define SDIOWIFI_FLOWCTRL_MASK_REG 0x7F ++#define SDIOWIFI_WR_FIFO_ADDR 0x07 ++#define SDIOWIFI_RD_FIFO_ADDR 0x08 ++ ++#define SDIOWIFI_INTR_ENABLE_REG_V3 0x00 ++#define SDIOWIFI_INTR_PENDING_REG_V3 0x01 ++#define SDIOWIFI_INTR_TO_DEVICE_REG_V3 0x02 ++#define SDIOWIFI_FLOW_CTRL_Q1_REG_V3 0x03 ++#define SDIOWIFI_MISC_INT_STATUS_REG_V3 0x04 ++#define SDIOWIFI_BYTEMODE_LEN_REG_V3 0x05 ++#define SDIOWIFI_BYTEMODE_LEN_MSB_REG_V3 0x06 ++#define SDIOWIFI_BYTEMODE_ENABLE_REG_V3 0x07 ++#define SDIOWIFI_MISC_CTRL_REG_V3 0x08 ++#define SDIOWIFI_FLOW_CTRL_Q2_REG_V3 0x09 ++#define SDIOWIFI_CLK_TEST_RESULT_REG_V3 0x0A ++#define SDIOWIFI_RD_FIFO_ADDR_V3 0x0F ++#define SDIOWIFI_WR_FIFO_ADDR_V3 0x10 ++ ++#define SDIOCLK_FREE_RUNNING_BIT (1 << 6) ++ ++#define SDIOWIFI_PWR_CTRL_INTERVAL 30 ++#define FLOW_CTRL_RETRY_COUNT 50 ++#define BUFFER_SIZE 1536 ++#define TAIL_LEN 4 ++#define TXQLEN (2048 * 4) ++ ++#define SDIO_SLEEP_ST 0 ++#define SDIO_ACTIVE_ST 1 ++ ++typedef enum { ++ SDIO_TYPE_DATA = 0X00, ++ SDIO_TYPE_CFG = 0X10, ++ SDIO_TYPE_CFG_CMD_RSP = 0X11, ++ SDIO_TYPE_CFG_DATA_CFM = 0X12 ++} sdio_type; ++ ++enum AICWF_IC { ++ PRODUCT_ID_AIC8801 = 0, ++ PRODUCT_ID_AIC8800DC, ++ PRODUCT_ID_AIC8800DW, ++ PRODUCT_ID_AIC8800D80, ++ PRODUCT_ID_AIC8800D80X2 ++}; ++ ++struct aic_sdio_reg { ++ u8 bytemode_len_reg; ++ u8 intr_config_reg; ++ u8 sleep_reg; ++ u8 wakeup_reg; ++ u8 flow_ctrl_reg; ++ u8 flowctrl_mask_reg; ++ u8 register_block; ++ u8 bytemode_enable_reg; ++ u8 block_cnt_reg; ++ u8 misc_int_status_reg; ++ u8 rd_fifo_addr; ++ u8 wr_fifo_addr; ++}; ++ ++struct aic_sdio_dev { ++ struct rwnx_cmd_mgr cmd_mgr; ++ struct sdio_func *func; ++ struct sdio_func *func_msg; ++ struct device *dev; ++ struct aicwf_bus *bus_if; ++ ++ struct aicwf_rx_priv *rx_priv; ++ struct aicwf_tx_priv *tx_priv; ++ u32 state; ++ ++#if defined(CONFIG_SDIO_PWRCTRL) ++ //for sdio pwr ctrl ++ struct timer_list timer; ++ uint active_duration; ++ struct completion pwrctrl_trgg; ++ struct task_struct *pwrctl_tsk; ++ spinlock_t pwrctl_lock; ++ struct semaphore pwrctl_wakeup_sema; ++#endif ++ u16 chipid; ++ u32 fw_version_uint; ++ struct aic_sdio_reg sdio_reg; ++ void (*sdio_hal_irqhandler)(struct sdio_func *func); ++}; ++ ++void *aicbsp_get_drvdata(void *args); ++int aicbsp_priv_aicwf_sdio_writeb(struct aic_sdio_dev *sdiodev, uint regaddr, u8 val); ++void aicbsp_priv_aicwf_sdio_hal_irqhandler(struct sdio_func *func); ++void aicwf_sdio_hal_irqhandler_func2(struct sdio_func *func); ++#if defined(CONFIG_SDIO_PWRCTRL) ++void aicbsp_priv_aicwf_sdio_pwrctl_timer(struct aic_sdio_dev *sdiodev, uint duration); ++int aicbsp_priv_aicwf_sdio_pwr_stctl(struct aic_sdio_dev *sdiodev, uint target); ++#endif ++void aicbsp_priv_aicwf_sdio_reg_init(struct aic_sdio_dev *sdiodev); ++int aicbsp_priv_aicwf_sdio_func_init(struct aic_sdio_dev *sdiodev); ++int aicbsp_priv_aicwf_sdiov3_func_init(struct aic_sdio_dev *sdiodev); ++void aicbsp_priv_aicwf_sdio_func_deinit(struct aic_sdio_dev *sdiodev); ++int aicbsp_priv_aicwf_sdio_flow_ctrl(struct aic_sdio_dev *sdiodev); ++int aicbsp_priv_aicwf_sdio_recv_pkt(struct aic_sdio_dev *sdiodev, struct sk_buff *skbbuf, ++ u32 size, u8 msg); ++int aicbsp_priv_aicwf_sdio_send_pkt(struct aic_sdio_dev *sdiodev, u8 *buf, uint count); ++void *aicbsp_priv_aicwf_sdio_bus_init(struct aic_sdio_dev *sdiodev); ++void aicbsp_priv_aicwf_sdio_release(struct aic_sdio_dev *sdiodev); ++void aicbsp_sdio_exit(void); ++int aicbsp_sdio_init(void); ++void aicbsp_sdio_release(struct aic_sdio_dev *sdiodev); ++int aicbsp_priv_aicwf_sdio_txpkt(struct aic_sdio_dev *sdiodev, struct sk_buff *pkt); ++int aicwf_sdio_bustx_thread(void *data); ++int aicwf_sdio_busrx_thread(void *data); ++int aicbsp_priv_aicwf_sdio_aggr(struct aicwf_tx_priv *tx_priv, struct sk_buff *pkt); ++int aicbsp_priv_aicwf_sdio_send(struct aicwf_tx_priv *tx_priv); ++void aicbsp_priv_aicwf_sdio_aggr_send(struct aicwf_tx_priv *tx_priv); ++void aicbsp_priv_aicwf_sdio_aggrbuf_reset(struct aicwf_tx_priv *tx_priv); ++extern void aicwf_hostif_ready(void); ++int aicbsp_priv_aicwf_process_rxframes(struct aicwf_rx_priv *rx_priv); ++uint8_t aicbsp_priv_crc8_ponl_107(uint8_t *p_buffer, uint16_t cal_size); ++#endif /* AICWF_SDIO_SUPPORT */ ++ ++#endif /*_AICWF_SDMMC_H_*/ +diff --git a/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio_txrxif.c b/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio_txrxif.c +new file mode 100755 +index 000000000..b33bd7e63 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio_txrxif.c +@@ -0,0 +1,485 @@ ++/** ++ * aicwf_bus.c ++ * ++ * bus function declarations ++ * ++ * Copyright (C) AICSemi 2018-2020 ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "aicsdio_txrxif.h" ++#include "aic_bsp_driver.h" ++ ++int aicbsp_priv_aicwf_bus_init(uint bus_hdrlen, struct device *dev) ++{ ++ int ret = 0; ++ struct aicwf_bus *bus_if; ++ ++ if (!dev) { ++ txrx_err("device not found\n"); ++ return -1; ++ } ++ 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; ++ } ++ memset(bus_if->cmd_buf, '\0', CMD_BUF_MAX); ++ ++ init_completion(&bus_if->bustx_trgg); ++ init_completion(&bus_if->busrx_trgg); ++#ifdef AICWF_SDIO_SUPPORT ++ bus_if->bustx_thread = kthread_run( ++ aicwf_sdio_bustx_thread, (void *)bus_if, "aicwf_bustx_thread"); ++ if (IS_ERR(bus_if->bustx_thread)) { ++ bus_if->bustx_thread = NULL; ++ txrx_err("aicwf_bustx_thread run fail\n"); ++ ret = -1; ++ goto fail; ++ } ++ ++ bus_if->busrx_thread = ++ kthread_run(aicwf_sdio_busrx_thread, ++ (void *)bus_if->bus_priv.sdio->rx_priv, ++ "aicwf_busrx_thread"); ++ if (IS_ERR(bus_if->busrx_thread)) { ++ bus_if->busrx_thread = NULL; ++ txrx_err("aicwf_bustx_thread run fail\n"); ++ ret = -1; ++ goto fail; ++ } ++ ++#endif ++ return ret; ++fail: ++ aicbsp_priv_aicwf_bus_deinit(dev); ++ ++ return ret; ++} ++ ++void aicbsp_priv_aicwf_bus_deinit(struct device *dev) ++{ ++ struct aicwf_bus *bus_if; ++ struct aic_sdio_dev *sdiodev; ++ ++ if (!dev) { ++ txrx_err("device not found\n"); ++ return; ++ } ++ sdio_dbg("%s", __func__); ++ bus_if = aicbsp_get_drvdata(dev); ++ aicwf_bus_stop(bus_if); ++ ++ sdiodev = bus_if->bus_priv.sdio; ++ ++ if (bus_if->cmd_buf) { ++ kfree(bus_if->cmd_buf); ++ bus_if->cmd_buf = NULL; ++ } ++ ++ if (bus_if->bustx_thread) { ++ complete_all(&bus_if->bustx_trgg); ++ kthread_stop(bus_if->bustx_thread); ++ bus_if->bustx_thread = NULL; ++ } ++} ++ ++void aicbsp_priv_aicwf_frame_tx(void *dev, struct sk_buff *skb) ++{ ++ struct aic_sdio_dev *sdiodev = (struct aic_sdio_dev *)dev; ++ aicwf_bus_txdata(sdiodev->bus_if, skb); ++} ++ ++struct aicwf_tx_priv *aicbsp_priv_aicwf_tx_init(void *arg) ++{ ++ struct aicwf_tx_priv *tx_priv; ++ ++ tx_priv = kzalloc(sizeof(struct aicwf_tx_priv), GFP_KERNEL); ++ if (!tx_priv) ++ return NULL; ++ ++ tx_priv->sdiodev = (struct aic_sdio_dev *)arg; ++ ++ atomic_set(&tx_priv->aggr_count, 0); ++ tx_priv->aggr_buf = dev_alloc_skb(MAX_AGGR_TXPKT_LEN); ++ if (!tx_priv->aggr_buf) { ++ txrx_err("Alloc bus->txdata_buf failed!\n"); ++ kfree(tx_priv); ++ return NULL; ++ } ++ tx_priv->head = tx_priv->aggr_buf->data; ++ tx_priv->tail = tx_priv->aggr_buf->data; ++ ++ return tx_priv; ++} ++ ++void aicbsp_priv_aicwf_tx_deinit(struct aicwf_tx_priv *tx_priv) ++{ ++ if (tx_priv && tx_priv->aggr_buf) ++ dev_kfree_skb(tx_priv->aggr_buf); ++ ++ kfree(tx_priv); ++ //tx_priv = NULL; ++} ++ ++static bool aicwf_another_ptk(struct sk_buff *skb) ++{ ++ u8 *data; ++ u16 aggr_len = 0; ++ ++ if (skb->data == NULL || skb->len == 0) { ++ return false; ++ } ++ data = skb->data; ++ aggr_len = (*skb->data | (*(skb->data + 1) << 8)); ++ if (aggr_len == 0) { ++ return false; ++ } ++ ++ return true; ++} ++ ++int aicbsp_priv_aicwf_process_rxframes(struct aicwf_rx_priv *rx_priv) ++{ ++ int ret = 0; ++ unsigned long flags = 0; ++ struct sk_buff *skb = NULL; ++ u16 pkt_len = 0; ++ struct sk_buff *skb_inblock = NULL; ++ u16 aggr_len = 0, adjust_len = 0; ++ u8 *data = NULL; ++ ++ while (1) { ++ spin_lock_irqsave(&rx_priv->rxqlock, flags); ++ if (aicbsp_priv_aicwf_is_framequeue_empty(&rx_priv->rxq)) { ++ spin_unlock_irqrestore(&rx_priv->rxqlock, flags); ++ break; ++ } ++ skb = aicbsp_priv_aicwf_frame_dequeue(&rx_priv->rxq); ++ spin_unlock_irqrestore(&rx_priv->rxqlock, flags); ++ if (skb == NULL) { ++ txrx_err("skb_error\r\n"); ++ break; ++ } ++ while (aicwf_another_ptk(skb)) { ++ data = skb->data; ++ pkt_len = (*skb->data | (*(skb->data + 1) << 8)); ++ ++ if ((skb->data[2] & SDIO_TYPE_CFG) != ++ SDIO_TYPE_CFG) { // type : data ++ aggr_len = pkt_len + RX_HWHRD_LEN; ++ ++ if (aggr_len & (RX_ALIGNMENT - 1)) ++ adjust_len = ++ roundup(aggr_len, RX_ALIGNMENT); ++ 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!\n"); ++ aicbsp_priv_aicwf_dev_skb_free(skb); ++ return -EBADE; ++ } ++ ++ skb_put(skb_inblock, aggr_len); ++ memcpy(skb_inblock->data, data, aggr_len); ++#if 0 ++ rwnx_rxdataind_aicwf(rx_priv->sdiodev->rwnx_hw, skb_inblock, (void *)rx_priv); ++#endif ++ 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; ++ ++ skb_inblock = __dev_alloc_skb(aggr_len + 4, ++ GFP_KERNEL); ++ if (skb_inblock == NULL) { ++ txrx_err("no more space!\n"); ++ aicbsp_priv_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) ++ aicbsp_priv_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); ++ } ++ ++#if defined(CONFIG_SDIO_PWRCTRL) ++ aicbsp_priv_aicwf_sdio_pwr_stctl(rx_priv->sdiodev, SDIO_ACTIVE_ST); ++#endif ++ ++ return ret; ++} ++ ++static struct recv_msdu *aicwf_rxframe_queue_init(struct list_head *q, ++ int qsize) ++{ ++ int i; ++ struct recv_msdu *req, *reqs; ++ ++ reqs = vmalloc(qsize * sizeof(struct recv_msdu)); ++ if (reqs == NULL) ++ return NULL; ++ ++ req = reqs; ++ for (i = 0; i < qsize; i++) { ++ INIT_LIST_HEAD(&req->rxframe_list); ++ list_add(&req->rxframe_list, q); ++ req->len = 0; ++ req++; ++ } ++ ++ return reqs; ++} ++ ++struct aicwf_rx_priv *aicbsp_priv_aicwf_rx_init(void *arg) ++{ ++ struct aicwf_rx_priv *rx_priv; ++ rx_priv = kzalloc(sizeof(struct aicwf_rx_priv), GFP_KERNEL); ++ if (!rx_priv) ++ return NULL; ++ ++ rx_priv->sdiodev = (struct aic_sdio_dev *)arg; ++ aicbsp_priv_aicwf_frame_queue_init(&rx_priv->rxq, 1, MAX_RXQLEN); ++ spin_lock_init(&rx_priv->rxqlock); ++ atomic_set(&rx_priv->rx_cnt, 0); ++ ++ INIT_LIST_HEAD(&rx_priv->rxframes_freequeue); ++ spin_lock_init(&rx_priv->freeq_lock); ++ rx_priv->recv_frames = aicwf_rxframe_queue_init( ++ &rx_priv->rxframes_freequeue, MAX_REORD_RXFRAME); ++ if (!rx_priv->recv_frames) { ++ txrx_err("no enough buffer for free recv frame queue!\n"); ++ kfree(rx_priv); ++ return NULL; ++ } ++ spin_lock_init(&rx_priv->stas_reord_lock); ++ INIT_LIST_HEAD(&rx_priv->stas_reord_list); ++ ++ return rx_priv; ++} ++ ++static void aicwf_recvframe_queue_deinit(struct list_head *q) ++{ ++ struct recv_msdu *req, *next; ++ ++ list_for_each_entry_safe (req, next, q, rxframe_list) { ++ list_del_init(&req->rxframe_list); ++ } ++} ++ ++void aicbsp_priv_aicwf_rx_deinit(struct aicwf_rx_priv *rx_priv) ++{ ++ if (rx_priv->sdiodev->bus_if->busrx_thread) { ++ complete_all(&rx_priv->sdiodev->bus_if->busrx_trgg); ++ kthread_stop(rx_priv->sdiodev->bus_if->busrx_thread); ++ rx_priv->sdiodev->bus_if->busrx_thread = NULL; ++ } ++ ++ aicbsp_priv_aicwf_frame_queue_flush(&rx_priv->rxq); ++ aicwf_recvframe_queue_deinit(&rx_priv->rxframes_freequeue); ++ if (rx_priv->recv_frames) ++ vfree(rx_priv->recv_frames); ++ ++ kfree(rx_priv); ++ //rx_priv = NULL; ++} ++ ++bool aicbsp_priv_aicwf_rxframe_enqueue(struct device *dev, struct frame_queue *q, ++ struct sk_buff *pkt) ++{ ++ return aicbsp_priv_aicwf_frame_enq(dev, q, pkt, 0); ++} ++ ++void aicbsp_priv_aicwf_dev_skb_free(struct sk_buff *skb) ++{ ++ if (!skb) ++ return; ++ ++ dev_kfree_skb_any(skb); ++} ++ ++static struct sk_buff *aicwf_frame_queue_penq(struct frame_queue *pq, int prio, ++ struct sk_buff *p) ++{ ++ struct sk_buff_head *q; ++ ++ if (pq->queuelist[prio].qlen >= pq->qmax) ++ return NULL; ++ ++ q = &pq->queuelist[prio]; ++ __skb_queue_tail(q, p); ++ pq->qcnt++; ++ if (pq->hi_prio < prio) ++ pq->hi_prio = (u16)prio; ++ ++ return p; ++} ++ ++void aicbsp_priv_aicwf_frame_queue_flush(struct frame_queue *pq) ++{ ++ int prio; ++ struct sk_buff_head *q; ++ struct sk_buff *p, *next; ++ ++ for (prio = 0; prio < pq->num_prio; prio++) { ++ q = &pq->queuelist[prio]; ++ skb_queue_walk_safe(q, p, next) ++ { ++ skb_unlink(p, q); ++ aicbsp_priv_aicwf_dev_skb_free(p); ++ pq->qcnt--; ++ } ++ } ++} ++ ++void aicbsp_priv_aicwf_frame_queue_init(struct frame_queue *pq, int num_prio, int max_len) ++{ ++ int prio; ++ ++ memset(pq, 0, ++ offsetof(struct frame_queue, queuelist) + ++ (sizeof(struct sk_buff_head) * num_prio)); ++ pq->num_prio = (u16)num_prio; ++ pq->qmax = (u16)max_len; ++ ++ for (prio = 0; prio < num_prio; prio++) { ++ skb_queue_head_init(&pq->queuelist[prio]); ++ } ++} ++ ++struct sk_buff *aicbsp_priv_aicwf_frame_queue_peek_tail(struct frame_queue *pq, ++ int *prio_out) ++{ ++ int prio; ++ ++ if (pq->qcnt == 0) ++ return NULL; ++ ++ for (prio = 0; prio < pq->hi_prio; prio++) ++ if (!skb_queue_empty(&pq->queuelist[prio])) ++ break; ++ ++ if (prio_out) ++ *prio_out = prio; ++ ++ return skb_peek_tail(&pq->queuelist[prio]); ++} ++ ++bool aicbsp_priv_aicwf_is_framequeue_empty(struct frame_queue *pq) ++{ ++ int prio, len = 0; ++ ++ for (prio = 0; prio <= pq->hi_prio; prio++) ++ len += pq->queuelist[prio].qlen; ++ ++ if (len > 0) ++ return false; ++ else ++ return true; ++} ++ ++struct sk_buff *aicbsp_priv_aicwf_frame_dequeue(struct frame_queue *pq) ++{ ++ struct sk_buff_head *q; ++ struct sk_buff *p; ++ int prio; ++ ++ if (pq->qcnt == 0) ++ return NULL; ++ ++ while ((prio = pq->hi_prio) > 0 && ++ skb_queue_empty(&pq->queuelist[prio])) ++ pq->hi_prio--; ++ ++ q = &pq->queuelist[prio]; ++ p = __skb_dequeue(q); ++ if (p == NULL) ++ return NULL; ++ ++ pq->qcnt--; ++ ++ 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 aicbsp_priv_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 = aicbsp_priv_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); ++ aicbsp_priv_aicwf_dev_skb_free(p); ++ ++ p = aicwf_frame_queue_penq(q, prio_modified, pkt); ++ if (p == NULL) ++ txrx_err("failed\n"); ++ } ++ ++ return p != NULL; ++} +diff --git a/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio_txrxif.h b/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio_txrxif.h +new file mode 100755 +index 000000000..1cc7ca968 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_bsp/aicsdio_txrxif.h +@@ -0,0 +1,219 @@ ++/** ++ * aicwf_txrxif.h ++ * ++ * bus function declarations ++ * ++ * Copyright (C) AICSemi 2018-2020 ++ */ ++ ++#ifndef _AICWF_TXRXIF_H_ ++#define _AICWF_TXRXIF_H_ ++ ++#include ++#include ++#include "aicsdio.h" ++ ++#define CMD_BUF_MAX 1536 ++#define TXPKT_BLOCKSIZE 512 ++#define MAX_AGGR_TXPKT_LEN (1536 * 4) ++#define CMD_TX_TIMEOUT 5000 ++#define TX_ALIGNMENT 4 ++ ++#define RX_HWHRD_LEN 60 //58->60 word allined ++#define CCMP_OR_WEP_INFO 8 ++#define MAX_RXQLEN 2000 ++#define RX_ALIGNMENT 4 ++ ++#define DEBUG_ERROR_LEVEL 0 ++#define DEBUG_DEBUG_LEVEL 1 ++#define DEBUG_INFO_LEVEL 2 ++ ++#define DBG_LEVEL DEBUG_DEBUG_LEVEL ++ ++#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__) ++#else ++#define sdio_dbg(fmt, ...) ++#define usb_dbg(fmt, ...) ++#endif ++#if DBG_LEVEL >= DEBUG_INFO_LEVEL ++#define sdio_info(fmt, ...) printk("aicbsp: " fmt, ##__VA_ARGS__) ++#define usb_info(fmt, ...) printk("aicbsp: " fmt, ##__VA_ARGS__) ++#else ++#define sdio_info(fmt, ...) ++#define usb_info(fmt, ...) ++#endif ++ ++enum aicwf_bus_state { BUS_DOWN_ST, BUS_UP_ST }; ++ ++struct aicwf_bus_ops { ++ int (*start)(struct device *dev); ++ void (*stop)(struct device *dev); ++ int (*txdata)(struct device *dev, struct sk_buff *skb); ++ int (*txmsg)(struct device *dev, u8 *msg, uint len); ++}; ++ ++struct frame_queue { ++ u16 num_prio; ++ u16 hi_prio; ++ u16 qmax; /* max number of queued frames */ ++ u16 qcnt; ++ struct sk_buff_head queuelist[8]; ++}; ++ ++struct aicwf_bus { ++ union { ++ struct aic_sdio_dev *sdio; ++ struct aic_usb_dev *usb; ++ } bus_priv; ++ struct device *dev; ++ struct aicwf_bus_ops *ops; ++ enum aicwf_bus_state state; ++ u8 *cmd_buf; ++ struct completion bustx_trgg; ++ struct completion busrx_trgg; ++ struct task_struct *bustx_thread; ++ struct task_struct *busrx_thread; ++}; ++ ++struct aicwf_tx_priv { ++#ifdef AICWF_SDIO_SUPPORT ++ struct aic_sdio_dev *sdiodev; ++ int fw_avail_bufcnt; ++ //for cmd tx ++ u8 *cmd_buf; ++ uint cmd_len; ++ bool cmd_txstate; ++ bool cmd_tx_succ; ++ struct semaphore cmd_txsema; ++ wait_queue_head_t cmd_txdone_wait; ++ //for data tx ++ atomic_t tx_pktcnt; ++ ++ struct frame_queue txq; ++ spinlock_t txqlock; ++ struct semaphore txctl_sema; ++#endif ++#ifdef AICWF_USB_SUPPORT ++ struct aic_usb_dev *usbdev; ++#endif ++ struct sk_buff *aggr_buf; ++ atomic_t aggr_count; ++ u8 *head; ++ u8 *tail; ++}; ++ ++#define MAX_REORD_RXFRAME 250 ++#define REORDER_UPDATE_TIME 50 ++#define AICWF_REORDER_WINSIZE 64 ++#define SN_LESS(a, b) (((a - b) & 0x800) != 0) ++#define SN_EQUAL(a, b) (a == b) ++ ++struct reord_ctrl { ++ struct aicwf_rx_priv *rx_priv; ++ u8 enable; ++ u16 ind_sn; ++ u8 wsize_b; ++ spinlock_t reord_list_lock; ++ struct list_head reord_list; ++ struct timer_list reord_timer; ++ struct work_struct reord_timer_work; ++}; ++ ++struct reord_ctrl_info { ++ u8 mac_addr[6]; ++ struct reord_ctrl preorder_ctrl[8]; ++ struct list_head list; ++}; ++ ++struct recv_msdu { ++ struct sk_buff *pkt; ++ u8 tid; ++ u16 seq_num; ++ uint len; ++ u8 *rx_data; ++ //for pending rx reorder list ++ struct list_head reord_pending_list; ++ //for total frame list, when rxframe from busif, dequeue, when submit frame to net, enqueue ++ struct list_head rxframe_list; ++ struct reord_ctrl *preorder_ctrl; ++}; ++ ++struct aicwf_rx_priv { ++ struct aic_sdio_dev *sdiodev; ++ void *rwnx_vif; ++ atomic_t rx_cnt; ++ u32 data_len; ++ spinlock_t rxqlock; ++ struct frame_queue rxq; ++ ++ spinlock_t freeq_lock; ++ struct list_head rxframes_freequeue; ++ struct list_head stas_reord_list; ++ spinlock_t stas_reord_lock; ++ struct recv_msdu *recv_frames; ++}; ++ ++static inline int aicwf_bus_start(struct aicwf_bus *bus) ++{ ++ return bus->ops->start(bus->dev); ++} ++ ++static inline void aicwf_bus_stop(struct aicwf_bus *bus) ++{ ++ bus->ops->stop(bus->dev); ++} ++ ++static inline int aicwf_bus_txdata(struct aicwf_bus *bus, struct sk_buff *skb) ++{ ++ return bus->ops->txdata(bus->dev, skb); ++} ++ ++static inline int aicwf_bus_txmsg(struct aicwf_bus *bus, u8 *msg, uint len) ++{ ++ return bus->ops->txmsg(bus->dev, msg, len); ++} ++ ++static inline void aicwf_sched_timeout(u32 millisec) ++{ ++ ulong timeout = 0, expires = 0; ++ expires = jiffies + msecs_to_jiffies(millisec); ++ timeout = millisec; ++ ++ while (timeout) { ++ timeout = schedule_timeout(timeout); ++ if (time_after(jiffies, expires)) ++ break; ++ } ++} ++ ++int aicbsp_priv_aicwf_bus_init(uint bus_hdrlen, struct device *dev); ++void aicbsp_priv_aicwf_bus_deinit(struct device *dev); ++void aicbsp_priv_aicwf_tx_deinit(struct aicwf_tx_priv *tx_priv); ++void aicbsp_priv_aicwf_rx_deinit(struct aicwf_rx_priv *rx_priv); ++struct aicwf_tx_priv *aicbsp_priv_aicwf_tx_init(void *arg); ++struct aicwf_rx_priv *aicbsp_priv_aicwf_rx_init(void *arg); ++void aicbsp_priv_aicwf_frame_queue_init(struct frame_queue *pq, int num_prio, int max_len); ++void aicbsp_priv_aicwf_frame_queue_flush(struct frame_queue *pq); ++bool aicbsp_priv_aicwf_frame_enq(struct device *dev, struct frame_queue *q, ++ struct sk_buff *pkt, int prio); ++bool aicbsp_priv_aicwf_rxframe_enqueue(struct device *dev, struct frame_queue *q, ++ struct sk_buff *pkt); ++bool aicbsp_priv_aicwf_is_framequeue_empty(struct frame_queue *pq); ++void aicbsp_priv_aicwf_frame_tx(void *dev, struct sk_buff *skb); ++void aicbsp_priv_aicwf_dev_skb_free(struct sk_buff *skb); ++struct sk_buff *aicbsp_priv_aicwf_frame_dequeue(struct frame_queue *pq); ++struct sk_buff *aicbsp_priv_aicwf_frame_queue_peek_tail(struct frame_queue *pq, ++ int *prio_out); ++ ++#endif /* _AICWF_TXRXIF_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_bsp/aicwf_firmware_array.c b/drivers/net/wireless/aic8800/aic8800_bsp/aicwf_firmware_array.c +new file mode 100755 +index 000000000..1b91677f5 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_bsp/aicwf_firmware_array.c +@@ -0,0 +1,26866 @@ ++#include ++ ++char fmacfw[259592] = { ++ 0x00, 0x38, 0x18, 0x00, 0x89, 0x01, 0x12, 0x00, 0xA5, 0xC6, 0x12, 0x00, ++ 0xA1, 0xCA, 0x12, 0x00, 0xA9, 0xCA, 0x12, 0x00, 0xB1, 0xCA, 0x12, 0x00, ++ 0xB9, 0xCA, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA5, 0xC6, 0x12, 0x00, ++ 0xA5, 0xC6, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA5, 0xC6, 0x12, 0x00, ++ 0xA5, 0xC6, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0xBB, 0x12, 0x00, ++ 0x19, 0x1E, 0x14, 0x00, 0x35, 0xEE, 0x12, 0x00, 0x49, 0xED, 0x12, 0x00, ++ 0x79, 0x5C, 0x13, 0x00, 0x99, 0x1A, 0x12, 0x00, 0x79, 0x5C, 0x13, 0x00, ++ 0x49, 0x11, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x1A, 0x12, 0x00, ++ 0x99, 0x1A, 0x12, 0x00, 0x65, 0x5A, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0xED, 0x12, 0x00, ++ 0x45, 0xED, 0x12, 0x00, 0x45, 0xED, 0x12, 0x00, 0x45, 0xED, 0x12, 0x00, ++ 0x45, 0xED, 0x12, 0x00, 0x7D, 0x4A, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x99, 0x1A, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x1A, 0x12, 0x00, ++ 0x99, 0x1A, 0x12, 0x00, 0x99, 0x1A, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x99, 0x1A, 0x12, 0x00, 0x8D, 0x52, 0x12, 0x00, 0x79, 0x51, 0x12, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCD, 0x5B, 0x12, 0x00, ++ 0x2C, 0x19, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x05, 0x48, 0x00, 0x68, ++ 0x10, 0xF0, 0x00, 0x4F, 0x0C, 0xBF, 0x04, 0x48, 0x20, 0xF0, 0x7F, 0x40, ++ 0x80, 0xF3, 0x08, 0x88, 0x02, 0x48, 0x00, 0x47, 0x44, 0x01, 0x50, 0x40, ++ 0x00, 0x38, 0x18, 0x00, 0x05, 0xC7, 0x12, 0x00, 0xF0, 0xB4, 0x86, 0x07, ++ 0x46, 0xD0, 0x54, 0x1E, 0x00, 0x2A, 0x3C, 0xD0, 0xCA, 0xB2, 0x03, 0x46, ++ 0x01, 0xE0, 0x01, 0x3C, 0x37, 0xD3, 0x03, 0xF8, 0x01, 0x2B, 0x9D, 0x07, ++ 0xF9, 0xD1, 0x03, 0x2C, 0x2A, 0xD9, 0xCD, 0xB2, 0x45, 0xEA, 0x05, 0x25, ++ 0x0F, 0x2C, 0x45, 0xEA, 0x05, 0x45, 0x34, 0xD9, 0xA4, 0xF1, 0x10, 0x02, ++ 0x22, 0xF0, 0x0F, 0x0C, 0x03, 0xF1, 0x20, 0x07, 0x16, 0x09, 0x67, 0x44, ++ 0x03, 0xF1, 0x10, 0x02, 0x42, 0xE9, 0x04, 0x55, 0x42, 0xE9, 0x02, 0x55, ++ 0x10, 0x32, 0xBA, 0x42, 0xF8, 0xD1, 0x72, 0x1C, 0x14, 0xF0, 0x0C, 0x0F, ++ 0x03, 0xEB, 0x02, 0x12, 0x04, 0xF0, 0x0F, 0x06, 0x13, 0xD0, 0x33, 0x1F, ++ 0x23, 0xF0, 0x03, 0x03, 0x04, 0x33, 0x13, 0x44, 0x42, 0xF8, 0x04, 0x5B, ++ 0x93, 0x42, 0xFB, 0xD1, 0x06, 0xF0, 0x03, 0x04, 0x2C, 0xB1, 0xCA, 0xB2, ++ 0x1C, 0x44, 0x03, 0xF8, 0x01, 0x2B, 0x9C, 0x42, 0xFB, 0xD1, 0xF0, 0xBC, ++ 0x70, 0x47, 0x34, 0x46, 0x13, 0x46, 0x00, 0x2C, 0xF3, 0xD1, 0xF8, 0xE7, ++ 0x14, 0x46, 0x03, 0x46, 0xC1, 0xE7, 0x1A, 0x46, 0x26, 0x46, 0xE0, 0xE7, ++ 0x2D, 0xE9, 0xF0, 0x47, 0xDF, 0xF8, 0x68, 0x91, 0x4F, 0x4F, 0xD9, 0xF8, ++ 0x00, 0x60, 0xDF, 0xF8, 0x64, 0xC1, 0x33, 0x89, 0xD6, 0xF8, 0x34, 0xE0, ++ 0xC7, 0xF8, 0x10, 0xE0, 0xD6, 0xE9, 0x09, 0x10, 0xD6, 0xE9, 0x0B, 0x45, ++ 0x39, 0x60, 0xC9, 0x08, 0x03, 0x29, 0x78, 0x60, 0x4F, 0xEA, 0xD0, 0x00, ++ 0x38, 0xBF, 0x03, 0x21, 0xBC, 0x60, 0x03, 0x28, 0x4F, 0xEA, 0xD4, 0x04, ++ 0x38, 0xBF, 0x03, 0x20, 0xFD, 0x60, 0x03, 0x2C, 0x4F, 0xEA, 0xD5, 0x05, ++ 0x4F, 0xF0, 0x54, 0x02, 0x4F, 0xEA, 0xDE, 0x07, 0x2C, 0xF0, 0x03, 0x0C, ++ 0x38, 0xBF, 0x03, 0x24, 0xDF, 0xF8, 0x1C, 0xE1, 0xDF, 0xF8, 0x1C, 0x81, ++ 0xDF, 0xF8, 0x1C, 0xA1, 0xC8, 0xF8, 0x00, 0x10, 0x03, 0x2D, 0x03, 0xFB, ++ 0x02, 0x22, 0x38, 0xBF, 0x03, 0x25, 0x62, 0x44, 0x03, 0x2F, 0x38, 0xBF, ++ 0x03, 0x27, 0x72, 0x45, 0xC8, 0xE9, 0x01, 0x04, 0xC8, 0xE9, 0x03, 0x57, ++ 0xCA, 0xF8, 0x00, 0xC0, 0x4F, 0xD8, 0x01, 0x33, 0xDF, 0xF8, 0xF4, 0xE0, ++ 0x2E, 0x4A, 0xDF, 0xF8, 0xF4, 0x80, 0xDF, 0xF8, 0xF4, 0x90, 0x4F, 0xF0, ++ 0x58, 0x0C, 0x0C, 0xFB, 0x03, 0xE3, 0xD2, 0xF8, 0x00, 0xC0, 0x2A, 0x4A, ++ 0x13, 0x60, 0x4F, 0xF4, 0xAC, 0x72, 0x02, 0xFB, 0x01, 0x33, 0x02, 0xFB, ++ 0x00, 0x30, 0x02, 0xFB, 0x04, 0x04, 0x02, 0xFB, 0x05, 0x45, 0xDC, 0xF8, ++ 0x00, 0x10, 0xC8, 0xF8, 0x00, 0x50, 0x02, 0xFB, 0x07, 0x52, 0xC9, 0xF8, ++ 0x00, 0x40, 0x21, 0x4F, 0x21, 0x4D, 0x22, 0x4C, 0x38, 0x60, 0x2B, 0x60, ++ 0xC4, 0xF8, 0x00, 0xE0, 0x41, 0xB9, 0xDC, 0xF8, 0x04, 0x30, 0x04, 0x33, ++ 0x11, 0x1D, 0x23, 0xF0, 0x03, 0x03, 0xCC, 0xF8, 0x00, 0x10, 0x1A, 0x44, ++ 0xDC, 0xF8, 0x08, 0x30, 0x13, 0xB9, 0x04, 0x32, 0xCC, 0xF8, 0x08, 0x20, ++ 0x18, 0x4B, 0xF2, 0x68, 0x1A, 0x60, 0x33, 0x78, 0x02, 0x2B, 0x0E, 0xD0, ++ 0x01, 0x2B, 0x01, 0xD0, 0xBD, 0xE8, 0xF0, 0x87, 0x72, 0x69, 0x00, 0x2A, ++ 0xFA, 0xD0, 0x13, 0x49, 0x91, 0x42, 0xF7, 0xD9, 0xBD, 0xE8, 0xF0, 0x47, ++ 0x11, 0x48, 0x05, 0xF0, 0xC1, 0xBF, 0x32, 0x69, 0xF3, 0xE7, 0x71, 0x46, ++ 0x0F, 0x48, 0x05, 0xF0, 0xBB, 0xFF, 0xD9, 0xF8, 0x00, 0x60, 0xD8, 0xF8, ++ 0x00, 0x10, 0x33, 0x89, 0xD8, 0xE9, 0x01, 0x04, 0xD8, 0xE9, 0x03, 0x57, ++ 0x01, 0x33, 0xA1, 0xE7, 0x7C, 0x28, 0x17, 0x00, 0x30, 0x36, 0x17, 0x00, ++ 0xEC, 0x57, 0x18, 0x00, 0xF4, 0x57, 0x18, 0x00, 0xF0, 0x57, 0x18, 0x00, ++ 0x14, 0x63, 0x18, 0x00, 0x00, 0x38, 0x18, 0x00, 0x00, 0x38, 0x18, 0x00, ++ 0x44, 0x76, 0x15, 0x00, 0x18, 0x76, 0x15, 0x00, 0x78, 0x36, 0x17, 0x00, ++ 0x2B, 0x07, 0x18, 0x00, 0x00, 0x24, 0x18, 0x00, 0x8C, 0x1F, 0x17, 0x00, ++ 0x40, 0x61, 0x17, 0x00, 0xE0, 0x9F, 0x18, 0x00, 0xFC, 0x57, 0x18, 0x00, ++ 0xF8, 0x57, 0x18, 0x00, 0x2D, 0xE9, 0xF0, 0x41, 0x49, 0x4C, 0x4A, 0x49, ++ 0x4A, 0x4E, 0x4B, 0x4A, 0x4B, 0x4D, 0x4C, 0x48, 0x0C, 0x60, 0x04, 0xF1, ++ 0x44, 0x07, 0x21, 0x1D, 0xD4, 0xF8, 0xD0, 0x30, 0x37, 0x60, 0x04, 0xF1, ++ 0x80, 0x07, 0x11, 0x60, 0x2F, 0x60, 0x47, 0x49, 0x47, 0x4A, 0x04, 0xF1, ++ 0x90, 0x05, 0x23, 0xF0, 0x7F, 0x43, 0x05, 0x60, 0x04, 0xF1, 0xA8, 0x00, ++ 0x08, 0x60, 0x23, 0xF0, 0xFF, 0x03, 0x04, 0xF1, 0xAA, 0x01, 0x11, 0x60, ++ 0x83, 0xB1, 0x94, 0xF8, 0xD1, 0x30, 0x23, 0xB1, 0x3F, 0x4A, 0x53, 0x6D, ++ 0x23, 0xF0, 0x01, 0x03, 0x53, 0x65, 0x94, 0xF8, 0xD2, 0x30, 0x00, 0x2B, ++ 0x5B, 0xD1, 0x3B, 0x4B, 0x4F, 0xF0, 0x80, 0x62, 0xC3, 0xF8, 0x10, 0x21, ++ 0x39, 0x4D, 0x3A, 0x4F, 0xD5, 0xF8, 0x30, 0x32, 0xDF, 0xF8, 0xF8, 0x80, ++ 0x98, 0x47, 0x01, 0x21, 0x00, 0x20, 0x05, 0xF0, 0x5F, 0xFF, 0x00, 0x20, ++ 0x05, 0xF0, 0x9A, 0xFF, 0x01, 0x21, 0x02, 0x20, 0x05, 0xF0, 0x58, 0xFF, ++ 0x02, 0x20, 0x05, 0xF0, 0x93, 0xFF, 0x01, 0x21, 0x03, 0x20, 0x05, 0xF0, ++ 0x51, 0xFF, 0x03, 0x20, 0x05, 0xF0, 0x8C, 0xFF, 0x3B, 0x68, 0x03, 0xF0, ++ 0x0F, 0x03, 0xA3, 0xF1, 0x0A, 0x03, 0xB3, 0xFA, 0x83, 0xF3, 0x5B, 0x09, ++ 0x88, 0xF8, 0x02, 0x30, 0x25, 0xF0, 0x0E, 0xFA, 0x05, 0xF0, 0x90, 0xFA, ++ 0x06, 0xF0, 0x54, 0xF8, 0xD5, 0xF8, 0x74, 0x32, 0x98, 0x47, 0x94, 0xF8, ++ 0x44, 0x10, 0x23, 0x48, 0x24, 0xF0, 0xEE, 0xF8, 0x07, 0xF0, 0x8C, 0xF8, ++ 0x06, 0xF0, 0xA8, 0xF9, 0x98, 0xF8, 0x02, 0x30, 0x0B, 0xB3, 0xD5, 0xF8, ++ 0x6C, 0x34, 0x98, 0x47, 0x1D, 0x4A, 0x1E, 0x49, 0x13, 0x68, 0x23, 0xF0, ++ 0x08, 0x03, 0x13, 0x60, 0x3B, 0x68, 0x23, 0xF0, 0x0F, 0x03, 0x3B, 0x60, ++ 0x02, 0x20, 0x24, 0xF0, 0x27, 0xF9, 0x33, 0x68, 0x1B, 0x78, 0x03, 0x2B, ++ 0x02, 0xD1, 0x17, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0xD5, 0xF8, 0x80, 0x32, ++ 0xBD, 0xE8, 0xF0, 0x41, 0x18, 0x47, 0x0D, 0x4A, 0x53, 0x6D, 0x23, 0xF0, ++ 0x02, 0x03, 0x53, 0x65, 0x9D, 0xE7, 0x11, 0x49, 0x02, 0x20, 0x24, 0xF0, ++ 0x11, 0xF9, 0xE8, 0xE7, 0x2C, 0x19, 0x17, 0x00, 0x34, 0x36, 0x17, 0x00, ++ 0x78, 0x36, 0x17, 0x00, 0xC8, 0x35, 0x17, 0x00, 0x30, 0x36, 0x17, 0x00, ++ 0xAC, 0x35, 0x17, 0x00, 0x74, 0x36, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x00, 0x00, 0x50, 0x40, 0x88, 0x1A, 0x17, 0x00, 0x1C, 0x00, 0x58, 0x40, ++ 0x70, 0x76, 0x15, 0x00, 0x10, 0x00, 0x58, 0x40, 0x80, 0x76, 0x15, 0x00, ++ 0x00, 0x41, 0x04, 0x40, 0x8C, 0x76, 0x15, 0x00, 0x3C, 0x36, 0x17, 0x00, ++ 0xF8, 0xB5, 0x20, 0x4B, 0x04, 0x46, 0x1E, 0x68, 0x1D, 0x68, 0x00, 0xF0, ++ 0xAB, 0xFE, 0x07, 0x46, 0x00, 0xF0, 0xAA, 0xFE, 0x01, 0x2C, 0xC6, 0xF3, ++ 0x03, 0x26, 0xC5, 0xF3, 0xC0, 0x65, 0x14, 0xD0, 0x02, 0x2C, 0x0E, 0xD0, ++ 0x3C, 0xB1, 0x18, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0x1C, 0xDB, 0x00, 0x20, 0xF8, 0xBD, 0x90, 0xB9, 0x05, 0xBB, 0x70, 0x1E, ++ 0x18, 0xBF, 0x01, 0x20, 0xF8, 0xBD, 0x01, 0x2E, 0x0D, 0xD0, 0x68, 0x1D, ++ 0xF8, 0xBD, 0x30, 0xB9, 0x01, 0x2E, 0x17, 0xD0, 0x00, 0x2F, 0x0C, 0xBF, ++ 0x03, 0x20, 0x09, 0x20, 0xF8, 0xBD, 0x0B, 0x20, 0xF8, 0xBD, 0x0A, 0x20, ++ 0xF8, 0xBD, 0x00, 0x2D, 0x14, 0xBF, 0x07, 0x20, 0x04, 0x20, 0xF8, 0xBD, ++ 0x07, 0x49, 0x08, 0x48, 0x40, 0xF2, 0xB5, 0x12, 0x24, 0xF0, 0xDC, 0xFA, ++ 0x00, 0x20, 0xF8, 0xBD, 0x08, 0x20, 0xF8, 0xBD, 0x02, 0x20, 0xF8, 0xBD, ++ 0x00, 0x00, 0x33, 0x40, 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x64, 0x7D, 0x15, 0x00, 0x10, 0xB4, 0x09, 0x49, 0x0B, 0x69, 0x83, 0xB0, ++ 0x18, 0x44, 0x20, 0x24, 0x01, 0x94, 0x01, 0x9B, 0x5A, 0x1E, 0x01, 0x92, ++ 0x00, 0x2B, 0xFA, 0xD1, 0x0B, 0x69, 0x1B, 0x1A, 0x00, 0x2B, 0xF5, 0xDB, ++ 0x03, 0xB0, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, 0x00, 0x10, 0x50, 0x40, ++ 0x08, 0xB5, 0xFF, 0xF7, 0x9D, 0xFF, 0x03, 0x4B, 0x1A, 0x78, 0x82, 0x42, ++ 0x18, 0xBF, 0x18, 0x70, 0x08, 0xBD, 0x00, 0xBF, 0x60, 0x25, 0x17, 0x00, ++ 0x38, 0xB5, 0x10, 0x4B, 0x10, 0x4C, 0x18, 0x68, 0xC0, 0xF3, 0x01, 0x60, ++ 0xFF, 0xF7, 0x8C, 0xFF, 0x08, 0x22, 0x05, 0x46, 0x00, 0x21, 0x20, 0x46, ++ 0xFF, 0xF7, 0xB6, 0xFD, 0x0B, 0x48, 0x0C, 0x4A, 0x00, 0xEB, 0x05, 0x10, ++ 0xFF, 0x21, 0xC3, 0x88, 0x80, 0x88, 0x10, 0x60, 0xC3, 0xF3, 0x85, 0x12, ++ 0x03, 0xF0, 0x3F, 0x03, 0x1A, 0x44, 0x21, 0x70, 0x4F, 0xF4, 0x96, 0x63, ++ 0xB3, 0xFB, 0xF2, 0xF3, 0x63, 0x70, 0x38, 0xBD, 0x00, 0x00, 0x33, 0x40, ++ 0x60, 0x25, 0x17, 0x00, 0x98, 0x76, 0x15, 0x00, 0x6C, 0x00, 0x34, 0x40, ++ 0x01, 0x4B, 0x58, 0x78, 0x70, 0x47, 0x00, 0xBF, 0x60, 0x25, 0x17, 0x00, ++ 0x10, 0xB4, 0x13, 0x4B, 0x13, 0x49, 0x11, 0x22, 0x1A, 0x60, 0x08, 0x69, ++ 0x83, 0xB0, 0x0A, 0x30, 0x20, 0x24, 0x00, 0x94, 0x00, 0x9B, 0x5A, 0x1E, ++ 0x00, 0x92, 0x00, 0x2B, 0xFA, 0xD1, 0x0A, 0x69, 0x12, 0x1A, 0x00, 0x2A, ++ 0xF5, 0xDB, 0x0A, 0x4A, 0x0A, 0x4C, 0x13, 0x60, 0x09, 0x69, 0x20, 0x20, ++ 0x0A, 0x31, 0x01, 0x90, 0x01, 0x9B, 0x5A, 0x1E, 0x01, 0x92, 0x00, 0x2B, ++ 0xFA, 0xD1, 0x23, 0x69, 0x5B, 0x1A, 0x00, 0x2B, 0xF5, 0xDB, 0x03, 0xB0, ++ 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, 0x00, 0xBF, 0x18, 0x00, 0x34, 0x40, ++ 0x00, 0x10, 0x50, 0x40, 0x16, 0x4A, 0x13, 0x68, 0x43, 0xF4, 0x80, 0x53, ++ 0x10, 0xB4, 0x13, 0x60, 0x00, 0xBF, 0x02, 0xF5, 0x99, 0x42, 0x13, 0x68, ++ 0x43, 0xF0, 0x00, 0x53, 0x13, 0x60, 0x00, 0xBF, 0x10, 0x4B, 0x11, 0x48, ++ 0x03, 0xF5, 0x00, 0x64, 0xC0, 0x1A, 0x1A, 0x18, 0x53, 0xF8, 0x04, 0x1B, ++ 0x11, 0x60, 0xA3, 0x42, 0xF9, 0xD1, 0x00, 0xBF, 0x09, 0x4B, 0x1A, 0x68, ++ 0x42, 0xF4, 0x00, 0x22, 0x1A, 0x60, 0x00, 0xBF, 0x1A, 0x68, 0x22, 0xF4, ++ 0x80, 0x52, 0x1A, 0x60, 0x00, 0xBF, 0x07, 0x4A, 0x5D, 0xF8, 0x04, 0x4B, ++ 0x13, 0x68, 0x23, 0xF0, 0x00, 0x53, 0x13, 0x60, 0x70, 0x47, 0x00, 0xBF, ++ 0x90, 0xB3, 0x33, 0x40, 0xB0, 0x05, 0x17, 0x00, 0x00, 0xA0, 0x33, 0x40, ++ 0x10, 0x00, 0x34, 0x40, 0x2D, 0xE9, 0xF0, 0x41, 0x07, 0x46, 0x15, 0x46, ++ 0x1C, 0x46, 0x9D, 0xF8, 0x18, 0x80, 0x0E, 0x46, 0xFF, 0xF7, 0x94, 0xFF, ++ 0x6C, 0x4A, 0x13, 0x68, 0x01, 0x2F, 0x23, 0xF0, 0x40, 0x03, 0x13, 0x60, ++ 0x00, 0xF0, 0x98, 0x80, 0x69, 0x4A, 0x6A, 0x49, 0x13, 0x68, 0x23, 0xF4, ++ 0xE0, 0x33, 0x43, 0xF4, 0x40, 0x43, 0x13, 0x60, 0x0B, 0x68, 0x02, 0xF5, ++ 0xD9, 0x32, 0x02, 0xF5, 0xA2, 0x72, 0x43, 0xF0, 0x01, 0x03, 0x0B, 0x60, ++ 0x13, 0x68, 0x23, 0xF4, 0x80, 0x73, 0x13, 0x60, 0x61, 0x4A, 0x10, 0x68, ++ 0x20, 0xF4, 0xFF, 0x40, 0x20, 0xF0, 0x7F, 0x00, 0x4F, 0xF0, 0x80, 0x63, ++ 0xB3, 0xFB, 0xF5, 0xF3, 0xC3, 0xF3, 0x0E, 0x03, 0x03, 0x43, 0x01, 0x2C, ++ 0x13, 0x60, 0x60, 0xD0, 0x02, 0x2C, 0x48, 0xD0, 0x00, 0x25, 0x59, 0x4B, ++ 0x1E, 0x68, 0x26, 0xF0, 0x03, 0x06, 0x35, 0x43, 0x1D, 0x60, 0x00, 0x23, ++ 0x56, 0x4A, 0x57, 0x49, 0x13, 0x60, 0x0B, 0x68, 0x56, 0x4D, 0x57, 0x48, ++ 0x57, 0x4E, 0x22, 0x06, 0x02, 0xF0, 0x40, 0x72, 0x23, 0xF0, 0x40, 0x73, ++ 0x13, 0x43, 0x0B, 0x60, 0x29, 0x68, 0x23, 0x04, 0x21, 0xF4, 0x40, 0x31, ++ 0x03, 0xF4, 0x40, 0x33, 0x0B, 0x43, 0x2B, 0x60, 0x03, 0x68, 0x23, 0xF0, ++ 0x80, 0x43, 0x03, 0x60, 0x31, 0x68, 0x05, 0xF5, 0x82, 0x35, 0x04, 0xF0, ++ 0x0F, 0x03, 0x21, 0xF0, 0x0F, 0x01, 0x05, 0xF5, 0x88, 0x75, 0x0B, 0x43, ++ 0x33, 0x60, 0x2B, 0x68, 0x23, 0xF0, 0x40, 0x73, 0x1A, 0x43, 0x2A, 0x60, ++ 0xEC, 0xB9, 0x50, 0xF8, 0x08, 0x3C, 0x45, 0x49, 0x45, 0x4A, 0x23, 0xF0, ++ 0x7F, 0x43, 0x43, 0xF0, 0xC8, 0x53, 0x40, 0xF8, 0x08, 0x3C, 0x0B, 0x68, ++ 0x23, 0xF0, 0x30, 0x03, 0x0B, 0x60, 0x13, 0x68, 0x23, 0xF4, 0x7F, 0x43, ++ 0x43, 0xF4, 0x1C, 0x43, 0x13, 0x60, 0xBD, 0xE8, 0xF0, 0x81, 0xAD, 0x1B, ++ 0x00, 0x2D, 0x42, 0xDD, 0x0A, 0x2D, 0xCC, 0xBF, 0x00, 0x25, 0x01, 0x25, ++ 0xAF, 0xE7, 0x01, 0x2C, 0x41, 0xD0, 0x38, 0x4A, 0x38, 0x49, 0x13, 0x68, ++ 0x38, 0x48, 0x23, 0xF0, 0x7F, 0x43, 0x43, 0xF0, 0x60, 0x63, 0x13, 0x60, ++ 0x08, 0x60, 0xBD, 0xE8, 0xF0, 0x81, 0x02, 0xF5, 0x28, 0x42, 0xB5, 0x42, ++ 0x53, 0x6B, 0x88, 0xBF, 0x01, 0x21, 0x23, 0xF0, 0x03, 0x03, 0x98, 0xBF, ++ 0x02, 0x21, 0x43, 0xEA, 0x01, 0x03, 0x02, 0xF1, 0x34, 0x02, 0x13, 0x60, ++ 0x94, 0xBF, 0x01, 0x23, 0x00, 0x23, 0x95, 0xE7, 0x1D, 0x49, 0x1E, 0x48, ++ 0x0B, 0x68, 0x23, 0xF4, 0xE0, 0x33, 0x43, 0xF4, 0xC0, 0x33, 0x0B, 0x60, ++ 0x03, 0x68, 0x01, 0xF5, 0xD9, 0x31, 0x01, 0xF5, 0xA2, 0x71, 0x23, 0xF0, ++ 0x01, 0x03, 0x03, 0x60, 0x0B, 0x68, 0x18, 0xF0, 0x04, 0x0F, 0x43, 0xF4, ++ 0x80, 0x73, 0x0B, 0x60, 0x3F, 0xF4, 0x64, 0xAF, 0x13, 0x68, 0x43, 0xF0, ++ 0x40, 0x03, 0x13, 0x60, 0x5E, 0xE7, 0x15, 0xF1, 0x0A, 0x0F, 0xB4, 0xBF, ++ 0x03, 0x25, 0x02, 0x25, 0x6B, 0xE7, 0x1A, 0x48, 0x14, 0x49, 0x03, 0x68, ++ 0x14, 0x4A, 0x23, 0xF0, 0x7F, 0x43, 0x43, 0xF0, 0xC0, 0x53, 0x03, 0x60, ++ 0x0B, 0x68, 0x23, 0xF0, 0x30, 0x03, 0x43, 0xF0, 0x10, 0x03, 0x0B, 0x60, ++ 0x13, 0x68, 0x23, 0xF4, 0x7F, 0x43, 0x43, 0xF4, 0xD8, 0x43, 0x13, 0x60, ++ 0xBD, 0xE8, 0xF0, 0x81, 0x24, 0x03, 0x32, 0x40, 0x4C, 0x00, 0x32, 0x40, ++ 0x20, 0x08, 0x33, 0x40, 0x4C, 0x08, 0x33, 0x40, 0x80, 0xB0, 0x33, 0x40, ++ 0x50, 0x08, 0x33, 0x40, 0x24, 0x08, 0x33, 0x40, 0x10, 0x03, 0x32, 0x40, ++ 0x0C, 0x08, 0x33, 0x40, 0x00, 0x08, 0x33, 0x40, 0x08, 0x00, 0x34, 0x40, ++ 0x8C, 0x08, 0x33, 0x40, 0x34, 0x08, 0x33, 0x40, 0x18, 0x08, 0x33, 0x40, ++ 0x06, 0x0C, 0x8E, 0x01, 0x04, 0x08, 0x33, 0x40, 0x44, 0x49, 0x45, 0x4A, ++ 0x0B, 0x68, 0x23, 0xF4, 0xFC, 0x63, 0x70, 0xB4, 0x0B, 0x60, 0x13, 0x68, ++ 0x42, 0x4C, 0x43, 0x4D, 0x43, 0x4E, 0x23, 0xF4, 0xE0, 0x23, 0x43, 0xF4, ++ 0x80, 0x33, 0x13, 0x60, 0x13, 0x68, 0x23, 0xF4, 0xE0, 0x03, 0x43, 0xF4, ++ 0x00, 0x13, 0x13, 0x60, 0x23, 0x68, 0xA1, 0xF5, 0x0F, 0x41, 0x23, 0xF4, ++ 0x00, 0x03, 0x23, 0x60, 0x04, 0x39, 0x0C, 0x23, 0x2B, 0x60, 0x0B, 0x68, ++ 0x32, 0x6A, 0x23, 0xF4, 0xFE, 0x43, 0x23, 0xF0, 0x7F, 0x03, 0x13, 0x43, ++ 0x40, 0xF6, 0xB4, 0x12, 0x90, 0x42, 0x0B, 0x60, 0x34, 0x4B, 0x26, 0xD0, ++ 0x72, 0x6A, 0x1A, 0x60, 0xA0, 0xF6, 0x6C, 0x13, 0x3C, 0x2B, 0x22, 0xD8, ++ 0xDF, 0xE8, 0x03, 0xF0, 0x40, 0x21, 0x21, 0x21, 0x21, 0x40, 0x21, 0x21, ++ 0x21, 0x21, 0x40, 0x21, 0x21, 0x21, 0x21, 0x40, 0x21, 0x21, 0x21, 0x21, ++ 0x40, 0x21, 0x21, 0x21, 0x21, 0x40, 0x21, 0x21, 0x21, 0x21, 0x40, 0x21, ++ 0x21, 0x21, 0x21, 0x47, 0x21, 0x21, 0x21, 0x21, 0x47, 0x21, 0x21, 0x21, ++ 0x21, 0x47, 0x21, 0x21, 0x21, 0x21, 0x47, 0x21, 0x21, 0x21, 0x21, 0x47, ++ 0x21, 0x21, 0x21, 0x21, 0x47, 0x00, 0x21, 0x4A, 0x1A, 0x60, 0x21, 0x4A, ++ 0x21, 0x49, 0x13, 0x68, 0x91, 0xF8, 0xB4, 0x10, 0x23, 0xF0, 0x04, 0x03, ++ 0x13, 0x60, 0x99, 0xB1, 0x1E, 0x49, 0x1F, 0x4B, 0x0A, 0x68, 0x22, 0xF4, ++ 0xFE, 0x62, 0x0A, 0x60, 0x1A, 0x68, 0x22, 0xF0, 0x0F, 0x02, 0x42, 0xF0, ++ 0x01, 0x02, 0x1A, 0x60, 0x9A, 0x68, 0x22, 0xF0, 0x0F, 0x02, 0x9A, 0x60, ++ 0xDA, 0x68, 0x22, 0xF0, 0x0F, 0x02, 0xDA, 0x60, 0x70, 0xBC, 0x70, 0x47, ++ 0x15, 0x49, 0x16, 0x4B, 0xB0, 0x6A, 0x72, 0x6B, 0x08, 0x60, 0x1A, 0x60, ++ 0xD9, 0xE7, 0x12, 0x4B, 0xF4, 0x6A, 0xB1, 0x6B, 0x11, 0x4A, 0x1C, 0x60, ++ 0x40, 0xF6, 0xA8, 0x13, 0x98, 0x42, 0x11, 0x60, 0xCF, 0xD1, 0x0F, 0x4B, ++ 0x11, 0x22, 0x1A, 0x60, 0xCB, 0xE7, 0x00, 0xBF, 0x04, 0x40, 0x34, 0x40, ++ 0x34, 0x21, 0x34, 0x40, 0x2C, 0x20, 0x34, 0x40, 0x00, 0xB3, 0x33, 0x40, ++ 0xDC, 0x18, 0x17, 0x00, 0x20, 0x03, 0x33, 0x40, 0x1B, 0x88, 0xB3, 0x01, ++ 0x30, 0x20, 0x34, 0x40, 0x2C, 0x19, 0x17, 0x00, 0x78, 0x40, 0x34, 0x40, ++ 0x00, 0x30, 0x50, 0x40, 0x30, 0x40, 0x34, 0x40, 0x2C, 0x40, 0x34, 0x40, ++ 0x24, 0x01, 0x58, 0x40, 0x70, 0x47, 0x00, 0xBF, 0x3A, 0x49, 0x3B, 0x4A, ++ 0x0B, 0x68, 0x23, 0xF4, 0xFC, 0x63, 0x43, 0xF4, 0xA8, 0x63, 0x30, 0xB4, ++ 0x0B, 0x60, 0x13, 0x68, 0x37, 0x4C, 0x38, 0x4D, 0x23, 0xF4, 0xE0, 0x23, ++ 0x43, 0xF4, 0x00, 0x33, 0x13, 0x60, 0x13, 0x68, 0x23, 0xF4, 0xE0, 0x03, ++ 0x13, 0x60, 0x23, 0x68, 0x33, 0x4A, 0xA1, 0xF5, 0x0F, 0x41, 0x43, 0xF4, ++ 0x00, 0x03, 0x23, 0x60, 0x04, 0x39, 0x0C, 0x23, 0x2B, 0x60, 0x0B, 0x68, ++ 0xD4, 0x6C, 0x23, 0xF4, 0xFE, 0x43, 0x23, 0xF0, 0x7F, 0x03, 0x23, 0x43, ++ 0x41, 0xF2, 0xC8, 0x44, 0xA0, 0x42, 0x0B, 0x60, 0x40, 0xD8, 0x2A, 0x4B, ++ 0x12, 0x6C, 0x1A, 0x60, 0x29, 0x4A, 0x2A, 0x4C, 0x13, 0x68, 0x2A, 0x4D, ++ 0x2A, 0x48, 0x2B, 0x49, 0x23, 0xF0, 0x80, 0x63, 0x13, 0x60, 0x13, 0x68, ++ 0x94, 0xF8, 0xB4, 0x40, 0x23, 0xF0, 0x0F, 0x03, 0x43, 0xF0, 0x08, 0x03, ++ 0x13, 0x60, 0x2B, 0x68, 0x23, 0xF0, 0xC0, 0x63, 0x43, 0xF0, 0x80, 0x63, ++ 0x2B, 0x60, 0x03, 0x68, 0x43, 0xF4, 0x70, 0x63, 0x03, 0x60, 0x0B, 0x68, ++ 0x43, 0xF0, 0x04, 0x03, 0x0B, 0x60, 0xDC, 0xB1, 0x01, 0xF5, 0x01, 0x51, ++ 0x1D, 0x4B, 0x8A, 0x68, 0x22, 0xF4, 0xFE, 0x62, 0x42, 0xF4, 0x88, 0x62, ++ 0x8A, 0x60, 0x1A, 0x68, 0x22, 0xF0, 0x0F, 0x02, 0x42, 0xF0, 0x03, 0x02, ++ 0x1A, 0x60, 0x9A, 0x68, 0x22, 0xF0, 0x0F, 0x02, 0x42, 0xF0, 0x03, 0x02, ++ 0x9A, 0x60, 0xDA, 0x68, 0x22, 0xF0, 0x0F, 0x02, 0x42, 0xF0, 0x03, 0x02, ++ 0x08, 0x31, 0xDA, 0x60, 0x30, 0xBC, 0x70, 0x47, 0x41, 0xF2, 0x44, 0x63, ++ 0x98, 0x42, 0x08, 0x4B, 0x94, 0xBF, 0x52, 0x6C, 0x92, 0x6C, 0x1A, 0x60, ++ 0xB8, 0xE7, 0x00, 0xBF, 0x04, 0x40, 0x34, 0x40, 0x34, 0x21, 0x34, 0x40, ++ 0x2C, 0x20, 0x34, 0x40, 0x00, 0xB3, 0x33, 0x40, 0xDC, 0x18, 0x17, 0x00, ++ 0x30, 0x40, 0x34, 0x40, 0x38, 0x40, 0x34, 0x40, 0x2C, 0x19, 0x17, 0x00, ++ 0x3C, 0x40, 0x34, 0x40, 0x08, 0x01, 0x58, 0x40, 0x30, 0x20, 0x34, 0x40, ++ 0x00, 0x30, 0x50, 0x40, 0x70, 0x47, 0x00, 0xBF, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0x85, 0xB0, 0x0F, 0x46, 0x9D, 0xF8, 0x3C, 0x10, 0x02, 0x91, 0xCD, 0xE9, ++ 0x00, 0x23, 0x05, 0x46, 0x14, 0x46, 0x1E, 0x46, 0x02, 0x46, 0x3B, 0x46, ++ 0xAE, 0x49, 0xAF, 0x48, 0x9D, 0xF8, 0x38, 0xA0, 0xDF, 0xF8, 0x08, 0x83, ++ 0xDF, 0xF8, 0x08, 0x93, 0x23, 0xF0, 0x4C, 0xFD, 0xAB, 0x49, 0x22, 0x46, ++ 0x04, 0x20, 0x23, 0xF0, 0x97, 0xFD, 0x30, 0x46, 0xFF, 0xF7, 0x06, 0xFD, ++ 0x39, 0x46, 0x33, 0x46, 0xD8, 0xF8, 0x40, 0x71, 0xCD, 0xF8, 0x00, 0xA0, ++ 0x22, 0x46, 0x28, 0x46, 0xB8, 0x47, 0x99, 0xF8, 0x2A, 0x30, 0xAB, 0x42, ++ 0x0A, 0xD0, 0xD8, 0xF8, 0x80, 0x34, 0x28, 0x46, 0x98, 0x47, 0x99, 0xF8, ++ 0x2A, 0x20, 0x9F, 0x49, 0x2B, 0x46, 0x04, 0x20, 0x23, 0xF0, 0x7C, 0xFD, ++ 0x9D, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xC0, 0xF2, ++ 0xA8, 0x80, 0x00, 0x2D, 0x00, 0xF0, 0xB7, 0x80, 0x41, 0xF2, 0x43, 0x63, ++ 0x9C, 0x42, 0x00, 0xF2, 0xAE, 0x80, 0x41, 0xF2, 0x7B, 0x53, 0x9C, 0x42, ++ 0x8B, 0xBF, 0x4F, 0xF0, 0xEC, 0x09, 0x4F, 0xF0, 0xFC, 0x09, 0x3B, 0x27, ++ 0x3F, 0x27, 0x20, 0x46, 0x35, 0xF0, 0x0E, 0xFD, 0x02, 0x46, 0x0B, 0x46, ++ 0x82, 0x46, 0x8B, 0x46, 0x35, 0xF0, 0xBC, 0xFB, 0x8D, 0x4B, 0x00, 0x22, ++ 0x35, 0xF0, 0x98, 0xFE, 0x8C, 0x4B, 0x00, 0x22, 0x35, 0xF0, 0x6A, 0xFD, ++ 0x35, 0xF0, 0x62, 0xFB, 0x36, 0xF0, 0x00, 0xF8, 0x52, 0x46, 0x5B, 0x46, ++ 0x88, 0x49, 0x05, 0x46, 0x00, 0x20, 0x35, 0xF0, 0x89, 0xFE, 0x00, 0x22, ++ 0x4F, 0xF0, 0x83, 0x43, 0x35, 0xF0, 0x5A, 0xFD, 0x35, 0xF0, 0x52, 0xFB, ++ 0x35, 0xF0, 0xF0, 0xFF, 0x03, 0x46, 0x38, 0x46, 0x1F, 0x46, 0x35, 0xF0, ++ 0xE7, 0xFC, 0x80, 0x4B, 0x00, 0x22, 0x35, 0xF0, 0x4D, 0xFD, 0x02, 0x46, ++ 0x0B, 0x46, 0x50, 0x46, 0x59, 0x46, 0x35, 0xF0, 0x71, 0xFE, 0x00, 0x22, ++ 0x4F, 0xF0, 0x83, 0x43, 0x35, 0xF0, 0x42, 0xFD, 0x35, 0xF0, 0x3A, 0xFB, ++ 0x35, 0xF0, 0xD8, 0xFF, 0x77, 0x4B, 0x78, 0x4A, 0xD3, 0xF8, 0x00, 0xE0, ++ 0x2E, 0xF4, 0x00, 0x0E, 0xC3, 0xF8, 0x00, 0xE0, 0xD3, 0xF8, 0x00, 0xE0, ++ 0x4E, 0xF4, 0x80, 0x0E, 0xC3, 0xF8, 0x00, 0xE0, 0xD3, 0xF8, 0x00, 0xE0, ++ 0x2E, 0xF4, 0x00, 0x1E, 0xC3, 0xF8, 0x00, 0xE0, 0xD3, 0xF8, 0x00, 0xE0, ++ 0x4E, 0xF0, 0x08, 0x0E, 0xC3, 0xF8, 0x00, 0xE0, 0xD3, 0xF8, 0x00, 0xE0, ++ 0x01, 0x46, 0x2E, 0xF0, 0x04, 0x0E, 0x6A, 0x48, 0xC3, 0xF8, 0x00, 0xE0, ++ 0x03, 0x68, 0x43, 0xF0, 0x80, 0x43, 0x03, 0x60, 0x03, 0x68, 0x43, 0xF0, ++ 0x00, 0x53, 0x03, 0x60, 0x13, 0x68, 0x23, 0xF4, 0xFF, 0x63, 0x23, 0xF0, ++ 0x04, 0x03, 0x43, 0xEA, 0x09, 0x03, 0x13, 0x60, 0x20, 0x46, 0xD8, 0xF8, ++ 0xA8, 0x34, 0x89, 0x46, 0x98, 0x47, 0x20, 0x46, 0xD8, 0xF8, 0xAC, 0x34, ++ 0x64, 0x08, 0x98, 0x47, 0x5C, 0x4B, 0x5D, 0x4A, 0x1D, 0x60, 0x17, 0x60, ++ 0xC3, 0xF8, 0x48, 0x90, 0x00, 0x2E, 0x00, 0xF0, 0x8D, 0x80, 0x01, 0x2E, ++ 0x04, 0xD1, 0x59, 0x4A, 0x13, 0x68, 0x23, 0xF4, 0x00, 0x63, 0x13, 0x60, ++ 0x57, 0x49, 0x58, 0x4B, 0x08, 0x68, 0x58, 0x4A, 0x03, 0x40, 0x43, 0xEA, ++ 0x04, 0x33, 0x01, 0x20, 0x0B, 0x60, 0x10, 0x60, 0x05, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x8F, 0x01, 0x2D, 0x7F, 0xF6, 0x55, 0xAF, 0x52, 0x49, 0x53, 0x48, ++ 0x40, 0xF6, 0x4A, 0x22, 0x23, 0xF0, 0xEE, 0xFE, 0x41, 0xF2, 0x43, 0x63, ++ 0x9C, 0x42, 0x7F, 0xF6, 0x52, 0xAF, 0x4F, 0xF0, 0xF0, 0x09, 0x3C, 0x27, ++ 0x57, 0xE7, 0x20, 0x46, 0x35, 0xF0, 0x66, 0xFC, 0x4B, 0x4B, 0x00, 0x22, ++ 0x82, 0x46, 0x8B, 0x46, 0x35, 0xF0, 0xCA, 0xFC, 0x39, 0x4B, 0x00, 0x22, ++ 0x35, 0xF0, 0xF0, 0xFD, 0x38, 0x4B, 0x00, 0x22, 0x35, 0xF0, 0xC2, 0xFC, ++ 0x35, 0xF0, 0xBA, 0xFA, 0x35, 0xF0, 0x58, 0xFF, 0x52, 0x46, 0x5B, 0x46, ++ 0x05, 0x46, 0x42, 0x49, 0x00, 0x20, 0x35, 0xF0, 0xE1, 0xFD, 0x00, 0x22, ++ 0x4F, 0xF0, 0x83, 0x43, 0x35, 0xF0, 0xB2, 0xFC, 0x35, 0xF0, 0xAA, 0xFA, ++ 0x35, 0xF0, 0x48, 0xFF, 0x24, 0xA3, 0xD3, 0xE9, 0x00, 0x23, 0x07, 0x46, ++ 0x59, 0x46, 0x50, 0x46, 0x35, 0xF0, 0xD0, 0xFD, 0x00, 0x22, 0x4F, 0xF0, ++ 0x83, 0x43, 0x35, 0xF0, 0xA1, 0xFC, 0x35, 0xF0, 0x99, 0xFA, 0x35, 0xF0, ++ 0x37, 0xFF, 0x27, 0x4B, 0x28, 0x4A, 0x19, 0x68, 0x21, 0xF4, 0x00, 0x01, ++ 0x19, 0x60, 0x19, 0x68, 0x21, 0xF4, 0x80, 0x01, 0x19, 0x60, 0x19, 0x68, ++ 0x41, 0xF4, 0x00, 0x11, 0x19, 0x60, 0x19, 0x68, 0x21, 0xF0, 0x08, 0x01, ++ 0x19, 0x60, 0x19, 0x68, 0x41, 0xF0, 0x04, 0x01, 0x19, 0x60, 0x13, 0x68, ++ 0x23, 0xF0, 0x80, 0x43, 0x13, 0x60, 0x13, 0x68, 0x81, 0x46, 0x23, 0xF0, ++ 0x00, 0x53, 0x19, 0x48, 0x13, 0x60, 0x03, 0x68, 0x23, 0xF4, 0xFF, 0x63, ++ 0x23, 0xF0, 0x04, 0x03, 0x43, 0xF0, 0xEC, 0x03, 0x03, 0x60, 0xD8, 0xF8, ++ 0xA0, 0x34, 0x20, 0x46, 0x98, 0x47, 0xD8, 0xF8, 0xA4, 0x34, 0x20, 0x46, ++ 0x98, 0x47, 0x69, 0xE7, 0x13, 0x4A, 0x13, 0x68, 0x43, 0xF4, 0x00, 0x63, ++ 0x13, 0x60, 0x73, 0xE7, 0xAF, 0xF3, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x70, 0xA2, 0x40, 0x78, 0x78, 0x15, 0x00, 0x58, 0x77, 0x15, 0x00, ++ 0x8C, 0x77, 0x15, 0x00, 0x9C, 0x77, 0x15, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x00, 0x00, 0x6A, 0x40, 0x00, 0x00, 0x50, 0x41, 0x00, 0x00, 0xB9, 0x40, ++ 0x00, 0x00, 0x54, 0x40, 0x14, 0x40, 0x34, 0x40, 0x3C, 0x40, 0x34, 0x40, ++ 0x30, 0x40, 0x34, 0x40, 0x10, 0x20, 0x34, 0x40, 0x54, 0x20, 0x34, 0x40, ++ 0x20, 0x40, 0x34, 0x40, 0x1C, 0x20, 0x34, 0x40, 0xFF, 0x0F, 0x00, 0xE0, ++ 0x84, 0x21, 0x34, 0x40, 0x70, 0x79, 0x15, 0x00, 0xB4, 0x77, 0x15, 0x00, ++ 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0xA4, 0x40, 0x88, 0x1A, 0x17, 0x00, ++ 0xBC, 0x34, 0x17, 0x00, 0xF8, 0xB5, 0x43, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0x6B, 0xDB, 0xFF, 0xF7, 0xBD, 0xFB, 0x40, 0x49, ++ 0x40, 0x4A, 0x0B, 0x68, 0x40, 0x48, 0x43, 0xF0, 0x00, 0x63, 0x0B, 0x60, ++ 0x13, 0x68, 0x43, 0xF0, 0x08, 0x03, 0x13, 0x60, 0x03, 0x68, 0xC3, 0xF3, ++ 0x03, 0x23, 0x02, 0x2B, 0x06, 0xD1, 0xA2, 0xF5, 0x99, 0x42, 0x04, 0x3A, ++ 0x13, 0x68, 0x43, 0xF0, 0x03, 0x03, 0x13, 0x60, 0x36, 0x4B, 0x1B, 0x68, ++ 0xC3, 0xF3, 0x03, 0x13, 0x02, 0x2B, 0x02, 0xD1, 0x34, 0x4B, 0x35, 0x4A, ++ 0x1A, 0x60, 0x35, 0x4A, 0x35, 0x49, 0x13, 0x68, 0xDF, 0xF8, 0x04, 0xC1, ++ 0x34, 0x4D, 0x35, 0x4F, 0x35, 0x4C, 0x36, 0x48, 0x36, 0x4E, 0x23, 0xF4, ++ 0xFF, 0x63, 0x23, 0xF0, 0x07, 0x03, 0x43, 0xF4, 0xE0, 0x63, 0x13, 0x60, ++ 0x4F, 0xF4, 0x80, 0x73, 0x0B, 0x60, 0x04, 0x23, 0xCC, 0xF8, 0x00, 0x30, ++ 0x01, 0x22, 0xC4, 0x23, 0x3A, 0x60, 0x2B, 0x60, 0x00, 0x23, 0x23, 0x60, ++ 0x6F, 0x24, 0x04, 0x60, 0x2C, 0x4C, 0xB0, 0x27, 0x37, 0x60, 0x23, 0x60, ++ 0xC3, 0x60, 0xAB, 0x61, 0x6B, 0x25, 0xE5, 0x60, 0x29, 0x4D, 0x83, 0x61, ++ 0x2A, 0x60, 0xA3, 0x61, 0x07, 0x24, 0x44, 0x62, 0xEC, 0x26, 0x27, 0x4C, ++ 0xEE, 0x60, 0x03, 0x25, 0xC5, 0x62, 0x23, 0x60, 0xD0, 0xF8, 0xEC, 0x31, ++ 0x93, 0x42, 0x00, 0xF5, 0xF6, 0x70, 0x0F, 0xD9, 0x22, 0x4B, 0xA0, 0xF5, ++ 0x56, 0x70, 0x1A, 0x60, 0x03, 0x68, 0x23, 0xF0, 0x7F, 0x43, 0x43, 0xF0, ++ 0x20, 0x43, 0x03, 0x60, 0x0B, 0x68, 0x23, 0xF4, 0x40, 0x73, 0x43, 0xF4, ++ 0x80, 0x73, 0x0B, 0x60, 0xF8, 0xBD, 0x1B, 0x4A, 0x13, 0x68, 0x12, 0x68, ++ 0x1B, 0x0E, 0x02, 0x33, 0x03, 0xEB, 0x83, 0x03, 0xC2, 0xF3, 0x07, 0x42, ++ 0x02, 0xEB, 0x43, 0x03, 0x1E, 0x2B, 0x86, 0xD0, 0x15, 0x49, 0x16, 0x48, ++ 0x40, 0xF6, 0x2C, 0x32, 0x23, 0xF0, 0xBC, 0xFD, 0x7F, 0xE7, 0x00, 0xBF, ++ 0x38, 0x36, 0x17, 0x00, 0x10, 0x00, 0x34, 0x40, 0x14, 0x00, 0x34, 0x40, ++ 0x00, 0x00, 0x33, 0x40, 0x04, 0xB1, 0x33, 0x40, 0x34, 0x34, 0x34, 0x00, ++ 0xB4, 0xB3, 0x33, 0x40, 0x00, 0x10, 0x34, 0x40, 0x08, 0x12, 0x34, 0x40, ++ 0x04, 0x12, 0x34, 0x40, 0x0C, 0x12, 0x34, 0x40, 0x10, 0x12, 0x34, 0x40, ++ 0x14, 0x12, 0x34, 0x40, 0x18, 0x12, 0x34, 0x40, 0x2C, 0x12, 0x34, 0x40, ++ 0x40, 0x12, 0x34, 0x40, 0x0C, 0x10, 0x34, 0x40, 0x3C, 0x00, 0x33, 0x40, ++ 0x70, 0x79, 0x15, 0x00, 0xC8, 0x77, 0x15, 0x00, 0x00, 0x12, 0x34, 0x40, ++ 0x10, 0xB5, 0x1A, 0x4C, 0x82, 0xB0, 0xD4, 0xF8, 0x3C, 0x31, 0x98, 0x47, ++ 0x18, 0x4B, 0x19, 0x4A, 0x1A, 0x60, 0x1A, 0x68, 0x42, 0xF0, 0x00, 0x42, ++ 0x1A, 0x60, 0x1A, 0x68, 0x00, 0x2A, 0xFC, 0xDB, 0x15, 0x4A, 0x1A, 0x60, ++ 0x19, 0x68, 0x12, 0x4A, 0x41, 0xF0, 0x00, 0x41, 0x19, 0x60, 0x13, 0x68, ++ 0x00, 0x2B, 0xFC, 0xDB, 0x11, 0x4B, 0x13, 0x60, 0x13, 0x68, 0x0D, 0x49, ++ 0x43, 0xF0, 0x00, 0x43, 0x13, 0x60, 0x0B, 0x68, 0xDB, 0x0F, 0xFC, 0xD1, ++ 0xCD, 0xE9, 0x00, 0x33, 0x40, 0xF6, 0x85, 0x12, 0x11, 0x46, 0x18, 0x46, ++ 0xD4, 0xF8, 0x28, 0x42, 0xA0, 0x47, 0x09, 0x49, 0x09, 0x4B, 0x0A, 0x4A, ++ 0x0C, 0x20, 0x08, 0x60, 0x1A, 0x60, 0x02, 0xB0, 0x10, 0xBD, 0x00, 0xBF, ++ 0x88, 0x1A, 0x17, 0x00, 0x20, 0x00, 0x58, 0x40, 0xBF, 0x3F, 0x42, 0x01, ++ 0xA2, 0x30, 0x43, 0x01, 0xDD, 0x1D, 0x44, 0x01, 0x00, 0xB3, 0x33, 0x40, ++ 0xC0, 0xB3, 0x33, 0x40, 0xA0, 0xA0, 0x28, 0x28, 0x70, 0xB5, 0x13, 0x4B, ++ 0x13, 0x4D, 0x04, 0x46, 0xED, 0x1A, 0x03, 0xF2, 0x3C, 0x50, 0x5A, 0x19, ++ 0x53, 0xF8, 0x04, 0x1B, 0x11, 0x60, 0x83, 0x42, 0xF9, 0xD1, 0xFF, 0xF7, ++ 0xEB, 0xFA, 0x0E, 0x4B, 0x0E, 0x4E, 0xD3, 0xF8, 0x24, 0x32, 0x20, 0x46, ++ 0x98, 0x47, 0x00, 0x23, 0x86, 0xF8, 0x2A, 0x30, 0x0F, 0xCC, 0x35, 0x46, ++ 0x0F, 0xC5, 0x0F, 0xCC, 0x0F, 0xC5, 0x23, 0x68, 0x2B, 0x60, 0x05, 0x21, ++ 0x4F, 0xF0, 0xFF, 0x12, 0xFF, 0x23, 0x86, 0xF8, 0x2B, 0x10, 0x72, 0x62, ++ 0x33, 0x85, 0x70, 0xBD, 0xB0, 0x0D, 0x17, 0x00, 0x00, 0x90, 0x33, 0x40, ++ 0x88, 0x1A, 0x17, 0x00, 0xBC, 0x34, 0x17, 0x00, 0x08, 0xB5, 0x05, 0x4B, ++ 0x1B, 0x68, 0x1B, 0x07, 0x00, 0xD4, 0x08, 0xBD, 0x14, 0xF0, 0xF4, 0xFD, ++ 0x02, 0x4B, 0x08, 0x22, 0x1A, 0x60, 0x08, 0xBD, 0xA8, 0x10, 0x34, 0x40, ++ 0xAC, 0x10, 0x34, 0x40, 0x03, 0x4A, 0x04, 0x4B, 0x12, 0x68, 0x02, 0x60, ++ 0x1B, 0x68, 0x0B, 0x60, 0x70, 0x47, 0x00, 0xBF, 0x00, 0x00, 0x33, 0x40, ++ 0x3C, 0x00, 0x33, 0x40, 0x2D, 0xE9, 0xF0, 0x4F, 0x83, 0xB0, 0x9D, 0xF8, ++ 0x38, 0x40, 0xBD, 0xF8, 0x30, 0xA0, 0x9D, 0xF8, 0x34, 0x90, 0x00, 0x2C, ++ 0x43, 0xD1, 0x98, 0x46, 0x25, 0x4B, 0x1B, 0x78, 0x05, 0x46, 0x0E, 0x46, ++ 0x17, 0x46, 0xD3, 0xB1, 0x23, 0x4C, 0x24, 0x4A, 0xCD, 0xF8, 0x00, 0x90, ++ 0x00, 0x23, 0xD2, 0xF8, 0x28, 0xB2, 0x01, 0x93, 0x42, 0x46, 0x33, 0x46, ++ 0x39, 0x46, 0x28, 0x46, 0xD8, 0x47, 0x84, 0xF8, 0x2A, 0x50, 0x84, 0xF8, ++ 0x2B, 0x60, 0x84, 0xF8, 0x2C, 0x90, 0xA7, 0x84, 0xA4, 0xF8, 0x26, 0x80, ++ 0xA4, 0xF8, 0x28, 0xA0, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x18, 0x4A, ++ 0x15, 0x4C, 0x13, 0x68, 0x23, 0xF4, 0x00, 0x73, 0x13, 0x60, 0x94, 0xF8, ++ 0x2A, 0x30, 0x83, 0x42, 0xDB, 0xD1, 0x94, 0xF8, 0x2B, 0x30, 0x8B, 0x42, ++ 0xD7, 0xD1, 0x94, 0xF8, 0x2C, 0x30, 0x4B, 0x45, 0xD3, 0xD1, 0xA3, 0x8C, ++ 0xBB, 0x42, 0xD0, 0xD1, 0xE3, 0x8C, 0x43, 0x45, 0xCD, 0xD1, 0x23, 0x8D, ++ 0x53, 0x45, 0xCA, 0xD1, 0x0B, 0x49, 0x0C, 0x48, 0x03, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x4F, 0x23, 0xF0, 0x35, 0xBA, 0x08, 0x49, 0x09, 0x48, 0x22, 0x46, ++ 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x4F, 0x23, 0xF0, 0x2D, 0xBA, 0x00, 0xBF, ++ 0x3C, 0x36, 0x17, 0x00, 0xBC, 0x34, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x90, 0xB3, 0x33, 0x40, 0x8C, 0x78, 0x15, 0x00, 0x38, 0x78, 0x15, 0x00, ++ 0x18, 0x78, 0x15, 0x00, 0x10, 0xB5, 0x04, 0x46, 0x71, 0xB9, 0x0A, 0x4A, ++ 0x93, 0x8C, 0x92, 0xF8, 0x2B, 0x00, 0x92, 0xF8, 0x2A, 0x10, 0xD2, 0xF8, ++ 0x26, 0x20, 0x62, 0x60, 0x1B, 0x04, 0x43, 0xEA, 0x00, 0x23, 0x0B, 0x43, ++ 0x23, 0x60, 0x10, 0xBD, 0x0A, 0x46, 0x03, 0x48, 0x03, 0x49, 0x23, 0xF0, ++ 0x07, 0xFA, 0xEA, 0xE7, 0xBC, 0x34, 0x17, 0x00, 0x18, 0x78, 0x15, 0x00, ++ 0x9C, 0x78, 0x15, 0x00, 0x04, 0x4B, 0x1B, 0x68, 0x1B, 0x07, 0x00, 0xD1, ++ 0x70, 0x47, 0x03, 0x49, 0x03, 0x48, 0x23, 0xF0, 0xF7, 0xB9, 0x00, 0xBF, ++ 0x38, 0x00, 0x32, 0x40, 0xAC, 0x78, 0x15, 0x00, 0x60, 0x78, 0x15, 0x00, ++ 0x4F, 0xF4, 0x7A, 0x70, 0x70, 0x47, 0x00, 0xBF, 0x01, 0x20, 0x70, 0x47, ++ 0x02, 0x4B, 0x18, 0x68, 0xC0, 0xF3, 0x40, 0x50, 0x70, 0x47, 0x00, 0xBF, ++ 0x00, 0x00, 0x33, 0x40, 0x03, 0x4B, 0x18, 0x68, 0x01, 0x28, 0x94, 0xBF, ++ 0x00, 0x20, 0x01, 0x20, 0x70, 0x47, 0x00, 0xBF, 0xFC, 0x13, 0x34, 0x40, ++ 0x04, 0x4A, 0x13, 0x68, 0xC0, 0x00, 0x00, 0xF0, 0x08, 0x00, 0x23, 0xF0, ++ 0x08, 0x03, 0x18, 0x43, 0x10, 0x60, 0x70, 0x47, 0xA0, 0x10, 0x34, 0x40, ++ 0x02, 0x4B, 0x18, 0x68, 0xC0, 0xF3, 0x80, 0x60, 0x70, 0x47, 0x00, 0xBF, ++ 0x00, 0x00, 0x33, 0x40, 0x02, 0x4B, 0x18, 0x68, 0xC0, 0xF3, 0x00, 0x70, ++ 0x70, 0x47, 0x00, 0xBF, 0x00, 0x00, 0x33, 0x40, 0x02, 0x4B, 0x18, 0x68, ++ 0xC0, 0xF3, 0x80, 0x70, 0x70, 0x47, 0x00, 0xBF, 0x00, 0x00, 0x33, 0x40, ++ 0x06, 0x4B, 0x02, 0x68, 0x1A, 0x60, 0x42, 0x68, 0x5A, 0x60, 0x0A, 0x68, ++ 0x9A, 0x60, 0x4A, 0x68, 0xDA, 0x60, 0x8A, 0x68, 0x1A, 0x61, 0xCA, 0x68, ++ 0x5A, 0x61, 0x70, 0x47, 0xA8, 0x08, 0x33, 0x40, 0x30, 0xB4, 0x06, 0x49, ++ 0x06, 0x4D, 0x07, 0x4B, 0x00, 0x24, 0xC0, 0xF3, 0x0A, 0x00, 0x40, 0xF2, ++ 0xFF, 0x72, 0x28, 0x60, 0x0C, 0x60, 0x30, 0xBC, 0x1A, 0x60, 0x70, 0x47, ++ 0xC4, 0x08, 0x33, 0x40, 0xC0, 0x08, 0x33, 0x40, 0xC8, 0x08, 0x33, 0x40, ++ 0x03, 0x4B, 0x18, 0x68, 0xC0, 0xF3, 0x03, 0x20, 0x01, 0x38, 0xC0, 0xB2, ++ 0x70, 0x47, 0x00, 0xBF, 0x00, 0x00, 0x33, 0x40, 0x03, 0x4B, 0x18, 0x68, ++ 0xC0, 0xF3, 0x03, 0x10, 0x01, 0x38, 0xC0, 0xB2, 0x70, 0x47, 0x00, 0xBF, ++ 0x00, 0x00, 0x33, 0x40, 0x03, 0x4B, 0x18, 0x68, 0x00, 0xF0, 0x0F, 0x00, ++ 0x01, 0x38, 0xC0, 0xB2, 0x70, 0x47, 0x00, 0xBF, 0x00, 0x00, 0x33, 0x40, ++ 0xF0, 0xB5, 0xBE, 0x4C, 0x94, 0xF8, 0x2A, 0x30, 0x00, 0x2B, 0x76, 0xD1, ++ 0xBC, 0x4B, 0x93, 0xF8, 0xBD, 0x50, 0x00, 0x2D, 0x66, 0xD0, 0xE0, 0x8C, ++ 0x40, 0xF6, 0x7B, 0x14, 0xA0, 0x42, 0x40, 0xF2, 0xCA, 0x80, 0x40, 0xF6, ++ 0x94, 0x14, 0xA0, 0x42, 0xB6, 0x48, 0x94, 0xBF, 0x90, 0xF9, 0x01, 0x60, ++ 0x90, 0xF9, 0x02, 0x60, 0x93, 0xF8, 0xBE, 0x40, 0xB3, 0x48, 0x06, 0xF1, ++ 0x0F, 0x05, 0x1E, 0x2D, 0x00, 0x5D, 0xA8, 0xBF, 0x1E, 0x25, 0x0A, 0x2C, ++ 0x4F, 0xEA, 0x20, 0x17, 0x00, 0xF0, 0x0F, 0x0C, 0x25, 0xEA, 0xE5, 0x75, ++ 0x00, 0xF3, 0xCF, 0x80, 0x00, 0xF0, 0xE4, 0x80, 0xAB, 0x48, 0x04, 0xEB, ++ 0x44, 0x04, 0x10, 0xF9, 0x14, 0xE0, 0x75, 0x45, 0x00, 0xEB, 0x44, 0x04, ++ 0x00, 0xF3, 0x06, 0x81, 0x64, 0x78, 0xA4, 0xEB, 0x0E, 0x04, 0x2C, 0x44, ++ 0x60, 0xB2, 0x6F, 0xF0, 0x04, 0x04, 0xA0, 0x42, 0x07, 0xF1, 0xFF, 0x37, ++ 0xB8, 0xBF, 0x20, 0x46, 0x60, 0x44, 0x80, 0xF3, 0x04, 0x00, 0x40, 0xEA, ++ 0x07, 0x10, 0x08, 0x70, 0x93, 0xF8, 0xBF, 0x10, 0x9D, 0x4B, 0x5B, 0x5C, ++ 0x0A, 0x29, 0x4F, 0xEA, 0x23, 0x10, 0x03, 0xF0, 0x0F, 0x03, 0x17, 0xDC, ++ 0x00, 0xF0, 0xD1, 0x80, 0x01, 0x31, 0x97, 0x4C, 0x01, 0xEB, 0x41, 0x01, ++ 0x14, 0xF9, 0x11, 0x60, 0xAE, 0x42, 0x04, 0xEB, 0x41, 0x01, 0xC0, 0xF2, ++ 0xD2, 0x80, 0x49, 0x78, 0x89, 0x1B, 0x0D, 0x44, 0x6D, 0xB2, 0x6F, 0xF0, ++ 0x04, 0x01, 0x01, 0x38, 0x8D, 0x42, 0xAC, 0xBF, 0x5B, 0x19, 0x5B, 0x18, ++ 0x83, 0xF3, 0x04, 0x03, 0x43, 0xEA, 0x00, 0x13, 0x13, 0x70, 0xF0, 0xBD, ++ 0x93, 0xF8, 0xAC, 0x40, 0xE5, 0x07, 0x68, 0xD5, 0x93, 0xF8, 0xB7, 0x00, ++ 0x08, 0x70, 0x93, 0xF8, 0xAD, 0x30, 0x13, 0x70, 0xF0, 0xBD, 0x81, 0x4B, ++ 0x93, 0xF8, 0xBD, 0x50, 0x00, 0x2D, 0x3A, 0xD0, 0xE0, 0x8C, 0x41, 0xF2, ++ 0xC8, 0x44, 0xA0, 0x42, 0x4F, 0xD9, 0xB0, 0xF5, 0xAF, 0x5F, 0x7D, 0xD8, ++ 0x7F, 0x48, 0x90, 0xF9, 0x01, 0x60, 0x93, 0xF8, 0xC3, 0x00, 0x7E, 0x4B, ++ 0x1B, 0x5C, 0x0A, 0x28, 0x4F, 0xEA, 0x23, 0x15, 0x03, 0xF0, 0x0F, 0x03, ++ 0x1D, 0xDC, 0x06, 0xF1, 0x0F, 0x04, 0x1E, 0x2C, 0xA8, 0xBF, 0x1E, 0x24, ++ 0x0A, 0x28, 0x24, 0xEA, 0xE4, 0x74, 0x7A, 0xD0, 0x76, 0x4E, 0x00, 0xEB, ++ 0x40, 0x00, 0x16, 0xF9, 0x10, 0x70, 0xBC, 0x42, 0x06, 0xEB, 0x40, 0x00, ++ 0x00, 0xF3, 0x9E, 0x80, 0x40, 0x78, 0xC0, 0x1B, 0x04, 0x44, 0x64, 0xB2, ++ 0x6F, 0xF0, 0x04, 0x00, 0x01, 0x3D, 0x84, 0x42, 0xAC, 0xBF, 0x1B, 0x19, ++ 0x1B, 0x18, 0x83, 0xF3, 0x04, 0x03, 0x43, 0xEA, 0x05, 0x13, 0xDB, 0xB2, ++ 0x13, 0x70, 0x0B, 0x70, 0xF0, 0xBD, 0x93, 0xF8, 0xAC, 0x40, 0xA4, 0x07, ++ 0x04, 0xD5, 0x93, 0xF8, 0xAE, 0x30, 0x0B, 0x70, 0x13, 0x70, 0xF0, 0xBD, ++ 0x90, 0xF9, 0x00, 0x30, 0x61, 0x48, 0x6F, 0xF0, 0x04, 0x04, 0xA3, 0x42, ++ 0xB8, 0xBF, 0x23, 0x46, 0x12, 0x2B, 0xA8, 0xBF, 0x12, 0x23, 0x05, 0x33, ++ 0x5B, 0x10, 0xC3, 0x5C, 0x0B, 0x70, 0x13, 0x70, 0xF0, 0xBD, 0x59, 0x48, ++ 0x90, 0xF9, 0x00, 0x60, 0xB1, 0xE7, 0x53, 0x48, 0x90, 0xF9, 0x00, 0x60, ++ 0x3A, 0xE7, 0x90, 0xF9, 0x00, 0x30, 0x51, 0x4D, 0x52, 0x4C, 0x01, 0x2B, ++ 0x6F, 0xF0, 0x01, 0x06, 0x18, 0x46, 0xB8, 0xBF, 0x01, 0x20, 0xB3, 0x42, ++ 0xB8, 0xBF, 0x33, 0x46, 0x17, 0x28, 0xA8, 0xBF, 0x17, 0x20, 0x14, 0x2B, ++ 0xA8, 0xBF, 0x14, 0x23, 0x01, 0x38, 0x02, 0x33, 0x40, 0x10, 0x5B, 0x10, ++ 0x28, 0x5C, 0xE3, 0x5C, 0x08, 0x70, 0x13, 0x70, 0xF0, 0xBD, 0x74, 0x1C, ++ 0x55, 0xDA, 0xA5, 0xF1, 0x0D, 0x00, 0x40, 0xB2, 0x6F, 0xF0, 0x04, 0x04, ++ 0xA0, 0x42, 0xA7, 0xF1, 0x02, 0x07, 0xB8, 0xBF, 0x20, 0x46, 0x3B, 0xE7, ++ 0x41, 0xF2, 0x44, 0x64, 0xA0, 0x42, 0x3F, 0x48, 0x94, 0xBF, 0x90, 0xF9, ++ 0x02, 0x60, 0x90, 0xF9, 0x03, 0x60, 0x7A, 0xE7, 0xB0, 0x1C, 0x53, 0xDB, ++ 0x01, 0x2E, 0x00, 0xF3, 0x8D, 0x80, 0xA5, 0xF1, 0x0F, 0x00, 0x40, 0xB2, ++ 0x28, 0xE7, 0x03, 0x36, 0x43, 0xDA, 0x09, 0x3C, 0x64, 0xB2, 0x6F, 0xF0, ++ 0x04, 0x00, 0x01, 0x3D, 0x84, 0x42, 0xAC, 0xBF, 0x1B, 0x19, 0x1B, 0x18, ++ 0x8D, 0xE7, 0x03, 0x36, 0x30, 0xDA, 0x09, 0x3D, 0x6D, 0xB2, 0x6F, 0xF0, ++ 0x04, 0x01, 0x01, 0x38, 0x8D, 0x42, 0xAC, 0xBF, 0x5B, 0x19, 0x5B, 0x18, ++ 0x38, 0xE7, 0x91, 0xF9, 0x04, 0x40, 0xAC, 0x42, 0x3B, 0xDD, 0xCC, 0x78, ++ 0x89, 0x78, 0x61, 0x1A, 0x0D, 0x44, 0x43, 0xFA, 0x85, 0xF3, 0x2D, 0xE7, ++ 0x94, 0xF9, 0x04, 0xE0, 0x75, 0x45, 0x57, 0xDA, 0xE0, 0x78, 0xA4, 0x78, ++ 0x00, 0x1B, 0x28, 0x44, 0x40, 0xB2, 0xFB, 0xE6, 0x90, 0xF9, 0x04, 0x60, ++ 0xB4, 0x42, 0x43, 0xDA, 0xC6, 0x78, 0x80, 0x78, 0x30, 0x1A, 0x04, 0x44, ++ 0x43, 0xFA, 0x84, 0xF3, 0x61, 0xE7, 0xA5, 0xF1, 0x0F, 0x04, 0x60, 0xB2, ++ 0x03, 0x28, 0xA8, 0xBF, 0x03, 0x20, 0xE9, 0xE6, 0x0F, 0x3D, 0x6D, 0xB2, ++ 0x05, 0x2D, 0xD4, 0xBF, 0x5B, 0x19, 0x05, 0x33, 0x0A, 0xE7, 0x0F, 0x3C, ++ 0x64, 0xB2, 0x05, 0x2C, 0xD4, 0xBF, 0x1B, 0x19, 0x05, 0x33, 0x4C, 0xE7, ++ 0xA5, 0xF1, 0x0A, 0x00, 0x40, 0xB2, 0x6F, 0xF0, 0x04, 0x04, 0xA0, 0x42, ++ 0x07, 0xF1, 0xFF, 0x37, 0xB8, 0xBF, 0x20, 0x46, 0xD0, 0xE6, 0x49, 0x79, ++ 0x09, 0x1B, 0x0D, 0x44, 0x6D, 0xB2, 0x05, 0x2D, 0xD4, 0xBF, 0x5B, 0x19, ++ 0x05, 0x33, 0x01, 0x30, 0xEE, 0xE6, 0x00, 0xBF, 0xBC, 0x34, 0x17, 0x00, ++ 0x2C, 0x19, 0x17, 0x00, 0x68, 0x25, 0x17, 0x00, 0xEC, 0x12, 0x17, 0x00, ++ 0xB8, 0x78, 0x15, 0x00, 0xF8, 0x12, 0x17, 0x00, 0x6C, 0x25, 0x17, 0x00, ++ 0x04, 0x13, 0x17, 0x00, 0x0C, 0x79, 0x15, 0x00, 0x40, 0x79, 0x80, 0x1B, ++ 0x04, 0x44, 0x64, 0xB2, 0x05, 0x2C, 0xD4, 0xBF, 0x1B, 0x19, 0x05, 0x33, ++ 0x01, 0x35, 0x1A, 0xE7, 0x60, 0x79, 0xA0, 0xEB, 0x0E, 0x00, 0x28, 0x44, ++ 0x40, 0xB2, 0x05, 0x28, 0xA8, 0xBF, 0x05, 0x20, 0x01, 0x37, 0x9F, 0xE6, ++ 0xA5, 0xF1, 0x11, 0x00, 0x40, 0xB2, 0x03, 0x28, 0x07, 0xF1, 0x02, 0x07, ++ 0xA8, 0xBF, 0x03, 0x20, 0x96, 0xE6, 0x00, 0xBF, 0xF0, 0xB4, 0xB9, 0x4B, ++ 0x93, 0xF8, 0x2A, 0x20, 0xDC, 0x8C, 0x52, 0xBB, 0xC0, 0xB9, 0x03, 0x29, ++ 0x00, 0xF2, 0x91, 0x80, 0xB5, 0x4A, 0xB6, 0x4B, 0x92, 0xF8, 0xBE, 0x50, ++ 0x5B, 0x5D, 0x02, 0x46, 0x01, 0x46, 0x07, 0x46, 0x40, 0xF6, 0x7B, 0x10, ++ 0x84, 0x42, 0x00, 0xF2, 0xBA, 0x80, 0xB1, 0x48, 0x90, 0xF9, 0x00, 0x60, ++ 0x00, 0x29, 0x00, 0xF0, 0xC0, 0x80, 0xD8, 0xB2, 0xF0, 0xBC, 0x70, 0x47, ++ 0x04, 0x28, 0x40, 0xF2, 0x8F, 0x80, 0x09, 0x29, 0x40, 0xF2, 0x8E, 0x80, ++ 0xA7, 0x4B, 0x93, 0xF8, 0xC2, 0x50, 0x08, 0x2D, 0x40, 0xF3, 0x17, 0x81, ++ 0x01, 0x21, 0x0F, 0x46, 0x09, 0x25, 0xD4, 0x23, 0xE0, 0xE7, 0x04, 0x28, ++ 0x44, 0xD9, 0x09, 0x29, 0x44, 0xD9, 0xA0, 0x4B, 0xA2, 0x49, 0x93, 0xF8, ++ 0xC6, 0x30, 0x09, 0x2B, 0xA8, 0xBF, 0x09, 0x23, 0x41, 0xF2, 0xC8, 0x42, ++ 0x94, 0x42, 0xC8, 0x5C, 0x4F, 0xF0, 0x00, 0x05, 0x53, 0xD9, 0xB4, 0xF5, ++ 0xAF, 0x5F, 0x00, 0xF2, 0xCC, 0x80, 0x9B, 0x4A, 0x92, 0xF9, 0x01, 0x20, ++ 0x00, 0x2D, 0xD1, 0xD1, 0x0A, 0x2B, 0x4F, 0xEA, 0x20, 0x14, 0x00, 0xF0, ++ 0x0F, 0x00, 0x1E, 0xDC, 0x02, 0xF1, 0x0F, 0x01, 0x1E, 0x29, 0xA8, 0xBF, ++ 0x1E, 0x21, 0x0A, 0x2B, 0x21, 0xEA, 0xE1, 0x71, 0x00, 0xF0, 0x3C, 0x81, ++ 0x91, 0x4A, 0x03, 0xEB, 0x43, 0x03, 0x12, 0xF9, 0x13, 0x50, 0x8D, 0x42, ++ 0x02, 0xEB, 0x43, 0x02, 0x80, 0xF2, 0xF6, 0x80, 0x92, 0xF9, 0x04, 0x50, ++ 0x8D, 0x42, 0x40, 0xF3, 0x40, 0x81, 0xD3, 0x78, 0x92, 0x78, 0x9B, 0x1A, ++ 0x19, 0x44, 0x40, 0xFA, 0x81, 0xF0, 0x80, 0xF3, 0x04, 0x00, 0x40, 0xEA, ++ 0x04, 0x10, 0xC0, 0xB2, 0xF0, 0xBC, 0x70, 0x47, 0x01, 0x28, 0x0C, 0xD9, ++ 0x07, 0x29, 0x2C, 0xD8, 0x04, 0x29, 0x0A, 0xD8, 0x7B, 0x4B, 0x93, 0xF8, ++ 0xC3, 0x30, 0xA3, 0xF1, 0x0B, 0x05, 0xB5, 0xFA, 0x85, 0xF5, 0x6D, 0x09, ++ 0x09, 0xE0, 0x09, 0x29, 0xF4, 0xD9, 0x76, 0x4B, 0x93, 0xF8, 0xC4, 0x30, ++ 0x0A, 0x2B, 0x4F, 0xF0, 0x00, 0x05, 0xA8, 0xBF, 0x0A, 0x23, 0x75, 0x49, ++ 0x41, 0xF2, 0xC8, 0x42, 0x94, 0x42, 0xC8, 0x5C, 0xAB, 0xD8, 0x73, 0x4A, ++ 0x92, 0xF9, 0x00, 0x20, 0xAE, 0xE7, 0x09, 0x29, 0x26, 0xD8, 0x6C, 0x4B, ++ 0x93, 0xF8, 0xBF, 0x50, 0x0B, 0x2D, 0x00, 0xF0, 0xF0, 0x80, 0x6F, 0x4B, ++ 0x00, 0x22, 0x5B, 0x5D, 0x11, 0x46, 0x01, 0x27, 0x68, 0xE7, 0x66, 0x4B, ++ 0x93, 0xF8, 0xC5, 0x30, 0x09, 0x2B, 0x4F, 0xF0, 0x00, 0x05, 0xA8, 0xBF, ++ 0x09, 0x23, 0xDE, 0xE7, 0x01, 0x28, 0xE6, 0xD0, 0x07, 0x29, 0x0B, 0xD9, ++ 0x5F, 0x4A, 0x65, 0x4B, 0x92, 0xF8, 0xC1, 0x50, 0x0A, 0x2D, 0xA8, 0xBF, ++ 0x0A, 0x25, 0x00, 0x22, 0x5B, 0x5D, 0x11, 0x46, 0x01, 0x27, 0x4F, 0xE7, ++ 0x04, 0x29, 0xD8, 0xD9, 0x58, 0x4A, 0x5E, 0x4B, 0x92, 0xF8, 0xC0, 0x50, ++ 0xA5, 0xF1, 0x0B, 0x01, 0xB1, 0xFA, 0x81, 0xF1, 0x5B, 0x5D, 0x00, 0x22, ++ 0x49, 0x09, 0x01, 0x27, 0x40, 0xE7, 0x40, 0xF6, 0x94, 0x10, 0x84, 0x42, ++ 0x52, 0x48, 0x94, 0xBF, 0x90, 0xF9, 0x01, 0x60, 0x90, 0xF9, 0x02, 0x60, ++ 0x00, 0x29, 0x7F, 0xF4, 0x40, 0xAF, 0x06, 0xF1, 0x0F, 0x01, 0x1E, 0x29, ++ 0xA8, 0xBF, 0x1E, 0x21, 0x0B, 0x2D, 0x21, 0xEA, 0xE1, 0x74, 0x4F, 0xEA, ++ 0x23, 0x10, 0x29, 0x46, 0x03, 0xF0, 0x0F, 0x03, 0xA8, 0xBF, 0x0B, 0x21, ++ 0x00, 0x2F, 0x3B, 0xD1, 0x0A, 0x2D, 0x2C, 0xDC, 0x48, 0xD0, 0x49, 0x4D, ++ 0x01, 0xEB, 0x41, 0x01, 0x15, 0xF9, 0x11, 0x60, 0xB4, 0x42, 0x05, 0xEB, ++ 0x41, 0x01, 0x34, 0xDC, 0x49, 0x78, 0x89, 0x1B, 0x21, 0x44, 0x49, 0xB2, ++ 0x6F, 0xF0, 0x04, 0x04, 0x01, 0x38, 0xA1, 0x42, 0xAC, 0xBF, 0x5B, 0x18, ++ 0x1B, 0x19, 0x83, 0xF3, 0x04, 0x03, 0x43, 0xEA, 0x00, 0x13, 0xD8, 0xB2, ++ 0x00, 0x2A, 0x3F, 0xF4, 0x11, 0xAF, 0x82, 0x42, 0xBF, 0xF6, 0x0E, 0xAF, ++ 0xD0, 0xB2, 0xF0, 0xBC, 0x70, 0x47, 0x41, 0xF2, 0x44, 0x62, 0x94, 0x42, ++ 0x33, 0x4A, 0x94, 0xBF, 0x92, 0xF9, 0x02, 0x20, 0x92, 0xF9, 0x03, 0x20, ++ 0x2C, 0xE7, 0x01, 0x36, 0x2A, 0xDA, 0xA4, 0xF1, 0x0D, 0x01, 0x49, 0xB2, ++ 0x6F, 0xF0, 0x04, 0x04, 0x02, 0x38, 0xA1, 0x42, 0xAC, 0xBF, 0x5B, 0x18, ++ 0x1B, 0x19, 0xDA, 0xE7, 0x0A, 0x2D, 0xD8, 0xDC, 0x58, 0xD0, 0x01, 0x31, ++ 0xC1, 0xE7, 0x91, 0xF9, 0x04, 0x50, 0xAC, 0x42, 0x1E, 0xDA, 0xCD, 0x78, ++ 0x89, 0x78, 0x69, 0x1A, 0x21, 0x44, 0x43, 0xFA, 0x81, 0xF3, 0xCA, 0xE7, ++ 0xB1, 0x1C, 0x2B, 0xDB, 0x01, 0x2E, 0x76, 0xDC, 0xA4, 0xF1, 0x0F, 0x01, ++ 0x43, 0xFA, 0x81, 0xF3, 0xC1, 0xE7, 0x1F, 0x4B, 0x08, 0xBF, 0xD4, 0x22, ++ 0x5B, 0x5D, 0x00, 0x21, 0x01, 0x27, 0xC7, 0xE6, 0xA4, 0xF1, 0x0F, 0x01, ++ 0x49, 0xB2, 0x03, 0x29, 0xD4, 0xBF, 0x5B, 0x18, 0x03, 0x33, 0xB2, 0xE7, ++ 0x49, 0x79, 0x49, 0x1B, 0x21, 0x44, 0x49, 0xB2, 0x05, 0x29, 0xD4, 0xBF, ++ 0x5B, 0x18, 0x05, 0x33, 0x01, 0x30, 0xA8, 0xE7, 0x53, 0x78, 0x5B, 0x1B, ++ 0x19, 0x44, 0x49, 0xB2, 0x6F, 0xF0, 0x04, 0x03, 0x01, 0x3C, 0x99, 0x42, ++ 0xAC, 0xBF, 0x40, 0x18, 0xC0, 0x18, 0x08, 0xE7, 0xA4, 0xF1, 0x0A, 0x01, ++ 0x49, 0xB2, 0x6F, 0xF0, 0x04, 0x04, 0x01, 0x38, 0xA1, 0x42, 0xAC, 0xBF, ++ 0x5B, 0x18, 0x1B, 0x19, 0x91, 0xE7, 0x00, 0xBF, 0xBC, 0x34, 0x17, 0x00, ++ 0x2C, 0x19, 0x17, 0x00, 0xEC, 0x12, 0x17, 0x00, 0x68, 0x25, 0x17, 0x00, ++ 0x04, 0x13, 0x17, 0x00, 0x6C, 0x25, 0x17, 0x00, 0x0C, 0x79, 0x15, 0x00, ++ 0xF8, 0x12, 0x17, 0x00, 0xB8, 0x78, 0x15, 0x00, 0x03, 0x36, 0x35, 0xDA, ++ 0xA4, 0xF1, 0x09, 0x01, 0x49, 0xB2, 0x6F, 0xF0, 0x04, 0x04, 0x01, 0x38, ++ 0xA1, 0x42, 0xAC, 0xBF, 0x5B, 0x18, 0x1B, 0x19, 0x71, 0xE7, 0x01, 0x21, ++ 0x0F, 0x46, 0x00, 0x22, 0x0F, 0x23, 0x79, 0xE6, 0x03, 0x32, 0x09, 0xDA, ++ 0x09, 0x39, 0x49, 0xB2, 0x6F, 0xF0, 0x04, 0x03, 0x01, 0x3C, 0x99, 0x42, ++ 0xAC, 0xBF, 0x40, 0x18, 0xC0, 0x18, 0xCC, 0xE6, 0x0F, 0x39, 0x49, 0xB2, ++ 0x05, 0x29, 0xD4, 0xBF, 0x40, 0x18, 0x05, 0x30, 0xC5, 0xE6, 0x53, 0x79, ++ 0x5B, 0x1B, 0x19, 0x44, 0x49, 0xB2, 0x05, 0x29, 0xD4, 0xBF, 0x40, 0x18, ++ 0x05, 0x30, 0x01, 0x34, 0xBB, 0xE6, 0xA4, 0xF1, 0x11, 0x01, 0x49, 0xB2, ++ 0x03, 0x29, 0xD4, 0xBF, 0x5B, 0x18, 0x03, 0x33, 0x02, 0x30, 0x46, 0xE7, ++ 0xA4, 0xF1, 0x0F, 0x01, 0x49, 0xB2, 0x05, 0x29, 0xD4, 0xBF, 0x5B, 0x18, ++ 0x05, 0x33, 0x3E, 0xE7, 0x14, 0x22, 0xF6, 0x23, 0x02, 0x70, 0x0B, 0x70, ++ 0x70, 0x47, 0x00, 0xBF, 0x08, 0xB5, 0x09, 0x49, 0x09, 0x48, 0x22, 0xF0, ++ 0xF3, 0xFD, 0x09, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0x00, 0xDB, 0x08, 0xBD, 0xBD, 0xE8, 0x08, 0x40, 0x05, 0x49, 0x06, 0x48, ++ 0x39, 0x22, 0x23, 0xF0, 0x5F, 0xB8, 0x00, 0xBF, 0x50, 0x79, 0x15, 0x00, ++ 0xCC, 0xB5, 0x15, 0x00, 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x64, 0x7D, 0x15, 0x00, 0x1F, 0x49, 0x20, 0x4A, 0x88, 0x68, 0x20, 0x4B, ++ 0x10, 0xB4, 0xD2, 0xF8, 0x14, 0x44, 0x04, 0x65, 0x10, 0x20, 0x18, 0x60, ++ 0x88, 0x68, 0xD2, 0xF8, 0xA0, 0x42, 0x44, 0x65, 0x20, 0x20, 0x18, 0x60, ++ 0x88, 0x68, 0xD2, 0xF8, 0xA0, 0x42, 0xC4, 0x65, 0x80, 0x20, 0x18, 0x60, ++ 0x88, 0x68, 0xD2, 0xF8, 0xD8, 0x40, 0x84, 0x64, 0x04, 0x20, 0x18, 0x60, ++ 0x88, 0x68, 0xD2, 0xF8, 0x0C, 0x44, 0xC4, 0x64, 0xF8, 0x24, 0x08, 0x20, ++ 0x83, 0xF8, 0x03, 0x43, 0x18, 0x60, 0x88, 0x68, 0xD2, 0xF8, 0x1C, 0x41, ++ 0xC0, 0xF8, 0x0C, 0x41, 0x4F, 0xF4, 0x00, 0x20, 0x58, 0x60, 0x89, 0x68, ++ 0xD2, 0xF8, 0x2C, 0x21, 0xC1, 0xF8, 0x10, 0x21, 0x4F, 0xF4, 0x80, 0x10, ++ 0x4F, 0xF4, 0x00, 0x41, 0x4F, 0xF4, 0x00, 0x12, 0x58, 0x60, 0x99, 0x60, ++ 0x1A, 0x60, 0x62, 0xB6, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, 0x00, 0xBF, ++ 0x00, 0xED, 0x00, 0xE0, 0x88, 0x1A, 0x17, 0x00, 0x00, 0xE1, 0x00, 0xE0, ++ 0x33, 0x49, 0x34, 0x4B, 0x0A, 0x68, 0x00, 0x28, 0x22, 0xF4, 0x00, 0x62, ++ 0xF0, 0xB5, 0x32, 0x4D, 0x0A, 0x60, 0x06, 0xBF, 0x1D, 0x46, 0x30, 0x26, ++ 0x20, 0x26, 0x32, 0x23, 0x00, 0xBF, 0x01, 0x3B, 0x13, 0xF0, 0xFF, 0x03, ++ 0xFA, 0xD1, 0x2A, 0x4F, 0x2C, 0x4C, 0x3A, 0x68, 0x22, 0xF4, 0x80, 0x52, ++ 0x3A, 0x60, 0x3A, 0x68, 0x42, 0xF4, 0x80, 0x62, 0x3A, 0x60, 0x3A, 0x68, ++ 0x42, 0xF4, 0x00, 0x62, 0x3A, 0x60, 0xB6, 0x00, 0x19, 0x46, 0x3A, 0x46, ++ 0x4F, 0xF0, 0xFF, 0x0E, 0xC8, 0x1C, 0xC0, 0xB2, 0xAC, 0x46, 0x13, 0x68, ++ 0x23, 0xF0, 0xFF, 0x03, 0x03, 0x43, 0x13, 0x60, 0x5C, 0xF8, 0x04, 0x3B, ++ 0x23, 0x60, 0x13, 0x68, 0x43, 0xF4, 0x80, 0x73, 0x13, 0x60, 0x00, 0xBF, ++ 0x00, 0xBF, 0x00, 0xBF, 0x00, 0xBF, 0x13, 0x68, 0x9B, 0x04, 0xFC, 0xD5, ++ 0x01, 0x38, 0xC0, 0xB2, 0x70, 0x45, 0xE8, 0xD1, 0x04, 0x31, 0x04, 0x30, ++ 0xB1, 0x42, 0x5F, 0xFA, 0x80, 0xFE, 0x05, 0xF1, 0x10, 0x05, 0xDD, 0xD1, ++ 0x3B, 0x68, 0x23, 0xF4, 0x80, 0x63, 0x3B, 0x60, 0xC8, 0x23, 0x00, 0xBF, ++ 0x01, 0x3B, 0x13, 0xF0, 0xFF, 0x03, 0xFA, 0xD1, 0x0A, 0x4A, 0x13, 0x68, ++ 0x23, 0xF4, 0x00, 0x63, 0x13, 0x60, 0x32, 0x23, 0x00, 0xBF, 0x01, 0x3B, ++ 0x13, 0xF0, 0xFF, 0x03, 0xFA, 0xD1, 0x05, 0x4B, 0x1A, 0x68, 0x42, 0xF4, ++ 0x80, 0x52, 0x1A, 0x60, 0x1A, 0x68, 0x42, 0xF4, 0x00, 0x62, 0x1A, 0x60, ++ 0xF0, 0xBD, 0x00, 0xBF, 0x60, 0x40, 0x34, 0x40, 0x1C, 0x13, 0x17, 0x00, ++ 0x1C, 0x16, 0x17, 0x00, 0x64, 0x40, 0x34, 0x40, 0x44, 0x4A, 0x45, 0x49, ++ 0x13, 0x68, 0xF0, 0xB4, 0x44, 0x4D, 0x23, 0xF4, 0x00, 0x63, 0x13, 0x60, ++ 0x00, 0x28, 0x0C, 0xBF, 0x28, 0x46, 0x08, 0x46, 0x32, 0x23, 0x00, 0xBF, ++ 0x01, 0x3B, 0x13, 0xF0, 0xFF, 0x03, 0xFA, 0xD1, 0x3B, 0x4A, 0x3E, 0x4D, ++ 0x13, 0x68, 0x23, 0xF4, 0x80, 0x53, 0x13, 0x60, 0x13, 0x68, 0x43, 0xF4, ++ 0x80, 0x63, 0x13, 0x60, 0x13, 0x68, 0x43, 0xF4, 0x00, 0x63, 0x13, 0x60, ++ 0x03, 0x21, 0xA0, 0xF1, 0x0C, 0x04, 0x13, 0x68, 0x23, 0xF0, 0xFF, 0x03, ++ 0x0B, 0x43, 0x13, 0x60, 0x54, 0xF8, 0x21, 0x30, 0x2B, 0x60, 0x13, 0x68, ++ 0x43, 0xF4, 0x80, 0x73, 0x13, 0x60, 0x00, 0xBF, 0x00, 0xBF, 0x00, 0xBF, ++ 0x00, 0xBF, 0x13, 0x68, 0x9E, 0x04, 0xFC, 0xD5, 0x04, 0x31, 0x43, 0x29, ++ 0xE9, 0xD1, 0x28, 0x4B, 0x2B, 0x4E, 0x2A, 0x4D, 0x04, 0x1F, 0x02, 0x21, ++ 0x1A, 0x68, 0x22, 0xF0, 0xFF, 0x02, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, ++ 0x42, 0xF4, 0x00, 0x72, 0x1A, 0x60, 0x00, 0xBF, 0x00, 0xBF, 0x00, 0xBF, ++ 0x00, 0xBF, 0x1A, 0x68, 0x90, 0x04, 0xFC, 0xD5, 0x37, 0x68, 0x54, 0xF8, ++ 0x21, 0x20, 0x18, 0x68, 0x27, 0xF0, 0x7F, 0x47, 0x02, 0xF0, 0x7F, 0x42, ++ 0x20, 0xF0, 0xFF, 0x00, 0x3A, 0x43, 0x08, 0x43, 0x18, 0x60, 0x2A, 0x60, ++ 0x1A, 0x68, 0x42, 0xF4, 0x80, 0x72, 0x1A, 0x60, 0x00, 0xBF, 0x00, 0xBF, ++ 0x00, 0xBF, 0x00, 0xBF, 0x1A, 0x68, 0x92, 0x04, 0xFC, 0xD5, 0x04, 0x31, ++ 0x42, 0x29, 0xD3, 0xD1, 0x1A, 0x68, 0x22, 0xF4, 0x80, 0x62, 0x1A, 0x60, ++ 0xC8, 0x23, 0x00, 0xBF, 0x01, 0x3B, 0x13, 0xF0, 0xFF, 0x03, 0xFA, 0xD1, ++ 0x0A, 0x4A, 0x13, 0x68, 0x23, 0xF4, 0x00, 0x63, 0x13, 0x60, 0x32, 0x23, ++ 0x00, 0xBF, 0x01, 0x3B, 0x13, 0xF0, 0xFF, 0x03, 0xFA, 0xD1, 0x05, 0x4B, ++ 0x1A, 0x68, 0x42, 0xF4, 0x80, 0x52, 0x1A, 0x60, 0x1A, 0x68, 0x42, 0xF4, ++ 0x00, 0x62, 0xF0, 0xBC, 0x1A, 0x60, 0x70, 0x47, 0x60, 0x40, 0x34, 0x40, ++ 0x1C, 0x16, 0x17, 0x00, 0x1C, 0x13, 0x17, 0x00, 0x64, 0x40, 0x34, 0x40, ++ 0x68, 0x40, 0x34, 0x40, 0x2C, 0x49, 0x2D, 0x4B, 0x0A, 0x68, 0x30, 0xB4, ++ 0x2C, 0x4C, 0x00, 0x28, 0x22, 0xF4, 0x80, 0x72, 0x0C, 0xBF, 0x18, 0x46, ++ 0x20, 0x46, 0x0A, 0x60, 0x0C, 0xBF, 0x20, 0x24, 0x10, 0x24, 0x32, 0x23, ++ 0x00, 0xBF, 0x01, 0x3B, 0x13, 0xF0, 0xFF, 0x03, 0xFA, 0xD1, 0x22, 0x49, ++ 0x24, 0x4D, 0x0A, 0x68, 0x22, 0xF4, 0x00, 0x72, 0x0A, 0x60, 0x0A, 0x68, ++ 0x42, 0xF0, 0x80, 0x02, 0x0A, 0x60, 0x0A, 0x68, 0x42, 0xF4, 0x80, 0x72, ++ 0x04, 0x38, 0x0A, 0x60, 0x0A, 0x68, 0x22, 0xF0, 0x1F, 0x02, 0x1A, 0x43, ++ 0x0A, 0x60, 0x50, 0xF8, 0x04, 0x2F, 0x2A, 0x60, 0x0A, 0x68, 0x42, 0xF0, ++ 0x20, 0x02, 0x0A, 0x60, 0x00, 0xBF, 0x00, 0xBF, 0x00, 0xBF, 0x00, 0xBF, ++ 0x0A, 0x68, 0x52, 0x05, 0xFC, 0xD5, 0x01, 0x33, 0x9C, 0x42, 0xE9, 0xD1, ++ 0x0B, 0x68, 0x23, 0xF0, 0x80, 0x03, 0x0B, 0x60, 0xC8, 0x23, 0x00, 0xBF, ++ 0x01, 0x3B, 0x13, 0xF0, 0xFF, 0x03, 0xFA, 0xD1, 0x0A, 0x4A, 0x13, 0x68, ++ 0x23, 0xF4, 0x80, 0x73, 0x13, 0x60, 0x32, 0x23, 0x00, 0xBF, 0x01, 0x3B, ++ 0x13, 0xF0, 0xFF, 0x03, 0xFA, 0xD1, 0x05, 0x4B, 0x1A, 0x68, 0x42, 0xF4, ++ 0x00, 0x72, 0x1A, 0x60, 0x1A, 0x68, 0x42, 0xF4, 0x80, 0x72, 0x30, 0xBC, ++ 0x1A, 0x60, 0x70, 0x47, 0x6C, 0x40, 0x34, 0x40, 0x1C, 0x18, 0x17, 0x00, ++ 0x9C, 0x18, 0x17, 0x00, 0x70, 0x40, 0x34, 0x40, 0x2D, 0xE9, 0xF0, 0x41, ++ 0xA6, 0x49, 0xA7, 0x4C, 0xA7, 0x4B, 0xA8, 0x4A, 0xDF, 0xF8, 0xE8, 0xE2, ++ 0x00, 0x28, 0x0E, 0xBF, 0xA4, 0x46, 0x8C, 0x46, 0x9E, 0x46, 0x13, 0x68, ++ 0x00, 0x2B, 0xFC, 0xD0, 0xA3, 0x4C, 0xA4, 0x49, 0x23, 0x68, 0x23, 0xF0, ++ 0x02, 0x03, 0x23, 0x60, 0x01, 0x23, 0x13, 0x60, 0x0B, 0x68, 0xA1, 0x4A, ++ 0x23, 0xF4, 0x00, 0x63, 0x0B, 0x60, 0x13, 0x68, 0x23, 0xF4, 0x80, 0x73, ++ 0x13, 0x60, 0x32, 0x24, 0x00, 0xBF, 0x01, 0x3C, 0x14, 0xF0, 0xFF, 0x04, ++ 0xFA, 0xD1, 0xDF, 0xF8, 0x64, 0x82, 0x99, 0x4A, 0xD8, 0xF8, 0x00, 0x30, ++ 0x98, 0x4F, 0x23, 0xF4, 0x80, 0x53, 0xC8, 0xF8, 0x00, 0x30, 0x13, 0x68, ++ 0x23, 0xF4, 0x00, 0x73, 0x13, 0x60, 0xD8, 0xF8, 0x00, 0x30, 0x43, 0xF4, ++ 0x80, 0x63, 0xC8, 0xF8, 0x00, 0x30, 0xD8, 0xF8, 0x00, 0x30, 0x43, 0xF4, ++ 0x00, 0x63, 0xC8, 0xF8, 0x00, 0x30, 0x42, 0x46, 0xFF, 0x26, 0xE1, 0x1C, ++ 0xC9, 0xB2, 0x75, 0x46, 0x13, 0x68, 0x23, 0xF0, 0xFF, 0x03, 0x0B, 0x43, ++ 0x13, 0x60, 0x55, 0xF8, 0x04, 0x3B, 0x3B, 0x60, 0x13, 0x68, 0x43, 0xF4, ++ 0x80, 0x73, 0x13, 0x60, 0x00, 0xBF, 0x00, 0xBF, 0x00, 0xBF, 0x00, 0xBF, ++ 0x13, 0x68, 0x9B, 0x04, 0xFC, 0xD5, 0x01, 0x39, 0xC9, 0xB2, 0x8E, 0x42, ++ 0xE8, 0xD1, 0x04, 0x34, 0x04, 0x36, 0x80, 0x2C, 0xF6, 0xB2, 0x0E, 0xF1, ++ 0x10, 0x0E, 0xDE, 0xD1, 0xD8, 0xF8, 0x00, 0x30, 0x23, 0xF4, 0x80, 0x63, ++ 0xC8, 0xF8, 0x00, 0x30, 0xC8, 0x23, 0x00, 0xBF, 0x01, 0x3B, 0x13, 0xF0, ++ 0xFF, 0x03, 0xFA, 0xD1, 0x74, 0x4C, 0x75, 0x49, 0x22, 0x68, 0x22, 0xF4, ++ 0x00, 0x62, 0x22, 0x60, 0x0A, 0x68, 0x42, 0xF0, 0x80, 0x02, 0x0A, 0x60, ++ 0x0A, 0x68, 0x42, 0xF4, 0x80, 0x72, 0x10, 0x34, 0xAC, 0xF1, 0x04, 0x0C, ++ 0x0A, 0x60, 0x0A, 0x68, 0x22, 0xF0, 0x1F, 0x02, 0x1A, 0x43, 0x0A, 0x60, ++ 0x5C, 0xF8, 0x04, 0x2F, 0x22, 0x60, 0x0A, 0x68, 0x42, 0xF0, 0x20, 0x02, ++ 0x0A, 0x60, 0x00, 0xBF, 0x00, 0xBF, 0x00, 0xBF, 0x00, 0xBF, 0x0A, 0x68, ++ 0x52, 0x05, 0xFC, 0xD5, 0x01, 0x33, 0x10, 0x2B, 0xE9, 0xD1, 0x0B, 0x68, ++ 0x23, 0xF0, 0x80, 0x03, 0x0B, 0x60, 0xC8, 0x23, 0x00, 0xBF, 0x01, 0x3B, ++ 0x13, 0xF0, 0xFF, 0x03, 0xFA, 0xD1, 0x5D, 0x49, 0x5E, 0x4A, 0x0B, 0x68, ++ 0x23, 0xF4, 0x80, 0x73, 0x0B, 0x60, 0x13, 0x68, 0x43, 0xF4, 0x00, 0x13, ++ 0x13, 0x60, 0x32, 0x23, 0x00, 0xBF, 0x01, 0x3B, 0x13, 0xF0, 0xFF, 0x03, ++ 0xFA, 0xD1, 0x54, 0x49, 0x54, 0x4B, 0x0C, 0x68, 0x56, 0x4A, 0x57, 0x4D, ++ 0x44, 0xF4, 0x80, 0x54, 0x0C, 0x60, 0x1C, 0x68, 0x44, 0xF4, 0x00, 0x74, ++ 0x1C, 0x60, 0x0C, 0x68, 0x44, 0xF4, 0x00, 0x64, 0x0C, 0x60, 0x19, 0x68, ++ 0x51, 0x4C, 0x41, 0xF4, 0x80, 0x71, 0x19, 0x60, 0x11, 0x68, 0x50, 0x4B, ++ 0x41, 0xF4, 0x80, 0x51, 0x11, 0x60, 0x29, 0x68, 0x21, 0xF4, 0x80, 0x21, ++ 0x29, 0x60, 0x21, 0x68, 0x21, 0xF0, 0x00, 0x51, 0x21, 0x60, 0xA5, 0xF5, ++ 0xBC, 0x45, 0x1C, 0x68, 0x2C, 0x60, 0x49, 0x49, 0x5D, 0x68, 0x0D, 0x60, ++ 0x48, 0x4C, 0x9D, 0x68, 0x25, 0x60, 0xDD, 0x68, 0x8D, 0x60, 0x1D, 0x69, ++ 0xA5, 0x60, 0x5C, 0x69, 0x0C, 0x61, 0xD3, 0xE9, 0x06, 0x64, 0x44, 0x4D, ++ 0x44, 0x4B, 0x2E, 0x60, 0x8C, 0x61, 0x9B, 0x78, 0x18, 0x31, 0xCB, 0xB1, ++ 0xA5, 0xF6, 0x78, 0x65, 0x41, 0x4C, 0x2B, 0x68, 0x23, 0xF0, 0xC0, 0x63, ++ 0x43, 0xF0, 0x00, 0x73, 0x2B, 0x60, 0x23, 0x68, 0x01, 0xF5, 0xBB, 0x41, ++ 0x7C, 0x31, 0x43, 0xF0, 0x80, 0x63, 0x23, 0x60, 0x0B, 0x68, 0x43, 0xF4, ++ 0x00, 0x63, 0x0B, 0x60, 0x13, 0x68, 0x23, 0xF4, 0x40, 0x63, 0x43, 0xF4, ++ 0x00, 0x63, 0x13, 0x60, 0x36, 0x4B, 0x93, 0xF8, 0xFA, 0x30, 0x38, 0xB9, ++ 0x43, 0xBB, 0x35, 0x4A, 0x13, 0x68, 0x23, 0xF0, 0x02, 0x03, 0x13, 0x60, ++ 0xBD, 0xE8, 0xF0, 0x81, 0xCB, 0xB1, 0x32, 0x49, 0x32, 0x4A, 0x0B, 0x68, ++ 0x23, 0xF0, 0xFF, 0x03, 0x43, 0xF0, 0xB5, 0x03, 0x0B, 0x60, 0x13, 0x68, ++ 0x23, 0xF0, 0xFF, 0x03, 0x43, 0xF0, 0xB5, 0x03, 0x13, 0x60, 0x0B, 0x68, ++ 0x23, 0xF4, 0x7F, 0x23, 0x43, 0xF4, 0x32, 0x23, 0x0B, 0x60, 0x13, 0x68, ++ 0x23, 0xF4, 0x7F, 0x23, 0x43, 0xF4, 0x32, 0x23, 0x13, 0x60, 0x24, 0x4A, ++ 0x13, 0x68, 0x43, 0xF0, 0x02, 0x03, 0x13, 0x60, 0xBD, 0xE8, 0xF0, 0x81, ++ 0x21, 0x49, 0x22, 0x4A, 0x0B, 0x68, 0x23, 0xF0, 0xFF, 0x03, 0x43, 0xF0, ++ 0xC2, 0x03, 0x0B, 0x60, 0x13, 0x68, 0x23, 0xF0, 0xFF, 0x03, 0x43, 0xF0, ++ 0xC2, 0x03, 0x13, 0x60, 0x0B, 0x68, 0x23, 0xF4, 0x7F, 0x23, 0x43, 0xF4, ++ 0x3F, 0x23, 0x0B, 0x60, 0x13, 0x68, 0x23, 0xF4, 0x7F, 0x23, 0x43, 0xF4, ++ 0x3F, 0x23, 0x13, 0x60, 0xBB, 0xE7, 0x00, 0xBF, 0x9C, 0x18, 0x17, 0x00, ++ 0x1C, 0x18, 0x17, 0x00, 0x1C, 0x16, 0x17, 0x00, 0x40, 0x42, 0x04, 0x40, ++ 0x18, 0x00, 0x58, 0x40, 0x60, 0x40, 0x34, 0x40, 0x6C, 0x40, 0x34, 0x40, ++ 0x64, 0x40, 0x34, 0x40, 0x58, 0x40, 0x34, 0x40, 0x14, 0x20, 0x34, 0x40, ++ 0x18, 0x20, 0x34, 0x40, 0x1C, 0x20, 0x34, 0x40, 0xDC, 0x18, 0x17, 0x00, ++ 0x1C, 0xC2, 0x33, 0x40, 0x20, 0xC2, 0x33, 0x40, 0x30, 0xC2, 0x33, 0x40, ++ 0x3C, 0x36, 0x17, 0x00, 0x38, 0x40, 0x34, 0x40, 0x2C, 0x19, 0x17, 0x00, ++ 0x94, 0x40, 0x04, 0x40, 0xAC, 0xB3, 0x33, 0x40, 0xD4, 0xB3, 0x33, 0x40, ++ 0x1C, 0x13, 0x17, 0x00, 0x10, 0xB4, 0x1C, 0x4B, 0x1C, 0x4C, 0x0F, 0xCB, ++ 0x85, 0xB0, 0x0D, 0xF1, 0x10, 0x0C, 0x0C, 0xE9, 0x0F, 0x00, 0x63, 0x68, ++ 0xDB, 0x06, 0x16, 0xD5, 0x61, 0x68, 0xA3, 0x69, 0x5C, 0xFA, 0x83, 0xF3, ++ 0xC8, 0x04, 0x13, 0xF8, 0x10, 0x2C, 0x22, 0xD4, 0x60, 0x68, 0x14, 0x49, ++ 0x14, 0x4B, 0x10, 0xF4, 0x80, 0x7F, 0x08, 0xBF, 0x0B, 0x46, 0x11, 0x06, ++ 0x44, 0xBF, 0x5B, 0x00, 0x02, 0xF0, 0x7F, 0x02, 0xB3, 0xFB, 0xF2, 0xF3, ++ 0x00, 0xE0, 0x0F, 0x4B, 0x0B, 0x4A, 0x0F, 0x4C, 0x52, 0x69, 0x0F, 0x48, ++ 0x0F, 0x49, 0xD2, 0xB2, 0xB3, 0xFB, 0xF2, 0xF3, 0x23, 0x60, 0xD0, 0xF8, ++ 0x84, 0x20, 0xD2, 0xB2, 0xB3, 0xFB, 0xF2, 0xF3, 0x0B, 0x60, 0x05, 0xB0, ++ 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, 0x09, 0x4B, 0xE1, 0xE7, 0x00, 0xBF, ++ 0x60, 0x79, 0x15, 0x00, 0x00, 0x00, 0x50, 0x40, 0x00, 0x38, 0x9C, 0x1C, ++ 0x00, 0xD0, 0x12, 0x13, 0x00, 0x75, 0x19, 0x03, 0x18, 0x13, 0x17, 0x00, ++ 0x00, 0x00, 0x10, 0x40, 0x14, 0x13, 0x17, 0x00, 0x00, 0x70, 0x38, 0x39, ++ 0x70, 0xB4, 0x5D, 0x4C, 0x5D, 0x48, 0x23, 0x68, 0x5D, 0x4D, 0x5E, 0x49, ++ 0x5E, 0x4A, 0x23, 0xF4, 0xC0, 0x63, 0x43, 0xF4, 0x00, 0x73, 0x23, 0x60, ++ 0x03, 0x68, 0x95, 0xF8, 0xFA, 0x40, 0x23, 0xF4, 0xBC, 0x03, 0x23, 0xF4, ++ 0x70, 0x53, 0x43, 0xF4, 0x60, 0x23, 0x43, 0xF4, 0x80, 0x63, 0x03, 0x60, ++ 0x0B, 0x68, 0x23, 0xF0, 0x60, 0x03, 0x0B, 0x60, 0x13, 0x68, 0x23, 0xF4, ++ 0xFE, 0x33, 0x43, 0xF4, 0x98, 0x33, 0x13, 0x60, 0x00, 0x2C, 0x00, 0xF0, ++ 0x8F, 0x80, 0xA2, 0xF5, 0x11, 0x12, 0xA2, 0xF6, 0x4C, 0x52, 0x13, 0x68, ++ 0x23, 0xF0, 0xC0, 0x63, 0x13, 0x60, 0x4C, 0x4D, 0x4C, 0x48, 0x2B, 0x68, ++ 0x4C, 0x4C, 0x4D, 0x4A, 0x4D, 0x49, 0x4E, 0x4E, 0x43, 0xF0, 0x80, 0x63, ++ 0x2B, 0x60, 0x03, 0x68, 0x43, 0xF4, 0x00, 0x63, 0x03, 0x60, 0x23, 0x68, ++ 0x23, 0xF4, 0x7F, 0x73, 0x43, 0xF0, 0x04, 0x03, 0x23, 0x60, 0x03, 0x68, ++ 0x23, 0xF4, 0x80, 0x53, 0x43, 0xF4, 0x00, 0x63, 0x03, 0x60, 0x13, 0x68, ++ 0x23, 0xF0, 0xCC, 0x03, 0x43, 0xF0, 0xC4, 0x03, 0x13, 0x60, 0x0B, 0x68, ++ 0x03, 0xF0, 0x7F, 0x43, 0xA5, 0xF5, 0xF8, 0x55, 0x43, 0xF4, 0x78, 0x13, ++ 0x0C, 0x3D, 0x43, 0xF4, 0x78, 0x73, 0x0B, 0x60, 0x2B, 0x68, 0x1B, 0x0C, ++ 0xA4, 0xF5, 0x00, 0x54, 0x1B, 0x04, 0x34, 0x3C, 0x43, 0xF0, 0x84, 0x03, ++ 0x2B, 0x60, 0x23, 0x68, 0x37, 0x4D, 0x23, 0xF4, 0x40, 0x63, 0x43, 0xF4, ++ 0x00, 0x63, 0x23, 0x60, 0xD0, 0xF8, 0x04, 0x31, 0x02, 0xF5, 0xF8, 0x52, ++ 0x23, 0xF4, 0xE0, 0x23, 0x18, 0x32, 0x43, 0xF4, 0x80, 0x33, 0xC0, 0xF8, ++ 0x04, 0x31, 0x13, 0x68, 0x23, 0xF0, 0x76, 0x53, 0x23, 0xF0, 0x07, 0x03, ++ 0x01, 0xF5, 0xF7, 0x51, 0x43, 0xF0, 0x04, 0x53, 0x04, 0x31, 0x43, 0xF0, ++ 0x07, 0x03, 0x13, 0x60, 0x0B, 0x68, 0x04, 0xF5, 0x00, 0x54, 0x02, 0xF1, ++ 0xEF, 0x52, 0x00, 0xF5, 0x01, 0x50, 0x1C, 0x34, 0x02, 0xF5, 0x3D, 0x22, ++ 0x02, 0xF6, 0x44, 0x02, 0x1D, 0x40, 0x08, 0x30, 0x22, 0x4B, 0x0D, 0x60, ++ 0x32, 0x60, 0x23, 0x60, 0x03, 0x68, 0x21, 0x4A, 0x21, 0x4C, 0x23, 0xF4, ++ 0x7F, 0x23, 0x23, 0xF4, 0x00, 0x63, 0x43, 0xF4, 0x32, 0x33, 0x03, 0x60, ++ 0xCB, 0x68, 0x43, 0xF4, 0x00, 0x63, 0xCB, 0x60, 0x13, 0x68, 0x23, 0xF0, ++ 0x09, 0x03, 0x43, 0xF4, 0x80, 0x53, 0x13, 0x60, 0x23, 0x68, 0x1B, 0x07, ++ 0x08, 0xD5, 0xA2, 0xF5, 0x0F, 0x12, 0xA2, 0xF5, 0x03, 0x52, 0x24, 0x3A, ++ 0x13, 0x68, 0x23, 0xF4, 0x00, 0x53, 0x13, 0x60, 0x70, 0xBC, 0x70, 0x47, ++ 0x12, 0x4A, 0x13, 0x68, 0x23, 0xF0, 0xC0, 0x63, 0x43, 0xF0, 0x00, 0x73, ++ 0x13, 0x60, 0x70, 0xE7, 0x20, 0x40, 0x34, 0x40, 0x24, 0x40, 0x34, 0x40, ++ 0x2C, 0x19, 0x17, 0x00, 0x28, 0x40, 0x34, 0x40, 0x04, 0x01, 0x58, 0x40, ++ 0x38, 0x40, 0x34, 0x40, 0x30, 0x20, 0x34, 0x40, 0x48, 0x40, 0x34, 0x40, ++ 0x28, 0x21, 0x34, 0x40, 0x24, 0x21, 0x34, 0x40, 0x2C, 0x40, 0x34, 0x40, ++ 0x03, 0x00, 0x00, 0xFF, 0x08, 0x51, 0x2E, 0x1A, 0x08, 0x01, 0x58, 0x40, ++ 0x94, 0x40, 0x04, 0x40, 0xB8, 0xB3, 0x33, 0x40, 0x38, 0xB5, 0xEF, 0xF3, ++ 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x0D, 0x4B, 0x01, 0x22, ++ 0x1A, 0x60, 0x0D, 0x4D, 0x0D, 0x4C, 0x2B, 0x68, 0x01, 0x33, 0x2B, 0x60, ++ 0x23, 0x68, 0x00, 0x2B, 0xFC, 0xD0, 0x4F, 0xF4, 0xDE, 0x73, 0x1B, 0x68, ++ 0x98, 0x47, 0x01, 0x23, 0x23, 0x60, 0x2B, 0x68, 0x33, 0xB1, 0x04, 0x4A, ++ 0x01, 0x3B, 0x12, 0x68, 0x2B, 0x60, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, ++ 0x38, 0xBD, 0x00, 0xBF, 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x5C, 0x40, 0x04, 0x40, 0x38, 0xB5, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, ++ 0x03, 0xD4, 0x72, 0xB6, 0x0D, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x0D, 0x4D, ++ 0x0D, 0x4C, 0x2B, 0x68, 0x01, 0x33, 0x2B, 0x60, 0x23, 0x68, 0x00, 0x2B, ++ 0xFC, 0xD0, 0x4F, 0xF4, 0xE6, 0x73, 0x1B, 0x68, 0x98, 0x47, 0x01, 0x23, ++ 0x23, 0x60, 0x2B, 0x68, 0x33, 0xB1, 0x04, 0x4A, 0x01, 0x3B, 0x12, 0x68, ++ 0x2B, 0x60, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0x38, 0xBD, 0x00, 0xBF, ++ 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0x5C, 0x40, 0x04, 0x40, ++ 0x38, 0xB5, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, ++ 0x0D, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x0D, 0x4D, 0x0D, 0x4C, 0x2B, 0x68, ++ 0x01, 0x33, 0x2B, 0x60, 0x23, 0x68, 0x00, 0x2B, 0xFC, 0xD0, 0x4F, 0xF4, ++ 0xE8, 0x73, 0x1B, 0x68, 0x98, 0x47, 0x01, 0x23, 0x23, 0x60, 0x2B, 0x68, ++ 0x33, 0xB1, 0x04, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x2B, 0x60, 0x0B, 0xB9, ++ 0x02, 0xB1, 0x62, 0xB6, 0x38, 0xBD, 0x00, 0xBF, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x5C, 0x40, 0x04, 0x40, 0x38, 0xB5, 0xEF, 0xF3, ++ 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x0D, 0x4B, 0x01, 0x24, ++ 0x1C, 0x60, 0x0D, 0x4D, 0x0D, 0x4C, 0x2B, 0x68, 0x01, 0x33, 0x2B, 0x60, ++ 0x23, 0x68, 0x00, 0x2B, 0xFC, 0xD0, 0x4F, 0xF4, 0xEA, 0x73, 0x1B, 0x68, ++ 0x98, 0x47, 0x01, 0x23, 0x23, 0x60, 0x2B, 0x68, 0x33, 0xB1, 0x04, 0x4A, ++ 0x01, 0x3B, 0x12, 0x68, 0x2B, 0x60, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, ++ 0x38, 0xBD, 0x00, 0xBF, 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x5C, 0x40, 0x04, 0x40, 0x2D, 0xE9, 0xF0, 0x47, 0x4C, 0x4B, 0x4D, 0x4D, ++ 0x08, 0x22, 0xC3, 0xF8, 0x00, 0x21, 0xAB, 0x78, 0x33, 0xB9, 0x4B, 0x4A, ++ 0x93, 0x68, 0x23, 0xF4, 0x80, 0x23, 0x43, 0xF4, 0x00, 0x33, 0x93, 0x60, ++ 0x47, 0x4A, 0x13, 0x6B, 0x03, 0xF0, 0x22, 0x03, 0x02, 0x2B, 0xFA, 0xD1, ++ 0x93, 0x68, 0x45, 0x4C, 0x41, 0x49, 0x45, 0x48, 0x23, 0xF4, 0x00, 0x63, ++ 0x43, 0xF0, 0x01, 0x13, 0x43, 0xF4, 0x04, 0x43, 0x93, 0x60, 0x06, 0x23, ++ 0x23, 0x60, 0x53, 0x6D, 0x40, 0x4C, 0x23, 0xF4, 0x40, 0x13, 0x53, 0x65, ++ 0x4F, 0xF4, 0x00, 0x63, 0xC1, 0xF8, 0x34, 0x31, 0x13, 0x68, 0x11, 0x68, ++ 0xC3, 0xF3, 0x09, 0x03, 0x43, 0xF0, 0x80, 0x03, 0x01, 0x40, 0x0B, 0x43, ++ 0x13, 0x60, 0x23, 0x68, 0x1B, 0x78, 0x01, 0x2B, 0x08, 0xD1, 0x13, 0x68, ++ 0x11, 0x68, 0xC3, 0xF3, 0x09, 0x03, 0x43, 0xF0, 0x08, 0x03, 0x08, 0x40, ++ 0x18, 0x43, 0x10, 0x60, 0x2E, 0x49, 0x2C, 0x4E, 0x0B, 0x68, 0x0A, 0x68, ++ 0x30, 0x48, 0xC3, 0xF3, 0x09, 0x03, 0x22, 0xF4, 0x7F, 0x72, 0x22, 0xF0, ++ 0x03, 0x02, 0x43, 0xF4, 0x80, 0x73, 0x13, 0x43, 0x0B, 0x60, 0x73, 0x6F, ++ 0x2B, 0x4A, 0x43, 0xF0, 0x02, 0x03, 0x73, 0x67, 0x03, 0x68, 0x2A, 0x4E, ++ 0x23, 0xF4, 0x00, 0x63, 0x03, 0x60, 0x13, 0x68, 0x96, 0xF8, 0xA9, 0x00, ++ 0x43, 0xF0, 0x80, 0x73, 0x13, 0x60, 0x68, 0xB1, 0x0B, 0x6B, 0x5F, 0x06, ++ 0x05, 0xD4, 0x0B, 0x6B, 0x58, 0x07, 0x02, 0xD5, 0x22, 0x4B, 0x01, 0x22, ++ 0x1A, 0x70, 0x1A, 0x4B, 0x1A, 0x6B, 0x52, 0x06, 0x40, 0xF1, 0x10, 0x82, ++ 0x1F, 0x4B, 0xD6, 0xF8, 0xA0, 0x20, 0x1A, 0x60, 0xAB, 0x78, 0x00, 0x2B, ++ 0x3E, 0xD0, 0x1D, 0x4B, 0x1A, 0x68, 0x13, 0x78, 0x02, 0x2B, 0x00, 0xF0, ++ 0x6C, 0x82, 0x11, 0x4B, 0x0E, 0x48, 0x02, 0x21, 0x11, 0x70, 0x1A, 0x6D, ++ 0xA9, 0x78, 0x42, 0xF4, 0x80, 0x22, 0x1A, 0x65, 0x02, 0x69, 0x22, 0xF0, ++ 0x80, 0x02, 0x02, 0x61, 0x5A, 0x6A, 0x22, 0xF0, 0xFF, 0x02, 0x42, 0xF0, ++ 0xDF, 0x02, 0x5A, 0x62, 0x5A, 0x6A, 0x22, 0xF4, 0x7F, 0x42, 0x42, 0xF4, ++ 0x5F, 0x42, 0x5A, 0x62, 0x00, 0x29, 0x33, 0xD0, 0x03, 0xF0, 0xB0, 0xFC, ++ 0x0C, 0x4F, 0x33, 0xE0, 0x00, 0x00, 0x50, 0x40, 0x3C, 0x36, 0x17, 0x00, ++ 0x00, 0x60, 0x50, 0x40, 0x10, 0x00, 0x58, 0x40, 0x00, 0xFC, 0xFF, 0xFF, ++ 0x78, 0x36, 0x17, 0x00, 0x00, 0x01, 0x58, 0x40, 0x20, 0x01, 0x58, 0x40, ++ 0x2C, 0x19, 0x17, 0x00, 0x4C, 0x36, 0x17, 0x00, 0xE0, 0x50, 0x34, 0x40, ++ 0x74, 0x36, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0xC0, 0x4B, 0xC1, 0x49, ++ 0x1A, 0x6D, 0x42, 0xF4, 0x80, 0x22, 0x1A, 0x65, 0x0A, 0x69, 0x22, 0xF0, ++ 0x80, 0x02, 0x0A, 0x61, 0x5A, 0x6A, 0x22, 0xF0, 0xFF, 0x02, 0x42, 0xF0, ++ 0xDF, 0x02, 0x5A, 0x62, 0x5A, 0x6A, 0x22, 0xF4, 0x7F, 0x42, 0x42, 0xF4, ++ 0x5F, 0x42, 0x5A, 0x62, 0xB7, 0x4F, 0xD7, 0xF8, 0xCC, 0x30, 0x98, 0x47, ++ 0x03, 0xF0, 0xF4, 0xF9, 0xD7, 0xF8, 0x9C, 0x34, 0x98, 0x47, 0xB2, 0x4B, ++ 0xB3, 0x49, 0x1B, 0x68, 0xB3, 0x4A, 0xA8, 0x78, 0x1B, 0x0C, 0x0B, 0x70, ++ 0x04, 0x23, 0x1B, 0x68, 0x1B, 0x09, 0x13, 0x70, 0x10, 0xB9, 0xD7, 0xF8, ++ 0x80, 0x34, 0x98, 0x47, 0xAE, 0x48, 0xAF, 0x4D, 0xFF, 0xF7, 0x78, 0xFE, ++ 0xAE, 0x48, 0xFF, 0xF7, 0x9D, 0xFE, 0x03, 0x46, 0x1A, 0x0C, 0xAD, 0x49, ++ 0x2A, 0x70, 0x1B, 0x0F, 0x02, 0x22, 0x0B, 0x70, 0xAB, 0x48, 0x11, 0x46, ++ 0xFF, 0xF7, 0xE2, 0xFE, 0x4F, 0xF4, 0x80, 0x52, 0x11, 0x46, 0xA9, 0x48, ++ 0xFF, 0xF7, 0xDC, 0xFE, 0xA8, 0x4A, 0xA9, 0x49, 0xA9, 0x48, 0xFF, 0xF7, ++ 0xD7, 0xFE, 0x2B, 0x78, 0x01, 0x2B, 0x00, 0xF0, 0x8E, 0x81, 0xA7, 0x48, ++ 0x4F, 0xF4, 0x7F, 0x52, 0x4F, 0xF4, 0x9E, 0x51, 0xFF, 0xF7, 0xCC, 0xFE, ++ 0x04, 0x22, 0xA4, 0x48, 0x11, 0x46, 0xFF, 0xF7, 0xC7, 0xFE, 0x23, 0x68, ++ 0x1B, 0x78, 0x02, 0x2B, 0x04, 0xD0, 0xA1, 0x48, 0x07, 0x22, 0x00, 0x21, ++ 0xFF, 0xF7, 0xBE, 0xFE, 0x01, 0x21, 0x02, 0x20, 0x03, 0xF0, 0x5C, 0xFE, ++ 0x04, 0x22, 0x9D, 0x48, 0x00, 0x21, 0xFF, 0xF7, 0xB5, 0xFE, 0x01, 0x21, ++ 0x03, 0x20, 0x03, 0xF0, 0x53, 0xFE, 0x08, 0x22, 0x98, 0x48, 0x00, 0x21, ++ 0xFF, 0xF7, 0xAC, 0xFE, 0x00, 0x21, 0x05, 0x20, 0x03, 0xF0, 0x4A, 0xFE, ++ 0x95, 0x48, 0x20, 0x22, 0x00, 0x21, 0xFF, 0xF7, 0xA3, 0xFE, 0x20, 0x22, ++ 0x11, 0x46, 0x93, 0x48, 0xFF, 0xF7, 0x9E, 0xFE, 0x20, 0x22, 0x11, 0x46, ++ 0x91, 0x48, 0xFF, 0xF7, 0x99, 0xFE, 0x02, 0x22, 0x90, 0x48, 0x11, 0x46, ++ 0xFF, 0xF7, 0x94, 0xFE, 0x4F, 0xF4, 0xD2, 0x73, 0x0F, 0x20, 0x1B, 0x68, ++ 0x98, 0x47, 0x00, 0xF0, 0x60, 0x00, 0x20, 0x28, 0x00, 0xF0, 0x74, 0x81, ++ 0x4F, 0xF4, 0xFC, 0x02, 0x11, 0x46, 0x89, 0x48, 0xFF, 0xF7, 0x84, 0xFE, ++ 0x88, 0x4A, 0x89, 0x48, 0x4F, 0xF0, 0x46, 0x41, 0xFF, 0xF7, 0x7E, 0xFE, ++ 0x87, 0x48, 0x3F, 0x22, 0x1F, 0x21, 0xFF, 0xF7, 0x79, 0xFE, 0x4F, 0xF4, ++ 0x80, 0x22, 0x85, 0x48, 0x00, 0x21, 0xFF, 0xF7, 0x73, 0xFE, 0x84, 0x48, ++ 0x4F, 0xF4, 0x8E, 0x71, 0xFF, 0xF7, 0x46, 0xFE, 0x82, 0x48, 0x4F, 0xF4, ++ 0xF8, 0x22, 0x4F, 0xF4, 0xD8, 0x21, 0xFF, 0xF7, 0x67, 0xFE, 0x40, 0x22, ++ 0x11, 0x46, 0x7F, 0x48, 0xFF, 0xF7, 0x62, 0xFE, 0x4F, 0xF4, 0xC0, 0x32, ++ 0x11, 0x46, 0x7D, 0x48, 0xFF, 0xF7, 0x5C, 0xFE, 0x7C, 0x48, 0x4F, 0xF4, ++ 0xE0, 0x62, 0x4F, 0xF4, 0x00, 0x71, 0xFF, 0xF7, 0x55, 0xFE, 0x96, 0xF8, ++ 0xC7, 0x70, 0xB7, 0xB3, 0x78, 0x4A, 0x96, 0xF8, 0xC8, 0x10, 0x78, 0x4B, ++ 0x96, 0xF8, 0xC9, 0x00, 0x11, 0x70, 0x96, 0xF8, 0xCA, 0x10, 0x50, 0x70, ++ 0x91, 0x70, 0x96, 0xF8, 0xCB, 0x50, 0x96, 0xF8, 0xCC, 0x00, 0x96, 0xF8, ++ 0xCD, 0x10, 0x96, 0xF8, 0xCE, 0x20, 0x1D, 0x70, 0x58, 0x70, 0x99, 0x70, ++ 0xDA, 0x70, 0x4F, 0xF4, 0xD2, 0x73, 0x0F, 0x20, 0x1B, 0x68, 0x98, 0x47, ++ 0x10, 0xF4, 0x60, 0x2F, 0xC0, 0xF3, 0x42, 0x41, 0x0E, 0xD0, 0x6A, 0x4A, ++ 0x8D, 0x01, 0x02, 0xF1, 0x40, 0x00, 0x52, 0xF8, 0x04, 0x3F, 0x23, 0xF4, ++ 0xE0, 0x73, 0x2B, 0x43, 0x90, 0x42, 0x13, 0x60, 0xF7, 0xD1, 0x65, 0x48, ++ 0x03, 0xF0, 0x68, 0xFD, 0x23, 0x68, 0x1C, 0x78, 0x01, 0x2C, 0x00, 0xF0, ++ 0xEF, 0x80, 0xBD, 0xE8, 0xF0, 0x87, 0x4F, 0xF4, 0xD2, 0x76, 0x0A, 0x20, ++ 0x33, 0x68, 0xDF, 0xF8, 0x6C, 0xA1, 0x98, 0x47, 0x33, 0x68, 0x05, 0x46, ++ 0x0B, 0x20, 0x98, 0x47, 0x33, 0x68, 0x80, 0x46, 0x0F, 0x20, 0x98, 0x47, ++ 0x5F, 0xEA, 0x95, 0x7C, 0x3A, 0x46, 0x0C, 0xBF, 0x4F, 0xF0, 0x08, 0x09, ++ 0x4F, 0xF0, 0x10, 0x09, 0x4F, 0xEA, 0x15, 0x6E, 0xD3, 0x00, 0x25, 0xFA, ++ 0x03, 0xF3, 0xDF, 0xB2, 0xC3, 0xF3, 0x03, 0x13, 0xBC, 0xF1, 0x00, 0x0F, ++ 0x38, 0xD1, 0x00, 0x2B, 0x54, 0xD1, 0x00, 0x2F, 0x40, 0xF0, 0x1F, 0x81, ++ 0x01, 0x32, 0x03, 0x2A, 0xEE, 0xD1, 0xDF, 0xF8, 0x24, 0xE1, 0x07, 0x0E, ++ 0x00, 0x21, 0xCB, 0x00, 0x28, 0xFA, 0x03, 0xF3, 0xDE, 0xB2, 0xC3, 0xF3, ++ 0x03, 0x13, 0xBC, 0xF1, 0x00, 0x0F, 0x0B, 0xD1, 0xEB, 0xB1, 0x08, 0x22, ++ 0x93, 0x42, 0x28, 0xBF, 0xD3, 0x1A, 0x5B, 0xB2, 0x0E, 0xF8, 0x01, 0x30, ++ 0x01, 0x31, 0x04, 0x29, 0xEB, 0xD1, 0x9C, 0xE7, 0x4D, 0x00, 0x6A, 0x1C, ++ 0x47, 0xFA, 0x02, 0xF2, 0x12, 0x01, 0x02, 0xF0, 0x10, 0x02, 0x13, 0x43, ++ 0x13, 0xF0, 0xFF, 0x03, 0x1F, 0xD1, 0x47, 0xFA, 0x05, 0xF3, 0x1B, 0x01, ++ 0x03, 0xF0, 0x10, 0x03, 0x06, 0xF0, 0x0F, 0x06, 0x1E, 0x43, 0x00, 0x2E, ++ 0xE6, 0xD0, 0x33, 0x46, 0x4A, 0x46, 0xDD, 0xE7, 0x56, 0x00, 0x71, 0x1C, ++ 0x4E, 0xFA, 0x01, 0xF1, 0x09, 0x01, 0x01, 0xF0, 0x10, 0x01, 0x0B, 0x43, ++ 0x13, 0xF0, 0xFF, 0x03, 0x09, 0xD0, 0x10, 0x21, 0x8B, 0x42, 0x28, 0xBF, ++ 0xCB, 0x1A, 0x5B, 0xB2, 0x0A, 0xF8, 0x02, 0x30, 0xB8, 0xE7, 0x10, 0x22, ++ 0xC8, 0xE7, 0x4E, 0xFA, 0x06, 0xF3, 0x1B, 0x01, 0x03, 0xF0, 0x10, 0x03, ++ 0x07, 0xF0, 0x0F, 0x07, 0x1F, 0x43, 0xAA, 0xE7, 0x08, 0x21, 0xEB, 0xE7, ++ 0x00, 0x60, 0x50, 0x40, 0x00, 0x00, 0x50, 0x40, 0x88, 0x1A, 0x17, 0x00, ++ 0x11, 0x13, 0x17, 0x00, 0x12, 0x13, 0x17, 0x00, 0x04, 0x02, 0x22, 0x03, ++ 0x10, 0x13, 0x17, 0x00, 0x00, 0x00, 0x01, 0x50, 0x70, 0x25, 0x17, 0x00, ++ 0x50, 0x91, 0x01, 0x50, 0x20, 0x91, 0x01, 0x50, 0xC0, 0xFD, 0x01, 0x00, ++ 0xC0, 0xF1, 0x01, 0x00, 0x24, 0x91, 0x01, 0x50, 0x08, 0x88, 0x01, 0x50, ++ 0x18, 0x88, 0x01, 0x50, 0x2C, 0x91, 0x01, 0x50, 0x00, 0x10, 0x01, 0x50, ++ 0x0C, 0x10, 0x01, 0x50, 0x10, 0x10, 0x01, 0x50, 0x18, 0x10, 0x01, 0x50, ++ 0x00, 0x30, 0x01, 0x50, 0x00, 0x88, 0x01, 0x50, 0x00, 0x00, 0xC0, 0xFF, ++ 0x04, 0x88, 0x01, 0x50, 0x28, 0x91, 0x01, 0x50, 0x5C, 0x00, 0x01, 0x50, ++ 0x58, 0x00, 0x01, 0x50, 0x74, 0x91, 0x01, 0x50, 0x18, 0x91, 0x01, 0x50, ++ 0x00, 0x91, 0x01, 0x50, 0x30, 0x88, 0x01, 0x50, 0x68, 0x25, 0x17, 0x00, ++ 0x6C, 0x25, 0x17, 0x00, 0x18, 0x18, 0x17, 0x00, 0x74, 0x79, 0x15, 0x00, ++ 0x1B, 0x6B, 0x59, 0x07, 0x7F, 0xF5, 0xEC, 0xAD, 0xD6, 0xF8, 0xA0, 0x30, ++ 0x3F, 0x48, 0x40, 0x49, 0x40, 0x4A, 0x43, 0xF0, 0x00, 0x73, 0x01, 0x27, ++ 0x07, 0x70, 0x0B, 0x60, 0x53, 0x6F, 0x43, 0xF0, 0x10, 0x03, 0x53, 0x67, ++ 0xE0, 0xE5, 0x3C, 0x4A, 0x3C, 0x49, 0x3D, 0x48, 0xFF, 0xF7, 0x40, 0xFD, ++ 0x3C, 0x48, 0x4F, 0xF4, 0x08, 0x42, 0x4F, 0xF4, 0x00, 0x41, 0xFF, 0xF7, ++ 0x39, 0xFD, 0x3A, 0x4A, 0x3A, 0x49, 0x3B, 0x48, 0xFF, 0xF7, 0x34, 0xFD, ++ 0x3A, 0x48, 0x8F, 0x22, 0x06, 0x21, 0xFF, 0xF7, 0x2F, 0xFD, 0x66, 0xE6, ++ 0x38, 0x49, 0x39, 0x48, 0x4F, 0xF0, 0xFF, 0x32, 0xFF, 0xF7, 0x28, 0xFD, ++ 0x4F, 0xF0, 0xFF, 0x32, 0x36, 0x48, 0x4F, 0xF0, 0x02, 0x11, 0xFF, 0xF7, ++ 0x21, 0xFD, 0x35, 0x49, 0x35, 0x48, 0xFF, 0xF7, 0xF5, 0xFC, 0x22, 0x46, ++ 0x21, 0x46, 0x34, 0x48, 0xBD, 0xE8, 0xF0, 0x47, 0xFF, 0xF7, 0x16, 0xBD, ++ 0x32, 0x48, 0x0F, 0x22, 0x01, 0x21, 0xFF, 0xF7, 0x11, 0xFD, 0x02, 0x22, ++ 0x11, 0x46, 0x30, 0x48, 0xFF, 0xF7, 0x0C, 0xFD, 0x02, 0x22, 0x11, 0x46, ++ 0x2E, 0x48, 0xFF, 0xF7, 0x07, 0xFD, 0x4F, 0xF4, 0x00, 0x52, 0x11, 0x46, ++ 0x2A, 0x48, 0xFF, 0xF7, 0x01, 0xFD, 0x4F, 0xF4, 0x00, 0x52, 0x11, 0x46, ++ 0x28, 0x48, 0xFF, 0xF7, 0xFB, 0xFC, 0x02, 0x22, 0x11, 0x46, 0x27, 0x48, ++ 0xFF, 0xF7, 0xF6, 0xFC, 0x25, 0x48, 0x4F, 0xF4, 0x00, 0x52, 0x00, 0x21, ++ 0xFF, 0xF7, 0xF0, 0xFC, 0x64, 0xE6, 0x23, 0x4B, 0x0F, 0x49, 0x1A, 0x6D, ++ 0x22, 0x4F, 0x42, 0xF4, 0x80, 0x22, 0x1A, 0x65, 0x0A, 0x69, 0x22, 0xF0, ++ 0x80, 0x02, 0x0A, 0x61, 0x5A, 0x6A, 0x22, 0xF0, 0xFF, 0x02, 0x42, 0xF0, ++ 0xDF, 0x02, 0x5A, 0x62, 0x5A, 0x6A, 0x22, 0xF4, 0x7F, 0x42, 0x42, 0xF4, ++ 0x5F, 0x42, 0x5A, 0x62, 0x03, 0xF0, 0x48, 0xFA, 0xCC, 0xE5, 0x3B, 0x46, ++ 0x49, 0x46, 0x1D, 0xE7, 0x4C, 0x36, 0x17, 0x00, 0xE0, 0x50, 0x34, 0x40, ++ 0x00, 0x00, 0x50, 0x40, 0xC0, 0x3F, 0x00, 0x40, 0x40, 0x12, 0x00, 0x40, ++ 0x08, 0x88, 0x01, 0x50, 0x04, 0x91, 0x01, 0x50, 0xE0, 0x01, 0x00, 0x22, ++ 0xC0, 0x00, 0x00, 0x02, 0x08, 0x91, 0x01, 0x50, 0x00, 0x91, 0x01, 0x50, ++ 0x00, 0x01, 0x00, 0x03, 0x0C, 0x80, 0x01, 0x50, 0x18, 0x80, 0x01, 0x50, ++ 0x0A, 0x33, 0x41, 0x01, 0x38, 0x91, 0x01, 0x50, 0x04, 0x00, 0x01, 0x50, ++ 0x04, 0x20, 0x01, 0x50, 0x04, 0x10, 0x01, 0x50, 0x08, 0x10, 0x01, 0x50, ++ 0x00, 0x10, 0x01, 0x50, 0x00, 0x60, 0x50, 0x40, 0x88, 0x1A, 0x17, 0x00, ++ 0x10, 0x4B, 0x11, 0x4A, 0x19, 0x68, 0x21, 0xF4, 0x78, 0x11, 0x41, 0xF4, ++ 0x50, 0x11, 0x19, 0x60, 0x19, 0x68, 0x21, 0xF4, 0x78, 0x11, 0x41, 0xF4, ++ 0xA0, 0x11, 0x19, 0x60, 0x11, 0x69, 0x18, 0x68, 0x20, 0xF4, 0x78, 0x10, ++ 0x40, 0xF4, 0x50, 0x10, 0x32, 0x31, 0x18, 0x60, 0x13, 0x69, 0xCB, 0x1A, ++ 0x00, 0x2B, 0xFB, 0xDA, 0x03, 0x4A, 0x13, 0x68, 0x23, 0xF4, 0x78, 0x13, ++ 0x43, 0xF4, 0x00, 0x13, 0x13, 0x60, 0x70, 0x47, 0x58, 0x40, 0x34, 0x40, ++ 0x00, 0x10, 0x50, 0x40, 0x1E, 0x49, 0x1F, 0x4A, 0x0B, 0x68, 0x43, 0xF4, ++ 0x00, 0x13, 0x10, 0xB4, 0x0B, 0x60, 0x13, 0x68, 0x59, 0x07, 0x08, 0xD4, ++ 0x32, 0x23, 0x00, 0xBF, 0x01, 0x3B, 0x9B, 0xB2, 0x00, 0x2B, 0xFA, 0xD1, ++ 0x13, 0x68, 0x59, 0x07, 0xF6, 0xD5, 0x15, 0x49, 0x15, 0x4A, 0x0B, 0x68, ++ 0x43, 0xF4, 0xC0, 0x23, 0x0B, 0x60, 0x13, 0x68, 0x9B, 0x07, 0x08, 0xD4, ++ 0x32, 0x23, 0x00, 0xBF, 0x01, 0x3B, 0x9B, 0xB2, 0x00, 0x2B, 0xFA, 0xD1, ++ 0x13, 0x68, 0x9B, 0x07, 0xF6, 0xD5, 0x0E, 0x4C, 0x0E, 0x48, 0x23, 0x68, ++ 0x0E, 0x4A, 0x0F, 0x49, 0x43, 0xF4, 0x00, 0x33, 0x23, 0x60, 0x03, 0x68, ++ 0x5D, 0xF8, 0x04, 0x4B, 0x43, 0xF0, 0x80, 0x73, 0x03, 0x60, 0x13, 0x68, ++ 0x43, 0xF4, 0xA4, 0x63, 0x43, 0xF0, 0x04, 0x03, 0x13, 0x60, 0x4F, 0xF4, ++ 0x00, 0x50, 0x21, 0xF0, 0xA1, 0xBD, 0x00, 0xBF, 0x58, 0x40, 0x34, 0x40, ++ 0x80, 0x40, 0x34, 0x40, 0x2C, 0x20, 0x34, 0x40, 0x10, 0x00, 0x34, 0x40, ++ 0x30, 0x20, 0x34, 0x40, 0x9C, 0x79, 0x15, 0x00, 0x10, 0xB5, 0x10, 0x4C, ++ 0x10, 0x48, 0x23, 0x68, 0x10, 0x49, 0x11, 0x4A, 0x23, 0xF4, 0x05, 0x43, ++ 0x23, 0xF0, 0xEC, 0x03, 0x23, 0x60, 0x03, 0x68, 0x23, 0xF4, 0x00, 0x33, ++ 0x03, 0x60, 0x0B, 0x68, 0x23, 0xF0, 0x80, 0x73, 0x0B, 0x60, 0x13, 0x68, ++ 0x23, 0xF4, 0xC0, 0x23, 0x0A, 0x20, 0x13, 0x60, 0xFD, 0xF7, 0xD6, 0xFC, ++ 0xBD, 0xE8, 0x10, 0x40, 0x06, 0x49, 0x4F, 0xF4, 0x00, 0x50, 0x21, 0xF0, ++ 0x73, 0xBD, 0x00, 0xBF, 0x30, 0x20, 0x34, 0x40, 0x2C, 0x20, 0x34, 0x40, ++ 0x10, 0x00, 0x34, 0x40, 0x58, 0x40, 0x34, 0x40, 0xB8, 0x79, 0x15, 0x00, ++ 0x32, 0x23, 0x00, 0xBF, 0x01, 0x3B, 0x9B, 0xB2, 0x00, 0x2B, 0xFA, 0xD1, ++ 0x19, 0x4B, 0x02, 0x22, 0x1A, 0x60, 0x32, 0x23, 0x00, 0xBF, 0x01, 0x3B, ++ 0x9B, 0xB2, 0x00, 0x2B, 0xFA, 0xD1, 0x16, 0x4A, 0x13, 0x68, 0xDB, 0x07, ++ 0x11, 0xD4, 0x32, 0x23, 0x00, 0xBF, 0x01, 0x3B, 0x9B, 0xB2, 0x00, 0x2B, ++ 0xFA, 0xD1, 0x13, 0x68, 0xDB, 0x07, 0xF6, 0xD5, 0x32, 0x23, 0x00, 0xBF, ++ 0x01, 0x3B, 0x9B, 0xB2, 0x00, 0x2B, 0xFA, 0xD1, 0x13, 0x68, 0xDB, 0x07, ++ 0xED, 0xD5, 0x0B, 0x4B, 0x1A, 0x68, 0x53, 0x0C, 0x00, 0x2A, 0xBC, 0xBF, ++ 0x6F, 0xEA, 0x43, 0x43, 0x6F, 0xEA, 0x53, 0x43, 0x03, 0x60, 0xC2, 0xF3, ++ 0x4E, 0x03, 0x12, 0x04, 0x44, 0xBF, 0x6F, 0xEA, 0x43, 0x43, 0x6F, 0xEA, ++ 0x53, 0x43, 0x0B, 0x60, 0x70, 0x47, 0x00, 0xBF, 0x84, 0x21, 0x34, 0x40, ++ 0x00, 0x22, 0x34, 0x40, 0x2D, 0xE9, 0xF0, 0x41, 0x2A, 0x4F, 0x2B, 0x4D, ++ 0x3B, 0x68, 0x2B, 0x4A, 0x23, 0xF4, 0x7F, 0x53, 0x3B, 0x60, 0x2B, 0x68, ++ 0x43, 0xF4, 0x80, 0x63, 0x2B, 0x60, 0x13, 0x68, 0x43, 0xF0, 0x40, 0x03, ++ 0x13, 0x60, 0x01, 0x20, 0xFD, 0xF7, 0x72, 0xFC, 0x00, 0x24, 0x26, 0x46, ++ 0x4F, 0xF0, 0x07, 0x08, 0x02, 0x20, 0xFD, 0xF7, 0x6B, 0xFC, 0x2B, 0x68, ++ 0xDA, 0x05, 0x54, 0xBF, 0x01, 0x36, 0x06, 0xF1, 0xFF, 0x36, 0x76, 0xB2, ++ 0x1B, 0x06, 0x3B, 0x68, 0x54, 0xBF, 0x01, 0x34, 0x04, 0xF1, 0xFF, 0x34, ++ 0x00, 0x2E, 0x23, 0xF4, 0x7F, 0x53, 0xDC, 0xBF, 0x70, 0x42, 0x43, 0xEA, ++ 0x80, 0x23, 0x64, 0xB2, 0xD4, 0xBF, 0x43, 0xF4, 0x00, 0x53, 0x43, 0xEA, ++ 0x86, 0x23, 0x00, 0x2C, 0xDC, 0xBF, 0x60, 0x42, 0x43, 0xEA, 0x80, 0x13, ++ 0x08, 0xF1, 0xFF, 0x32, 0xCC, 0xBF, 0x43, 0xEA, 0x84, 0x13, 0x43, 0xF4, ++ 0x00, 0x73, 0x12, 0xF0, 0xFF, 0x08, 0x3B, 0x60, 0xD2, 0xD1, 0x0A, 0x48, ++ 0x0A, 0x49, 0x02, 0x68, 0x22, 0xF4, 0x80, 0x62, 0x02, 0x60, 0x0A, 0x68, ++ 0xC3, 0xF3, 0x83, 0x10, 0x22, 0xF0, 0x40, 0x02, 0xC3, 0xF3, 0x83, 0x23, ++ 0x0A, 0x60, 0x43, 0xEA, 0x00, 0x10, 0xBD, 0xE8, 0xF0, 0x81, 0x00, 0xBF, ++ 0x50, 0x40, 0x34, 0x40, 0x14, 0x40, 0x34, 0x40, 0x5C, 0x40, 0x34, 0x40, ++ 0x01, 0x28, 0x15, 0xD0, 0x02, 0x28, 0x05, 0xD0, 0x4B, 0x78, 0x10, 0x2B, ++ 0x19, 0xD8, 0x30, 0x23, 0x8B, 0x70, 0x70, 0x47, 0xD2, 0xE9, 0x00, 0x32, ++ 0x00, 0x2B, 0x24, 0xDD, 0x00, 0x2A, 0x37, 0xDB, 0xB3, 0xEB, 0x42, 0x0F, ++ 0x0B, 0x78, 0xCC, 0xBF, 0x10, 0x3B, 0x18, 0x3B, 0x4B, 0x70, 0x70, 0x47, ++ 0x13, 0x68, 0xB3, 0xF5, 0x00, 0x5F, 0x10, 0xDA, 0x00, 0x2B, 0x1A, 0xDD, ++ 0x40, 0x23, 0x0B, 0x70, 0x70, 0x47, 0x30, 0x2B, 0x0C, 0xD9, 0x60, 0x2B, ++ 0x1A, 0xD8, 0x92, 0x68, 0x00, 0x2A, 0x28, 0xDB, 0x60, 0x2B, 0xDC, 0xD1, ++ 0x20, 0x23, 0x8B, 0x70, 0x70, 0x47, 0x20, 0x23, 0x0B, 0x70, 0x70, 0x47, ++ 0x18, 0x23, 0x8B, 0x70, 0x70, 0x47, 0x00, 0x2A, 0x1E, 0xDD, 0x0B, 0x78, ++ 0x20, 0x3B, 0x4B, 0x70, 0x70, 0x47, 0x13, 0xF5, 0x00, 0x5F, 0xD4, 0xBF, ++ 0xE0, 0x23, 0xC0, 0x23, 0x0B, 0x70, 0x70, 0x47, 0xC0, 0x2B, 0x09, 0xD8, ++ 0x92, 0x68, 0x00, 0x2A, 0x19, 0xDD, 0x60, 0x23, 0x8B, 0x70, 0x70, 0x47, ++ 0x0B, 0x78, 0x20, 0x33, 0x4B, 0x70, 0x70, 0x47, 0xD8, 0x2B, 0x0D, 0xD8, ++ 0xE8, 0x23, 0x8B, 0x70, 0x70, 0x47, 0xA0, 0x23, 0x8B, 0x70, 0x70, 0x47, ++ 0xB3, 0xEB, 0x42, 0x0F, 0x0B, 0x78, 0xB4, 0xBF, 0x10, 0x33, 0x18, 0x33, ++ 0x4B, 0x70, 0x70, 0x47, 0xD0, 0x23, 0x8B, 0x70, 0x70, 0x47, 0xA0, 0x2B, ++ 0xFA, 0xD1, 0xE0, 0x23, 0x8B, 0x70, 0x70, 0x47, 0x01, 0x28, 0x1D, 0xD0, ++ 0x02, 0x28, 0x08, 0xD0, 0x09, 0x78, 0x01, 0x39, 0x05, 0x29, 0x69, 0xD8, ++ 0xDF, 0xE8, 0x01, 0xF0, 0x3C, 0x42, 0x39, 0x33, 0x2D, 0x2A, 0x10, 0xB4, ++ 0x1C, 0x68, 0xB4, 0xF5, 0x00, 0x5F, 0x19, 0xDA, 0x00, 0x2C, 0x4A, 0xDD, ++ 0x5B, 0x68, 0x00, 0x2B, 0x13, 0x78, 0xAA, 0xBF, 0x03, 0x20, 0x10, 0x33, ++ 0x10, 0x3B, 0x53, 0x70, 0x08, 0x70, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, ++ 0x1B, 0x68, 0xB3, 0xF5, 0x00, 0x5F, 0x04, 0xDA, 0x00, 0x2B, 0x2B, 0xDD, ++ 0x50, 0x23, 0x13, 0x70, 0x70, 0x47, 0x30, 0x23, 0x13, 0x70, 0x70, 0x47, ++ 0x13, 0x78, 0x01, 0x20, 0x10, 0x33, 0x53, 0x70, 0x08, 0x70, 0x5D, 0xF8, ++ 0x04, 0x4B, 0x70, 0x47, 0xC8, 0x23, 0x93, 0x70, 0x70, 0x47, 0x9B, 0x68, ++ 0x00, 0x2B, 0x21, 0xDD, 0x70, 0x23, 0x93, 0x70, 0x70, 0x47, 0x9B, 0x68, ++ 0x00, 0x2B, 0x18, 0xDD, 0x90, 0x23, 0x93, 0x70, 0x70, 0x47, 0x38, 0x23, ++ 0x93, 0x70, 0x70, 0x47, 0x9B, 0x68, 0x00, 0x2B, 0xF0, 0xDD, 0x20, 0x23, ++ 0x93, 0x70, 0x70, 0x47, 0x9B, 0x68, 0x00, 0x2B, 0xF0, 0xDD, 0x40, 0x23, ++ 0x93, 0x70, 0x70, 0x47, 0x13, 0xF5, 0x00, 0x5F, 0xD4, 0xBF, 0xD0, 0x23, ++ 0xB0, 0x23, 0x13, 0x70, 0x70, 0x47, 0xE0, 0x23, 0x93, 0x70, 0x70, 0x47, ++ 0xC0, 0x23, 0x93, 0x70, 0x70, 0x47, 0x14, 0xF5, 0x00, 0x5F, 0x05, 0xDC, ++ 0x13, 0x78, 0x04, 0x20, 0x10, 0x3B, 0x53, 0x70, 0x08, 0x70, 0xB4, 0xE7, ++ 0x5B, 0x68, 0x00, 0x2B, 0x13, 0x78, 0xCC, 0xBF, 0x05, 0x20, 0x06, 0x20, ++ 0x10, 0x3B, 0x53, 0x70, 0x08, 0x70, 0xAA, 0xE7, 0x88, 0x23, 0x93, 0x70, ++ 0x70, 0x47, 0x00, 0xBF, 0x30, 0xB4, 0x0F, 0x29, 0x15, 0x46, 0x1C, 0x46, ++ 0x02, 0x9A, 0x03, 0xD0, 0x30, 0xBC, 0x19, 0x46, 0xFF, 0xF7, 0x1C, 0xBF, ++ 0x13, 0x46, 0x29, 0x46, 0x22, 0x46, 0x30, 0xBC, 0xFF, 0xF7, 0x7A, 0xBF, ++ 0x70, 0xB4, 0x50, 0xEA, 0x01, 0x04, 0x02, 0xD1, 0x70, 0xBC, 0x1A, 0x60, ++ 0x70, 0x47, 0x08, 0x18, 0x18, 0xBF, 0x00, 0x21, 0x03, 0xD1, 0x20, 0xE0, ++ 0xE9, 0xB2, 0x81, 0x42, 0x1D, 0xDA, 0x53, 0xF8, 0x21, 0x40, 0x94, 0x42, ++ 0x01, 0xF1, 0x01, 0x05, 0x03, 0xEB, 0x81, 0x06, 0xF4, 0xDC, 0xC0, 0xB2, ++ 0x88, 0x42, 0x0F, 0xD9, 0x44, 0x1E, 0x61, 0x1A, 0x1C, 0x1F, 0xC9, 0xB2, ++ 0x04, 0xEB, 0x80, 0x04, 0xA4, 0xEB, 0x81, 0x04, 0x03, 0xEB, 0x80, 0x03, ++ 0x53, 0xF8, 0x04, 0x1C, 0x43, 0xF8, 0x04, 0x19, 0xA3, 0x42, 0xF9, 0xD1, ++ 0x32, 0x60, 0x70, 0xBC, 0x70, 0x47, 0x70, 0xBC, 0x43, 0xF8, 0x20, 0x20, ++ 0x70, 0x47, 0x00, 0xBF, 0x2D, 0xE9, 0xF0, 0x4F, 0x00, 0xF1, 0xFF, 0x3C, ++ 0x85, 0xB0, 0xCC, 0xF3, 0x47, 0x0C, 0x4F, 0xF0, 0x80, 0x34, 0x48, 0xF2, ++ 0x80, 0x03, 0x01, 0x28, 0xCD, 0xE9, 0x01, 0xC4, 0xAD, 0xF8, 0x0C, 0x30, ++ 0x40, 0xF2, 0x83, 0x80, 0x80, 0x24, 0xA2, 0x46, 0x16, 0x46, 0x00, 0x25, ++ 0x01, 0x23, 0x43, 0xF2, 0xB0, 0x69, 0x8E, 0x46, 0x00, 0x92, 0x18, 0xE0, ++ 0x80, 0x2C, 0x04, 0xBF, 0x04, 0xAA, 0x02, 0xEB, 0x45, 0x01, 0x4F, 0xEA, ++ 0x45, 0x07, 0x04, 0xAA, 0x17, 0x44, 0x04, 0xBF, 0x03, 0xF1, 0xFF, 0x34, ++ 0x01, 0xF8, 0x08, 0x4C, 0x07, 0xF8, 0x07, 0x3C, 0x01, 0x33, 0xDB, 0xB2, ++ 0x98, 0x42, 0x22, 0xD0, 0x04, 0xAA, 0x02, 0xEB, 0x45, 0x01, 0x11, 0xF8, ++ 0x08, 0x4C, 0x37, 0x68, 0x56, 0xF8, 0x04, 0x1F, 0x7F, 0x1A, 0x77, 0x45, ++ 0xE0, 0xDD, 0x80, 0x2C, 0xEE, 0xD0, 0x00, 0x9A, 0x52, 0xF8, 0x24, 0x10, ++ 0x49, 0x45, 0x4F, 0xEA, 0x45, 0x07, 0x04, 0xAA, 0x55, 0xDD, 0x02, 0xEB, ++ 0x45, 0x01, 0x11, 0xF8, 0x07, 0x8C, 0x61, 0x46, 0x0C, 0x44, 0xA0, 0x45, ++ 0x61, 0xDB, 0x01, 0x33, 0xDB, 0xB2, 0x01, 0x35, 0x98, 0x42, 0xED, 0xB2, ++ 0xDC, 0xD1, 0x02, 0x2D, 0x00, 0x9A, 0x68, 0xD9, 0x9D, 0xF8, 0x08, 0x10, ++ 0x80, 0x29, 0x3A, 0xD0, 0x9D, 0xF8, 0x09, 0x30, 0x52, 0xF8, 0x21, 0x40, ++ 0x52, 0xF8, 0x23, 0x50, 0x58, 0x1C, 0x40, 0x1A, 0x64, 0x1B, 0xC0, 0xB2, ++ 0x02, 0xAD, 0x94, 0xFB, 0xF0, 0xF4, 0x01, 0x27, 0xA4, 0xB2, 0x00, 0x26, ++ 0x95, 0xF8, 0x02, 0xE0, 0xBE, 0xF1, 0x80, 0x0F, 0x5F, 0xFA, 0x87, 0xFC, ++ 0x16, 0xD0, 0x95, 0xF8, 0x03, 0x80, 0x52, 0xF8, 0x2E, 0x30, 0x08, 0xF1, ++ 0x01, 0x01, 0xA1, 0xEB, 0x0E, 0x01, 0xC9, 0xB2, 0x52, 0xF8, 0x28, 0xE0, ++ 0x81, 0x42, 0xA3, 0xEB, 0x0E, 0x03, 0x93, 0xFB, 0xF1, 0xF3, 0x9B, 0xB2, ++ 0x32, 0xD8, 0x61, 0xD0, 0x02, 0x2F, 0x05, 0xF1, 0x02, 0x05, 0x34, 0xD1, ++ 0x04, 0xAB, 0x03, 0xEB, 0x46, 0x06, 0x16, 0xF8, 0x08, 0x1C, 0x16, 0xF8, ++ 0x07, 0x3C, 0x5B, 0x1A, 0x01, 0x33, 0x01, 0xEB, 0x63, 0x03, 0xDB, 0xB2, ++ 0x01, 0x93, 0x01, 0x9B, 0x52, 0xF8, 0x23, 0x00, 0x05, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x8F, 0x02, 0xEB, 0x45, 0x08, 0x00, 0x9A, 0x18, 0xF8, 0x07, 0x8C, ++ 0x52, 0xF8, 0x28, 0xB0, 0x25, 0x4A, 0x93, 0x45, 0xA3, 0xDB, 0xB1, 0xF5, ++ 0x7A, 0x7F, 0x02, 0xDA, 0x23, 0x4A, 0x93, 0x45, 0x9D, 0xDA, 0x02, 0x21, ++ 0x0C, 0x44, 0xA0, 0x45, 0x9D, 0xDA, 0x04, 0xAA, 0x17, 0x44, 0x07, 0xF8, ++ 0x08, 0xAC, 0x07, 0xF8, 0x07, 0xAC, 0x75, 0xE7, 0x02, 0x2F, 0x1C, 0x46, ++ 0x08, 0x46, 0x66, 0x46, 0x05, 0xF1, 0x02, 0x05, 0xCA, 0xD0, 0x02, 0x27, ++ 0xAA, 0xE7, 0x04, 0xAB, 0x03, 0xEB, 0x45, 0x01, 0x6D, 0x00, 0x11, 0xF8, ++ 0x08, 0x3C, 0x80, 0x2B, 0x8E, 0xD0, 0x52, 0xF8, 0x23, 0x00, 0x11, 0xF8, ++ 0x07, 0x1C, 0x43, 0xF2, 0xB0, 0x64, 0xA0, 0x42, 0x0A, 0xDC, 0x0F, 0x4E, ++ 0x52, 0xF8, 0x21, 0x40, 0xB4, 0x42, 0x05, 0xDB, 0xB0, 0xF5, 0x7A, 0x7F, ++ 0x13, 0xDA, 0x14, 0xF5, 0x7A, 0x7F, 0x10, 0xDD, 0x9C, 0x44, 0x61, 0x45, ++ 0xBF, 0xF6, 0x78, 0xAF, 0x04, 0xAB, 0x1D, 0x44, 0x80, 0x23, 0x05, 0xF8, ++ 0x08, 0x3C, 0x05, 0xF8, 0x07, 0x3C, 0x6F, 0xE7, 0xA3, 0x42, 0x9B, 0xD2, ++ 0x1C, 0x46, 0x66, 0x46, 0x98, 0xE7, 0x4F, 0xF0, 0x02, 0x0C, 0xEB, 0xE7, ++ 0x50, 0xC9, 0xFF, 0xFF, 0x19, 0xFC, 0xFF, 0xFF, 0xD0, 0xED, 0x00, 0x7A, ++ 0x90, 0xED, 0x01, 0x7A, 0xF4, 0xEE, 0xC7, 0x7A, 0xF1, 0xEE, 0x10, 0xFA, ++ 0x08, 0xD5, 0x91, 0xED, 0x00, 0x6A, 0xD1, 0xED, 0x01, 0x6A, 0xB4, 0xEE, ++ 0xE6, 0x6A, 0xF1, 0xEE, 0x10, 0xFA, 0x5E, 0xDA, 0xF4, 0xEE, 0xC7, 0x7A, ++ 0xF1, 0xEE, 0x10, 0xFA, 0x08, 0xDD, 0x91, 0xED, 0x00, 0x6A, 0xD1, 0xED, ++ 0x01, 0x6A, 0xB4, 0xEE, 0xE6, 0x6A, 0xF1, 0xEE, 0x10, 0xFA, 0x50, 0xD9, ++ 0xD0, 0xED, 0x02, 0x6A, 0xF4, 0xEE, 0xE6, 0x7A, 0xF1, 0xEE, 0x10, 0xFA, ++ 0x08, 0xD5, 0xD1, 0xED, 0x00, 0x5A, 0x91, 0xED, 0x02, 0x6A, 0xF4, 0xEE, ++ 0xC6, 0x5A, 0xF1, 0xEE, 0x10, 0xFA, 0x40, 0xDA, 0xF4, 0xEE, 0xE6, 0x7A, ++ 0xF1, 0xEE, 0x10, 0xFA, 0x32, 0xDC, 0xB4, 0xEE, 0xE6, 0x7A, 0xF1, 0xEE, ++ 0x10, 0xFA, 0x08, 0xD5, 0x91, 0xED, 0x01, 0x6A, 0xD1, 0xED, 0x02, 0x7A, ++ 0xB4, 0xEE, 0xE7, 0x6A, 0xF1, 0xEE, 0x10, 0xFA, 0x2D, 0xDA, 0xB4, 0xEE, ++ 0xE6, 0x7A, 0xF1, 0xEE, 0x10, 0xFA, 0x08, 0xDD, 0x91, 0xED, 0x01, 0x7A, ++ 0xD1, 0xED, 0x02, 0x7A, 0xB4, 0xEE, 0xE7, 0x7A, 0xF1, 0xEE, 0x10, 0xFA, ++ 0x1F, 0xD9, 0xD1, 0xED, 0x00, 0x7A, 0xF5, 0xEE, 0xC0, 0x7A, 0xF1, 0xEE, ++ 0x10, 0xFA, 0x1A, 0xDD, 0x91, 0xED, 0x01, 0x7A, 0xB5, 0xEE, 0xC0, 0x7A, ++ 0xF1, 0xEE, 0x10, 0xFA, 0x13, 0xDD, 0x91, 0xED, 0x02, 0x7A, 0xB5, 0xEE, ++ 0xC0, 0x7A, 0xF1, 0xEE, 0x10, 0xFA, 0x0C, 0xDD, 0x01, 0x20, 0x70, 0x47, ++ 0x91, 0xED, 0x00, 0x6A, 0xD1, 0xED, 0x02, 0x7A, 0xB4, 0xEE, 0xE7, 0x6A, ++ 0xF1, 0xEE, 0x10, 0xFA, 0xC3, 0xD8, 0x02, 0x20, 0x70, 0x47, 0xF5, 0xEE, ++ 0xC0, 0x7A, 0xF1, 0xEE, 0x10, 0xFA, 0x01, 0xD4, 0x00, 0x20, 0x70, 0x47, ++ 0xD1, 0xED, 0x01, 0x7A, 0xF5, 0xEE, 0xC0, 0x7A, 0xF1, 0xEE, 0x10, 0xFA, ++ 0xF6, 0xD5, 0xD1, 0xED, 0x02, 0x7A, 0xF5, 0xEE, 0xC0, 0x7A, 0xF1, 0xEE, ++ 0x10, 0xFA, 0x4C, 0xBF, 0x01, 0x20, 0x00, 0x20, 0x70, 0x47, 0x00, 0xBF, ++ 0x00, 0x28, 0x00, 0xF0, 0xC7, 0x80, 0x2D, 0xE9, 0xF0, 0x47, 0x00, 0x22, ++ 0xA1, 0xF1, 0x02, 0x08, 0x82, 0xB0, 0x44, 0x46, 0x17, 0x46, 0x94, 0x46, ++ 0x10, 0x46, 0x4F, 0xF0, 0x01, 0x0E, 0x02, 0xE0, 0x05, 0x2E, 0x11, 0xD0, ++ 0x01, 0x32, 0x34, 0xF9, 0x02, 0x5F, 0x0E, 0xFA, 0x02, 0xF3, 0x00, 0x2D, ++ 0xD6, 0xB2, 0x43, 0xEA, 0x00, 0x03, 0xF3, 0xDA, 0x01, 0x2A, 0xD8, 0xB2, ++ 0x40, 0xF2, 0x83, 0x80, 0x01, 0x37, 0x05, 0x2E, 0xFF, 0xB2, 0xED, 0xD1, ++ 0x04, 0x2F, 0x00, 0xF0, 0x81, 0x80, 0x02, 0x2F, 0x00, 0xF2, 0x81, 0x80, ++ 0xBC, 0xF1, 0x00, 0x0F, 0x0B, 0xD1, 0xB1, 0xF9, 0x02, 0x30, 0xB1, 0xF9, ++ 0x00, 0x20, 0x03, 0xF1, 0x09, 0x04, 0x94, 0x42, 0x02, 0xDB, 0x09, 0x3B, ++ 0x9A, 0x42, 0x00, 0xDA, 0x4A, 0x80, 0xB1, 0xF9, 0x04, 0x20, 0xB1, 0xF9, ++ 0x06, 0x30, 0x03, 0x24, 0x40, 0xF2, 0x04, 0x55, 0x9A, 0x42, 0x8D, 0xF8, ++ 0x01, 0x40, 0xAD, 0xF8, 0x02, 0x50, 0xC0, 0xF2, 0x8E, 0x80, 0xB1, 0xF9, ++ 0x08, 0x20, 0xB1, 0xF9, 0x0A, 0x30, 0x9A, 0x42, 0x25, 0x46, 0x4F, 0xF0, ++ 0x06, 0x09, 0x4F, 0xF0, 0x04, 0x07, 0x4F, 0xF0, 0x02, 0x04, 0x80, 0xF2, ++ 0x8E, 0x80, 0x40, 0xF2, 0x05, 0x43, 0xAD, 0xF8, 0x02, 0x30, 0x4F, 0xF0, ++ 0x05, 0x0E, 0x4F, 0xF0, 0x08, 0x08, 0x04, 0x26, 0x0A, 0x22, 0xCB, 0x5F, ++ 0x8F, 0x5E, 0xBB, 0x42, 0x07, 0xDA, 0xBA, 0x46, 0x72, 0x46, 0x8D, 0xF8, ++ 0x02, 0x40, 0x1F, 0x46, 0xA6, 0x46, 0x53, 0x46, 0x14, 0x46, 0x31, 0xF9, ++ 0x09, 0x20, 0x31, 0xF9, 0x08, 0x80, 0x42, 0x45, 0x05, 0xDA, 0x8D, 0xF8, ++ 0x03, 0x50, 0x8D, 0xF8, 0x01, 0x60, 0x42, 0x46, 0x35, 0x46, 0x97, 0x42, ++ 0x05, 0xDD, 0x8D, 0xF8, 0x02, 0x50, 0x8D, 0xF8, 0x01, 0xE0, 0x3A, 0x46, ++ 0x75, 0x46, 0x9D, 0xF8, 0x02, 0xE0, 0x9D, 0xF8, 0x01, 0x60, 0x31, 0xF9, ++ 0x1E, 0x70, 0x31, 0xF9, 0x16, 0x80, 0x07, 0x32, 0xFE, 0x1D, 0x93, 0x42, ++ 0xD4, 0xBF, 0x04, 0x23, 0x00, 0x23, 0xB0, 0x45, 0x9D, 0xF8, 0x03, 0x60, ++ 0x31, 0xF9, 0x16, 0x20, 0x02, 0xF1, 0x07, 0x02, 0xD8, 0xBF, 0x43, 0xF0, ++ 0x02, 0x03, 0xBA, 0x42, 0xA8, 0xBF, 0x43, 0xF0, 0x01, 0x03, 0x06, 0x2B, ++ 0x4E, 0xD8, 0xDF, 0xE8, 0x03, 0xF0, 0x4A, 0xA9, 0xA1, 0x9B, 0x93, 0x4A, ++ 0xB1, 0x00, 0x0C, 0xF1, 0x01, 0x0C, 0x5F, 0xFA, 0x8C, 0xFC, 0x69, 0xE7, ++ 0xBC, 0xF1, 0x02, 0x0F, 0x78, 0xD0, 0x00, 0x23, 0x1C, 0x46, 0x1A, 0x46, ++ 0x40, 0xFA, 0x03, 0xF5, 0xEF, 0x07, 0x05, 0xD4, 0x31, 0xF8, 0x13, 0x50, ++ 0x01, 0x34, 0x2A, 0x44, 0xE4, 0xB2, 0x12, 0xB2, 0x01, 0x33, 0x06, 0x2B, ++ 0xF2, 0xD1, 0x92, 0xFB, 0xF4, 0xF2, 0x00, 0x23, 0x40, 0xFA, 0x03, 0xF4, ++ 0xE6, 0x07, 0x48, 0xBF, 0x21, 0xF8, 0x13, 0x20, 0x01, 0x33, 0x06, 0x2B, ++ 0xF6, 0xD1, 0x02, 0xB0, 0xBD, 0xE8, 0xF0, 0x87, 0x8B, 0x1E, 0x80, 0x20, ++ 0x0A, 0x31, 0x33, 0xF9, 0x02, 0x2F, 0x00, 0x2A, 0xB8, 0xBF, 0x18, 0x80, ++ 0x99, 0x42, 0xF8, 0xD1, 0x70, 0x47, 0xB1, 0xF9, 0x08, 0x20, 0xB1, 0xF9, ++ 0x0A, 0x30, 0x02, 0x25, 0x9A, 0x42, 0x8D, 0xF8, 0x01, 0x50, 0x4F, 0xF0, ++ 0x04, 0x09, 0x4F, 0xF0, 0x06, 0x07, 0xFF, 0xF6, 0x72, 0xAF, 0x4F, 0xF0, ++ 0x0A, 0x08, 0x08, 0x22, 0x4F, 0xF0, 0x04, 0x0E, 0x75, 0xE7, 0xBC, 0xF1, ++ 0x00, 0x0F, 0x69, 0xD0, 0x00, 0x24, 0x22, 0x46, 0x02, 0x23, 0x40, 0xFA, ++ 0x03, 0xF5, 0xED, 0x07, 0x05, 0xD4, 0x31, 0xF8, 0x13, 0x50, 0x01, 0x34, ++ 0x2A, 0x44, 0xE4, 0xB2, 0x12, 0xB2, 0x01, 0x33, 0x06, 0x2B, 0xF2, 0xD1, ++ 0x64, 0xB9, 0xC3, 0x07, 0x03, 0xD4, 0x0B, 0x88, 0x1A, 0x44, 0x12, 0xB2, ++ 0x01, 0x24, 0x87, 0x07, 0x04, 0xD4, 0x4B, 0x88, 0x01, 0x34, 0x13, 0x44, ++ 0xE4, 0xB2, 0x1A, 0xB2, 0x00, 0x23, 0x92, 0xFB, 0xF4, 0xF4, 0x00, 0xE0, ++ 0x01, 0x33, 0x40, 0xFA, 0x03, 0xF2, 0xD6, 0x07, 0xDD, 0xB2, 0x03, 0xD5, ++ 0x01, 0x2B, 0x14, 0xD9, 0x21, 0xF8, 0x13, 0x40, 0x05, 0x2D, 0xF3, 0xD1, ++ 0xBC, 0xF1, 0x01, 0x0F, 0xA9, 0xD1, 0xC2, 0x07, 0x0F, 0xD4, 0x83, 0x07, ++ 0xA5, 0xD5, 0x0B, 0x88, 0x4B, 0x80, 0xA2, 0xE7, 0x0A, 0x31, 0x80, 0x23, ++ 0x28, 0xF8, 0x02, 0x3F, 0x88, 0x45, 0xFB, 0xD1, 0x9B, 0xE7, 0xBC, 0xF1, ++ 0x02, 0x0F, 0xDF, 0xD1, 0xE6, 0xE7, 0x4B, 0x88, 0x0B, 0x80, 0x94, 0xE7, ++ 0x01, 0x22, 0x02, 0xFA, 0x0E, 0xF3, 0xB2, 0x40, 0x13, 0x43, 0x18, 0x43, ++ 0xC0, 0xB2, 0xB1, 0xE7, 0x01, 0x23, 0x03, 0xFA, 0x04, 0xF4, 0x20, 0x43, ++ 0xC0, 0xB2, 0xAB, 0xE7, 0x01, 0x23, 0x03, 0xFA, 0x06, 0xF6, 0x30, 0x43, ++ 0xA3, 0x40, 0x18, 0x43, 0xC0, 0xB2, 0xA3, 0xE7, 0x01, 0x23, 0x03, 0xFA, ++ 0x04, 0xF4, 0x20, 0x43, 0xAB, 0x40, 0x18, 0x43, 0xC0, 0xB2, 0x9B, 0xE7, ++ 0x01, 0x23, 0x03, 0xFA, 0x06, 0xF6, 0x30, 0x43, 0xC0, 0xB2, 0x95, 0xE7, ++ 0x40, 0xF0, 0x3C, 0x00, 0x92, 0xE7, 0x00, 0xBF, 0xF0, 0xB5, 0xD1, 0xED, ++ 0x01, 0x6A, 0x91, 0xED, 0x00, 0x7A, 0x2D, 0xED, 0x08, 0x8B, 0xF4, 0xEE, ++ 0xC7, 0x6A, 0xF1, 0xEE, 0x10, 0xFA, 0x83, 0xB0, 0x0C, 0x46, 0x07, 0x46, ++ 0x15, 0x46, 0x1E, 0x46, 0x05, 0xDC, 0xF0, 0xEE, 0x66, 0x7A, 0xF0, 0xEE, ++ 0x47, 0x6A, 0xB0, 0xEE, 0x67, 0x7A, 0xD4, 0xED, 0x02, 0x7A, 0xF4, 0xEE, ++ 0xE6, 0x7A, 0xF1, 0xEE, 0x10, 0xFA, 0x08, 0xDC, 0xF4, 0xEE, 0xC7, 0x7A, ++ 0xF1, 0xEE, 0x10, 0xFA, 0x48, 0xBF, 0xB0, 0xEE, 0x67, 0x7A, 0xF0, 0xEE, ++ 0x66, 0x7A, 0x77, 0xEE, 0xC7, 0x7A, 0xB0, 0xEE, 0x08, 0xBA, 0xFC, 0xEE, ++ 0xE7, 0x7A, 0x17, 0xEE, 0x90, 0x3A, 0xB3, 0x70, 0xD4, 0xED, 0x00, 0x8A, ++ 0x94, 0xED, 0x01, 0xAA, 0xD4, 0xED, 0x02, 0x9A, 0x6A, 0xEE, 0x0A, 0x7A, ++ 0x28, 0xEE, 0xA8, 0x6A, 0x69, 0xEE, 0xA9, 0xAA, 0x36, 0xEE, 0x27, 0x6A, ++ 0x38, 0xEE, 0x8A, 0x7A, 0x76, 0xEE, 0x2A, 0xAA, 0x37, 0xEE, 0x29, 0x9A, ++ 0x2A, 0xEE, 0x8B, 0xBA, 0x69, 0xEE, 0x09, 0x7A, 0x3B, 0xEE, 0x67, 0xBA, ++ 0xB5, 0xEE, 0xC0, 0xBA, 0xF1, 0xEE, 0x10, 0xFA, 0x40, 0xF3, 0xD0, 0x80, ++ 0x1B, 0xEE, 0x10, 0x0A, 0x33, 0xF0, 0x44, 0xF8, 0x6F, 0xA3, 0xD3, 0xE9, ++ 0x00, 0x23, 0x33, 0xF0, 0x09, 0xFB, 0x80, 0xB1, 0x9F, 0xED, 0x6E, 0xBA, ++ 0x33, 0x78, 0x6E, 0x49, 0x43, 0xF0, 0x04, 0x03, 0x33, 0x70, 0x4F, 0xF4, ++ 0x00, 0x50, 0x21, 0xF0, 0x73, 0xF8, 0xD4, 0xED, 0x00, 0x8A, 0x94, 0xED, ++ 0x01, 0xAA, 0xD4, 0xED, 0x02, 0x9A, 0x95, 0xED, 0x00, 0x4A, 0xD5, 0xED, ++ 0x01, 0x4A, 0x95, 0xED, 0x02, 0x5A, 0xF7, 0xEE, 0x00, 0x7A, 0x87, 0xEE, ++ 0x8B, 0x6A, 0x0D, 0x2F, 0xF0, 0xEE, 0x08, 0x6A, 0x26, 0xEE, 0x49, 0x7A, ++ 0x66, 0xEE, 0x26, 0x6A, 0x2A, 0xEE, 0x86, 0x6A, 0x66, 0xEE, 0xA8, 0x7A, ++ 0x66, 0xEE, 0x8A, 0x5A, 0x67, 0xEE, 0x28, 0x8A, 0x27, 0xEE, 0x0A, 0xAA, ++ 0x77, 0xEE, 0x87, 0x7A, 0x26, 0xEE, 0xA9, 0x8A, 0x78, 0xEE, 0x86, 0x8A, ++ 0x67, 0xEE, 0x29, 0x9A, 0x75, 0xEE, 0x87, 0x5A, 0x3A, 0xEE, 0x06, 0xAA, ++ 0x38, 0xEE, 0x07, 0x8A, 0x67, 0xEE, 0x84, 0x7A, 0x68, 0xEE, 0x84, 0x8A, ++ 0x79, 0xEE, 0x86, 0x9A, 0x25, 0xEE, 0xA4, 0x7A, 0x2A, 0xEE, 0x24, 0xAA, ++ 0x77, 0xEE, 0x87, 0x7A, 0x78, 0xEE, 0x8A, 0x8A, 0x28, 0xEE, 0x05, 0x8A, ++ 0x69, 0xEE, 0x85, 0x9A, 0x37, 0xEE, 0x88, 0x8A, 0x78, 0xEE, 0xA9, 0x8A, ++ 0x2E, 0xD9, 0xF3, 0xEE, 0x04, 0x7A, 0xB4, 0xEE, 0xE7, 0x8A, 0xF1, 0xEE, ++ 0x10, 0xFA, 0x27, 0xD5, 0x33, 0x78, 0x44, 0x49, 0x43, 0xF0, 0x08, 0x03, ++ 0x33, 0x70, 0x4F, 0xF4, 0x00, 0x50, 0x21, 0xF0, 0x1D, 0xF8, 0xB7, 0xEE, ++ 0x00, 0x8A, 0xF0, 0xEE, 0x00, 0x6A, 0xB1, 0xEE, 0x68, 0x7A, 0xC7, 0xEE, ++ 0x08, 0x7A, 0x9F, 0xED, 0x3D, 0x7A, 0xF4, 0xEE, 0xC7, 0x7A, 0xF1, 0xEE, ++ 0x10, 0xFA, 0x21, 0xDC, 0xF5, 0xEE, 0xC0, 0x7A, 0xF1, 0xEE, 0x10, 0xFA, ++ 0x4E, 0xD4, 0xB6, 0xEE, 0x00, 0x7A, 0x77, 0xEE, 0x87, 0x7A, 0xFC, 0xEE, ++ 0xE7, 0x7A, 0xCD, 0xED, 0x01, 0x7A, 0x9D, 0xF8, 0x04, 0x30, 0x12, 0xE0, ++ 0x18, 0xEE, 0x10, 0x0A, 0x32, 0xF0, 0xBA, 0xFF, 0x2A, 0xA3, 0xD3, 0xE9, ++ 0x00, 0x23, 0x33, 0xF0, 0x7F, 0xFA, 0x00, 0x28, 0xCC, 0xD1, 0x68, 0xEE, ++ 0x08, 0x6A, 0xF7, 0xEE, 0x00, 0x7A, 0x76, 0xEE, 0xA7, 0x6A, 0xD2, 0xE7, ++ 0xFF, 0x23, 0x73, 0x70, 0xD4, 0xED, 0x00, 0x7A, 0x94, 0xED, 0x01, 0x7A, ++ 0xD4, 0xED, 0x02, 0x4A, 0x95, 0xED, 0x00, 0x5A, 0xD5, 0xED, 0x01, 0x5A, ++ 0x95, 0xED, 0x02, 0x6A, 0x68, 0xEE, 0x27, 0x7A, 0x28, 0xEE, 0x07, 0x7A, ++ 0x77, 0xEE, 0xA8, 0x7A, 0x37, 0xEE, 0x28, 0x7A, 0x28, 0xEE, 0x24, 0x8A, ++ 0x77, 0xEE, 0xC5, 0x7A, 0x37, 0xEE, 0x65, 0x7A, 0x38, 0xEE, 0x28, 0x8A, ++ 0x27, 0xEE, 0x07, 0x7A, 0x38, 0xEE, 0x46, 0x8A, 0x67, 0xEE, 0xA7, 0x7A, ++ 0x28, 0xEE, 0x08, 0x8A, 0x77, 0xEE, 0x87, 0x7A, 0x37, 0xEE, 0x88, 0x8A, ++ 0xC8, 0xEE, 0x26, 0x7A, 0xC6, 0xED, 0x01, 0x7A, 0x03, 0xB0, 0xBD, 0xEC, ++ 0x08, 0x8B, 0xF0, 0xBD, 0x00, 0x23, 0xCC, 0xE7, 0xF1, 0xEE, 0x4B, 0x7A, ++ 0x17, 0xEE, 0x90, 0x0A, 0x32, 0xF0, 0x72, 0xFF, 0x06, 0xA3, 0xD3, 0xE9, ++ 0x00, 0x23, 0x33, 0xF0, 0x37, 0xFA, 0x00, 0x28, 0x3F, 0xF4, 0x3D, 0xAF, ++ 0x9F, 0xED, 0x08, 0xBA, 0x2A, 0xE7, 0x00, 0xBF, 0xAF, 0xF3, 0x00, 0x80, ++ 0xF1, 0x68, 0xE3, 0x88, 0xB5, 0xF8, 0xE4, 0x3E, 0x00, 0x50, 0xC3, 0x47, ++ 0xD4, 0x79, 0x15, 0x00, 0x00, 0x7A, 0x15, 0x00, 0x00, 0x00, 0x7F, 0x43, ++ 0xAC, 0xC5, 0x27, 0xB7, 0x2D, 0xE9, 0xF0, 0x47, 0x09, 0x29, 0x8E, 0xB0, ++ 0x88, 0x46, 0x1D, 0x46, 0x70, 0xD9, 0x03, 0x28, 0x6E, 0xD0, 0x4F, 0xF0, ++ 0x86, 0x4A, 0x57, 0x1E, 0x00, 0x26, 0x0D, 0xF1, 0x18, 0x09, 0x00, 0x22, ++ 0x10, 0x46, 0xF1, 0xB2, 0xD3, 0xB2, 0x8B, 0x42, 0x19, 0xD0, 0x00, 0x2B, ++ 0x00, 0xF0, 0xAF, 0x80, 0xBB, 0x5C, 0x07, 0xEE, 0x90, 0x3A, 0x0E, 0xAB, ++ 0xF8, 0xEE, 0x67, 0x7A, 0x03, 0xEB, 0x80, 0x03, 0x43, 0xED, 0x0E, 0x7A, ++ 0x84, 0x00, 0x55, 0xF8, 0x22, 0x30, 0x07, 0xEE, 0x90, 0x3A, 0x0E, 0xAB, ++ 0xF8, 0xEE, 0xE7, 0x7A, 0x1C, 0x44, 0x01, 0x30, 0xC0, 0xB2, 0x44, 0xED, ++ 0x0B, 0x7A, 0x01, 0x32, 0x04, 0x2A, 0xDF, 0xD1, 0x00, 0x23, 0x03, 0xA9, ++ 0x68, 0x46, 0x09, 0xF8, 0x36, 0x30, 0xFF, 0xF7, 0x9F, 0xFC, 0x10, 0xF0, ++ 0x0E, 0x0F, 0x09, 0xF8, 0x36, 0x00, 0x00, 0xF0, 0x95, 0x80, 0x01, 0x36, ++ 0x04, 0x2E, 0xCC, 0xD1, 0x07, 0xAD, 0x00, 0x24, 0x2A, 0x46, 0x23, 0x46, ++ 0x80, 0x21, 0x12, 0xF8, 0x04, 0x0C, 0x00, 0x28, 0x40, 0xF0, 0x82, 0x80, ++ 0x0E, 0xA8, 0x80, 0x29, 0x00, 0xEB, 0xC1, 0x00, 0x00, 0xF0, 0x8A, 0x80, ++ 0x92, 0xED, 0x00, 0x7A, 0x50, 0xED, 0x07, 0x7A, 0xB4, 0xEE, 0x67, 0x7A, ++ 0xF1, 0xEE, 0x10, 0xFA, 0x98, 0xBF, 0x19, 0x46, 0x01, 0x33, 0xDB, 0xB2, ++ 0x04, 0x2B, 0x02, 0xF1, 0x08, 0x02, 0xE4, 0xD1, 0x00, 0x2C, 0x00, 0xF0, ++ 0x84, 0x80, 0x80, 0x29, 0x76, 0xD0, 0x0E, 0xAB, 0x03, 0xEB, 0xC1, 0x00, ++ 0x42, 0x46, 0x10, 0xF8, 0x1F, 0x4C, 0x10, 0xF8, 0x20, 0x3C, 0x55, 0x49, ++ 0x4F, 0xF4, 0x00, 0x50, 0x20, 0xF0, 0x22, 0xFF, 0x20, 0x46, 0x0E, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x87, 0x13, 0x78, 0xD5, 0xED, 0x00, 0x6A, 0x95, 0xED, ++ 0x01, 0x7A, 0xD5, 0xED, 0x02, 0x7A, 0x05, 0xEE, 0x90, 0x3A, 0x53, 0x78, ++ 0x06, 0xEE, 0x10, 0x3A, 0xF8, 0xEE, 0x65, 0x5A, 0xB8, 0xEE, 0x46, 0x6A, ++ 0xF8, 0xEE, 0xE6, 0x6A, 0xB8, 0xEE, 0xC7, 0x7A, 0xF8, 0xEE, 0xE7, 0x7A, ++ 0x4F, 0xF0, 0x86, 0x42, 0x00, 0x23, 0xB8, 0xF1, 0x09, 0x0F, 0xCD, 0xED, ++ 0x01, 0x5A, 0x8D, 0xED, 0x02, 0x6A, 0xCD, 0xED, 0x03, 0x6A, 0x8D, 0xED, ++ 0x04, 0x7A, 0xCD, 0xED, 0x05, 0x7A, 0x00, 0x92, 0x8D, 0xF8, 0x18, 0x30, ++ 0x16, 0xD8, 0x06, 0xAB, 0x03, 0xAA, 0x69, 0x46, 0x40, 0x46, 0xFF, 0xF7, ++ 0x17, 0xFE, 0x9D, 0xF8, 0x18, 0x30, 0x13, 0xF0, 0x0E, 0x0F, 0x4C, 0xD1, ++ 0x9D, 0xF8, 0x19, 0x40, 0x35, 0x49, 0x42, 0x46, 0x4F, 0xF4, 0x00, 0x50, ++ 0x20, 0xF0, 0xE2, 0xFE, 0x20, 0x46, 0x0E, 0xB0, 0xBD, 0xE8, 0xF0, 0x87, ++ 0x03, 0xA9, 0x68, 0x46, 0xFF, 0xF7, 0x1C, 0xFC, 0x10, 0xF0, 0x0E, 0x0F, ++ 0x8D, 0xF8, 0x18, 0x00, 0x18, 0xBF, 0x03, 0x46, 0x49, 0xD0, 0xC8, 0xF1, ++ 0x09, 0x04, 0x64, 0x01, 0xE6, 0xE7, 0x0E, 0xAB, 0x03, 0xEB, 0x80, 0x03, ++ 0x84, 0x00, 0x43, 0xF8, 0x38, 0xAC, 0x54, 0xE7, 0x06, 0x07, 0x1B, 0xD4, ++ 0x01, 0x28, 0x08, 0xBF, 0x01, 0x24, 0x87, 0xE7, 0x09, 0xEB, 0xC6, 0x03, ++ 0x03, 0xAA, 0x69, 0x46, 0x40, 0x46, 0xFF, 0xF7, 0xE3, 0xFD, 0x62, 0xE7, ++ 0x19, 0x46, 0x7D, 0xE7, 0x00, 0x23, 0x15, 0xF8, 0x04, 0x2C, 0x01, 0x2A, ++ 0x17, 0xD0, 0x01, 0x33, 0xDB, 0xB2, 0x04, 0x2B, 0x05, 0xF1, 0x08, 0x05, ++ 0xF5, 0xD1, 0x80, 0x29, 0x7F, 0xF4, 0x7B, 0xAF, 0x17, 0x49, 0x42, 0x46, ++ 0x4F, 0xF4, 0x00, 0x50, 0x20, 0xF0, 0xA4, 0xFE, 0xC8, 0xF1, 0x09, 0x04, ++ 0x64, 0x01, 0x20, 0x46, 0x0E, 0xB0, 0xBD, 0xE8, 0xF0, 0x87, 0x80, 0x24, ++ 0xB2, 0xE7, 0x0E, 0xAA, 0x80, 0x29, 0x02, 0xEB, 0xC1, 0x02, 0x0A, 0xD0, ++ 0x95, 0xED, 0x00, 0x7A, 0x52, 0xED, 0x07, 0x7A, 0xB4, 0xEE, 0x67, 0x7A, ++ 0xF1, 0xEE, 0x10, 0xFA, 0x98, 0xBF, 0x19, 0x46, 0xD7, 0xE7, 0x19, 0x46, ++ 0xD5, 0xE7, 0x06, 0xAB, 0x03, 0xAA, 0x69, 0x46, 0x40, 0x46, 0xFF, 0xF7, ++ 0xAB, 0xFD, 0x9D, 0xF8, 0x18, 0x30, 0x13, 0xF0, 0x0E, 0x0F, 0x93, 0xD0, ++ 0xA9, 0xE7, 0x00, 0xBF, 0x14, 0x7A, 0x15, 0x00, 0x30, 0x7A, 0x15, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0x9A, 0x4A, 0xDF, 0xF8, 0x8C, 0x82, 0x13, 0x68, ++ 0x2D, 0xED, 0x08, 0x8B, 0x23, 0xF4, 0xFF, 0x43, 0x43, 0xF4, 0xCE, 0x35, ++ 0x8B, 0xB0, 0x43, 0xF4, 0x1D, 0x43, 0x0C, 0x46, 0x45, 0xF4, 0x80, 0x75, ++ 0x01, 0x46, 0x13, 0x60, 0x01, 0x20, 0x15, 0x60, 0x0D, 0x46, 0x03, 0x91, ++ 0xFC, 0xF7, 0xBA, 0xFD, 0xA2, 0x7B, 0x8F, 0x48, 0x02, 0xF0, 0x0F, 0x03, ++ 0x01, 0x68, 0x12, 0x09, 0x9B, 0x02, 0x43, 0xEA, 0x82, 0x13, 0x21, 0xF4, ++ 0x7F, 0x52, 0x13, 0x43, 0x03, 0x60, 0x02, 0x20, 0xFC, 0xF7, 0xAA, 0xFD, ++ 0xAB, 0x6B, 0xC3, 0xF3, 0x07, 0x22, 0x02, 0x92, 0x4F, 0xEA, 0x02, 0x4B, ++ 0xDA, 0xB2, 0x01, 0x92, 0x4F, 0xEA, 0x03, 0x6A, 0x4F, 0xF0, 0x00, 0x09, ++ 0xDD, 0xE9, 0x01, 0x32, 0xB9, 0xF1, 0x00, 0x0F, 0x18, 0xBF, 0x13, 0x46, ++ 0xA3, 0xF1, 0x40, 0x02, 0x12, 0xB2, 0x40, 0x33, 0x5F, 0xFA, 0x89, 0xF1, ++ 0x00, 0x2A, 0xAD, 0xF8, 0x14, 0x20, 0xAD, 0xF8, 0x16, 0x30, 0x00, 0x91, ++ 0xC0, 0xF2, 0xEA, 0x80, 0xFF, 0x2B, 0x01, 0xD9, 0x77, 0x4B, 0x05, 0x93, ++ 0x00, 0x25, 0x2E, 0x46, 0x05, 0x24, 0x48, 0xF2, 0x80, 0x07, 0xBD, 0xF9, ++ 0x14, 0x30, 0x08, 0xA9, 0x06, 0xA8, 0xB9, 0xF1, 0x00, 0x0F, 0x00, 0xF0, ++ 0xC3, 0x80, 0x4A, 0xEA, 0x03, 0x43, 0x3B, 0x43, 0xC8, 0xF8, 0x00, 0x30, ++ 0xFF, 0xF7, 0xAE, 0xF8, 0xBD, 0xF9, 0x16, 0x30, 0x4A, 0xEA, 0x03, 0x43, ++ 0x3B, 0x43, 0xC8, 0xF8, 0x00, 0x30, 0x09, 0xA9, 0x07, 0xA8, 0xFF, 0xF7, ++ 0xA3, 0xF8, 0xDD, 0xE9, 0x06, 0x02, 0xDD, 0xE9, 0x08, 0x13, 0x01, 0x3C, ++ 0x12, 0x1A, 0x5B, 0x1A, 0x14, 0xF0, 0xFF, 0x04, 0x16, 0x44, 0x1D, 0x44, ++ 0xD9, 0xD1, 0x62, 0x4B, 0x83, 0xFB, 0x06, 0x12, 0xF6, 0x17, 0xC6, 0xEB, ++ 0x62, 0x06, 0x07, 0xEE, 0x90, 0x6A, 0x83, 0xFB, 0x05, 0x13, 0xED, 0x17, ++ 0xC5, 0xEB, 0x63, 0x05, 0xB8, 0xEE, 0xE7, 0x7A, 0x07, 0xEE, 0x90, 0x5A, ++ 0xF8, 0xEE, 0xE7, 0x7A, 0xB9, 0xF1, 0x00, 0x0F, 0x00, 0xF0, 0x9D, 0x80, ++ 0x00, 0x9B, 0x01, 0x2B, 0x40, 0xF0, 0x9D, 0x80, 0xC7, 0xEE, 0x27, 0x9A, ++ 0x03, 0x9B, 0x54, 0x49, 0x54, 0x4F, 0x4F, 0xF4, 0x00, 0x50, 0x1E, 0x1F, ++ 0x03, 0xF1, 0x3C, 0x08, 0xB6, 0xEE, 0x00, 0xAA, 0x79, 0xEE, 0x88, 0x9A, ++ 0xF7, 0xEE, 0x00, 0xAA, 0x69, 0xEE, 0x8A, 0x9A, 0x8A, 0xEE, 0xA9, 0x8A, ++ 0xFD, 0xEE, 0xC8, 0x8A, 0x18, 0xEE, 0x90, 0x2A, 0x20, 0xF0, 0xCA, 0xFD, ++ 0xF8, 0xEE, 0xE8, 0x8A, 0xDF, 0xED, 0x49, 0x7A, 0x49, 0x49, 0x38, 0xEE, ++ 0x68, 0x8A, 0x4F, 0xF4, 0x00, 0x50, 0x28, 0xEE, 0x27, 0x8A, 0xFD, 0xEE, ++ 0xC8, 0x7A, 0x17, 0xEE, 0x90, 0x2A, 0x20, 0xF0, 0xB9, 0xFD, 0x69, 0xEE, ++ 0xA9, 0x7A, 0x39, 0xEE, 0xAA, 0xBA, 0x17, 0xEE, 0x90, 0x0A, 0x32, 0xF0, ++ 0x71, 0xFD, 0x40, 0x4B, 0x00, 0x22, 0x32, 0xF0, 0x0F, 0xFC, 0x7A, 0xEE, ++ 0xE9, 0xAA, 0x04, 0x46, 0x0D, 0x46, 0x56, 0xF8, 0x04, 0x3F, 0xC3, 0xF3, ++ 0x07, 0x22, 0x08, 0xEE, 0x90, 0x2A, 0xDB, 0xB2, 0x08, 0xEE, 0x10, 0x3A, ++ 0xF8, 0xEE, 0xE8, 0x8A, 0xB8, 0xEE, 0xC8, 0x8A, 0x68, 0xEE, 0xAA, 0x8A, ++ 0x28, 0xEE, 0x0B, 0x8A, 0x69, 0xEE, 0xA8, 0x7A, 0x78, 0xEE, 0x67, 0x7A, ++ 0x29, 0xEE, 0x88, 0x8A, 0x17, 0xEE, 0x90, 0x0A, 0x32, 0xF0, 0x4E, 0xFD, ++ 0x22, 0x46, 0x2B, 0x46, 0x32, 0xF0, 0xCC, 0xFE, 0x33, 0xF0, 0x5A, 0xF8, ++ 0x78, 0xEE, 0x28, 0x7A, 0x09, 0xEE, 0x10, 0x0A, 0x17, 0xEE, 0x90, 0x0A, ++ 0x32, 0xF0, 0x40, 0xFD, 0x22, 0x46, 0x2B, 0x46, 0x32, 0xF0, 0xBE, 0xFE, ++ 0x33, 0xF0, 0x4C, 0xF8, 0x07, 0xEE, 0x90, 0x0A, 0x77, 0xEE, 0x8A, 0x7A, ++ 0x39, 0xEE, 0x0A, 0x9A, 0xFD, 0xEE, 0xE7, 0x7A, 0xB0, 0x45, 0x17, 0xEE, ++ 0x90, 0x3A, 0xFD, 0xEE, 0xC9, 0x7A, 0x4F, 0xEA, 0x03, 0x23, 0xCD, 0xED, ++ 0x00, 0x7A, 0x9D, 0xF8, 0x00, 0x20, 0x03, 0xF4, 0x7F, 0x43, 0x43, 0xEA, ++ 0x02, 0x03, 0x43, 0xEA, 0x07, 0x03, 0x33, 0x60, 0xB5, 0xD1, 0x0B, 0xB0, ++ 0xBD, 0xEC, 0x08, 0x8B, 0xBD, 0xE8, 0xF0, 0x8F, 0x4B, 0xEA, 0x03, 0x63, ++ 0x3B, 0x43, 0xC8, 0xF8, 0x00, 0x30, 0x08, 0xA9, 0x06, 0xA8, 0xFE, 0xF7, ++ 0xE9, 0xFF, 0xBD, 0xF9, 0x16, 0x30, 0x4B, 0xEA, 0x03, 0x63, 0x3B, 0x43, ++ 0x39, 0xE7, 0xF1, 0xEE, 0x67, 0x7A, 0x87, 0xEE, 0x87, 0x8A, 0x09, 0xF1, ++ 0x01, 0x09, 0x01, 0xE7, 0x4F, 0xF4, 0x00, 0x03, 0x05, 0x93, 0x15, 0xE7, ++ 0x58, 0x40, 0x34, 0x40, 0x50, 0x40, 0x34, 0x40, 0x80, 0x00, 0xFF, 0x00, ++ 0x67, 0x66, 0x66, 0x66, 0x48, 0x7A, 0x15, 0x00, 0x00, 0x00, 0x80, 0x80, ++ 0x00, 0x00, 0x7A, 0x44, 0x58, 0x7A, 0x15, 0x00, 0x00, 0x00, 0xF0, 0x3F, ++ 0x4C, 0x40, 0x34, 0x40, 0x2D, 0xE9, 0xF0, 0x4F, 0xB5, 0x4C, 0x2D, 0xED, ++ 0x04, 0x8B, 0x27, 0x68, 0xAD, 0xF2, 0xE4, 0x7D, 0x06, 0x46, 0x0D, 0x46, ++ 0x14, 0x46, 0xB2, 0x49, 0x0A, 0x94, 0x3A, 0x46, 0x4F, 0xF4, 0x00, 0x50, ++ 0x9A, 0x46, 0xCD, 0xE9, 0x13, 0x56, 0x20, 0xF0, 0x17, 0xFD, 0xAE, 0x4B, ++ 0xAE, 0x49, 0x1A, 0x68, 0x4F, 0xF4, 0x00, 0x50, 0x20, 0xF0, 0x10, 0xFD, ++ 0xAC, 0x4B, 0xAD, 0x49, 0x1A, 0x68, 0x4F, 0xF4, 0x00, 0x50, 0x20, 0xF0, ++ 0x09, 0xFD, 0xAB, 0x4B, 0xAB, 0x49, 0x1A, 0x68, 0x4F, 0xF4, 0x00, 0x50, ++ 0x20, 0xF0, 0x02, 0xFD, 0xA9, 0x49, 0x4F, 0xF4, 0x00, 0x50, 0x20, 0xF0, ++ 0xFD, 0xFC, 0x16, 0xF0, 0x01, 0x03, 0x15, 0x93, 0x07, 0xD1, 0xA6, 0x4A, ++ 0x13, 0x68, 0x43, 0xF4, 0x00, 0x61, 0x43, 0xF4, 0xC0, 0x53, 0x11, 0x60, ++ 0x13, 0x60, 0x14, 0x9A, 0xC2, 0xF3, 0x40, 0x03, 0x03, 0x33, 0x12, 0xF0, ++ 0x0C, 0x0F, 0x09, 0xEE, 0x10, 0x3A, 0xC2, 0xF3, 0x81, 0x03, 0x00, 0xF0, ++ 0x9C, 0x82, 0x01, 0x2B, 0x14, 0xBF, 0x0A, 0x23, 0x05, 0x23, 0x08, 0xEE, ++ 0x90, 0x3A, 0x9A, 0x4A, 0x9A, 0x4E, 0x14, 0x68, 0xDF, 0xF8, 0x7C, 0xE2, ++ 0x99, 0x4B, 0x9A, 0x49, 0xDF, 0xF8, 0x78, 0x92, 0xDF, 0xF8, 0x78, 0xB2, ++ 0x98, 0x48, 0xDF, 0xF8, 0x78, 0xC2, 0x98, 0x4F, 0xDF, 0xF8, 0x74, 0x82, ++ 0x24, 0xF0, 0x04, 0x04, 0x14, 0x60, 0x35, 0x68, 0x00, 0x24, 0x25, 0xF4, ++ 0x70, 0x45, 0x35, 0x60, 0xCE, 0xF8, 0x00, 0x40, 0x1D, 0x68, 0x45, 0xF0, ++ 0x80, 0x05, 0x1D, 0x60, 0x0D, 0x68, 0x45, 0xF0, 0x00, 0x45, 0x0D, 0x60, ++ 0x15, 0x68, 0x01, 0x26, 0x45, 0xF0, 0x04, 0x05, 0x15, 0x60, 0xCB, 0xF8, ++ 0x00, 0x60, 0xC9, 0xF8, 0x00, 0x40, 0x15, 0x68, 0x25, 0xF0, 0x04, 0x05, ++ 0x15, 0x60, 0x0D, 0x68, 0x25, 0xF0, 0x00, 0x45, 0x0D, 0x60, 0x1D, 0x68, ++ 0x25, 0xF0, 0x80, 0x05, 0x1D, 0x60, 0x15, 0x68, 0x45, 0xF0, 0x04, 0x05, ++ 0x15, 0x60, 0x82, 0x4D, 0x2A, 0x68, 0x42, 0xF0, 0x02, 0x02, 0x2A, 0x60, ++ 0x1A, 0x68, 0x22, 0xF4, 0xE0, 0x42, 0x22, 0xF0, 0x04, 0x02, 0x42, 0xF4, ++ 0x80, 0x42, 0x32, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x22, 0xF0, 0x07, 0x22, ++ 0x42, 0xF0, 0xC0, 0x62, 0x42, 0xF4, 0x84, 0x72, 0x1A, 0x60, 0x0B, 0x68, ++ 0x03, 0xF0, 0x00, 0x43, 0x43, 0xEA, 0x0A, 0x03, 0x0B, 0x60, 0x03, 0x68, ++ 0x43, 0xF0, 0x3F, 0x03, 0x03, 0x60, 0xDC, 0xF8, 0x00, 0x30, 0x0B, 0x94, ++ 0x43, 0xF4, 0x00, 0x63, 0x38, 0xAA, 0x78, 0xA9, 0x10, 0x92, 0x0F, 0x91, ++ 0xCC, 0xF8, 0x00, 0x30, 0x0D, 0xF1, 0x7F, 0x03, 0xCD, 0xE9, 0x11, 0x21, ++ 0x0D, 0x93, 0x08, 0xEE, 0x10, 0x4A, 0x0D, 0xF1, 0xAF, 0x03, 0x81, 0x46, ++ 0x0E, 0x93, 0x00, 0x23, 0x0C, 0x93, 0x9D, 0xF8, 0x30, 0x50, 0x18, 0xEE, ++ 0x10, 0x3A, 0x2B, 0x43, 0x09, 0x93, 0x00, 0x24, 0x3D, 0xE0, 0x0C, 0x9B, ++ 0x00, 0x2B, 0x6C, 0xD0, 0x66, 0x00, 0x0D, 0x9B, 0x26, 0x44, 0x48, 0xF2, ++ 0x80, 0x0B, 0x13, 0xF8, 0x06, 0xA0, 0x0E, 0x9B, 0x9E, 0x5D, 0x4F, 0xEA, ++ 0x0A, 0x63, 0x43, 0xEA, 0x0A, 0x43, 0x43, 0xEA, 0x0B, 0x03, 0xC8, 0xF8, ++ 0x00, 0x30, 0x19, 0xA9, 0x18, 0xA8, 0xFE, 0xF7, 0xE3, 0xFE, 0xB2, 0x45, ++ 0x0A, 0xD0, 0x33, 0x06, 0x43, 0xEA, 0x06, 0x46, 0x46, 0xEA, 0x0B, 0x06, ++ 0xC8, 0xF8, 0x00, 0x60, 0x19, 0xA9, 0x17, 0xA8, 0xFE, 0xF7, 0xD6, 0xFE, ++ 0x04, 0xEB, 0x84, 0x03, 0xB8, 0xAA, 0xDE, 0x00, 0x00, 0x21, 0x02, 0xEB, ++ 0xC3, 0x03, 0x28, 0x46, 0x18, 0x9A, 0xFF, 0xF7, 0x51, 0xF8, 0x0D, 0xF5, ++ 0xAC, 0x63, 0x33, 0x44, 0x19, 0x9A, 0x01, 0x34, 0x00, 0x21, 0x28, 0x46, ++ 0xFF, 0xF7, 0x48, 0xF8, 0x10, 0x2C, 0xB8, 0xAE, 0x0D, 0xF5, 0xAC, 0x6B, ++ 0x59, 0xD0, 0x3B, 0x68, 0x23, 0xF4, 0xFF, 0x43, 0x43, 0xEA, 0x44, 0x23, ++ 0x43, 0xF4, 0x01, 0x42, 0x43, 0xF4, 0xC0, 0x33, 0x43, 0xF4, 0x80, 0x73, ++ 0x3A, 0x60, 0x01, 0x20, 0x3B, 0x60, 0xFC, 0xF7, 0x71, 0xFB, 0x09, 0x9B, ++ 0xE6, 0xB2, 0x00, 0x2B, 0x3D, 0xD0, 0x0A, 0x9B, 0xD9, 0xF8, 0x00, 0x10, ++ 0x1A, 0x5D, 0x02, 0xF0, 0x0F, 0x03, 0x9B, 0x02, 0x12, 0x09, 0x43, 0xEA, ++ 0x82, 0x13, 0x21, 0xF4, 0x7F, 0x52, 0x13, 0x43, 0xC9, 0xF8, 0x00, 0x30, ++ 0x02, 0x20, 0xFC, 0xF7, 0x5B, 0xFB, 0x0B, 0x9B, 0x00, 0x2B, 0x98, 0xD1, ++ 0x4F, 0xF0, 0x80, 0x33, 0xC8, 0xF8, 0x00, 0x30, 0x19, 0xA9, 0x18, 0xA8, ++ 0xFE, 0xF7, 0x8C, 0xFE, 0xB4, 0xE7, 0x10, 0x9B, 0x04, 0xEB, 0x44, 0x0B, ++ 0x03, 0xEB, 0x04, 0x12, 0x20, 0xAB, 0x18, 0xEE, 0x10, 0x0A, 0x5B, 0x44, ++ 0x00, 0x92, 0x31, 0x46, 0x0D, 0xF1, 0x5A, 0x02, 0xFE, 0xF7, 0xF2, 0xFF, ++ 0x0F, 0x9B, 0x4F, 0xEA, 0x04, 0x1A, 0x0A, 0xEB, 0x03, 0x02, 0x2C, 0xAB, ++ 0x31, 0x46, 0x00, 0x92, 0x18, 0xEE, 0x10, 0x0A, 0x5B, 0x44, 0x0D, 0xF1, ++ 0x5B, 0x02, 0x66, 0x00, 0xFE, 0xF7, 0xE2, 0xFF, 0x73, 0xE7, 0xFE, 0xF7, ++ 0xA7, 0xFE, 0x0A, 0x9B, 0x18, 0x55, 0x02, 0x20, 0xFC, 0xF7, 0x28, 0xFB, ++ 0xCE, 0xE7, 0x0C, 0x9B, 0x18, 0xEE, 0x90, 0x2A, 0x01, 0x33, 0x93, 0x42, ++ 0x0C, 0x93, 0x7F, 0xF4, 0x58, 0xAF, 0x18, 0xEE, 0x90, 0xAA, 0x00, 0x25, ++ 0x45, 0xE0, 0x00, 0xBF, 0x10, 0x20, 0x34, 0x40, 0x60, 0x7A, 0x15, 0x00, ++ 0x1C, 0x20, 0x34, 0x40, 0x74, 0x7A, 0x15, 0x00, 0x04, 0x22, 0x34, 0x40, ++ 0x88, 0x7A, 0x15, 0x00, 0x18, 0x00, 0x58, 0x40, 0x9C, 0x7A, 0x15, 0x00, ++ 0xB0, 0x7A, 0x15, 0x00, 0x04, 0x40, 0x34, 0x40, 0x30, 0x20, 0x34, 0x40, ++ 0x60, 0x20, 0x34, 0x40, 0x5C, 0x20, 0x34, 0x40, 0x64, 0x20, 0x34, 0x40, ++ 0x50, 0x40, 0x34, 0x40, 0x58, 0x40, 0x34, 0x40, 0x80, 0x21, 0x34, 0x40, ++ 0x68, 0x20, 0x34, 0x40, 0x0C, 0xB6, 0x33, 0x40, 0x08, 0xB6, 0x33, 0x40, ++ 0x20, 0x40, 0x34, 0x40, 0x4C, 0x40, 0x34, 0x40, 0x06, 0x2D, 0x34, 0xBF, ++ 0x32, 0x21, 0x64, 0x21, 0x09, 0x91, 0xFE, 0xF7, 0xDB, 0xFF, 0x11, 0x9B, ++ 0x09, 0x99, 0x84, 0x46, 0x43, 0xF8, 0x04, 0xC0, 0x5A, 0x46, 0x50, 0x46, ++ 0xFE, 0xF7, 0xD2, 0xFF, 0x01, 0x35, 0x12, 0x9B, 0x10, 0x2D, 0x18, 0x51, ++ 0x06, 0xF1, 0x28, 0x06, 0x0B, 0xF1, 0x28, 0x0B, 0x14, 0xD0, 0xBA, 0xF1, ++ 0x01, 0x0F, 0x32, 0x46, 0x4F, 0xEA, 0x05, 0x14, 0x50, 0x46, 0xDF, 0xD1, ++ 0x11, 0x9B, 0x30, 0x68, 0x18, 0x51, 0x01, 0x35, 0x12, 0x9B, 0xDB, 0xF8, ++ 0x00, 0x10, 0x19, 0x51, 0x10, 0x2D, 0x06, 0xF1, 0x28, 0x06, 0x0B, 0xF1, ++ 0x28, 0x0B, 0xEA, 0xD1, 0x11, 0x9A, 0x0B, 0x9B, 0x04, 0x32, 0x11, 0x92, ++ 0x12, 0x9A, 0x04, 0x32, 0x12, 0x92, 0x0D, 0x9A, 0x01, 0x32, 0x0D, 0x92, ++ 0x0E, 0x9A, 0x01, 0x32, 0x01, 0x33, 0x0E, 0x92, 0x19, 0xEE, 0x10, 0x2A, ++ 0x0B, 0x93, 0xDB, 0xB2, 0x9A, 0x42, 0x08, 0xEE, 0x10, 0x3A, 0x3F, 0xF6, ++ 0xE0, 0xAE, 0x20, 0xAD, 0x2C, 0xAC, 0xAB, 0x46, 0x0B, 0x95, 0xDD, 0xF8, ++ 0x40, 0x80, 0x0F, 0x9F, 0x09, 0x94, 0x19, 0xEE, 0x10, 0x5A, 0xA2, 0x46, ++ 0x00, 0x26, 0x09, 0xE0, 0x13, 0x9A, 0x42, 0xF8, 0x26, 0x30, 0x01, 0x36, ++ 0x0B, 0xF1, 0x03, 0x0B, 0x08, 0xF1, 0x10, 0x08, 0x0A, 0xF1, 0x03, 0x0A, ++ 0x5F, 0xFA, 0x86, 0xF9, 0x49, 0x46, 0x43, 0x46, 0x5A, 0x46, 0x28, 0x46, ++ 0xFF, 0xF7, 0x98, 0xFB, 0x07, 0xEB, 0x06, 0x13, 0x04, 0x46, 0x52, 0x46, ++ 0x49, 0x46, 0x28, 0x46, 0xFF, 0xF7, 0x90, 0xFB, 0x03, 0x02, 0xE2, 0xB2, ++ 0x03, 0xF4, 0x7F, 0x43, 0x13, 0x43, 0x43, 0xF0, 0x00, 0x43, 0x09, 0x2E, ++ 0x43, 0xF4, 0x00, 0x03, 0xDA, 0xD9, 0x1A, 0xAB, 0x03, 0xEB, 0x46, 0x02, ++ 0x1D, 0xAB, 0x03, 0xEB, 0x46, 0x03, 0xB9, 0xF1, 0x0F, 0x0F, 0x22, 0xF8, ++ 0x14, 0x4C, 0x23, 0xF8, 0x14, 0x0C, 0xD0, 0xD1, 0x14, 0x9B, 0x09, 0x9C, ++ 0x0B, 0x9D, 0xC3, 0xF3, 0x40, 0x10, 0x1A, 0xA9, 0x09, 0x90, 0xFF, 0xF7, ++ 0xD3, 0xF8, 0x09, 0x98, 0x1D, 0xA9, 0xFF, 0xF7, 0xCF, 0xF8, 0x13, 0x9B, ++ 0xDF, 0xF8, 0x98, 0xC1, 0x1D, 0xA8, 0x1A, 0xA9, 0x03, 0xF1, 0x24, 0x06, ++ 0x03, 0xF1, 0x3C, 0x07, 0x30, 0xF9, 0x02, 0x3B, 0x31, 0xF9, 0x02, 0x2B, ++ 0x1B, 0x02, 0x03, 0xF4, 0x7F, 0x43, 0xD2, 0xB2, 0x13, 0x43, 0x43, 0xEA, ++ 0x0C, 0x03, 0x46, 0xF8, 0x04, 0x3F, 0xBE, 0x42, 0xF0, 0xD1, 0x10, 0x9B, ++ 0xDF, 0xF8, 0x6C, 0x81, 0xDD, 0xF8, 0x3C, 0xA0, 0x03, 0xF5, 0x80, 0x77, ++ 0x00, 0x26, 0x99, 0x46, 0xD9, 0xF8, 0x0C, 0x20, 0xAB, 0x78, 0xD9, 0xF8, ++ 0x08, 0xC0, 0x68, 0x78, 0xD9, 0xF8, 0x04, 0x10, 0x06, 0x92, 0x15, 0xF8, ++ 0x03, 0x2B, 0x05, 0x93, 0x59, 0xF8, 0x10, 0x3B, 0x00, 0x93, 0xCD, 0xE9, ++ 0x03, 0x0C, 0xCD, 0xE9, 0x01, 0x21, 0x80, 0x23, 0x32, 0x46, 0x41, 0x46, ++ 0x4F, 0xF4, 0x00, 0x50, 0x20, 0xF0, 0xC6, 0xFA, 0xDA, 0xF8, 0x0C, 0x20, ++ 0xA3, 0x78, 0x60, 0x78, 0xDA, 0xF8, 0x04, 0x10, 0xDA, 0xF8, 0x08, 0xC0, ++ 0x06, 0x92, 0x14, 0xF8, 0x03, 0x2B, 0x05, 0x93, 0x5A, 0xF8, 0x10, 0x3B, ++ 0x00, 0x93, 0xCD, 0xE9, 0x01, 0x21, 0xCD, 0xE9, 0x03, 0x0C, 0x32, 0x46, ++ 0x36, 0x49, 0x80, 0x23, 0x4F, 0xF4, 0x00, 0x50, 0x20, 0xF0, 0xAC, 0xFA, ++ 0x4F, 0x45, 0x06, 0xF1, 0x01, 0x06, 0xC7, 0xD1, 0x13, 0x9B, 0x32, 0x4E, ++ 0x1D, 0x1F, 0x00, 0x24, 0x55, 0xF8, 0x04, 0x3F, 0xC3, 0xF3, 0x07, 0x22, ++ 0x00, 0x92, 0xDB, 0xB2, 0x22, 0x46, 0x31, 0x46, 0x01, 0x34, 0x4F, 0xF4, ++ 0x00, 0x50, 0x20, 0xF0, 0x97, 0xFA, 0x10, 0x2C, 0xF0, 0xD1, 0x14, 0x9B, ++ 0xDB, 0x06, 0x0D, 0xD5, 0x15, 0x9B, 0x3B, 0xB1, 0x27, 0x4A, 0x13, 0x68, ++ 0x43, 0xF4, 0x00, 0x61, 0x43, 0xF4, 0xC0, 0x53, 0x11, 0x60, 0x13, 0x60, ++ 0x0A, 0x99, 0x13, 0x98, 0xFF, 0xF7, 0x0C, 0xFC, 0x22, 0x49, 0x23, 0x4A, ++ 0x0B, 0x68, 0x23, 0x4E, 0x23, 0x4C, 0x24, 0x48, 0x23, 0xF0, 0x02, 0x03, ++ 0x0B, 0x60, 0x13, 0x68, 0x23, 0xF4, 0xEE, 0x43, 0x23, 0xF0, 0x09, 0x03, ++ 0x43, 0xF4, 0x58, 0x53, 0xA1, 0xF5, 0xD6, 0x41, 0x43, 0xF0, 0x04, 0x03, ++ 0x13, 0x60, 0x74, 0x39, 0x02, 0xF5, 0xFF, 0x52, 0x1C, 0x32, 0x00, 0x23, ++ 0x4F, 0xF0, 0x80, 0x35, 0x33, 0x60, 0x25, 0x60, 0x03, 0x60, 0x0B, 0x60, ++ 0x13, 0x68, 0x17, 0x49, 0x23, 0xF4, 0x7F, 0x43, 0x00, 0xF5, 0x09, 0x40, ++ 0x23, 0xF0, 0x80, 0x03, 0xFC, 0x30, 0x43, 0xF4, 0x80, 0x34, 0x13, 0x60, ++ 0x14, 0x60, 0x03, 0x68, 0x23, 0xF4, 0xC0, 0x53, 0x03, 0x60, 0x4F, 0xF4, ++ 0x00, 0x50, 0x20, 0xF0, 0x4F, 0xFA, 0x0D, 0xF2, 0xE4, 0x7D, 0xBD, 0xEC, ++ 0x04, 0x8B, 0xBD, 0xE8, 0xF0, 0x8F, 0x01, 0x23, 0x08, 0xEE, 0x90, 0x3A, ++ 0x65, 0xE5, 0x00, 0xBF, 0xF0, 0x7A, 0x15, 0x00, 0x1C, 0x7B, 0x15, 0x00, ++ 0x04, 0x40, 0x34, 0x40, 0x80, 0x21, 0x34, 0x40, 0x5C, 0x20, 0x34, 0x40, ++ 0x50, 0x40, 0x34, 0x40, 0x4C, 0x40, 0x34, 0x40, 0x08, 0xB6, 0x33, 0x40, ++ 0x3C, 0x7B, 0x15, 0x00, 0x00, 0x00, 0x80, 0x80, 0xC4, 0x7A, 0x15, 0x00, ++ 0xF0, 0xB5, 0x07, 0x78, 0x43, 0x68, 0x83, 0xB0, 0x0E, 0x46, 0x3A, 0x46, ++ 0x27, 0x49, 0x01, 0x93, 0x4F, 0xF4, 0x00, 0x50, 0x20, 0xF0, 0x22, 0xFA, ++ 0x01, 0x9B, 0x30, 0x1F, 0x06, 0xF1, 0x3C, 0x01, 0x4F, 0xF0, 0x80, 0x32, ++ 0x40, 0xF8, 0x04, 0x2F, 0x88, 0x42, 0xFB, 0xD1, 0x06, 0xF1, 0x3F, 0x00, ++ 0x06, 0xF1, 0x4F, 0x02, 0x00, 0x24, 0x00, 0xF8, 0x01, 0x4F, 0x82, 0x42, ++ 0xFB, 0xD1, 0x30, 0x46, 0x34, 0x65, 0x06, 0xF1, 0x94, 0x05, 0x40, 0xF8, ++ 0x54, 0x4F, 0x00, 0x24, 0x40, 0xF8, 0x04, 0x4F, 0xA8, 0x42, 0xFB, 0xD1, ++ 0xBA, 0x09, 0x18, 0xD0, 0x15, 0x4C, 0xDF, 0xF8, 0x74, 0xC0, 0x21, 0x68, ++ 0x14, 0x4D, 0x15, 0x4A, 0x15, 0x48, 0x21, 0xF4, 0x00, 0x11, 0x21, 0x60, ++ 0xF9, 0x09, 0x00, 0x29, 0x08, 0xBF, 0x62, 0x46, 0x2A, 0x60, 0x05, 0x68, ++ 0x11, 0x49, 0x12, 0x4C, 0x12, 0x4A, 0x01, 0xEA, 0x05, 0x01, 0x08, 0xBF, ++ 0x22, 0x46, 0x0A, 0x43, 0x02, 0x60, 0x01, 0x93, 0xFE, 0xF7, 0x08, 0xFC, ++ 0x0E, 0x4A, 0x01, 0x9B, 0xD2, 0xF8, 0xBC, 0x44, 0x38, 0x46, 0x06, 0xF1, ++ 0x40, 0x02, 0x31, 0x46, 0xA0, 0x47, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x40, ++ 0xFE, 0xF7, 0x44, 0xBC, 0x50, 0x7B, 0x15, 0x00, 0x58, 0x40, 0x34, 0x40, ++ 0x10, 0x20, 0x34, 0x40, 0x76, 0x62, 0xF7, 0x0B, 0x1C, 0x20, 0x34, 0x40, ++ 0xFF, 0x0F, 0x00, 0xE0, 0x00, 0x50, 0x98, 0x00, 0x00, 0x90, 0x9B, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x76, 0x62, 0xB7, 0x0B, 0x17, 0x4B, 0x01, 0x22, ++ 0x30, 0xB4, 0x1A, 0x60, 0x32, 0x23, 0x00, 0xBF, 0x01, 0x3B, 0x9B, 0xB2, ++ 0x00, 0x2B, 0xFA, 0xD1, 0x13, 0x4A, 0x13, 0x68, 0x00, 0x2B, 0x08, 0xDB, ++ 0x32, 0x23, 0x00, 0xBF, 0x01, 0x3B, 0x9B, 0xB2, 0x00, 0x2B, 0xFA, 0xD1, ++ 0x13, 0x68, 0x00, 0x2B, 0xF6, 0xDA, 0x0E, 0x4A, 0x0C, 0x4B, 0x15, 0x68, ++ 0x1C, 0x68, 0xC5, 0xF3, 0x10, 0x02, 0xED, 0x03, 0x44, 0xBF, 0x6F, 0xEA, ++ 0x02, 0x42, 0x6F, 0xEA, 0x12, 0x42, 0xC4, 0xF3, 0x10, 0x03, 0x02, 0x60, ++ 0xE2, 0x03, 0x44, 0xBF, 0x6F, 0xEA, 0x03, 0x43, 0x6F, 0xEA, 0x13, 0x43, ++ 0x30, 0xBC, 0x0B, 0x60, 0x70, 0x47, 0x00, 0xBF, 0x6C, 0x08, 0x62, 0x40, ++ 0x90, 0x08, 0x62, 0x40, 0x8C, 0x08, 0x62, 0x40, 0x30, 0xB4, 0x11, 0x4C, ++ 0x11, 0x4D, 0x12, 0x4B, 0x04, 0xEA, 0x02, 0x42, 0xC1, 0xF3, 0x0E, 0x01, ++ 0x0A, 0x43, 0x2A, 0x60, 0x1A, 0x68, 0x00, 0xF0, 0x07, 0x00, 0x22, 0xF0, ++ 0xE0, 0x62, 0x02, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x42, 0xF0, 0x00, 0x42, ++ 0x1A, 0x60, 0x1A, 0x68, 0x42, 0xF0, 0x80, 0x42, 0x1A, 0x60, 0x1A, 0x68, ++ 0x22, 0xF0, 0x80, 0x42, 0x1A, 0x60, 0x1A, 0x68, 0x22, 0xF0, 0x00, 0x42, ++ 0x30, 0xBC, 0x1A, 0x60, 0x70, 0x47, 0x00, 0xBF, 0x00, 0x00, 0xFF, 0x7F, ++ 0x44, 0x05, 0x62, 0x40, 0x28, 0x05, 0x62, 0x40, 0x38, 0xB5, 0x28, 0x4C, ++ 0x28, 0x4A, 0x23, 0x68, 0x28, 0x49, 0x23, 0xF0, 0xFF, 0x03, 0x03, 0x43, ++ 0x43, 0xF0, 0x80, 0x03, 0x23, 0x60, 0x13, 0x68, 0x43, 0xF0, 0x01, 0x03, ++ 0x13, 0x60, 0x0A, 0x68, 0x22, 0xF0, 0x03, 0x02, 0x42, 0xF0, 0x02, 0x03, ++ 0x0B, 0x60, 0x32, 0x23, 0x00, 0xBF, 0x01, 0x3B, 0x9B, 0xB2, 0x00, 0x2B, ++ 0xFA, 0xD1, 0x1D, 0x4B, 0x42, 0xF0, 0x03, 0x02, 0x1A, 0x60, 0x32, 0x23, ++ 0x00, 0xBF, 0x01, 0x3B, 0x9B, 0xB2, 0x00, 0x2B, 0xFA, 0xD1, 0x19, 0x4A, ++ 0x13, 0x68, 0x98, 0x07, 0x08, 0xD4, 0x32, 0x23, 0x00, 0xBF, 0x01, 0x3B, ++ 0x9B, 0xB2, 0x00, 0x2B, 0xFA, 0xD1, 0x13, 0x68, 0x98, 0x07, 0xF6, 0xD5, ++ 0x13, 0x4C, 0x22, 0x68, 0x51, 0x00, 0x0E, 0xD4, 0x12, 0x4D, 0x29, 0x46, ++ 0x4F, 0xF4, 0x00, 0x50, 0x20, 0xF0, 0x28, 0xF9, 0x32, 0x23, 0x00, 0xBF, ++ 0x01, 0x3B, 0x9B, 0xB2, 0x00, 0x2B, 0xFA, 0xD1, 0x22, 0x68, 0x53, 0x00, ++ 0xF1, 0xD5, 0x0C, 0x4A, 0x0C, 0x49, 0x13, 0x68, 0x43, 0xF4, 0x80, 0x03, ++ 0x13, 0x60, 0x4F, 0xF4, 0x00, 0x50, 0xBD, 0xE8, 0x38, 0x40, 0x20, 0xF0, ++ 0x13, 0xB9, 0x00, 0xBF, 0x08, 0x01, 0x60, 0x40, 0x08, 0x05, 0x62, 0x40, ++ 0x00, 0x00, 0x62, 0x40, 0x80, 0x40, 0x34, 0x40, 0x04, 0x22, 0x34, 0x40, ++ 0x68, 0x7B, 0x15, 0x00, 0x04, 0x00, 0x62, 0x40, 0x7C, 0x7B, 0x15, 0x00, ++ 0x10, 0xB5, 0x0F, 0x4C, 0x0F, 0x4A, 0x23, 0x68, 0x0F, 0x48, 0x10, 0x49, ++ 0x23, 0xF4, 0x80, 0x03, 0x23, 0x60, 0x13, 0x68, 0x23, 0xF0, 0x03, 0x03, ++ 0x13, 0x60, 0x13, 0x60, 0x03, 0x68, 0x23, 0xF0, 0xFF, 0x03, 0x03, 0x60, ++ 0x0B, 0x68, 0x23, 0xF0, 0x01, 0x03, 0x0B, 0x60, 0x14, 0x20, 0xFC, 0xF7, ++ 0x45, 0xF8, 0xBD, 0xE8, 0x10, 0x40, 0x06, 0x49, 0x4F, 0xF4, 0x00, 0x50, ++ 0x20, 0xF0, 0xE2, 0xB8, 0x04, 0x00, 0x62, 0x40, 0x00, 0x00, 0x62, 0x40, ++ 0x08, 0x01, 0x60, 0x40, 0x08, 0x05, 0x62, 0x40, 0x88, 0x7B, 0x15, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0x83, 0xB0, 0x07, 0x46, 0x10, 0x1A, 0x0E, 0x46, ++ 0x9B, 0x46, 0xDD, 0xE9, 0x0E, 0x54, 0x9D, 0xF8, 0x30, 0x90, 0x9D, 0xF8, ++ 0x34, 0x80, 0x32, 0xF0, 0x65, 0xFD, 0x82, 0x46, 0xAB, 0xEB, 0x06, 0x00, ++ 0x32, 0xF0, 0x60, 0xFD, 0xBA, 0xF1, 0x00, 0x0F, 0x11, 0xD0, 0x07, 0xFA, ++ 0x09, 0xF7, 0x07, 0xEE, 0x90, 0x7A, 0xB8, 0xEE, 0xE7, 0x7A, 0x07, 0xEE, ++ 0x90, 0xAA, 0xF8, 0xEE, 0xE7, 0x7A, 0xC7, 0xEE, 0x27, 0x6A, 0xFD, 0xEE, ++ 0xE6, 0x7A, 0xCD, 0xED, 0x01, 0x7A, 0x9D, 0xF9, 0x04, 0xA0, 0x85, 0xF8, ++ 0x00, 0xA0, 0xA8, 0xB1, 0x06, 0xFA, 0x08, 0xF6, 0x07, 0xEE, 0x90, 0x6A, ++ 0xB8, 0xEE, 0xE7, 0x7A, 0x07, 0xEE, 0x90, 0x0A, 0xF8, 0xEE, 0xE7, 0x7A, ++ 0xC7, 0xEE, 0x27, 0x6A, 0xFD, 0xEE, 0xE6, 0x7A, 0xCD, 0xED, 0x01, 0x7A, ++ 0x9D, 0xF9, 0x04, 0x30, 0x23, 0x70, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, ++ 0x03, 0x46, 0x23, 0x70, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x00, 0xBF, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0xA1, 0x4F, 0xA2, 0x4C, 0x3D, 0x68, 0xA2, 0x4E, ++ 0xAD, 0xB2, 0x25, 0x43, 0x2D, 0xED, 0x02, 0x8B, 0x3D, 0x60, 0x35, 0x68, ++ 0x91, 0xB0, 0x25, 0xF0, 0x01, 0x05, 0x86, 0x46, 0x35, 0x60, 0x8C, 0x46, ++ 0x4F, 0xF4, 0x00, 0x50, 0x9B, 0x49, 0xCD, 0xF8, 0x1C, 0xE0, 0xCD, 0xE9, ++ 0x08, 0x23, 0x08, 0xEE, 0x10, 0xCA, 0x75, 0x46, 0x20, 0xF0, 0x72, 0xF8, ++ 0x3B, 0x68, 0x9B, 0xB2, 0x23, 0x43, 0x3B, 0x60, 0x00, 0x2D, 0x00, 0xF0, ++ 0x16, 0x81, 0x00, 0x26, 0x34, 0x46, 0x35, 0x46, 0x0D, 0xF1, 0x34, 0x0B, ++ 0x0D, 0xF1, 0x30, 0x0A, 0x32, 0x23, 0x00, 0xBF, 0x01, 0x3B, 0x9B, 0xB2, ++ 0x00, 0x2B, 0xFA, 0xD1, 0x59, 0x46, 0x50, 0x46, 0xFF, 0xF7, 0x96, 0xFE, ++ 0xDD, 0xE9, 0x0C, 0x32, 0x8A, 0x49, 0xCD, 0xE9, 0x00, 0x32, 0x4F, 0xF4, ++ 0x00, 0x50, 0x23, 0x46, 0x2A, 0x46, 0x20, 0xF0, 0x4F, 0xF8, 0x0C, 0x9B, ++ 0x00, 0x2B, 0xC0, 0xF2, 0xA5, 0x80, 0x00, 0x2E, 0x00, 0xF0, 0xB9, 0x80, ++ 0x01, 0x2E, 0x00, 0xF0, 0xDD, 0x80, 0x0D, 0x9B, 0x15, 0xF1, 0x7C, 0x0F, ++ 0xAC, 0xBF, 0x2A, 0x1F, 0x2A, 0x1D, 0x00, 0x2B, 0x80, 0xF2, 0xA1, 0x80, ++ 0x01, 0x2E, 0x4F, 0xF0, 0x02, 0x08, 0x00, 0xF0, 0xDA, 0x80, 0x7B, 0x2C, ++ 0x00, 0xF3, 0xA1, 0x80, 0x23, 0x1D, 0x4F, 0xF0, 0x02, 0x09, 0xA3, 0xF1, ++ 0x80, 0x01, 0x38, 0x68, 0xC9, 0xB2, 0x09, 0x04, 0xA2, 0xF1, 0x80, 0x0C, ++ 0x41, 0xEA, 0x0C, 0x61, 0x80, 0xB2, 0x01, 0x43, 0x39, 0x60, 0x32, 0x21, ++ 0x00, 0xBF, 0x01, 0x39, 0x89, 0xB2, 0x00, 0x29, 0xFA, 0xD1, 0x0F, 0xA9, ++ 0x0E, 0xA8, 0xCD, 0xE9, 0x05, 0x23, 0xFF, 0xF7, 0x55, 0xFE, 0xDD, 0xE9, ++ 0x0E, 0x10, 0xDD, 0xE9, 0x05, 0x23, 0x01, 0x90, 0x00, 0x91, 0x4F, 0xF4, ++ 0x00, 0x50, 0x68, 0x49, 0x20, 0xF0, 0x0E, 0xF8, 0x0D, 0xF1, 0x2F, 0x03, ++ 0x03, 0x93, 0x0D, 0xF1, 0x2E, 0x03, 0xCD, 0xE9, 0x01, 0x93, 0xDD, 0xE9, ++ 0x0C, 0x01, 0xDD, 0xE9, 0x0E, 0x23, 0xCD, 0xF8, 0x00, 0x80, 0xFF, 0xF7, ++ 0x27, 0xFF, 0x9D, 0xF9, 0x2F, 0x30, 0x9D, 0xF9, 0x2E, 0x20, 0x5E, 0x49, ++ 0x4F, 0xF4, 0x00, 0x50, 0x1F, 0xF0, 0xF6, 0xFF, 0x9D, 0xF9, 0x2F, 0x30, ++ 0x9D, 0xF9, 0x2E, 0x20, 0x39, 0x68, 0xE4, 0x1A, 0x6F, 0xF0, 0x7F, 0x03, ++ 0x9C, 0x42, 0xB8, 0xBF, 0x1C, 0x46, 0xAD, 0x1A, 0x7F, 0x2C, 0xA8, 0xBF, ++ 0x7F, 0x24, 0x9D, 0x42, 0xB8, 0xBF, 0x1D, 0x46, 0x04, 0xEB, 0x03, 0x08, ++ 0x7F, 0x2D, 0xA8, 0xBF, 0x7F, 0x25, 0x5F, 0xFA, 0x88, 0xF8, 0xA5, 0xF1, ++ 0x80, 0x02, 0x4F, 0xEA, 0x08, 0x43, 0x43, 0xEA, 0x02, 0x63, 0x89, 0xB2, ++ 0x0B, 0x43, 0x01, 0x36, 0x3B, 0x60, 0x07, 0x9B, 0xF6, 0xB2, 0xB3, 0x42, ++ 0x5F, 0xFA, 0x82, 0xF9, 0x7F, 0xF4, 0x68, 0xAF, 0x32, 0x23, 0x00, 0xBF, ++ 0x01, 0x3B, 0x9B, 0xB2, 0x00, 0x2B, 0xFA, 0xD1, 0x59, 0x46, 0x50, 0x46, ++ 0xFF, 0xF7, 0xFE, 0xFD, 0xDD, 0xE9, 0x0C, 0x13, 0x2A, 0x46, 0x01, 0x93, ++ 0x00, 0x91, 0x23, 0x46, 0x3F, 0x49, 0x4F, 0xF4, 0x00, 0x50, 0x1F, 0xF0, ++ 0xB7, 0xFF, 0x08, 0x9B, 0x83, 0xF8, 0x00, 0x90, 0x09, 0x9B, 0xDD, 0xE9, ++ 0x0C, 0x12, 0x18, 0xEE, 0x10, 0x0A, 0x83, 0xF8, 0x00, 0x80, 0xFF, 0xF7, ++ 0x1D, 0xFE, 0x11, 0xB0, 0xBD, 0xEC, 0x02, 0x8B, 0xBD, 0xE8, 0xF0, 0x8F, ++ 0x06, 0xB3, 0x01, 0x2E, 0x29, 0xD0, 0x0D, 0x9B, 0x7B, 0x2D, 0xD4, 0xBF, ++ 0x2A, 0x1D, 0x2A, 0x1F, 0x00, 0x2B, 0xFF, 0xF6, 0x5F, 0xAF, 0x01, 0x2E, ++ 0x4F, 0xF0, 0x02, 0x08, 0x26, 0xD0, 0x14, 0xF1, 0x7C, 0x0F, 0xFF, 0xF6, ++ 0x5F, 0xAF, 0x23, 0x1F, 0x4F, 0xF0, 0x02, 0x09, 0x5D, 0xE7, 0x0D, 0x9B, ++ 0x00, 0x2B, 0xA5, 0xF1, 0x20, 0x02, 0x0A, 0xDA, 0x4F, 0xF0, 0x05, 0x08, ++ 0xC1, 0x46, 0x04, 0xF1, 0x20, 0x03, 0x52, 0xE7, 0x0D, 0x9B, 0x00, 0x2B, ++ 0x05, 0xF1, 0x20, 0x02, 0xF4, 0xDB, 0x4F, 0xF0, 0x05, 0x08, 0xC1, 0x46, ++ 0xA4, 0xF1, 0x20, 0x03, 0x47, 0xE7, 0x6F, 0x2D, 0xD3, 0xDC, 0x0D, 0x9B, ++ 0x00, 0x2B, 0x05, 0xF1, 0x10, 0x02, 0x4F, 0xF0, 0x04, 0x08, 0x12, 0xDB, ++ 0x14, 0xF1, 0x70, 0x0F, 0xD5, 0xDB, 0xA4, 0xF1, 0x10, 0x03, 0x4F, 0xF0, ++ 0x04, 0x09, 0x36, 0xE7, 0x15, 0xF1, 0x70, 0x0F, 0xFF, 0xF6, 0x1F, 0xAF, ++ 0x0D, 0x9B, 0x00, 0x2B, 0xA5, 0xF1, 0x10, 0x02, 0x4F, 0xF0, 0x04, 0x08, ++ 0xEC, 0xDA, 0x6F, 0x2C, 0x3F, 0xF7, 0x23, 0xAF, 0x04, 0xF1, 0x10, 0x03, ++ 0x4F, 0xF0, 0x04, 0x09, 0x23, 0xE7, 0x07, 0x9C, 0x4F, 0xF0, 0x80, 0x08, ++ 0x25, 0x46, 0xC1, 0x46, 0x0D, 0xF1, 0x34, 0x0B, 0x0D, 0xF1, 0x30, 0x0A, ++ 0x7E, 0xE7, 0x00, 0xBF, 0x4C, 0x40, 0x34, 0x40, 0x00, 0x00, 0x80, 0x80, ++ 0x1C, 0x40, 0x34, 0x40, 0x94, 0x7B, 0x15, 0x00, 0xA8, 0x7B, 0x15, 0x00, ++ 0xCC, 0x7B, 0x15, 0x00, 0xF0, 0x7B, 0x15, 0x00, 0x0C, 0x7C, 0x15, 0x00, ++ 0x2D, 0xE9, 0xF8, 0x43, 0x22, 0x4B, 0x23, 0x4E, 0x1A, 0x68, 0x00, 0x25, ++ 0x22, 0xF4, 0x7F, 0x52, 0x1A, 0x60, 0x98, 0x46, 0x2F, 0x46, 0x4F, 0xF0, ++ 0x07, 0x09, 0x02, 0x20, 0xFB, 0xF7, 0x86, 0xFE, 0x33, 0x68, 0xD8, 0xF8, ++ 0x00, 0x40, 0xDA, 0x05, 0x54, 0xBF, 0x01, 0x37, 0x07, 0xF1, 0xFF, 0x37, ++ 0x7F, 0xB2, 0x1B, 0x06, 0x54, 0xBF, 0x01, 0x35, 0x05, 0xF1, 0xFF, 0x35, ++ 0x00, 0x2F, 0x24, 0xF4, 0x7F, 0x54, 0xDC, 0xBF, 0x7B, 0x42, 0x44, 0xEA, ++ 0x83, 0x24, 0x6D, 0xB2, 0xD4, 0xBF, 0x44, 0xF4, 0x00, 0x54, 0x44, 0xEA, ++ 0x87, 0x24, 0x00, 0x2D, 0xDC, 0xBF, 0x6B, 0x42, 0x44, 0xEA, 0x83, 0x14, ++ 0x09, 0xF1, 0xFF, 0x33, 0xCC, 0xBF, 0x44, 0xEA, 0x85, 0x14, 0x44, 0xF4, ++ 0x00, 0x74, 0x13, 0xF0, 0xFF, 0x09, 0xC8, 0xF8, 0x00, 0x40, 0xD0, 0xD1, ++ 0x07, 0x49, 0x2B, 0x46, 0x3A, 0x46, 0x4F, 0xF4, 0x00, 0x50, 0x1F, 0xF0, ++ 0xF7, 0xFE, 0xC4, 0xF3, 0x87, 0x10, 0xBD, 0xE8, 0xF8, 0x83, 0x00, 0xBF, ++ 0x50, 0x40, 0x34, 0x40, 0x14, 0x40, 0x34, 0x40, 0x34, 0x7C, 0x15, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0x4E, 0x4A, 0x4F, 0x4D, 0x13, 0x68, 0x87, 0xB0, ++ 0xC1, 0xF3, 0x03, 0x24, 0x03, 0x93, 0x23, 0xF0, 0x00, 0x43, 0x23, 0xF4, ++ 0xE0, 0x03, 0x43, 0xEA, 0x04, 0x53, 0x43, 0xF0, 0x0A, 0x03, 0x13, 0x60, ++ 0x2C, 0x68, 0x48, 0x4B, 0x24, 0xF4, 0xC0, 0x54, 0xC1, 0xF3, 0x01, 0x62, ++ 0x22, 0x43, 0x2A, 0x60, 0x1A, 0x68, 0x01, 0xF0, 0x0F, 0x04, 0xC1, 0xF3, ++ 0x03, 0x15, 0x42, 0xF0, 0x3F, 0x02, 0xA5, 0x42, 0x02, 0x94, 0xC1, 0xF3, ++ 0x03, 0x3A, 0x1A, 0x60, 0x5E, 0xD8, 0xDF, 0xF8, 0x04, 0x81, 0x3E, 0x4E, ++ 0xDF, 0xF8, 0x00, 0xB1, 0x44, 0x19, 0x99, 0x46, 0xEF, 0xB2, 0xD8, 0xF8, ++ 0x00, 0x20, 0x22, 0xF4, 0xFF, 0x42, 0x42, 0xEA, 0x45, 0x22, 0x42, 0xF4, ++ 0x40, 0x40, 0x42, 0xF4, 0xE0, 0x31, 0xC8, 0xF8, 0x00, 0x00, 0x2A, 0x46, ++ 0xC8, 0xF8, 0x00, 0x10, 0x4F, 0xF4, 0x00, 0x50, 0x33, 0x49, 0x1F, 0xF0, ++ 0xA9, 0xFE, 0x32, 0x68, 0x42, 0xF4, 0x80, 0x62, 0x32, 0x60, 0xDB, 0xF8, ++ 0x00, 0x20, 0x42, 0xF0, 0x40, 0x02, 0xCB, 0xF8, 0x00, 0x20, 0x32, 0x22, ++ 0x00, 0xBF, 0x01, 0x3A, 0x92, 0xB2, 0x00, 0x2A, 0xFA, 0xD1, 0xFF, 0xF7, ++ 0x5D, 0xFF, 0x04, 0xF8, 0x01, 0x0B, 0x32, 0x68, 0x22, 0xF4, 0x80, 0x62, ++ 0x32, 0x60, 0xD9, 0xF8, 0x00, 0x20, 0x22, 0xF0, 0x40, 0x02, 0xC9, 0xF8, ++ 0x00, 0x20, 0x32, 0x22, 0x00, 0xBF, 0x01, 0x3A, 0x92, 0xB2, 0x00, 0x2A, ++ 0xFA, 0xD1, 0x0D, 0xF1, 0x17, 0x03, 0x01, 0x93, 0x0D, 0xF1, 0x16, 0x03, ++ 0x39, 0x46, 0x00, 0x93, 0x05, 0xAA, 0x0D, 0xF1, 0x15, 0x03, 0x50, 0x46, ++ 0xFF, 0xF7, 0xE8, 0xFD, 0x01, 0x35, 0x02, 0x9B, 0x9D, 0xF8, 0x16, 0xC0, ++ 0x9D, 0xF8, 0x17, 0x00, 0x9D, 0xF8, 0x14, 0x10, 0x9D, 0xF8, 0x15, 0x20, ++ 0x84, 0xF8, 0x04, 0xC0, 0xEF, 0xB2, 0xBB, 0x42, 0x60, 0x72, 0xA1, 0x73, ++ 0xE2, 0x74, 0xA8, 0xD2, 0x11, 0x4A, 0x0D, 0x48, 0x13, 0x68, 0x0D, 0x49, ++ 0x0A, 0x4C, 0x23, 0xF4, 0x7F, 0x43, 0x23, 0xF0, 0x80, 0x03, 0x13, 0x60, ++ 0x43, 0xF4, 0x80, 0x33, 0x13, 0x60, 0x03, 0x68, 0x23, 0xF4, 0xC0, 0x53, ++ 0x03, 0x60, 0x0B, 0x68, 0x23, 0xF0, 0x3F, 0x03, 0x0B, 0x60, 0x03, 0x9B, ++ 0x23, 0x60, 0x07, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x1C, 0x05, 0x62, 0x40, ++ 0x04, 0x40, 0x34, 0x40, 0x50, 0x40, 0x34, 0x40, 0x14, 0x40, 0x34, 0x40, ++ 0x54, 0x7C, 0x15, 0x00, 0x58, 0x40, 0x34, 0x40, 0x5C, 0x40, 0x34, 0x40, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0x3C, 0x4D, 0x3D, 0x49, 0x81, 0x46, 0x89, 0xB0, ++ 0x4F, 0xF4, 0x00, 0x50, 0x1F, 0xF0, 0x34, 0xFE, 0x2B, 0x68, 0xD9, 0xF8, ++ 0x00, 0x40, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xE2, 0xB2, 0x04, 0xF0, ++ 0x7F, 0x0A, 0xC4, 0xF3, 0x03, 0x18, 0x04, 0xF0, 0x0F, 0x04, 0x4A, 0xDB, ++ 0x33, 0x4D, 0x34, 0x4F, 0x2E, 0x68, 0x2B, 0x68, 0x43, 0xF4, 0x80, 0x73, ++ 0x2B, 0x60, 0xD7, 0xF8, 0x00, 0xB0, 0x3B, 0x68, 0x23, 0xF0, 0x02, 0x03, ++ 0x3B, 0x60, 0x50, 0x46, 0xFF, 0xF7, 0xB2, 0xFC, 0xD9, 0xF8, 0x00, 0x10, ++ 0x01, 0xA8, 0xFF, 0xF7, 0x25, 0xFF, 0xFF, 0xF7, 0x0D, 0xFD, 0xC7, 0xF8, ++ 0x00, 0xB0, 0x2B, 0x68, 0x2B, 0x68, 0x06, 0xF4, 0x80, 0x76, 0x1E, 0x43, ++ 0xA0, 0x45, 0x2E, 0x60, 0x26, 0xD8, 0x25, 0x48, 0x0D, 0xF1, 0x05, 0x03, ++ 0xA4, 0xEB, 0x08, 0x04, 0x43, 0x44, 0x01, 0xAA, 0x42, 0x44, 0x53, 0xFA, ++ 0x84, 0xF4, 0x00, 0xEB, 0x08, 0x10, 0x15, 0x78, 0x53, 0x79, 0x92, 0xF8, ++ 0x0A, 0xC0, 0xD7, 0x7B, 0x16, 0x7D, 0x29, 0x06, 0x1B, 0x04, 0x01, 0xF0, ++ 0x70, 0x41, 0x43, 0xEA, 0x0C, 0x63, 0x41, 0xEA, 0x05, 0x51, 0x3B, 0x43, ++ 0x01, 0x32, 0x09, 0x0E, 0x43, 0xEA, 0x06, 0x23, 0xA2, 0x42, 0x80, 0xF8, ++ 0x07, 0x12, 0xC0, 0xF8, 0x00, 0x32, 0x00, 0xF1, 0x10, 0x00, 0xE4, 0xD1, ++ 0x09, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x12, 0xF0, 0x0C, 0x0F, 0x08, 0xD1, ++ 0xA0, 0x45, 0xAF, 0xD9, 0x0E, 0x49, 0x0F, 0x48, 0x41, 0xF2, 0x7F, 0x02, ++ 0x1F, 0xF0, 0xFA, 0xFF, 0xA8, 0xE7, 0x0B, 0x49, 0x0C, 0x48, 0x41, 0xF2, ++ 0x7E, 0x02, 0x1F, 0xF0, 0xF3, 0xFF, 0x2B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0xEB, 0xDB, 0x9C, 0xE7, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, ++ 0x68, 0x7C, 0x15, 0x00, 0x00, 0x04, 0x60, 0x40, 0x18, 0x00, 0x58, 0x40, ++ 0x1C, 0x13, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x88, 0x7C, 0x15, 0x00, ++ 0x78, 0x7C, 0x15, 0x00, 0x24, 0x4B, 0x25, 0x4A, 0x06, 0x21, 0x10, 0xB4, ++ 0xC3, 0xF8, 0x00, 0x11, 0x53, 0x68, 0x23, 0xF4, 0x80, 0x23, 0x53, 0x60, ++ 0x53, 0x68, 0x43, 0xF4, 0x00, 0x33, 0x53, 0x60, 0x13, 0x6B, 0x03, 0xF0, ++ 0x44, 0x03, 0x04, 0x2B, 0xFA, 0xD1, 0x1D, 0x4B, 0x1D, 0x4C, 0x1B, 0x68, ++ 0x1D, 0x48, 0x19, 0x49, 0xA4, 0xFB, 0x03, 0x43, 0x9B, 0x0C, 0x43, 0xF0, ++ 0x00, 0x44, 0x44, 0xF4, 0xA0, 0x14, 0x43, 0xF4, 0xA0, 0x13, 0x03, 0x60, ++ 0x04, 0x60, 0x03, 0x60, 0x53, 0x68, 0x5D, 0xF8, 0x04, 0x4B, 0x43, 0xF4, ++ 0xC4, 0x33, 0x43, 0xF0, 0x02, 0x03, 0x4F, 0xF4, 0x80, 0x50, 0x53, 0x60, ++ 0xC1, 0xF8, 0x34, 0x01, 0x13, 0x68, 0x43, 0xF0, 0x40, 0x03, 0x13, 0x60, ++ 0x4B, 0x6F, 0x43, 0xF0, 0x01, 0x03, 0x4B, 0x67, 0x53, 0x6C, 0x43, 0xF0, ++ 0x08, 0x43, 0x53, 0x64, 0x53, 0x6D, 0x23, 0xF4, 0x00, 0x13, 0x53, 0x65, ++ 0x53, 0x6D, 0x43, 0xF0, 0x02, 0x03, 0x53, 0x65, 0x53, 0x6D, 0x23, 0xF4, ++ 0x00, 0x63, 0x53, 0x65, 0x70, 0x47, 0x00, 0xBF, 0x00, 0x00, 0x50, 0x40, ++ 0x00, 0x60, 0x50, 0x40, 0x18, 0x13, 0x17, 0x00, 0x83, 0xDE, 0x1B, 0x43, ++ 0x08, 0x00, 0x58, 0x40, 0x3B, 0x4A, 0x3C, 0x48, 0x13, 0x68, 0x3C, 0x49, ++ 0xDF, 0xF8, 0x24, 0xC1, 0x43, 0xF0, 0x7C, 0x53, 0xF0, 0xB4, 0x13, 0x60, ++ 0x39, 0x4C, 0x3A, 0x4B, 0x23, 0x60, 0x03, 0xF1, 0xBE, 0x43, 0xA3, 0xF5, ++ 0x69, 0x03, 0xA3, 0xF6, 0x77, 0x33, 0x03, 0x60, 0x36, 0x4B, 0x0B, 0x60, ++ 0x36, 0x4F, 0x37, 0x4E, 0x37, 0x4D, 0x40, 0xF6, 0x77, 0x13, 0xCC, 0xF8, ++ 0x00, 0x30, 0x36, 0x4B, 0x3B, 0x60, 0x04, 0xF5, 0x00, 0x24, 0x01, 0xF5, ++ 0x2F, 0x11, 0x00, 0xF5, 0x2F, 0x10, 0x49, 0xF2, 0x02, 0x43, 0x02, 0xF5, ++ 0x00, 0x22, 0x33, 0x60, 0x0C, 0x34, 0x30, 0x4B, 0x2B, 0x60, 0x01, 0xF5, ++ 0x05, 0x61, 0x00, 0xF6, 0x58, 0x00, 0x02, 0xF6, 0x7C, 0x02, 0x07, 0xF5, ++ 0x2F, 0x17, 0x2C, 0x4D, 0x25, 0x60, 0x07, 0xF6, 0x68, 0x07, 0x0B, 0x60, ++ 0x06, 0xF5, 0x37, 0x16, 0x03, 0x60, 0x13, 0x60, 0x40, 0xF6, 0x34, 0x03, ++ 0x3B, 0x60, 0x06, 0xF2, 0xE4, 0x46, 0x26, 0x4B, 0x33, 0x60, 0x01, 0xF5, ++ 0xFE, 0x31, 0x03, 0xF1, 0x50, 0x53, 0x88, 0x31, 0x03, 0xF5, 0x54, 0x13, ++ 0x0F, 0x33, 0x0B, 0x60, 0x00, 0xF5, 0xFE, 0x30, 0x03, 0xF1, 0x48, 0x43, ++ 0x1F, 0x4D, 0x00, 0xF5, 0x90, 0x70, 0x02, 0xF5, 0xFE, 0x32, 0xA3, 0xF5, ++ 0x78, 0x13, 0x02, 0xF5, 0xB4, 0x72, 0xA3, 0xF2, 0x1F, 0x63, 0x4F, 0xF0, ++ 0x36, 0x36, 0x2B, 0x60, 0x06, 0x60, 0x4F, 0xF4, 0x7F, 0x40, 0x10, 0x60, ++ 0x04, 0xF5, 0x01, 0x34, 0x02, 0xF1, 0xAC, 0x42, 0x20, 0x34, 0x15, 0x4B, ++ 0x15, 0x4D, 0x25, 0x60, 0xA2, 0xF5, 0xB5, 0x12, 0x45, 0xF2, 0x55, 0x30, ++ 0xA2, 0xF6, 0x8A, 0x62, 0xC1, 0xF8, 0xA8, 0x00, 0xF0, 0xBC, 0x1A, 0x60, ++ 0x70, 0x47, 0x00, 0xBF, 0x0C, 0x00, 0x58, 0x40, 0x2C, 0x40, 0x34, 0x40, ++ 0x30, 0x40, 0x34, 0x40, 0x04, 0x01, 0x58, 0x40, 0xFB, 0x23, 0x09, 0x00, ++ 0x08, 0x51, 0x2E, 0x1A, 0x24, 0x40, 0x34, 0x40, 0x28, 0x40, 0x34, 0x40, ++ 0x8C, 0x04, 0x60, 0x40, 0x94, 0xC5, 0x2E, 0x00, 0x34, 0x08, 0x50, 0x00, ++ 0x58, 0x00, 0x7E, 0x02, 0x13, 0x20, 0x20, 0x20, 0xA0, 0x05, 0x62, 0x40, ++ 0x1C, 0x05, 0x62, 0x40, 0x0F, 0x12, 0x15, 0x0C, 0x20, 0x40, 0x34, 0x40, ++ 0x63, 0x49, 0x64, 0x4A, 0x0B, 0x68, 0x23, 0xF4, 0x00, 0x63, 0xF0, 0xB4, ++ 0x0B, 0x60, 0x13, 0x68, 0x23, 0xF4, 0x80, 0x73, 0x13, 0x60, 0x32, 0x23, ++ 0x00, 0xBF, 0x01, 0x3B, 0x9B, 0xB2, 0x00, 0x2B, 0xFA, 0xD1, 0xDF, 0xF8, ++ 0x6C, 0xC1, 0x5B, 0x4A, 0xDC, 0xF8, 0x00, 0x30, 0x5A, 0x4F, 0x5B, 0x4E, ++ 0x23, 0xF4, 0x80, 0x53, 0xCC, 0xF8, 0x00, 0x30, 0x13, 0x68, 0x23, 0xF4, ++ 0x00, 0x73, 0x13, 0x60, 0xDC, 0xF8, 0x00, 0x30, 0x43, 0xF4, 0x80, 0x63, ++ 0xCC, 0xF8, 0x00, 0x30, 0xDC, 0xF8, 0x00, 0x30, 0x43, 0xF4, 0x00, 0x63, ++ 0xCC, 0xF8, 0x00, 0x30, 0x62, 0x46, 0xFF, 0x25, 0x2B, 0x1D, 0x2C, 0x46, ++ 0xDD, 0xB2, 0x29, 0x46, 0x38, 0x46, 0x13, 0x68, 0x23, 0xF0, 0xFF, 0x03, ++ 0x0B, 0x43, 0x13, 0x60, 0x50, 0xF8, 0x04, 0x3B, 0x33, 0x60, 0x13, 0x68, ++ 0x43, 0xF4, 0x80, 0x73, 0x13, 0x60, 0x00, 0xBF, 0x00, 0xBF, 0x00, 0xBF, ++ 0x00, 0xBF, 0x13, 0x68, 0x9B, 0x04, 0xFC, 0xD5, 0x01, 0x39, 0xC9, 0xB2, ++ 0xA1, 0x42, 0xE8, 0xD1, 0x8F, 0x2D, 0x07, 0xF1, 0x10, 0x07, 0xDF, 0xD1, ++ 0xDC, 0xF8, 0x00, 0x30, 0x23, 0xF4, 0x80, 0x63, 0xCC, 0xF8, 0x00, 0x30, ++ 0xC8, 0x23, 0x00, 0xBF, 0x01, 0x3B, 0x9B, 0xB2, 0x00, 0x2B, 0xFA, 0xD1, ++ 0x36, 0x4D, 0x37, 0x49, 0x2A, 0x68, 0x39, 0x48, 0x39, 0x4C, 0x22, 0xF4, ++ 0x00, 0x62, 0x2A, 0x60, 0x0A, 0x68, 0x42, 0xF0, 0x80, 0x02, 0x0A, 0x60, ++ 0x0A, 0x68, 0x42, 0xF4, 0x80, 0x72, 0x0A, 0x60, 0x0A, 0x68, 0x22, 0xF0, ++ 0x1F, 0x02, 0x1A, 0x43, 0x0A, 0x60, 0x50, 0xF8, 0x04, 0x2F, 0x22, 0x60, ++ 0x0A, 0x68, 0x42, 0xF0, 0x20, 0x02, 0x0A, 0x60, 0x00, 0xBF, 0x00, 0xBF, ++ 0x00, 0xBF, 0x00, 0xBF, 0x0A, 0x68, 0x52, 0x05, 0xFC, 0xD5, 0x01, 0x33, ++ 0x20, 0x2B, 0xE9, 0xD1, 0x0B, 0x68, 0x23, 0xF0, 0x80, 0x03, 0x0B, 0x60, ++ 0xC8, 0x23, 0x00, 0xBF, 0x01, 0x3B, 0x9B, 0xB2, 0x00, 0x2B, 0xFA, 0xD1, ++ 0x1F, 0x4C, 0x24, 0x48, 0x22, 0x68, 0x24, 0x49, 0x24, 0x4D, 0x22, 0xF4, ++ 0x80, 0x72, 0x22, 0x60, 0x02, 0x68, 0x22, 0xF0, 0x02, 0x02, 0x02, 0x60, ++ 0x0A, 0x68, 0x22, 0xF0, 0x80, 0x62, 0x0A, 0x60, 0x32, 0x22, 0x2B, 0x60, ++ 0x00, 0xBF, 0x01, 0x3A, 0x92, 0xB2, 0x00, 0x2A, 0xFA, 0xD1, 0x13, 0x49, ++ 0x13, 0x4A, 0x08, 0x68, 0x1A, 0x4D, 0x1B, 0x4C, 0x1B, 0x4B, 0x40, 0xF4, ++ 0x80, 0x50, 0x08, 0x60, 0x08, 0x68, 0x40, 0xF4, 0x00, 0x60, 0x08, 0x60, ++ 0x11, 0x68, 0x41, 0xF4, 0x00, 0x71, 0x11, 0x60, 0x11, 0x68, 0x41, 0xF4, ++ 0x80, 0x71, 0x11, 0x60, 0x2A, 0x68, 0x42, 0xF4, 0x80, 0x52, 0x2A, 0x60, ++ 0x22, 0x68, 0x22, 0xF4, 0x80, 0x22, 0x22, 0x60, 0x1A, 0x68, 0x22, 0xF0, ++ 0x00, 0x52, 0x1A, 0x60, 0x1A, 0x68, 0x42, 0xF0, 0x80, 0x42, 0xF0, 0xBC, ++ 0x1A, 0x60, 0x70, 0x47, 0x60, 0x40, 0x34, 0x40, 0x6C, 0x40, 0x34, 0x40, ++ 0x1C, 0x13, 0x17, 0x00, 0x64, 0x40, 0x34, 0x40, 0x18, 0x18, 0x17, 0x00, ++ 0x70, 0x40, 0x34, 0x40, 0x18, 0x00, 0x58, 0x40, 0x58, 0x40, 0x34, 0x40, ++ 0x08, 0x40, 0x34, 0x40, 0x14, 0x20, 0x34, 0x40, 0x18, 0x20, 0x34, 0x40, ++ 0x1C, 0x20, 0x34, 0x40, 0x10, 0xB5, 0x09, 0x4C, 0x82, 0xB0, 0xD4, 0xF8, ++ 0xC0, 0x34, 0x01, 0x90, 0x98, 0x47, 0xD4, 0xF8, 0xC4, 0x34, 0x98, 0x47, ++ 0xD4, 0xF8, 0xC8, 0x34, 0x98, 0x47, 0xD4, 0xF8, 0xCC, 0x34, 0x00, 0x21, ++ 0x01, 0xA8, 0x98, 0x47, 0x02, 0xB0, 0x10, 0xBD, 0x88, 0x1A, 0x17, 0x00, ++ 0x10, 0xB5, 0x2D, 0x4C, 0x23, 0x68, 0x1B, 0x78, 0x02, 0x2B, 0x17, 0xD0, ++ 0x0F, 0x24, 0x4F, 0xF4, 0x00, 0x62, 0x11, 0x46, 0x29, 0x48, 0xFD, 0xF7, ++ 0x61, 0xFA, 0x4F, 0xF4, 0x40, 0x72, 0x28, 0x48, 0x00, 0x21, 0xFD, 0xF7, ++ 0x5B, 0xFA, 0x21, 0x46, 0x26, 0x48, 0xFD, 0xF7, 0x2F, 0xFA, 0x02, 0x22, ++ 0xBD, 0xE8, 0x10, 0x40, 0x24, 0x48, 0x11, 0x46, 0xFD, 0xF7, 0x50, 0xBA, ++ 0x04, 0xF0, 0x2E, 0xFD, 0x22, 0x4B, 0x4F, 0xF4, 0x00, 0x42, 0xC3, 0xF8, ++ 0x80, 0x20, 0xBF, 0xF3, 0x4F, 0x8F, 0xBF, 0xF3, 0x6F, 0x8F, 0x1F, 0x48, ++ 0x1F, 0xF0, 0x52, 0xFB, 0x1E, 0x4A, 0xD2, 0xF8, 0x04, 0x38, 0x43, 0xF0, ++ 0x02, 0x03, 0xC2, 0xF8, 0x04, 0x38, 0x13, 0x69, 0x43, 0xF0, 0x01, 0x03, ++ 0x13, 0x61, 0x13, 0x69, 0xDB, 0x07, 0xFC, 0xD4, 0x18, 0x48, 0x1F, 0xF0, ++ 0x41, 0xFB, 0x18, 0x4A, 0x18, 0x48, 0x4F, 0xF4, 0x00, 0x21, 0xFD, 0xF7, ++ 0x2B, 0xFA, 0x17, 0x4B, 0x4F, 0xF4, 0x80, 0x61, 0x4F, 0xF4, 0x00, 0x02, ++ 0xC3, 0xF8, 0x28, 0x11, 0xC3, 0xF8, 0x18, 0x21, 0x23, 0x68, 0x1B, 0x78, ++ 0x02, 0x2B, 0xB5, 0xD1, 0x04, 0xF0, 0xB6, 0xFE, 0x00, 0x28, 0xB1, 0xD0, ++ 0x0F, 0x4B, 0x10, 0x48, 0xD3, 0xF8, 0x00, 0x41, 0x21, 0x46, 0x1F, 0xF0, ++ 0x23, 0xFB, 0xAA, 0xE7, 0x78, 0x36, 0x17, 0x00, 0x0C, 0x88, 0x01, 0x50, ++ 0x14, 0x88, 0x01, 0x50, 0x00, 0x70, 0x01, 0x50, 0x08, 0x70, 0x01, 0x50, ++ 0x00, 0xE1, 0x00, 0xE0, 0x9C, 0x7C, 0x15, 0x00, 0x00, 0x00, 0x20, 0x40, ++ 0xA8, 0x7C, 0x15, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x90, 0x01, 0x50, ++ 0x00, 0x00, 0x10, 0x40, 0x2C, 0x19, 0x17, 0x00, 0xB8, 0x7C, 0x15, 0x00, ++ 0x38, 0xB5, 0x36, 0x4C, 0x36, 0x48, 0x44, 0x22, 0x00, 0x21, 0xFB, 0xF7, ++ 0x91, 0xF8, 0x23, 0x68, 0x1A, 0x07, 0xC3, 0xF3, 0xC0, 0x01, 0x51, 0xD5, ++ 0x22, 0x46, 0x00, 0xBF, 0x13, 0x68, 0xDB, 0x06, 0xFB, 0xD5, 0x30, 0x4D, ++ 0x30, 0x48, 0x29, 0x68, 0x30, 0x4B, 0x00, 0x68, 0x30, 0x4A, 0xC1, 0xF8, ++ 0x44, 0x02, 0x00, 0x21, 0x19, 0x60, 0x11, 0x60, 0x19, 0x68, 0x2E, 0x48, ++ 0x2E, 0x4C, 0x21, 0xF0, 0x03, 0x01, 0x41, 0xF0, 0x02, 0x01, 0x19, 0x60, ++ 0x19, 0x68, 0x21, 0xF0, 0x0C, 0x01, 0x41, 0xF0, 0x08, 0x01, 0x19, 0x60, ++ 0x19, 0x68, 0x21, 0xF4, 0x40, 0x71, 0x41, 0xF4, 0x00, 0x71, 0x19, 0x60, ++ 0x19, 0x68, 0x21, 0xF4, 0x40, 0x61, 0x41, 0xF4, 0x00, 0x61, 0x19, 0x60, ++ 0x19, 0x68, 0x21, 0xF4, 0x40, 0x51, 0x41, 0xF4, 0x00, 0x51, 0x19, 0x60, ++ 0x11, 0x68, 0x21, 0xF0, 0x40, 0x51, 0x41, 0xF0, 0x00, 0x51, 0x11, 0x60, ++ 0x11, 0x68, 0x21, 0xF0, 0x40, 0x41, 0x41, 0xF0, 0x00, 0x41, 0x11, 0x60, ++ 0x1A, 0x68, 0x42, 0xF4, 0x40, 0x32, 0x1A, 0x60, 0x1A, 0x68, 0x42, 0xF4, ++ 0x40, 0x22, 0x1A, 0x60, 0x1A, 0x68, 0x42, 0xF4, 0x40, 0x12, 0x1A, 0x60, ++ 0x1A, 0x68, 0x42, 0xF4, 0x40, 0x02, 0x1A, 0x60, 0x1A, 0x68, 0x42, 0xF0, ++ 0x40, 0x72, 0x1A, 0x60, 0x04, 0x60, 0x38, 0xBD, 0x23, 0x68, 0x09, 0x4D, ++ 0x43, 0xF0, 0x08, 0x03, 0x23, 0x60, 0x28, 0x68, 0x4F, 0xF4, 0x12, 0x72, ++ 0xFB, 0xF7, 0x30, 0xF8, 0x23, 0x68, 0x43, 0xF0, 0x10, 0x03, 0x23, 0x60, ++ 0xA4, 0xE7, 0x00, 0xBF, 0x80, 0x40, 0x04, 0x40, 0x04, 0x35, 0x17, 0x00, ++ 0x00, 0x38, 0x18, 0x00, 0x84, 0x1A, 0x17, 0x00, 0x14, 0x41, 0x04, 0x40, ++ 0x18, 0x41, 0x04, 0x40, 0x0C, 0x41, 0x04, 0x40, 0x33, 0x1F, 0x00, 0xC0, ++ 0x0C, 0x4B, 0x10, 0xB5, 0x1C, 0x68, 0x14, 0xF4, 0xF8, 0x54, 0x00, 0xD1, ++ 0x10, 0xBD, 0x60, 0x08, 0x1E, 0xF0, 0x02, 0xF8, 0x08, 0x4A, 0x09, 0x49, ++ 0x09, 0x4B, 0x0C, 0x60, 0x14, 0x60, 0x1A, 0x78, 0x00, 0x2A, 0xF3, 0xD0, ++ 0x07, 0x4A, 0x01, 0x21, 0x59, 0x70, 0x13, 0x68, 0x0B, 0x43, 0x13, 0x60, ++ 0x10, 0xBD, 0x00, 0xBF, 0x1C, 0x41, 0x04, 0x40, 0x08, 0x41, 0x04, 0x40, ++ 0x10, 0x41, 0x04, 0x40, 0x3C, 0x36, 0x17, 0x00, 0x10, 0x00, 0x58, 0x40, ++ 0x2D, 0xE9, 0xF8, 0x4F, 0x29, 0x4B, 0x06, 0x46, 0x53, 0xF8, 0x20, 0x00, ++ 0x1E, 0xF0, 0x04, 0xF8, 0x27, 0x4A, 0x13, 0x68, 0x00, 0x2B, 0xFC, 0xD0, ++ 0x26, 0x4B, 0xD3, 0xF8, 0x00, 0xA0, 0xDA, 0xF8, 0x3C, 0x32, 0x0A, 0xF5, ++ 0x0F, 0x7B, 0x8B, 0xB3, 0x23, 0x4D, 0xDF, 0xF8, 0x98, 0x90, 0xDF, 0xF8, ++ 0x98, 0x80, 0x05, 0xF2, 0x14, 0x57, 0x1D, 0xE0, 0x95, 0xF8, 0x10, 0x35, ++ 0x85, 0xF8, 0x11, 0x45, 0x01, 0x33, 0xA9, 0xFB, 0x03, 0x24, 0xA4, 0x09, ++ 0x04, 0xEB, 0xC4, 0x04, 0x04, 0xEB, 0xC4, 0x04, 0x1C, 0x1B, 0x85, 0xF8, ++ 0x10, 0x45, 0x1E, 0xF0, 0xA1, 0xF8, 0xD8, 0xF8, 0x00, 0x20, 0x05, 0xEB, ++ 0x04, 0x11, 0x02, 0x44, 0xC1, 0xE9, 0x01, 0x26, 0x38, 0x46, 0x1E, 0xF0, ++ 0x53, 0xF8, 0xDA, 0xF8, 0x3C, 0x32, 0x5B, 0xB1, 0x95, 0xF8, 0x11, 0x15, ++ 0x95, 0xF8, 0x12, 0x25, 0x91, 0x42, 0x58, 0x46, 0x01, 0xF1, 0x01, 0x04, ++ 0xD8, 0xD3, 0x0D, 0x48, 0x01, 0xF0, 0x54, 0xF8, 0x08, 0x4B, 0x01, 0x24, ++ 0x1C, 0x60, 0x20, 0x20, 0x08, 0x36, 0x1D, 0xF0, 0x9B, 0xFF, 0x04, 0xFA, ++ 0x06, 0xF6, 0x08, 0x4B, 0x06, 0xF4, 0xF8, 0x56, 0x1E, 0x60, 0xBD, 0xE8, ++ 0xF8, 0x8F, 0x00, 0xBF, 0x80, 0x7E, 0x15, 0x00, 0x4C, 0x40, 0x04, 0x40, ++ 0x00, 0x38, 0x18, 0x00, 0x58, 0x58, 0x17, 0x00, 0xCC, 0x7C, 0x15, 0x00, ++ 0x0C, 0x41, 0x04, 0x40, 0xE7, 0x87, 0x45, 0xCA, 0x84, 0x1A, 0x17, 0x00, ++ 0x1D, 0x4B, 0x10, 0xB5, 0x1C, 0x68, 0xA0, 0x06, 0x2C, 0xD4, 0xE1, 0x06, ++ 0x20, 0xD4, 0xA2, 0x07, 0x16, 0xD4, 0x63, 0x00, 0x08, 0xD5, 0x19, 0x4B, ++ 0x01, 0x20, 0xD3, 0xF8, 0x78, 0x34, 0x98, 0x47, 0x17, 0x4B, 0x4F, 0xF0, ++ 0x80, 0x42, 0x1A, 0x60, 0x00, 0x2C, 0x00, 0xDB, 0x10, 0xBD, 0x13, 0x4B, ++ 0xD3, 0xF8, 0x68, 0x34, 0x98, 0x47, 0x12, 0x4B, 0x4F, 0xF0, 0x00, 0x42, ++ 0x1A, 0x60, 0x10, 0xBD, 0x4F, 0xF0, 0x80, 0x50, 0x1D, 0xF0, 0x5E, 0xFF, ++ 0x0E, 0x4B, 0x02, 0x22, 0x1A, 0x60, 0xE0, 0xE7, 0x0C, 0x49, 0x0B, 0x4A, ++ 0x10, 0x23, 0x0B, 0x60, 0x4F, 0xF4, 0x00, 0x10, 0x13, 0x60, 0x1D, 0xF0, ++ 0x51, 0xFF, 0xD4, 0xE7, 0x07, 0x49, 0x06, 0x4A, 0x20, 0x23, 0x0B, 0x60, ++ 0x4F, 0xF4, 0x80, 0x10, 0x13, 0x60, 0x1D, 0xF0, 0x47, 0xFF, 0xC8, 0xE7, ++ 0x1C, 0x41, 0x04, 0x40, 0x88, 0x1A, 0x17, 0x00, 0x08, 0x41, 0x04, 0x40, ++ 0x10, 0x41, 0x04, 0x40, 0x06, 0x4A, 0x07, 0x49, 0x12, 0x68, 0xD2, 0xF8, ++ 0x24, 0x02, 0x20, 0x23, 0x0B, 0x60, 0x08, 0xB1, 0x01, 0x20, 0x70, 0x47, ++ 0x03, 0x4A, 0x13, 0x60, 0x70, 0x47, 0x00, 0xBF, 0x00, 0x38, 0x18, 0x00, ++ 0x08, 0x41, 0x04, 0x40, 0x0C, 0x41, 0x04, 0x40, 0x10, 0xB5, 0x15, 0x4C, ++ 0x23, 0x68, 0x00, 0x2B, 0xFC, 0xD0, 0x14, 0x4B, 0x18, 0x68, 0xD0, 0xF8, ++ 0x24, 0x32, 0xBB, 0xB1, 0x00, 0xF5, 0x09, 0x70, 0x1E, 0xF0, 0x02, 0xF8, ++ 0x10, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x01, 0x22, 0x00, 0x2B, ++ 0x22, 0x60, 0x01, 0xDB, 0x14, 0x30, 0x10, 0xBD, 0x00, 0x28, 0xFB, 0xD1, ++ 0x0B, 0x49, 0x0C, 0x48, 0x40, 0xF2, 0x92, 0x32, 0x1F, 0xF0, 0x00, 0xFC, ++ 0x14, 0x20, 0x10, 0xBD, 0x06, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x01, 0x22, 0x00, 0x2B, 0x22, 0x60, 0xF5, 0xDA, 0xEE, 0xE7, 0x00, 0xBF, ++ 0x54, 0x40, 0x04, 0x40, 0x00, 0x38, 0x18, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xE4, 0x7C, 0x15, 0x00, 0x10, 0xB5, 0x0A, 0x4C, ++ 0x23, 0x68, 0x00, 0x2B, 0xFC, 0xD0, 0x09, 0x4B, 0x1B, 0x68, 0xD3, 0xF8, ++ 0x14, 0x02, 0x40, 0xB1, 0x03, 0xF5, 0x05, 0x70, 0x1D, 0xF0, 0xCC, 0xFF, ++ 0x01, 0x23, 0x23, 0x60, 0x00, 0xB1, 0x04, 0x30, 0x10, 0xBD, 0x01, 0x23, ++ 0x23, 0x60, 0x10, 0xBD, 0x58, 0x40, 0x04, 0x40, 0x00, 0x38, 0x18, 0x00, ++ 0x70, 0x47, 0x00, 0xBF, 0x01, 0x4B, 0x08, 0x22, 0x1A, 0x60, 0x70, 0x47, ++ 0x00, 0x41, 0x04, 0x40, 0x02, 0x4B, 0x4F, 0xF4, 0x80, 0x72, 0x1A, 0x60, ++ 0x70, 0x47, 0x00, 0xBF, 0x00, 0x41, 0x04, 0x40, 0x01, 0x4B, 0x80, 0x22, ++ 0x1A, 0x60, 0x70, 0x47, 0x00, 0x41, 0x04, 0x40, 0xF8, 0xB5, 0x04, 0x46, ++ 0x40, 0x89, 0x29, 0x4F, 0x10, 0x30, 0x1D, 0xF0, 0xA3, 0xFB, 0x3E, 0x68, ++ 0xB6, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x05, 0x46, 0x22, 0xDB, 0xA3, 0x88, ++ 0x62, 0x89, 0xE0, 0x88, 0xAB, 0x80, 0x00, 0x21, 0x0C, 0x23, 0x2B, 0x81, ++ 0x6A, 0x81, 0xE8, 0x80, 0x29, 0x60, 0xE3, 0x18, 0x62, 0xB1, 0x01, 0x3A, ++ 0x22, 0xF0, 0x03, 0x02, 0x10, 0x32, 0x14, 0x44, 0x05, 0xF1, 0x08, 0x02, ++ 0x53, 0xF8, 0x04, 0x1B, 0x42, 0xF8, 0x04, 0x1F, 0xA3, 0x42, 0xF9, 0xD1, ++ 0xB6, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x0F, 0xDB, 0x05, 0xF1, 0x0C, 0x00, ++ 0xBD, 0xE8, 0xF8, 0x40, 0x1D, 0xF0, 0xD8, 0xBA, 0x00, 0x28, 0xDA, 0xD1, ++ 0x12, 0x49, 0x13, 0x48, 0x40, 0xF2, 0x6F, 0x42, 0x1F, 0xF0, 0x82, 0xFB, ++ 0x3E, 0x68, 0xD2, 0xE7, 0x0D, 0x28, 0x0D, 0xD8, 0x0B, 0x28, 0xEB, 0xD9, ++ 0x0C, 0x49, 0x0E, 0x48, 0x4F, 0xF4, 0x90, 0x62, 0x1F, 0xF0, 0x76, 0xFB, ++ 0x05, 0xF1, 0x0C, 0x00, 0xBD, 0xE8, 0xF8, 0x40, 0x1D, 0xF0, 0xBE, 0xBA, ++ 0x06, 0x49, 0x09, 0x48, 0xBB, 0x22, 0x1F, 0xF0, 0x6B, 0xFB, 0x04, 0x49, ++ 0x05, 0x48, 0x4F, 0xF4, 0x90, 0x62, 0x1F, 0xF0, 0x65, 0xFB, 0xED, 0xE7, ++ 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0xFC, 0x7C, 0x15, 0x00, ++ 0x20, 0x7D, 0x15, 0x00, 0x10, 0x7D, 0x15, 0x00, 0xF8, 0xB5, 0x05, 0x46, ++ 0x40, 0x89, 0x2B, 0x4F, 0x10, 0x30, 0x1D, 0xF0, 0x43, 0xFB, 0x3E, 0x68, ++ 0xB6, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x04, 0x46, 0x2A, 0xDB, 0xAB, 0x88, ++ 0x6A, 0x89, 0xEF, 0x88, 0xA3, 0x80, 0x00, 0x21, 0x0C, 0x23, 0x23, 0x81, ++ 0x62, 0x81, 0xE7, 0x80, 0x21, 0x60, 0xEB, 0x18, 0x62, 0xB1, 0x01, 0x3A, ++ 0x22, 0xF0, 0x03, 0x02, 0x10, 0x32, 0x2A, 0x44, 0x04, 0xF1, 0x08, 0x01, ++ 0x53, 0xF8, 0x04, 0x0B, 0x41, 0xF8, 0x04, 0x0F, 0x93, 0x42, 0xF9, 0xD1, ++ 0x1A, 0x4A, 0x53, 0x7D, 0x59, 0x1C, 0x51, 0x75, 0x2B, 0x81, 0xB6, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0x12, 0xDB, 0x17, 0x4B, 0x04, 0x22, 0x04, 0xF1, ++ 0x0C, 0x00, 0x1A, 0x60, 0xBD, 0xE8, 0xF8, 0x40, 0x1D, 0xF0, 0x70, 0xBA, ++ 0x00, 0x28, 0xD2, 0xD1, 0x12, 0x49, 0x13, 0x48, 0x40, 0xF2, 0x8E, 0x42, ++ 0x1F, 0xF0, 0x1A, 0xFB, 0x3E, 0x68, 0xCA, 0xE7, 0x0D, 0x2F, 0x08, 0xD8, ++ 0x0B, 0x2F, 0xE8, 0xD9, 0x0C, 0x49, 0x0E, 0x48, 0x40, 0xF2, 0xA3, 0x42, ++ 0x1F, 0xF0, 0x0E, 0xFB, 0xE1, 0xE7, 0x09, 0x49, 0x0B, 0x48, 0xBB, 0x22, ++ 0x1F, 0xF0, 0x08, 0xFB, 0x06, 0x49, 0x08, 0x48, 0x40, 0xF2, 0xA3, 0x42, ++ 0x1F, 0xF0, 0x02, 0xFB, 0xD5, 0xE7, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, ++ 0x04, 0x35, 0x17, 0x00, 0x00, 0x41, 0x04, 0x40, 0x70, 0x79, 0x15, 0x00, ++ 0xFC, 0x7C, 0x15, 0x00, 0x20, 0x7D, 0x15, 0x00, 0x10, 0x7D, 0x15, 0x00, ++ 0xF8, 0xB5, 0x0B, 0x4C, 0x23, 0x68, 0x9A, 0x07, 0x0A, 0xD5, 0x0A, 0x4F, ++ 0x0A, 0x4E, 0x02, 0x25, 0x38, 0x68, 0x35, 0x60, 0x04, 0x30, 0xFF, 0xF7, ++ 0x8B, 0xFF, 0x23, 0x68, 0x9B, 0x07, 0xF7, 0xD4, 0x4F, 0xF0, 0x80, 0x50, ++ 0x1D, 0xF0, 0x0C, 0xFE, 0x04, 0x4B, 0x02, 0x22, 0x1A, 0x60, 0xF8, 0xBD, ++ 0x04, 0x41, 0x04, 0x40, 0x00, 0x38, 0x18, 0x00, 0x08, 0x41, 0x04, 0x40, ++ 0x0C, 0x41, 0x04, 0x40, 0x2D, 0xE9, 0xF0, 0x47, 0xDF, 0xF8, 0x20, 0x93, ++ 0xD9, 0xF8, 0x00, 0x20, 0x13, 0x78, 0x03, 0x2B, 0x82, 0xB0, 0x04, 0x46, ++ 0x00, 0xF0, 0x16, 0x81, 0x00, 0x27, 0x3E, 0x46, 0x01, 0x2B, 0x00, 0xF0, ++ 0xC2, 0x80, 0x02, 0x2B, 0x4F, 0xF0, 0x00, 0x05, 0x00, 0xF0, 0xD3, 0x80, ++ 0x62, 0x89, 0xA3, 0x88, 0x33, 0x80, 0xF2, 0x80, 0x7A, 0xB9, 0xD9, 0xF8, ++ 0x00, 0x30, 0x1B, 0x78, 0x03, 0x2B, 0x1C, 0xD0, 0x02, 0x2B, 0x2F, 0xD0, ++ 0x01, 0x2B, 0x00, 0xF0, 0x89, 0x80, 0x20, 0x46, 0x02, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x47, 0x1D, 0xF0, 0x41, 0xBA, 0xA3, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0xC0, 0xF2, 0x20, 0x81, 0x06, 0xF1, 0x0C, 0x00, ++ 0x04, 0xF1, 0x0C, 0x01, 0x31, 0xF0, 0x40, 0xFD, 0xD9, 0xF8, 0x00, 0x30, ++ 0x1B, 0x78, 0x03, 0x2B, 0xE2, 0xD1, 0x9B, 0x4E, 0x33, 0x68, 0x00, 0x2B, ++ 0xFC, 0xD0, 0x9A, 0x4B, 0x18, 0x68, 0x39, 0x1F, 0x00, 0xF5, 0x03, 0x70, ++ 0x1D, 0xF0, 0x36, 0xFE, 0x97, 0x4B, 0x01, 0x21, 0x02, 0x22, 0x31, 0x60, ++ 0x1A, 0x60, 0xD9, 0xF8, 0x00, 0x30, 0x1B, 0x78, 0x02, 0x2B, 0xCF, 0xD1, ++ 0x60, 0x89, 0x10, 0xF0, 0x03, 0x03, 0x40, 0xF0, 0xE9, 0x80, 0x19, 0x46, ++ 0x9C, 0x46, 0x90, 0x4E, 0x42, 0xF2, 0x34, 0x03, 0xF2, 0x5A, 0xB2, 0xF5, ++ 0xC3, 0x7F, 0x00, 0xF2, 0xFD, 0x80, 0x57, 0x1C, 0xBF, 0xB2, 0x4F, 0xEA, ++ 0xC2, 0x0E, 0x8B, 0x4B, 0xA8, 0xF8, 0x0C, 0x20, 0xD3, 0xF8, 0x00, 0xA0, ++ 0x00, 0xF1, 0x10, 0x03, 0x0A, 0xEB, 0x0E, 0x00, 0x0C, 0xEB, 0x03, 0x02, ++ 0x45, 0x60, 0x2A, 0xF8, 0x0E, 0x20, 0xC2, 0x78, 0x02, 0xF0, 0x31, 0x02, ++ 0x42, 0xF0, 0x04, 0x02, 0xC2, 0x70, 0x96, 0xF8, 0x02, 0x2C, 0x42, 0xF2, ++ 0x34, 0x0C, 0x0B, 0x44, 0x01, 0x32, 0x01, 0x21, 0x4F, 0xF0, 0x00, 0x0E, ++ 0x26, 0xF8, 0x0C, 0x70, 0x86, 0xF8, 0x02, 0x2C, 0xC8, 0xE9, 0x01, 0x03, ++ 0x88, 0xF8, 0x0E, 0x10, 0xC8, 0xF8, 0x00, 0xE0, 0xEF, 0xF3, 0x10, 0x83, ++ 0xDB, 0x07, 0x02, 0xD4, 0x72, 0xB6, 0x76, 0x4B, 0x19, 0x60, 0x76, 0x4E, ++ 0x76, 0x48, 0x33, 0x68, 0x41, 0x46, 0x01, 0x33, 0x33, 0x60, 0x1D, 0xF0, ++ 0xE3, 0xFD, 0x74, 0x4B, 0xD3, 0xF8, 0x44, 0x34, 0x98, 0x47, 0x33, 0x68, ++ 0x33, 0xB1, 0x6E, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x33, 0x60, 0x0B, 0xB9, ++ 0x02, 0xB1, 0x62, 0xB6, 0xD9, 0xF8, 0x00, 0x30, 0x1B, 0x78, 0x01, 0x2B, ++ 0x7F, 0xF4, 0x77, 0xAF, 0x01, 0xF0, 0xF2, 0xFF, 0x00, 0x28, 0x00, 0xF0, ++ 0x0C, 0x81, 0xA1, 0x7A, 0x68, 0x4A, 0x0C, 0x31, 0x29, 0x70, 0x61, 0x89, ++ 0x0C, 0x31, 0x00, 0x27, 0x09, 0x12, 0x11, 0x26, 0x69, 0x70, 0xAE, 0x70, ++ 0xEF, 0x70, 0x61, 0x89, 0x86, 0x68, 0x47, 0x60, 0x10, 0x31, 0xC1, 0xF3, ++ 0x0B, 0x01, 0x32, 0x40, 0x0A, 0x43, 0x42, 0xF0, 0x00, 0x42, 0x05, 0x60, ++ 0x82, 0x60, 0x03, 0xF0, 0x35, 0xF8, 0x20, 0x46, 0x02, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x47, 0x1D, 0xF0, 0x99, 0xB9, 0x63, 0x89, 0x6C, 0x2B, 0x40, 0xF2, ++ 0x8C, 0x80, 0x58, 0x4B, 0x1B, 0x68, 0xD3, 0xE9, 0x01, 0x02, 0x13, 0x69, ++ 0x98, 0x47, 0x05, 0x46, 0x00, 0x2D, 0x00, 0xF0, 0x8A, 0x80, 0xD9, 0xF8, ++ 0x00, 0x30, 0x1B, 0x78, 0x02, 0x2B, 0x05, 0xF1, 0x04, 0x06, 0x7F, 0xF4, ++ 0x2D, 0xAF, 0x63, 0x89, 0x6C, 0x2B, 0x7A, 0xD9, 0x4D, 0x4B, 0x1B, 0x68, ++ 0xD3, 0xE9, 0x01, 0x02, 0x13, 0x69, 0x98, 0x47, 0x05, 0x46, 0x00, 0x2D, ++ 0x75, 0xD0, 0x42, 0x4A, 0x42, 0xF2, 0x24, 0x03, 0xD3, 0x58, 0x00, 0x2B, ++ 0x00, 0xF0, 0x9A, 0x80, 0xEF, 0xF3, 0x10, 0x83, 0xD9, 0x07, 0x03, 0xD4, ++ 0x72, 0xB6, 0x3E, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x3D, 0x4E, 0x42, 0x48, ++ 0x33, 0x68, 0x01, 0x33, 0x33, 0x60, 0x1D, 0xF0, 0xB7, 0xFD, 0x33, 0x68, ++ 0x80, 0x46, 0x33, 0xB1, 0x37, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x33, 0x60, ++ 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0xA3, 0x7A, 0x0C, 0x33, 0x2B, 0x70, ++ 0x63, 0x89, 0x0C, 0x33, 0x1B, 0x12, 0x11, 0x22, 0x6B, 0x70, 0x00, 0x23, ++ 0xAA, 0x70, 0xEB, 0x70, 0x2E, 0x1D, 0xF3, 0xE6, 0x28, 0x4D, 0x2B, 0x68, ++ 0x00, 0x2B, 0xFC, 0xD0, 0x27, 0x4B, 0x18, 0x68, 0xD0, 0xF8, 0x04, 0x32, ++ 0xD3, 0xB1, 0x00, 0xF5, 0x01, 0x70, 0x1D, 0xF0, 0x93, 0xFD, 0x21, 0x4B, ++ 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x01, 0x22, 0x00, 0x2B, 0x2A, 0x60, ++ 0xC0, 0xF2, 0x8B, 0x80, 0x07, 0x1D, 0xD9, 0xF8, 0x00, 0x20, 0x3E, 0x46, ++ 0x27, 0x4B, 0xB3, 0x60, 0x13, 0x78, 0xCD, 0xE6, 0xC3, 0xF1, 0x04, 0x03, ++ 0x5F, 0xFA, 0x83, 0xFC, 0x61, 0x46, 0x12, 0xE7, 0x15, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x01, 0x21, 0x00, 0x2B, 0x29, 0x60, 0xC0, 0xF2, ++ 0x82, 0x80, 0x04, 0x26, 0x37, 0x46, 0xE9, 0xE7, 0xB2, 0xF5, 0x80, 0x6F, ++ 0x7F, 0xF6, 0xDC, 0xAE, 0x4F, 0xF4, 0xB1, 0x62, 0x1A, 0x49, 0x1B, 0x48, ++ 0x1F, 0xF0, 0x76, 0xF9, 0x62, 0x89, 0xD3, 0xE6, 0x4F, 0xF0, 0x00, 0x0E, ++ 0x72, 0x46, 0x01, 0x27, 0x01, 0xE7, 0x01, 0xF0, 0xCF, 0xFF, 0x05, 0x46, ++ 0x76, 0xE7, 0x05, 0xF0, 0x2B, 0xF8, 0x05, 0x46, 0x87, 0xE7, 0xE3, 0x88, ++ 0x22, 0x89, 0xA1, 0x88, 0x11, 0x48, 0x00, 0xF0, 0x1D, 0xFD, 0xB2, 0xE6, ++ 0x38, 0x36, 0x17, 0x00, 0x50, 0x40, 0x04, 0x40, 0x00, 0x38, 0x18, 0x00, ++ 0x00, 0x41, 0x04, 0x40, 0x7C, 0x36, 0x17, 0x00, 0x54, 0x60, 0x17, 0x00, ++ 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0xA8, 0x56, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x00, 0xF0, 0xFF, 0x7F, 0x1C, 0x58, 0x17, 0x00, ++ 0xA0, 0x56, 0x17, 0x00, 0x2A, 0xDE, 0xDE, 0xAD, 0x70, 0x79, 0x15, 0x00, ++ 0xDC, 0x7D, 0x15, 0x00, 0x68, 0x7D, 0x15, 0x00, 0x78, 0x36, 0x17, 0x00, ++ 0xEF, 0xF3, 0x10, 0x83, 0xDA, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x20, 0x4B, ++ 0x01, 0x22, 0x1A, 0x60, 0x1F, 0x4D, 0x20, 0x4A, 0x2B, 0x68, 0xD2, 0xF8, ++ 0x44, 0x24, 0x01, 0x33, 0x2B, 0x60, 0x90, 0x47, 0x2A, 0x68, 0x03, 0x46, ++ 0x32, 0xB1, 0x19, 0x49, 0x01, 0x3A, 0x09, 0x68, 0x2A, 0x60, 0x0A, 0xB9, ++ 0x01, 0xB1, 0x62, 0xB6, 0x18, 0x48, 0x01, 0x93, 0x1D, 0xF0, 0x4E, 0xFD, ++ 0x00, 0x90, 0x17, 0x48, 0x1D, 0xF0, 0x4A, 0xFD, 0xDD, 0xE9, 0x00, 0x13, ++ 0x02, 0x46, 0x15, 0x48, 0x00, 0xF0, 0xD0, 0xFC, 0x65, 0xE6, 0x14, 0x48, ++ 0x00, 0xF0, 0xCC, 0xFC, 0x61, 0xE6, 0x60, 0xB1, 0x07, 0x1D, 0x7F, 0xF4, ++ 0x72, 0xAF, 0x40, 0xF2, 0x31, 0x52, 0x10, 0x49, 0x10, 0x48, 0x1F, 0xF0, ++ 0x05, 0xF9, 0x3E, 0x46, 0xD9, 0xF8, 0x00, 0x20, 0x6A, 0xE7, 0x40, 0xF2, ++ 0x26, 0x32, 0x0B, 0x49, 0x0C, 0x48, 0x04, 0x26, 0x1F, 0xF0, 0xFA, 0xF8, ++ 0x37, 0x46, 0xD9, 0xF8, 0x00, 0x20, 0x5F, 0xE7, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0xA0, 0x56, 0x17, 0x00, ++ 0xA8, 0x56, 0x17, 0x00, 0xA4, 0x7D, 0x15, 0x00, 0x08, 0x7E, 0x15, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x54, 0x7D, 0x15, 0x00, 0x44, 0x7D, 0x15, 0x00, ++ 0x10, 0xB4, 0x15, 0x49, 0x15, 0x4C, 0x16, 0x4B, 0x4F, 0xF4, 0x4C, 0x02, ++ 0x22, 0x60, 0x0A, 0x60, 0x1A, 0x68, 0x22, 0xF0, 0x30, 0x02, 0x1A, 0x60, ++ 0x1A, 0x68, 0x22, 0xF0, 0xC0, 0x02, 0x1A, 0x60, 0x1A, 0x68, 0x22, 0xF4, ++ 0x40, 0x52, 0x1A, 0x60, 0x1A, 0x68, 0x4F, 0xF0, 0x60, 0x50, 0x22, 0xF4, ++ 0x40, 0x42, 0x1A, 0x60, 0x20, 0x60, 0x08, 0x60, 0x1A, 0x68, 0x5D, 0xF8, ++ 0x04, 0x4B, 0x22, 0xF4, 0x40, 0x02, 0x1A, 0x60, 0x1A, 0x68, 0x22, 0xF0, ++ 0x40, 0x72, 0x1A, 0x60, 0x1A, 0x68, 0x22, 0xF0, 0x40, 0x62, 0x1A, 0x60, ++ 0x70, 0x47, 0x00, 0xBF, 0x0C, 0x40, 0x04, 0x40, 0x08, 0x40, 0x04, 0x40, ++ 0x18, 0x40, 0x04, 0x40, 0x10, 0xB5, 0x01, 0x46, 0x04, 0x46, 0x05, 0x48, ++ 0x1E, 0xF0, 0x30, 0xFE, 0x04, 0x4A, 0x05, 0x4B, 0x14, 0x60, 0x4F, 0xF0, ++ 0x80, 0x72, 0x1A, 0x60, 0x10, 0xBD, 0x00, 0xBF, 0x2C, 0x7E, 0x15, 0x00, ++ 0x98, 0x40, 0x04, 0x40, 0x00, 0x40, 0x04, 0x40, 0x02, 0x4B, 0x4F, 0xF0, ++ 0x00, 0x72, 0x1A, 0x60, 0x70, 0x47, 0x00, 0xBF, 0x00, 0x40, 0x04, 0x40, ++ 0x02, 0x4B, 0x4F, 0xF0, 0x80, 0x62, 0x1A, 0x60, 0x70, 0x47, 0x00, 0xBF, ++ 0x00, 0x40, 0x04, 0x40, 0x08, 0xB5, 0x25, 0x4B, 0x19, 0x68, 0x4A, 0x03, ++ 0x04, 0xD5, 0x4F, 0xF4, 0x80, 0x22, 0x43, 0xF8, 0x14, 0x2C, 0x08, 0xBD, ++ 0x08, 0x03, 0x04, 0xD5, 0x20, 0x4B, 0x4F, 0xF4, 0x00, 0x22, 0x1A, 0x60, ++ 0x08, 0xBD, 0x4A, 0x02, 0x0F, 0xD4, 0x0B, 0x02, 0x1D, 0xD4, 0x08, 0x01, ++ 0x10, 0xD5, 0x1C, 0x4B, 0x1A, 0x4A, 0xDB, 0x7D, 0x4F, 0xF0, 0x00, 0x61, ++ 0x01, 0x2B, 0x11, 0x60, 0xE9, 0xD1, 0xBD, 0xE8, 0x08, 0x40, 0x23, 0xF0, ++ 0xED, 0xBE, 0x15, 0x4B, 0x4F, 0xF4, 0x80, 0x02, 0x1A, 0x60, 0x08, 0xBD, ++ 0x11, 0xF0, 0x80, 0x53, 0x16, 0xD0, 0x12, 0x49, 0x10, 0x4B, 0x01, 0x20, ++ 0x4F, 0xF0, 0x80, 0x52, 0x48, 0x75, 0x1A, 0x60, 0x08, 0xBD, 0x0D, 0x4B, ++ 0x0E, 0x48, 0x4F, 0xF4, 0x00, 0x02, 0x1A, 0x60, 0x00, 0xF0, 0x0E, 0xFC, ++ 0x03, 0x20, 0x00, 0xF0, 0x93, 0xFC, 0x0B, 0x4B, 0x4F, 0xF4, 0x80, 0x02, ++ 0x1A, 0x60, 0x08, 0xBD, 0x8A, 0x00, 0xC4, 0xD5, 0x05, 0x49, 0x04, 0x4A, ++ 0x4B, 0x75, 0x4F, 0xF0, 0x00, 0x53, 0x13, 0x60, 0x08, 0xBD, 0x00, 0xBF, ++ 0x1C, 0x40, 0x04, 0x40, 0x08, 0x40, 0x04, 0x40, 0x4C, 0x36, 0x17, 0x00, ++ 0x40, 0x7E, 0x15, 0x00, 0x00, 0x40, 0x04, 0x40, 0x15, 0x4B, 0xD3, 0xF8, ++ 0x24, 0x31, 0x59, 0x06, 0x09, 0xD5, 0x10, 0xB5, 0x13, 0x4C, 0x23, 0x68, ++ 0x1A, 0x07, 0x88, 0xB0, 0xC3, 0xF3, 0xC0, 0x00, 0x03, 0xD4, 0x08, 0xB0, ++ 0x10, 0xBD, 0x01, 0x20, 0x70, 0x47, 0x0F, 0x49, 0x20, 0x22, 0x68, 0x46, ++ 0x31, 0xF0, 0xC6, 0xFA, 0x0D, 0x4B, 0x1B, 0x68, 0x23, 0x68, 0xC3, 0xF3, ++ 0x40, 0x00, 0x9B, 0x07, 0xEF, 0xD5, 0x0B, 0x4B, 0x0B, 0x4A, 0x4F, 0xF4, ++ 0x00, 0x11, 0x19, 0x60, 0x10, 0x68, 0x10, 0xF4, 0x40, 0x13, 0xFB, 0xD0, ++ 0x08, 0x4A, 0xC0, 0xF3, 0x00, 0x50, 0x13, 0x60, 0xE1, 0xE7, 0x00, 0xBF, ++ 0x00, 0x00, 0x50, 0x40, 0x84, 0x40, 0x04, 0x40, 0x30, 0x95, 0x16, 0x00, ++ 0x30, 0x60, 0x50, 0x40, 0x00, 0x40, 0x04, 0x40, 0x04, 0x40, 0x04, 0x40, ++ 0x08, 0x40, 0x04, 0x40, 0x01, 0x28, 0x06, 0xD0, 0x02, 0x28, 0x09, 0xD1, ++ 0x0B, 0x4B, 0x4F, 0xF4, 0x00, 0x22, 0x1A, 0x60, 0x70, 0x47, 0x09, 0x4B, ++ 0x4F, 0xF4, 0x80, 0x22, 0x1A, 0x60, 0x70, 0x47, 0x07, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x00, 0xDB, 0x70, 0x47, 0x05, 0x49, ++ 0x05, 0x48, 0x40, 0xF2, 0x52, 0x72, 0x1E, 0xF0, 0xE1, 0xBF, 0x00, 0xBF, ++ 0x00, 0x40, 0x04, 0x40, 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x64, 0x7D, 0x15, 0x00, 0x38, 0xB5, 0x22, 0x48, 0xFC, 0xF7, 0xFA, 0xFB, ++ 0x83, 0x07, 0x23, 0xD5, 0x20, 0x48, 0x00, 0xF0, 0x8B, 0xFB, 0x20, 0x48, ++ 0xFC, 0xF7, 0xF2, 0xFB, 0x04, 0x46, 0x1F, 0x48, 0xFC, 0xF7, 0xEE, 0xFB, ++ 0x03, 0x46, 0x1D, 0x48, 0x1C, 0x40, 0xFC, 0xF7, 0xE9, 0xFB, 0x84, 0x42, ++ 0x1F, 0xD0, 0x05, 0x20, 0x00, 0xF0, 0x14, 0xFC, 0x01, 0x28, 0x04, 0x46, ++ 0x17, 0xD0, 0x03, 0x20, 0x00, 0xF0, 0x06, 0xFC, 0x02, 0x25, 0x21, 0x46, ++ 0x15, 0x48, 0x00, 0xF0, 0x6F, 0xFB, 0x28, 0x46, 0xBD, 0xE8, 0x38, 0x40, ++ 0xFF, 0xF7, 0xB2, 0xBF, 0x01, 0x46, 0x12, 0x48, 0x00, 0xF0, 0x66, 0xFB, ++ 0x11, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x08, 0xDB, ++ 0x38, 0xBD, 0x05, 0x46, 0xE9, 0xE7, 0x20, 0x22, 0x0D, 0x48, 0x11, 0x46, ++ 0xFC, 0xF7, 0x12, 0xFC, 0xD9, 0xE7, 0xBD, 0xE8, 0x38, 0x40, 0x0B, 0x49, ++ 0x0B, 0x48, 0x4F, 0xF4, 0xD3, 0x62, 0x1E, 0xF0, 0x93, 0xBF, 0x00, 0xBF, ++ 0x08, 0x30, 0x01, 0x50, 0x54, 0x7E, 0x15, 0x00, 0x20, 0x10, 0x01, 0x50, ++ 0x18, 0x10, 0x01, 0x50, 0x60, 0x7E, 0x15, 0x00, 0x6C, 0x7E, 0x15, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x24, 0x10, 0x01, 0x50, 0x70, 0x79, 0x15, 0x00, ++ 0x64, 0x7D, 0x15, 0x00, 0x02, 0x48, 0x38, 0x22, 0x00, 0x21, 0xFA, 0xF7, ++ 0x91, 0xBA, 0x00, 0xBF, 0x48, 0x35, 0x17, 0x00, 0x2D, 0xE9, 0xF8, 0x4F, ++ 0x5D, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x80, 0x46, ++ 0x0F, 0x46, 0x16, 0x46, 0xC0, 0xF2, 0xA8, 0x80, 0x00, 0x23, 0x3B, 0x62, ++ 0xEF, 0xF3, 0x10, 0x83, 0xDA, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x56, 0x4B, ++ 0x01, 0x22, 0x1A, 0x60, 0xB5, 0x01, 0x05, 0xF1, 0x80, 0x42, 0x02, 0xF5, ++ 0xE2, 0x24, 0x53, 0x49, 0x23, 0x68, 0x08, 0x68, 0x43, 0xF0, 0x01, 0x03, ++ 0x00, 0xF1, 0x01, 0x0C, 0x02, 0xF5, 0xE0, 0x22, 0x23, 0x60, 0xC1, 0xF8, ++ 0x00, 0xC0, 0x23, 0x68, 0xDB, 0x03, 0xFC, 0xD5, 0xDF, 0xF8, 0x38, 0xE1, ++ 0x5E, 0xF8, 0x26, 0x90, 0xB9, 0xF1, 0x00, 0x0F, 0x0A, 0xD0, 0x05, 0xF1, ++ 0x80, 0x43, 0x03, 0xF5, 0xE0, 0x23, 0x41, 0xF2, 0x0C, 0x0A, 0x53, 0xF8, ++ 0x0A, 0xA0, 0x1A, 0xF4, 0x00, 0x6F, 0x61, 0xD0, 0x05, 0xF1, 0x80, 0x43, ++ 0x03, 0xF5, 0xE0, 0x23, 0x41, 0xF2, 0x08, 0x09, 0xDF, 0xF8, 0x0C, 0xA1, ++ 0x43, 0xF8, 0x09, 0xA0, 0x41, 0xF2, 0x0C, 0x05, 0x4F, 0xF0, 0x14, 0x0A, ++ 0x43, 0xF8, 0x05, 0xA0, 0x41, 0xF2, 0x10, 0x0B, 0x41, 0xF2, 0x14, 0x0A, ++ 0x00, 0x25, 0x43, 0xF8, 0x0B, 0x50, 0x43, 0xF8, 0x0A, 0x50, 0x41, 0xF2, ++ 0x18, 0x0B, 0x41, 0xF2, 0x1C, 0x0A, 0x43, 0xF8, 0x0B, 0x50, 0x43, 0xF8, ++ 0x0A, 0x50, 0x03, 0xF5, 0x81, 0x5B, 0x41, 0xF2, 0x24, 0x0A, 0xCB, 0xF8, ++ 0x00, 0x50, 0x43, 0xF8, 0x0A, 0x50, 0x41, 0xF2, 0x28, 0x0B, 0x41, 0xF2, ++ 0x2C, 0x0A, 0x43, 0xF8, 0x0B, 0x50, 0x43, 0xF8, 0x0A, 0x50, 0x41, 0xF2, ++ 0x34, 0x0B, 0x41, 0xF2, 0x38, 0x0A, 0x43, 0xF8, 0x0B, 0x50, 0x43, 0xF8, ++ 0x0A, 0x50, 0x41, 0xF2, 0x3C, 0x0B, 0x41, 0xF2, 0x30, 0x0A, 0x43, 0xF8, ++ 0x0B, 0x50, 0x43, 0xF8, 0x0A, 0x80, 0xBD, 0x68, 0x45, 0xF4, 0x00, 0x25, ++ 0xBD, 0x60, 0x53, 0xF8, 0x09, 0x50, 0x45, 0xF0, 0x01, 0x05, 0x43, 0xF8, ++ 0x09, 0x50, 0x41, 0xF2, 0x04, 0x05, 0x53, 0x59, 0x43, 0xF0, 0x01, 0x03, ++ 0x53, 0x51, 0x23, 0x68, 0x4E, 0xF8, 0x26, 0x70, 0x23, 0xF0, 0x01, 0x03, ++ 0x23, 0x60, 0xBC, 0xF1, 0x00, 0x0F, 0x05, 0xD0, 0x14, 0x4B, 0x08, 0x60, ++ 0x1B, 0x68, 0x08, 0xB9, 0x03, 0xB1, 0x62, 0xB6, 0xBD, 0xE8, 0xF8, 0x8F, ++ 0x41, 0xF2, 0x18, 0x02, 0x9D, 0x58, 0x2D, 0x03, 0x07, 0xD5, 0x9D, 0x58, ++ 0x41, 0xF2, 0x30, 0x0A, 0x25, 0xF4, 0x00, 0x25, 0x9D, 0x50, 0x43, 0xF8, ++ 0x0A, 0x80, 0xD9, 0xF8, 0x08, 0x30, 0x23, 0xF4, 0x00, 0x23, 0xC9, 0xF8, ++ 0x08, 0x30, 0xC9, 0xF8, 0x20, 0x80, 0xD8, 0xE7, 0x0D, 0x2A, 0x7F, 0xF7, ++ 0x55, 0xAF, 0x06, 0x49, 0x06, 0x48, 0x4E, 0x22, 0x1E, 0xF0, 0xBA, 0xFE, ++ 0x4E, 0xE7, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x94, 0x7E, 0x15, 0x00, ++ 0x48, 0x35, 0x17, 0x00, 0x10, 0x00, 0x01, 0x00, 0x03, 0x4B, 0x04, 0x4A, ++ 0x01, 0x30, 0x43, 0xEA, 0x00, 0x43, 0x13, 0x63, 0x70, 0x47, 0x00, 0xBF, ++ 0x3F, 0x00, 0x00, 0x20, 0x00, 0x00, 0x07, 0x40, 0x70, 0xB4, 0x18, 0x4D, ++ 0x18, 0x4C, 0x2E, 0x6B, 0xB1, 0xF5, 0x00, 0x6F, 0x46, 0xF0, 0x80, 0x56, ++ 0x2E, 0x63, 0x60, 0x60, 0xEB, 0x63, 0x20, 0x60, 0x0B, 0x46, 0x28, 0xBF, ++ 0x4F, 0xF4, 0x00, 0x63, 0x80, 0x07, 0x11, 0xD0, 0xC1, 0xF3, 0x10, 0x05, ++ 0x10, 0x48, 0x43, 0xF0, 0x0C, 0x53, 0x21, 0xF0, 0x70, 0x41, 0xA3, 0x60, ++ 0xE5, 0x60, 0x21, 0x61, 0x60, 0x61, 0x0B, 0x49, 0x00, 0x23, 0x23, 0x62, ++ 0x08, 0x46, 0x70, 0xBC, 0xFF, 0xF7, 0x04, 0xBF, 0xC1, 0xF3, 0x10, 0x05, ++ 0x43, 0xF0, 0x23, 0x43, 0x21, 0xF0, 0x70, 0x41, 0x4F, 0xF0, 0x04, 0x10, ++ 0xA3, 0x60, 0xE5, 0x60, 0x21, 0x61, 0x60, 0x61, 0xEB, 0xE7, 0x00, 0xBF, ++ 0x00, 0x00, 0x07, 0x40, 0x74, 0x25, 0x17, 0x00, 0x01, 0x00, 0x04, 0x00, ++ 0x01, 0x23, 0x06, 0x4A, 0x03, 0xFA, 0x00, 0xF0, 0x93, 0x69, 0x03, 0x42, ++ 0xFC, 0xD1, 0x13, 0x6B, 0x23, 0xF0, 0x80, 0x53, 0x13, 0x63, 0x10, 0x6C, ++ 0x70, 0x47, 0x00, 0xBF, 0x00, 0x00, 0x07, 0x40, 0x08, 0x4A, 0xD3, 0x68, ++ 0x19, 0x04, 0x44, 0xBF, 0x4F, 0xF4, 0x00, 0x01, 0x91, 0x60, 0x5B, 0x05, ++ 0x00, 0xD4, 0x70, 0x47, 0x03, 0x4B, 0x4F, 0xF4, 0x80, 0x22, 0x9A, 0x60, ++ 0x4F, 0xF0, 0x80, 0x40, 0x1D, 0xF0, 0x4E, 0xB9, 0x00, 0x10, 0x50, 0x40, ++ 0x11, 0x4A, 0x13, 0x68, 0x13, 0xF0, 0x01, 0x01, 0x0A, 0xD1, 0x23, 0xF4, ++ 0x40, 0x73, 0x43, 0xF4, 0x90, 0x73, 0x43, 0xF0, 0x01, 0x03, 0x11, 0x20, ++ 0x11, 0x61, 0x51, 0x61, 0x50, 0x60, 0x13, 0x60, 0x5A, 0x04, 0x03, 0xD4, ++ 0x08, 0x4A, 0x43, 0xF4, 0x80, 0x43, 0x13, 0x60, 0x07, 0x4B, 0x08, 0x49, ++ 0x9A, 0x68, 0xD1, 0xF8, 0xD0, 0x10, 0xC2, 0xF8, 0xB4, 0x10, 0xA3, 0xF5, ++ 0x40, 0x63, 0x4F, 0xF0, 0x00, 0x52, 0x1A, 0x60, 0x70, 0x47, 0x00, 0xBF, ++ 0x00, 0x10, 0x50, 0x40, 0x00, 0xED, 0x00, 0xE0, 0x88, 0x1A, 0x17, 0x00, ++ 0x06, 0x4B, 0x07, 0x49, 0x9A, 0x68, 0xD1, 0xF8, 0xD0, 0x10, 0xC2, 0xF8, ++ 0xB4, 0x10, 0xA3, 0xF5, 0x40, 0x63, 0x4F, 0xF0, 0x00, 0x52, 0x1A, 0x60, ++ 0x70, 0x47, 0x00, 0xBF, 0x00, 0xED, 0x00, 0xE0, 0x88, 0x1A, 0x17, 0x00, ++ 0x3E, 0x4B, 0x1A, 0x68, 0x00, 0x2A, 0x6F, 0xD1, 0x3D, 0x49, 0xD1, 0xF8, ++ 0xA4, 0x10, 0x00, 0x29, 0xF0, 0xB4, 0x56, 0xDA, 0x3B, 0x48, 0x00, 0x68, ++ 0x00, 0x28, 0x4E, 0xD0, 0x3A, 0x4D, 0x3B, 0x48, 0x3B, 0x4C, 0x2A, 0x60, ++ 0x01, 0x25, 0x02, 0x60, 0x25, 0x60, 0xC2, 0x68, 0x39, 0x4D, 0x3A, 0x4C, ++ 0x42, 0xF4, 0x80, 0x72, 0xC2, 0x60, 0x03, 0x22, 0x2A, 0x60, 0x62, 0x68, ++ 0x92, 0x07, 0x21, 0xF0, 0x00, 0x41, 0x57, 0xD5, 0x35, 0x4A, 0x12, 0x68, ++ 0x10, 0x09, 0x81, 0x42, 0x4D, 0xD2, 0xB2, 0xFB, 0xF1, 0xF1, 0xC1, 0xF3, ++ 0x42, 0x04, 0x01, 0xF0, 0x0F, 0x02, 0x12, 0x1B, 0xC1, 0xF3, 0x07, 0x1C, ++ 0x04, 0xEB, 0x02, 0x14, 0xC1, 0xF3, 0x07, 0x31, 0x2A, 0x4A, 0x28, 0x4D, ++ 0x10, 0x68, 0x2C, 0x4E, 0x2C, 0x4F, 0x40, 0xF0, 0x80, 0x00, 0x10, 0x60, ++ 0xC7, 0xF8, 0x00, 0xC0, 0x29, 0x60, 0x34, 0x60, 0x11, 0x68, 0x21, 0x4C, ++ 0x22, 0x48, 0x28, 0x4E, 0x21, 0xF0, 0x80, 0x01, 0x11, 0x60, 0x07, 0x22, ++ 0x22, 0x60, 0x02, 0x68, 0x25, 0x4C, 0x26, 0x49, 0xD4, 0xF8, 0xBC, 0x40, ++ 0x22, 0xF4, 0xFF, 0x72, 0x22, 0xF0, 0x01, 0x02, 0x42, 0xF0, 0x01, 0x02, ++ 0x02, 0x60, 0x01, 0x22, 0x2A, 0x60, 0xB0, 0x68, 0x4F, 0xF4, 0x80, 0x32, ++ 0xC0, 0xF8, 0x80, 0x40, 0x0A, 0x60, 0x01, 0x22, 0xF0, 0xBC, 0x1A, 0x60, ++ 0x70, 0x47, 0x10, 0x4A, 0x12, 0x68, 0x00, 0x2A, 0xF7, 0xD0, 0x10, 0x48, ++ 0x17, 0x4C, 0x16, 0x49, 0xD4, 0xF8, 0xBC, 0x40, 0x16, 0x4A, 0x01, 0x25, ++ 0x05, 0x60, 0x88, 0x68, 0x4F, 0xF4, 0x80, 0x31, 0xC0, 0xF8, 0x80, 0x40, ++ 0x11, 0x60, 0xE8, 0xE7, 0x70, 0x47, 0x00, 0x24, 0x21, 0x46, 0x4F, 0xF0, ++ 0x01, 0x0C, 0xB9, 0xE7, 0x0F, 0x48, 0x10, 0x4A, 0xA7, 0xE7, 0x00, 0xBF, ++ 0xA4, 0x25, 0x17, 0x00, 0x2C, 0x19, 0x17, 0x00, 0x68, 0x28, 0x17, 0x00, ++ 0x08, 0x10, 0x04, 0x40, 0x04, 0x10, 0x04, 0x40, 0x24, 0x10, 0x04, 0x40, ++ 0x0C, 0x10, 0x04, 0x40, 0x00, 0x00, 0x10, 0x40, 0x14, 0x13, 0x17, 0x00, ++ 0x28, 0x10, 0x04, 0x40, 0x00, 0x10, 0x04, 0x40, 0x00, 0xED, 0x00, 0xE0, ++ 0x88, 0x1A, 0x17, 0x00, 0x00, 0xE1, 0x00, 0xE0, 0x50, 0x97, 0x31, 0x00, ++ 0x00, 0x75, 0x19, 0x03, 0x03, 0x4A, 0x13, 0x68, 0x1B, 0x03, 0xFC, 0xD4, ++ 0x02, 0x4B, 0x18, 0x60, 0x70, 0x47, 0x00, 0xBF, 0x20, 0x10, 0x04, 0x40, ++ 0x00, 0x10, 0x04, 0x40, 0x03, 0x4A, 0x13, 0x68, 0xDB, 0x07, 0xFC, 0xD5, ++ 0x02, 0x4B, 0x18, 0x68, 0xC0, 0xB2, 0x70, 0x47, 0x14, 0x10, 0x04, 0x40, ++ 0x00, 0x10, 0x04, 0x40, 0xF0, 0xB5, 0x03, 0x46, 0xC3, 0xB0, 0xEF, 0xF3, ++ 0x05, 0x85, 0x73, 0x4C, 0x22, 0x68, 0x12, 0x78, 0x02, 0x2A, 0x04, 0xD1, ++ 0x71, 0x4A, 0xB2, 0xF8, 0xAA, 0x20, 0x52, 0x04, 0x56, 0xD4, 0x00, 0x91, ++ 0x00, 0x22, 0x4F, 0xF4, 0x80, 0x71, 0x02, 0xA8, 0x1D, 0xF0, 0x46, 0xFE, ++ 0x06, 0x46, 0x00, 0x2E, 0x31, 0xDD, 0x6B, 0x4B, 0x1B, 0x68, 0x1B, 0xB9, ++ 0x6A, 0x4B, 0xD3, 0xF8, 0x28, 0x33, 0x98, 0x47, 0x1D, 0xB9, 0x69, 0x4A, ++ 0x13, 0x68, 0x00, 0x2B, 0xFC, 0xD0, 0x68, 0x4B, 0x1B, 0x68, 0x33, 0xB9, ++ 0x67, 0x4A, 0x13, 0x68, 0x1F, 0x03, 0xFC, 0xD4, 0x66, 0x4B, 0x5F, 0x22, ++ 0x1A, 0x60, 0x5F, 0x4B, 0xB3, 0xF8, 0xAA, 0x30, 0x13, 0xF4, 0x80, 0x43, ++ 0x18, 0xD1, 0x02, 0xA9, 0x60, 0x4A, 0x61, 0x48, 0x77, 0x18, 0x4F, 0xF0, ++ 0x0D, 0x0C, 0x11, 0xF8, 0x01, 0x4B, 0x0A, 0x2C, 0x1C, 0xD0, 0x13, 0x68, ++ 0x1B, 0x03, 0xFC, 0xD4, 0x04, 0x60, 0xB9, 0x42, 0x11, 0xF8, 0x01, 0x3C, ++ 0xF3, 0xD1, 0x15, 0xB9, 0x55, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x30, 0x46, ++ 0x43, 0xB0, 0xF0, 0xBD, 0x23, 0x68, 0x1B, 0x78, 0x01, 0x2B, 0x1C, 0xD0, ++ 0x02, 0x2B, 0xF2, 0xD1, 0x53, 0x4B, 0x1B, 0x68, 0x1B, 0x78, 0x03, 0x2B, ++ 0xED, 0xD0, 0x00, 0x2D, 0xEF, 0xD1, 0x26, 0xE0, 0x0D, 0x2B, 0xE0, 0xD0, ++ 0x13, 0x68, 0x1C, 0x03, 0xFC, 0xD4, 0xC0, 0xF8, 0x00, 0xC0, 0x11, 0xF8, ++ 0x01, 0x4C, 0xD8, 0xE7, 0x00, 0x91, 0x00, 0x22, 0x4F, 0xF4, 0x80, 0x71, ++ 0x03, 0xA8, 0x1D, 0xF0, 0xEF, 0xFD, 0x06, 0x46, 0xA7, 0xE7, 0x46, 0x4F, ++ 0x3B, 0x68, 0x1B, 0x78, 0x03, 0x2B, 0xD2, 0xD0, 0x00, 0x2D, 0xD4, 0xD1, ++ 0x43, 0x48, 0x1D, 0xF0, 0x07, 0xF9, 0x04, 0x28, 0x62, 0xD8, 0x23, 0x68, ++ 0x1B, 0x78, 0x02, 0x2B, 0xC8, 0xD1, 0x3B, 0x68, 0x1B, 0x78, 0x03, 0x2B, ++ 0xC4, 0xD0, 0x3E, 0x48, 0x1D, 0xF0, 0xFA, 0xF8, 0x04, 0x28, 0xBF, 0xD9, ++ 0x3B, 0x48, 0x3C, 0x4C, 0x1D, 0xF0, 0xB4, 0xF8, 0x42, 0xF2, 0x34, 0x03, ++ 0x13, 0x25, 0xE2, 0x5A, 0x8D, 0xF8, 0x08, 0x60, 0x00, 0x23, 0xB2, 0xF5, ++ 0xC3, 0x7F, 0x02, 0xAF, 0x01, 0x46, 0x7D, 0x80, 0x7B, 0x70, 0x4D, 0xD8, ++ 0x55, 0x1C, 0xAD, 0xB2, 0xD3, 0x00, 0x33, 0x48, 0x8A, 0x81, 0xD0, 0xF8, ++ 0x00, 0xC0, 0x0C, 0xEB, 0x03, 0x00, 0x32, 0x1D, 0x47, 0x60, 0x2C, 0xF8, ++ 0x03, 0x20, 0xC3, 0x78, 0x03, 0xF0, 0x31, 0x03, 0x43, 0xF0, 0x04, 0x03, ++ 0xC3, 0x70, 0x94, 0xF8, 0x02, 0x3C, 0x42, 0xF2, 0x34, 0x0C, 0x01, 0x33, ++ 0x84, 0xF8, 0x02, 0x3C, 0x01, 0x27, 0x00, 0x23, 0x24, 0xF8, 0x0C, 0x50, ++ 0xC1, 0xE9, 0x01, 0x02, 0x8F, 0x73, 0x0B, 0x60, 0xEF, 0xF3, 0x10, 0x83, ++ 0xDB, 0x07, 0x02, 0xD4, 0x72, 0xB6, 0x22, 0x4B, 0x1F, 0x60, 0x22, 0x4C, ++ 0x22, 0x48, 0x23, 0x68, 0x01, 0x33, 0x23, 0x60, 0x1D, 0xF0, 0x32, 0xF8, ++ 0x13, 0x4B, 0xD3, 0xF8, 0x44, 0x34, 0x98, 0x47, 0x23, 0x68, 0x00, 0x2B, ++ 0x3F, 0xF4, 0x76, 0xAF, 0x19, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x23, 0x60, ++ 0x00, 0x2B, 0x7F, 0xF4, 0x6F, 0xAF, 0x00, 0x2A, 0x3F, 0xF4, 0x6C, 0xAF, ++ 0x62, 0xB6, 0x69, 0xE7, 0x7C, 0x2E, 0x32, 0x46, 0xA8, 0xBF, 0x7C, 0x22, ++ 0x92, 0xB2, 0x02, 0xA9, 0x13, 0x20, 0x02, 0xF0, 0xF9, 0xFA, 0x5F, 0xE7, ++ 0x1A, 0x46, 0x01, 0x25, 0xB1, 0xE7, 0x00, 0xBF, 0x78, 0x36, 0x17, 0x00, ++ 0x2C, 0x19, 0x17, 0x00, 0xA4, 0x25, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x40, 0x40, 0x04, 0x40, 0x68, 0x28, 0x17, 0x00, 0x20, 0x10, 0x04, 0x40, ++ 0x00, 0x10, 0x04, 0x40, 0x74, 0x36, 0x17, 0x00, 0x20, 0x60, 0x17, 0x00, ++ 0xA0, 0x56, 0x17, 0x00, 0x7C, 0x36, 0x17, 0x00, 0x54, 0x60, 0x17, 0x00, ++ 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0xA8, 0x56, 0x17, 0x00, ++ 0x0F, 0xB4, 0x00, 0xB5, 0x83, 0xB0, 0x04, 0xA9, 0x05, 0x4B, 0x51, 0xF8, ++ 0x04, 0x0B, 0xD3, 0xF8, 0x30, 0x34, 0x01, 0x91, 0x98, 0x47, 0x03, 0xB0, ++ 0x5D, 0xF8, 0x04, 0xEB, 0x04, 0xB0, 0x70, 0x47, 0x88, 0x1A, 0x17, 0x00, ++ 0x01, 0x22, 0x90, 0x42, 0x10, 0xB4, 0x02, 0xFA, 0x00, 0xF4, 0x11, 0xDD, ++ 0xA0, 0xF1, 0x08, 0x03, 0x93, 0x42, 0x0D, 0xD9, 0x0F, 0x28, 0x25, 0xDD, ++ 0x1F, 0x28, 0x12, 0xDC, 0x15, 0x4A, 0x52, 0xF8, 0x20, 0x30, 0x23, 0xF0, ++ 0x0F, 0x03, 0x43, 0xF0, 0x02, 0x03, 0x42, 0xF8, 0x20, 0x30, 0x08, 0xE0, ++ 0x10, 0x4A, 0x52, 0xF8, 0x20, 0x30, 0x23, 0xF0, 0x0F, 0x03, 0x43, 0xF0, ++ 0x01, 0x03, 0x42, 0xF8, 0x20, 0x30, 0x0D, 0x4B, 0x5A, 0x68, 0x22, 0x43, ++ 0x5A, 0x60, 0x9A, 0x68, 0x29, 0xB9, 0x22, 0xEA, 0x04, 0x02, 0x9A, 0x60, ++ 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, 0x22, 0x43, 0x9A, 0x60, 0x5D, 0xF8, ++ 0x04, 0x4B, 0x70, 0x47, 0x03, 0x4A, 0x52, 0xF8, 0x20, 0x30, 0x23, 0xF0, ++ 0x0F, 0x03, 0x42, 0xF8, 0x20, 0x30, 0xE6, 0xE7, 0x00, 0x30, 0x50, 0x40, ++ 0x00, 0x40, 0x50, 0x40, 0x04, 0x49, 0x01, 0x22, 0x0B, 0x68, 0x02, 0xFA, ++ 0x00, 0xF0, 0x23, 0xEA, 0x00, 0x03, 0x0B, 0x60, 0x70, 0x47, 0x00, 0xBF, ++ 0x00, 0x40, 0x50, 0x40, 0x10, 0xB5, 0x01, 0x29, 0x82, 0xB0, 0x04, 0x46, ++ 0x10, 0xD0, 0x20, 0xF0, 0x03, 0x03, 0x0F, 0x22, 0x9A, 0x40, 0x11, 0x46, ++ 0x0D, 0x48, 0xFC, 0xF7, 0x51, 0xF8, 0x01, 0x22, 0xA2, 0x40, 0x0C, 0x48, ++ 0x11, 0x46, 0x02, 0xB0, 0xBD, 0xE8, 0x10, 0x40, 0xFC, 0xF7, 0x48, 0xB8, ++ 0x01, 0xFA, 0x00, 0xF2, 0x11, 0x46, 0x07, 0x48, 0x01, 0x92, 0xFC, 0xF7, ++ 0x41, 0xF8, 0x01, 0x9A, 0x05, 0x48, 0x11, 0x46, 0x02, 0xB0, 0xBD, 0xE8, ++ 0x10, 0x40, 0xFC, 0xF7, 0x39, 0xB8, 0x00, 0xBF, 0x2C, 0x10, 0x01, 0x50, ++ 0x04, 0x10, 0x01, 0x50, 0x08, 0x10, 0x01, 0x50, 0x01, 0x23, 0x03, 0xFA, ++ 0x00, 0xF2, 0x11, 0x46, 0x01, 0x48, 0xFC, 0xF7, 0x2B, 0xB8, 0x00, 0xBF, ++ 0x00, 0x10, 0x01, 0x50, 0x01, 0x22, 0x82, 0x40, 0x00, 0x21, 0x01, 0x48, ++ 0xFC, 0xF7, 0x22, 0xB8, 0x00, 0x10, 0x01, 0x50, 0x10, 0xB5, 0x04, 0x46, ++ 0x03, 0x48, 0xFB, 0xF7, 0xCB, 0xFF, 0xE0, 0x40, 0x00, 0xF0, 0x01, 0x00, ++ 0x10, 0xBD, 0x00, 0xBF, 0x00, 0x10, 0x01, 0x50, 0x70, 0x47, 0x00, 0xBF, ++ 0x70, 0x47, 0x00, 0xBF, 0x70, 0x47, 0x00, 0xBF, 0x0E, 0x48, 0x0F, 0x4A, ++ 0x03, 0x68, 0x0F, 0x49, 0x23, 0xF0, 0xFF, 0x03, 0x43, 0xF0, 0xC2, 0x03, ++ 0x03, 0x60, 0x13, 0x68, 0x23, 0xF0, 0xFF, 0x03, 0x43, 0xF0, 0xC2, 0x03, ++ 0x13, 0x60, 0x03, 0x68, 0x23, 0xF4, 0x7F, 0x23, 0x43, 0xF4, 0x3F, 0x23, ++ 0x03, 0x60, 0x13, 0x68, 0x23, 0xF4, 0x7F, 0x23, 0x43, 0xF4, 0x3F, 0x23, ++ 0xC2, 0x20, 0x13, 0x60, 0xC8, 0x71, 0x70, 0x47, 0xAC, 0xB3, 0x33, 0x40, ++ 0xD4, 0xB3, 0x33, 0x40, 0x80, 0x35, 0x17, 0x00, 0x24, 0x4B, 0x25, 0x48, ++ 0x1B, 0x68, 0x2D, 0xE9, 0xF0, 0x41, 0x24, 0x4D, 0x24, 0x4F, 0x6A, 0x79, ++ 0x95, 0xF9, 0x07, 0x10, 0x3C, 0x68, 0x23, 0x4E, 0x03, 0xF0, 0x0F, 0x03, ++ 0x1A, 0x44, 0x52, 0xB2, 0x89, 0x1A, 0x6F, 0xF0, 0x3D, 0x03, 0x99, 0x42, ++ 0xB8, 0xBF, 0x19, 0x46, 0x5F, 0xFA, 0x81, 0xFC, 0x24, 0xF0, 0xFF, 0x04, ++ 0x44, 0xEA, 0x0C, 0x04, 0x3C, 0x60, 0x33, 0x68, 0x23, 0xF0, 0xFF, 0x03, ++ 0x43, 0xEA, 0x0C, 0x03, 0x33, 0x60, 0x3C, 0x68, 0xCB, 0x1E, 0x5F, 0xFA, ++ 0x83, 0xFC, 0x24, 0xF4, 0x7F, 0x24, 0x44, 0xEA, 0x0C, 0x34, 0x3C, 0x60, ++ 0x33, 0x68, 0x23, 0xF4, 0x7F, 0x23, 0x4C, 0xB2, 0x43, 0xEA, 0x0C, 0x33, ++ 0x33, 0x60, 0x21, 0x46, 0xEC, 0x71, 0x1E, 0xF0, 0xC3, 0xF8, 0x3D, 0x34, ++ 0x0E, 0xDB, 0x0D, 0x4B, 0x29, 0x89, 0x1A, 0x69, 0x0C, 0x4B, 0x47, 0xF2, ++ 0x30, 0x54, 0x05, 0xF1, 0x0C, 0x00, 0x04, 0xFB, 0x01, 0x21, 0xD3, 0xF8, ++ 0xE0, 0x31, 0xBD, 0xE8, 0xF0, 0x41, 0x18, 0x47, 0xBD, 0xE8, 0xF0, 0x81, ++ 0x1C, 0x01, 0x32, 0x40, 0xB8, 0x7E, 0x15, 0x00, 0x80, 0x35, 0x17, 0x00, ++ 0xAC, 0xB3, 0x33, 0x40, 0xD4, 0xB3, 0x33, 0x40, 0x00, 0x10, 0x50, 0x40, ++ 0x88, 0x1A, 0x17, 0x00, 0x12, 0x4A, 0x12, 0x68, 0xD2, 0xE9, 0x06, 0x01, ++ 0x38, 0xB5, 0x11, 0x4B, 0x15, 0x6A, 0x18, 0x60, 0x59, 0x60, 0x50, 0x6A, ++ 0x0F, 0x4C, 0xD2, 0xE9, 0x0A, 0x12, 0xC3, 0xE9, 0x02, 0x50, 0xC3, 0xE9, ++ 0x04, 0x12, 0xD4, 0xF8, 0x2C, 0x33, 0x98, 0x47, 0xD4, 0xF8, 0xC0, 0x30, ++ 0x98, 0x47, 0xFB, 0xF7, 0xAF, 0xFA, 0x09, 0x4B, 0x1B, 0x68, 0x1B, 0x78, ++ 0x03, 0x2B, 0x02, 0xD1, 0xD4, 0xF8, 0x20, 0x31, 0x98, 0x47, 0xBD, 0xE8, ++ 0x38, 0x40, 0xFF, 0xF7, 0x79, 0xBB, 0x00, 0xBF, 0xC8, 0x35, 0x17, 0x00, ++ 0xB0, 0x35, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x78, 0x36, 0x17, 0x00, ++ 0x30, 0xB4, 0x08, 0x4B, 0x08, 0x48, 0x18, 0x60, 0xC2, 0x25, 0x40, 0xF6, ++ 0xEC, 0x20, 0x4F, 0xF4, 0x7A, 0x74, 0x06, 0x49, 0x06, 0x4A, 0xDD, 0x71, ++ 0x98, 0x80, 0x1C, 0x81, 0x19, 0x61, 0x30, 0xBC, 0x1A, 0x62, 0x70, 0x47, ++ 0x80, 0x35, 0x17, 0x00, 0x01, 0x00, 0x00, 0x14, 0x95, 0x64, 0x12, 0x00, ++ 0x4D, 0x64, 0x12, 0x00, 0x90, 0xF8, 0x62, 0x30, 0xCB, 0xB9, 0x0D, 0x4B, ++ 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x10, 0xB5, 0x04, 0x46, ++ 0x03, 0xDB, 0x00, 0x23, 0x84, 0xF8, 0xAC, 0x30, 0x10, 0xBD, 0x90, 0xF8, ++ 0xAC, 0x30, 0x01, 0x2B, 0xF7, 0xD0, 0x06, 0x49, 0x06, 0x48, 0x40, 0xF2, ++ 0xE7, 0x12, 0x1E, 0xF0, 0xBB, 0xFA, 0x00, 0x23, 0x84, 0xF8, 0xAC, 0x30, ++ 0x10, 0xBD, 0x70, 0x47, 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0xCC, 0x7E, 0x15, 0x00, 0x13, 0x4A, 0x90, 0xF8, 0x22, 0x30, 0x4F, 0xF4, ++ 0xA4, 0x61, 0x01, 0xFB, 0x03, 0x23, 0x93, 0xF8, 0x62, 0x30, 0x02, 0x2B, ++ 0x1B, 0xD1, 0x0F, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0x10, 0xB5, 0x04, 0x46, 0x08, 0xDB, 0x94, 0xF8, 0x23, 0x10, 0x0B, 0x48, ++ 0x1E, 0xF0, 0x1E, 0xF8, 0x00, 0x23, 0x84, 0xF8, 0x70, 0x32, 0x10, 0xBD, ++ 0x90, 0xF8, 0x70, 0x32, 0x01, 0x2B, 0xF2, 0xD0, 0x06, 0x49, 0x07, 0x48, ++ 0x40, 0xF2, 0xF3, 0x12, 0x1E, 0xF0, 0x8A, 0xFA, 0xEB, 0xE7, 0x70, 0x47, ++ 0x18, 0x88, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, 0x10, 0x7F, 0x15, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xF0, 0x7E, 0x15, 0x00, 0x2D, 0xE9, 0xF0, 0x41, ++ 0x90, 0xF8, 0x62, 0x40, 0x1C, 0xB9, 0x90, 0xF8, 0x64, 0x30, 0x06, 0x46, ++ 0x0B, 0xB9, 0xBD, 0xE8, 0xF0, 0x81, 0xD0, 0xE9, 0x24, 0x23, 0xD0, 0xF8, ++ 0x98, 0x10, 0x42, 0x48, 0xDF, 0xF8, 0x30, 0x81, 0x1D, 0xF0, 0xF0, 0xFF, ++ 0x45, 0x46, 0x06, 0xF5, 0xB2, 0x77, 0x28, 0x46, 0x06, 0x22, 0x39, 0x46, ++ 0x30, 0xF0, 0xD8, 0xFC, 0x14, 0x35, 0x40, 0xB1, 0x01, 0x34, 0x05, 0x2C, ++ 0xF5, 0xD1, 0x3A, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0x5B, 0xDB, 0x04, 0xEB, 0x84, 0x03, 0x08, 0xEB, 0x83, 0x03, 0xA2, 0x00, ++ 0xD9, 0x79, 0x00, 0x29, 0xD9, 0xD1, 0x1B, 0x7A, 0x03, 0xBB, 0xD6, 0xF8, ++ 0x90, 0x30, 0x31, 0x2B, 0x29, 0xD9, 0xD6, 0xF8, 0x94, 0x10, 0xB1, 0xEB, ++ 0x53, 0x0F, 0x3B, 0xD8, 0x14, 0x44, 0x08, 0xEB, 0x84, 0x08, 0x98, 0xF8, ++ 0x06, 0x30, 0x00, 0x2B, 0x48, 0xD1, 0x00, 0x23, 0xC6, 0xE9, 0x24, 0x33, ++ 0x29, 0x4A, 0xC6, 0xF8, 0x98, 0x30, 0x12, 0x69, 0x28, 0x49, 0x29, 0x4B, ++ 0x06, 0xF1, 0x9C, 0x00, 0xD3, 0xF8, 0xE0, 0x31, 0xBD, 0xE8, 0xF0, 0x41, ++ 0x11, 0x44, 0x18, 0x47, 0xD6, 0xF8, 0x98, 0x30, 0x53, 0xB3, 0xD6, 0xF8, ++ 0x90, 0x30, 0x00, 0x2B, 0x37, 0xD0, 0x11, 0x19, 0x08, 0xEB, 0x81, 0x01, ++ 0x00, 0x20, 0x08, 0x72, 0xD3, 0xE7, 0x0B, 0x2B, 0x12, 0xD8, 0xD6, 0xF8, ++ 0x98, 0x20, 0x14, 0x2A, 0xDB, 0xD9, 0x00, 0x2B, 0xD9, 0xD1, 0x1B, 0x48, ++ 0x1D, 0xF0, 0x9A, 0xFF, 0x18, 0x4B, 0x01, 0x22, 0x88, 0xF8, 0x06, 0x20, ++ 0x30, 0x46, 0xD3, 0xF8, 0xBC, 0x31, 0xBD, 0xE8, 0xF0, 0x41, 0x18, 0x47, ++ 0xD6, 0xF8, 0x94, 0x10, 0x14, 0x4A, 0xA2, 0xFB, 0x03, 0x02, 0x22, 0xF0, ++ 0x03, 0x00, 0x00, 0xEB, 0x92, 0x02, 0x8A, 0x42, 0xE1, 0xD8, 0xE6, 0xE7, ++ 0xD6, 0xF8, 0x90, 0x30, 0xD5, 0xE7, 0x0F, 0x49, 0x0F, 0x48, 0x40, 0xF2, ++ 0x13, 0x22, 0x1E, 0xF0, 0xF5, 0xF9, 0x9C, 0xE7, 0x00, 0x23, 0x0D, 0x48, ++ 0x88, 0xF8, 0x06, 0x30, 0x1D, 0xF0, 0x74, 0xFF, 0xAF, 0xE7, 0x0B, 0x48, ++ 0xD4, 0xE7, 0x00, 0xBF, 0x1C, 0x7F, 0x15, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x00, 0x10, 0x50, 0x40, 0x80, 0xC3, 0xC9, 0x01, 0x88, 0x1A, 0x17, 0x00, ++ 0x44, 0x7F, 0x15, 0x00, 0xAB, 0xAA, 0xAA, 0xAA, 0x70, 0x79, 0x15, 0x00, ++ 0x64, 0x7D, 0x15, 0x00, 0x3C, 0x7F, 0x15, 0x00, 0x30, 0x7F, 0x15, 0x00, ++ 0xCC, 0x35, 0x17, 0x00, 0x06, 0x4B, 0x1B, 0x68, 0x1B, 0x78, 0x01, 0x2B, ++ 0x05, 0xD0, 0x02, 0x2B, 0x01, 0xD0, 0x04, 0xF0, 0xEF, 0xBC, 0x03, 0xF0, ++ 0xD5, 0xBF, 0x00, 0xF0, 0xD7, 0xBF, 0x00, 0xBF, 0x78, 0x36, 0x17, 0x00, ++ 0x08, 0xB5, 0x08, 0x46, 0x00, 0xF0, 0x6C, 0xFE, 0x01, 0x20, 0x08, 0xBD, ++ 0x70, 0xB5, 0x30, 0x4C, 0x23, 0x68, 0x1B, 0x78, 0x01, 0x2B, 0x1E, 0xD0, ++ 0x02, 0x2B, 0x14, 0xD1, 0x2D, 0x4B, 0x2E, 0x49, 0x2E, 0x4A, 0xC3, 0xE9, ++ 0x06, 0x12, 0x2E, 0x4D, 0xD5, 0xF8, 0x14, 0x31, 0x98, 0x47, 0xD5, 0xF8, ++ 0x18, 0x31, 0x98, 0x47, 0x23, 0x68, 0x1B, 0x78, 0x01, 0x2B, 0x36, 0xD0, ++ 0x02, 0x2B, 0x1D, 0xD0, 0x03, 0x2B, 0x0E, 0xD0, 0x70, 0xBD, 0x03, 0x2B, ++ 0xED, 0xD1, 0x22, 0x4B, 0x25, 0x49, 0x26, 0x4A, 0xC3, 0xE9, 0x08, 0x12, ++ 0xE7, 0xE7, 0x1F, 0x4B, 0x24, 0x49, 0x25, 0x4A, 0xC3, 0xE9, 0x02, 0x12, ++ 0xE1, 0xE7, 0x24, 0x4B, 0x1B, 0x4C, 0x24, 0x4A, 0x1A, 0x60, 0x04, 0xF0, ++ 0x87, 0xFC, 0x23, 0x6A, 0x22, 0x48, 0x98, 0x47, 0x63, 0x6A, 0xBD, 0xE8, ++ 0x70, 0x40, 0x18, 0x47, 0x1D, 0x4B, 0x20, 0x49, 0x20, 0x4A, 0x19, 0x60, ++ 0x13, 0x4D, 0x42, 0xF2, 0x34, 0x03, 0x00, 0x21, 0xD1, 0x52, 0x04, 0xF0, ++ 0x1B, 0xF8, 0x03, 0xF0, 0x35, 0xFF, 0xAB, 0x69, 0x18, 0x48, 0x98, 0x47, ++ 0xEB, 0x69, 0x98, 0x47, 0x04, 0xF0, 0x1A, 0xFC, 0x23, 0x68, 0x1B, 0x78, ++ 0xCA, 0xE7, 0x12, 0x4B, 0x09, 0x4D, 0x16, 0x4A, 0x1A, 0x60, 0x00, 0xF0, ++ 0xCB, 0xFE, 0x00, 0xF0, 0xE9, 0xFE, 0x00, 0xF0, 0x13, 0xFF, 0xAB, 0x68, ++ 0x0E, 0x48, 0x98, 0x47, 0xEB, 0x68, 0x98, 0x47, 0x23, 0x68, 0x1B, 0x78, ++ 0xB6, 0xE7, 0x00, 0xBF, 0x78, 0x36, 0x17, 0x00, 0x28, 0x58, 0x17, 0x00, ++ 0xA1, 0xA9, 0x12, 0x00, 0x85, 0xA9, 0x12, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x3D, 0xB2, 0x12, 0x00, 0x29, 0xB2, 0x12, 0x00, 0x0D, 0x7A, 0x12, 0x00, ++ 0xF9, 0x79, 0x12, 0x00, 0x1C, 0x58, 0x17, 0x00, 0xBC, 0x60, 0x17, 0x00, ++ 0xB8, 0x7F, 0x15, 0x00, 0xA4, 0x60, 0x17, 0x00, 0x7C, 0x36, 0x17, 0x00, ++ 0x28, 0x60, 0x17, 0x00, 0x10, 0xB5, 0x0B, 0x4C, 0x50, 0x22, 0x51, 0x23, ++ 0x04, 0xF2, 0x14, 0x50, 0xA4, 0xF8, 0x10, 0x25, 0x84, 0xF8, 0x12, 0x35, ++ 0x1C, 0xF0, 0xD8, 0xFC, 0x27, 0x22, 0x28, 0x23, 0x04, 0xF5, 0xF4, 0x60, ++ 0xA4, 0xF8, 0x9C, 0x27, 0x84, 0xF8, 0x9E, 0x37, 0xBD, 0xE8, 0x10, 0x40, ++ 0x1C, 0xF0, 0xCC, 0xBC, 0x58, 0x58, 0x17, 0x00, 0x70, 0xB5, 0x41, 0xF6, ++ 0x10, 0x02, 0x25, 0x4D, 0x25, 0x4C, 0x4C, 0xF2, 0xBF, 0x03, 0x41, 0xF6, ++ 0x12, 0x00, 0x00, 0x26, 0xAB, 0x52, 0x41, 0xF6, 0x14, 0x01, 0x05, 0xF5, ++ 0xC1, 0x52, 0xA5, 0xF8, 0x00, 0x3C, 0x2E, 0x54, 0x05, 0xF6, 0x08, 0x40, ++ 0x6E, 0x50, 0x16, 0x70, 0x85, 0xF8, 0x02, 0x6C, 0xC5, 0xF8, 0x04, 0x6C, ++ 0x1C, 0xF0, 0xAE, 0xFC, 0xA4, 0xF1, 0x0C, 0x00, 0x1C, 0xF0, 0xAA, 0xFC, ++ 0x04, 0xF5, 0x00, 0x60, 0x1C, 0xF0, 0xA6, 0xFC, 0x04, 0xF6, 0x08, 0x00, ++ 0x1C, 0xF0, 0xA2, 0xFC, 0x42, 0xF2, 0x34, 0x03, 0x31, 0x46, 0x4F, 0xF4, ++ 0x00, 0x62, 0x20, 0x46, 0xEE, 0x52, 0x85, 0xF8, 0x02, 0x6C, 0xC5, 0xF8, ++ 0x04, 0x6C, 0xF9, 0xF7, 0x05, 0xFC, 0x04, 0xF5, 0x00, 0x65, 0x2E, 0x46, ++ 0x21, 0x46, 0x30, 0x46, 0x10, 0x34, 0x1C, 0xF0, 0x91, 0xFC, 0xAC, 0x42, ++ 0xF8, 0xD1, 0x09, 0x4A, 0x00, 0x21, 0x02, 0xF5, 0xB4, 0x70, 0xA2, 0xF1, ++ 0x24, 0x03, 0x43, 0xF8, 0x04, 0x1B, 0x93, 0x42, 0xFB, 0xD1, 0x03, 0xF1, ++ 0x24, 0x02, 0x82, 0x42, 0xF5, 0xD1, 0x70, 0xBD, 0x7C, 0x36, 0x17, 0x00, ++ 0xA0, 0x4E, 0x17, 0x00, 0xD8, 0x56, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0x40, 0x20, 0x85, 0xB0, 0x1C, 0xF0, 0xF6, 0xFB, 0xA7, 0x4B, 0x9B, 0x68, ++ 0x03, 0x93, 0x00, 0x2B, 0x00, 0xF0, 0x80, 0x81, 0xDF, 0xF8, 0xB0, 0x92, ++ 0xDF, 0xF8, 0xB0, 0xB2, 0x09, 0xE0, 0x94, 0xF8, 0x64, 0x30, 0x63, 0xB1, ++ 0x03, 0x9B, 0x1B, 0x68, 0x03, 0x93, 0x03, 0x9B, 0x00, 0x2B, 0x00, 0xF0, ++ 0x71, 0x81, 0x03, 0x9C, 0x20, 0x46, 0x07, 0xF0, 0x33, 0xFF, 0x00, 0x28, ++ 0xEF, 0xD0, 0x03, 0x9B, 0x9A, 0x4C, 0x03, 0xF5, 0xA3, 0x65, 0x01, 0x26, ++ 0xEF, 0xF3, 0x10, 0x83, 0xDF, 0x07, 0x02, 0xD4, 0x72, 0xB6, 0xC9, 0xF8, ++ 0x00, 0x60, 0x23, 0x68, 0x28, 0x46, 0x01, 0x33, 0x23, 0x60, 0x1C, 0xF0, ++ 0x8B, 0xFC, 0x23, 0x68, 0x5A, 0x1E, 0x2B, 0xB1, 0xD9, 0xF8, 0x00, 0x30, ++ 0x22, 0x60, 0x0A, 0xB9, 0x03, 0xB1, 0x62, 0xB6, 0x05, 0x21, 0x38, 0xB1, ++ 0xDB, 0xF8, 0x24, 0x34, 0x98, 0x47, 0xEF, 0xF3, 0x10, 0x83, 0xDF, 0x07, ++ 0xE7, 0xD4, 0xE3, 0xE7, 0x89, 0x4B, 0x93, 0xF8, 0xFF, 0x31, 0x00, 0x2B, ++ 0xC8, 0xD1, 0xDD, 0xF8, 0x0C, 0xA0, 0x87, 0x4E, 0x04, 0x23, 0x01, 0x93, ++ 0xDA, 0xF8, 0x10, 0x35, 0x00, 0x2B, 0x00, 0xF0, 0x8C, 0x80, 0x9D, 0xF8, ++ 0x04, 0x70, 0x0A, 0xF5, 0xA2, 0x68, 0x40, 0x46, 0x1C, 0xF0, 0x62, 0xFC, ++ 0x80, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x05, 0x46, ++ 0x43, 0x7F, 0x7F, 0xDB, 0x4F, 0xF4, 0x1E, 0x72, 0x02, 0xFB, 0x03, 0x62, ++ 0x92, 0xF8, 0x25, 0x10, 0x19, 0xB9, 0xE9, 0x8B, 0x08, 0x07, 0x40, 0xF1, ++ 0x07, 0x81, 0x4F, 0xF4, 0x1E, 0x72, 0x02, 0xFB, 0x03, 0x62, 0x92, 0xF8, ++ 0x24, 0x20, 0x01, 0x2A, 0x00, 0xF0, 0x9E, 0x80, 0xDB, 0xF8, 0x24, 0x34, ++ 0x28, 0x46, 0x39, 0x46, 0x98, 0x47, 0xDA, 0xF8, 0x10, 0x35, 0x00, 0x2B, ++ 0xD7, 0xD1, 0x0A, 0xF5, 0x9D, 0x65, 0xA8, 0x46, 0xEF, 0xF3, 0x10, 0x83, ++ 0xDD, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x01, 0x23, 0xC9, 0xF8, 0x00, 0x30, ++ 0x23, 0x68, 0xDA, 0xF8, 0xE8, 0x14, 0x5A, 0x1C, 0x22, 0x60, 0x2A, 0xB1, ++ 0xD9, 0xF8, 0x00, 0x20, 0x23, 0x60, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, ++ 0x00, 0x29, 0x34, 0xD0, 0x4A, 0x7F, 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, ++ 0x02, 0x63, 0x93, 0xF8, 0x25, 0x00, 0x00, 0x28, 0x00, 0xF0, 0x87, 0x80, ++ 0x93, 0xF8, 0x24, 0x30, 0x01, 0x2B, 0x46, 0xD0, 0xC9, 0x7E, 0xDB, 0xF8, ++ 0x34, 0x31, 0x10, 0x46, 0x98, 0x47, 0x00, 0x28, 0x00, 0xF0, 0xD7, 0x80, ++ 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x01, 0x23, ++ 0xC9, 0xF8, 0x00, 0x30, 0x23, 0x68, 0x40, 0x46, 0x01, 0x33, 0x23, 0x60, ++ 0x1C, 0xF0, 0x00, 0xFC, 0x23, 0x68, 0x05, 0x46, 0x33, 0xB1, 0x01, 0x3B, ++ 0xD9, 0xF8, 0x00, 0x20, 0x23, 0x60, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, ++ 0xDB, 0xF8, 0x24, 0x34, 0x39, 0x46, 0x28, 0x46, 0x98, 0x47, 0x00, 0x2D, ++ 0xB4, 0xD1, 0x01, 0x9B, 0x01, 0x3B, 0x1D, 0x46, 0x38, 0x46, 0x01, 0x93, ++ 0x0B, 0xF0, 0x26, 0xFA, 0x2B, 0x46, 0x01, 0x33, 0xAA, 0xF1, 0x08, 0x0A, ++ 0x3F, 0xF4, 0x38, 0xAF, 0xDA, 0xF8, 0x10, 0x35, 0x00, 0x2B, 0x7F, 0xF4, ++ 0x74, 0xAF, 0x9D, 0xF8, 0x04, 0x70, 0x9C, 0xE7, 0x09, 0x2B, 0x7F, 0xF6, ++ 0x7D, 0xAF, 0x3C, 0x49, 0x3C, 0x48, 0x4F, 0xF4, 0x96, 0x72, 0x1D, 0xF0, ++ 0xE1, 0xFF, 0x6B, 0x7F, 0x74, 0xE7, 0xEF, 0xF3, 0x10, 0x81, 0xC9, 0x07, ++ 0x02, 0xD4, 0x72, 0xB6, 0xC9, 0xF8, 0x00, 0x30, 0x23, 0x68, 0x02, 0x92, ++ 0x01, 0x33, 0x40, 0x46, 0x23, 0x60, 0x1C, 0xF0, 0xC1, 0xFB, 0x23, 0x68, ++ 0x02, 0x9A, 0x05, 0x46, 0x33, 0xB1, 0x01, 0x3B, 0xD9, 0xF8, 0x00, 0x10, ++ 0x23, 0x60, 0x0B, 0xB9, 0x01, 0xB1, 0x62, 0xB6, 0x01, 0x9B, 0x4F, 0x20, ++ 0x00, 0xFB, 0x02, 0x30, 0x41, 0x30, 0x06, 0xEB, 0xC0, 0x00, 0x29, 0x46, ++ 0x1C, 0xF0, 0x68, 0xFB, 0x00, 0x2D, 0x7F, 0xF4, 0x6F, 0xAF, 0xB8, 0xE7, ++ 0x23, 0x4A, 0x12, 0x68, 0xB2, 0xF9, 0x00, 0x20, 0x00, 0x2A, 0x4D, 0xDB, ++ 0xEA, 0x8B, 0xD2, 0x07, 0x7F, 0xF5, 0x5D, 0xAF, 0x01, 0x9A, 0x4F, 0x20, ++ 0x46, 0x32, 0x10, 0xFB, 0x03, 0x20, 0x29, 0x46, 0x06, 0xEB, 0xC0, 0x00, ++ 0x1C, 0xF0, 0x50, 0xFB, 0x51, 0xE7, 0x93, 0xF8, 0x23, 0x10, 0x1B, 0x48, ++ 0x1D, 0xF0, 0x24, 0xFD, 0xEF, 0xF3, 0x10, 0x83, 0xD8, 0x07, 0x03, 0xD4, ++ 0x72, 0xB6, 0x01, 0x23, 0xC9, 0xF8, 0x00, 0x30, 0x23, 0x68, 0x40, 0x46, ++ 0x01, 0x33, 0x23, 0x60, 0x1C, 0xF0, 0x80, 0xFB, 0x4F, 0xF0, 0x00, 0x42, ++ 0x39, 0x46, 0x05, 0x46, 0x28, 0xF0, 0x2A, 0xFE, 0x23, 0x68, 0x00, 0x2B, ++ 0x85, 0xD0, 0x01, 0x3B, 0xD9, 0xF8, 0x00, 0x20, 0x23, 0x60, 0x00, 0x2B, ++ 0x7F, 0xF4, 0x7F, 0xAF, 0x00, 0x2A, 0x3F, 0xF4, 0x7C, 0xAF, 0x62, 0xB6, ++ 0x00, 0x2D, 0x7F, 0xF4, 0x2F, 0xAF, 0x78, 0xE7, 0x00, 0x88, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x20, 0x62, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x50, 0x7F, 0x15, 0x00, ++ 0x7C, 0x7F, 0x15, 0x00, 0x38, 0x61, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0xEA, 0x8B, 0xD1, 0x07, 0xB2, 0xD4, 0x11, 0x49, 0x11, 0x48, 0x02, 0x93, ++ 0x40, 0xF2, 0x35, 0x12, 0x1D, 0xF0, 0x5A, 0xFF, 0x02, 0x9B, 0xA5, 0xE7, ++ 0x92, 0xF8, 0x23, 0x10, 0x0D, 0x48, 0x1D, 0xF0, 0xD9, 0xFC, 0x28, 0x46, ++ 0x4F, 0xF0, 0x00, 0x42, 0x39, 0x46, 0x28, 0xF0, 0xED, 0xFD, 0xDA, 0xF8, ++ 0x10, 0x35, 0x00, 0x2B, 0x7F, 0xF4, 0xD3, 0xAE, 0xF9, 0xE6, 0x07, 0x4A, ++ 0x01, 0x23, 0x82, 0xF8, 0x00, 0x32, 0x42, 0xE7, 0x05, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x8F, 0x00, 0xBF, 0x70, 0x79, 0x15, 0x00, 0x8C, 0x7F, 0x15, 0x00, ++ 0x7C, 0x7F, 0x15, 0x00, 0x20, 0x62, 0x17, 0x00, 0x08, 0x4B, 0x1B, 0x68, ++ 0x1B, 0x78, 0x01, 0x2B, 0x05, 0xD0, 0x02, 0x2B, 0x07, 0xD0, 0x06, 0x4B, ++ 0xD3, 0xF8, 0x30, 0x31, 0x18, 0x47, 0x04, 0x4B, 0xD3, 0xF8, 0x08, 0x33, ++ 0x18, 0x47, 0x03, 0xF0, 0x8F, 0xBF, 0x00, 0xBF, 0x78, 0x36, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x08, 0x4B, 0x1B, 0x68, 0x1B, 0x78, 0x01, 0x2B, ++ 0x07, 0xD0, 0x02, 0x2B, 0x03, 0xD1, 0x06, 0x4B, 0xD3, 0xF8, 0x34, 0x34, ++ 0x18, 0x47, 0x04, 0xF0, 0x93, 0xBB, 0x03, 0x4B, 0xD3, 0xF8, 0x00, 0x33, ++ 0x18, 0x47, 0x00, 0xBF, 0x78, 0x36, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x07, 0x4B, 0x1B, 0x68, 0x1B, 0x78, 0x01, 0x2B, 0x05, 0xD0, 0x02, 0x2B, ++ 0x01, 0xD0, 0x04, 0xF0, 0x83, 0xBB, 0x04, 0xF0, 0x7B, 0xB8, 0x03, 0x4B, ++ 0xD3, 0xF8, 0x0C, 0x33, 0x18, 0x47, 0x00, 0xBF, 0x78, 0x36, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x08, 0x4B, 0x1B, 0x68, 0x1B, 0x78, 0x01, 0x2B, ++ 0x07, 0xD0, 0x02, 0x2B, 0x03, 0xD1, 0x06, 0x4B, 0xD3, 0xF8, 0x38, 0x34, ++ 0x18, 0x47, 0x04, 0xF0, 0x6D, 0xBB, 0x03, 0x4B, 0xD3, 0xF8, 0x04, 0x33, ++ 0x18, 0x47, 0x00, 0xBF, 0x78, 0x36, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x06, 0x4B, 0x1B, 0x68, 0x1B, 0x78, 0x01, 0x2B, 0x05, 0xD0, 0x02, 0x2B, ++ 0x01, 0xD0, 0x04, 0xF0, 0x5D, 0xBB, 0x04, 0xF0, 0xAD, 0xB9, 0x01, 0xF0, ++ 0x6B, 0xB9, 0x00, 0xBF, 0x78, 0x36, 0x17, 0x00, 0x08, 0xB5, 0x0C, 0x22, ++ 0x08, 0x23, 0x01, 0x21, 0x40, 0xF2, 0x0D, 0x40, 0x1B, 0xF0, 0xE6, 0xFD, ++ 0xBD, 0xE8, 0x08, 0x40, 0x1B, 0xF0, 0x12, 0xBE, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0x89, 0xB0, 0x82, 0x46, 0x00, 0x68, 0x05, 0x91, 0x03, 0x90, 0x07, 0x92, ++ 0x62, 0xB1, 0xB0, 0xFB, 0xF2, 0xF3, 0x11, 0x46, 0x02, 0xFB, 0x13, 0x02, ++ 0x0B, 0x46, 0x00, 0x2A, 0x40, 0xF0, 0xDE, 0x80, 0x03, 0x9A, 0x04, 0x3B, ++ 0x1A, 0x44, 0x03, 0x92, 0x9A, 0xF8, 0x08, 0x30, 0x00, 0x2B, 0x00, 0xF0, ++ 0xD2, 0x80, 0x00, 0x23, 0xDF, 0xF8, 0xC0, 0x81, 0xDF, 0xF8, 0xC0, 0x91, ++ 0x00, 0x93, 0x1F, 0x46, 0xD3, 0x46, 0x08, 0xE0, 0x00, 0x9B, 0x9B, 0xF8, ++ 0x08, 0x20, 0x01, 0x33, 0xDF, 0xB2, 0xBA, 0x42, 0x00, 0x93, 0x40, 0xF2, ++ 0xC0, 0x80, 0x05, 0x9B, 0xDB, 0xF8, 0x0C, 0x10, 0x33, 0xF8, 0x27, 0x00, ++ 0x03, 0xEB, 0x87, 0x02, 0x00, 0x24, 0x55, 0x88, 0x07, 0xEB, 0x47, 0x02, ++ 0x01, 0xEB, 0x82, 0x06, 0x41, 0xF8, 0x22, 0x40, 0xB4, 0x80, 0x00, 0x2D, ++ 0xE4, 0xD0, 0x03, 0x1D, 0x01, 0x93, 0x03, 0x9B, 0x75, 0x80, 0x03, 0xF1, ++ 0x04, 0x0A, 0x02, 0x95, 0xB0, 0x80, 0x55, 0x46, 0xCD, 0xF8, 0x18, 0xB0, ++ 0xA2, 0x46, 0x04, 0x97, 0x34, 0xE0, 0xD8, 0xF8, 0x04, 0x20, 0x13, 0x44, ++ 0xAB, 0x42, 0x37, 0xD3, 0x04, 0x9B, 0x05, 0xF8, 0x04, 0x3C, 0xD8, 0xF8, ++ 0x00, 0x30, 0xAB, 0x42, 0x41, 0xD8, 0xD8, 0xF8, 0x04, 0x20, 0x13, 0x44, ++ 0xAB, 0x42, 0x3C, 0xD3, 0x55, 0x23, 0x05, 0xF8, 0x03, 0x3C, 0xD8, 0xF8, ++ 0x00, 0x30, 0xAB, 0x42, 0x46, 0xD8, 0xD8, 0xF8, 0x04, 0x20, 0x13, 0x44, ++ 0xAB, 0x42, 0x41, 0xD3, 0x00, 0x23, 0x05, 0xF8, 0x02, 0x3C, 0xD8, 0xF8, ++ 0x00, 0x30, 0xAB, 0x42, 0x4B, 0xD8, 0xD8, 0xF8, 0x04, 0x20, 0x13, 0x44, ++ 0xAB, 0x42, 0x46, 0xD3, 0xCB, 0xF8, 0x04, 0x70, 0x33, 0x88, 0x01, 0x99, ++ 0x01, 0x33, 0x01, 0x34, 0x33, 0x80, 0x02, 0x9B, 0xA2, 0xB2, 0x93, 0x42, ++ 0x0D, 0x44, 0x48, 0xD9, 0xD8, 0xF8, 0x00, 0x30, 0xAB, 0x42, 0x57, 0x46, ++ 0xA5, 0xF1, 0x04, 0x0B, 0xAA, 0x46, 0xC2, 0xD9, 0xD9, 0xF8, 0x00, 0x30, ++ 0xAB, 0x42, 0x04, 0xD8, 0xD9, 0xF8, 0x04, 0x20, 0x13, 0x44, 0xAB, 0x42, ++ 0xBE, 0xD2, 0x31, 0x48, 0x29, 0x46, 0xFF, 0xF7, 0xE9, 0xF9, 0xD8, 0xF8, ++ 0x00, 0x30, 0xAB, 0x42, 0xBD, 0xD9, 0xD9, 0xF8, 0x00, 0x30, 0xAB, 0x42, ++ 0x04, 0xD8, 0xD9, 0xF8, 0x04, 0x20, 0x13, 0x44, 0xAB, 0x42, 0xB9, 0xD2, ++ 0x29, 0x48, 0x29, 0x46, 0xFF, 0xF7, 0xD8, 0xF9, 0xD8, 0xF8, 0x00, 0x30, ++ 0xAB, 0x42, 0xB8, 0xD9, 0xD9, 0xF8, 0x00, 0x30, 0xAB, 0x42, 0x04, 0xD8, ++ 0xD9, 0xF8, 0x04, 0x20, 0x13, 0x44, 0xAB, 0x42, 0xB4, 0xD2, 0x22, 0x48, ++ 0x29, 0x46, 0xFF, 0xF7, 0xC7, 0xF9, 0xD8, 0xF8, 0x00, 0x30, 0xAB, 0x42, ++ 0xB3, 0xD9, 0xD9, 0xF8, 0x00, 0x30, 0xAB, 0x42, 0x04, 0xD8, 0xD9, 0xF8, ++ 0x04, 0x20, 0x13, 0x44, 0xAB, 0x42, 0xAF, 0xD2, 0x29, 0x46, 0x1A, 0x48, ++ 0xFF, 0xF7, 0xB6, 0xF9, 0xAC, 0xE7, 0x0A, 0x46, 0x5D, 0x1E, 0x03, 0x99, ++ 0xDD, 0xF8, 0x18, 0xB0, 0xAD, 0xB2, 0x05, 0xFB, 0x02, 0x13, 0x05, 0xFB, ++ 0x02, 0x25, 0x48, 0x19, 0x07, 0x99, 0x03, 0x90, 0x04, 0x33, 0xB3, 0x60, ++ 0x00, 0x29, 0x3F, 0xF4, 0x47, 0xAF, 0xB0, 0xFB, 0xF1, 0xF3, 0x01, 0xFB, ++ 0x13, 0x02, 0x0B, 0x46, 0x22, 0xB1, 0x8B, 0x1A, 0x03, 0x2B, 0x9C, 0xBF, ++ 0x0A, 0x46, 0x9B, 0x18, 0x03, 0x9A, 0x04, 0x3B, 0x1A, 0x44, 0x03, 0x92, ++ 0x36, 0xE7, 0x09, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x8B, 0x1A, 0x03, 0x2B, ++ 0x9C, 0xBF, 0x0A, 0x46, 0x9B, 0x18, 0x1B, 0xE7, 0xE0, 0x7F, 0x15, 0x00, ++ 0x10, 0x80, 0x15, 0x00, 0x38, 0x80, 0x15, 0x00, 0x64, 0x80, 0x15, 0x00, ++ 0xC8, 0x25, 0x17, 0x00, 0xE4, 0x25, 0x17, 0x00, 0xF8, 0xB5, 0x06, 0x7A, ++ 0x00, 0x2E, 0x00, 0xF0, 0xBC, 0x80, 0xC5, 0x68, 0x00, 0x2D, 0x00, 0xF0, ++ 0x82, 0x80, 0x2C, 0x46, 0x01, 0x23, 0x09, 0xE0, 0x22, 0x88, 0xA2, 0xB9, ++ 0x9E, 0x42, 0x0F, 0xD9, 0x03, 0xEB, 0x43, 0x04, 0x05, 0xEB, 0x84, 0x04, ++ 0x01, 0x33, 0xDB, 0xB2, 0xA0, 0x88, 0x88, 0x42, 0x03, 0xEB, 0x43, 0x02, ++ 0xF0, 0xD2, 0x9E, 0x42, 0x02, 0xD9, 0x05, 0xEB, 0x82, 0x04, 0xF3, 0xE7, ++ 0x9E, 0x42, 0x00, 0xF0, 0x9E, 0x80, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, ++ 0x03, 0xD4, 0x72, 0xB6, 0x4E, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x4E, 0x4E, ++ 0x23, 0x88, 0x35, 0x68, 0x6A, 0x1C, 0x32, 0x60, 0x00, 0x2B, 0x5D, 0xD0, ++ 0x4B, 0x4F, 0xA5, 0x68, 0x3A, 0x68, 0xAA, 0x42, 0x28, 0xD8, 0x79, 0x68, ++ 0x11, 0x44, 0x8D, 0x42, 0x24, 0xD8, 0x29, 0x68, 0xA1, 0x60, 0x01, 0x3B, ++ 0xAA, 0x42, 0x23, 0x80, 0x32, 0xD8, 0x7B, 0x68, 0x13, 0x44, 0xAB, 0x42, ++ 0x2E, 0xD3, 0x15, 0xF8, 0x03, 0x1C, 0x55, 0x29, 0x53, 0xD1, 0xAA, 0x23, ++ 0x05, 0xF8, 0x03, 0x3C, 0x3B, 0x68, 0x9D, 0x42, 0x5D, 0xD3, 0x7A, 0x68, ++ 0x13, 0x44, 0x9D, 0x42, 0x59, 0xD8, 0x01, 0x23, 0x05, 0xF8, 0x02, 0x3C, ++ 0x33, 0x68, 0x00, 0x2B, 0x34, 0xD0, 0x36, 0x4A, 0x01, 0x3B, 0x12, 0x68, ++ 0x33, 0x60, 0x7B, 0xBB, 0x72, 0xB3, 0x35, 0xE0, 0x35, 0x48, 0x01, 0x68, ++ 0x8D, 0x42, 0x03, 0xD3, 0x40, 0x68, 0x01, 0x44, 0x8D, 0x42, 0xD2, 0xD9, ++ 0x29, 0x46, 0x32, 0x48, 0xFF, 0xF7, 0x12, 0xF9, 0x23, 0x88, 0x3A, 0x68, ++ 0x00, 0x21, 0x01, 0x3B, 0xAA, 0x42, 0xA1, 0x60, 0x23, 0x80, 0xCC, 0xD9, ++ 0x2B, 0x48, 0x03, 0x68, 0xAB, 0x42, 0x1F, 0xD8, 0x41, 0x68, 0x19, 0x44, ++ 0xA9, 0x42, 0x1B, 0xD3, 0x15, 0xF8, 0x03, 0x1C, 0x55, 0x29, 0x1C, 0xD1, ++ 0xAA, 0x42, 0x37, 0xD9, 0x42, 0x68, 0x13, 0x44, 0x9D, 0x42, 0xC2, 0xD9, ++ 0x29, 0x46, 0x24, 0x48, 0xFF, 0xF7, 0xF4, 0xF8, 0xC0, 0xE7, 0x23, 0x48, ++ 0xFF, 0xF7, 0xF0, 0xF8, 0x28, 0x46, 0xF8, 0xBD, 0xC2, 0xB1, 0x1A, 0x4B, ++ 0x35, 0x60, 0x1B, 0x68, 0xA5, 0xB9, 0x9B, 0xB1, 0x62, 0xB6, 0xF5, 0xE7, ++ 0x29, 0x46, 0x1D, 0x48, 0xFF, 0xF7, 0xE2, 0xF8, 0x00, 0x21, 0x33, 0x68, ++ 0x33, 0xB1, 0x13, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x33, 0x60, 0x0B, 0xB9, ++ 0x02, 0xB1, 0x62, 0xB6, 0x17, 0x48, 0x2A, 0x46, 0xFF, 0xF7, 0xD4, 0xF8, ++ 0x00, 0x25, 0x28, 0x46, 0xF8, 0xBD, 0x0F, 0x4A, 0x13, 0x68, 0x9D, 0x42, ++ 0x03, 0xD3, 0x52, 0x68, 0x13, 0x44, 0x9D, 0x42, 0x9D, 0xD9, 0x29, 0x46, ++ 0x10, 0x48, 0xFF, 0xF7, 0xC5, 0xF8, 0x9B, 0xE7, 0x79, 0x68, 0x0A, 0x44, ++ 0x95, 0x42, 0x8A, 0xD9, 0x9D, 0x42, 0xC5, 0xD3, 0xC0, 0xE7, 0x0C, 0x48, ++ 0xFF, 0xF7, 0xBA, 0xF8, 0x00, 0x25, 0xC7, 0xE7, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0xC8, 0x25, 0x17, 0x00, 0xE4, 0x25, 0x17, 0x00, ++ 0xCC, 0x80, 0x15, 0x00, 0x10, 0x80, 0x15, 0x00, 0x98, 0x80, 0x15, 0x00, ++ 0x00, 0x81, 0x15, 0x00, 0x28, 0x81, 0x15, 0x00, 0x38, 0x80, 0x15, 0x00, ++ 0xB4, 0x80, 0x15, 0x00, 0x00, 0x29, 0x00, 0xF0, 0x0F, 0x81, 0x2D, 0xE9, ++ 0xF8, 0x43, 0x03, 0x68, 0x8B, 0x42, 0x05, 0x46, 0x0C, 0x46, 0x59, 0xD8, ++ 0x42, 0x68, 0x13, 0x44, 0x99, 0x42, 0x55, 0xD8, 0x83, 0x4F, 0x3B, 0x68, ++ 0x99, 0x42, 0x55, 0xD3, 0x7A, 0x68, 0x13, 0x44, 0x99, 0x42, 0x51, 0xD8, ++ 0x14, 0xF8, 0x04, 0x6C, 0x2B, 0x7A, 0xB3, 0x42, 0x48, 0xD9, 0xD5, 0xF8, ++ 0x0C, 0x80, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, ++ 0x7A, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x7A, 0x4D, 0x38, 0x68, 0x2B, 0x68, ++ 0x84, 0x42, 0x03, 0xF1, 0x01, 0x03, 0x2B, 0x60, 0x25, 0xD3, 0x7B, 0x68, ++ 0x03, 0x44, 0x9C, 0x42, 0x21, 0xD8, 0x14, 0xF8, 0x03, 0x9C, 0xB9, 0xF1, ++ 0xAA, 0x0F, 0x00, 0xF0, 0xAB, 0x80, 0xB9, 0xF1, 0xFF, 0x0F, 0x20, 0xD1, ++ 0x7B, 0x68, 0x18, 0x44, 0x84, 0x42, 0x00, 0xF2, 0xA1, 0x80, 0x14, 0xF8, ++ 0x02, 0x0C, 0x01, 0x38, 0xC0, 0xB2, 0x04, 0xF8, 0x02, 0x0C, 0x00, 0x28, ++ 0x47, 0xD0, 0x2B, 0x68, 0x33, 0xB1, 0x67, 0x4A, 0x01, 0x3B, 0x12, 0x68, ++ 0x2B, 0x60, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0x40, 0xB2, 0xBD, 0xE8, ++ 0xF8, 0x83, 0x64, 0x4B, 0x1A, 0x68, 0x94, 0x42, 0x1E, 0xD2, 0x63, 0x48, ++ 0x21, 0x46, 0xFF, 0xF7, 0x47, 0xF8, 0x2B, 0x68, 0x33, 0xB1, 0x5D, 0x4A, ++ 0x01, 0x3B, 0x12, 0x68, 0x2B, 0x60, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, ++ 0x4F, 0xF0, 0xFF, 0x30, 0xBD, 0xE8, 0xF8, 0x83, 0x59, 0x4B, 0x1A, 0x68, ++ 0x94, 0x42, 0x03, 0xD3, 0x5B, 0x68, 0x1A, 0x44, 0x94, 0x42, 0xA5, 0xD9, ++ 0x57, 0x48, 0x21, 0x46, 0xFF, 0xF7, 0x2E, 0xF8, 0x00, 0x26, 0xA1, 0xE7, ++ 0x59, 0x68, 0x11, 0x44, 0x8C, 0x42, 0xDC, 0xD8, 0x14, 0xF8, 0x03, 0x9C, ++ 0xB9, 0xF1, 0xAA, 0x0F, 0x6C, 0xD0, 0xB9, 0xF1, 0xFF, 0x0F, 0xD8, 0xD1, ++ 0x84, 0x42, 0xB5, 0xD2, 0x1A, 0x68, 0x94, 0x42, 0x03, 0xD3, 0x5B, 0x68, ++ 0x1A, 0x44, 0x94, 0x42, 0xB3, 0xD9, 0x4B, 0x48, 0x21, 0x46, 0xFF, 0xF7, ++ 0x13, 0xF8, 0xB9, 0xF1, 0xFF, 0x0F, 0x5D, 0xD0, 0x06, 0xEB, 0x46, 0x06, ++ 0x08, 0xEB, 0x86, 0x09, 0x38, 0xF8, 0x26, 0x20, 0xB9, 0xF8, 0x02, 0x30, ++ 0x9A, 0x42, 0x4F, 0xEA, 0x86, 0x06, 0xBC, 0xD2, 0x3B, 0x68, 0x9C, 0x42, ++ 0x31, 0xD3, 0x7A, 0x68, 0x13, 0x44, 0x9C, 0x42, 0x2D, 0xD8, 0x55, 0x23, ++ 0x04, 0xF8, 0x03, 0x3C, 0x3B, 0x68, 0x9C, 0x42, 0x1A, 0xD3, 0x7A, 0x68, ++ 0x13, 0x44, 0x9C, 0x42, 0x16, 0xD8, 0xD9, 0xF8, 0x08, 0x30, 0x23, 0x60, ++ 0x38, 0xF8, 0x06, 0x30, 0x28, 0x68, 0xC9, 0xF8, 0x08, 0x40, 0x01, 0x33, ++ 0x28, 0xF8, 0x06, 0x30, 0x38, 0xB1, 0x2E, 0x4B, 0x01, 0x38, 0x1B, 0x68, ++ 0x28, 0x60, 0x10, 0xB9, 0x0B, 0xB1, 0x62, 0xB6, 0xA2, 0xE7, 0x00, 0x20, ++ 0xBD, 0xE8, 0xF8, 0x83, 0x2A, 0x4A, 0x13, 0x68, 0x9C, 0x42, 0x03, 0xD3, ++ 0x52, 0x68, 0x13, 0x44, 0x9C, 0x42, 0xE0, 0xD9, 0x21, 0x46, 0x2A, 0x48, ++ 0xFE, 0xF7, 0xD0, 0xFF, 0xDE, 0xE7, 0x24, 0x4A, 0x13, 0x68, 0x9C, 0x42, ++ 0x03, 0xD3, 0x52, 0x68, 0x13, 0x44, 0x9C, 0x42, 0xC9, 0xD9, 0x21, 0x46, ++ 0x24, 0x48, 0xFE, 0xF7, 0xC3, 0xFF, 0xC7, 0xE7, 0x1D, 0x4B, 0xA1, 0xE7, ++ 0x14, 0xF8, 0x02, 0x0C, 0x01, 0x38, 0xC0, 0xB2, 0x04, 0xF8, 0x02, 0x0C, ++ 0x00, 0x28, 0x7F, 0xF4, 0x5C, 0xAF, 0xA5, 0xE7, 0x84, 0x42, 0xBF, 0xF4, ++ 0x4B, 0xAF, 0x96, 0xE7, 0x3B, 0x68, 0x9C, 0x42, 0x11, 0xD3, 0x7A, 0x68, ++ 0x13, 0x44, 0x9C, 0x42, 0x0D, 0xD8, 0x01, 0x23, 0x04, 0xF8, 0x02, 0x3C, ++ 0x2B, 0x68, 0x33, 0xB1, 0x0D, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x2B, 0x60, ++ 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0x01, 0x20, 0x60, 0xE7, 0x0B, 0x4A, ++ 0x13, 0x68, 0x9C, 0x42, 0x03, 0xD3, 0x52, 0x68, 0x13, 0x44, 0x9C, 0x42, ++ 0xE9, 0xD9, 0x21, 0x46, 0x0C, 0x48, 0xFE, 0xF7, 0x91, 0xFF, 0xE7, 0xE7, ++ 0x4F, 0xF0, 0xFF, 0x30, 0x70, 0x47, 0x00, 0xBF, 0xC8, 0x25, 0x17, 0x00, ++ 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0xE4, 0x25, 0x17, 0x00, ++ 0x00, 0x81, 0x15, 0x00, 0x50, 0x81, 0x15, 0x00, 0x80, 0x81, 0x15, 0x00, ++ 0x64, 0x80, 0x15, 0x00, 0x10, 0x80, 0x15, 0x00, 0x38, 0x80, 0x15, 0x00, ++ 0x0B, 0x4A, 0x13, 0x68, 0x83, 0x42, 0x05, 0xD8, 0x52, 0x68, 0x13, 0x44, ++ 0x98, 0x42, 0x01, 0xD8, 0x01, 0x20, 0x70, 0x47, 0x07, 0x4A, 0x13, 0x68, ++ 0x98, 0x42, 0x06, 0xD3, 0x52, 0x68, 0x13, 0x44, 0x98, 0x42, 0x8C, 0xBF, ++ 0x00, 0x20, 0x01, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0xBF, ++ 0xC8, 0x25, 0x17, 0x00, 0xE4, 0x25, 0x17, 0x00, 0x10, 0x4B, 0x70, 0xB5, ++ 0x10, 0x4C, 0xDC, 0x60, 0x15, 0x46, 0x0E, 0x46, 0x03, 0x24, 0x01, 0x46, ++ 0x20, 0x22, 0x18, 0x46, 0x5D, 0x60, 0x1C, 0x72, 0x1E, 0x60, 0xFF, 0xF7, ++ 0xCD, 0xFC, 0x0B, 0x4B, 0x4F, 0xF4, 0x80, 0x32, 0x01, 0x21, 0x4F, 0xF0, ++ 0x02, 0x15, 0x04, 0x24, 0x4F, 0xF4, 0x80, 0x20, 0x5A, 0x60, 0x00, 0x22, ++ 0xC3, 0xE9, 0x05, 0x40, 0xDD, 0x60, 0x19, 0x60, 0x99, 0x60, 0x1A, 0x61, ++ 0x9A, 0x83, 0x70, 0xBD, 0xE4, 0x25, 0x17, 0x00, 0xF4, 0x25, 0x17, 0x00, ++ 0xA8, 0x25, 0x17, 0x00, 0x38, 0xB5, 0x0F, 0x4B, 0x1B, 0x68, 0x1B, 0x78, ++ 0x01, 0x2B, 0x05, 0x46, 0x0D, 0xD0, 0x0D, 0x48, 0x7C, 0x21, 0xFF, 0xF7, ++ 0xAB, 0xFD, 0x04, 0x46, 0x2C, 0xB1, 0x20, 0x46, 0xFF, 0xF7, 0xAC, 0xFF, ++ 0x38, 0xB1, 0x04, 0xF8, 0x01, 0x5C, 0x20, 0x46, 0x38, 0xBD, 0x00, 0xF0, ++ 0xC3, 0xF9, 0x04, 0x46, 0xF2, 0xE7, 0x21, 0x46, 0x04, 0x48, 0xFE, 0xF7, ++ 0x17, 0xFF, 0x20, 0x46, 0x38, 0xBD, 0x00, 0xBF, 0x78, 0x36, 0x17, 0x00, ++ 0xE4, 0x25, 0x17, 0x00, 0xAC, 0x81, 0x15, 0x00, 0x10, 0xB5, 0x04, 0x46, ++ 0xFF, 0xF7, 0x92, 0xFF, 0x98, 0xB1, 0x31, 0x4B, 0x14, 0xF8, 0x04, 0x2C, ++ 0x1B, 0x68, 0x1B, 0x78, 0x01, 0x2B, 0x23, 0xD0, 0x02, 0x2B, 0x2A, 0xD0, ++ 0x03, 0x2B, 0x15, 0xD1, 0x2C, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0x30, 0xDB, 0x02, 0x2A, 0x30, 0xD0, 0x10, 0xBD, 0x29, 0x48, ++ 0x21, 0x46, 0xFE, 0xF7, 0xF1, 0xFE, 0x25, 0x4B, 0x1B, 0x68, 0x1B, 0x78, ++ 0x01, 0x2B, 0x11, 0xD0, 0x02, 0x2B, 0x18, 0xD0, 0x03, 0x2B, 0x29, 0xD0, ++ 0x20, 0x46, 0xFF, 0xF7, 0x6D, 0xFF, 0x90, 0xB3, 0x21, 0x46, 0x21, 0x48, ++ 0xBD, 0xE8, 0x10, 0x40, 0xFF, 0xF7, 0x3C, 0xBE, 0x02, 0x2A, 0x0F, 0xD0, ++ 0x00, 0x2A, 0xE3, 0xD1, 0x20, 0x46, 0xBD, 0xE8, 0x10, 0x40, 0x00, 0xF0, ++ 0x9B, 0xB9, 0x02, 0x2A, 0x26, 0xD0, 0x00, 0x2A, 0xDA, 0xD1, 0x20, 0x46, ++ 0xBD, 0xE8, 0x10, 0x40, 0x03, 0xF0, 0xF2, 0xB9, 0x20, 0x46, 0xBD, 0xE8, ++ 0x10, 0x40, 0x00, 0xF0, 0x45, 0xB9, 0x02, 0x2A, 0x0C, 0xD1, 0x13, 0x4B, ++ 0x20, 0x46, 0xD3, 0xF8, 0xE8, 0x34, 0xBD, 0xE8, 0x10, 0x40, 0x18, 0x47, ++ 0x0C, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xC1, 0xDA, ++ 0xBD, 0xE8, 0x10, 0x40, 0x0C, 0x49, 0x0D, 0x48, 0xBE, 0x22, 0x1D, 0xF0, ++ 0xF5, 0xBA, 0x21, 0x46, 0x0B, 0x48, 0xFE, 0xF7, 0xAD, 0xFE, 0xC7, 0xE7, ++ 0x20, 0x46, 0xBD, 0xE8, 0x10, 0x40, 0x03, 0xF0, 0x21, 0xB9, 0x00, 0xBF, ++ 0x78, 0x36, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, 0x50, 0x81, 0x15, 0x00, ++ 0xE4, 0x25, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0xD4, 0x81, 0x15, 0x00, 0xE4, 0x81, 0x15, 0x00, 0x30, 0xB5, 0x1A, 0x4C, ++ 0x1A, 0x4A, 0x23, 0x68, 0x1A, 0x48, 0x5D, 0x88, 0x99, 0x88, 0xB2, 0xF8, ++ 0xD4, 0x20, 0x85, 0xB0, 0x04, 0x3A, 0xAD, 0xF8, 0x02, 0x50, 0xDD, 0x88, ++ 0xAD, 0xF8, 0x06, 0x10, 0x19, 0x89, 0xAD, 0xF8, 0x0A, 0x50, 0xD3, 0xE9, ++ 0x05, 0x35, 0xAD, 0xF8, 0x0E, 0x10, 0x01, 0x21, 0x03, 0x60, 0x01, 0x72, ++ 0x10, 0x4B, 0x45, 0x60, 0x0C, 0x21, 0xC3, 0x60, 0xAD, 0xF8, 0x0C, 0x20, ++ 0x40, 0xF2, 0x3C, 0x63, 0xAD, 0xF8, 0x00, 0x10, 0x7C, 0x25, 0x69, 0x46, ++ 0x20, 0x22, 0xAD, 0xF8, 0x08, 0x30, 0xAD, 0xF8, 0x04, 0x50, 0xFF, 0xF7, ++ 0xE9, 0xFB, 0x23, 0x68, 0x01, 0xA8, 0xD3, 0xE9, 0x07, 0x12, 0xFF, 0xF7, ++ 0x07, 0xFF, 0x05, 0xB0, 0x30, 0xBD, 0x00, 0xBF, 0x78, 0x36, 0x17, 0x00, ++ 0x2C, 0x19, 0x17, 0x00, 0xC8, 0x25, 0x17, 0x00, 0xD8, 0x25, 0x17, 0x00, ++ 0xF8, 0xB5, 0x0C, 0x4D, 0x0C, 0x48, 0x1B, 0xF0, 0x3F, 0xFE, 0x2B, 0x68, ++ 0x5B, 0x88, 0x83, 0xB1, 0x0A, 0x4F, 0x09, 0x4E, 0x00, 0x24, 0x0C, 0x21, ++ 0x38, 0x46, 0xFF, 0xF7, 0xCB, 0xFC, 0x01, 0x46, 0x30, 0x46, 0x1B, 0xF0, ++ 0x35, 0xFE, 0x2B, 0x68, 0x01, 0x34, 0x5A, 0x88, 0xA3, 0xB2, 0x9A, 0x42, ++ 0xF1, 0xD8, 0xF8, 0xBD, 0x78, 0x36, 0x17, 0x00, 0x08, 0x60, 0x17, 0x00, ++ 0xC8, 0x25, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x41, 0xDF, 0xF8, 0x4C, 0x80, ++ 0x0F, 0x48, 0x1B, 0xF0, 0x1D, 0xFE, 0xD8, 0xF8, 0x00, 0x30, 0x1B, 0x89, ++ 0xB3, 0xB1, 0x0D, 0x4D, 0x0D, 0x4F, 0x0B, 0x4E, 0x00, 0x24, 0x4F, 0xF4, ++ 0xD7, 0x61, 0x38, 0x46, 0xFF, 0xF7, 0xA6, 0xFC, 0x01, 0x46, 0x30, 0x46, ++ 0x1B, 0xF0, 0x10, 0xFE, 0xD8, 0xF8, 0x00, 0x20, 0x2B, 0x68, 0x11, 0x89, ++ 0x01, 0x34, 0xA2, 0xB2, 0x01, 0x33, 0x91, 0x42, 0x2B, 0x60, 0xEC, 0xD8, ++ 0xBD, 0xE8, 0xF0, 0x81, 0x00, 0x60, 0x17, 0x00, 0x18, 0x26, 0x17, 0x00, ++ 0xE4, 0x25, 0x17, 0x00, 0x78, 0x36, 0x17, 0x00, 0xF8, 0xB5, 0x0C, 0x4D, ++ 0x0C, 0x48, 0x1B, 0xF0, 0xF3, 0xFD, 0x2B, 0x68, 0x9B, 0x88, 0x83, 0xB1, ++ 0x0A, 0x4F, 0x09, 0x4E, 0x00, 0x24, 0x7C, 0x21, 0x38, 0x46, 0xFF, 0xF7, ++ 0x7F, 0xFC, 0x01, 0x46, 0x30, 0x46, 0x1B, 0xF0, 0xE9, 0xFD, 0x2B, 0x68, ++ 0x01, 0x34, 0x9A, 0x88, 0xA3, 0xB2, 0x9A, 0x42, 0xF1, 0xD8, 0xF8, 0xBD, ++ 0x78, 0x36, 0x17, 0x00, 0x20, 0x60, 0x17, 0x00, 0xE4, 0x25, 0x17, 0x00, ++ 0x10, 0xB5, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, ++ 0x09, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x09, 0x4C, 0x09, 0x48, 0x23, 0x68, ++ 0x01, 0x33, 0x23, 0x60, 0x1B, 0xF0, 0x10, 0xFE, 0x23, 0x68, 0x33, 0xB1, ++ 0x03, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x23, 0x60, 0x0B, 0xB9, 0x02, 0xB1, ++ 0x62, 0xB6, 0x10, 0xBD, 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x08, 0x60, 0x17, 0x00, 0x10, 0xB5, 0x01, 0x46, 0xEF, 0xF3, 0x10, 0x83, ++ 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x0A, 0x4B, 0x01, 0x22, 0x1A, 0x60, ++ 0x09, 0x4C, 0x0A, 0x48, 0x23, 0x68, 0x01, 0x33, 0x23, 0x60, 0x1B, 0xF0, ++ 0xAB, 0xFD, 0x23, 0x68, 0x33, 0xB1, 0x04, 0x4A, 0x01, 0x3B, 0x12, 0x68, ++ 0x23, 0x60, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0x10, 0xBD, 0x00, 0xBF, ++ 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0x08, 0x60, 0x17, 0x00, ++ 0x10, 0xB5, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, ++ 0x0C, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x0C, 0x4C, 0x0C, 0x48, 0x23, 0x68, ++ 0x01, 0x33, 0x23, 0x60, 0x1B, 0xF0, 0xCE, 0xFD, 0x18, 0xB1, 0x0A, 0x4A, ++ 0x13, 0x68, 0x01, 0x3B, 0x13, 0x60, 0x23, 0x68, 0x33, 0xB1, 0x04, 0x4A, ++ 0x01, 0x3B, 0x12, 0x68, 0x23, 0x60, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, ++ 0x10, 0xBD, 0x00, 0xBF, 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x00, 0x60, 0x17, 0x00, 0x18, 0x26, 0x17, 0x00, 0x10, 0xB5, 0x01, 0x46, ++ 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x0C, 0x4B, ++ 0x01, 0x22, 0x1A, 0x60, 0x0B, 0x4C, 0x0C, 0x48, 0x23, 0x68, 0x01, 0x33, ++ 0x23, 0x60, 0x1B, 0xF0, 0x61, 0xFD, 0x0A, 0x49, 0x23, 0x68, 0x0A, 0x68, ++ 0x01, 0x32, 0x0A, 0x60, 0x33, 0xB1, 0x04, 0x4A, 0x01, 0x3B, 0x12, 0x68, ++ 0x23, 0x60, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0x10, 0xBD, 0x00, 0xBF, ++ 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0x00, 0x60, 0x17, 0x00, ++ 0x18, 0x26, 0x17, 0x00, 0x10, 0xB5, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, ++ 0x03, 0xD4, 0x72, 0xB6, 0x09, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x09, 0x4C, ++ 0x09, 0x48, 0x23, 0x68, 0x01, 0x33, 0x23, 0x60, 0x1B, 0xF0, 0x7E, 0xFD, ++ 0x23, 0x68, 0x33, 0xB1, 0x03, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x23, 0x60, ++ 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0x10, 0xBD, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x20, 0x60, 0x17, 0x00, 0x10, 0xB5, 0x01, 0x46, ++ 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x0A, 0x4B, ++ 0x01, 0x22, 0x1A, 0x60, 0x09, 0x4C, 0x0A, 0x48, 0x23, 0x68, 0x01, 0x33, ++ 0x23, 0x60, 0x1B, 0xF0, 0x19, 0xFD, 0x23, 0x68, 0x33, 0xB1, 0x04, 0x4A, ++ 0x01, 0x3B, 0x12, 0x68, 0x23, 0x60, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, ++ 0x10, 0xBD, 0x00, 0xBF, 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x20, 0x60, 0x17, 0x00, 0x2D, 0xE9, 0xF8, 0x4F, 0x41, 0x4B, 0xDF, 0xF8, ++ 0x20, 0xB1, 0x1B, 0x68, 0x40, 0x4D, 0x1F, 0x8E, 0xDF, 0xF8, 0x18, 0x91, ++ 0xDF, 0xF8, 0x18, 0x81, 0x8B, 0x89, 0x0C, 0x46, 0x06, 0x46, 0x9F, 0x42, ++ 0x6A, 0xD9, 0xD8, 0xF8, 0x00, 0x30, 0x04, 0x2B, 0x63, 0xD9, 0xD6, 0xE9, ++ 0x01, 0x03, 0x1B, 0x69, 0x98, 0x47, 0x82, 0x46, 0x00, 0x28, 0x62, 0xD0, ++ 0xFF, 0xF7, 0x0E, 0xFF, 0x00, 0x28, 0x4A, 0xD0, 0x00, 0x22, 0x34, 0x4B, ++ 0x02, 0x60, 0x1B, 0x68, 0x42, 0x60, 0x53, 0x44, 0x82, 0x60, 0x03, 0x60, ++ 0xEF, 0xF3, 0x10, 0x83, 0xDA, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x2F, 0x4B, ++ 0x01, 0x22, 0x1A, 0x60, 0x2E, 0x4A, 0xDB, 0xF8, 0x00, 0x30, 0xD2, 0xF8, ++ 0x00, 0xC0, 0x43, 0xF0, 0x01, 0x03, 0x0C, 0xF1, 0x01, 0x01, 0x11, 0x60, ++ 0xCB, 0xF8, 0x00, 0x30, 0xDB, 0xF8, 0x00, 0x30, 0x9B, 0x07, 0xFB, 0xD4, ++ 0x2B, 0x68, 0x1B, 0xBB, 0xD9, 0xF8, 0x00, 0x30, 0xC9, 0xF8, 0x00, 0x00, ++ 0x2B, 0x68, 0xB4, 0xF8, 0x0C, 0xE0, 0x60, 0x60, 0x0E, 0xF1, 0x01, 0x0E, ++ 0x98, 0xB2, 0x01, 0x30, 0x1F, 0xFA, 0x8E, 0xF3, 0xA3, 0x81, 0x28, 0x60, ++ 0xDB, 0xF8, 0x00, 0x00, 0x20, 0xF0, 0x01, 0x00, 0xCB, 0xF8, 0x00, 0x00, ++ 0x00, 0x29, 0xB4, 0xD0, 0x18, 0x49, 0xC2, 0xF8, 0x00, 0xC0, 0x0A, 0x68, ++ 0xBC, 0xF1, 0x00, 0x0F, 0xAD, 0xD1, 0x00, 0x2A, 0xAB, 0xD0, 0x62, 0xB6, ++ 0xA3, 0x89, 0xA8, 0xE7, 0x63, 0x68, 0x00, 0x2B, 0xDC, 0xD0, 0x58, 0x60, ++ 0xDA, 0xE7, 0x12, 0x48, 0xFE, 0xF7, 0xAA, 0xFC, 0xD6, 0xE9, 0x01, 0x03, ++ 0x51, 0x46, 0x5B, 0x69, 0x98, 0x47, 0x09, 0x4B, 0xA2, 0x89, 0x1B, 0x68, ++ 0x5B, 0x8E, 0x9A, 0x42, 0x02, 0xD2, 0x04, 0x20, 0x1B, 0xF0, 0xEA, 0xFB, ++ 0x01, 0x20, 0xBD, 0xE8, 0xF8, 0x8F, 0xD8, 0xF8, 0x00, 0x10, 0x08, 0x48, ++ 0xFE, 0xF7, 0x94, 0xFC, 0xED, 0xE7, 0x00, 0xBF, 0xC8, 0x35, 0x17, 0x00, ++ 0x64, 0x00, 0x24, 0x40, 0x34, 0x1A, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x24, 0x82, 0x15, 0x00, 0x0C, 0x82, 0x15, 0x00, ++ 0x60, 0x00, 0x24, 0x40, 0x68, 0x00, 0x24, 0x40, 0x18, 0x26, 0x17, 0x00, ++ 0x08, 0xB5, 0x03, 0x4B, 0xD3, 0xF8, 0xF8, 0x32, 0x98, 0x47, 0x01, 0x20, ++ 0x08, 0xBD, 0x00, 0xBF, 0x88, 0x1A, 0x17, 0x00, 0x10, 0xB5, 0x0A, 0x4A, ++ 0x0A, 0x49, 0x0B, 0x4C, 0x00, 0x23, 0xC2, 0xE9, 0x02, 0x03, 0xC2, 0xE9, ++ 0x04, 0x33, 0xC2, 0xE9, 0x00, 0x33, 0xC1, 0xE9, 0x00, 0x33, 0x8B, 0x81, ++ 0x8B, 0x60, 0x8B, 0x73, 0x10, 0x46, 0xD4, 0xF8, 0x10, 0x31, 0x98, 0x47, ++ 0x01, 0x20, 0x10, 0xBD, 0x28, 0x60, 0x17, 0x00, 0x10, 0x60, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, 0x89, 0xB0, 0xB9, 0x4B, ++ 0xD3, 0xF8, 0x14, 0x35, 0x00, 0x2B, 0x00, 0xF0, 0x30, 0x81, 0xEF, 0xF3, ++ 0x10, 0x83, 0xD8, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0xB4, 0x4A, 0x01, 0x23, ++ 0x13, 0x60, 0xDF, 0xF8, 0x04, 0x93, 0xB1, 0x4B, 0xD9, 0xF8, 0x00, 0x20, ++ 0xD3, 0xF8, 0x14, 0x35, 0x51, 0x1C, 0xC9, 0xF8, 0x00, 0x10, 0x31, 0xB1, ++ 0xAD, 0x49, 0xC9, 0xF8, 0x00, 0x20, 0x09, 0x68, 0x0A, 0xB9, 0x01, 0xB1, ++ 0x62, 0xB6, 0x93, 0xF8, 0x0C, 0xB0, 0x5A, 0x7B, 0x5C, 0x68, 0x05, 0x92, ++ 0xBB, 0xF1, 0x00, 0x0F, 0x00, 0xF0, 0x38, 0x81, 0x00, 0x2C, 0x00, 0xF0, ++ 0x35, 0x81, 0x9B, 0x68, 0x00, 0x2B, 0x00, 0xF0, 0x31, 0x81, 0xA3, 0x4B, ++ 0x07, 0x93, 0x9B, 0x89, 0x1F, 0xFA, 0x8B, 0xF2, 0x5B, 0x45, 0x06, 0x92, ++ 0xC0, 0xF0, 0x5C, 0x81, 0xDF, 0xF8, 0xB0, 0xA2, 0x00, 0x26, 0xAA, 0xE0, ++ 0xD4, 0xE9, 0x00, 0x53, 0x03, 0x93, 0x6B, 0x1E, 0xB3, 0xF5, 0xE8, 0x1F, ++ 0x27, 0xD3, 0xEF, 0xF3, 0x10, 0x83, 0xDA, 0x07, 0x03, 0xD4, 0x72, 0xB6, ++ 0x95, 0x4A, 0x01, 0x23, 0x13, 0x60, 0x03, 0x9B, 0xD9, 0xF8, 0x00, 0x70, ++ 0x01, 0x93, 0x23, 0x68, 0x93, 0x48, 0x00, 0x93, 0x5A, 0x46, 0x23, 0x46, ++ 0x31, 0x46, 0x01, 0x37, 0xC9, 0xF8, 0x00, 0x70, 0x1C, 0xF0, 0xC4, 0xFD, ++ 0x4F, 0xF4, 0x80, 0x71, 0xA4, 0xF1, 0x80, 0x00, 0x1D, 0xF0, 0x9C, 0xF9, ++ 0xD9, 0xF8, 0x00, 0x30, 0x3B, 0xB1, 0x88, 0x4A, 0x01, 0x3B, 0x12, 0x68, ++ 0xC9, 0xF8, 0x00, 0x30, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0x20, 0x46, ++ 0xFF, 0xF7, 0x1A, 0xFE, 0x6B, 0x7E, 0x2F, 0x7E, 0x09, 0x2B, 0x09, 0xD8, ++ 0x83, 0x4A, 0x4F, 0xF4, 0x1E, 0x71, 0x01, 0xFB, 0x03, 0x23, 0x93, 0xF8, ++ 0x25, 0x30, 0x00, 0x2B, 0x00, 0xF0, 0xDD, 0x80, 0x6B, 0x8B, 0x13, 0xF0, ++ 0x08, 0x0F, 0x7E, 0x4B, 0x40, 0xF0, 0xBC, 0x80, 0x1A, 0x46, 0x04, 0x93, ++ 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x07, 0x23, 0x93, 0xF8, 0x64, 0x30, ++ 0x00, 0x2B, 0x00, 0xF0, 0xCC, 0x80, 0x95, 0xF8, 0x16, 0x80, 0xB8, 0xF1, ++ 0x05, 0x0F, 0x00, 0xF2, 0x09, 0x81, 0x75, 0x4C, 0x75, 0x48, 0x1B, 0xF0, ++ 0xF1, 0xFB, 0x23, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x04, 0x46, ++ 0xC0, 0xF2, 0xA5, 0x80, 0xE1, 0x8B, 0x71, 0x4B, 0xE2, 0x6C, 0x13, 0xF8, ++ 0x08, 0xC0, 0x21, 0xF0, 0x01, 0x01, 0x00, 0x23, 0xE1, 0x83, 0x63, 0x64, ++ 0x13, 0x61, 0xE3, 0x62, 0x6B, 0x4B, 0x29, 0x46, 0x0C, 0xF1, 0x01, 0x0C, ++ 0x1C, 0x22, 0x20, 0x1D, 0x03, 0xF8, 0x08, 0xC0, 0x2F, 0xF0, 0x8A, 0xFA, ++ 0xE1, 0x8B, 0xDA, 0xF8, 0x00, 0x00, 0x00, 0x23, 0x21, 0xF4, 0x00, 0x42, ++ 0x84, 0xF8, 0x42, 0x30, 0x22, 0xF0, 0x02, 0x02, 0x2D, 0x1A, 0x63, 0x62, ++ 0x23, 0x65, 0x0B, 0x07, 0xE2, 0x83, 0xA5, 0x64, 0x00, 0xF1, 0x87, 0x80, ++ 0x63, 0x7F, 0x09, 0x2B, 0x0E, 0xD8, 0xE2, 0x7E, 0x08, 0x2A, 0x0B, 0xD8, ++ 0x03, 0xEB, 0xC3, 0x03, 0x13, 0x44, 0x5A, 0x49, 0xA0, 0x88, 0x03, 0xF6, ++ 0x0E, 0x03, 0x51, 0xF8, 0x23, 0x20, 0x02, 0x44, 0x41, 0xF8, 0x23, 0x20, ++ 0xA4, 0x20, 0x04, 0x9B, 0x00, 0xFB, 0x07, 0x80, 0x99, 0x30, 0x21, 0x46, ++ 0x03, 0xEB, 0xC0, 0x00, 0x03, 0x9C, 0x1B, 0xF0, 0x61, 0xFB, 0x01, 0x36, ++ 0xF3, 0xB2, 0x9B, 0x45, 0x16, 0xD9, 0x05, 0x9B, 0x00, 0x2B, 0x3F, 0xF4, ++ 0x51, 0xAF, 0x4D, 0x49, 0x4F, 0xF4, 0x80, 0x60, 0x1C, 0xF0, 0x7E, 0xFD, ++ 0x20, 0x46, 0xD4, 0xE9, 0x00, 0x54, 0xFF, 0xF7, 0x93, 0xFD, 0xDA, 0xF8, ++ 0x00, 0x00, 0x01, 0x36, 0x28, 0x1A, 0xFF, 0xF7, 0x4B, 0xFC, 0xF3, 0xB2, ++ 0x9B, 0x45, 0xE8, 0xD8, 0x07, 0x9A, 0x06, 0x99, 0x93, 0x89, 0x5B, 0x1A, ++ 0x93, 0x81, 0xEF, 0xF3, 0x10, 0x83, 0xD9, 0x07, 0x03, 0xD4, 0x72, 0xB6, ++ 0x35, 0x4A, 0x01, 0x23, 0x13, 0x60, 0xD9, 0xF8, 0x00, 0x30, 0x3D, 0x48, ++ 0x01, 0x33, 0xC9, 0xF8, 0x00, 0x30, 0x1B, 0xF0, 0x75, 0xFB, 0x2F, 0x49, ++ 0x91, 0xF8, 0x11, 0x35, 0xD1, 0xF8, 0x14, 0x25, 0x01, 0x3B, 0x81, 0xF8, ++ 0x11, 0x35, 0x00, 0x2A, 0x00, 0xF0, 0x94, 0x80, 0xD9, 0xF8, 0x00, 0x30, ++ 0x00, 0x2B, 0x3F, 0xF4, 0xDC, 0xAE, 0x28, 0x4A, 0x01, 0x3B, 0x12, 0x68, ++ 0xC9, 0xF8, 0x00, 0x30, 0x00, 0x2B, 0x7F, 0xF4, 0xD4, 0xAE, 0x00, 0x2A, ++ 0x3F, 0xF4, 0xD1, 0xAE, 0x62, 0xB6, 0x21, 0x4B, 0xD3, 0xF8, 0x14, 0x35, ++ 0x00, 0x2B, 0x7F, 0xF4, 0xD0, 0xAE, 0x40, 0x20, 0x1B, 0xF0, 0x6A, 0xFA, ++ 0x04, 0x20, 0x09, 0xB0, 0xBD, 0xE8, 0xF0, 0x4F, 0x1B, 0xF0, 0x64, 0xBA, ++ 0x1F, 0x4C, 0x04, 0x93, 0x4F, 0xF0, 0x05, 0x08, 0x50, 0xE7, 0x00, 0x28, ++ 0x7F, 0xF4, 0x58, 0xAF, 0x21, 0x49, 0x22, 0x48, 0x4F, 0xF4, 0xE5, 0x72, ++ 0x1C, 0xF0, 0x4C, 0xFF, 0x50, 0xE7, 0x04, 0x9B, 0x4F, 0xF4, 0xA4, 0x60, ++ 0x00, 0xFB, 0x07, 0x30, 0x21, 0x46, 0x00, 0xF5, 0xA3, 0x60, 0x03, 0x9C, ++ 0x1B, 0xF0, 0xEC, 0xFA, 0x89, 0xE7, 0xDA, 0xF8, 0x00, 0x00, 0x03, 0x9C, ++ 0x28, 0x1A, 0xFF, 0xF7, 0xE7, 0xFB, 0x82, 0xE7, 0x0A, 0x4B, 0x16, 0x48, ++ 0x07, 0x93, 0x1D, 0x46, 0xFE, 0xF7, 0xEE, 0xFA, 0xAB, 0x89, 0x1F, 0xFA, ++ 0x8B, 0xF2, 0x5B, 0x45, 0x06, 0x92, 0x27, 0xD3, 0xBB, 0xF1, 0x00, 0x0F, ++ 0x7F, 0xF4, 0xC8, 0xAE, 0x8C, 0xE7, 0x00, 0xBF, 0x58, 0x58, 0x17, 0x00, ++ 0x38, 0x61, 0x17, 0x00, 0x10, 0x60, 0x17, 0x00, 0x50, 0x82, 0x15, 0x00, ++ 0x68, 0x65, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x20, 0x58, 0x17, 0x00, 0x74, 0x28, 0x17, 0x00, 0x7C, 0x36, 0x17, 0x00, ++ 0xB4, 0x82, 0x15, 0x00, 0x6C, 0x5D, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x9C, 0x82, 0x15, 0x00, 0x34, 0x82, 0x15, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x34, 0x1A, 0x17, 0x00, 0x10, 0x48, 0xFE, 0xF7, 0xBD, 0xFA, 0xBB, 0xF1, ++ 0x00, 0x0F, 0x7F, 0xF4, 0x9D, 0xAE, 0x61, 0xE7, 0x0D, 0x48, 0x0E, 0x4C, ++ 0x1C, 0xF0, 0x7E, 0xFC, 0x80, 0x21, 0xA5, 0xF1, 0x40, 0x00, 0x1D, 0xF0, ++ 0x57, 0xF8, 0x23, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xBF, 0xF6, ++ 0xE9, 0xAE, 0x08, 0x49, 0x08, 0x48, 0x4F, 0xF4, 0xE3, 0x72, 0x1C, 0xF0, ++ 0xE7, 0xFE, 0xE1, 0xE6, 0x20, 0x20, 0x1B, 0xF0, 0x11, 0xFA, 0x67, 0xE7, ++ 0x44, 0x82, 0x15, 0x00, 0x74, 0x82, 0x15, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x88, 0x82, 0x15, 0x00, 0x2D, 0xE9, 0xF8, 0x4F, ++ 0xDF, 0xF8, 0x24, 0x91, 0xDF, 0xF8, 0x24, 0x81, 0x42, 0x4F, 0x43, 0x4B, ++ 0xD3, 0xF8, 0xA0, 0x27, 0x00, 0x2A, 0x5E, 0xD0, 0x15, 0x7B, 0xD2, 0xF8, ++ 0x04, 0xA0, 0x56, 0x7B, 0x65, 0xB3, 0x4F, 0xF0, 0x00, 0x0B, 0x11, 0xE0, ++ 0xDA, 0xE9, 0x00, 0x4A, 0xFF, 0xF7, 0xB0, 0xFC, 0x20, 0x46, 0xFD, 0xF7, ++ 0x03, 0xFB, 0xD8, 0xF8, 0x00, 0x00, 0x0B, 0xF1, 0x01, 0x0B, 0x20, 0x1A, ++ 0xFF, 0xF7, 0x64, 0xFB, 0x5F, 0xFA, 0x8B, 0xF1, 0xA9, 0x42, 0x17, 0xD2, ++ 0x50, 0x46, 0x39, 0x46, 0x00, 0x2E, 0xE9, 0xD0, 0x4F, 0xF4, 0x80, 0x60, ++ 0x1C, 0xF0, 0x80, 0xFC, 0x50, 0x46, 0xDA, 0xE9, 0x00, 0x4A, 0xFF, 0xF7, ++ 0x95, 0xFC, 0xD8, 0xF8, 0x00, 0x00, 0x0B, 0xF1, 0x01, 0x0B, 0x20, 0x1A, ++ 0xFF, 0xF7, 0x4C, 0xFB, 0x5F, 0xFA, 0x8B, 0xF1, 0xA9, 0x42, 0xE7, 0xD3, ++ 0x28, 0x4A, 0x93, 0x89, 0x5D, 0x1B, 0x95, 0x81, 0xEF, 0xF3, 0x10, 0x83, ++ 0xDA, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x25, 0x4A, 0x01, 0x23, 0x13, 0x60, ++ 0xD9, 0xF8, 0x00, 0x30, 0x23, 0x48, 0x01, 0x33, 0xC9, 0xF8, 0x00, 0x30, ++ 0x1B, 0xF0, 0x76, 0xFA, 0x1D, 0x49, 0xD9, 0xF8, 0x00, 0x20, 0x91, 0xF8, ++ 0x9D, 0x37, 0x01, 0x3B, 0x81, 0xF8, 0x9D, 0x37, 0x00, 0x2A, 0xAA, 0xD0, ++ 0x1A, 0x4B, 0x01, 0x3A, 0x1B, 0x68, 0xC9, 0xF8, 0x00, 0x20, 0x00, 0x2A, ++ 0xA3, 0xD1, 0x00, 0x2B, 0xA1, 0xD0, 0x62, 0xB6, 0x13, 0x4B, 0xD3, 0xF8, ++ 0xA0, 0x27, 0x00, 0x2A, 0xA0, 0xD1, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, ++ 0x03, 0xD4, 0x72, 0xB6, 0x10, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0xD9, 0xF8, ++ 0x00, 0x30, 0x4F, 0xF4, 0x00, 0x00, 0x01, 0x33, 0xC9, 0xF8, 0x00, 0x30, ++ 0x1B, 0xF0, 0x8A, 0xF9, 0x04, 0x20, 0x1B, 0xF0, 0x63, 0xF9, 0xD9, 0xF8, ++ 0x00, 0x30, 0x3B, 0xB1, 0x07, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0xC9, 0xF8, ++ 0x00, 0x30, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0xBD, 0xE8, 0xF8, 0x8F, ++ 0xB0, 0x82, 0x15, 0x00, 0x58, 0x58, 0x17, 0x00, 0x10, 0x60, 0x17, 0x00, ++ 0x38, 0x61, 0x17, 0x00, 0xF8, 0x5F, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x34, 0x1A, 0x17, 0x00, 0x2D, 0xE9, 0xF8, 0x4F, 0xDF, 0xF8, 0xD8, 0x80, ++ 0xDF, 0xF8, 0xD8, 0x90, 0xDF, 0xF8, 0xD8, 0xA0, 0xD9, 0xF8, 0x08, 0x3C, ++ 0x00, 0x2B, 0x41, 0xD0, 0x1F, 0x89, 0x5D, 0x68, 0xBF, 0xB1, 0x00, 0x24, ++ 0x26, 0x46, 0x23, 0x46, 0xB3, 0x42, 0xAB, 0x46, 0x04, 0xF1, 0x01, 0x04, ++ 0x6D, 0x68, 0x08, 0xD1, 0xDA, 0xF8, 0x8C, 0x32, 0x98, 0x47, 0x9B, 0xF8, ++ 0x0B, 0x30, 0x03, 0xF0, 0x7F, 0x03, 0x1E, 0x44, 0xB6, 0xB2, 0x58, 0x46, ++ 0xFF, 0xF7, 0x0A, 0xFC, 0xA3, 0xB2, 0xBB, 0x42, 0xEA, 0xD3, 0xEF, 0xF3, ++ 0x10, 0x83, 0xDA, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x1F, 0x4A, 0x01, 0x23, ++ 0x13, 0x60, 0xD8, 0xF8, 0x00, 0x30, 0x1E, 0x48, 0x01, 0x33, 0xC8, 0xF8, ++ 0x00, 0x30, 0x1B, 0xF0, 0xF7, 0xF9, 0x99, 0xF8, 0x02, 0x3C, 0xD8, 0xF8, ++ 0x00, 0x20, 0x01, 0x3B, 0x89, 0xF8, 0x02, 0x3C, 0x00, 0x2A, 0xC7, 0xD0, ++ 0x15, 0x4B, 0x01, 0x3A, 0x1B, 0x68, 0xC8, 0xF8, 0x00, 0x20, 0x00, 0x2A, ++ 0xC0, 0xD1, 0x00, 0x2B, 0xBE, 0xD0, 0x62, 0xB6, 0xD9, 0xF8, 0x08, 0x3C, ++ 0x00, 0x2B, 0xBD, 0xD1, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, ++ 0x72, 0xB6, 0x0C, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0xD8, 0xF8, 0x00, 0x30, ++ 0x10, 0x20, 0x01, 0x33, 0xC8, 0xF8, 0x00, 0x30, 0x1B, 0xF0, 0x0E, 0xF9, ++ 0xD8, 0xF8, 0x00, 0x30, 0x3B, 0xB1, 0x05, 0x4A, 0x01, 0x3B, 0x12, 0x68, ++ 0xC8, 0xF8, 0x00, 0x30, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0xBD, 0xE8, ++ 0xF8, 0x8F, 0x00, 0xBF, 0x38, 0x61, 0x17, 0x00, 0x84, 0x42, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x7C, 0x36, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF8, 0x4F, 0xDF, 0xF8, 0xB4, 0x80, 0x2A, 0x4E, 0xC1, 0x46, ++ 0xA8, 0xF1, 0x06, 0x07, 0xD8, 0xF8, 0x00, 0x30, 0x00, 0x2B, 0x33, 0xD0, ++ 0x1D, 0x89, 0x5C, 0x68, 0x7D, 0xB1, 0x4F, 0xF0, 0x00, 0x0B, 0x20, 0x68, ++ 0xA2, 0x46, 0x0B, 0xF1, 0x01, 0x0B, 0x64, 0x68, 0xFF, 0xF7, 0x5E, 0xFA, ++ 0x50, 0x46, 0xFF, 0xF7, 0x9D, 0xFB, 0x1F, 0xFA, 0x8B, 0xF2, 0xAA, 0x42, ++ 0xF1, 0xD3, 0xEF, 0xF3, 0x10, 0x83, 0xDA, 0x07, 0x03, 0xD4, 0x72, 0xB6, ++ 0x1B, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x33, 0x68, 0x48, 0x46, 0x01, 0x33, ++ 0x33, 0x60, 0x1B, 0xF0, 0x8B, 0xF9, 0x3B, 0x78, 0x32, 0x68, 0x01, 0x3B, ++ 0x3B, 0x70, 0x00, 0x2A, 0xD4, 0xD0, 0x14, 0x4B, 0x01, 0x3A, 0x1B, 0x68, ++ 0x32, 0x60, 0x00, 0x2A, 0xCE, 0xD1, 0x00, 0x2B, 0xCC, 0xD0, 0x62, 0xB6, ++ 0xD8, 0xF8, 0x00, 0x30, 0x00, 0x2B, 0xCB, 0xD1, 0xEF, 0xF3, 0x10, 0x83, ++ 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x0B, 0x4B, 0x01, 0x22, 0x1A, 0x60, ++ 0x33, 0x68, 0x08, 0x20, 0x01, 0x33, 0x33, 0x60, 0x1B, 0xF0, 0xA8, 0xF8, ++ 0x33, 0x68, 0x33, 0xB1, 0x05, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x33, 0x60, ++ 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0xBD, 0xE8, 0xF8, 0x8F, 0x00, 0xBF, ++ 0x6C, 0x28, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, 0x94, 0x4E, 0x17, 0x00, ++ 0x10, 0xB5, 0x04, 0x20, 0x1B, 0xF0, 0x92, 0xF8, 0x03, 0x4B, 0x04, 0x49, ++ 0xD3, 0xF8, 0x10, 0x31, 0x03, 0x48, 0xBD, 0xE8, 0x10, 0x40, 0x18, 0x47, ++ 0x88, 0x1A, 0x17, 0x00, 0x10, 0x60, 0x17, 0x00, 0x28, 0x60, 0x17, 0x00, ++ 0xF8, 0xB5, 0xA8, 0x4B, 0xA8, 0x4A, 0x1B, 0x68, 0x14, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0xC0, 0xF2, 0xB7, 0x81, 0x65, 0x05, 0x18, 0xD5, ++ 0xA4, 0x4A, 0x13, 0x68, 0x98, 0x00, 0xFC, 0xD4, 0xA3, 0x4B, 0xA2, 0x49, ++ 0x13, 0x60, 0x0B, 0x68, 0x13, 0xF0, 0x00, 0x53, 0xFB, 0xD1, 0xA1, 0x49, ++ 0xA1, 0x48, 0x0A, 0x68, 0x42, 0xF0, 0x10, 0x02, 0x0A, 0x60, 0x02, 0x78, ++ 0x02, 0xB1, 0x03, 0x70, 0x9E, 0x4B, 0x1A, 0x78, 0x00, 0x2A, 0x40, 0xF0, ++ 0xE0, 0x81, 0x21, 0x05, 0x09, 0xD5, 0x97, 0x4A, 0x13, 0x68, 0x9B, 0x00, ++ 0xFC, 0xD4, 0x9A, 0x4B, 0x94, 0x49, 0x13, 0x60, 0x0B, 0x68, 0x9F, 0x00, ++ 0xFC, 0xD4, 0xE2, 0x04, 0x05, 0xD5, 0x94, 0x49, 0x96, 0x4B, 0x97, 0x4A, ++ 0x01, 0x20, 0x08, 0x70, 0x1A, 0x60, 0x66, 0x06, 0x04, 0xD5, 0x95, 0x4B, ++ 0x95, 0x48, 0x19, 0x68, 0x1C, 0xF0, 0x9C, 0xFA, 0x14, 0xF4, 0x9B, 0x7F, ++ 0x40, 0xF0, 0x89, 0x81, 0xA5, 0x05, 0x00, 0xF1, 0x8D, 0x81, 0x20, 0x06, ++ 0x00, 0xF1, 0x94, 0x81, 0x21, 0x04, 0x00, 0xF1, 0x9F, 0x81, 0xE2, 0x02, ++ 0x00, 0xF1, 0xA6, 0x81, 0xA3, 0x02, 0x03, 0xD5, 0x8B, 0x4B, 0x4F, 0xF4, ++ 0x00, 0x12, 0x1A, 0x60, 0xE7, 0x03, 0x41, 0xD5, 0x89, 0x4B, 0x93, 0xF8, ++ 0x11, 0x15, 0x93, 0xF8, 0x12, 0x25, 0x91, 0x42, 0x80, 0xF0, 0xB1, 0x81, ++ 0x93, 0xF8, 0x10, 0x05, 0x85, 0x4A, 0x86, 0x4D, 0x86, 0x4E, 0x01, 0x30, ++ 0xA2, 0xFB, 0x00, 0x72, 0x92, 0x09, 0x02, 0xEB, 0xC2, 0x02, 0x02, 0xEB, ++ 0xC2, 0x02, 0x82, 0x1A, 0x01, 0x31, 0x83, 0xF8, 0x11, 0x15, 0x83, 0xF8, ++ 0x10, 0x25, 0x03, 0xEB, 0x02, 0x11, 0x30, 0x68, 0x2E, 0x68, 0x4E, 0x60, ++ 0x6E, 0x68, 0x8E, 0x60, 0x28, 0x3D, 0xC0, 0xF3, 0x00, 0x26, 0x08, 0x73, ++ 0x4E, 0x73, 0x28, 0x68, 0x40, 0xF0, 0x10, 0x00, 0x11, 0x01, 0x28, 0x60, ++ 0x28, 0x68, 0x86, 0x06, 0xFC, 0xD4, 0x19, 0x44, 0x75, 0x4B, 0x8A, 0x68, ++ 0x75, 0x48, 0x52, 0x68, 0x1A, 0x60, 0x2B, 0x68, 0x23, 0xF0, 0x10, 0x03, ++ 0x2B, 0x60, 0x1B, 0xF0, 0x6F, 0xF8, 0x20, 0x20, 0x1A, 0xF0, 0xCA, 0xFF, ++ 0x69, 0x4B, 0x4F, 0xF4, 0x80, 0x32, 0x1A, 0x60, 0x65, 0x03, 0x4E, 0xD5, ++ 0x67, 0x4B, 0x93, 0xF8, 0x9D, 0x17, 0x93, 0xF8, 0x9E, 0x27, 0x91, 0x42, ++ 0x80, 0xF0, 0x7B, 0x81, 0x93, 0xF8, 0x9C, 0x07, 0x68, 0x4A, 0x69, 0x4F, ++ 0x69, 0x4D, 0xDF, 0xF8, 0xE0, 0xC1, 0x01, 0x30, 0xA2, 0xFB, 0x00, 0x62, ++ 0x56, 0x09, 0x06, 0xEB, 0x86, 0x06, 0xA0, 0xEB, 0xC6, 0x06, 0x4A, 0x1C, ++ 0x83, 0xF8, 0x9D, 0x27, 0x83, 0xF8, 0x9C, 0x67, 0x03, 0xEB, 0x06, 0x11, ++ 0x3A, 0x68, 0x28, 0x68, 0xC1, 0xF8, 0x20, 0x05, 0x06, 0xF1, 0x52, 0x07, ++ 0x03, 0xEB, 0x07, 0x15, 0xDC, 0xF8, 0x00, 0x10, 0x5C, 0x48, 0x69, 0x60, ++ 0xC2, 0xF3, 0x00, 0x21, 0x69, 0x72, 0x2A, 0x72, 0x05, 0x68, 0x45, 0xF0, ++ 0x04, 0x05, 0x05, 0x60, 0x31, 0x01, 0x05, 0x46, 0x2A, 0x68, 0x10, 0x07, ++ 0xFC, 0xD4, 0x03, 0xEB, 0x07, 0x12, 0x01, 0xF2, 0x1C, 0x51, 0x50, 0x68, ++ 0x53, 0x4A, 0x40, 0x68, 0x10, 0x60, 0x2A, 0x68, 0x52, 0x48, 0x22, 0xF0, ++ 0x04, 0x02, 0x19, 0x44, 0x2A, 0x60, 0x1B, 0xF0, 0x1F, 0xF8, 0x4F, 0xF4, ++ 0x00, 0x00, 0x1A, 0xF0, 0x79, 0xFF, 0x41, 0x4B, 0x4F, 0xF4, 0x80, 0x22, ++ 0x1A, 0x60, 0xA2, 0x03, 0x1B, 0xD5, 0x4B, 0x4B, 0x1A, 0x78, 0x00, 0x2A, ++ 0x40, 0xF0, 0x35, 0x81, 0x49, 0x48, 0x90, 0xF8, 0x02, 0x1C, 0x90, 0xF8, ++ 0x01, 0x2C, 0x91, 0x42, 0xC0, 0xF0, 0xA2, 0x80, 0x46, 0x48, 0x1C, 0xF0, ++ 0xDF, 0xF9, 0x36, 0x4B, 0x4F, 0xF4, 0x00, 0x32, 0x1A, 0x60, 0x44, 0x4B, ++ 0x1B, 0x68, 0x23, 0xB9, 0x43, 0x4A, 0x13, 0x78, 0x23, 0xF0, 0x01, 0x03, ++ 0x13, 0x70, 0x23, 0x03, 0x1D, 0xD5, 0x3C, 0x4B, 0x1A, 0x78, 0x00, 0x2A, ++ 0x40, 0xF0, 0x09, 0x81, 0x3A, 0x48, 0x41, 0xF6, 0x12, 0x04, 0x41, 0xF6, ++ 0x11, 0x03, 0x02, 0x5D, 0xC3, 0x5C, 0x93, 0x42, 0x10, 0xD8, 0x11, 0x46, ++ 0x39, 0x48, 0x1C, 0xF0, 0xBF, 0xF9, 0x26, 0x4B, 0x4F, 0xF4, 0x00, 0x22, ++ 0x1A, 0x60, 0x37, 0x4B, 0x1B, 0x68, 0x23, 0xB9, 0x33, 0x4A, 0x13, 0x78, ++ 0x23, 0xF0, 0x02, 0x03, 0x13, 0x70, 0xF8, 0xBD, 0x41, 0xF6, 0x10, 0x05, ++ 0x32, 0x4B, 0x41, 0x5D, 0x01, 0x31, 0xA3, 0xFB, 0x01, 0x63, 0xDB, 0x09, ++ 0x03, 0xEB, 0x43, 0x03, 0xA1, 0xEB, 0x83, 0x13, 0x43, 0x55, 0x03, 0xF1, ++ 0xC1, 0x01, 0x2D, 0x4E, 0x00, 0xEB, 0x01, 0x11, 0x35, 0x68, 0x4D, 0x60, ++ 0x2B, 0x4D, 0x00, 0xEB, 0x03, 0x13, 0x01, 0x32, 0x2D, 0x68, 0xA3, 0xF8, ++ 0x18, 0x5C, 0x02, 0x55, 0x28, 0x48, 0x1A, 0xF0, 0xB9, 0xFF, 0x08, 0x20, ++ 0x1A, 0xF0, 0x14, 0xFF, 0x0E, 0x4B, 0x4F, 0xF4, 0x00, 0x22, 0x1A, 0x60, ++ 0xCF, 0xE7, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, 0x24, 0x00, 0x24, 0x40, ++ 0x40, 0x00, 0x24, 0x40, 0x01, 0x09, 0x00, 0x32, 0x44, 0x00, 0x24, 0x40, ++ 0x1C, 0x26, 0x17, 0x00, 0x3C, 0x36, 0x17, 0x00, 0x02, 0x09, 0x00, 0x32, ++ 0x2C, 0x00, 0x24, 0x40, 0x09, 0x70, 0x00, 0xCF, 0x08, 0x00, 0x24, 0x40, ++ 0xDC, 0x82, 0x15, 0x00, 0x28, 0x00, 0x24, 0x40, 0x58, 0x58, 0x17, 0x00, ++ 0xE7, 0x87, 0x45, 0xCA, 0x88, 0x00, 0x24, 0x40, 0x90, 0x00, 0x24, 0x40, ++ 0x74, 0x00, 0x24, 0x40, 0x6C, 0x5D, 0x17, 0x00, 0xCD, 0xCC, 0xCC, 0xCC, ++ 0x84, 0x00, 0x24, 0x40, 0x7C, 0x00, 0x24, 0x40, 0x60, 0x00, 0x24, 0x40, ++ 0x6C, 0x00, 0x24, 0x40, 0xF8, 0x5F, 0x17, 0x00, 0x1D, 0x26, 0x17, 0x00, ++ 0x7C, 0x36, 0x17, 0x00, 0x80, 0x83, 0x15, 0x00, 0xA0, 0x00, 0x24, 0x40, ++ 0x9C, 0x4E, 0x17, 0x00, 0x98, 0x83, 0x15, 0x00, 0x98, 0x00, 0x24, 0x40, ++ 0xAB, 0xAA, 0xAA, 0xAA, 0xA4, 0x00, 0x24, 0x40, 0xA8, 0x00, 0x24, 0x40, ++ 0x94, 0x4E, 0x17, 0x00, 0x80, 0x00, 0x24, 0x40, 0x90, 0xF8, 0x00, 0x2C, ++ 0x4B, 0x4B, 0x4C, 0x4D, 0x01, 0x32, 0xA3, 0xFB, 0x02, 0x63, 0xDB, 0x09, ++ 0x03, 0xEB, 0x43, 0x03, 0xA2, 0xEB, 0x83, 0x13, 0x00, 0xEB, 0x03, 0x12, ++ 0x2D, 0x68, 0x55, 0x60, 0x46, 0x4D, 0x80, 0xF8, 0x00, 0x3C, 0x2B, 0x68, ++ 0x13, 0x81, 0x01, 0x31, 0x80, 0xF8, 0x02, 0x1C, 0x11, 0x46, 0x00, 0xF6, ++ 0x08, 0x40, 0x1A, 0xF0, 0x49, 0xFF, 0x10, 0x20, 0x1A, 0xF0, 0xA4, 0xFE, ++ 0x3F, 0x4B, 0x4F, 0xF4, 0x00, 0x32, 0x1A, 0x60, 0x3F, 0xE7, 0x00, 0x2C, ++ 0x7F, 0xF4, 0x46, 0xAE, 0x3C, 0x49, 0x3D, 0x48, 0x26, 0x22, 0x1C, 0xF0, ++ 0x8D, 0xFB, 0x14, 0xF4, 0x9B, 0x7F, 0x3F, 0xF4, 0x77, 0xAE, 0x3A, 0x48, ++ 0x21, 0x46, 0x1C, 0xF0, 0x0B, 0xF9, 0xA5, 0x05, 0x7F, 0xF5, 0x73, 0xAE, ++ 0x37, 0x48, 0x1C, 0xF0, 0x05, 0xF9, 0x32, 0x4B, 0x4F, 0xF4, 0x00, 0x72, ++ 0x20, 0x06, 0x1A, 0x60, 0x7F, 0xF5, 0x6C, 0xAE, 0x33, 0x48, 0x1C, 0xF0, ++ 0xFB, 0xF8, 0x33, 0x4A, 0x2C, 0x49, 0x13, 0x68, 0x80, 0x20, 0x23, 0xF0, ++ 0x10, 0x03, 0x13, 0x60, 0x08, 0x60, 0x21, 0x04, 0x7F, 0xF5, 0x61, 0xAE, ++ 0x2E, 0x48, 0x1C, 0xF0, 0xED, 0xF8, 0x26, 0x4B, 0x4F, 0xF4, 0x00, 0x42, ++ 0x1A, 0x60, 0xE2, 0x02, 0x7F, 0xF5, 0x5A, 0xAE, 0x2A, 0x4A, 0x2B, 0x4B, ++ 0x15, 0x68, 0x2B, 0x48, 0x1A, 0x78, 0x29, 0x46, 0xFD, 0xF7, 0x14, 0xFF, ++ 0x29, 0x4A, 0x1E, 0x4B, 0x15, 0x60, 0x4F, 0xF4, 0x80, 0x12, 0x1A, 0x60, ++ 0x4A, 0xE6, 0x27, 0x4A, 0x01, 0x21, 0x59, 0x70, 0x13, 0x68, 0x26, 0x49, ++ 0x43, 0xF0, 0x01, 0x03, 0x13, 0x60, 0x02, 0x20, 0x1C, 0xF0, 0x1C, 0xF9, ++ 0x13, 0xE6, 0x23, 0x48, 0x1C, 0xF0, 0xC8, 0xF8, 0x13, 0x4B, 0x4F, 0xF4, ++ 0x80, 0x32, 0x1A, 0x60, 0x80, 0xE6, 0x00, 0x22, 0x02, 0x20, 0x1A, 0x70, ++ 0xFD, 0xF7, 0x86, 0xFF, 0xF0, 0xE6, 0x1D, 0x48, 0x1C, 0xF0, 0xBA, 0xF8, ++ 0x0C, 0x4B, 0x4F, 0xF4, 0x80, 0x22, 0x1A, 0x60, 0xC3, 0xE6, 0x00, 0x22, ++ 0x02, 0x20, 0x1A, 0x70, 0xFD, 0xF7, 0x78, 0xFF, 0x17, 0x48, 0x90, 0xF8, ++ 0x02, 0x1C, 0x90, 0xF8, 0x01, 0x2C, 0x91, 0x42, 0xBF, 0xF4, 0xC6, 0xAE, ++ 0x66, 0xE7, 0x00, 0xBF, 0xAB, 0xAA, 0xAA, 0xAA, 0xAC, 0x00, 0x24, 0x40, ++ 0xB0, 0x00, 0x24, 0x40, 0x28, 0x00, 0x24, 0x40, 0x70, 0x79, 0x15, 0x00, ++ 0xC0, 0x82, 0x15, 0x00, 0xEC, 0x82, 0x15, 0x00, 0x08, 0x83, 0x15, 0x00, ++ 0x1C, 0x83, 0x15, 0x00, 0x4C, 0x00, 0x24, 0x40, 0x30, 0x83, 0x15, 0x00, ++ 0x30, 0x00, 0x24, 0x40, 0x45, 0x00, 0x24, 0x40, 0x48, 0x83, 0x15, 0x00, ++ 0x34, 0x00, 0x24, 0x40, 0x10, 0x00, 0x58, 0x40, 0xD0, 0x82, 0x15, 0x00, ++ 0xCC, 0x7C, 0x15, 0x00, 0x64, 0x83, 0x15, 0x00, 0x7C, 0x36, 0x17, 0x00, ++ 0xF8, 0xB5, 0x47, 0x4B, 0x1A, 0x68, 0x42, 0xF0, 0x10, 0x02, 0x1A, 0x60, ++ 0x1B, 0x68, 0x5A, 0x07, 0x7F, 0xD4, 0x44, 0x49, 0x0B, 0x68, 0x9B, 0x00, ++ 0xFC, 0xD4, 0x43, 0x4B, 0x41, 0x4A, 0x0B, 0x60, 0x13, 0x68, 0x9F, 0x00, ++ 0xFC, 0xD4, 0x13, 0x68, 0x9E, 0x07, 0x03, 0xD4, 0x3C, 0x4A, 0x13, 0x68, ++ 0xDD, 0x07, 0xFC, 0xD5, 0x3A, 0x4A, 0x3D, 0x4D, 0x13, 0x68, 0x3D, 0x48, ++ 0x3D, 0x49, 0x3E, 0x4C, 0x3E, 0x4F, 0x3F, 0x4E, 0x43, 0xF0, 0x02, 0x03, ++ 0x13, 0x60, 0x2B, 0x68, 0x03, 0x40, 0x43, 0xF0, 0x10, 0x03, 0x2B, 0x60, ++ 0x2B, 0x68, 0x9B, 0xB2, 0x43, 0xF4, 0x80, 0x13, 0x2B, 0x60, 0x0B, 0x68, ++ 0x03, 0x40, 0x43, 0xF0, 0x10, 0x03, 0x0B, 0x60, 0x0B, 0x68, 0x9B, 0xB2, ++ 0x43, 0xF4, 0x80, 0x13, 0x0B, 0x60, 0x4F, 0xF6, 0xFF, 0x73, 0x23, 0x60, ++ 0x52, 0xF8, 0x34, 0x3C, 0x03, 0x40, 0x43, 0xF4, 0x88, 0x53, 0x43, 0xF0, ++ 0x11, 0x03, 0x42, 0xF8, 0x34, 0x3C, 0x03, 0x23, 0xAB, 0x64, 0x4F, 0xF4, ++ 0xFC, 0x53, 0x3B, 0x60, 0x4F, 0xF0, 0xFF, 0x33, 0x33, 0x60, 0x2A, 0x48, ++ 0x2A, 0x4B, 0x23, 0x62, 0x00, 0x24, 0x20, 0x23, 0x04, 0x60, 0x41, 0xF8, ++ 0xAC, 0x3C, 0x52, 0xF8, 0x34, 0x3C, 0x27, 0x4C, 0x27, 0x48, 0x23, 0xF4, ++ 0x7F, 0x03, 0x43, 0xF4, 0x80, 0x33, 0x42, 0xF8, 0x34, 0x3C, 0x41, 0xF8, ++ 0x84, 0x4C, 0x1C, 0xF0, 0x1B, 0xF8, 0x17, 0x4B, 0x17, 0x49, 0x1A, 0x68, ++ 0x94, 0x00, 0xFC, 0xD4, 0x19, 0x60, 0x1A, 0x68, 0x90, 0x00, 0xFC, 0xD4, ++ 0x1A, 0x68, 0x12, 0xF0, 0x06, 0x0F, 0xF4, 0xD0, 0x10, 0x4A, 0x13, 0x68, ++ 0x99, 0x00, 0xFC, 0xD4, 0x1A, 0x4B, 0x0E, 0x49, 0x13, 0x60, 0x0B, 0x68, ++ 0x9B, 0x00, 0xFC, 0xD4, 0x18, 0x48, 0x1C, 0xF0, 0x01, 0xF8, 0x18, 0x4B, ++ 0x18, 0x49, 0x9A, 0x68, 0xD1, 0xF8, 0xFC, 0x12, 0x91, 0x67, 0xA3, 0xF5, ++ 0x40, 0x63, 0x4F, 0xF4, 0x80, 0x42, 0x1A, 0x60, 0xF8, 0xBD, 0x14, 0x4B, ++ 0x0C, 0x4A, 0x1A, 0x60, 0xFE, 0xF7, 0x9A, 0xFB, 0xED, 0xE7, 0x00, 0xBF, ++ 0x44, 0x00, 0x24, 0x40, 0x40, 0x00, 0x24, 0x40, 0x00, 0x02, 0x00, 0x20, ++ 0x04, 0x00, 0x24, 0x40, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x24, 0x40, ++ 0x0C, 0x00, 0x24, 0x40, 0xB4, 0x00, 0x24, 0x40, 0x28, 0x00, 0x24, 0x40, ++ 0x38, 0x00, 0x24, 0x40, 0x09, 0x60, 0x00, 0xCF, 0x00, 0x00, 0x20, 0x4E, ++ 0xB8, 0x83, 0x15, 0x00, 0x06, 0x03, 0x00, 0x30, 0xCC, 0x83, 0x15, 0x00, ++ 0x00, 0xED, 0x00, 0xE0, 0x88, 0x1A, 0x17, 0x00, 0x2C, 0x00, 0x24, 0x40, ++ 0x2D, 0xE9, 0xF0, 0x41, 0x07, 0x46, 0x82, 0xB0, 0xEF, 0xF3, 0x10, 0x83, ++ 0xD8, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x24, 0x4B, 0x01, 0x20, 0x18, 0x60, ++ 0x23, 0x4E, 0x24, 0x4B, 0x35, 0x68, 0x1B, 0x68, 0x01, 0x35, 0x35, 0x60, ++ 0x1C, 0x78, 0x01, 0x2C, 0x2B, 0xD0, 0x21, 0x4C, 0x23, 0x68, 0x43, 0xF4, ++ 0x80, 0x73, 0x23, 0x60, 0x23, 0x68, 0x9B, 0x05, 0xFC, 0xD4, 0x1E, 0x4B, ++ 0x18, 0x68, 0xC8, 0xB1, 0x1D, 0x4B, 0x1E, 0x4C, 0xD3, 0xF8, 0x04, 0x0C, ++ 0x47, 0x60, 0x20, 0x68, 0x01, 0x44, 0x21, 0x60, 0x17, 0x49, 0xC3, 0xF8, ++ 0x04, 0x2C, 0x0B, 0x68, 0x23, 0xF4, 0x80, 0x73, 0x0B, 0x60, 0x35, 0xB1, ++ 0x10, 0x4B, 0x01, 0x3D, 0x1B, 0x68, 0x35, 0x60, 0x0D, 0xB9, 0x03, 0xB1, ++ 0x62, 0xB6, 0x02, 0xB0, 0xBD, 0xE8, 0xF0, 0x81, 0x11, 0x48, 0x1F, 0x60, ++ 0x04, 0x68, 0x0F, 0x4B, 0x21, 0x44, 0x01, 0x60, 0xE6, 0xE7, 0xDF, 0xF8, ++ 0x3C, 0x80, 0x98, 0xF8, 0x00, 0x30, 0x00, 0x2B, 0xCD, 0xD1, 0x02, 0x20, ++ 0xCD, 0xE9, 0x00, 0x12, 0xFD, 0xF7, 0x3C, 0xFE, 0xDD, 0xE9, 0x00, 0x12, ++ 0x35, 0x68, 0x88, 0xF8, 0x00, 0x40, 0xC2, 0xE7, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x74, 0x36, 0x17, 0x00, 0x60, 0x00, 0x24, 0x40, ++ 0xA0, 0x00, 0x24, 0x40, 0x7C, 0x36, 0x17, 0x00, 0x9C, 0x00, 0x24, 0x40, ++ 0x1D, 0x26, 0x17, 0x00, 0x30, 0xB4, 0x85, 0x68, 0x06, 0x4C, 0xC3, 0xF3, ++ 0x0B, 0x03, 0x2C, 0x40, 0x02, 0x9D, 0x1C, 0x43, 0x44, 0xEA, 0xC5, 0x74, ++ 0x84, 0x60, 0xC0, 0xE9, 0x00, 0x12, 0x30, 0xBC, 0x70, 0x47, 0x00, 0xBF, ++ 0x00, 0xF0, 0xFF, 0x7F, 0xF8, 0xB5, 0x04, 0x46, 0xEF, 0xF3, 0x10, 0x83, ++ 0xDA, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x23, 0x4B, 0x01, 0x22, 0x1A, 0x60, ++ 0x22, 0x4D, 0x23, 0x4B, 0x29, 0x68, 0x1B, 0x68, 0x01, 0x31, 0x29, 0x60, ++ 0x1E, 0x78, 0x01, 0x2E, 0x30, 0xD0, 0x20, 0x4A, 0x13, 0x68, 0x43, 0xF0, ++ 0x40, 0x03, 0x13, 0x60, 0x13, 0x68, 0x1B, 0x06, 0xFC, 0xD4, 0x1D, 0x4B, ++ 0x1A, 0x68, 0xF2, 0xB1, 0x1C, 0x4B, 0x1D, 0x48, 0x41, 0xF6, 0x14, 0x02, ++ 0x9A, 0x58, 0x54, 0x60, 0x02, 0x68, 0x01, 0x32, 0x02, 0x60, 0x41, 0xF6, ++ 0x14, 0x02, 0x15, 0x4E, 0x9C, 0x50, 0x18, 0x48, 0x32, 0x68, 0x03, 0x78, ++ 0x22, 0xF0, 0x40, 0x02, 0x43, 0xF0, 0x02, 0x03, 0x32, 0x60, 0x03, 0x70, ++ 0x31, 0xB1, 0x0C, 0x4B, 0x01, 0x39, 0x1B, 0x68, 0x29, 0x60, 0x09, 0xB9, ++ 0x03, 0xB1, 0x62, 0xB6, 0xF8, 0xBD, 0x0E, 0x48, 0x1C, 0x60, 0x02, 0x68, ++ 0x0B, 0x4B, 0x01, 0x32, 0x02, 0x60, 0xE2, 0xE7, 0x0C, 0x4F, 0x3B, 0x78, ++ 0x00, 0x2B, 0xCA, 0xD1, 0x02, 0x20, 0xFD, 0xF7, 0xC9, 0xFD, 0x29, 0x68, ++ 0x3E, 0x70, 0xC4, 0xE7, 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x74, 0x36, 0x17, 0x00, 0x60, 0x00, 0x24, 0x40, 0x98, 0x00, 0x24, 0x40, ++ 0x7C, 0x36, 0x17, 0x00, 0x94, 0x00, 0x24, 0x40, 0x9C, 0x4E, 0x17, 0x00, ++ 0x1D, 0x26, 0x17, 0x00, 0x2D, 0xE9, 0xF8, 0x43, 0x80, 0x46, 0x04, 0x20, ++ 0x0F, 0x46, 0x15, 0x46, 0xFE, 0xF7, 0xF0, 0xFD, 0x68, 0xB3, 0x04, 0x46, ++ 0xFE, 0xF7, 0x34, 0xFF, 0x06, 0x46, 0x00, 0xB3, 0xC5, 0xF3, 0x03, 0x23, ++ 0x4F, 0xF0, 0x00, 0x09, 0x25, 0x70, 0x63, 0x70, 0x2A, 0x46, 0x84, 0xF8, ++ 0x02, 0x80, 0x39, 0x46, 0x84, 0xF8, 0x03, 0x90, 0x20, 0x1D, 0x2E, 0xF0, ++ 0xF9, 0xFB, 0xB2, 0x68, 0x0E, 0x4B, 0xC6, 0xF8, 0x04, 0x90, 0x04, 0x35, ++ 0x13, 0x40, 0xC5, 0xF3, 0x0B, 0x05, 0x1D, 0x43, 0x45, 0xF0, 0x00, 0x45, ++ 0x34, 0x60, 0xB5, 0x60, 0x30, 0x46, 0xBD, 0xE8, 0xF8, 0x43, 0xFF, 0xF7, ++ 0x71, 0xBF, 0x07, 0x48, 0x1C, 0xF0, 0xCC, 0xFF, 0x20, 0x46, 0xBD, 0xE8, ++ 0xF8, 0x43, 0xFE, 0xF7, 0xE7, 0xBD, 0xBD, 0xE8, 0xF8, 0x43, 0x03, 0x48, ++ 0x1C, 0xF0, 0xC2, 0xBF, 0x00, 0xF0, 0xFF, 0x7F, 0xEC, 0x83, 0x15, 0x00, ++ 0xD8, 0x83, 0x15, 0x00, 0x05, 0x4B, 0x1B, 0x78, 0x33, 0xB9, 0x05, 0x4B, ++ 0x18, 0x68, 0x6F, 0xEA, 0x10, 0x10, 0x00, 0xF0, 0x01, 0x00, 0x70, 0x47, ++ 0x01, 0x20, 0x70, 0x47, 0x1C, 0x26, 0x17, 0x00, 0x44, 0x00, 0x24, 0x40, ++ 0x44, 0x4A, 0x13, 0x69, 0x43, 0xF0, 0x01, 0x03, 0x30, 0xB4, 0x13, 0x61, ++ 0x13, 0x69, 0xD9, 0x07, 0xFC, 0xD4, 0x40, 0x4A, 0x13, 0x69, 0x00, 0x2B, ++ 0xFC, 0xDA, 0xD3, 0x68, 0x3E, 0x48, 0x3D, 0x49, 0x43, 0xF0, 0x80, 0x43, ++ 0x43, 0xF0, 0x07, 0x03, 0xD3, 0x60, 0xD3, 0x68, 0x18, 0x43, 0xD0, 0x60, ++ 0xD3, 0x68, 0x23, 0xF4, 0x71, 0x53, 0x23, 0xF0, 0x28, 0x03, 0xD3, 0x60, ++ 0x13, 0x69, 0x43, 0xF0, 0x01, 0x03, 0x13, 0x61, 0x0B, 0x69, 0xDA, 0x07, ++ 0xFC, 0xD4, 0x32, 0x4B, 0x1A, 0x69, 0x00, 0x2A, 0xFC, 0xDA, 0xDA, 0x68, ++ 0x30, 0x48, 0x2F, 0x49, 0x42, 0xF0, 0x80, 0x42, 0x42, 0xF0, 0x07, 0x02, ++ 0xDA, 0x60, 0xDA, 0x68, 0x10, 0x43, 0xD8, 0x60, 0xDA, 0x68, 0x22, 0xF4, ++ 0x71, 0x52, 0x22, 0xF0, 0x28, 0x02, 0xDA, 0x60, 0xD3, 0xF8, 0x00, 0x28, ++ 0x22, 0xF4, 0xC0, 0x52, 0x22, 0xF0, 0x03, 0x02, 0xC3, 0xF8, 0x00, 0x28, ++ 0xD3, 0xF8, 0x00, 0x28, 0x42, 0xF4, 0x00, 0x02, 0x42, 0xF0, 0x04, 0x02, ++ 0xC3, 0xF8, 0x00, 0x28, 0x00, 0x24, 0x4F, 0xF0, 0xFF, 0x35, 0x01, 0x22, ++ 0x9C, 0x61, 0x01, 0x2A, 0x5D, 0x61, 0xC3, 0xF8, 0x1C, 0x48, 0xC3, 0xF8, ++ 0x14, 0x48, 0xC3, 0xF8, 0x10, 0x48, 0xA2, 0xF1, 0x02, 0x03, 0x28, 0x46, ++ 0x01, 0xEB, 0x43, 0x13, 0x0B, 0xD0, 0x05, 0x2A, 0xC3, 0xF8, 0x28, 0x0B, ++ 0xC3, 0xF8, 0x28, 0x09, 0x0A, 0xD0, 0x01, 0x32, 0x93, 0x1E, 0x01, 0x2A, ++ 0x01, 0xEB, 0x43, 0x13, 0xF3, 0xD1, 0xC1, 0xF8, 0x08, 0x0B, 0xC1, 0xF8, ++ 0x08, 0x09, 0xF4, 0xE7, 0x0F, 0x48, 0x10, 0x4B, 0x0C, 0x4A, 0x88, 0x61, ++ 0x4B, 0x63, 0x53, 0x6B, 0x1B, 0x01, 0xFC, 0xD5, 0xD2, 0xF8, 0x04, 0x38, ++ 0x23, 0xF0, 0x02, 0x03, 0xC2, 0xF8, 0x04, 0x38, 0xD2, 0xF8, 0x04, 0x38, ++ 0x2E, 0x21, 0x43, 0xF4, 0x00, 0x43, 0xC2, 0xF8, 0x04, 0x38, 0x91, 0x60, ++ 0x93, 0x68, 0x43, 0xF0, 0x01, 0x03, 0x30, 0xBC, 0x93, 0x60, 0x70, 0x47, ++ 0x00, 0x00, 0x20, 0x40, 0x10, 0x00, 0x06, 0x40, 0x00, 0x38, 0x00, 0x80, ++ 0x41, 0x00, 0x44, 0x02, 0x0A, 0x4B, 0x0B, 0x49, 0x1A, 0x68, 0x08, 0x68, ++ 0x0A, 0x49, 0x0B, 0x4B, 0xC2, 0xE9, 0x00, 0x10, 0xC3, 0xF8, 0x14, 0x2B, ++ 0xD3, 0xF8, 0x08, 0x2B, 0xC3, 0xF8, 0x08, 0x2B, 0xD3, 0xF8, 0x00, 0x2B, ++ 0x42, 0xF0, 0x04, 0x42, 0xC3, 0xF8, 0x00, 0x2B, 0x70, 0x47, 0x00, 0xBF, ++ 0x5C, 0x60, 0x17, 0x00, 0x60, 0x60, 0x17, 0x00, 0x40, 0x00, 0x00, 0x0A, ++ 0x00, 0x00, 0x20, 0x40, 0x12, 0x4A, 0x13, 0x4B, 0x11, 0x68, 0x18, 0x68, ++ 0x12, 0x4B, 0x30, 0xB4, 0x12, 0x4C, 0x4F, 0xF0, 0x20, 0x62, 0x00, 0x25, ++ 0x65, 0x81, 0xC1, 0xE9, 0x00, 0x20, 0x1A, 0x69, 0x22, 0xF4, 0xFC, 0x62, ++ 0x42, 0xF0, 0x20, 0x02, 0x1A, 0x61, 0x18, 0x69, 0x10, 0xF0, 0x20, 0x00, ++ 0xFB, 0xD1, 0xD3, 0xF8, 0x08, 0x29, 0xC3, 0xF8, 0x08, 0x29, 0xC3, 0xF8, ++ 0x14, 0x19, 0xD3, 0xF8, 0x00, 0x29, 0x42, 0xF0, 0x04, 0x42, 0x30, 0xBC, ++ 0xC3, 0xF8, 0x00, 0x29, 0x70, 0x47, 0x00, 0xBF, 0x40, 0x60, 0x17, 0x00, ++ 0x58, 0x60, 0x17, 0x00, 0x00, 0x00, 0x20, 0x40, 0xB4, 0x27, 0x17, 0x00, ++ 0x70, 0xB5, 0x0B, 0x4B, 0x04, 0x46, 0x01, 0x38, 0x03, 0xEB, 0x00, 0x10, ++ 0x10, 0x22, 0x05, 0x7A, 0x00, 0x21, 0xF7, 0xF7, 0x4D, 0xFB, 0x55, 0xB1, ++ 0x06, 0x48, 0x00, 0xEB, 0x84, 0x04, 0x23, 0x6A, 0x2B, 0xB1, 0x00, 0x21, ++ 0xBD, 0xE8, 0x70, 0x40, 0x08, 0x46, 0x01, 0x22, 0x18, 0x47, 0x70, 0xBD, ++ 0x08, 0x28, 0x17, 0x00, 0x20, 0x26, 0x17, 0x00, 0x70, 0xB5, 0x0B, 0x4B, ++ 0x04, 0x46, 0x01, 0x38, 0x03, 0xEB, 0x00, 0x10, 0x10, 0x22, 0xC5, 0x7A, ++ 0x00, 0x21, 0xF7, 0xF7, 0x31, 0xFB, 0x55, 0xB1, 0x06, 0x48, 0x00, 0xEB, ++ 0x84, 0x04, 0x23, 0x6B, 0x2B, 0xB1, 0x00, 0x21, 0xBD, 0xE8, 0x70, 0x40, ++ 0x08, 0x46, 0x01, 0x22, 0x18, 0x47, 0x70, 0xBD, 0xC8, 0x27, 0x17, 0x00, ++ 0x20, 0x26, 0x17, 0x00, 0x10, 0xB5, 0x01, 0x24, 0x82, 0xB0, 0xE0, 0xB2, ++ 0x01, 0x90, 0x01, 0x34, 0xFF, 0xF7, 0xC0, 0xFF, 0x01, 0x98, 0xFF, 0xF7, ++ 0xD9, 0xFF, 0x05, 0x2C, 0xF5, 0xD1, 0x02, 0xB0, 0x10, 0xBD, 0x00, 0xBF, ++ 0x38, 0xB5, 0x0C, 0x46, 0x00, 0x28, 0x39, 0xD0, 0x09, 0xBB, 0x1D, 0x4B, ++ 0x1D, 0x4A, 0x1B, 0x68, 0x51, 0x81, 0x1D, 0x4D, 0x4F, 0xF0, 0x42, 0x42, ++ 0x1A, 0x60, 0xDA, 0x78, 0x42, 0xF0, 0x04, 0x02, 0xDA, 0x70, 0xD9, 0x78, ++ 0x28, 0x68, 0x19, 0x4A, 0x58, 0x60, 0x01, 0xF0, 0x07, 0x01, 0x41, 0xF0, ++ 0x08, 0x01, 0xD9, 0x70, 0xD2, 0xF8, 0x08, 0x19, 0xC2, 0xF8, 0x08, 0x19, ++ 0xC2, 0xF8, 0x14, 0x39, 0xD2, 0xF8, 0x00, 0x39, 0x43, 0xF0, 0x04, 0x43, ++ 0xC2, 0xF8, 0x00, 0x39, 0x38, 0xBD, 0x0E, 0x4D, 0x01, 0x46, 0x22, 0x46, ++ 0x28, 0x68, 0x2E, 0xF0, 0x71, 0xFA, 0x09, 0x4B, 0x09, 0x4A, 0x1B, 0x68, ++ 0x54, 0x81, 0x4F, 0xF0, 0x40, 0x41, 0xC2, 0x22, 0x40, 0x2C, 0x19, 0x60, ++ 0x1C, 0x80, 0xDA, 0x70, 0xD3, 0xD1, 0xD2, 0xB2, 0x6F, 0xF3, 0x82, 0x02, ++ 0xDA, 0x70, 0xD2, 0xE7, 0x02, 0x4D, 0xEC, 0xE7, 0x40, 0x60, 0x17, 0x00, ++ 0xB4, 0x27, 0x17, 0x00, 0x58, 0x60, 0x17, 0x00, 0x00, 0x00, 0x20, 0x40, ++ 0xF0, 0xB4, 0x80, 0xB3, 0x27, 0x4D, 0x43, 0x1E, 0x05, 0xEB, 0x43, 0x16, ++ 0x08, 0x36, 0x05, 0xEB, 0x43, 0x15, 0x2F, 0x68, 0x17, 0xF0, 0x80, 0x2F, ++ 0x22, 0xD0, 0x23, 0x4B, 0x3B, 0x40, 0xB3, 0xF5, 0x00, 0x3F, 0x2C, 0xD0, ++ 0x21, 0x4C, 0xD4, 0xF8, 0x04, 0x38, 0x43, 0xF4, 0x00, 0x73, 0xC4, 0xF8, ++ 0x04, 0x38, 0x63, 0x69, 0x1B, 0x06, 0xFC, 0xD5, 0x2B, 0x68, 0x19, 0x43, ++ 0x41, 0xF0, 0x00, 0x61, 0x41, 0xF4, 0x00, 0x41, 0x29, 0x60, 0x1A, 0xB1, ++ 0x2B, 0x68, 0x23, 0xEA, 0x02, 0x02, 0x2A, 0x60, 0x60, 0xB9, 0x16, 0x4A, ++ 0xD2, 0xF8, 0x04, 0x38, 0x43, 0xF4, 0x80, 0x63, 0xC2, 0xF8, 0x04, 0x38, ++ 0xF0, 0xBC, 0xFF, 0xF7, 0x3D, 0xBF, 0x12, 0x4E, 0x12, 0x4D, 0xD2, 0xE7, ++ 0x00, 0x2F, 0x0C, 0xDB, 0x3B, 0x04, 0xEE, 0xD4, 0x2B, 0x68, 0x23, 0xF4, ++ 0x00, 0x43, 0x2B, 0x60, 0xE9, 0xE7, 0xB1, 0xF1, 0x00, 0x6F, 0xCF, 0xD1, ++ 0x00, 0x2A, 0xCD, 0xD1, 0xEA, 0xE7, 0x02, 0x23, 0x33, 0x60, 0x2B, 0x68, ++ 0x43, 0xF0, 0x80, 0x43, 0x2B, 0x60, 0x33, 0x68, 0x9A, 0x07, 0xFC, 0xD5, ++ 0x3B, 0x04, 0xD8, 0xD4, 0xE8, 0xE7, 0x00, 0xBF, 0x20, 0x0B, 0x20, 0x40, ++ 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x20, 0x40, 0x08, 0x0B, 0x20, 0x40, ++ 0x00, 0x0B, 0x20, 0x40, 0x70, 0xB4, 0x70, 0xB3, 0x44, 0x1E, 0x36, 0x4B, ++ 0x66, 0x01, 0x03, 0xEB, 0x44, 0x14, 0xF5, 0x58, 0x15, 0xF0, 0x80, 0x2F, ++ 0x4D, 0xD0, 0x08, 0x36, 0x33, 0x44, 0x32, 0x4E, 0x2E, 0x40, 0xB6, 0xF5, ++ 0x00, 0x3F, 0x29, 0xD1, 0xB1, 0xF1, 0x00, 0x6F, 0x46, 0xD0, 0x40, 0x26, ++ 0x1E, 0x60, 0x23, 0x68, 0x0B, 0x43, 0x43, 0xF0, 0x00, 0x63, 0x43, 0xF4, ++ 0x00, 0x43, 0x23, 0x60, 0x00, 0x2A, 0x45, 0xD1, 0x29, 0x4A, 0x83, 0x01, ++ 0x43, 0xF0, 0x20, 0x03, 0x13, 0x61, 0x13, 0x69, 0x99, 0x06, 0xFC, 0xD4, ++ 0x2B, 0x04, 0x03, 0xD4, 0x23, 0x68, 0x23, 0xF4, 0x00, 0x43, 0x23, 0x60, ++ 0x48, 0xBB, 0x70, 0xBC, 0x70, 0x47, 0x22, 0x4C, 0x25, 0x68, 0x15, 0xF0, ++ 0x80, 0x2F, 0xF8, 0xD0, 0x1D, 0x4E, 0x20, 0x4B, 0x2E, 0x40, 0xB6, 0xF5, ++ 0x00, 0x3F, 0xD5, 0xD0, 0x40, 0x26, 0x1E, 0x60, 0x26, 0x68, 0x31, 0x43, ++ 0x41, 0xF0, 0x00, 0x61, 0x41, 0xF4, 0x00, 0x41, 0x00, 0x2D, 0x21, 0x60, ++ 0xD6, 0xDA, 0xAE, 0x03, 0x04, 0xD4, 0x19, 0x68, 0x49, 0x06, 0xFC, 0xD5, ++ 0x40, 0x21, 0x19, 0x60, 0xDA, 0xB9, 0x02, 0x22, 0x1A, 0x60, 0x22, 0x68, ++ 0x42, 0xF0, 0x80, 0x42, 0x22, 0x60, 0x1A, 0x68, 0x96, 0x07, 0xFC, 0xD5, ++ 0xC6, 0xE7, 0x70, 0xBC, 0xFF, 0xF7, 0xD4, 0xBE, 0x00, 0x2A, 0xCF, 0xD0, ++ 0x40, 0x21, 0x19, 0x60, 0x23, 0x68, 0x43, 0xF0, 0x00, 0x63, 0x43, 0xF4, ++ 0x00, 0x43, 0x23, 0x60, 0x23, 0x68, 0x23, 0xEA, 0x02, 0x02, 0x22, 0x60, ++ 0xB4, 0xE7, 0x21, 0x68, 0x21, 0xEA, 0x02, 0x02, 0x22, 0x60, 0xDE, 0xE7, ++ 0x20, 0x09, 0x20, 0x40, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x20, 0x40, ++ 0x00, 0x09, 0x20, 0x40, 0x08, 0x09, 0x20, 0x40, 0x49, 0xB9, 0x0A, 0x4B, ++ 0x0A, 0x4A, 0x01, 0x28, 0x0C, 0xBF, 0x18, 0x46, 0x10, 0x46, 0x00, 0x68, ++ 0xC0, 0xF3, 0x40, 0x50, 0x70, 0x47, 0x01, 0x28, 0x0C, 0xBF, 0x04, 0x48, ++ 0x04, 0x48, 0x49, 0x01, 0x08, 0x44, 0x00, 0x68, 0xC0, 0xF3, 0x40, 0x50, ++ 0x70, 0x47, 0x00, 0xBF, 0x00, 0x09, 0x20, 0x40, 0x00, 0x0B, 0x20, 0x40, ++ 0x38, 0xB9, 0x04, 0x29, 0x0D, 0xD8, 0x02, 0x46, 0x08, 0x46, 0x4F, 0xF0, ++ 0x00, 0x61, 0xFF, 0xF7, 0x07, 0xBF, 0x04, 0x29, 0x05, 0xD8, 0x08, 0x46, ++ 0x00, 0x22, 0x4F, 0xF0, 0x00, 0x61, 0xFF, 0xF7, 0x5B, 0xBF, 0x70, 0x47, ++ 0x38, 0xB9, 0x04, 0x29, 0x0D, 0xD8, 0x02, 0x46, 0x08, 0x46, 0x4F, 0xF4, ++ 0x00, 0x11, 0xFF, 0xF7, 0xF5, 0xBE, 0x04, 0x29, 0x05, 0xD8, 0x08, 0x46, ++ 0x00, 0x22, 0x4F, 0xF4, 0x00, 0x11, 0xFF, 0xF7, 0x49, 0xBF, 0x70, 0x47, ++ 0x40, 0xB9, 0x04, 0x29, 0x0F, 0xD8, 0x08, 0x46, 0x4F, 0xF4, 0x00, 0x12, ++ 0x4F, 0xF0, 0x00, 0x61, 0xFF, 0xF7, 0xE2, 0xBE, 0x04, 0x29, 0x06, 0xD8, ++ 0x08, 0x46, 0x4F, 0xF4, 0x00, 0x12, 0x4F, 0xF0, 0x00, 0x61, 0xFF, 0xF7, ++ 0x35, 0xBF, 0x70, 0x47, 0xFF, 0xF7, 0xC6, 0xBF, 0x2D, 0xE9, 0xF8, 0x43, ++ 0x04, 0x46, 0x0D, 0x46, 0x57, 0x48, 0x00, 0x21, 0x1B, 0xF0, 0x04, 0xFC, ++ 0x00, 0x2C, 0x00, 0xF0, 0x95, 0x80, 0x23, 0x68, 0x00, 0x2B, 0x7B, 0xD0, ++ 0x63, 0x68, 0x00, 0x2B, 0x78, 0xD0, 0xA3, 0x68, 0x00, 0x2B, 0x75, 0xD0, ++ 0x63, 0x69, 0x00, 0x2B, 0x72, 0xD0, 0x4F, 0x4E, 0x33, 0x78, 0x03, 0xF0, ++ 0xFF, 0x07, 0x00, 0x2B, 0x6F, 0xD1, 0xDF, 0xF8, 0x68, 0x81, 0x21, 0x46, ++ 0x40, 0x46, 0x01, 0x24, 0x48, 0x22, 0x34, 0x70, 0x2E, 0xF0, 0x06, 0xF9, ++ 0x48, 0x4B, 0xD3, 0xF8, 0x94, 0x30, 0x00, 0x2B, 0x77, 0xD0, 0x47, 0x48, ++ 0x1B, 0xF0, 0xDE, 0xFB, 0x46, 0x4B, 0xD3, 0xF8, 0x00, 0x28, 0x12, 0xF4, ++ 0xFE, 0x6F, 0x5B, 0xD0, 0x44, 0x49, 0x45, 0x4A, 0xD1, 0xF8, 0x00, 0xC0, ++ 0x44, 0x49, 0x12, 0x68, 0xDF, 0xF8, 0x30, 0x91, 0x09, 0x68, 0xC9, 0xF8, ++ 0x04, 0x70, 0x04, 0x20, 0xC9, 0xF8, 0x08, 0x70, 0x89, 0xF8, 0x00, 0x70, ++ 0xC2, 0xF8, 0x04, 0xC0, 0x30, 0x70, 0xC3, 0xF8, 0x14, 0x2B, 0xC8, 0x78, ++ 0x3C, 0x4A, 0x40, 0xF0, 0xC0, 0x00, 0xD2, 0xF8, 0x00, 0xC0, 0xC8, 0x70, ++ 0x9C, 0xF8, 0x03, 0x00, 0x39, 0x4A, 0x40, 0xF0, 0xC0, 0x00, 0x17, 0x68, ++ 0x8C, 0xF8, 0x03, 0x00, 0xF8, 0x78, 0xD2, 0xF8, 0x04, 0xE0, 0x40, 0xF0, ++ 0xC0, 0x00, 0xF8, 0x70, 0x9E, 0xF8, 0x03, 0x00, 0xD2, 0xE9, 0x02, 0xC7, ++ 0x40, 0xF0, 0xC0, 0x02, 0x8E, 0xF8, 0x03, 0x20, 0x9C, 0xF8, 0x03, 0x20, ++ 0x42, 0xF0, 0xC0, 0x02, 0x8C, 0xF8, 0x03, 0x20, 0xFA, 0x78, 0x42, 0xF0, ++ 0xC0, 0x02, 0xFA, 0x70, 0xC3, 0xF8, 0x14, 0x19, 0xFF, 0xF7, 0x86, 0xFD, ++ 0xD8, 0xF8, 0x44, 0x30, 0x89, 0xF8, 0x00, 0x40, 0x03, 0xB1, 0x98, 0x47, ++ 0x26, 0x4B, 0x27, 0x49, 0x9A, 0x68, 0xD1, 0xF8, 0x04, 0x11, 0xD1, 0x67, ++ 0xA3, 0xF5, 0x40, 0x63, 0x4F, 0xF4, 0x00, 0x42, 0x01, 0x2D, 0x1A, 0x60, ++ 0x23, 0xD0, 0x00, 0x20, 0xBD, 0xE8, 0xF8, 0x83, 0x02, 0x20, 0xBD, 0xE8, ++ 0xF8, 0x83, 0x03, 0x20, 0xBD, 0xE8, 0xF8, 0x83, 0x9A, 0x68, 0xD2, 0x07, ++ 0x14, 0xD5, 0x9A, 0x68, 0x22, 0xF0, 0x01, 0x02, 0x9A, 0x60, 0xD3, 0xF8, ++ 0x04, 0x28, 0x42, 0xF0, 0x02, 0x02, 0xC3, 0xF8, 0x04, 0x28, 0xFF, 0xF7, ++ 0xC9, 0xFC, 0xD9, 0xE7, 0x01, 0x20, 0xBD, 0xE8, 0xF8, 0x83, 0x14, 0x48, ++ 0xFD, 0xF7, 0x9C, 0xF9, 0x04, 0x20, 0xE2, 0xE7, 0xFF, 0xF7, 0xBE, 0xFC, ++ 0xCE, 0xE7, 0x11, 0x4B, 0x11, 0x48, 0x1B, 0x69, 0x1B, 0xF0, 0x5C, 0xFB, ++ 0x33, 0x78, 0x04, 0x2B, 0xFC, 0xD1, 0xD2, 0xE7, 0xFC, 0x83, 0x15, 0x00, ++ 0x6F, 0x26, 0x17, 0x00, 0x00, 0x00, 0x10, 0x40, 0x08, 0x84, 0x15, 0x00, ++ 0x00, 0x00, 0x20, 0x40, 0x60, 0x60, 0x17, 0x00, 0x5C, 0x60, 0x17, 0x00, ++ 0x40, 0x60, 0x17, 0x00, 0x54, 0x60, 0x17, 0x00, 0x44, 0x60, 0x17, 0x00, ++ 0x00, 0xED, 0x00, 0xE0, 0x88, 0x1A, 0x17, 0x00, 0x1C, 0x84, 0x15, 0x00, ++ 0x00, 0x10, 0x50, 0x40, 0x34, 0x84, 0x15, 0x00, 0x20, 0x26, 0x17, 0x00, ++ 0xB4, 0x27, 0x17, 0x00, 0x14, 0x4B, 0x4F, 0xF4, 0x00, 0x42, 0xC3, 0xF8, ++ 0x80, 0x20, 0xBF, 0xF3, 0x4F, 0x8F, 0xBF, 0xF3, 0x6F, 0x8F, 0x11, 0x4A, ++ 0x11, 0x4B, 0x12, 0x48, 0x00, 0x21, 0x11, 0x70, 0x9A, 0x68, 0x22, 0xF0, ++ 0x01, 0x02, 0x9A, 0x60, 0xD3, 0xF8, 0x04, 0x28, 0x42, 0xF0, 0x02, 0x02, ++ 0xC3, 0xF8, 0x04, 0x28, 0x1A, 0x69, 0x42, 0xF0, 0x01, 0x02, 0x1A, 0x61, ++ 0xD3, 0xF8, 0x04, 0x28, 0x42, 0xF0, 0x02, 0x02, 0xC3, 0xF8, 0x04, 0x28, ++ 0x1A, 0x69, 0x42, 0xF0, 0x01, 0x02, 0x1A, 0x61, 0x48, 0x22, 0xF7, 0xF7, ++ 0x9F, 0xB8, 0x00, 0xBF, 0x00, 0xE1, 0x00, 0xE0, 0x6F, 0x26, 0x17, 0x00, ++ 0x00, 0x00, 0x20, 0x40, 0x20, 0x26, 0x17, 0x00, 0x2D, 0xE9, 0xF8, 0x4F, ++ 0x4E, 0x1E, 0xF7, 0xB2, 0x03, 0x2F, 0x41, 0xD8, 0x14, 0x46, 0x0D, 0x46, ++ 0x9B, 0x46, 0x02, 0x46, 0x00, 0x28, 0x3D, 0xD0, 0x04, 0xF0, 0xFD, 0x01, ++ 0x01, 0x29, 0x5B, 0xD0, 0xDF, 0x1C, 0xBF, 0x10, 0x7F, 0x00, 0xBF, 0xB2, ++ 0xBA, 0x46, 0x4F, 0xEA, 0x07, 0x49, 0x4F, 0xEA, 0x45, 0x18, 0x08, 0xF1, ++ 0x80, 0x48, 0x08, 0xF5, 0x00, 0x18, 0xD8, 0xF8, 0x00, 0x19, 0x11, 0xF0, ++ 0x80, 0x2F, 0x68, 0xD1, 0xA2, 0x04, 0x02, 0xF4, 0x40, 0x22, 0xCB, 0xF3, ++ 0x0A, 0x03, 0x3B, 0x4C, 0x13, 0x43, 0x43, 0xEA, 0x85, 0x53, 0x21, 0x88, ++ 0x43, 0xF0, 0xC0, 0x53, 0x43, 0xF4, 0x00, 0x43, 0xC8, 0xF8, 0x00, 0x39, ++ 0x01, 0xEB, 0x0A, 0x03, 0xB3, 0xF5, 0xC0, 0x6F, 0x5E, 0xDC, 0x34, 0x4A, ++ 0x40, 0x36, 0x02, 0xEB, 0x86, 0x06, 0x41, 0xEA, 0x09, 0x03, 0x73, 0x60, ++ 0xD2, 0xF8, 0x1C, 0x38, 0x0F, 0x44, 0x01, 0x21, 0x01, 0xFA, 0x05, 0xF5, ++ 0x1D, 0x43, 0x27, 0x80, 0xC2, 0xF8, 0x1C, 0x58, 0xBD, 0xE8, 0xF8, 0x8F, ++ 0x4E, 0x01, 0x06, 0xF1, 0x80, 0x46, 0x06, 0xF5, 0x00, 0x16, 0xD6, 0xF8, ++ 0x00, 0x2B, 0x12, 0xF0, 0x80, 0x2F, 0x33, 0xD1, 0xA4, 0x04, 0x04, 0xF4, ++ 0x40, 0x24, 0xCB, 0xF3, 0x0A, 0x03, 0x23, 0x43, 0x43, 0xF0, 0xC0, 0x53, ++ 0x21, 0x4A, 0x43, 0xF4, 0x00, 0x43, 0xC6, 0xF8, 0x00, 0x3B, 0xD2, 0xF8, ++ 0x1C, 0x38, 0x4F, 0xF4, 0x80, 0x31, 0x01, 0xFA, 0x05, 0xF5, 0x1D, 0x43, ++ 0xC2, 0xF8, 0x1C, 0x58, 0xBD, 0xE8, 0xF8, 0x8F, 0xB3, 0xF5, 0x48, 0x7F, ++ 0x20, 0xD8, 0xDF, 0x1C, 0xBF, 0x10, 0x7F, 0x00, 0xBF, 0xB2, 0xBA, 0x46, ++ 0x4F, 0xEA, 0x07, 0x49, 0xBB, 0xF5, 0x80, 0x6F, 0x9D, 0xD9, 0x6F, 0xF4, ++ 0x80, 0x63, 0x0B, 0xEB, 0x03, 0x01, 0xB1, 0xF5, 0x80, 0x6F, 0x25, 0xBF, ++ 0x10, 0x4B, 0xA3, 0xFB, 0x0B, 0x13, 0x4F, 0xEA, 0x5B, 0x0B, 0xC3, 0xF3, ++ 0x4F, 0x0B, 0x8E, 0xE7, 0xFF, 0xF7, 0x34, 0xFE, 0xC8, 0xE7, 0x10, 0x46, ++ 0x29, 0x46, 0xFF, 0xF7, 0x2F, 0xFE, 0x91, 0xE7, 0x4F, 0xF4, 0xC8, 0x7A, ++ 0x57, 0x46, 0x4F, 0xF0, 0xC8, 0x79, 0xDF, 0xE7, 0x06, 0x48, 0x52, 0x46, ++ 0x4F, 0xF4, 0xC0, 0x63, 0xFD, 0xF7, 0x9E, 0xF8, 0x21, 0x88, 0x98, 0xE7, ++ 0x48, 0x28, 0x17, 0x00, 0x00, 0x00, 0x20, 0x40, 0xAB, 0xAA, 0xAA, 0xAA, ++ 0x40, 0x84, 0x15, 0x00, 0xF8, 0xB5, 0x27, 0x4B, 0x1B, 0x78, 0x04, 0x2B, ++ 0x3C, 0xD1, 0x44, 0x1E, 0xDF, 0xB2, 0xE3, 0xB2, 0x04, 0x2B, 0x39, 0xD8, ++ 0x8D, 0x07, 0x3D, 0xD1, 0x22, 0x4E, 0x4F, 0xEA, 0x04, 0x1E, 0x06, 0xEB, ++ 0x04, 0x1C, 0x56, 0xF8, 0x0E, 0x50, 0x8D, 0xBB, 0x43, 0x01, 0x03, 0xF1, ++ 0x80, 0x43, 0x03, 0xF5, 0x00, 0x13, 0xD3, 0xF8, 0x00, 0x0B, 0x00, 0x04, ++ 0x2A, 0xD5, 0x1B, 0x48, 0x46, 0xF8, 0x0E, 0x10, 0x50, 0xF8, 0x24, 0x00, ++ 0x19, 0x4F, 0x01, 0x26, 0x8C, 0xF8, 0x08, 0x60, 0xC6, 0x78, 0x64, 0x01, ++ 0x04, 0xF1, 0x80, 0x44, 0xBA, 0x42, 0x04, 0xF5, 0x00, 0x14, 0x06, 0xF0, ++ 0x31, 0x06, 0x28, 0xBF, 0x3A, 0x46, 0x46, 0xF0, 0x0E, 0x06, 0xCC, 0xF8, ++ 0x04, 0x20, 0x02, 0x80, 0x41, 0x60, 0xC6, 0x70, 0xC4, 0xF8, 0x34, 0x0B, ++ 0xD3, 0xF8, 0x00, 0x2B, 0x42, 0xF0, 0x04, 0x42, 0x28, 0x46, 0xC3, 0xF8, ++ 0x00, 0x2B, 0xF8, 0xBD, 0x01, 0x20, 0xF8, 0xBD, 0x02, 0x20, 0xF8, 0xBD, ++ 0x38, 0x46, 0xF8, 0xBD, 0x05, 0x20, 0xF8, 0xBD, 0x06, 0x48, 0xFD, 0xF7, ++ 0x47, 0xF8, 0x03, 0x20, 0xF8, 0xBD, 0x00, 0xBF, 0x6F, 0x26, 0x17, 0x00, ++ 0x08, 0x28, 0x17, 0x00, 0x44, 0x60, 0x17, 0x00, 0xFF, 0xFF, 0x07, 0x00, ++ 0x80, 0x84, 0x15, 0x00, 0xF8, 0xB5, 0x28, 0x4B, 0x1B, 0x78, 0x04, 0x2B, ++ 0x3E, 0xD1, 0x44, 0x1E, 0xDF, 0xB2, 0xE3, 0xB2, 0x04, 0x2B, 0x3B, 0xD8, ++ 0x8D, 0x07, 0x3F, 0xD1, 0x23, 0x4E, 0x4F, 0xEA, 0x04, 0x1E, 0x06, 0xEB, ++ 0x04, 0x1C, 0x56, 0xF8, 0x0E, 0x50, 0x9D, 0xBB, 0x43, 0x01, 0x03, 0xF1, ++ 0x80, 0x43, 0x03, 0xF5, 0x00, 0x13, 0xD3, 0xF8, 0x00, 0x0B, 0x00, 0x04, ++ 0x2C, 0xD5, 0x1C, 0x48, 0x46, 0xF8, 0x0E, 0x10, 0x50, 0xF8, 0x24, 0x00, ++ 0x1A, 0x4F, 0x01, 0x26, 0x8C, 0xF8, 0x08, 0x60, 0xC6, 0x78, 0x64, 0x01, ++ 0x04, 0xF1, 0x80, 0x44, 0xBA, 0x42, 0x04, 0xF5, 0x00, 0x14, 0x06, 0xF0, ++ 0x31, 0x06, 0x28, 0xBF, 0x3A, 0x46, 0x46, 0xF0, 0x0E, 0x06, 0xCC, 0xF8, ++ 0x04, 0x20, 0x02, 0x80, 0x41, 0x60, 0xC6, 0x70, 0xC4, 0xF8, 0x34, 0x0B, ++ 0xD3, 0xF8, 0x00, 0x2B, 0x22, 0xF0, 0x04, 0x42, 0x42, 0xF0, 0x00, 0x42, ++ 0x28, 0x46, 0xC3, 0xF8, 0x00, 0x2B, 0xF8, 0xBD, 0x01, 0x20, 0xF8, 0xBD, ++ 0x02, 0x20, 0xF8, 0xBD, 0x38, 0x46, 0xF8, 0xBD, 0x05, 0x20, 0xF8, 0xBD, ++ 0x06, 0x48, 0xFC, 0xF7, 0xEB, 0xFF, 0x03, 0x20, 0xF8, 0xBD, 0x00, 0xBF, ++ 0x6F, 0x26, 0x17, 0x00, 0x08, 0x28, 0x17, 0x00, 0x44, 0x60, 0x17, 0x00, ++ 0xFF, 0xFF, 0x07, 0x00, 0x80, 0x84, 0x15, 0x00, 0x10, 0xB5, 0x0C, 0x4C, ++ 0x0C, 0x4B, 0xE0, 0x89, 0x18, 0x80, 0x20, 0xB9, 0x0B, 0x4B, 0x03, 0x22, ++ 0x1A, 0x70, 0x01, 0x20, 0x10, 0xBD, 0x0A, 0x4B, 0x5B, 0x69, 0x4B, 0xB1, ++ 0xC0, 0xB2, 0x98, 0x47, 0x30, 0xB1, 0x06, 0x4A, 0x04, 0x21, 0x07, 0x23, ++ 0x11, 0x70, 0x23, 0x70, 0x01, 0x20, 0x10, 0xBD, 0x00, 0x20, 0x10, 0xBD, ++ 0xB4, 0x27, 0x17, 0x00, 0x6C, 0x26, 0x17, 0x00, 0x6F, 0x26, 0x17, 0x00, ++ 0x20, 0x26, 0x17, 0x00, 0xF8, 0xB5, 0x0C, 0x46, 0x00, 0x28, 0x70, 0xD1, ++ 0x01, 0xF0, 0x21, 0x03, 0x21, 0x2B, 0x7F, 0xD0, 0xE1, 0x07, 0x76, 0xD5, ++ 0x14, 0xF0, 0x08, 0x01, 0x00, 0xF0, 0x8B, 0x80, 0xB5, 0x4D, 0x2B, 0x78, ++ 0x00, 0x2B, 0x40, 0xF0, 0x76, 0x82, 0x63, 0x06, 0x40, 0xF1, 0x15, 0x81, ++ 0xB2, 0x4B, 0xD3, 0xF8, 0x14, 0x3B, 0x08, 0x3B, 0x00, 0x22, 0xC5, 0xE9, ++ 0x01, 0x22, 0x02, 0x20, 0x28, 0x70, 0x1A, 0x78, 0x29, 0x7B, 0xD2, 0x09, ++ 0x62, 0xF3, 0xC7, 0x11, 0x29, 0x73, 0x19, 0x78, 0x2A, 0x7B, 0x49, 0x11, ++ 0x61, 0xF3, 0x46, 0x12, 0x2A, 0x73, 0x19, 0x78, 0x61, 0xF3, 0x04, 0x02, ++ 0x2A, 0x73, 0x5A, 0x78, 0x6A, 0x73, 0xD9, 0x78, 0x9A, 0x78, 0x42, 0xEA, ++ 0x01, 0x22, 0xEA, 0x81, 0x59, 0x79, 0x1A, 0x79, 0x42, 0xEA, 0x01, 0x22, ++ 0x2A, 0x82, 0xDA, 0x79, 0x9B, 0x79, 0x43, 0xEA, 0x02, 0x23, 0x6B, 0x82, ++ 0x23, 0xB9, 0x95, 0xF9, 0x0C, 0x30, 0x00, 0x2B, 0xC0, 0xF2, 0x73, 0x82, ++ 0x9A, 0x4B, 0x9B, 0x4C, 0xD3, 0xF8, 0x14, 0x28, 0xE1, 0x68, 0x22, 0xF0, ++ 0x10, 0x02, 0xC3, 0xF8, 0x14, 0x28, 0xD3, 0xF8, 0x10, 0x28, 0x22, 0xF0, ++ 0x10, 0x02, 0xC3, 0xF8, 0x10, 0x28, 0x21, 0xB1, 0x91, 0x48, 0x88, 0x47, ++ 0x00, 0x28, 0x40, 0xF0, 0xB5, 0x80, 0x92, 0x4F, 0x2B, 0x7B, 0x3A, 0x78, ++ 0x13, 0xF0, 0x60, 0x0F, 0xD6, 0xB2, 0x40, 0xF0, 0xCF, 0x80, 0x68, 0x7B, ++ 0x0B, 0x28, 0x00, 0xF2, 0xDA, 0x80, 0xDF, 0xE8, 0x10, 0xF0, 0xDE, 0x00, ++ 0x27, 0x01, 0xD8, 0x00, 0xFA, 0x00, 0xD8, 0x00, 0x8C, 0x00, 0x5D, 0x01, ++ 0xD8, 0x00, 0x4F, 0x01, 0x44, 0x01, 0x98, 0x01, 0x85, 0x01, 0x82, 0x4D, ++ 0x2B, 0x78, 0x02, 0x2B, 0x53, 0xD0, 0xCA, 0x07, 0x55, 0xD4, 0xA1, 0x06, ++ 0x02, 0xD5, 0x2B, 0x78, 0x06, 0x2B, 0x3D, 0xD0, 0xF8, 0xBD, 0x7C, 0x4D, ++ 0x22, 0x07, 0x2B, 0x78, 0x35, 0xD5, 0x01, 0x2B, 0x8B, 0xD0, 0xF8, 0xBD, ++ 0x79, 0x4A, 0xD2, 0xF8, 0x10, 0x3B, 0x03, 0xF0, 0x7F, 0x03, 0x40, 0x2B, ++ 0x7F, 0xF4, 0x78, 0xAF, 0xD2, 0xF8, 0x10, 0x3B, 0x18, 0x03, 0x7F, 0xF5, ++ 0x73, 0xAF, 0xBD, 0xE8, 0xF8, 0x40, 0xFF, 0xF7, 0xDB, 0xBA, 0x74, 0x4B, ++ 0x6F, 0x4D, 0x1E, 0x68, 0xF3, 0x78, 0x13, 0xF0, 0x01, 0x03, 0x40, 0xF0, ++ 0xE2, 0x81, 0x2A, 0x78, 0x02, 0x2A, 0x3F, 0xF4, 0x6E, 0xAF, 0x03, 0x2A, ++ 0x00, 0xF0, 0xE6, 0x81, 0x05, 0x2A, 0x0D, 0xD1, 0x68, 0x4A, 0x2B, 0x70, ++ 0xD2, 0xF8, 0x14, 0x38, 0x23, 0xF0, 0x10, 0x03, 0xC2, 0xF8, 0x14, 0x38, ++ 0xD2, 0xF8, 0x10, 0x38, 0x23, 0xF0, 0x10, 0x03, 0xC2, 0xF8, 0x10, 0x38, ++ 0xFF, 0xF7, 0xBA, 0xFA, 0xBF, 0xE7, 0x02, 0x2B, 0xBD, 0xD1, 0x54, 0xE7, ++ 0xFF, 0xF7, 0xB4, 0xFA, 0x5D, 0x4A, 0x07, 0x23, 0x2B, 0x70, 0xD2, 0xF8, ++ 0x14, 0x38, 0x43, 0xF0, 0x10, 0x03, 0xC2, 0xF8, 0x14, 0x38, 0xBD, 0xE8, ++ 0xF8, 0x40, 0xFF, 0xF7, 0xC5, 0xBA, 0x5B, 0x48, 0xFC, 0xF7, 0xEC, 0xFE, ++ 0x41, 0xE7, 0x04, 0x2B, 0x00, 0xF0, 0xDD, 0x81, 0x07, 0x2B, 0xA4, 0xD1, ++ 0x52, 0x4B, 0x57, 0x49, 0x00, 0x20, 0x28, 0x70, 0xD3, 0xF8, 0x14, 0x28, ++ 0x22, 0xF0, 0x10, 0x02, 0xC3, 0xF8, 0x14, 0x28, 0xD3, 0xF8, 0x10, 0x28, ++ 0x22, 0xF0, 0x10, 0x02, 0xC3, 0xF8, 0x10, 0x28, 0x0A, 0x78, 0x00, 0x2A, ++ 0x96, 0xD0, 0xD3, 0xF8, 0x04, 0x48, 0x12, 0x01, 0x02, 0xF0, 0x70, 0x02, ++ 0x24, 0xF0, 0x70, 0x04, 0x22, 0x43, 0xC3, 0xF8, 0x04, 0x28, 0x08, 0x70, ++ 0xF8, 0xBD, 0x43, 0x48, 0xE9, 0x89, 0xD0, 0xF8, 0x00, 0x28, 0x0B, 0x01, ++ 0x22, 0xF4, 0xFE, 0x62, 0x03, 0xF4, 0xFE, 0x63, 0x13, 0x43, 0x07, 0x22, ++ 0xC0, 0xF8, 0x00, 0x38, 0x2A, 0x70, 0x00, 0x29, 0x40, 0xF0, 0xF2, 0x81, ++ 0x02, 0x23, 0x3B, 0x70, 0x04, 0x2E, 0x40, 0xF0, 0x9F, 0x80, 0x3B, 0x78, ++ 0x04, 0x2B, 0x01, 0xD0, 0xFF, 0xF7, 0xE8, 0xFA, 0x2B, 0x78, 0x03, 0x2B, ++ 0x26, 0xD0, 0x04, 0x2B, 0x00, 0xF0, 0xAB, 0x80, 0x07, 0x2B, 0x00, 0xF0, ++ 0x91, 0x80, 0x00, 0x24, 0x22, 0x46, 0x20, 0x46, 0x4F, 0xF4, 0x00, 0x11, ++ 0x2C, 0x70, 0xFF, 0xF7, 0x2F, 0xFB, 0x22, 0x46, 0x20, 0x46, 0x4F, 0xF4, ++ 0x00, 0x11, 0xFF, 0xF7, 0x85, 0xFB, 0xBD, 0xE8, 0xF8, 0x40, 0xFF, 0xF7, ++ 0x49, 0xBA, 0x2B, 0x4B, 0x1B, 0x68, 0x5B, 0x68, 0xEA, 0xE6, 0x2C, 0x48, ++ 0xFC, 0xF7, 0x8A, 0xFE, 0x04, 0x2E, 0xE4, 0xD1, 0x3B, 0x78, 0x04, 0x2B, ++ 0xE1, 0xD0, 0xFF, 0xF7, 0xBF, 0xFA, 0xDE, 0xE7, 0x6B, 0x68, 0x00, 0x2B, ++ 0x7F, 0xF4, 0x57, 0xAF, 0x25, 0x4B, 0x6B, 0x60, 0x53, 0xE7, 0x04, 0x2E, ++ 0xD5, 0xD1, 0x3B, 0x78, 0x04, 0x2B, 0xF0, 0xD1, 0xD1, 0xE7, 0x3B, 0x78, ++ 0x04, 0x2B, 0x00, 0xF0, 0xCB, 0x81, 0x2B, 0x8A, 0x00, 0x2B, 0xE3, 0xD1, ++ 0x2B, 0x7B, 0x03, 0xF0, 0x1F, 0x03, 0x01, 0x2B, 0x00, 0xF0, 0xCF, 0x81, ++ 0x02, 0x2B, 0x00, 0xF0, 0xC1, 0x80, 0x00, 0x2B, 0xE7, 0xD1, 0x19, 0x4A, ++ 0x19, 0x4B, 0x12, 0x78, 0x1A, 0x80, 0x02, 0x21, 0x04, 0x22, 0x6B, 0x60, ++ 0x29, 0x81, 0x2A, 0x70, 0x5A, 0xE0, 0x3B, 0x78, 0x04, 0x2B, 0x02, 0xD0, ++ 0x2B, 0x8A, 0x00, 0x2B, 0xC8, 0xD1, 0x2B, 0x7B, 0x13, 0xF0, 0x1F, 0x03, ++ 0x00, 0xF0, 0xB9, 0x81, 0x02, 0x2B, 0x03, 0xD1, 0xEB, 0x89, 0x00, 0x2B, ++ 0x00, 0xF0, 0xBF, 0x81, 0x07, 0x23, 0x04, 0x2E, 0x2B, 0x70, 0xA0, 0xD1, ++ 0xC9, 0xE7, 0x00, 0xBF, 0xB4, 0x27, 0x17, 0x00, 0x00, 0x00, 0x20, 0x40, ++ 0x20, 0x26, 0x17, 0x00, 0x6F, 0x26, 0x17, 0x00, 0x5C, 0x60, 0x17, 0x00, ++ 0x98, 0x84, 0x15, 0x00, 0x70, 0x26, 0x17, 0x00, 0xD8, 0x84, 0x15, 0x00, ++ 0x74, 0x26, 0x17, 0x00, 0x6E, 0x26, 0x17, 0x00, 0x50, 0x28, 0x17, 0x00, ++ 0x3B, 0x78, 0x04, 0x2B, 0x02, 0xD0, 0x2B, 0x8A, 0x00, 0x2B, 0x9B, 0xD1, ++ 0x2B, 0x7B, 0x03, 0xF0, 0x1F, 0x03, 0x02, 0x2B, 0xD8, 0xD1, 0xEB, 0x89, ++ 0x00, 0x2B, 0xD5, 0xD1, 0x28, 0x8A, 0x00, 0xF0, 0x0F, 0x01, 0xC0, 0xF3, ++ 0xC0, 0x10, 0xFF, 0xF7, 0xBF, 0xFB, 0x07, 0x23, 0x04, 0x2E, 0x2B, 0x70, ++ 0x00, 0xF0, 0x95, 0x81, 0xFF, 0xF7, 0xE6, 0xF9, 0xE7, 0xE6, 0xA9, 0x4B, ++ 0xD3, 0xF8, 0xE0, 0x34, 0x98, 0x47, 0x04, 0x46, 0x04, 0x2E, 0x5A, 0xD0, ++ 0x00, 0x2C, 0x7F, 0xF4, 0x59, 0xAF, 0x60, 0xE7, 0xA4, 0x4B, 0x6B, 0x60, ++ 0x02, 0x22, 0x04, 0x23, 0x2A, 0x81, 0x2B, 0x70, 0x04, 0x2E, 0x3F, 0xF4, ++ 0x4A, 0xAF, 0x29, 0x89, 0x68, 0x68, 0xFF, 0xF7, 0x43, 0xFA, 0xCE, 0xE6, ++ 0xE8, 0x89, 0x03, 0x0A, 0x01, 0x3B, 0x01, 0x0A, 0x0E, 0x2B, 0x3F, 0xF6, ++ 0x62, 0xAF, 0x01, 0xA2, 0x52, 0xF8, 0x23, 0xF0, 0xC1, 0x97, 0x12, 0x00, ++ 0x05, 0x98, 0x12, 0x00, 0xF1, 0x97, 0x12, 0x00, 0xFF, 0x95, 0x12, 0x00, ++ 0xFF, 0x95, 0x12, 0x00, 0x65, 0x98, 0x12, 0x00, 0xDB, 0x95, 0x12, 0x00, ++ 0xDB, 0x95, 0x12, 0x00, 0xDB, 0x95, 0x12, 0x00, 0xDB, 0x95, 0x12, 0x00, ++ 0xDB, 0x95, 0x12, 0x00, 0xDB, 0x95, 0x12, 0x00, 0xDB, 0x95, 0x12, 0x00, ++ 0xDB, 0x95, 0x12, 0x00, 0x45, 0x98, 0x12, 0x00, 0xA3, 0x69, 0x00, 0x2B, ++ 0x3F, 0xF4, 0x40, 0xAF, 0xE9, 0x89, 0x28, 0x8A, 0x98, 0x47, 0x00, 0x28, ++ 0x3F, 0xF4, 0x3A, 0xAF, 0x85, 0x4A, 0x86, 0x4B, 0x29, 0x8A, 0x11, 0x80, ++ 0xEA, 0x89, 0x1A, 0x70, 0x07, 0x23, 0x2B, 0x70, 0x06, 0xE7, 0x3B, 0x78, ++ 0x04, 0x2B, 0xDA, 0xB2, 0x7F, 0xF4, 0x2C, 0xAF, 0x7E, 0x4B, 0x7F, 0x49, ++ 0x18, 0x88, 0x2A, 0x70, 0x01, 0x23, 0x28, 0x82, 0x69, 0x60, 0x2B, 0x81, ++ 0xAE, 0xE7, 0x3B, 0x78, 0x04, 0x2B, 0xA1, 0xD0, 0xFF, 0xF7, 0xE4, 0xF9, ++ 0x00, 0x2C, 0x7F, 0xF4, 0xF9, 0xAE, 0x00, 0xE7, 0x01, 0x46, 0xFF, 0xF7, ++ 0x0B, 0xFB, 0x00, 0x28, 0x00, 0xF0, 0x05, 0x81, 0x74, 0x4B, 0x01, 0x22, ++ 0x1A, 0x80, 0x3A, 0xE7, 0x23, 0x68, 0x01, 0x20, 0x98, 0x47, 0x00, 0x28, ++ 0x3F, 0xF4, 0x0A, 0xAF, 0x03, 0x78, 0x12, 0x2B, 0x7F, 0xF4, 0x06, 0xAF, ++ 0x42, 0x78, 0x01, 0x2A, 0x7F, 0xF4, 0x02, 0xAF, 0x2B, 0x81, 0x68, 0x60, ++ 0x6B, 0x8A, 0x2A, 0x89, 0x9A, 0x42, 0x88, 0xBF, 0x2B, 0x81, 0x04, 0x23, ++ 0x2B, 0x70, 0x83, 0xE7, 0xA3, 0x68, 0xC0, 0xB2, 0x98, 0x47, 0x68, 0x60, ++ 0x00, 0x28, 0x3F, 0xF4, 0xF1, 0xAE, 0x03, 0x78, 0x2B, 0x81, 0xED, 0xE7, ++ 0x63, 0x68, 0x00, 0x20, 0x98, 0x47, 0x00, 0x28, 0x3F, 0xF4, 0xE8, 0xAE, ++ 0x03, 0x78, 0x09, 0x2B, 0x7F, 0xF4, 0xE4, 0xAE, 0x43, 0x78, 0x02, 0x2B, ++ 0x7F, 0xF4, 0xE0, 0xAE, 0xC2, 0x78, 0x83, 0x78, 0x68, 0x60, 0x43, 0xEA, ++ 0x02, 0x23, 0x2B, 0x81, 0xC3, 0x79, 0x58, 0x4A, 0x13, 0xF0, 0x40, 0x0F, ++ 0x13, 0x78, 0x14, 0xBF, 0x43, 0xF0, 0x01, 0x03, 0x23, 0xF0, 0x01, 0x03, ++ 0x13, 0x70, 0xCD, 0xE7, 0x23, 0x68, 0x0F, 0x20, 0x98, 0x47, 0x00, 0x28, ++ 0x3F, 0xF4, 0xC8, 0xAE, 0x03, 0x78, 0x05, 0x2B, 0x7F, 0xF4, 0xC4, 0xAE, ++ 0x43, 0x78, 0x0F, 0x2B, 0x7F, 0xF4, 0xC0, 0xAE, 0x83, 0x78, 0xBB, 0xE7, ++ 0x23, 0x68, 0x06, 0x20, 0x98, 0x47, 0x00, 0x28, 0x3F, 0xF4, 0xB8, 0xAE, ++ 0x03, 0x78, 0x0A, 0x2B, 0x7F, 0xF4, 0xB4, 0xAE, 0x42, 0x78, 0x06, 0x2A, ++ 0x7F, 0xF4, 0xB0, 0xAE, 0xAC, 0xE7, 0x2B, 0x78, 0x00, 0x2B, 0x51, 0xD1, ++ 0x01, 0x23, 0x2B, 0x70, 0xF8, 0xBD, 0x00, 0x21, 0x01, 0x20, 0xFF, 0xF7, ++ 0xB3, 0xFA, 0x84, 0xE5, 0x68, 0x89, 0x2B, 0x89, 0x36, 0x88, 0x6A, 0x68, ++ 0x3C, 0x49, 0x1B, 0x1A, 0xC6, 0xF1, 0x40, 0x06, 0x9B, 0xB2, 0x9E, 0x42, ++ 0xA8, 0xBF, 0x1E, 0x46, 0x10, 0x44, 0x09, 0x68, 0xB2, 0xB2, 0x2D, 0xF0, ++ 0x07, 0xFC, 0x6A, 0x89, 0x2B, 0x89, 0x16, 0x44, 0xB6, 0xB2, 0xB3, 0x42, ++ 0x6E, 0x81, 0x7F, 0xF4, 0x11, 0xAE, 0x33, 0x4B, 0x1B, 0x69, 0x0B, 0xB1, ++ 0x28, 0x46, 0x98, 0x47, 0xA0, 0x06, 0x35, 0xD4, 0x06, 0x23, 0x2B, 0x70, ++ 0xF8, 0xBD, 0x29, 0x89, 0x6A, 0x89, 0x88, 0x1A, 0x80, 0xB2, 0x30, 0xB9, ++ 0x05, 0x23, 0x2B, 0x70, 0xF8, 0xBD, 0x2B, 0x48, 0xFC, 0xF7, 0x00, 0xFD, ++ 0x88, 0xE5, 0x40, 0x28, 0x22, 0xD0, 0x40, 0x28, 0x28, 0xBF, 0x40, 0x20, ++ 0x00, 0x26, 0x02, 0x44, 0x92, 0xB2, 0x91, 0x42, 0x6A, 0x81, 0x29, 0xD3, ++ 0x89, 0x1A, 0x89, 0xB2, 0x40, 0x29, 0x0F, 0xD8, 0x79, 0xB9, 0x66, 0xBB, ++ 0x21, 0x4A, 0x05, 0x23, 0x2B, 0x70, 0xD2, 0xF8, 0x10, 0x38, 0x43, 0xF0, ++ 0x10, 0x03, 0xC2, 0xF8, 0x10, 0x38, 0xF8, 0xBD, 0x01, 0x20, 0xFF, 0xF7, ++ 0x65, 0xFA, 0xA9, 0xE7, 0x40, 0x21, 0x68, 0x68, 0x10, 0x44, 0xFF, 0xF7, ++ 0x27, 0xF9, 0x98, 0xE5, 0x01, 0x26, 0xDE, 0xE7, 0xFF, 0xF7, 0x8E, 0xF8, ++ 0x15, 0x4A, 0x07, 0x23, 0x2B, 0x70, 0xD2, 0xF8, 0x14, 0x38, 0x43, 0xF0, ++ 0x10, 0x03, 0xC2, 0xF8, 0x14, 0x38, 0xFF, 0xF7, 0xA1, 0xF8, 0x8A, 0xE5, ++ 0x10, 0x48, 0xFC, 0xF7, 0xC7, 0xFC, 0x29, 0x89, 0x6A, 0x89, 0xCF, 0xE7, ++ 0x03, 0x23, 0x3B, 0x70, 0x0C, 0xE6, 0x08, 0x46, 0xFF, 0xF7, 0x0A, 0xF9, ++ 0x7B, 0xE5, 0x00, 0xBF, 0x88, 0x1A, 0x17, 0x00, 0x6C, 0x26, 0x17, 0x00, ++ 0x6A, 0x26, 0x17, 0x00, 0x68, 0x26, 0x17, 0x00, 0x50, 0x28, 0x17, 0x00, ++ 0x6E, 0x26, 0x17, 0x00, 0x60, 0x60, 0x17, 0x00, 0x20, 0x26, 0x17, 0x00, ++ 0xB4, 0x84, 0x15, 0x00, 0x00, 0x00, 0x20, 0x40, 0xF0, 0x84, 0x15, 0x00, ++ 0x2B, 0x7B, 0x03, 0xF0, 0x1F, 0x03, 0x01, 0x2B, 0x07, 0xD0, 0x02, 0x2B, ++ 0x7F, 0xF4, 0x39, 0xAE, 0x28, 0x8A, 0x00, 0xF0, 0x0F, 0x01, 0x04, 0x29, ++ 0x2A, 0xD9, 0x17, 0x4B, 0x00, 0x22, 0x1A, 0x80, 0x35, 0xE6, 0xE8, 0x89, ++ 0x02, 0x28, 0x19, 0xD0, 0x00, 0xF1, 0xFF, 0x3C, 0x07, 0x23, 0xDC, 0xF1, ++ 0x00, 0x04, 0x44, 0xEB, 0x0C, 0x04, 0x2B, 0x70, 0x7E, 0xE6, 0x28, 0x8A, ++ 0x00, 0xF0, 0x0F, 0x01, 0xC0, 0xF3, 0xC0, 0x10, 0xFF, 0xF7, 0x18, 0xFA, ++ 0x07, 0x23, 0x04, 0x2E, 0x2B, 0x70, 0x7F, 0xF4, 0x6B, 0xAE, 0x3B, 0x78, ++ 0x04, 0x2B, 0x3F, 0xF4, 0x67, 0xAE, 0xC9, 0xE5, 0x2B, 0x8A, 0x07, 0x49, ++ 0x1B, 0x0A, 0x07, 0x22, 0x04, 0x2E, 0x0B, 0x70, 0x2A, 0x70, 0x7F, 0xF4, ++ 0x5D, 0xAE, 0xF0, 0xE7, 0xC0, 0xF3, 0xC0, 0x10, 0xC7, 0xE6, 0x00, 0xBF, ++ 0x50, 0x28, 0x17, 0x00, 0x70, 0x26, 0x17, 0x00, 0x2D, 0xE9, 0xF8, 0x43, ++ 0xB4, 0x4B, 0xB5, 0x4D, 0xD3, 0xF8, 0x00, 0x38, 0x13, 0xF4, 0xFE, 0x6F, ++ 0x03, 0xD0, 0x2B, 0x78, 0x04, 0x2B, 0x00, 0xF0, 0x8F, 0x81, 0xAF, 0x4C, ++ 0xB0, 0x4A, 0xB1, 0x48, 0x00, 0x21, 0x02, 0x23, 0x2B, 0x70, 0x11, 0x70, ++ 0x1A, 0xF0, 0x1A, 0xFE, 0xD4, 0xF8, 0x00, 0x3E, 0x23, 0xF0, 0x01, 0x03, ++ 0xC4, 0xF8, 0x00, 0x3E, 0xD4, 0xF8, 0x04, 0x38, 0x23, 0xF0, 0x01, 0x03, ++ 0xC4, 0xF8, 0x04, 0x38, 0xFF, 0xF7, 0x7E, 0xF8, 0xA3, 0x69, 0x1D, 0x06, ++ 0x03, 0xD5, 0xA3, 0x69, 0x23, 0xF0, 0x80, 0x03, 0xA3, 0x61, 0xA0, 0x4B, ++ 0xD3, 0xF8, 0x04, 0x28, 0x42, 0xF4, 0x00, 0x72, 0xC3, 0xF8, 0x04, 0x28, ++ 0x5A, 0x69, 0x14, 0x06, 0xFC, 0xD5, 0x01, 0x23, 0x01, 0x2B, 0x9E, 0x4C, ++ 0x9E, 0x4D, 0x9F, 0x4A, 0x9F, 0x4F, 0x4F, 0xF0, 0x02, 0x0C, 0x1C, 0xD0, ++ 0x4F, 0xEA, 0x43, 0x1E, 0x5E, 0xF8, 0x02, 0x10, 0x11, 0xF0, 0x80, 0x2F, ++ 0x10, 0xD0, 0x5E, 0xF8, 0x02, 0x00, 0x00, 0x29, 0x40, 0xEA, 0x05, 0x00, ++ 0x4E, 0xF8, 0x02, 0x00, 0xC0, 0xF2, 0x0F, 0x81, 0x08, 0x04, 0x05, 0xD4, ++ 0x5E, 0xF8, 0x02, 0x10, 0x21, 0xF4, 0x00, 0x41, 0x4E, 0xF8, 0x02, 0x10, ++ 0x05, 0x2B, 0x0A, 0xD0, 0x01, 0x33, 0x01, 0x2B, 0xE2, 0xD1, 0x21, 0x68, ++ 0x11, 0xF0, 0x80, 0x2F, 0xF8, 0xD0, 0x21, 0x68, 0x29, 0x43, 0x21, 0x60, ++ 0xF4, 0xE7, 0x84, 0x4B, 0xD3, 0xF8, 0x04, 0x28, 0x42, 0xF4, 0x80, 0x62, ++ 0xC3, 0xF8, 0x04, 0x28, 0xD3, 0xF8, 0x04, 0x28, 0x42, 0xF0, 0x80, 0x02, ++ 0xC3, 0xF8, 0x04, 0x28, 0x5A, 0x69, 0x51, 0x06, 0xFC, 0xD5, 0x01, 0x23, ++ 0x01, 0x2B, 0x83, 0x4F, 0xDF, 0xF8, 0x40, 0x82, 0xDF, 0xF8, 0xF8, 0xC1, ++ 0x81, 0x4D, 0xDF, 0xF8, 0x3C, 0xE2, 0x4F, 0xF0, 0x40, 0x06, 0x4F, 0xF0, ++ 0x02, 0x09, 0x19, 0xD0, 0x5A, 0x01, 0x05, 0xEB, 0x43, 0x10, 0x51, 0x59, ++ 0x11, 0xF0, 0x80, 0x2F, 0x0D, 0xD0, 0x72, 0x44, 0x16, 0x60, 0x04, 0x68, ++ 0x00, 0x29, 0x44, 0xEA, 0x0C, 0x04, 0x04, 0x60, 0x11, 0xDB, 0x0A, 0x04, ++ 0x03, 0xD4, 0x02, 0x68, 0x22, 0xF4, 0x00, 0x42, 0x02, 0x60, 0x05, 0x2B, ++ 0x1A, 0xD0, 0x01, 0x33, 0x01, 0x2B, 0xE5, 0xD1, 0x39, 0x68, 0x11, 0xF0, ++ 0x80, 0x2F, 0xF8, 0xD0, 0x42, 0x46, 0x38, 0x46, 0xE6, 0xE7, 0x8C, 0x03, ++ 0x09, 0xD5, 0xC2, 0xF8, 0x00, 0x90, 0x04, 0x68, 0x44, 0xF0, 0x80, 0x44, ++ 0x04, 0x60, 0x14, 0x68, 0xA4, 0x07, 0xFC, 0xD5, 0xE1, 0xE7, 0x14, 0x68, ++ 0x64, 0x06, 0xFC, 0xD5, 0x16, 0x60, 0xF0, 0xE7, 0x5B, 0x4B, 0x4F, 0xF4, ++ 0x86, 0x62, 0x1A, 0x61, 0x1A, 0x69, 0x12, 0xF0, 0x30, 0x0F, 0xFB, 0xD1, ++ 0xD3, 0xF8, 0x04, 0x28, 0x4F, 0xF0, 0x01, 0x14, 0x42, 0xF4, 0x80, 0x72, ++ 0x29, 0x20, 0x09, 0x21, 0xC3, 0xF8, 0x04, 0x28, 0xC3, 0xF8, 0x1C, 0x48, ++ 0xC3, 0xF8, 0x14, 0x08, 0xC3, 0xF8, 0x10, 0x18, 0x9A, 0x69, 0x42, 0xF4, ++ 0x40, 0x22, 0x9A, 0x61, 0x9A, 0x6C, 0x14, 0x03, 0x4C, 0xD4, 0x4C, 0x4D, ++ 0x55, 0x4B, 0xD5, 0xF8, 0x00, 0x28, 0x55, 0x48, 0x00, 0x24, 0x22, 0xF4, ++ 0xFE, 0x62, 0xC5, 0xF8, 0x00, 0x28, 0x21, 0x46, 0xC3, 0xE9, 0x01, 0x44, ++ 0x40, 0x22, 0x1C, 0x70, 0xF6, 0xF7, 0xDE, 0xFA, 0x21, 0x46, 0x40, 0x22, ++ 0x4E, 0x48, 0xF6, 0xF7, 0xD9, 0xFA, 0x4E, 0x4A, 0x4E, 0x4B, 0x11, 0x68, ++ 0x4E, 0x4A, 0x1B, 0x68, 0x12, 0x68, 0x59, 0x60, 0xC5, 0xF8, 0x14, 0x3B, ++ 0xD1, 0x78, 0x4C, 0x4B, 0x4C, 0x48, 0x1F, 0x68, 0x4C, 0x4B, 0x06, 0x6A, ++ 0x18, 0x68, 0xD3, 0xF8, 0x04, 0xC0, 0x41, 0xF0, 0xC0, 0x01, 0xD1, 0x70, ++ 0xF9, 0x78, 0x41, 0xF0, 0xC0, 0x01, 0xF9, 0x70, 0xC1, 0x78, 0x41, 0xF0, ++ 0xC0, 0x01, 0xC1, 0x70, 0x9C, 0xF8, 0x03, 0x10, 0xD3, 0xE9, 0x02, 0x70, ++ 0x41, 0xF0, 0xC0, 0x03, 0x8C, 0xF8, 0x03, 0x30, 0xFB, 0x78, 0x43, 0xF0, ++ 0xC0, 0x03, 0xFB, 0x70, 0xC3, 0x78, 0x43, 0xF0, 0xC0, 0x03, 0xC3, 0x70, ++ 0xC5, 0xF8, 0x14, 0x29, 0x0E, 0xB1, 0x20, 0x46, 0xB0, 0x47, 0xBD, 0xE8, ++ 0xF8, 0x43, 0x3A, 0x48, 0x1A, 0xF0, 0x10, 0xBD, 0x39, 0x49, 0x3A, 0x4C, ++ 0x24, 0x4A, 0x40, 0xF2, 0x17, 0x15, 0x5D, 0x62, 0x4F, 0xF4, 0x9C, 0x70, ++ 0x9C, 0x62, 0x08, 0x80, 0xD3, 0xF8, 0x04, 0x18, 0x41, 0xF0, 0x80, 0x01, ++ 0xC3, 0xF8, 0x04, 0x18, 0x53, 0x69, 0x58, 0x06, 0xFC, 0xD5, 0x1C, 0x49, ++ 0x0B, 0x69, 0x00, 0x2B, 0xFC, 0xDA, 0x4F, 0xF4, 0x84, 0x63, 0x19, 0x4A, ++ 0x0B, 0x61, 0x13, 0x69, 0x99, 0x06, 0xFC, 0xD4, 0xD2, 0xF8, 0x04, 0x38, ++ 0x15, 0x49, 0x43, 0xF4, 0x80, 0x73, 0xC2, 0xF8, 0x04, 0x38, 0xD2, 0xF8, ++ 0x04, 0x38, 0x43, 0xF4, 0x00, 0x73, 0xC2, 0xF8, 0x04, 0x38, 0x4B, 0x69, ++ 0x1A, 0x06, 0xFC, 0xD5, 0x0B, 0x69, 0x0E, 0x4A, 0x43, 0xF0, 0x10, 0x03, ++ 0x0B, 0x61, 0x13, 0x69, 0xDB, 0x06, 0xFC, 0xD4, 0xD2, 0xF8, 0x04, 0x38, ++ 0x43, 0xF4, 0x80, 0x63, 0xC2, 0xF8, 0x04, 0x38, 0x75, 0xE7, 0x4E, 0xF8, ++ 0x07, 0xC0, 0x5E, 0xF8, 0x02, 0x00, 0x40, 0xF0, 0x80, 0x40, 0x4E, 0xF8, ++ 0x02, 0x00, 0x0E, 0xEB, 0x07, 0x06, 0x30, 0x68, 0x80, 0x07, 0xFC, 0xD5, ++ 0xE2, 0xE6, 0x00, 0xBF, 0x00, 0x00, 0x20, 0x40, 0x6F, 0x26, 0x17, 0x00, ++ 0x6E, 0x26, 0x17, 0x00, 0x20, 0x85, 0x15, 0x00, 0x00, 0x0B, 0x20, 0x40, ++ 0x00, 0x80, 0x00, 0x08, 0xE0, 0x0A, 0x20, 0x40, 0xE8, 0x0A, 0x20, 0x40, ++ 0x00, 0x09, 0x20, 0x40, 0xE0, 0x08, 0x20, 0x40, 0xB4, 0x27, 0x17, 0x00, ++ 0x08, 0x28, 0x17, 0x00, 0xC8, 0x27, 0x17, 0x00, 0x60, 0x60, 0x17, 0x00, ++ 0x5C, 0x60, 0x17, 0x00, 0x40, 0x60, 0x17, 0x00, 0x54, 0x60, 0x17, 0x00, ++ 0x20, 0x26, 0x17, 0x00, 0x44, 0x60, 0x17, 0x00, 0x28, 0x85, 0x15, 0x00, ++ 0x48, 0x28, 0x17, 0x00, 0x17, 0x01, 0x21, 0x00, 0x08, 0x09, 0x20, 0x40, ++ 0xE8, 0x08, 0x20, 0x40, 0x05, 0x48, 0x1E, 0x21, 0x1A, 0xF0, 0x90, 0xFC, ++ 0x4F, 0xF4, 0xF0, 0x42, 0x01, 0x21, 0x40, 0xF2, 0x1E, 0x40, 0x18, 0xF0, ++ 0x7F, 0xFC, 0x64, 0xE6, 0x0C, 0x85, 0x15, 0x00, 0x08, 0xB5, 0x04, 0x49, ++ 0x04, 0x48, 0x1A, 0xF0, 0x81, 0xFC, 0x04, 0x4B, 0x01, 0x22, 0x1A, 0x70, ++ 0x08, 0xBD, 0x00, 0xBF, 0x54, 0x85, 0x15, 0x00, 0xCC, 0xB5, 0x15, 0x00, ++ 0x52, 0x28, 0x17, 0x00, 0x01, 0x4B, 0x18, 0x78, 0x70, 0x47, 0x00, 0xBF, ++ 0x52, 0x28, 0x17, 0x00, 0x08, 0xB5, 0x07, 0x48, 0x1A, 0xF0, 0x6C, 0xFC, ++ 0x06, 0x4B, 0x07, 0x4A, 0x00, 0x21, 0x19, 0x70, 0xD2, 0xF8, 0x00, 0x3E, ++ 0x23, 0xF0, 0x01, 0x03, 0xC2, 0xF8, 0x00, 0x3E, 0x08, 0xBD, 0x00, 0xBF, ++ 0x30, 0x85, 0x15, 0x00, 0x52, 0x28, 0x17, 0x00, 0x00, 0x00, 0x20, 0x40, ++ 0x38, 0xB5, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, ++ 0x1A, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x1A, 0x4C, 0x1A, 0x4D, 0x23, 0x68, ++ 0x2A, 0x78, 0x01, 0x33, 0x23, 0x60, 0x1A, 0xB1, 0x18, 0x4A, 0x12, 0x78, ++ 0x04, 0x2A, 0x08, 0xD0, 0x33, 0xB1, 0x13, 0x4A, 0x01, 0x3B, 0x12, 0x68, ++ 0x23, 0x60, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0x38, 0xBD, 0x13, 0x4A, ++ 0x13, 0x49, 0xD2, 0xF8, 0x04, 0x38, 0x43, 0xF0, 0x01, 0x03, 0xC2, 0xF8, ++ 0x04, 0x38, 0x0A, 0x69, 0x02, 0xF5, 0x0C, 0x52, 0x28, 0x32, 0x0B, 0x69, ++ 0xD3, 0x1A, 0x00, 0x2B, 0xFB, 0xDA, 0x0B, 0x4A, 0x0C, 0x48, 0xD2, 0xF8, ++ 0x04, 0x38, 0x23, 0xF0, 0x01, 0x03, 0xC2, 0xF8, 0x04, 0x38, 0x1A, 0xF0, ++ 0x23, 0xFC, 0x00, 0x22, 0x23, 0x68, 0x2A, 0x70, 0xD8, 0xE7, 0x00, 0xBF, ++ 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0x52, 0x28, 0x17, 0x00, ++ 0x6F, 0x26, 0x17, 0x00, 0x00, 0x00, 0x20, 0x40, 0x00, 0x10, 0x50, 0x40, ++ 0x3C, 0x85, 0x15, 0x00, 0x38, 0xB5, 0x04, 0x46, 0x0D, 0x46, 0xFF, 0xF7, ++ 0xB1, 0xFF, 0x15, 0x4B, 0x1B, 0x78, 0x04, 0x2B, 0x20, 0xD1, 0x62, 0x1E, ++ 0xD3, 0xB2, 0x04, 0x2B, 0x1E, 0xD8, 0x60, 0x01, 0x00, 0xF1, 0x80, 0x40, ++ 0x00, 0xF5, 0x00, 0x10, 0xD0, 0xF8, 0x00, 0x39, 0x1B, 0x04, 0x17, 0xD5, ++ 0x0D, 0x49, 0x53, 0x01, 0x03, 0xF1, 0x80, 0x43, 0x01, 0xEB, 0x02, 0x12, ++ 0x03, 0xF5, 0x00, 0x13, 0x01, 0x21, 0xD1, 0x72, 0xC3, 0xF8, 0x34, 0x59, ++ 0xD0, 0xF8, 0x00, 0x39, 0x43, 0xF0, 0x04, 0x43, 0xC0, 0xF8, 0x00, 0x39, ++ 0x00, 0x20, 0x38, 0xBD, 0x01, 0x20, 0x38, 0xBD, 0x02, 0x20, 0x38, 0xBD, ++ 0x05, 0x20, 0x38, 0xBD, 0x6F, 0x26, 0x17, 0x00, 0xC8, 0x27, 0x17, 0x00, ++ 0x93, 0x4B, 0x5A, 0x69, 0x2D, 0xE9, 0xF0, 0x4F, 0x5A, 0x61, 0x9C, 0x69, ++ 0x14, 0x40, 0xE1, 0x04, 0x85, 0xB0, 0x0A, 0xD5, 0x8F, 0x4B, 0xD3, 0xF8, ++ 0xDC, 0x34, 0x98, 0x47, 0x14, 0xF4, 0x00, 0x5A, 0x40, 0xF0, 0xAB, 0x80, ++ 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xDF, 0xF8, 0x44, 0xA2, 0xA2, 0x04, ++ 0x04, 0xEA, 0x0A, 0x0A, 0x04, 0xF4, 0x80, 0x25, 0x04, 0xF4, 0x00, 0x29, ++ 0x04, 0xF4, 0x00, 0x6B, 0x00, 0xF1, 0x9F, 0x80, 0x00, 0x2D, 0x42, 0xD0, ++ 0x81, 0x4D, 0x83, 0x4E, 0xD5, 0xF8, 0x18, 0x28, 0xD5, 0xF8, 0x1C, 0x38, ++ 0x00, 0x24, 0x02, 0xEA, 0x03, 0x08, 0x01, 0x20, 0x00, 0xFA, 0x04, 0xF3, ++ 0x13, 0xEA, 0x08, 0x0F, 0xE7, 0xB2, 0x2D, 0xD0, 0x00, 0x2C, 0x00, 0xF0, ++ 0xA0, 0x80, 0x63, 0x1E, 0x05, 0xEB, 0x43, 0x13, 0xD3, 0xF8, 0x28, 0x29, ++ 0xC3, 0xF8, 0x28, 0x29, 0xD5, 0xF8, 0x10, 0x18, 0x11, 0x40, 0x11, 0xF0, ++ 0x09, 0x0F, 0x74, 0xD0, 0x16, 0xF8, 0x05, 0x3C, 0xD3, 0xB1, 0x56, 0xF8, ++ 0x0C, 0x3C, 0x01, 0x93, 0xD2, 0x43, 0x56, 0xF8, 0x10, 0x3C, 0x02, 0x93, ++ 0x12, 0xF0, 0x01, 0x03, 0x00, 0x93, 0x40, 0xF0, 0xB6, 0x80, 0x10, 0x22, ++ 0x00, 0x21, 0xA6, 0xF1, 0x10, 0x00, 0xF6, 0xF7, 0x15, 0xF9, 0x6A, 0x4B, ++ 0x03, 0xEB, 0x84, 0x03, 0x1B, 0x6B, 0x1B, 0xB1, 0xDD, 0xE9, 0x00, 0x21, ++ 0x02, 0x98, 0x98, 0x47, 0x04, 0x2F, 0x02, 0xD0, 0x01, 0x34, 0x10, 0x36, ++ 0xC5, 0xE7, 0xB9, 0xF1, 0x00, 0x0F, 0x3C, 0xD0, 0x5E, 0x4D, 0x62, 0x4E, ++ 0xD5, 0xF8, 0x18, 0x78, 0xD5, 0xF8, 0x1C, 0x38, 0xDF, 0xF8, 0x90, 0x81, ++ 0xDF, 0xF8, 0x74, 0x91, 0x1F, 0x40, 0x00, 0x24, 0x4F, 0xF4, 0x80, 0x33, ++ 0xA3, 0x40, 0x3B, 0x42, 0x0C, 0xD0, 0xC4, 0xB1, 0x63, 0x1E, 0x05, 0xEB, ++ 0x43, 0x13, 0xD3, 0xF8, 0x28, 0x2B, 0xC3, 0xF8, 0x28, 0x2B, 0xD5, 0xF8, ++ 0x14, 0x38, 0x13, 0x40, 0xDB, 0x07, 0x5F, 0xD4, 0xE3, 0xB2, 0x04, 0x2B, ++ 0x1B, 0xD0, 0x01, 0x34, 0x4F, 0xF4, 0x80, 0x33, 0xA3, 0x40, 0x3B, 0x42, ++ 0x06, 0xF1, 0x10, 0x06, 0xF4, 0xD0, 0x00, 0x2C, 0xE6, 0xD1, 0xD5, 0xF8, ++ 0x08, 0x1B, 0xC5, 0xF8, 0x08, 0x1B, 0xD5, 0xF8, 0x14, 0x38, 0x0B, 0x40, ++ 0xDA, 0x06, 0x7B, 0xD4, 0x13, 0xF0, 0x29, 0x0F, 0xE9, 0xD0, 0x44, 0x4B, ++ 0x20, 0x46, 0xD3, 0xF8, 0x00, 0x31, 0x98, 0x47, 0xE3, 0xE7, 0xBB, 0xF1, ++ 0x00, 0x0F, 0x03, 0xD0, 0x3F, 0x4B, 0xD3, 0xF8, 0x8C, 0x34, 0x98, 0x47, ++ 0xBA, 0xF1, 0x00, 0x0F, 0xBF, 0xF6, 0x60, 0xAF, 0x3B, 0x4B, 0xD3, 0xF8, ++ 0x90, 0x34, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x4F, 0x18, 0x47, 0x3C, 0x48, ++ 0xFC, 0xF7, 0x56, 0xF9, 0xA4, 0xE7, 0x4F, 0xF0, 0x00, 0x0B, 0xD9, 0x46, ++ 0x5D, 0x46, 0x33, 0x4B, 0xD3, 0xF8, 0x08, 0x38, 0x13, 0xF0, 0x06, 0x0F, ++ 0xC3, 0xF3, 0x47, 0x02, 0x04, 0xD0, 0xD3, 0x07, 0x02, 0xD5, 0x34, 0x4B, ++ 0x01, 0x22, 0x1A, 0x60, 0x2C, 0x4B, 0x33, 0x4A, 0xC3, 0xF8, 0x00, 0x29, ++ 0xC3, 0xF8, 0x00, 0x2B, 0xFE, 0xF7, 0xF4, 0xFC, 0x4A, 0xE7, 0xD5, 0xF8, ++ 0x08, 0x19, 0xC5, 0xF8, 0x08, 0x19, 0xD5, 0xF8, 0x10, 0x38, 0x0B, 0x40, ++ 0x13, 0xF0, 0x18, 0x0F, 0x2B, 0xD1, 0xDF, 0x07, 0x80, 0xD5, 0x23, 0x4B, ++ 0xD3, 0xF8, 0x00, 0x31, 0x98, 0x47, 0x7B, 0xE7, 0x16, 0xF8, 0x08, 0x3C, ++ 0x00, 0x2B, 0x9B, 0xD0, 0x58, 0xF8, 0x24, 0x30, 0x56, 0xF8, 0x0C, 0x1C, ++ 0x1B, 0x88, 0x02, 0x93, 0x30, 0x46, 0xA3, 0x00, 0x50, 0xF8, 0x10, 0x2D, ++ 0x03, 0x92, 0x01, 0x91, 0x10, 0x22, 0x00, 0x21, 0x00, 0x93, 0xF6, 0xF7, ++ 0x71, 0xF8, 0x00, 0x9B, 0x4B, 0x44, 0x1B, 0x6A, 0x00, 0x2B, 0x85, 0xD0, ++ 0xDD, 0xE9, 0x01, 0x01, 0x00, 0x22, 0x41, 0x1A, 0x03, 0x98, 0x98, 0x47, ++ 0x7E, 0xE7, 0x39, 0x46, 0xFE, 0xF7, 0x8A, 0xFE, 0x45, 0xE7, 0xD5, 0xF8, ++ 0x10, 0x38, 0x23, 0xF0, 0x10, 0x03, 0xC5, 0xF8, 0x10, 0x38, 0x22, 0x46, ++ 0x4F, 0xF4, 0x00, 0x11, 0x20, 0x46, 0xFE, 0xF7, 0xE9, 0xFD, 0x49, 0xE7, ++ 0xD5, 0xF8, 0x14, 0x38, 0x23, 0xF0, 0x10, 0x03, 0xC5, 0xF8, 0x14, 0x38, ++ 0x22, 0x46, 0x4F, 0xF4, 0x00, 0x11, 0x20, 0x46, 0xFE, 0xF7, 0x80, 0xFD, ++ 0x63, 0xE7, 0x00, 0xBF, 0x00, 0x00, 0x20, 0x40, 0x88, 0x1A, 0x17, 0x00, ++ 0xC8, 0x27, 0x17, 0x00, 0x20, 0x26, 0x17, 0x00, 0x08, 0x28, 0x17, 0x00, ++ 0x48, 0x85, 0x15, 0x00, 0x4C, 0x28, 0x17, 0x00, 0x00, 0x80, 0x00, 0x08, ++ 0x00, 0x3C, 0x0C, 0x88, 0x40, 0x60, 0x17, 0x00, 0x38, 0xB9, 0x0C, 0x4A, ++ 0x0C, 0x4B, 0x10, 0x70, 0x18, 0x70, 0x0C, 0x4B, 0x1B, 0x68, 0x5B, 0xB1, ++ 0x18, 0x47, 0x01, 0x28, 0x09, 0xD0, 0x09, 0x4B, 0x02, 0x38, 0x1B, 0x68, ++ 0x01, 0x28, 0x94, 0xBF, 0x02, 0x20, 0x03, 0x20, 0x00, 0x2B, 0xF3, 0xD1, ++ 0x70, 0x47, 0x05, 0x4A, 0x05, 0x4B, 0x10, 0x70, 0x18, 0x70, 0xEA, 0xE7, ++ 0x59, 0x28, 0x17, 0x00, 0x5A, 0x28, 0x17, 0x00, 0x60, 0x28, 0x17, 0x00, ++ 0x5B, 0x28, 0x17, 0x00, 0x5C, 0x28, 0x17, 0x00, 0x00, 0x48, 0x70, 0x47, ++ 0x54, 0x86, 0x15, 0x00, 0x01, 0x28, 0x15, 0xD1, 0x08, 0xB5, 0x0B, 0x4B, ++ 0x1B, 0x68, 0x0B, 0xB1, 0x04, 0x20, 0x98, 0x47, 0x02, 0x22, 0x11, 0x46, ++ 0x4F, 0xF4, 0x00, 0x73, 0x01, 0x20, 0xFE, 0xF7, 0x65, 0xFF, 0x4F, 0xF4, ++ 0x00, 0x73, 0x02, 0x22, 0x01, 0x21, 0x00, 0x20, 0xFE, 0xF7, 0x5E, 0xFF, ++ 0x01, 0x20, 0x08, 0xBD, 0x00, 0x20, 0x70, 0x47, 0x60, 0x28, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x41, 0x58, 0x4E, 0xDF, 0xF8, 0x9C, 0xE1, 0x33, 0x88, ++ 0x57, 0x4C, 0x00, 0x2A, 0x03, 0xF1, 0x01, 0x03, 0x0C, 0xBF, 0x02, 0x25, ++ 0x03, 0x25, 0x9B, 0xB2, 0x00, 0x27, 0x33, 0x80, 0x8E, 0xF8, 0x00, 0x50, ++ 0x27, 0x70, 0x9E, 0xF8, 0x00, 0xC0, 0xBC, 0xF1, 0x02, 0x0F, 0x4C, 0xD1, ++ 0x03, 0x29, 0x04, 0x46, 0x0D, 0x46, 0x8E, 0xF8, 0x00, 0x70, 0x55, 0xD9, ++ 0x43, 0x78, 0x4C, 0x4A, 0x07, 0x78, 0x12, 0x78, 0x90, 0xF8, 0x02, 0x80, ++ 0x1B, 0x02, 0x03, 0xF4, 0x70, 0x63, 0x1F, 0x43, 0x00, 0x2A, 0x78, 0xD1, ++ 0xB8, 0xF1, 0x01, 0x0F, 0x64, 0xD0, 0xB8, 0xF1, 0x11, 0x0F, 0x55, 0xD1, ++ 0xDF, 0xF8, 0x44, 0x81, 0x98, 0xF8, 0x9D, 0x27, 0x98, 0xF8, 0x9E, 0x37, ++ 0x9A, 0x42, 0x77, 0xD2, 0x3B, 0x1D, 0xAB, 0x42, 0x02, 0xD0, 0x7B, 0x1D, ++ 0x9D, 0x42, 0x6E, 0xD1, 0x3D, 0x4B, 0xD3, 0xF8, 0x3C, 0x34, 0x98, 0x47, ++ 0x98, 0xF8, 0x9C, 0x37, 0x3B, 0x49, 0x98, 0xF8, 0x9D, 0x27, 0x01, 0x33, ++ 0xA1, 0xFB, 0x03, 0x01, 0x49, 0x09, 0x01, 0xEB, 0x81, 0x01, 0xA3, 0xEB, ++ 0xC1, 0x01, 0x08, 0xEB, 0x01, 0x15, 0x04, 0x34, 0x53, 0x1C, 0x88, 0xF8, ++ 0x9C, 0x17, 0x34, 0x48, 0xC5, 0xF8, 0x20, 0x45, 0x05, 0xF2, 0x1C, 0x51, ++ 0xC5, 0xF8, 0x24, 0x75, 0x88, 0xF8, 0x9D, 0x37, 0x19, 0xF0, 0x22, 0xF8, ++ 0x4F, 0xF4, 0x00, 0x00, 0x18, 0xF0, 0x7C, 0xFF, 0x0B, 0xE0, 0x9E, 0xF8, ++ 0x00, 0x10, 0x2C, 0x48, 0xFC, 0xF7, 0x28, 0xF8, 0x47, 0xF2, 0x30, 0x52, ++ 0x01, 0x21, 0x40, 0xF2, 0x1E, 0x40, 0x18, 0xF0, 0xE1, 0xF9, 0x01, 0x20, ++ 0xBD, 0xE8, 0xF0, 0x81, 0x31, 0x88, 0x26, 0x48, 0x89, 0xB2, 0x2A, 0x46, ++ 0xFC, 0xF7, 0x18, 0xF8, 0x24, 0x4B, 0x18, 0x68, 0x20, 0x1A, 0xFD, 0xF7, ++ 0x05, 0xF9, 0x1D, 0x4B, 0xD3, 0xF8, 0x3C, 0x34, 0x98, 0x47, 0x01, 0x20, ++ 0xBD, 0xE8, 0xF0, 0x81, 0x41, 0x46, 0x1F, 0x48, 0xFC, 0xF7, 0x08, 0xF8, ++ 0x31, 0x88, 0x1E, 0x48, 0x89, 0xB2, 0x2B, 0x46, 0x3A, 0x46, 0xFC, 0xF7, ++ 0x01, 0xF8, 0xE7, 0xE7, 0xBD, 0x42, 0x02, 0xD0, 0x7B, 0x1C, 0xAB, 0x42, ++ 0x12, 0xD1, 0x11, 0x4D, 0xD5, 0xF8, 0x3C, 0x34, 0x98, 0x47, 0x20, 0x1D, ++ 0xD5, 0xF8, 0x0C, 0x31, 0x98, 0x47, 0x40, 0x20, 0x18, 0xF0, 0x3E, 0xFF, ++ 0xCD, 0xE7, 0x0A, 0x46, 0x4F, 0xF4, 0x00, 0x70, 0x11, 0x49, 0x1A, 0xF0, ++ 0x03, 0xFA, 0x7F, 0xE7, 0x31, 0x88, 0x10, 0x48, 0xDE, 0xE7, 0x31, 0x88, ++ 0x0F, 0x48, 0xDB, 0xE7, 0x0F, 0x48, 0xFB, 0xF7, 0xDF, 0xFF, 0xC5, 0xE7, ++ 0x56, 0x28, 0x17, 0x00, 0x58, 0x28, 0x17, 0x00, 0x64, 0x28, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0xCD, 0xCC, 0xCC, 0xCC, 0xF8, 0x5F, 0x17, 0x00, ++ 0xD0, 0x85, 0x15, 0x00, 0xC0, 0x85, 0x15, 0x00, 0x80, 0x1A, 0x17, 0x00, ++ 0xB0, 0x85, 0x15, 0x00, 0x78, 0x85, 0x15, 0x00, 0x68, 0x85, 0x15, 0x00, ++ 0x70, 0x85, 0x15, 0x00, 0x84, 0x85, 0x15, 0x00, 0x98, 0x85, 0x15, 0x00, ++ 0x59, 0x28, 0x17, 0x00, 0x58, 0x58, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x41, ++ 0x00, 0x2A, 0x2A, 0x4B, 0x0C, 0xBF, 0x02, 0x21, 0x03, 0x21, 0x19, 0x70, ++ 0x19, 0x78, 0x02, 0x29, 0x3D, 0xD1, 0x27, 0x4C, 0x22, 0x78, 0x00, 0x21, ++ 0x19, 0x70, 0x52, 0xB3, 0x25, 0x4D, 0x26, 0x4F, 0xA5, 0xF1, 0x08, 0x06, ++ 0x0A, 0xE0, 0x01, 0x2A, 0x41, 0x46, 0x38, 0x46, 0x28, 0xD1, 0x13, 0x2B, ++ 0x40, 0x46, 0x01, 0xD0, 0xFD, 0xF7, 0x90, 0xF8, 0x23, 0x78, 0xD3, 0xB1, ++ 0x28, 0x46, 0x18, 0xF0, 0xCD, 0xFF, 0x42, 0x68, 0x23, 0x78, 0xD2, 0xF8, ++ 0x04, 0x80, 0x01, 0x3B, 0x01, 0x46, 0x30, 0x46, 0x23, 0x70, 0x18, 0xF0, ++ 0x7F, 0xFF, 0x98, 0xF8, 0x02, 0x30, 0x1A, 0x09, 0xE3, 0xD1, 0x17, 0x4A, ++ 0x13, 0x88, 0x10, 0x20, 0x01, 0x33, 0x13, 0x80, 0x18, 0xF0, 0xD2, 0xFE, ++ 0x23, 0x78, 0x00, 0x2B, 0xE4, 0xD1, 0x13, 0x4B, 0xD3, 0xF8, 0x44, 0x34, ++ 0x98, 0x47, 0x01, 0x20, 0xBD, 0xE8, 0xF0, 0x81, 0xFB, 0xF7, 0x78, 0xFF, ++ 0x40, 0x46, 0x20, 0x21, 0x1A, 0xF0, 0x1C, 0xFD, 0xD4, 0xE7, 0x19, 0x78, ++ 0x0C, 0x48, 0xFB, 0xF7, 0x6F, 0xFF, 0x47, 0xF2, 0x30, 0x52, 0x01, 0x21, ++ 0x40, 0xF2, 0x1E, 0x40, 0x18, 0xF0, 0x28, 0xF9, 0x01, 0x20, 0xBD, 0xE8, ++ 0xF0, 0x81, 0x00, 0xBF, 0x5A, 0x28, 0x17, 0x00, 0x64, 0x60, 0x17, 0x00, ++ 0xA8, 0x56, 0x17, 0x00, 0xF0, 0x85, 0x15, 0x00, 0x54, 0x28, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x00, 0x86, 0x15, 0x00, 0x10, 0x4B, 0x11, 0x49, ++ 0x11, 0x4A, 0x2D, 0xE9, 0xF0, 0x41, 0x05, 0x46, 0x00, 0x68, 0x18, 0x60, ++ 0xDF, 0xF8, 0x44, 0x80, 0x0E, 0x4F, 0x0F, 0x4E, 0x00, 0x23, 0x0B, 0x70, ++ 0x13, 0x70, 0x29, 0x7A, 0xD8, 0xF8, 0x08, 0x31, 0x00, 0x39, 0x18, 0xBF, ++ 0x01, 0x21, 0x38, 0x46, 0x98, 0x47, 0x04, 0x46, 0x01, 0x46, 0x30, 0x46, ++ 0x1A, 0xF0, 0x04, 0xF9, 0x00, 0x2C, 0xF0, 0xD1, 0x20, 0x46, 0xBD, 0xE8, ++ 0xF0, 0x81, 0x00, 0xBF, 0x60, 0x28, 0x17, 0x00, 0x59, 0x28, 0x17, 0x00, ++ 0x5A, 0x28, 0x17, 0x00, 0x38, 0x1A, 0x17, 0x00, 0x20, 0x86, 0x15, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0xF8, 0xB5, 0x1D, 0x4D, 0x2B, 0x78, 0xFB, 0xB9, ++ 0xD8, 0xB1, 0x0A, 0x46, 0xC9, 0xB1, 0x1B, 0x4F, 0x3B, 0x78, 0xE3, 0xB9, ++ 0x1A, 0x4C, 0x01, 0x26, 0x3E, 0x70, 0xD4, 0xF8, 0x30, 0x3B, 0x23, 0xF0, ++ 0xFF, 0x53, 0x23, 0xF4, 0xC0, 0x13, 0x01, 0x46, 0xC4, 0xF8, 0x30, 0x3B, ++ 0x30, 0x46, 0xFE, 0xF7, 0x7B, 0xFE, 0x04, 0x46, 0xC8, 0xB9, 0x13, 0x4B, ++ 0x1E, 0x70, 0x2B, 0x78, 0x73, 0xB9, 0x20, 0x46, 0xF8, 0xBD, 0x6F, 0xF0, ++ 0x0A, 0x04, 0xFA, 0xE7, 0x6F, 0xF0, 0x0D, 0x04, 0xF7, 0xE7, 0x39, 0x78, ++ 0x0D, 0x48, 0xFB, 0xF7, 0xFD, 0xFE, 0x6F, 0xF0, 0x02, 0x04, 0xF0, 0xE7, ++ 0x31, 0x46, 0xFE, 0xF7, 0xB3, 0xFC, 0x3C, 0x70, 0x6F, 0xF0, 0x0D, 0x04, ++ 0xE9, 0xE7, 0x01, 0x46, 0x07, 0x48, 0xFB, 0xF7, 0xEF, 0xFE, 0x4F, 0xF0, ++ 0xFF, 0x34, 0xE2, 0xE7, 0x5B, 0x28, 0x17, 0x00, 0x59, 0x28, 0x17, 0x00, ++ 0x00, 0x00, 0x20, 0x40, 0x58, 0x28, 0x17, 0x00, 0x30, 0x86, 0x15, 0x00, ++ 0x48, 0x86, 0x15, 0x00, 0xF8, 0xB5, 0x20, 0x4D, 0x2B, 0x78, 0x2B, 0xBB, ++ 0x08, 0xB3, 0x0A, 0x46, 0xF9, 0xB1, 0x1E, 0x4F, 0x3B, 0x78, 0x13, 0xBB, ++ 0x1D, 0x4C, 0x01, 0x26, 0x3E, 0x70, 0xD4, 0xF8, 0x30, 0x3B, 0x23, 0xF0, ++ 0xFF, 0x53, 0x23, 0xF4, 0xC0, 0x13, 0xC4, 0xF8, 0x30, 0x3B, 0xD4, 0xF8, ++ 0x00, 0x38, 0x43, 0xF4, 0x00, 0x53, 0x01, 0x46, 0xC4, 0xF8, 0x00, 0x38, ++ 0x30, 0x46, 0xFE, 0xF7, 0x87, 0xFE, 0x04, 0x46, 0xC8, 0xB9, 0x13, 0x4B, ++ 0x1E, 0x70, 0x2B, 0x78, 0x73, 0xB9, 0x20, 0x46, 0xF8, 0xBD, 0x6F, 0xF0, ++ 0x0A, 0x04, 0xFA, 0xE7, 0x6F, 0xF0, 0x0D, 0x04, 0xF7, 0xE7, 0x39, 0x78, ++ 0x0D, 0x48, 0xFB, 0xF7, 0xAF, 0xFE, 0x6F, 0xF0, 0x02, 0x04, 0xF0, 0xE7, ++ 0x31, 0x46, 0xFE, 0xF7, 0x65, 0xFC, 0x3C, 0x70, 0x6F, 0xF0, 0x0D, 0x04, ++ 0xE9, 0xE7, 0x01, 0x46, 0x07, 0x48, 0xFB, 0xF7, 0xA1, 0xFE, 0x4F, 0xF0, ++ 0xFF, 0x34, 0xE2, 0xE7, 0x5B, 0x28, 0x17, 0x00, 0x59, 0x28, 0x17, 0x00, ++ 0x00, 0x00, 0x20, 0x40, 0x58, 0x28, 0x17, 0x00, 0x30, 0x86, 0x15, 0x00, ++ 0x48, 0x86, 0x15, 0x00, 0xF8, 0xB5, 0x26, 0x4C, 0xFF, 0xF7, 0xFE, 0xFB, ++ 0x23, 0x78, 0x00, 0x2B, 0x42, 0xD1, 0x24, 0x4D, 0x28, 0x46, 0x18, 0xF0, ++ 0xFB, 0xFE, 0xDF, 0xF8, 0x90, 0xC0, 0xC0, 0xB2, 0x8C, 0xF8, 0x00, 0x00, ++ 0x00, 0x28, 0x31, 0xD0, 0x1F, 0x4A, 0x2F, 0x68, 0x42, 0xF2, 0x30, 0x03, ++ 0x01, 0x28, 0xD6, 0x58, 0x28, 0xD0, 0xBD, 0x89, 0xB3, 0x89, 0xAB, 0x42, ++ 0x11, 0xD2, 0x39, 0x46, 0x03, 0x46, 0x03, 0xE0, 0x53, 0xB1, 0x95, 0x89, ++ 0x0E, 0x46, 0x11, 0x46, 0xC2, 0x1A, 0xD2, 0xB2, 0x01, 0x3B, 0xF5, 0xB1, ++ 0x0A, 0x68, 0xDB, 0xB2, 0x00, 0x2A, 0xF3, 0xD1, 0x8C, 0xF8, 0x00, 0x30, ++ 0x0E, 0x46, 0xB3, 0x7B, 0x72, 0x68, 0x79, 0x68, 0x01, 0x3B, 0x02, 0xEB, ++ 0xC3, 0x02, 0x01, 0x20, 0xD3, 0x78, 0x20, 0x70, 0x23, 0xF0, 0x0A, 0x03, ++ 0x43, 0xF0, 0x0A, 0x03, 0xD3, 0x70, 0x02, 0x20, 0xBD, 0xE8, 0xF8, 0x40, ++ 0xFF, 0xF7, 0x0A, 0xBC, 0x00, 0x2E, 0xEA, 0xD1, 0x6F, 0xF0, 0x61, 0x00, ++ 0xF8, 0xBD, 0x8C, 0xF8, 0x00, 0x20, 0xE4, 0xE7, 0x6F, 0xF0, 0x62, 0x00, ++ 0xF8, 0xBD, 0x00, 0xBF, 0x5A, 0x28, 0x17, 0x00, 0xA8, 0x56, 0x17, 0x00, ++ 0x7C, 0x36, 0x17, 0x00, 0x64, 0x60, 0x17, 0x00, 0x01, 0x28, 0x07, 0xD0, ++ 0x06, 0x28, 0x07, 0xD0, 0x04, 0x4B, 0x0F, 0x28, 0x0C, 0xBF, 0x18, 0x46, ++ 0x00, 0x20, 0x70, 0x47, 0x02, 0x48, 0x70, 0x47, 0x02, 0x48, 0x70, 0x47, ++ 0x74, 0x86, 0x15, 0x00, 0x80, 0x86, 0x15, 0x00, 0x94, 0x86, 0x15, 0x00, ++ 0x06, 0x28, 0x0B, 0xD8, 0x01, 0x38, 0x05, 0x28, 0x16, 0xD8, 0xDF, 0xE8, ++ 0x00, 0xF0, 0x05, 0x03, 0x13, 0x0F, 0x11, 0x03, 0x09, 0x48, 0x70, 0x47, ++ 0x09, 0x48, 0x70, 0x47, 0x12, 0x30, 0xC0, 0xB2, 0x06, 0x4B, 0x02, 0x28, ++ 0x34, 0xBF, 0x18, 0x46, 0x00, 0x20, 0x70, 0x47, 0x05, 0x48, 0x70, 0x47, ++ 0x05, 0x48, 0x70, 0x47, 0x05, 0x48, 0x70, 0x47, 0x05, 0x48, 0x70, 0x47, ++ 0xC4, 0x86, 0x15, 0x00, 0xB4, 0x86, 0x15, 0x00, 0xA0, 0x86, 0x15, 0x00, ++ 0xA8, 0x86, 0x15, 0x00, 0xD8, 0x86, 0x15, 0x00, 0xEC, 0x86, 0x15, 0x00, ++ 0x2D, 0xE9, 0xF8, 0x4F, 0x1D, 0x4F, 0x1E, 0x48, 0x18, 0xF0, 0xE4, 0xFD, ++ 0x3B, 0x68, 0x1B, 0x89, 0x93, 0xB3, 0xDF, 0xF8, 0x7C, 0x90, 0x1B, 0x4E, ++ 0xDF, 0xF8, 0x78, 0x80, 0xDF, 0xF8, 0x78, 0xB0, 0xDF, 0xF8, 0x78, 0xA0, ++ 0x00, 0x25, 0x0C, 0xE0, 0x21, 0x46, 0x15, 0x48, 0x18, 0xF0, 0xD6, 0xFD, ++ 0x3A, 0x68, 0x33, 0x88, 0x11, 0x89, 0x01, 0x35, 0xAA, 0xB2, 0x01, 0x33, ++ 0x91, 0x42, 0x33, 0x80, 0x1A, 0xD9, 0xB9, 0xF8, 0xD4, 0x10, 0x04, 0x39, ++ 0x89, 0xB2, 0x40, 0x46, 0xFC, 0xF7, 0x58, 0xFC, 0x04, 0x46, 0x00, 0x28, ++ 0xE8, 0xD1, 0xA9, 0xB2, 0x58, 0x46, 0x19, 0xF0, 0x99, 0xFF, 0xDA, 0xF8, ++ 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xDE, 0xDA, 0x07, 0x49, ++ 0x07, 0x48, 0x4F, 0xF4, 0xFB, 0x72, 0x1A, 0xF0, 0x07, 0xFA, 0xD7, 0xE7, ++ 0xBD, 0xE8, 0xF8, 0x8F, 0x78, 0x36, 0x17, 0x00, 0x80, 0x60, 0x17, 0x00, ++ 0x66, 0x28, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x64, 0x7D, 0x15, 0x00, ++ 0x2C, 0x19, 0x17, 0x00, 0xE4, 0x25, 0x17, 0x00, 0xF0, 0x86, 0x15, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x10, 0xB5, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, ++ 0x03, 0xD4, 0x72, 0xB6, 0x0C, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x0C, 0x4C, ++ 0x0C, 0x48, 0x23, 0x68, 0x01, 0x33, 0x23, 0x60, 0x18, 0xF0, 0xD2, 0xFD, ++ 0x18, 0xB1, 0x0A, 0x4A, 0x13, 0x88, 0x01, 0x3B, 0x13, 0x80, 0x23, 0x68, ++ 0x33, 0xB1, 0x04, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x23, 0x60, 0x0B, 0xB9, ++ 0x02, 0xB1, 0x62, 0xB6, 0x10, 0xBD, 0x00, 0xBF, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x80, 0x60, 0x17, 0x00, 0x66, 0x28, 0x17, 0x00, ++ 0x38, 0xB5, 0x01, 0x46, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, ++ 0x72, 0xB6, 0x28, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x27, 0x4C, 0x28, 0x48, ++ 0x23, 0x68, 0x01, 0x33, 0x23, 0x60, 0x18, 0xF0, 0x65, 0xFD, 0x26, 0x4A, ++ 0x26, 0x49, 0x13, 0x88, 0x0D, 0x78, 0x01, 0x33, 0x9B, 0xB2, 0x13, 0x80, ++ 0x24, 0x4A, 0x11, 0x78, 0x9D, 0xB9, 0x49, 0xB9, 0x23, 0x68, 0x33, 0xB1, ++ 0x1C, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x23, 0x60, 0x0B, 0xB9, 0x02, 0xB1, ++ 0x62, 0xB6, 0x38, 0xBD, 0x1E, 0x49, 0x09, 0x78, 0x99, 0x42, 0xF1, 0xD8, ++ 0x01, 0x21, 0x40, 0xF2, 0x1F, 0x40, 0x15, 0x70, 0x1B, 0xE0, 0x00, 0x29, ++ 0xEA, 0xD0, 0x19, 0x49, 0x09, 0x78, 0x99, 0x42, 0xE6, 0xD8, 0x18, 0x4B, ++ 0x00, 0x21, 0x11, 0x70, 0xD3, 0xF8, 0x00, 0x28, 0x22, 0xF4, 0x00, 0x52, ++ 0xC3, 0xF8, 0x00, 0x28, 0xD3, 0xF8, 0x20, 0x2B, 0x8A, 0x42, 0x05, 0xDA, ++ 0xD3, 0xF8, 0x20, 0x2B, 0x42, 0xF0, 0x80, 0x62, 0xC3, 0xF8, 0x20, 0x2B, ++ 0x01, 0x21, 0x40, 0xF2, 0x1F, 0x40, 0x17, 0xF0, 0xA9, 0xFF, 0x0D, 0x49, ++ 0x4F, 0xF4, 0x00, 0x70, 0x19, 0xF0, 0x4E, 0xFF, 0x0B, 0x4B, 0xD3, 0xF8, ++ 0x3C, 0x34, 0x98, 0x47, 0xC4, 0xE7, 0x00, 0xBF, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x80, 0x60, 0x17, 0x00, 0x66, 0x28, 0x17, 0x00, ++ 0x68, 0x60, 0x17, 0x00, 0x64, 0x28, 0x17, 0x00, 0x88, 0x60, 0x17, 0x00, ++ 0x00, 0x00, 0x20, 0x40, 0x20, 0x87, 0x15, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0xF8, 0xB5, 0x0C, 0x4D, 0x0C, 0x48, 0x18, 0xF0, 0x01, 0xFD, 0x2B, 0x68, ++ 0x9B, 0x88, 0x83, 0xB1, 0x0A, 0x4F, 0x09, 0x4E, 0x00, 0x24, 0x7C, 0x21, ++ 0x38, 0x46, 0xFC, 0xF7, 0x8D, 0xFB, 0x01, 0x46, 0x30, 0x46, 0x18, 0xF0, ++ 0xF7, 0xFC, 0x2B, 0x68, 0x01, 0x34, 0x9A, 0x88, 0xA3, 0xB2, 0x9A, 0x42, ++ 0xF1, 0xD8, 0xF8, 0xBD, 0x78, 0x36, 0x17, 0x00, 0x70, 0x60, 0x17, 0x00, ++ 0xE4, 0x25, 0x17, 0x00, 0x10, 0xB5, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, ++ 0x03, 0xD4, 0x72, 0xB6, 0x09, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x09, 0x4C, ++ 0x09, 0x48, 0x23, 0x68, 0x01, 0x33, 0x23, 0x60, 0x18, 0xF0, 0x1E, 0xFD, ++ 0x23, 0x68, 0x33, 0xB1, 0x03, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x23, 0x60, ++ 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0x10, 0xBD, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x70, 0x60, 0x17, 0x00, 0x10, 0xB5, 0x01, 0x46, ++ 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x0A, 0x4B, ++ 0x01, 0x22, 0x1A, 0x60, 0x09, 0x4C, 0x0A, 0x48, 0x23, 0x68, 0x01, 0x33, ++ 0x23, 0x60, 0x18, 0xF0, 0xB9, 0xFC, 0x23, 0x68, 0x33, 0xB1, 0x04, 0x4A, ++ 0x01, 0x3B, 0x12, 0x68, 0x23, 0x60, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, ++ 0x10, 0xBD, 0x00, 0xBF, 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x70, 0x60, 0x17, 0x00, 0x08, 0xB5, 0x04, 0x48, 0xFF, 0xF7, 0x5E, 0xFD, ++ 0x03, 0x48, 0x19, 0xF0, 0x7B, 0xFE, 0x01, 0x20, 0x08, 0xBD, 0x00, 0xBF, ++ 0xFC, 0x87, 0x15, 0x00, 0x28, 0x87, 0x15, 0x00, 0x70, 0xB5, 0x3C, 0x4D, ++ 0x3C, 0x4C, 0x2A, 0x68, 0x3C, 0x49, 0x12, 0x69, 0x3C, 0x4B, 0x22, 0x60, ++ 0x02, 0xF1, 0x40, 0x06, 0x00, 0x24, 0x0E, 0x60, 0x3A, 0x4E, 0x98, 0x60, ++ 0xC3, 0xE9, 0x00, 0x44, 0x21, 0x46, 0x10, 0x46, 0x4F, 0xF4, 0xA0, 0x72, ++ 0xC3, 0xE9, 0x04, 0x44, 0xDC, 0x60, 0xB4, 0x81, 0xF5, 0xF7, 0xEC, 0xFB, ++ 0x2B, 0x68, 0x34, 0x49, 0x58, 0x69, 0x34, 0x4A, 0x34, 0x4B, 0x08, 0x60, ++ 0x21, 0x46, 0x00, 0xF1, 0x08, 0x04, 0x14, 0x60, 0x00, 0xF1, 0x10, 0x02, ++ 0x1A, 0x60, 0x00, 0xF1, 0x18, 0x02, 0x5A, 0x60, 0x00, 0xF1, 0x20, 0x02, ++ 0x9A, 0x60, 0x2E, 0x4C, 0x00, 0xF1, 0x28, 0x02, 0xDA, 0x60, 0x00, 0xF1, ++ 0x30, 0x03, 0x4F, 0xF4, 0x4B, 0x62, 0x23, 0x60, 0xF5, 0xF7, 0xCE, 0xFB, ++ 0x29, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x2E, 0xDB, ++ 0x27, 0x4B, 0x28, 0x49, 0xB3, 0xF8, 0xD4, 0x20, 0x0C, 0x68, 0xB3, 0xF8, ++ 0xD6, 0x00, 0xB3, 0xF8, 0xE6, 0x10, 0x25, 0x4D, 0x25, 0x4E, 0x12, 0x1B, ++ 0x25, 0x4C, 0x04, 0x3A, 0x22, 0x60, 0x04, 0x38, 0x24, 0x4C, 0x30, 0x60, ++ 0x05, 0xFB, 0x01, 0xF1, 0x93, 0xF8, 0xE0, 0x00, 0x22, 0x4D, 0x20, 0x70, ++ 0x22, 0x4A, 0x93, 0xF8, 0xE1, 0x00, 0x28, 0x70, 0x93, 0xF8, 0xE2, 0x50, ++ 0x20, 0x48, 0x15, 0x70, 0x20, 0x4C, 0x21, 0x4A, 0x93, 0xF8, 0xE3, 0x50, ++ 0x93, 0xF8, 0xE4, 0x30, 0x03, 0x70, 0x1F, 0x4B, 0x25, 0x70, 0x91, 0x42, ++ 0xD4, 0xBF, 0x19, 0x60, 0x1A, 0x60, 0x01, 0x20, 0x70, 0xBD, 0x2B, 0x68, ++ 0x9B, 0x69, 0xB3, 0xF5, 0x4B, 0x6F, 0xCB, 0xD2, 0x19, 0x49, 0x1A, 0x48, ++ 0x40, 0xF2, 0xF2, 0x22, 0x1A, 0xF0, 0x76, 0xF8, 0xC4, 0xE7, 0x00, 0xBF, ++ 0x78, 0x36, 0x17, 0x00, 0x60, 0x60, 0x17, 0x00, 0x58, 0x60, 0x17, 0x00, ++ 0xA4, 0x60, 0x17, 0x00, 0x8C, 0x60, 0x17, 0x00, 0x5C, 0x60, 0x17, 0x00, ++ 0x40, 0x60, 0x17, 0x00, 0x44, 0x60, 0x17, 0x00, 0x54, 0x60, 0x17, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x2C, 0x19, 0x17, 0x00, 0x80, 0x1A, 0x17, 0x00, ++ 0x40, 0x42, 0x0F, 0x00, 0x9C, 0x60, 0x17, 0x00, 0x78, 0x60, 0x17, 0x00, ++ 0x7C, 0x60, 0x17, 0x00, 0x88, 0x60, 0x17, 0x00, 0xA0, 0x60, 0x17, 0x00, ++ 0x68, 0x60, 0x17, 0x00, 0xA1, 0x60, 0x17, 0x00, 0xFF, 0xA2, 0xE1, 0x11, ++ 0x6C, 0x60, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x3C, 0x87, 0x15, 0x00, ++ 0x2D, 0xE9, 0xF8, 0x43, 0x43, 0x7E, 0x07, 0x7E, 0x09, 0x2B, 0x05, 0x46, ++ 0x09, 0xD8, 0x49, 0x4A, 0x4F, 0xF4, 0x1E, 0x71, 0x01, 0xFB, 0x03, 0x23, ++ 0x93, 0xF8, 0x25, 0x30, 0x00, 0x2B, 0x00, 0xF0, 0x81, 0x80, 0x6B, 0x8B, ++ 0xDF, 0xF8, 0x30, 0x81, 0x1A, 0x07, 0x5A, 0xD4, 0x4F, 0xF4, 0xA4, 0x63, ++ 0x03, 0xFB, 0x07, 0x83, 0x93, 0xF8, 0x64, 0x30, 0x00, 0x2B, 0x73, 0xD0, ++ 0x3E, 0x4B, 0xAE, 0x7D, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0x63, 0xDB, 0x3C, 0x48, 0x18, 0xF0, 0x0C, 0xFC, 0x04, 0x46, 0x00, 0x28, ++ 0x4C, 0xD0, 0x3A, 0x48, 0xE1, 0x8B, 0x83, 0x5D, 0xE2, 0x6C, 0x4F, 0xF0, ++ 0x00, 0x09, 0x01, 0x33, 0x21, 0xF0, 0x01, 0x01, 0x83, 0x55, 0xE1, 0x83, ++ 0xC4, 0xF8, 0x44, 0x90, 0x29, 0x46, 0xC2, 0xF8, 0x10, 0x90, 0x20, 0x1D, ++ 0x1C, 0x22, 0xC4, 0xF8, 0x2C, 0x90, 0x2C, 0xF0, 0xA9, 0xFA, 0x30, 0x4B, ++ 0xE1, 0x8B, 0x1B, 0x68, 0x84, 0xF8, 0x42, 0x90, 0xEB, 0x1A, 0x04, 0x3B, ++ 0x21, 0xF4, 0x00, 0x42, 0x22, 0xF0, 0x02, 0x02, 0xA3, 0x64, 0x0B, 0x07, ++ 0xC4, 0xF8, 0x24, 0x90, 0xC4, 0xF8, 0x50, 0x90, 0xE2, 0x83, 0x29, 0xD4, ++ 0x63, 0x7F, 0x09, 0x2B, 0x0E, 0xD8, 0xE2, 0x7E, 0x08, 0x2A, 0x0B, 0xD8, ++ 0x03, 0xEB, 0xC3, 0x03, 0x13, 0x44, 0x23, 0x49, 0xA0, 0x88, 0x03, 0xF6, ++ 0x0E, 0x03, 0x51, 0xF8, 0x23, 0x20, 0x02, 0x44, 0x41, 0xF8, 0x23, 0x20, ++ 0xA4, 0x20, 0x00, 0xFB, 0x07, 0x60, 0x99, 0x30, 0x21, 0x46, 0x08, 0xEB, ++ 0xC0, 0x00, 0xBD, 0xE8, 0xF8, 0x43, 0x18, 0xF0, 0x7F, 0xBB, 0x16, 0x48, ++ 0x18, 0xF0, 0xC0, 0xFB, 0x05, 0x26, 0x04, 0x46, 0x00, 0x28, 0xB2, 0xD1, ++ 0x13, 0x4B, 0x16, 0x48, 0x99, 0x5D, 0xFB, 0xF7, 0x83, 0xFB, 0xFE, 0xE7, ++ 0x4F, 0xF4, 0xA4, 0x60, 0x00, 0xFB, 0x07, 0x80, 0x21, 0x46, 0x00, 0xF5, ++ 0xA3, 0x60, 0xBD, 0xE8, 0xF8, 0x43, 0x18, 0xF0, 0x67, 0xBB, 0x05, 0x2E, ++ 0x99, 0xD9, 0x0E, 0x49, 0x0E, 0x48, 0x40, 0xF2, 0x5F, 0x32, 0x19, 0xF0, ++ 0xB3, 0xFF, 0x92, 0xE7, 0x07, 0x4B, 0x18, 0x68, 0x28, 0x1A, 0x04, 0x38, ++ 0xBD, 0xE8, 0xF8, 0x43, 0xFC, 0xF7, 0x58, 0xBC, 0x68, 0x65, 0x17, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x20, 0x58, 0x17, 0x00, 0x74, 0x28, 0x17, 0x00, ++ 0x80, 0x1A, 0x17, 0x00, 0x7C, 0x36, 0x17, 0x00, 0x60, 0x87, 0x15, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x88, 0x82, 0x15, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF8, 0x4F, 0xDF, 0xF8, 0x48, 0x81, 0xDF, 0xF8, 0x48, 0x91, ++ 0xDF, 0xF8, 0x48, 0xA1, 0x59, 0xE0, 0x47, 0x48, 0x18, 0xF0, 0x7A, 0xFB, ++ 0x04, 0x46, 0xDF, 0xF8, 0x40, 0xE1, 0x1C, 0x22, 0x29, 0x46, 0x04, 0x30, ++ 0x00, 0x2C, 0x63, 0xD0, 0xB4, 0xF8, 0x1E, 0xB0, 0x1E, 0xF8, 0x07, 0xC0, ++ 0xE3, 0x6C, 0x66, 0x64, 0x2B, 0xF0, 0x01, 0x0B, 0x0C, 0xF1, 0x01, 0x0C, ++ 0xA4, 0xF8, 0x1E, 0xB0, 0x1E, 0x61, 0xE6, 0x62, 0x0E, 0xF8, 0x07, 0xC0, ++ 0x2C, 0xF0, 0x16, 0xFA, 0x95, 0xF8, 0x20, 0x20, 0xE3, 0x8B, 0x38, 0x48, ++ 0x12, 0xF0, 0x01, 0x0F, 0x14, 0xBF, 0x4F, 0xF4, 0x00, 0x52, 0x4F, 0xF4, ++ 0x08, 0x52, 0x2A, 0x61, 0x84, 0xF8, 0x42, 0x60, 0xC5, 0xE9, 0x05, 0x66, ++ 0x62, 0x7F, 0x10, 0x32, 0x92, 0x02, 0x45, 0xF8, 0x18, 0x2C, 0x21, 0x7F, ++ 0x26, 0x65, 0xA4, 0x22, 0x99, 0x37, 0x23, 0xF4, 0x00, 0x43, 0x12, 0xFB, ++ 0x01, 0x77, 0x23, 0xF0, 0x02, 0x03, 0x4C, 0x3D, 0xA5, 0x64, 0x00, 0xEB, ++ 0xC7, 0x00, 0xE3, 0x83, 0x21, 0x46, 0x18, 0xF0, 0xF5, 0xFA, 0xEF, 0xF3, ++ 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x24, 0x4B, 0x01, 0x22, ++ 0x1A, 0x60, 0x24, 0x4C, 0x24, 0x48, 0x23, 0x68, 0x01, 0x33, 0x23, 0x60, ++ 0x18, 0xF0, 0x2A, 0xFB, 0x98, 0xF8, 0x11, 0x35, 0x22, 0x68, 0x01, 0x3B, ++ 0x88, 0xF8, 0x11, 0x35, 0x3A, 0xBB, 0xD8, 0xF8, 0x14, 0x35, 0x00, 0x26, ++ 0xDB, 0xB1, 0xD9, 0xF8, 0x00, 0x20, 0x5D, 0x68, 0xB2, 0xF9, 0x00, 0x30, ++ 0xAF, 0x7D, 0x00, 0x2B, 0x99, 0xDA, 0x05, 0x2F, 0x97, 0xD9, 0x18, 0x49, ++ 0x4F, 0xF4, 0x66, 0x72, 0x50, 0x46, 0x19, 0xF0, 0x1F, 0xFF, 0x90, 0xE7, ++ 0x15, 0x48, 0x1E, 0xF8, 0x07, 0x10, 0xFB, 0xF7, 0xD5, 0xFA, 0x14, 0x4B, ++ 0x18, 0x68, 0x28, 0x1A, 0x04, 0x38, 0xFC, 0xF7, 0xC1, 0xFB, 0x20, 0x20, ++ 0x18, 0xF0, 0x3E, 0xFA, 0xBD, 0xE8, 0xF8, 0x4F, 0x40, 0x20, 0x18, 0xF0, ++ 0x15, 0xBA, 0x08, 0x4B, 0x01, 0x3A, 0x1B, 0x68, 0x22, 0x60, 0x00, 0x2A, ++ 0x7F, 0xF4, 0x74, 0xAF, 0x00, 0x2B, 0x3F, 0xF4, 0x71, 0xAF, 0x62, 0xB6, ++ 0x6E, 0xE7, 0x00, 0xBF, 0x20, 0x58, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0x6C, 0x5D, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x60, 0x87, 0x15, 0x00, 0x80, 0x1A, 0x17, 0x00, ++ 0x58, 0x58, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, 0x88, 0x82, 0x15, 0x00, ++ 0x74, 0x28, 0x17, 0x00, 0x2D, 0xE9, 0xF8, 0x43, 0xDF, 0xF8, 0xB8, 0x90, ++ 0x29, 0x4D, 0x2A, 0x4F, 0xDF, 0xF8, 0xAC, 0x80, 0x29, 0x4E, 0x20, 0xE0, ++ 0x5C, 0x68, 0x20, 0x46, 0xFA, 0xF7, 0x1E, 0xFB, 0x38, 0x68, 0x20, 0x1A, ++ 0x04, 0x38, 0xFC, 0xF7, 0x81, 0xFB, 0xEF, 0xF3, 0x10, 0x83, 0xDA, 0x07, ++ 0x03, 0xD4, 0x72, 0xB6, 0x01, 0x23, 0xC8, 0xF8, 0x00, 0x30, 0xD9, 0xF8, ++ 0x00, 0x30, 0x30, 0x46, 0x01, 0x33, 0xC9, 0xF8, 0x00, 0x30, 0x18, 0xF0, ++ 0xB3, 0xFA, 0x95, 0xF8, 0x9D, 0x37, 0xD9, 0xF8, 0x00, 0x20, 0x01, 0x3B, ++ 0x85, 0xF8, 0x9D, 0x37, 0x0A, 0xBB, 0xD5, 0xF8, 0xA0, 0x37, 0x00, 0x2B, ++ 0xDA, 0xD1, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, ++ 0x14, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0xD9, 0xF8, 0x00, 0x30, 0x4F, 0xF4, ++ 0x00, 0x00, 0x01, 0x33, 0xC9, 0xF8, 0x00, 0x30, 0x18, 0xF0, 0xD4, 0xF9, ++ 0xD9, 0xF8, 0x00, 0x30, 0x3B, 0xB1, 0x0D, 0x4A, 0x01, 0x3B, 0x12, 0x68, ++ 0xC9, 0xF8, 0x00, 0x30, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0xBD, 0xE8, ++ 0xF8, 0x83, 0x01, 0x3A, 0xD8, 0xF8, 0x00, 0x30, 0xC9, 0xF8, 0x00, 0x20, ++ 0x00, 0x2A, 0xB3, 0xD1, 0x00, 0x2B, 0xB1, 0xD0, 0x62, 0xB6, 0xAF, 0xE7, ++ 0x58, 0x58, 0x17, 0x00, 0x80, 0x1A, 0x17, 0x00, 0xF8, 0x5F, 0x17, 0x00, ++ 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0x0E, 0x4B, 0x10, 0xB5, ++ 0xD3, 0xF8, 0x90, 0x32, 0x98, 0x47, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, ++ 0x03, 0xD4, 0x72, 0xB6, 0x0A, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x0A, 0x4C, ++ 0x23, 0x68, 0x10, 0x20, 0x01, 0x33, 0x23, 0x60, 0x18, 0xF0, 0x9E, 0xF9, ++ 0x23, 0x68, 0x33, 0xB1, 0x04, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x23, 0x60, ++ 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0x10, 0xBD, 0x88, 0x1A, 0x17, 0x00, ++ 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0xF8, 0xB5, 0x16, 0x4C, ++ 0x16, 0x4E, 0x17, 0x4F, 0x14, 0x4D, 0x15, 0xE0, 0x58, 0x68, 0xFC, 0xF7, ++ 0x05, 0xFB, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x02, 0xD4, 0x72, 0xB6, ++ 0x01, 0x23, 0x33, 0x60, 0x3B, 0x68, 0x28, 0x46, 0x01, 0x33, 0x3B, 0x60, ++ 0x18, 0xF0, 0x3A, 0xFA, 0x0E, 0x4A, 0x39, 0x68, 0x13, 0x78, 0x01, 0x3B, ++ 0x13, 0x70, 0x39, 0xB9, 0x23, 0x68, 0x00, 0x2B, 0xE6, 0xD1, 0xBD, 0xE8, ++ 0xF8, 0x40, 0x08, 0x20, 0x18, 0xF0, 0x6A, 0xB9, 0x01, 0x39, 0x33, 0x68, ++ 0x39, 0x60, 0x00, 0x29, 0xDA, 0xD1, 0x00, 0x2B, 0xD8, 0xD0, 0x62, 0xB6, ++ 0xD6, 0xE7, 0x00, 0xBF, 0x94, 0x4E, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x8E, 0x4E, 0x17, 0x00, 0x59, 0x4B, 0x1B, 0x78, ++ 0x00, 0x2B, 0x67, 0xD1, 0x2D, 0xE9, 0xF0, 0x47, 0x57, 0x4D, 0x2B, 0x78, ++ 0x00, 0x2B, 0x47, 0xD1, 0x56, 0x4B, 0x1A, 0x78, 0x00, 0x2A, 0x5B, 0xD1, ++ 0x55, 0x49, 0x56, 0x4A, 0x09, 0x78, 0x12, 0x88, 0x91, 0x42, 0x5E, 0xD2, ++ 0x54, 0x4B, 0xD3, 0xE9, 0x01, 0x02, 0x13, 0x69, 0x98, 0x47, 0x04, 0x46, ++ 0x00, 0x28, 0x78, 0xD0, 0x2B, 0x78, 0x00, 0x2B, 0x4D, 0xD0, 0x4C, 0x4B, ++ 0xDF, 0xF8, 0x60, 0xA1, 0x1B, 0x78, 0x4E, 0x4F, 0xDA, 0xF8, 0x00, 0x00, ++ 0x00, 0x2B, 0x7B, 0xD1, 0x4C, 0x4B, 0x39, 0x68, 0xD3, 0xF8, 0x40, 0x34, ++ 0x20, 0x44, 0x98, 0x47, 0x00, 0x28, 0x39, 0xD0, 0x01, 0x46, 0x49, 0x48, ++ 0xDF, 0xF8, 0x08, 0x91, 0xDF, 0xF8, 0x18, 0x81, 0xFB, 0xF7, 0xAE, 0xF9, ++ 0x05, 0x26, 0x2B, 0x78, 0x00, 0x2B, 0x48, 0xD1, 0xDA, 0xF8, 0x00, 0x00, ++ 0xD8, 0xF8, 0x40, 0x34, 0x39, 0x68, 0x20, 0x44, 0x98, 0x47, 0x28, 0xB3, ++ 0x01, 0x3E, 0xF2, 0xD1, 0x05, 0x21, 0x3F, 0x48, 0xFB, 0xF7, 0x9C, 0xF9, ++ 0x20, 0x46, 0xFC, 0xF7, 0x8B, 0xFA, 0xBD, 0xE8, 0xF0, 0x47, 0x04, 0x20, ++ 0x18, 0xF0, 0xE2, 0xB8, 0x34, 0x4B, 0x1B, 0x88, 0x00, 0x2B, 0x46, 0xD0, ++ 0x31, 0x4A, 0x12, 0x78, 0x9A, 0x42, 0xB9, 0xD3, 0x36, 0x4A, 0x2E, 0x4B, ++ 0x12, 0x68, 0x01, 0x21, 0x19, 0x70, 0x00, 0x2A, 0x47, 0xD1, 0x34, 0x4B, ++ 0x34, 0x49, 0x1A, 0x88, 0x4F, 0xF4, 0x00, 0x70, 0x92, 0xB2, 0x19, 0xF0, ++ 0x97, 0xFB, 0xA9, 0xE7, 0xBD, 0xE8, 0xF0, 0x87, 0x70, 0x47, 0xDF, 0xF8, ++ 0xC8, 0xA0, 0x28, 0x4F, 0xDA, 0xF8, 0x00, 0x00, 0xB4, 0xE7, 0x1A, 0x78, ++ 0x00, 0x2A, 0x9D, 0xD1, 0x28, 0x4A, 0x12, 0x68, 0x01, 0x21, 0x19, 0x70, ++ 0x92, 0xBB, 0x27, 0x4B, 0x27, 0x49, 0x1A, 0x88, 0xBD, 0xE8, 0xF0, 0x47, ++ 0x4F, 0xF4, 0x00, 0x70, 0x92, 0xB2, 0x19, 0xF0, 0x7B, 0xBB, 0x99, 0xF8, ++ 0x00, 0x30, 0xDA, 0xF8, 0x00, 0x00, 0x2B, 0xB9, 0xD8, 0xF8, 0x40, 0x34, ++ 0x39, 0x68, 0x20, 0x44, 0x98, 0x47, 0xB2, 0xE7, 0x39, 0x68, 0x20, 0x44, ++ 0xFF, 0xF7, 0x72, 0xFA, 0xAD, 0xE7, 0x04, 0x20, 0x18, 0xF0, 0x9C, 0xF8, ++ 0xBD, 0xE8, 0xF0, 0x47, 0x19, 0x48, 0xFB, 0xF7, 0x49, 0xB9, 0xBD, 0xE8, ++ 0xF0, 0x47, 0x18, 0x49, 0x4F, 0xF4, 0x00, 0x70, 0x19, 0xF0, 0x5C, 0xBB, ++ 0x39, 0x68, 0x20, 0x44, 0xFF, 0xF7, 0x5E, 0xFA, 0x84, 0xE7, 0x40, 0xF2, ++ 0x1F, 0x40, 0x17, 0xF0, 0xF9, 0xFA, 0xB2, 0xE7, 0x40, 0xF2, 0x1F, 0x40, ++ 0x17, 0xF0, 0xF4, 0xFA, 0xC7, 0xE7, 0x00, 0xBF, 0x58, 0x28, 0x17, 0x00, ++ 0x68, 0x60, 0x17, 0x00, 0x64, 0x28, 0x17, 0x00, 0x7C, 0x60, 0x17, 0x00, ++ 0x66, 0x28, 0x17, 0x00, 0xA4, 0x60, 0x17, 0x00, 0x78, 0x60, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x8C, 0x87, 0x15, 0x00, 0xAC, 0x87, 0x15, 0x00, ++ 0x6C, 0x60, 0x17, 0x00, 0x56, 0x28, 0x17, 0x00, 0x7C, 0x87, 0x15, 0x00, ++ 0x98, 0x87, 0x15, 0x00, 0x84, 0x87, 0x15, 0x00, 0x80, 0x1A, 0x17, 0x00, ++ 0x08, 0xB5, 0x0F, 0x48, 0x19, 0xF0, 0xD8, 0xFA, 0x0E, 0x4B, 0xD3, 0xE9, ++ 0x01, 0x02, 0x13, 0x69, 0x98, 0x47, 0x80, 0xB1, 0x0C, 0x4B, 0x0D, 0x49, ++ 0x1A, 0x68, 0x0D, 0x4B, 0x09, 0x68, 0xD3, 0xF8, 0x40, 0x34, 0x10, 0x44, ++ 0x98, 0x47, 0x01, 0x1E, 0x00, 0xDB, 0x08, 0xBD, 0xBD, 0xE8, 0x08, 0x40, ++ 0x08, 0x48, 0xFB, 0xF7, 0xF7, 0xB8, 0xBD, 0xE8, 0x08, 0x40, 0x07, 0x48, ++ 0xFB, 0xF7, 0xF2, 0xB8, 0xC0, 0x87, 0x15, 0x00, 0xA4, 0x60, 0x17, 0x00, ++ 0x80, 0x1A, 0x17, 0x00, 0x78, 0x60, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0xCC, 0x87, 0x15, 0x00, 0xE4, 0x87, 0x15, 0x00, 0x10, 0xB5, 0x04, 0x20, ++ 0x18, 0xF0, 0x52, 0xF8, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, ++ 0x72, 0xB6, 0x0A, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x09, 0x4C, 0x0A, 0x4A, ++ 0x23, 0x68, 0xD2, 0xF8, 0x3C, 0x24, 0x01, 0x33, 0x23, 0x60, 0x90, 0x47, ++ 0x23, 0x68, 0x33, 0xB1, 0x03, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x23, 0x60, ++ 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0x10, 0xBD, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0xF8, 0xB5, 0x11, 0x4D, ++ 0x11, 0x4F, 0x28, 0x68, 0x00, 0xF5, 0x0D, 0x70, 0x18, 0xF0, 0xA4, 0xF8, ++ 0x28, 0x68, 0x00, 0xF5, 0x0F, 0x70, 0x18, 0xF0, 0x9F, 0xF8, 0x3B, 0x68, ++ 0x1B, 0x89, 0x93, 0xB1, 0x0B, 0x4E, 0x00, 0x24, 0x4F, 0xF4, 0xD7, 0x61, ++ 0x30, 0x46, 0xFB, 0xF7, 0x2B, 0xFF, 0x01, 0x46, 0x28, 0x68, 0x00, 0xF5, ++ 0x0D, 0x70, 0x18, 0xF0, 0x93, 0xF8, 0x3B, 0x68, 0x01, 0x34, 0x1A, 0x89, ++ 0xA3, 0xB2, 0x9A, 0x42, 0xEE, 0xD8, 0xF8, 0xBD, 0x00, 0x38, 0x18, 0x00, ++ 0x78, 0x36, 0x17, 0x00, 0xE4, 0x25, 0x17, 0x00, 0x00, 0x20, 0x70, 0x47, ++ 0x10, 0xB5, 0x12, 0x4A, 0x01, 0x46, 0x13, 0x68, 0x00, 0x2B, 0xFC, 0xD0, ++ 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x0E, 0x4B, ++ 0x01, 0x22, 0x1A, 0x60, 0x0D, 0x4C, 0x0E, 0x4A, 0x23, 0x68, 0x10, 0x68, ++ 0x01, 0x33, 0x00, 0xF5, 0x0D, 0x70, 0x23, 0x60, 0x18, 0xF0, 0x6C, 0xF8, ++ 0x23, 0x68, 0x33, 0xB1, 0x06, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x23, 0x60, ++ 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0x02, 0x4B, 0x01, 0x22, 0x1A, 0x60, ++ 0x10, 0xBD, 0x00, 0xBF, 0x4C, 0x40, 0x04, 0x40, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x00, 0x38, 0x18, 0x00, 0x08, 0xB5, 0x03, 0x49, ++ 0x4F, 0xF4, 0x80, 0x70, 0x19, 0xF0, 0x7A, 0xFA, 0x01, 0x20, 0x08, 0xBD, ++ 0x08, 0x88, 0x15, 0x00, 0x05, 0x4A, 0x06, 0x49, 0x00, 0x23, 0xC2, 0xE9, ++ 0x02, 0x03, 0xC2, 0xE9, 0x04, 0x33, 0xC2, 0xE9, 0x00, 0x33, 0x8B, 0x81, ++ 0x01, 0x20, 0x70, 0x47, 0xBC, 0x60, 0x17, 0x00, 0xD4, 0x60, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF8, 0x4F, 0xDF, 0xF8, 0x0C, 0x92, 0xDF, 0xF8, 0x0C, 0x82, ++ 0xD9, 0xF8, 0x14, 0x35, 0x00, 0x2B, 0x00, 0xF0, 0x8F, 0x80, 0xDF, 0xF8, ++ 0xE8, 0xA1, 0xDF, 0xF8, 0x00, 0xB2, 0x78, 0xE0, 0x71, 0x49, 0x4F, 0xF4, ++ 0xA4, 0x62, 0x02, 0xFB, 0x06, 0x12, 0x92, 0xF8, 0x64, 0x20, 0x00, 0x2A, ++ 0x00, 0xF0, 0xB2, 0x80, 0x6D, 0x4A, 0x1F, 0x7A, 0x13, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0xC0, 0xF2, 0xA1, 0x80, 0x6A, 0x48, 0x18, 0xF0, ++ 0x5B, 0xF8, 0x04, 0x46, 0x00, 0x28, 0x6C, 0xD0, 0xC2, 0x8B, 0xC1, 0x6C, ++ 0x1A, 0xF8, 0x07, 0xC0, 0x00, 0x23, 0x22, 0xF0, 0x01, 0x02, 0xC2, 0x83, ++ 0x43, 0x64, 0x0C, 0xF1, 0x01, 0x0C, 0x0B, 0x61, 0x1C, 0x22, 0xC3, 0x62, ++ 0x29, 0x46, 0x04, 0x30, 0x0A, 0xF8, 0x07, 0xC0, 0x2B, 0xF0, 0xFA, 0xFE, ++ 0xE2, 0x8B, 0xDB, 0xF8, 0x00, 0x10, 0x6D, 0x1A, 0xC2, 0xF3, 0x0E, 0x01, ++ 0x00, 0x23, 0xE1, 0x83, 0x11, 0x07, 0x84, 0xF8, 0x42, 0x30, 0x23, 0x65, ++ 0xA5, 0x64, 0x6F, 0xD4, 0x63, 0x7F, 0x09, 0x2B, 0x0E, 0xD8, 0xE2, 0x7E, ++ 0x08, 0x2A, 0x0B, 0xD8, 0x03, 0xEB, 0xC3, 0x03, 0x13, 0x44, 0x53, 0x49, ++ 0xA0, 0x88, 0x03, 0xF6, 0x0E, 0x03, 0x51, 0xF8, 0x23, 0x20, 0x02, 0x44, ++ 0x41, 0xF8, 0x23, 0x20, 0xA4, 0x20, 0x00, 0xFB, 0x06, 0x76, 0x4A, 0x48, ++ 0x99, 0x36, 0x21, 0x46, 0x00, 0xEB, 0xC6, 0x00, 0x17, 0xF0, 0xD6, 0xFF, ++ 0xEF, 0xF3, 0x10, 0x83, 0xDA, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x48, 0x4B, ++ 0x01, 0x22, 0x1A, 0x60, 0xD8, 0xF8, 0x00, 0x30, 0x46, 0x48, 0x01, 0x33, ++ 0xC8, 0xF8, 0x00, 0x30, 0x18, 0xF0, 0x0A, 0xF8, 0x99, 0xF8, 0x11, 0x35, ++ 0xD8, 0xF8, 0x00, 0x20, 0x01, 0x3B, 0x89, 0xF8, 0x11, 0x35, 0x3A, 0xB1, ++ 0x3E, 0x4B, 0x01, 0x3A, 0x1B, 0x68, 0xC8, 0xF8, 0x00, 0x20, 0x0A, 0xB9, ++ 0x03, 0xB1, 0x62, 0xB6, 0xD9, 0xF8, 0x14, 0x35, 0x83, 0xB1, 0x5D, 0x68, ++ 0x6A, 0x8B, 0x2E, 0x7E, 0x14, 0x07, 0x81, 0xD5, 0x34, 0x48, 0x17, 0xF0, ++ 0xEF, 0xFF, 0x05, 0x27, 0x04, 0x46, 0x00, 0x28, 0x92, 0xD1, 0x35, 0x4B, ++ 0x35, 0x48, 0xD9, 0x5D, 0xFA, 0xF7, 0xB2, 0xFF, 0xEF, 0xF3, 0x10, 0x83, ++ 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x2E, 0x4B, 0x01, 0x22, 0x1A, 0x60, ++ 0xD8, 0xF8, 0x00, 0x30, 0x20, 0x20, 0x01, 0x33, 0xC8, 0xF8, 0x00, 0x30, ++ 0x17, 0xF0, 0x14, 0xFF, 0x40, 0x20, 0x17, 0xF0, 0xED, 0xFE, 0xD8, 0xF8, ++ 0x00, 0x30, 0x3B, 0xB1, 0x25, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0xC8, 0xF8, ++ 0x00, 0x30, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0xBD, 0xE8, 0xF8, 0x8F, ++ 0x24, 0x4B, 0x4F, 0xF4, 0xA4, 0x60, 0x21, 0x46, 0x00, 0xFB, 0x06, 0x30, ++ 0x17, 0xF0, 0x7A, 0xFF, 0xA2, 0xE7, 0x05, 0x2F, 0x7F, 0xF6, 0x5C, 0xAF, ++ 0x1F, 0x49, 0x20, 0x48, 0xB8, 0x22, 0x19, 0xF0, 0xC5, 0xFB, 0x55, 0xE7, ++ 0xDB, 0xF8, 0x00, 0x00, 0x28, 0x1A, 0xFC, 0xF7, 0x6D, 0xF8, 0xEF, 0xF3, ++ 0x10, 0x83, 0xD8, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x12, 0x4B, 0x01, 0x22, ++ 0x1A, 0x60, 0xD8, 0xF8, 0x00, 0x30, 0x11, 0x48, 0x01, 0x33, 0xC8, 0xF8, ++ 0x00, 0x30, 0x17, 0xF0, 0x9F, 0xFF, 0x99, 0xF8, 0x11, 0x25, 0xD8, 0xF8, ++ 0x00, 0x30, 0x01, 0x3A, 0x89, 0xF8, 0x11, 0x25, 0x00, 0x2B, 0x9B, 0xD0, ++ 0x08, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0xC8, 0xF8, 0x00, 0x30, 0x00, 0x2B, ++ 0x94, 0xD1, 0x00, 0x2A, 0x92, 0xD0, 0x90, 0xE7, 0x18, 0x88, 0x17, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x20, 0x58, 0x17, 0x00, 0x7C, 0x36, 0x17, 0x00, ++ 0x38, 0x61, 0x17, 0x00, 0x6C, 0x5D, 0x17, 0x00, 0x74, 0x28, 0x17, 0x00, ++ 0x1C, 0x88, 0x15, 0x00, 0x30, 0x8D, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x88, 0x82, 0x15, 0x00, 0x58, 0x58, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x84, 0x1A, 0x17, 0x00, 0x70, 0x47, 0x00, 0xBF, 0x70, 0x47, 0x00, 0xBF, ++ 0x70, 0x47, 0x00, 0xBF, 0x04, 0x20, 0x17, 0xF0, 0xA5, 0xBE, 0x00, 0xBF, ++ 0x2D, 0xE9, 0xF8, 0x43, 0xD0, 0xF8, 0xA8, 0x44, 0xD1, 0xF8, 0xB0, 0x50, ++ 0x07, 0x46, 0x0E, 0x46, 0x00, 0x2C, 0x00, 0xF0, 0x8F, 0x80, 0xA2, 0x49, ++ 0xA2, 0x4A, 0x4F, 0xF0, 0xFF, 0x33, 0x0B, 0x60, 0x13, 0x60, 0x94, 0xF8, ++ 0x60, 0x80, 0xB8, 0xF1, 0x04, 0x0F, 0x00, 0xF2, 0xB9, 0x81, 0xDF, 0xE8, ++ 0x18, 0xF0, 0x49, 0x00, 0xF3, 0x00, 0x45, 0x01, 0x03, 0x01, 0x05, 0x00, ++ 0x9A, 0x4B, 0x62, 0x6E, 0x1A, 0x60, 0xA2, 0x6E, 0x5A, 0x60, 0xE2, 0x6E, ++ 0x9A, 0x60, 0x22, 0x6F, 0xDA, 0x60, 0x22, 0x6D, 0xDA, 0x61, 0x62, 0x6D, ++ 0x1A, 0x62, 0xA2, 0x6D, 0x5A, 0x62, 0x94, 0x4B, 0x94, 0x4A, 0xE1, 0x6D, ++ 0x1B, 0x68, 0x11, 0x60, 0x1B, 0x78, 0x13, 0xF0, 0x02, 0x0F, 0xC1, 0x46, ++ 0x4F, 0xF4, 0x80, 0x63, 0x4F, 0xF4, 0x80, 0x51, 0x4F, 0xF0, 0x01, 0x08, ++ 0x48, 0xD0, 0x97, 0xF8, 0x63, 0xC0, 0x94, 0xF8, 0x62, 0x00, 0x8C, 0x4A, ++ 0x43, 0xEA, 0x0C, 0x13, 0x43, 0xEA, 0x00, 0x43, 0x0B, 0x43, 0x43, 0xF0, ++ 0x80, 0x43, 0x13, 0x60, 0x13, 0x68, 0x5C, 0x00, 0xFC, 0xD4, 0x00, 0x2D, ++ 0x48, 0xD0, 0x81, 0x4B, 0x7F, 0x49, 0xD6, 0xF8, 0x26, 0x00, 0x72, 0x8D, ++ 0x08, 0x60, 0x1A, 0x60, 0x95, 0xF8, 0x60, 0x30, 0x04, 0x2B, 0x00, 0xF2, ++ 0x68, 0x81, 0xDF, 0xE8, 0x13, 0xF0, 0x78, 0x00, 0x41, 0x00, 0xD4, 0x00, ++ 0xCF, 0x00, 0xC5, 0x00, 0x00, 0x21, 0x4F, 0xF0, 0x01, 0x09, 0x77, 0x4B, ++ 0x62, 0x6E, 0x1A, 0x60, 0xA2, 0x6E, 0x5A, 0x60, 0xE2, 0x6E, 0x9A, 0x60, ++ 0x22, 0x6F, 0xDA, 0x60, 0x73, 0x4B, 0x1B, 0x68, 0xB9, 0xF1, 0x02, 0x0F, ++ 0x1B, 0x78, 0x40, 0xF0, 0xF2, 0x80, 0xD8, 0x07, 0x40, 0xF1, 0x20, 0x81, ++ 0x71, 0x48, 0x22, 0x6D, 0x02, 0x60, 0x62, 0x6D, 0x42, 0x60, 0xA2, 0x6D, ++ 0x82, 0x60, 0xE2, 0x6D, 0xC2, 0x60, 0x9B, 0x07, 0x00, 0xF1, 0xFF, 0x80, ++ 0x4F, 0xF4, 0x00, 0x73, 0x97, 0xF8, 0x63, 0xC0, 0x94, 0xF8, 0x62, 0x00, ++ 0x67, 0x4A, 0x43, 0xEA, 0x0C, 0x13, 0x43, 0xEA, 0x00, 0x43, 0x0B, 0x43, ++ 0x43, 0xF0, 0x80, 0x43, 0x13, 0x60, 0x13, 0x68, 0x58, 0x00, 0xFC, 0xD4, ++ 0x00, 0x2D, 0xB6, 0xD1, 0xBD, 0xE8, 0xF8, 0x83, 0xA1, 0x46, 0x4F, 0xF0, ++ 0x01, 0x08, 0xAE, 0xE7, 0x4F, 0xF0, 0x02, 0x09, 0x59, 0x4B, 0x6A, 0x6E, ++ 0x1A, 0x60, 0xAA, 0x6E, 0x5A, 0x60, 0xEA, 0x6E, 0x9A, 0x60, 0x2A, 0x6F, ++ 0xDA, 0x60, 0xB9, 0xF1, 0x04, 0x0F, 0x40, 0xF0, 0x96, 0x80, 0x57, 0x4B, ++ 0x2A, 0x6D, 0x1A, 0x60, 0x6A, 0x6D, 0x5A, 0x60, 0xAA, 0x6D, 0x9A, 0x60, ++ 0x50, 0x4B, 0x51, 0x4A, 0xE9, 0x6D, 0x1B, 0x68, 0x11, 0x60, 0x1B, 0x78, ++ 0x99, 0x07, 0x40, 0xF1, 0xD6, 0x80, 0x4F, 0xEA, 0x08, 0x38, 0x4F, 0xF4, ++ 0x80, 0x69, 0x97, 0xF8, 0x63, 0x30, 0x95, 0xF8, 0x62, 0x10, 0x4A, 0x4A, ++ 0x1B, 0x01, 0x43, 0xEA, 0x01, 0x43, 0x43, 0xEA, 0x08, 0x03, 0x43, 0xEA, ++ 0x09, 0x03, 0x43, 0xF0, 0x80, 0x43, 0x13, 0x60, 0x13, 0x68, 0x58, 0x00, ++ 0xFC, 0xD4, 0xBD, 0xE8, 0xF8, 0x83, 0x4F, 0xF0, 0x00, 0x08, 0x4F, 0xF0, ++ 0x01, 0x09, 0x3D, 0x4B, 0x6A, 0x6E, 0x1A, 0x60, 0xAA, 0x6E, 0x5A, 0x60, ++ 0xEA, 0x6E, 0x9A, 0x60, 0x2A, 0x6F, 0xDA, 0x60, 0xB9, 0xF1, 0x02, 0x0F, ++ 0x62, 0xD1, 0x38, 0x4B, 0x1B, 0x68, 0x1B, 0x78, 0xDA, 0x07, 0x40, 0xF1, ++ 0xB3, 0x80, 0x38, 0x4A, 0x29, 0x6D, 0x11, 0x60, 0x69, 0x6D, 0x51, 0x60, ++ 0xA9, 0x6D, 0x91, 0x60, 0xE9, 0x6D, 0xD1, 0x60, 0x9A, 0x07, 0x7A, 0xD4, ++ 0x4F, 0xF4, 0x00, 0x79, 0x97, 0xF8, 0x63, 0x30, 0x95, 0xF8, 0x62, 0x10, ++ 0x2E, 0x4A, 0x1B, 0x01, 0x43, 0xEA, 0x01, 0x43, 0x43, 0xEA, 0x08, 0x03, ++ 0x43, 0xEA, 0x09, 0x03, 0x43, 0xF0, 0x80, 0x43, 0x13, 0x60, 0x13, 0x68, ++ 0x59, 0x00, 0xFC, 0xD4, 0xBD, 0xE8, 0xF8, 0x83, 0x4F, 0xF0, 0x02, 0x09, ++ 0x22, 0x4B, 0x62, 0x6E, 0x1A, 0x60, 0xA2, 0x6E, 0x5A, 0x60, 0xE2, 0x6E, ++ 0x9A, 0x60, 0x22, 0x6F, 0xDA, 0x60, 0x4F, 0xF4, 0x80, 0x51, 0x4F, 0xF0, ++ 0x01, 0x08, 0x51, 0xE7, 0x4F, 0xF0, 0x01, 0x09, 0xC8, 0x46, 0x4F, 0xF4, ++ 0x80, 0x51, 0x42, 0xE7, 0x18, 0x4B, 0x6A, 0x6E, 0x1A, 0x60, 0xAA, 0x6E, ++ 0x5A, 0x60, 0xEA, 0x6E, 0x9A, 0x60, 0x2A, 0x6F, 0xDA, 0x60, 0x80, 0xE7, ++ 0x4F, 0xEA, 0x08, 0x38, 0x4F, 0xF0, 0x01, 0x09, 0xA7, 0xE7, 0x95, 0xF8, ++ 0x74, 0x30, 0x10, 0x2B, 0x00, 0xF0, 0x83, 0x80, 0x20, 0x2B, 0x7B, 0xD0, ++ 0x0D, 0x4B, 0x6A, 0x6E, 0x1A, 0x60, 0xAA, 0x6E, 0x5A, 0x60, 0xEA, 0x6E, ++ 0x9A, 0x60, 0x2A, 0x6F, 0xDA, 0x60, 0x4F, 0xF0, 0x03, 0x09, 0xB9, 0xF1, ++ 0x02, 0x0F, 0x4F, 0xEA, 0x08, 0x38, 0x9C, 0xD0, 0x06, 0x4B, 0x1B, 0x68, ++ 0x1B, 0x78, 0x9E, 0x07, 0x56, 0xD4, 0x4F, 0xEA, 0x09, 0x29, 0xA7, 0xE7, ++ 0xBC, 0x00, 0x32, 0x40, 0xC0, 0x00, 0x32, 0x40, 0xAC, 0x00, 0x32, 0x40, ++ 0x34, 0x36, 0x17, 0x00, 0xD4, 0x00, 0x32, 0x40, 0xC4, 0x00, 0x32, 0x40, ++ 0xC8, 0x00, 0x32, 0x40, 0x94, 0xF8, 0x74, 0x30, 0x10, 0x2B, 0x5B, 0xD0, ++ 0x20, 0x2B, 0x4A, 0xD0, 0x4F, 0xF0, 0x03, 0x09, 0xA6, 0xE7, 0x9A, 0x07, ++ 0x42, 0xD5, 0x09, 0xF1, 0xFF, 0x33, 0xDB, 0xB2, 0x01, 0x2B, 0x14, 0xD9, ++ 0x4F, 0xEA, 0x09, 0x23, 0xCB, 0xE6, 0x97, 0xF8, 0x63, 0x30, 0x95, 0xF8, ++ 0x62, 0x10, 0x3A, 0x4A, 0x1B, 0x01, 0x43, 0xEA, 0x01, 0x43, 0x43, 0xEA, ++ 0x08, 0x03, 0x43, 0xF0, 0x80, 0x43, 0x13, 0x60, 0x13, 0x68, 0x5C, 0x00, ++ 0xFC, 0xD4, 0xBD, 0xE8, 0xF8, 0x83, 0x97, 0xF8, 0x63, 0x30, 0x94, 0xF8, ++ 0x62, 0x00, 0x31, 0x4A, 0x41, 0xEA, 0x03, 0x13, 0x43, 0xEA, 0x00, 0x43, ++ 0x43, 0xF0, 0x80, 0x43, 0x13, 0x60, 0x13, 0x68, 0x5B, 0x00, 0xFC, 0xD4, ++ 0xB9, 0xE6, 0x4F, 0xEA, 0x08, 0x38, 0x4F, 0xF4, 0x80, 0x69, 0x5F, 0xE7, ++ 0x29, 0x48, 0x02, 0x68, 0x22, 0xF0, 0x01, 0x02, 0x02, 0x60, 0xE2, 0xE6, ++ 0x26, 0x49, 0x0A, 0x68, 0x22, 0xF0, 0x01, 0x02, 0x0A, 0x60, 0x4F, 0xE7, ++ 0x09, 0xF1, 0xFF, 0x33, 0xDB, 0xB2, 0x01, 0x2B, 0xC7, 0xD9, 0x4F, 0xEA, ++ 0x09, 0x29, 0x14, 0xE7, 0x4F, 0xEA, 0x09, 0x23, 0xD6, 0xE6, 0x4F, 0xF4, ++ 0x00, 0x51, 0x4F, 0xF0, 0x03, 0x09, 0xB0, 0xE6, 0x4F, 0xF4, 0x00, 0x58, ++ 0x4F, 0xF0, 0x03, 0x09, 0x1F, 0xE7, 0x4F, 0xF0, 0x00, 0x08, 0x4F, 0xF0, ++ 0x03, 0x09, 0x1A, 0xE7, 0x00, 0x21, 0x88, 0x46, 0x4F, 0xF0, 0x03, 0x09, ++ 0xA1, 0xE6, 0x15, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0xBF, 0xF6, 0xD6, 0xAE, 0x12, 0x49, 0x13, 0x48, 0xA6, 0x22, 0x19, 0xF0, ++ 0xA7, 0xF9, 0xCF, 0xE6, 0x0E, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0x06, 0xDB, 0x4F, 0xF4, 0x80, 0x51, 0x4F, 0xF0, 0x00, 0x09, ++ 0x4F, 0xF0, 0x01, 0x08, 0x87, 0xE6, 0x09, 0x49, 0x09, 0x48, 0x4F, 0x22, ++ 0x19, 0xF0, 0x94, 0xF9, 0x4F, 0xF0, 0x00, 0x09, 0x4F, 0xF4, 0x80, 0x51, ++ 0x4F, 0xF0, 0x01, 0x08, 0x7B, 0xE6, 0x00, 0xBF, 0xC4, 0x00, 0x32, 0x40, ++ 0x64, 0x05, 0x32, 0x40, 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x64, 0x7D, 0x15, 0x00, 0x2D, 0xE9, 0xF0, 0x41, 0xA3, 0x4E, 0x0D, 0x46, ++ 0xD6, 0xF8, 0xF0, 0x70, 0x04, 0x46, 0xF4, 0xF7, 0xF7, 0xFE, 0xB8, 0x47, ++ 0xA0, 0x4A, 0xA1, 0x49, 0x13, 0x68, 0x23, 0xF4, 0x00, 0x63, 0x13, 0x60, ++ 0x0A, 0x68, 0x9F, 0x4B, 0x42, 0xF4, 0x80, 0x32, 0x0A, 0x60, 0x1A, 0x68, ++ 0x42, 0xF0, 0x7F, 0x42, 0x1A, 0x60, 0x1A, 0x68, 0x42, 0xF4, 0x00, 0x02, ++ 0x1A, 0x60, 0x1A, 0x68, 0x22, 0xF4, 0xFE, 0x02, 0x42, 0xF4, 0x80, 0x12, ++ 0x1A, 0x60, 0x97, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x4F, 0xF4, ++ 0x40, 0x52, 0x00, 0x2B, 0xC1, 0xF8, 0x04, 0x21, 0xC0, 0xF2, 0xAD, 0x80, ++ 0x92, 0x4B, 0x8E, 0x4A, 0x92, 0x49, 0x19, 0x60, 0x13, 0x68, 0x92, 0x4F, ++ 0x43, 0xF4, 0x00, 0x53, 0x13, 0x60, 0xF5, 0xF7, 0x49, 0xFD, 0xDF, 0xF8, ++ 0x9C, 0xC2, 0x8F, 0x49, 0xDC, 0xF8, 0x00, 0x20, 0x43, 0x1C, 0x9B, 0x06, ++ 0x22, 0xF0, 0xE0, 0x52, 0x03, 0xF0, 0xE0, 0x53, 0x13, 0x43, 0xCC, 0xF8, ++ 0x00, 0x30, 0x0B, 0x68, 0x89, 0x4A, 0x23, 0xF0, 0x01, 0x03, 0x0B, 0x60, ++ 0x13, 0x68, 0x43, 0xF0, 0x02, 0x03, 0x13, 0x60, 0x3B, 0x68, 0x9A, 0x03, ++ 0x00, 0xF1, 0xAF, 0x80, 0x84, 0x4A, 0x28, 0x8C, 0x13, 0x68, 0x80, 0x49, ++ 0x9B, 0xB2, 0x43, 0xEA, 0x00, 0x43, 0x13, 0x60, 0x0B, 0x68, 0x1F, 0x04, ++ 0x00, 0xF1, 0x87, 0x80, 0x75, 0x4B, 0xDF, 0xF8, 0x50, 0xE2, 0x1A, 0x68, ++ 0xDF, 0xF8, 0x4C, 0xC2, 0x7C, 0x48, 0x7D, 0x4F, 0x7D, 0x49, 0x42, 0xF0, ++ 0x01, 0x02, 0x1A, 0x60, 0x4F, 0xF4, 0x40, 0x72, 0xCE, 0xF8, 0x00, 0x20, ++ 0xE2, 0x6D, 0xCC, 0xF8, 0x00, 0x20, 0xB4, 0xF8, 0x60, 0x20, 0x02, 0x60, ++ 0xA2, 0x6B, 0xA0, 0x8F, 0x3A, 0x60, 0xD4, 0xF8, 0x90, 0x21, 0x08, 0x60, ++ 0x91, 0x78, 0x74, 0x4A, 0x02, 0xEB, 0x81, 0x01, 0x50, 0x68, 0x49, 0x69, ++ 0xC7, 0xF8, 0xBC, 0x10, 0x19, 0x68, 0x21, 0xF4, 0xE0, 0x61, 0x19, 0x60, ++ 0x13, 0x68, 0x6F, 0x49, 0x6F, 0x4A, 0x03, 0x43, 0x3B, 0x64, 0x6F, 0x48, ++ 0x6F, 0x4B, 0x08, 0x60, 0x13, 0x60, 0xD6, 0xF8, 0xB0, 0x31, 0x94, 0xF8, ++ 0x63, 0x10, 0x95, 0xF8, 0x23, 0x00, 0x98, 0x47, 0x29, 0x46, 0x20, 0x46, ++ 0xFF, 0xF7, 0x70, 0xFD, 0x09, 0xF0, 0xAC, 0xFB, 0x68, 0x4B, 0x93, 0xF8, ++ 0xB6, 0x30, 0x23, 0xB1, 0x67, 0x4A, 0x13, 0x68, 0x43, 0xF0, 0x01, 0x03, ++ 0x13, 0x60, 0xD6, 0xF8, 0x60, 0x32, 0x98, 0x47, 0x64, 0x4A, 0x65, 0x49, ++ 0xD6, 0xF8, 0x9C, 0x34, 0x11, 0x60, 0x98, 0x47, 0x4D, 0x4A, 0x63, 0x48, ++ 0x13, 0x68, 0x30, 0x24, 0x43, 0xF0, 0x04, 0x03, 0x13, 0x60, 0x01, 0x21, ++ 0x04, 0x60, 0x00, 0x20, 0x17, 0xF0, 0xDE, 0xF9, 0x5E, 0x4B, 0x1B, 0x68, ++ 0x5A, 0x78, 0x22, 0xB1, 0x5D, 0x49, 0x0A, 0x68, 0x42, 0xF0, 0x40, 0x02, ++ 0x0A, 0x60, 0x5C, 0x49, 0x9B, 0x78, 0x0A, 0x68, 0xD8, 0x06, 0x4C, 0xBF, ++ 0x22, 0xF0, 0x00, 0x42, 0x42, 0xF0, 0x00, 0x42, 0x0A, 0x60, 0x58, 0x4A, ++ 0x13, 0xF0, 0x01, 0x0F, 0x13, 0x68, 0x14, 0xBF, 0x43, 0xF4, 0x80, 0x23, ++ 0x23, 0xF4, 0x80, 0x23, 0x13, 0x60, 0xBD, 0xE8, 0xF0, 0x81, 0x3C, 0x4B, ++ 0x1B, 0x68, 0xB3, 0xF1, 0xC8, 0x5F, 0xBF, 0xF4, 0x4D, 0xAF, 0x50, 0x49, ++ 0x50, 0x48, 0xF3, 0x22, 0x19, 0xF0, 0x9C, 0xF8, 0x46, 0xE7, 0xF5, 0xF7, ++ 0x35, 0xFC, 0x00, 0x28, 0x3F, 0xF4, 0x74, 0xAF, 0x6B, 0x68, 0x9A, 0x06, ++ 0x7F, 0xF5, 0x70, 0xAF, 0x28, 0x8C, 0xF5, 0xF7, 0x71, 0xFC, 0x07, 0xF0, ++ 0xB9, 0xFF, 0xD6, 0xF8, 0xE0, 0x33, 0x98, 0x47, 0x94, 0xF8, 0x62, 0x30, ++ 0x04, 0x2B, 0x3F, 0xF4, 0x63, 0xAF, 0xD6, 0xF8, 0x30, 0x33, 0x94, 0xF8, ++ 0x63, 0x00, 0x98, 0x47, 0x5C, 0xE7, 0xF5, 0xF7, 0x3F, 0xFC, 0x00, 0x28, ++ 0x3F, 0xF4, 0x4C, 0xAF, 0xF5, 0xF7, 0x6E, 0xFC, 0xDF, 0xF8, 0xF4, 0x80, ++ 0xD8, 0xF8, 0x00, 0x30, 0x00, 0x02, 0x23, 0xF4, 0xE0, 0x63, 0x00, 0xF4, ++ 0xE0, 0x60, 0x18, 0x43, 0xC8, 0xF8, 0x00, 0x00, 0xD8, 0xF8, 0x00, 0x30, ++ 0x23, 0xF0, 0xE0, 0x03, 0x43, 0xF0, 0x60, 0x03, 0xC8, 0xF8, 0x00, 0x30, ++ 0xD8, 0xF8, 0x00, 0x30, 0x43, 0xF0, 0x04, 0x03, 0xC8, 0xF8, 0x00, 0x30, ++ 0xD8, 0xF8, 0x00, 0x30, 0x43, 0xF0, 0x01, 0x03, 0xC8, 0xF8, 0x00, 0x30, ++ 0x3B, 0x68, 0x1B, 0x04, 0x0F, 0xD4, 0x15, 0x4B, 0x1B, 0x68, 0x9B, 0x03, ++ 0x7F, 0xF5, 0x22, 0xAF, 0xF5, 0xF7, 0x18, 0xFC, 0x00, 0x28, 0x3F, 0xF4, ++ 0x1D, 0xAF, 0x27, 0x4A, 0x13, 0x68, 0x43, 0xF0, 0x02, 0x03, 0x13, 0x60, ++ 0x16, 0xE7, 0xF5, 0xF7, 0xDF, 0xFB, 0x00, 0x28, 0xEB, 0xD0, 0xD8, 0xF8, ++ 0x00, 0x30, 0x23, 0xF0, 0x60, 0x63, 0x43, 0xF0, 0x80, 0x63, 0xC8, 0xF8, ++ 0x00, 0x30, 0xE2, 0xE7, 0x88, 0x1A, 0x17, 0x00, 0x4C, 0x00, 0x32, 0x40, ++ 0x54, 0x00, 0x32, 0x40, 0x64, 0x00, 0x32, 0x40, 0x38, 0x36, 0x17, 0x00, ++ 0xD8, 0x00, 0x32, 0x40, 0x10, 0x19, 0x04, 0x00, 0x04, 0x00, 0x32, 0x40, ++ 0x48, 0x80, 0x32, 0x40, 0x6C, 0x00, 0x32, 0x40, 0x68, 0x00, 0x32, 0x40, ++ 0x14, 0x00, 0x32, 0x40, 0x20, 0x00, 0x32, 0x40, 0x24, 0x00, 0x32, 0x40, ++ 0x98, 0x9C, 0x17, 0x00, 0x74, 0x80, 0x32, 0x40, 0x80, 0x80, 0x32, 0x40, ++ 0x4C, 0xF1, 0x73, 0x8B, 0xC0, 0x07, 0xF9, 0x80, 0x2C, 0x19, 0x17, 0x00, ++ 0x8C, 0x00, 0x32, 0x40, 0xC0, 0xB3, 0x33, 0x40, 0xA0, 0xA0, 0x28, 0x28, ++ 0x38, 0x00, 0x32, 0x40, 0x34, 0x36, 0x17, 0x00, 0x24, 0x02, 0x32, 0x40, ++ 0x80, 0x04, 0x32, 0x40, 0x10, 0x03, 0x32, 0x40, 0x70, 0x79, 0x15, 0x00, ++ 0x40, 0x88, 0x15, 0x00, 0x50, 0x03, 0x32, 0x40, 0x9C, 0x00, 0x32, 0x40, ++ 0x1C, 0x00, 0x32, 0x40, 0x10, 0x00, 0x32, 0x40, 0x2D, 0xE9, 0xF0, 0x47, ++ 0x5B, 0x4B, 0x5C, 0x4A, 0x1D, 0x68, 0xD2, 0xF8, 0x20, 0x80, 0x15, 0xF0, ++ 0x01, 0x05, 0xD8, 0xF8, 0xE4, 0x90, 0x84, 0xB0, 0x00, 0xF0, 0x83, 0x80, ++ 0x1A, 0x68, 0x57, 0x4F, 0x22, 0xF0, 0x01, 0x02, 0x1A, 0x60, 0x00, 0x23, ++ 0x7B, 0x70, 0x01, 0x22, 0x54, 0x48, 0x55, 0x49, 0x03, 0x68, 0x55, 0x4C, ++ 0x43, 0xF0, 0x10, 0x03, 0x03, 0x60, 0x0B, 0x68, 0x00, 0xF5, 0xEC, 0x10, ++ 0x00, 0xF6, 0x6C, 0x70, 0x23, 0xF0, 0x01, 0x03, 0x0B, 0x60, 0x23, 0x68, ++ 0x01, 0x69, 0x00, 0x91, 0x02, 0x20, 0x4E, 0x49, 0x4E, 0x4C, 0x18, 0xF0, ++ 0x9D, 0xFD, 0x3B, 0x78, 0x00, 0x2B, 0x42, 0xD0, 0xD4, 0xF8, 0x3C, 0x31, ++ 0xD8, 0xF8, 0x40, 0x60, 0x00, 0x20, 0x98, 0x47, 0x49, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x62, 0xDB, 0xD4, 0xF8, 0x9C, 0x34, ++ 0xDF, 0xF8, 0x38, 0xA1, 0x98, 0x47, 0xD4, 0xF8, 0x80, 0x34, 0x30, 0x79, ++ 0x98, 0x47, 0x4F, 0xF0, 0x00, 0x0C, 0x33, 0x89, 0xF2, 0x88, 0x71, 0x79, ++ 0x30, 0x79, 0xCD, 0xF8, 0x08, 0xC0, 0x96, 0xF8, 0x0D, 0xC0, 0xCD, 0xF8, ++ 0x04, 0xC0, 0xB6, 0xF8, 0x0A, 0xC0, 0xCD, 0xF8, 0x00, 0xC0, 0xF5, 0xF7, ++ 0x9F, 0xFA, 0xD4, 0xF8, 0x3C, 0x33, 0x96, 0xF9, 0x0C, 0x00, 0x98, 0x47, ++ 0x9A, 0xF8, 0x2A, 0x30, 0x00, 0x2B, 0x33, 0xD0, 0xD4, 0xF8, 0xA8, 0x34, ++ 0xBA, 0xF8, 0x26, 0x00, 0x98, 0x47, 0xBA, 0xF8, 0x26, 0x00, 0xD4, 0xF8, ++ 0xAC, 0x34, 0x98, 0x47, 0xD4, 0xF8, 0xD8, 0x34, 0x49, 0x46, 0x40, 0x46, ++ 0x98, 0x47, 0x00, 0x23, 0xC7, 0xE9, 0x01, 0x33, 0x3B, 0x70, 0x00, 0x2D, ++ 0x33, 0xD0, 0x2B, 0x49, 0x2B, 0x4A, 0x0B, 0x68, 0x23, 0xF4, 0x00, 0x73, ++ 0x0B, 0x60, 0x13, 0x68, 0x23, 0xF0, 0x01, 0x03, 0x13, 0x60, 0x28, 0x4A, ++ 0x28, 0x48, 0x13, 0x68, 0x28, 0x49, 0x23, 0xF0, 0xFF, 0x03, 0x43, 0xF0, ++ 0x10, 0x03, 0x13, 0x60, 0x83, 0x68, 0xD4, 0xF8, 0xA0, 0x22, 0x5A, 0x65, ++ 0x20, 0x23, 0x0B, 0x60, 0x04, 0xB0, 0xBD, 0xE8, 0xF0, 0x87, 0x16, 0x4F, ++ 0x2A, 0x46, 0x81, 0xE7, 0xD4, 0xF8, 0xA0, 0x34, 0xBA, 0xF8, 0x26, 0x00, ++ 0x98, 0x47, 0xBA, 0xF8, 0x26, 0x00, 0xD4, 0xF8, 0xA4, 0x34, 0x98, 0x47, ++ 0xCA, 0xE7, 0x33, 0x7E, 0xFF, 0x2B, 0x99, 0xD1, 0x19, 0x49, 0x1A, 0x48, ++ 0x40, 0xF2, 0x89, 0x12, 0x18, 0xF0, 0x4C, 0xFF, 0x92, 0xE7, 0x40, 0x46, ++ 0x0B, 0xF0, 0xF6, 0xF8, 0xD8, 0xF8, 0x04, 0x30, 0x15, 0x4A, 0x43, 0xF0, ++ 0x01, 0x03, 0xC8, 0xF8, 0x04, 0x30, 0x92, 0xF8, 0xB6, 0x30, 0x00, 0x2B, ++ 0xC7, 0xD0, 0x03, 0xF0, 0x99, 0xF8, 0xC4, 0xE7, 0x10, 0x00, 0x58, 0x40, ++ 0x1C, 0x9E, 0x17, 0x00, 0x3C, 0x36, 0x17, 0x00, 0x94, 0x80, 0x32, 0x40, ++ 0x84, 0x40, 0x04, 0x40, 0x88, 0x00, 0x32, 0x40, 0x88, 0x88, 0x15, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, 0x90, 0xB3, 0x33, 0x40, ++ 0x8C, 0x00, 0x32, 0x40, 0x78, 0x00, 0x32, 0x40, 0x00, 0xED, 0x00, 0xE0, ++ 0x00, 0xE1, 0x00, 0xE0, 0x70, 0x79, 0x15, 0x00, 0xA4, 0x88, 0x15, 0x00, ++ 0x2C, 0x19, 0x17, 0x00, 0xBC, 0x34, 0x17, 0x00, 0xF8, 0xB5, 0x3F, 0x4F, ++ 0x3F, 0x4C, 0x3E, 0x6A, 0x3F, 0x49, 0xD6, 0xF8, 0xE4, 0x50, 0x4F, 0xF4, ++ 0xBE, 0x72, 0x20, 0x46, 0x2B, 0xF0, 0xB0, 0xF9, 0x31, 0x46, 0x4F, 0xF4, ++ 0xA4, 0x62, 0x04, 0xF5, 0xBE, 0x70, 0x2B, 0xF0, 0xA9, 0xF9, 0x29, 0x46, ++ 0x4F, 0xF4, 0x1E, 0x72, 0x04, 0xF2, 0x9C, 0x60, 0x2B, 0xF0, 0xA2, 0xF9, ++ 0x06, 0xF1, 0xEC, 0x01, 0xE8, 0x22, 0x04, 0xF6, 0x14, 0x10, 0x2B, 0xF0, ++ 0x9B, 0xF9, 0x31, 0x6C, 0x1C, 0x22, 0x04, 0xF6, 0xFC, 0x10, 0x2B, 0xF0, ++ 0x95, 0xF9, 0x2F, 0x49, 0x34, 0x22, 0x04, 0xF6, 0x18, 0x20, 0x2B, 0xF0, ++ 0x8F, 0xF9, 0x2D, 0x49, 0x18, 0x22, 0x04, 0xF6, 0x4C, 0x20, 0x2B, 0xF0, ++ 0x89, 0xF9, 0x2B, 0x49, 0x4F, 0xF4, 0x40, 0x72, 0x04, 0xF6, 0x64, 0x20, ++ 0x2B, 0xF0, 0x82, 0xF9, 0x28, 0x49, 0x4F, 0xF4, 0x98, 0x62, 0x04, 0xF6, ++ 0x64, 0x50, 0x2B, 0xF0, 0x7B, 0xF9, 0x26, 0x49, 0x26, 0x48, 0x40, 0x22, ++ 0x2B, 0xF0, 0x76, 0xF9, 0x39, 0x46, 0x28, 0x22, 0x24, 0x48, 0x2B, 0xF0, ++ 0x71, 0xF9, 0x24, 0x49, 0x24, 0x48, 0x60, 0x22, 0x2B, 0xF0, 0x6C, 0xF9, ++ 0x23, 0x4A, 0x24, 0x4B, 0x12, 0x68, 0xD3, 0xF8, 0x84, 0x60, 0xB2, 0xF8, ++ 0x3C, 0xC0, 0xD3, 0xF8, 0x80, 0x20, 0xD3, 0xE9, 0x22, 0x07, 0x41, 0xF2, ++ 0x10, 0x33, 0x41, 0xF2, 0x30, 0x31, 0x24, 0xF8, 0x03, 0xC0, 0x41, 0xF2, ++ 0x2C, 0x33, 0x66, 0x50, 0xE2, 0x50, 0x41, 0xF2, 0x38, 0x36, 0x41, 0xF2, ++ 0x3C, 0x33, 0x41, 0xF2, 0x34, 0x31, 0x18, 0x4A, 0xE2, 0x50, 0xA7, 0x51, ++ 0x17, 0x4B, 0x60, 0x50, 0x05, 0xF5, 0xBC, 0x70, 0x05, 0xF5, 0xCE, 0x71, ++ 0x50, 0xF8, 0x04, 0x2F, 0x1A, 0xB1, 0x14, 0x7B, 0x9C, 0x70, 0x12, 0x89, ++ 0x1A, 0x80, 0x88, 0x42, 0x03, 0xF1, 0x04, 0x03, 0xF4, 0xD1, 0xF8, 0xBD, ++ 0x1C, 0x9E, 0x17, 0x00, 0x00, 0x40, 0x1E, 0x00, 0xE4, 0xB8, 0x17, 0x00, ++ 0x98, 0x9C, 0x17, 0x00, 0x00, 0x88, 0x17, 0x00, 0xF4, 0xE4, 0x17, 0x00, ++ 0x34, 0xE0, 0x17, 0x00, 0xF4, 0xDF, 0x17, 0x00, 0x24, 0x52, 0x1E, 0x00, ++ 0x64, 0x52, 0x1E, 0x00, 0x30, 0x9D, 0x17, 0x00, 0x8C, 0x52, 0x1E, 0x00, ++ 0xC8, 0x35, 0x17, 0x00, 0x2C, 0x19, 0x17, 0x00, 0xEC, 0x34, 0x17, 0x00, ++ 0xEC, 0x52, 0x1E, 0x00, 0x70, 0xB5, 0x65, 0x4A, 0x53, 0x78, 0x00, 0x2B, ++ 0x7F, 0xD1, 0x64, 0x4B, 0x1B, 0x68, 0x3B, 0xB1, 0x63, 0x48, 0xD9, 0x68, ++ 0x00, 0x69, 0x09, 0x1A, 0xB1, 0xF5, 0xFA, 0x6F, 0x00, 0xF1, 0xA5, 0x80, ++ 0x13, 0x78, 0x00, 0x2B, 0x68, 0xD0, 0xD2, 0xE9, 0x01, 0x35, 0x5D, 0x48, ++ 0x5D, 0x4A, 0x5E, 0x49, 0x04, 0x69, 0x0E, 0x68, 0xB2, 0xF8, 0xB0, 0x00, ++ 0xB2, 0xF8, 0xB2, 0x10, 0xB2, 0x8E, 0x2B, 0x44, 0x1B, 0x1B, 0x1B, 0x1A, ++ 0x5B, 0x1A, 0x9B, 0x1A, 0x00, 0x2B, 0xC0, 0xF2, 0x98, 0x80, 0xFF, 0xF7, ++ 0x37, 0xFF, 0x56, 0x4B, 0x1B, 0x6A, 0x1C, 0x6C, 0x23, 0x79, 0x20, 0x89, ++ 0x00, 0x2B, 0x56, 0xD0, 0x2A, 0xF0, 0xC8, 0xFB, 0x02, 0x46, 0x0B, 0x46, ++ 0x2A, 0xF0, 0x78, 0xFA, 0x50, 0x4B, 0x00, 0x22, 0x2A, 0xF0, 0x54, 0xFD, ++ 0x4F, 0x4B, 0x00, 0x22, 0x2A, 0xF0, 0x26, 0xFC, 0x2A, 0xF0, 0x1E, 0xFA, ++ 0x2A, 0xF0, 0xBC, 0xFE, 0x05, 0x46, 0x20, 0x89, 0x2A, 0xF0, 0xB4, 0xFB, ++ 0x02, 0x46, 0x0B, 0x46, 0x00, 0x20, 0x49, 0x49, 0x2A, 0xF0, 0x42, 0xFD, ++ 0x00, 0x22, 0x4F, 0xF0, 0x83, 0x43, 0x2A, 0xF0, 0x13, 0xFC, 0x2A, 0xF0, ++ 0x0B, 0xFA, 0x2A, 0xF0, 0xA9, 0xFE, 0x03, 0x46, 0x20, 0x89, 0x1C, 0x46, ++ 0x2A, 0xF0, 0xA0, 0xFB, 0x34, 0xA3, 0xD3, 0xE9, 0x00, 0x23, 0x2A, 0xF0, ++ 0x2F, 0xFD, 0x00, 0x22, 0x4F, 0xF0, 0x83, 0x43, 0x2A, 0xF0, 0x00, 0xFC, ++ 0x2A, 0xF0, 0xF8, 0xF9, 0x2A, 0xF0, 0x96, 0xFE, 0x3A, 0x4B, 0x3B, 0x49, ++ 0x03, 0xF5, 0x99, 0x56, 0x02, 0x46, 0x35, 0x60, 0x41, 0xF2, 0x24, 0x30, ++ 0x41, 0xF2, 0x28, 0x35, 0x1C, 0x50, 0x5A, 0x51, 0x02, 0x20, 0x18, 0xF0, ++ 0xD5, 0xFB, 0x35, 0x4B, 0x4F, 0xF0, 0x80, 0x42, 0x1A, 0x60, 0x70, 0xBD, ++ 0x33, 0x49, 0x02, 0x20, 0x18, 0xF0, 0xCC, 0xFB, 0x30, 0x4B, 0x4F, 0xF0, ++ 0x00, 0x42, 0x1A, 0x60, 0x70, 0xBD, 0x30, 0x49, 0xF5, 0xE7, 0x2A, 0xF0, ++ 0x71, 0xFB, 0x2F, 0x4B, 0x00, 0x22, 0x2A, 0xF0, 0xD7, 0xFB, 0x25, 0x4B, ++ 0x00, 0x22, 0x2A, 0xF0, 0xFD, 0xFC, 0x24, 0x4B, 0x00, 0x22, 0x2A, 0xF0, ++ 0xCF, 0xFB, 0x2A, 0xF0, 0xC7, 0xF9, 0x2A, 0xF0, 0x65, 0xFE, 0x05, 0x46, ++ 0x20, 0x89, 0x2A, 0xF0, 0x5D, 0xFB, 0x02, 0x46, 0x0B, 0x46, 0x00, 0x20, ++ 0x24, 0x49, 0x2A, 0xF0, 0xEB, 0xFC, 0x00, 0x22, 0x4F, 0xF0, 0x83, 0x43, ++ 0x2A, 0xF0, 0xBC, 0xFB, 0x2A, 0xF0, 0xB4, 0xF9, 0x2A, 0xF0, 0x52, 0xFE, ++ 0x03, 0x46, 0x20, 0x89, 0x1C, 0x46, 0x2A, 0xF0, 0x49, 0xFB, 0x0B, 0xA3, ++ 0xD3, 0xE9, 0x00, 0x23, 0xA7, 0xE7, 0x5A, 0x68, 0x1A, 0x49, 0x02, 0x20, ++ 0x18, 0xF0, 0x92, 0xFB, 0x13, 0x4B, 0x4F, 0xF0, 0x00, 0x42, 0x1A, 0x60, ++ 0x70, 0xBD, 0x17, 0x49, 0xBB, 0xE7, 0x00, 0xBF, 0xAF, 0xF3, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xB3, 0x40, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x70, 0xA2, 0x40, 0x3C, 0x36, 0x17, 0x00, 0xD0, 0x9C, 0x17, 0x00, ++ 0x00, 0x10, 0x50, 0x40, 0x2C, 0x19, 0x17, 0x00, 0xC8, 0x35, 0x17, 0x00, ++ 0x1C, 0x9E, 0x17, 0x00, 0x00, 0x00, 0x6A, 0x40, 0x00, 0x00, 0x50, 0x41, ++ 0x00, 0x00, 0xB9, 0x40, 0x00, 0x40, 0x1E, 0x00, 0x20, 0x89, 0x15, 0x00, ++ 0x00, 0x41, 0x04, 0x40, 0x1C, 0x89, 0x15, 0x00, 0xC4, 0x88, 0x15, 0x00, ++ 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0xA4, 0x40, 0xE8, 0x88, 0x15, 0x00, ++ 0x00, 0x89, 0x15, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, 0x2D, 0xED, 0x02, 0x8B, ++ 0x56, 0x4E, 0xDF, 0xF8, 0x90, 0x81, 0x96, 0xF8, 0xDF, 0x31, 0x96, 0xF8, ++ 0xBF, 0x56, 0xDF, 0xF8, 0x88, 0xB1, 0x53, 0x4C, 0x4F, 0xF4, 0xA4, 0x62, ++ 0x02, 0xFB, 0x03, 0xF7, 0x83, 0xB0, 0x08, 0xEB, 0x07, 0x09, 0x06, 0xF5, ++ 0xBE, 0x71, 0x48, 0x46, 0x01, 0x93, 0x4F, 0xF4, 0x1E, 0x7A, 0x00, 0x97, ++ 0x2B, 0xF0, 0x0E, 0xF8, 0x07, 0xF1, 0xEC, 0x00, 0x0A, 0xFB, 0x05, 0xF5, ++ 0x06, 0xF6, 0x14, 0x11, 0xE8, 0x22, 0x40, 0x44, 0x2B, 0xF0, 0x04, 0xF8, ++ 0x05, 0xEB, 0x0B, 0x03, 0x18, 0x46, 0x52, 0x46, 0x06, 0xF2, 0x9C, 0x61, ++ 0x08, 0xEE, 0x10, 0x3A, 0x2A, 0xF0, 0xFA, 0xFF, 0x06, 0xF6, 0xFC, 0x11, ++ 0x1C, 0x22, 0xD9, 0xF8, 0x40, 0x00, 0x3F, 0x4F, 0xDF, 0xF8, 0x30, 0xA1, ++ 0x2A, 0xF0, 0xF0, 0xFF, 0x06, 0xF6, 0x18, 0x21, 0x34, 0x22, 0x3C, 0x48, ++ 0x2A, 0xF0, 0xEA, 0xFF, 0x31, 0x46, 0x4F, 0xF4, 0xBE, 0x72, 0x3A, 0x48, ++ 0x2A, 0xF0, 0xE4, 0xFF, 0x06, 0xF6, 0x4C, 0x21, 0x18, 0x22, 0x38, 0x48, ++ 0x2A, 0xF0, 0xDE, 0xFF, 0x06, 0xF6, 0x64, 0x21, 0x4F, 0xF4, 0x18, 0x62, ++ 0x35, 0x48, 0x2A, 0xF0, 0xD7, 0xFF, 0x06, 0xF6, 0x64, 0x51, 0x4F, 0xF4, ++ 0x98, 0x62, 0x33, 0x48, 0x33, 0x4E, 0x2A, 0xF0, 0xCF, 0xFF, 0x40, 0x22, ++ 0xA4, 0xF1, 0xC8, 0x01, 0x31, 0x48, 0x2A, 0xF0, 0xC9, 0xFF, 0x28, 0x22, ++ 0xA4, 0xF1, 0x88, 0x01, 0x2F, 0x48, 0x2A, 0xF0, 0xC3, 0xFF, 0x2F, 0x48, ++ 0x60, 0x22, 0xA4, 0xF1, 0x60, 0x01, 0x2A, 0xF0, 0xBD, 0xFF, 0x05, 0xF5, ++ 0xBE, 0x75, 0xAB, 0x44, 0x5B, 0xF8, 0x04, 0x3B, 0x50, 0x46, 0x19, 0x46, ++ 0x4B, 0xB1, 0xA2, 0x78, 0x1A, 0x73, 0xD7, 0xF8, 0xDC, 0x22, 0x25, 0x88, ++ 0x1D, 0x81, 0xC3, 0xE9, 0x45, 0x23, 0x17, 0xF0, 0x01, 0xF9, 0x04, 0x34, ++ 0xB4, 0x42, 0xED, 0xD1, 0x1B, 0x48, 0x22, 0x4D, 0x49, 0x46, 0x17, 0xF0, ++ 0xF9, 0xF8, 0x21, 0x48, 0x49, 0x46, 0x17, 0xF0, 0xA5, 0xF8, 0x00, 0x9E, ++ 0x06, 0xF1, 0xE4, 0x00, 0x18, 0xEE, 0x10, 0x1A, 0x40, 0x44, 0x17, 0xF0, ++ 0x9D, 0xF8, 0x01, 0x9A, 0xA4, 0x24, 0x99, 0x23, 0x14, 0xFB, 0x02, 0x34, ++ 0x08, 0xEB, 0xC4, 0x04, 0x35, 0x44, 0x20, 0x46, 0x17, 0xF0, 0x8E, 0xF8, ++ 0x04, 0xF1, 0x28, 0x00, 0x08, 0x34, 0x17, 0xF0, 0x89, 0xF8, 0xAC, 0x42, ++ 0xF5, 0xD1, 0x00, 0x9B, 0x03, 0xF5, 0xA3, 0x60, 0x40, 0x44, 0x03, 0xB0, ++ 0xBD, 0xEC, 0x02, 0x8B, 0xBD, 0xE8, 0xF0, 0x4F, 0x17, 0xF0, 0x7C, 0xB8, ++ 0x00, 0x40, 0x1E, 0x00, 0xEC, 0x52, 0x1E, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x98, 0x9C, 0x17, 0x00, 0xE4, 0xB8, 0x17, 0x00, 0x00, 0x88, 0x17, 0x00, ++ 0xF4, 0xE4, 0x17, 0x00, 0x34, 0xE0, 0x17, 0x00, 0x10, 0x53, 0x1E, 0x00, ++ 0xF4, 0xDF, 0x17, 0x00, 0x1C, 0x9E, 0x17, 0x00, 0x30, 0x9D, 0x17, 0x00, ++ 0x08, 0x8D, 0x17, 0x00, 0x08, 0x88, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0x68, 0x65, 0x17, 0x00, 0xF8, 0xDE, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x41, ++ 0x6C, 0x4E, 0x6D, 0x4A, 0x33, 0x68, 0xDF, 0xF8, 0x00, 0x82, 0x0D, 0x46, ++ 0x09, 0x8C, 0x9B, 0xB2, 0x43, 0xEA, 0x01, 0x43, 0xD0, 0xF8, 0x90, 0x11, ++ 0x33, 0x60, 0x8B, 0x78, 0x67, 0x49, 0x02, 0xEB, 0x83, 0x03, 0x1C, 0x3E, ++ 0x5B, 0x69, 0x0B, 0x60, 0x31, 0x68, 0x21, 0xF4, 0xE0, 0x61, 0x04, 0x46, ++ 0x50, 0x68, 0x31, 0x60, 0x13, 0x68, 0x62, 0x49, 0x62, 0x4A, 0x03, 0x43, ++ 0x0B, 0x60, 0x62, 0x4B, 0x62, 0x49, 0x11, 0x60, 0x62, 0x4A, 0x1A, 0x60, ++ 0xD8, 0xF8, 0x00, 0x30, 0x9F, 0x03, 0x70, 0xD4, 0x60, 0x4B, 0x1B, 0x68, ++ 0x1A, 0x68, 0xE2, 0xB1, 0x5F, 0x49, 0x0A, 0x60, 0x5A, 0x68, 0xF2, 0xB1, ++ 0xC2, 0xF3, 0x0B, 0x01, 0x00, 0x29, 0x61, 0xD1, 0xE1, 0x68, 0x5C, 0x48, ++ 0x22, 0xF4, 0x7F, 0x62, 0x22, 0xF0, 0x0F, 0x02, 0xC1, 0xF3, 0x0B, 0x01, ++ 0x0A, 0x43, 0x02, 0x60, 0x9A, 0x68, 0xA2, 0xB9, 0x57, 0x4A, 0x21, 0x69, ++ 0x11, 0x60, 0xDB, 0x68, 0xA3, 0xB9, 0x56, 0x4B, 0x62, 0x69, 0x1A, 0x60, ++ 0x12, 0xE0, 0x51, 0x4A, 0xA1, 0x68, 0x11, 0x60, 0x5A, 0x68, 0x00, 0x2A, ++ 0xE0, 0xD1, 0x4F, 0x4A, 0xE1, 0x68, 0x11, 0x60, 0x9A, 0x68, 0x00, 0x2A, ++ 0xEA, 0xD0, 0x4D, 0x49, 0x0A, 0x60, 0xDB, 0x68, 0x00, 0x2B, 0xEA, 0xD0, ++ 0x4B, 0x4A, 0x13, 0x60, 0x4B, 0x4B, 0xD3, 0xF8, 0x60, 0x32, 0x98, 0x47, ++ 0x4A, 0x4B, 0x1B, 0x68, 0x9C, 0x01, 0x06, 0xD4, 0x49, 0x4B, 0x3E, 0x4A, ++ 0x01, 0x21, 0x19, 0x60, 0x13, 0x68, 0x0B, 0x43, 0x13, 0x60, 0x28, 0x46, ++ 0x1B, 0xF0, 0xE4, 0xFA, 0x43, 0x4A, 0x13, 0x68, 0x23, 0xF0, 0x04, 0x03, ++ 0x13, 0x60, 0x01, 0x21, 0x00, 0x20, 0x16, 0xF0, 0x51, 0xFD, 0x41, 0x4B, ++ 0x1B, 0x68, 0x5A, 0x78, 0x22, 0xB1, 0x40, 0x49, 0x0A, 0x68, 0x42, 0xF0, ++ 0x40, 0x02, 0x0A, 0x60, 0x3E, 0x49, 0x9B, 0x78, 0x0A, 0x68, 0xD8, 0x06, ++ 0x4C, 0xBF, 0x22, 0xF0, 0x00, 0x42, 0x42, 0xF0, 0x00, 0x42, 0x0A, 0x60, ++ 0x3A, 0x4A, 0x13, 0xF0, 0x01, 0x0F, 0x13, 0x68, 0x14, 0xBF, 0x43, 0xF4, ++ 0x80, 0x23, 0x23, 0xF4, 0x80, 0x23, 0x13, 0x60, 0xBD, 0xE8, 0xF0, 0x81, ++ 0x2B, 0x49, 0x0A, 0x60, 0xB8, 0xE7, 0xF4, 0xF7, 0xD7, 0xFF, 0x00, 0x28, ++ 0x8A, 0xD0, 0xF5, 0xF7, 0x07, 0xF8, 0x31, 0x4F, 0x3B, 0x68, 0x00, 0x02, ++ 0x23, 0xF4, 0xE0, 0x63, 0x00, 0xF4, 0xE0, 0x60, 0x18, 0x43, 0x38, 0x60, ++ 0x3B, 0x68, 0x23, 0xF0, 0xE0, 0x03, 0x43, 0xF0, 0x60, 0x03, 0x3B, 0x60, ++ 0x3B, 0x68, 0x43, 0xF0, 0x04, 0x03, 0x3B, 0x60, 0x3B, 0x68, 0x43, 0xF0, ++ 0x01, 0x03, 0x3B, 0x60, 0xD8, 0xF8, 0x00, 0x30, 0x1B, 0x04, 0x0F, 0xD4, ++ 0x24, 0x4B, 0x1B, 0x68, 0x9E, 0x03, 0x7F, 0xF5, 0x69, 0xAF, 0xF4, 0xF7, ++ 0xB9, 0xFF, 0x00, 0x28, 0x3F, 0xF4, 0x64, 0xAF, 0x1E, 0x4A, 0x13, 0x68, ++ 0x43, 0xF0, 0x02, 0x03, 0x13, 0x60, 0x5D, 0xE7, 0xF4, 0xF7, 0x80, 0xFF, ++ 0x00, 0x28, 0xEB, 0xD0, 0x33, 0x68, 0x43, 0xF4, 0x00, 0x23, 0x33, 0x60, ++ 0x3B, 0x68, 0x23, 0xF0, 0x60, 0x63, 0x43, 0xF0, 0x80, 0x63, 0x3B, 0x60, ++ 0xE0, 0xE7, 0x00, 0xBF, 0x68, 0x00, 0x32, 0x40, 0x98, 0x9C, 0x17, 0x00, ++ 0xDC, 0x00, 0x32, 0x40, 0x60, 0x00, 0x32, 0x40, 0x74, 0x80, 0x32, 0x40, ++ 0x80, 0x80, 0x32, 0x40, 0x4C, 0xF1, 0x73, 0x8B, 0xC0, 0x07, 0xF9, 0x80, ++ 0xAC, 0x35, 0x17, 0x00, 0x00, 0x02, 0x32, 0x40, 0x04, 0x02, 0x32, 0x40, ++ 0x08, 0x02, 0x32, 0x40, 0x0C, 0x02, 0x32, 0x40, 0x88, 0x1A, 0x17, 0x00, ++ 0x4C, 0x00, 0x32, 0x40, 0x70, 0x80, 0x32, 0x40, 0x34, 0x36, 0x17, 0x00, ++ 0x24, 0x02, 0x32, 0x40, 0x80, 0x04, 0x32, 0x40, 0x10, 0x03, 0x32, 0x40, ++ 0x50, 0x03, 0x32, 0x40, 0x04, 0x00, 0x32, 0x40, 0x2D, 0xE9, 0xF0, 0x41, ++ 0x33, 0x4D, 0xDF, 0xF8, 0xE4, 0x80, 0xD5, 0xF8, 0xD0, 0x34, 0x32, 0x4E, ++ 0x41, 0xF2, 0x12, 0x32, 0x18, 0xF8, 0x02, 0x70, 0x98, 0x47, 0xD5, 0xF8, ++ 0x9C, 0x34, 0x98, 0x47, 0xD8, 0xF8, 0xBC, 0x41, 0xF4, 0xF7, 0x46, 0xF9, ++ 0x2C, 0x49, 0xD5, 0xF8, 0x88, 0x24, 0x0B, 0x68, 0x23, 0xF4, 0x00, 0x73, ++ 0x0B, 0x60, 0x20, 0x79, 0x90, 0x47, 0x23, 0x79, 0x86, 0xF8, 0x2A, 0x30, ++ 0x62, 0x79, 0x86, 0xF8, 0x2B, 0x20, 0x62, 0x7B, 0x86, 0xF8, 0x2C, 0x20, ++ 0xE1, 0x88, 0x20, 0x89, 0x62, 0x89, 0x32, 0x85, 0xFF, 0xB2, 0xB1, 0x84, ++ 0xF0, 0x84, 0xD3, 0xB9, 0xD5, 0xF8, 0xA0, 0x34, 0x98, 0x47, 0xF0, 0x8C, ++ 0xD5, 0xF8, 0xA4, 0x34, 0x98, 0x47, 0x1D, 0x4E, 0x94, 0xF9, 0x0C, 0x00, ++ 0xD5, 0xF8, 0x3C, 0x33, 0x98, 0x47, 0xD5, 0xF8, 0xD4, 0x34, 0x06, 0xF5, ++ 0xA4, 0x61, 0x30, 0x46, 0x98, 0x47, 0x17, 0xF0, 0x0D, 0x0F, 0x0C, 0xD0, ++ 0xD5, 0xF8, 0x54, 0x32, 0xBD, 0xE8, 0xF0, 0x41, 0x18, 0x47, 0xD5, 0xF8, ++ 0xA8, 0x34, 0x98, 0x47, 0xF0, 0x8C, 0xD5, 0xF8, 0xAC, 0x34, 0x98, 0x47, ++ 0xE3, 0xE7, 0xBB, 0x07, 0x14, 0xD5, 0x0F, 0x4A, 0xD8, 0xF8, 0x80, 0x31, ++ 0x11, 0x69, 0x0E, 0x48, 0xD5, 0xF8, 0xE0, 0x21, 0x46, 0x61, 0x05, 0x24, ++ 0x44, 0x77, 0x01, 0xF5, 0x1C, 0x51, 0x43, 0xF0, 0x02, 0x03, 0xC8, 0xF8, ++ 0x80, 0x31, 0x10, 0x31, 0xBD, 0xE8, 0xF0, 0x41, 0x0C, 0x30, 0x10, 0x47, ++ 0xBD, 0xE8, 0xF0, 0x81, 0x88, 0x1A, 0x17, 0x00, 0xBC, 0x34, 0x17, 0x00, ++ 0x90, 0xB3, 0x33, 0x40, 0x7C, 0x41, 0x1E, 0x00, 0x00, 0x10, 0x50, 0x40, ++ 0x1C, 0x9E, 0x17, 0x00, 0x00, 0x40, 0x1E, 0x00, 0x38, 0xB5, 0x50, 0xBB, ++ 0x1A, 0x4B, 0x1A, 0x68, 0x52, 0xB1, 0x1A, 0x4B, 0x1A, 0x49, 0x18, 0x69, ++ 0xD3, 0x68, 0xB1, 0xF8, 0xB0, 0x10, 0x1B, 0x1A, 0x5B, 0x1A, 0xB3, 0xF5, ++ 0xFA, 0x6F, 0x17, 0xD4, 0x16, 0x4A, 0x13, 0x78, 0x7B, 0xB1, 0xD2, 0xE9, ++ 0x01, 0x34, 0x12, 0x48, 0x14, 0x4D, 0x12, 0x49, 0x00, 0x69, 0x2A, 0x68, ++ 0xB1, 0xF8, 0xB0, 0x10, 0x92, 0x8E, 0x23, 0x44, 0x1B, 0x1A, 0x5B, 0x1A, ++ 0x9B, 0x1A, 0x00, 0x2B, 0x0E, 0xDB, 0x0F, 0x4B, 0x4F, 0xF0, 0x80, 0x42, ++ 0x1A, 0x60, 0x38, 0xBD, 0x52, 0x68, 0x0D, 0x49, 0x02, 0x20, 0x18, 0xF0, ++ 0xDB, 0xF8, 0x0A, 0x4B, 0x4F, 0xF0, 0x00, 0x42, 0x1A, 0x60, 0x38, 0xBD, ++ 0x09, 0x49, 0x02, 0x20, 0x18, 0xF0, 0xD2, 0xF8, 0xF5, 0xE7, 0x00, 0xBF, ++ 0xD0, 0x9C, 0x17, 0x00, 0x00, 0x10, 0x50, 0x40, 0x2C, 0x19, 0x17, 0x00, ++ 0x3C, 0x36, 0x17, 0x00, 0xC8, 0x35, 0x17, 0x00, 0x00, 0x41, 0x04, 0x40, ++ 0xE8, 0x88, 0x15, 0x00, 0x28, 0x89, 0x15, 0x00, 0xF0, 0xB5, 0x1B, 0x4B, ++ 0x01, 0x22, 0x85, 0xB0, 0xDA, 0x60, 0xEF, 0xF3, 0x14, 0x81, 0xEF, 0xF3, ++ 0x03, 0x82, 0xEF, 0xF3, 0x09, 0x85, 0xEF, 0xF3, 0x08, 0x84, 0xEF, 0xF3, ++ 0x10, 0x83, 0x70, 0x46, 0xCD, 0xE9, 0x01, 0x30, 0x00, 0x94, 0x13, 0x48, ++ 0x2B, 0x46, 0x18, 0xF0, 0x59, 0xF8, 0x15, 0xB9, 0x34, 0xB9, 0x05, 0xB0, ++ 0xF0, 0xBD, 0x10, 0x48, 0x18, 0xF0, 0x52, 0xF8, 0x00, 0x2C, 0xF8, 0xD0, ++ 0x0E, 0x48, 0x0F, 0x4F, 0x0F, 0x4E, 0x24, 0xF0, 0x0F, 0x04, 0x18, 0xF0, ++ 0x49, 0xF8, 0x04, 0xF5, 0x80, 0x75, 0x06, 0xE0, 0x54, 0xF8, 0x04, 0x1B, ++ 0x30, 0x46, 0x18, 0xF0, 0x41, 0xF8, 0xA5, 0x42, 0xE7, 0xD0, 0x23, 0x07, ++ 0xF6, 0xD1, 0x21, 0x46, 0x38, 0x46, 0x18, 0xF0, 0x39, 0xF8, 0xF1, 0xE7, ++ 0x00, 0xA0, 0x10, 0x40, 0x40, 0x89, 0x15, 0x00, 0x94, 0x89, 0x15, 0x00, ++ 0xA0, 0x89, 0x15, 0x00, 0xAC, 0x89, 0x15, 0x00, 0xB8, 0x89, 0x15, 0x00, ++ 0x30, 0xB4, 0x0C, 0x4C, 0x0C, 0x49, 0xD4, 0xF8, 0x3C, 0x31, 0x0C, 0x4A, ++ 0x0C, 0x4D, 0x43, 0xF0, 0x04, 0x03, 0xC4, 0xF8, 0x3C, 0x31, 0xC0, 0x03, ++ 0x03, 0x24, 0xF4, 0x23, 0x08, 0x60, 0x8C, 0x60, 0x82, 0xF8, 0x44, 0x33, ++ 0xAB, 0x68, 0x07, 0x49, 0xC3, 0xF8, 0x50, 0x11, 0x10, 0x23, 0x30, 0xBC, ++ 0x93, 0x60, 0x70, 0x47, 0x00, 0x00, 0x50, 0x40, 0x00, 0xA0, 0x10, 0x40, ++ 0x00, 0xE1, 0x00, 0xE0, 0x00, 0xED, 0x00, 0xE0, 0xA9, 0xC5, 0x12, 0x00, ++ 0x01, 0x4B, 0x1A, 0x68, 0x1A, 0x60, 0x70, 0x47, 0x00, 0xA0, 0x10, 0x40, ++ 0x02, 0x4A, 0x93, 0x68, 0x23, 0xF0, 0x02, 0x03, 0x93, 0x60, 0x70, 0x47, ++ 0x00, 0xA0, 0x10, 0x40, 0x02, 0x4A, 0x93, 0x68, 0x43, 0xF0, 0x02, 0x03, ++ 0x93, 0x60, 0x70, 0x47, 0x00, 0xA0, 0x10, 0x40, 0x08, 0xB5, 0x06, 0x4B, ++ 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x00, 0xDB, 0xFE, 0xE7, ++ 0x03, 0x49, 0x04, 0x48, 0xBA, 0x22, 0x18, 0xF0, 0x5F, 0xFA, 0xF8, 0xE7, ++ 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x64, 0x7D, 0x15, 0x00, ++ 0x0B, 0x4B, 0x41, 0xF2, 0x1C, 0x32, 0x41, 0xF2, 0x18, 0x31, 0x9A, 0x58, ++ 0x5B, 0x58, 0x72, 0xB1, 0x10, 0xB4, 0x08, 0x4C, 0x00, 0x22, 0x19, 0x68, ++ 0x58, 0x68, 0x08, 0x60, 0x21, 0x68, 0x02, 0x32, 0x91, 0x42, 0x03, 0xF1, ++ 0x08, 0x03, 0xF6, 0xD8, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, 0x70, 0x47, ++ 0x00, 0x40, 0x1E, 0x00, 0x1C, 0x53, 0x1E, 0x00, 0x32, 0x49, 0x33, 0x4B, ++ 0x99, 0x42, 0x10, 0xB5, 0x0C, 0xD2, 0x01, 0x3B, 0x5B, 0x1A, 0x31, 0x4A, ++ 0x23, 0xF0, 0x03, 0x03, 0x04, 0x33, 0x13, 0x44, 0x52, 0xF8, 0x04, 0x0B, ++ 0x41, 0xF8, 0x04, 0x0B, 0x9A, 0x42, 0xF9, 0xD1, 0x2C, 0x4A, 0x2D, 0x4B, ++ 0x9A, 0x42, 0x0A, 0xD2, 0x01, 0x3B, 0x9B, 0x1A, 0x23, 0xF0, 0x03, 0x03, ++ 0x04, 0x33, 0x13, 0x44, 0x00, 0x21, 0x42, 0xF8, 0x04, 0x1B, 0x9A, 0x42, ++ 0xFB, 0xD1, 0x27, 0x49, 0x27, 0x4B, 0x99, 0x42, 0x0D, 0xD2, 0x01, 0x3B, ++ 0x5B, 0x1A, 0x26, 0x4A, 0x23, 0xF0, 0x03, 0x03, 0x04, 0x33, 0x13, 0x44, ++ 0x08, 0x46, 0x52, 0xF8, 0x04, 0x4B, 0x40, 0xF8, 0x04, 0x4B, 0x9A, 0x42, ++ 0xF9, 0xD1, 0x21, 0x4A, 0x21, 0x48, 0xD2, 0xF8, 0x88, 0x30, 0x43, 0xF4, ++ 0x70, 0x03, 0xC2, 0xF8, 0x88, 0x30, 0x91, 0x60, 0x00, 0x23, 0xFF, 0x21, ++ 0xC2, 0x18, 0x01, 0x33, 0x50, 0x2B, 0x82, 0xF8, 0x00, 0x13, 0xF9, 0xD1, ++ 0x1A, 0x4B, 0x1B, 0x68, 0x13, 0xF0, 0x80, 0x6F, 0x16, 0x4B, 0x1B, 0x68, ++ 0x4F, 0xF6, 0xF0, 0x72, 0x03, 0xEA, 0x02, 0x03, 0x0D, 0xD0, 0x4C, 0xF2, ++ 0x40, 0x22, 0x93, 0x42, 0x0D, 0xD0, 0x14, 0x4C, 0xF5, 0xF7, 0xBC, 0xFC, ++ 0xD4, 0xF8, 0x7C, 0x34, 0x98, 0x47, 0xD4, 0xF8, 0x74, 0x34, 0x98, 0x47, ++ 0xFE, 0xE7, 0x4D, 0xF2, 0x10, 0x22, 0x93, 0x42, 0xF1, 0xD1, 0x0E, 0x4B, ++ 0x01, 0x22, 0x1A, 0x60, 0xED, 0xE7, 0x00, 0xBF, 0x80, 0x01, 0x17, 0x00, ++ 0x5C, 0x25, 0x17, 0x00, 0x2C, 0xD2, 0x15, 0x00, 0x60, 0x25, 0x17, 0x00, ++ 0x28, 0x07, 0x18, 0x00, 0x00, 0x00, 0x17, 0x00, 0x80, 0x01, 0x17, 0x00, ++ 0x00, 0x00, 0x12, 0x00, 0x00, 0xED, 0x00, 0xE0, 0x00, 0xE1, 0x00, 0xE0, ++ 0x00, 0x00, 0x50, 0x40, 0x88, 0x1A, 0x17, 0x00, 0x68, 0x28, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x41, 0x72, 0x4F, 0x73, 0x4E, 0x86, 0xB0, 0x3D, 0x46, ++ 0x00, 0x24, 0x21, 0x46, 0x55, 0xF8, 0x04, 0x2B, 0x30, 0x46, 0x01, 0x34, ++ 0xF9, 0xF7, 0x6A, 0xFD, 0x0D, 0x2C, 0xF6, 0xD1, 0xD7, 0xE9, 0x11, 0x21, ++ 0x3B, 0x6C, 0x6C, 0x4D, 0x00, 0x93, 0xCD, 0xE9, 0x01, 0x21, 0x6B, 0x48, ++ 0x79, 0x6B, 0xD7, 0xE9, 0x0E, 0x23, 0xF9, 0xF7, 0x5B, 0xFD, 0x29, 0x68, ++ 0x6A, 0x68, 0xAB, 0x68, 0xE8, 0x68, 0x00, 0x90, 0x66, 0x48, 0xF9, 0xF7, ++ 0x53, 0xFD, 0x69, 0x6A, 0xAA, 0x6A, 0xEB, 0x6A, 0x28, 0x6B, 0xEC, 0x6B, ++ 0xCD, 0xE9, 0x00, 0x04, 0x62, 0x48, 0xF9, 0xF7, 0x49, 0xFD, 0xAC, 0x6A, ++ 0x14, 0xF0, 0xFF, 0x01, 0x68, 0xD1, 0xC4, 0xF3, 0x07, 0x25, 0x14, 0xF4, ++ 0x7F, 0x4F, 0x29, 0x46, 0x44, 0xD1, 0x21, 0x0C, 0x2E, 0xD1, 0xFB, 0x6C, ++ 0x1C, 0x07, 0x23, 0xD5, 0x5A, 0x48, 0xF9, 0xF7, 0x37, 0xFD, 0x3B, 0x6D, ++ 0xD8, 0x07, 0x21, 0xD4, 0x58, 0x48, 0xF9, 0xF7, 0x31, 0xFD, 0xFB, 0x6C, ++ 0x59, 0x07, 0x4C, 0xBF, 0x56, 0x48, 0x57, 0x48, 0xF9, 0xF7, 0x2A, 0xFD, ++ 0x39, 0x6D, 0xEF, 0xF3, 0x10, 0x82, 0xEF, 0xF3, 0x13, 0x83, 0xEF, 0xF3, ++ 0x11, 0x80, 0x00, 0x90, 0x52, 0x48, 0xF9, 0xF7, 0x1F, 0xFD, 0xBC, 0x6C, ++ 0x00, 0x2C, 0x71, 0xD1, 0x7C, 0x6C, 0x00, 0x2C, 0x56, 0xD1, 0x06, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x81, 0x4D, 0x48, 0xF9, 0xF7, 0x13, 0xFD, 0xDD, 0xE7, ++ 0x4C, 0x48, 0xF9, 0xF7, 0x0F, 0xFD, 0xDC, 0xE7, 0xC4, 0xF3, 0x40, 0x63, ++ 0xC4, 0xF3, 0x00, 0x60, 0xC4, 0xF3, 0xC0, 0x42, 0x03, 0x93, 0xC4, 0xF3, ++ 0x80, 0x43, 0xCD, 0xE9, 0x01, 0x20, 0x00, 0x93, 0xC4, 0xF3, 0x00, 0x42, ++ 0xC4, 0xF3, 0x40, 0x43, 0x43, 0x48, 0xF9, 0xF7, 0xFB, 0xFC, 0xBC, 0xE7, ++ 0xC4, 0xF3, 0xC0, 0x33, 0xC4, 0xF3, 0x00, 0x30, 0xC4, 0xF3, 0xC0, 0x22, ++ 0x04, 0x93, 0xC4, 0xF3, 0x40, 0x36, 0xC4, 0xF3, 0x80, 0x23, 0xCD, 0xE9, ++ 0x00, 0x32, 0xCD, 0xE9, 0x02, 0x06, 0xC4, 0xF3, 0x40, 0x23, 0x3A, 0x48, ++ 0xC4, 0xF3, 0x00, 0x22, 0xF9, 0xF7, 0xE4, 0xFC, 0x2D, 0x06, 0xA2, 0xD5, ++ 0x2A, 0x4B, 0x37, 0x48, 0x99, 0x6B, 0xF9, 0xF7, 0xDD, 0xFC, 0x9C, 0xE7, ++ 0xC4, 0xF3, 0xC0, 0x16, 0xC4, 0xF3, 0x40, 0x10, 0xC4, 0xF3, 0x00, 0x12, ++ 0xC4, 0xF3, 0xC0, 0x03, 0xCD, 0xE9, 0x02, 0x06, 0xCD, 0xE9, 0x00, 0x32, ++ 0x2F, 0x48, 0xC4, 0xF3, 0x40, 0x03, 0x04, 0xF0, 0x01, 0x02, 0xF9, 0xF7, ++ 0xC9, 0xFC, 0x26, 0x06, 0x81, 0xD5, 0x69, 0x6B, 0x2B, 0x48, 0xF9, 0xF7, ++ 0xC3, 0xFC, 0x7C, 0xE7, 0x2A, 0x48, 0x2B, 0x4F, 0x2B, 0x4E, 0x24, 0xF0, ++ 0x0F, 0x04, 0xF9, 0xF7, 0xBB, 0xFC, 0x04, 0xF5, 0x80, 0x75, 0x06, 0xE0, ++ 0x54, 0xF8, 0x04, 0x1B, 0x30, 0x46, 0xF9, 0xF7, 0xB3, 0xFC, 0xA5, 0x42, ++ 0x97, 0xD0, 0x23, 0x07, 0xF6, 0xD1, 0x21, 0x46, 0x38, 0x46, 0xF9, 0xF7, ++ 0xAB, 0xFC, 0xF1, 0xE7, 0x21, 0x48, 0xDF, 0xF8, 0x7C, 0x80, 0x1F, 0x4E, ++ 0x24, 0xF0, 0x0F, 0x04, 0xF9, 0xF7, 0xA2, 0xFC, 0x04, 0xF5, 0x80, 0x75, ++ 0x07, 0xE0, 0x54, 0xF8, 0x04, 0x1B, 0x30, 0x46, 0xF9, 0xF7, 0x9A, 0xFC, ++ 0xA5, 0x42, 0x3F, 0xF4, 0x7B, 0xAF, 0x22, 0x07, 0xF5, 0xD1, 0x21, 0x46, ++ 0x40, 0x46, 0xF9, 0xF7, 0x91, 0xFC, 0xF0, 0xE7, 0xE4, 0x60, 0x17, 0x00, ++ 0xC0, 0x89, 0x15, 0x00, 0x00, 0xED, 0x00, 0xE0, 0xD0, 0x89, 0x15, 0x00, ++ 0x1C, 0x8A, 0x15, 0x00, 0x50, 0x8A, 0x15, 0x00, 0xF0, 0x8B, 0x15, 0x00, ++ 0x10, 0x8C, 0x15, 0x00, 0x34, 0x8C, 0x15, 0x00, 0x40, 0x8C, 0x15, 0x00, ++ 0x4C, 0x8C, 0x15, 0x00, 0x24, 0x8C, 0x15, 0x00, 0x00, 0x8C, 0x15, 0x00, ++ 0x8C, 0x8B, 0x15, 0x00, 0x04, 0x8B, 0x15, 0x00, 0x7C, 0x8B, 0x15, 0x00, ++ 0x90, 0x8A, 0x15, 0x00, 0xF4, 0x8A, 0x15, 0x00, 0x80, 0x8C, 0x15, 0x00, ++ 0xAC, 0x89, 0x15, 0x00, 0xB8, 0x89, 0x15, 0x00, 0xA0, 0x89, 0x15, 0x00, ++ 0x08, 0xB5, 0x02, 0x48, 0xF9, 0xF7, 0x60, 0xFC, 0xFE, 0xE7, 0x00, 0xBF, ++ 0x8C, 0x8C, 0x15, 0x00, 0x04, 0x46, 0x08, 0xB5, 0x10, 0x48, 0xF9, 0xF7, ++ 0x57, 0xFC, 0x30, 0x2C, 0x10, 0xD0, 0x40, 0x2C, 0x16, 0xD0, 0x20, 0x2C, ++ 0x10, 0xD0, 0x0D, 0x48, 0xF9, 0xF7, 0x4E, 0xFC, 0x0C, 0x48, 0xF9, 0xF7, ++ 0x4B, 0xFC, 0xFF, 0xF7, 0xD1, 0xFE, 0x0B, 0x48, 0xF9, 0xF7, 0x46, 0xFC, ++ 0xFF, 0xF7, 0xE0, 0xFF, 0x09, 0x48, 0xF9, 0xF7, 0x41, 0xFC, 0xF1, 0xE7, ++ 0x08, 0x48, 0xF9, 0xF7, 0x3D, 0xFC, 0xED, 0xE7, 0x07, 0x48, 0xF9, 0xF7, ++ 0x39, 0xFC, 0xE9, 0xE7, 0x98, 0x8C, 0x15, 0x00, 0xE8, 0x8C, 0x15, 0x00, ++ 0xF4, 0x8C, 0x15, 0x00, 0x00, 0x8D, 0x15, 0x00, 0xD0, 0x8C, 0x15, 0x00, ++ 0xC0, 0x8C, 0x15, 0x00, 0xDC, 0x8C, 0x15, 0x00, 0x4F, 0xF0, 0x10, 0x03, ++ 0x00, 0xF0, 0x0C, 0xB8, 0x4F, 0xF0, 0x20, 0x03, 0x00, 0xF0, 0x08, 0xB8, ++ 0x4F, 0xF0, 0x30, 0x03, 0x00, 0xF0, 0x04, 0xB8, 0x4F, 0xF0, 0x40, 0x03, ++ 0x00, 0xF0, 0x00, 0xB8, 0xEF, 0xF3, 0x08, 0x80, 0x4F, 0xF0, 0x04, 0x01, ++ 0x72, 0x46, 0x0A, 0x42, 0x01, 0xD0, 0xEF, 0xF3, 0x09, 0x80, 0x9C, 0x46, ++ 0x24, 0x49, 0x02, 0x68, 0x0A, 0x60, 0x04, 0x31, 0x42, 0x68, 0x0A, 0x60, ++ 0x04, 0x31, 0x82, 0x68, 0x0A, 0x60, 0x04, 0x31, 0xC2, 0x68, 0x0A, 0x60, ++ 0x04, 0x31, 0xF0, 0xC1, 0x47, 0x46, 0x0F, 0x60, 0x04, 0x31, 0x4F, 0x46, ++ 0x0F, 0x60, 0x04, 0x31, 0x57, 0x46, 0x0F, 0x60, 0x04, 0x31, 0x5F, 0x46, ++ 0x0F, 0x60, 0x04, 0x31, 0x02, 0x69, 0x0A, 0x60, 0x08, 0x31, 0x42, 0x69, ++ 0x0A, 0x60, 0x04, 0x31, 0x82, 0x69, 0x0A, 0x60, 0x04, 0x31, 0xC2, 0x69, ++ 0x0A, 0x60, 0x04, 0x31, 0x03, 0x46, 0x20, 0x33, 0x4F, 0xF4, 0x00, 0x76, ++ 0x32, 0x42, 0x00, 0xD0, 0x04, 0x33, 0x75, 0x46, 0x4F, 0xF0, 0x10, 0x06, ++ 0x35, 0x42, 0x00, 0xD1, 0x48, 0x33, 0x0C, 0x46, 0x10, 0x3C, 0x23, 0x60, ++ 0xEF, 0xF3, 0x09, 0x82, 0x0A, 0x60, 0x04, 0x31, 0xEF, 0xF3, 0x08, 0x82, ++ 0x0A, 0x60, 0x04, 0x31, 0x72, 0x46, 0x0A, 0x60, 0x04, 0x31, 0xEF, 0xF3, ++ 0x14, 0x82, 0x0A, 0x60, 0x03, 0x4B, 0x60, 0x46, 0x01, 0x49, 0x98, 0x47, ++ 0xFE, 0xE7, 0x00, 0x00, 0xE4, 0x60, 0x17, 0x00, 0x3D, 0xCA, 0x12, 0x00, ++ 0x08, 0xB5, 0x08, 0x4B, 0x00, 0x22, 0x5A, 0x70, 0x18, 0xF0, 0x3E, 0xF8, ++ 0x1A, 0xF0, 0x14, 0xFC, 0x05, 0x4B, 0xD3, 0xF8, 0xA8, 0x31, 0x98, 0x47, ++ 0x16, 0xF0, 0x88, 0xFB, 0xBD, 0xE8, 0x08, 0x40, 0x18, 0xF0, 0x42, 0xB8, ++ 0x70, 0x28, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x2D, 0xE9, 0xF8, 0x4F, ++ 0x4B, 0x4E, 0x4C, 0x4A, 0x4C, 0x49, 0x4D, 0x48, 0x17, 0xF0, 0x6E, 0xFD, ++ 0x33, 0x68, 0xDB, 0x78, 0x00, 0x2B, 0x40, 0xF0, 0x89, 0x80, 0x62, 0xB6, ++ 0xBF, 0xF3, 0x4F, 0x8F, 0xBF, 0xF3, 0x6F, 0x8F, 0xDF, 0xF8, 0x3C, 0x81, ++ 0xDF, 0xF8, 0x3C, 0x91, 0x45, 0x4D, 0x46, 0x4F, 0x46, 0x4C, 0xDF, 0xF8, ++ 0x38, 0xB1, 0x4F, 0xF0, 0x01, 0x0A, 0x33, 0x68, 0xDB, 0x78, 0xFB, 0xB9, ++ 0x98, 0xF8, 0x00, 0x30, 0x13, 0xB3, 0x18, 0xF0, 0x71, 0xFE, 0xEF, 0xF3, ++ 0x10, 0x83, 0xDB, 0x07, 0x02, 0xD4, 0x72, 0xB6, 0xC9, 0xF8, 0x00, 0xA0, ++ 0x2B, 0x68, 0x3A, 0x68, 0x01, 0x33, 0x2B, 0x60, 0xBA, 0xB1, 0x00, 0x2B, ++ 0xE9, 0xD0, 0x01, 0x3B, 0xD9, 0xF8, 0x00, 0x20, 0x2B, 0x60, 0x00, 0x2B, ++ 0xE3, 0xD1, 0x00, 0x2A, 0xE1, 0xD0, 0x62, 0xB6, 0x33, 0x68, 0xDB, 0x78, ++ 0x00, 0x2B, 0xDF, 0xD0, 0xFF, 0xF7, 0x2C, 0xFD, 0x98, 0xF8, 0x00, 0x30, ++ 0x00, 0x2B, 0xDC, 0xD1, 0x16, 0xF0, 0xF8, 0xFA, 0xD9, 0xE7, 0xD4, 0xF8, ++ 0x7C, 0x32, 0x98, 0x47, 0x33, 0x68, 0xDB, 0x78, 0x00, 0x2B, 0x37, 0xD1, ++ 0xDB, 0xF8, 0x00, 0x30, 0x1B, 0x78, 0x01, 0x2B, 0x17, 0xD0, 0xBF, 0xF3, ++ 0x4F, 0x8F, 0x30, 0xBF, 0xBF, 0xF3, 0x6F, 0x8F, 0x00, 0xBF, 0x00, 0xBF, ++ 0x00, 0xBF, 0x00, 0xBF, 0xD4, 0xF8, 0x78, 0x32, 0x98, 0x47, 0x00, 0x28, ++ 0xF1, 0xD0, 0x33, 0x68, 0xDB, 0x78, 0x23, 0xBB, 0xD4, 0xF8, 0x84, 0x32, ++ 0x98, 0x47, 0x2B, 0x68, 0x00, 0x2B, 0xB0, 0xD0, 0xC5, 0xE7, 0x1D, 0x4B, ++ 0x1B, 0x78, 0x00, 0x2B, 0xE3, 0xD0, 0x1C, 0x4B, 0x1B, 0x68, 0x1B, 0x78, ++ 0x03, 0x2B, 0x17, 0xD0, 0x01, 0x2B, 0x05, 0xD0, 0x00, 0x2B, 0xDA, 0xD1, ++ 0x18, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0xD6, 0xD0, 0x17, 0x4B, 0x5B, 0x78, ++ 0x00, 0x2B, 0xD2, 0xD0, 0x16, 0x4A, 0x13, 0x68, 0x43, 0xF4, 0x80, 0x53, ++ 0x13, 0x60, 0xCC, 0xE7, 0xFF, 0xF7, 0xEA, 0xFC, 0xC4, 0xE7, 0xFF, 0xF7, ++ 0xEF, 0xFC, 0xD7, 0xE7, 0xFB, 0xF7, 0x32, 0xFE, 0x00, 0x28, 0xEF, 0xD1, ++ 0x0B, 0x4B, 0x1B, 0x68, 0x1B, 0x78, 0xDF, 0xE7, 0x10, 0x20, 0xFF, 0xF7, ++ 0xB1, 0xFC, 0x72, 0xE7, 0x34, 0x36, 0x17, 0x00, 0xDC, 0xD1, 0x15, 0x00, ++ 0x00, 0xD2, 0x15, 0x00, 0x1C, 0x8D, 0x15, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x80, 0xB6, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x3D, 0x61, 0x17, 0x00, ++ 0x74, 0x36, 0x17, 0x00, 0x3C, 0x61, 0x17, 0x00, 0x70, 0x28, 0x17, 0x00, ++ 0x00, 0x60, 0x50, 0x40, 0x3C, 0x36, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, ++ 0x78, 0x36, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x41, 0xEF, 0xF3, 0x10, 0x83, ++ 0xDA, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x72, 0x4B, 0x01, 0x22, 0x1A, 0x60, ++ 0x71, 0x4C, 0x72, 0x4A, 0x23, 0x68, 0x72, 0x49, 0x72, 0x4D, 0x01, 0x33, ++ 0x4F, 0xF4, 0x80, 0x60, 0x23, 0x60, 0x17, 0xF0, 0xF9, 0xFC, 0x4F, 0xF0, ++ 0x00, 0x40, 0x16, 0xF0, 0x4D, 0xFA, 0xD5, 0xF8, 0xEC, 0x30, 0x98, 0x47, ++ 0x6C, 0x4B, 0x6D, 0x4A, 0x19, 0x68, 0x21, 0xF0, 0x7F, 0x41, 0x19, 0x60, ++ 0x19, 0x68, 0x41, 0xF0, 0x10, 0x01, 0x19, 0x60, 0x11, 0x69, 0x64, 0x31, ++ 0x13, 0x69, 0xCB, 0x1A, 0x00, 0x2B, 0xFB, 0xDA, 0x66, 0x4E, 0xD5, 0xF8, ++ 0x10, 0x24, 0x33, 0x68, 0x40, 0xF2, 0x11, 0x17, 0x3B, 0x43, 0x33, 0x60, ++ 0x90, 0x47, 0x60, 0x49, 0x62, 0x4A, 0x0B, 0x68, 0xDF, 0xF8, 0xAC, 0xC1, ++ 0x23, 0xF0, 0x10, 0x03, 0x0B, 0x60, 0x33, 0x68, 0x23, 0xF4, 0x88, 0x73, ++ 0x23, 0xF0, 0x01, 0x03, 0x33, 0x60, 0x0B, 0x23, 0x10, 0x68, 0x13, 0x60, ++ 0xDC, 0xF8, 0x00, 0x30, 0xDB, 0x06, 0x18, 0xD5, 0x59, 0x4B, 0x40, 0xF2, ++ 0x01, 0x2C, 0x19, 0x68, 0xC3, 0xF8, 0x00, 0xC0, 0x19, 0x60, 0x33, 0x68, ++ 0xA2, 0xF5, 0x7C, 0x72, 0x1F, 0x43, 0x37, 0x60, 0x11, 0x68, 0x02, 0x31, ++ 0x13, 0x68, 0x5B, 0x1A, 0x00, 0x2B, 0xFB, 0xDB, 0x4E, 0x4A, 0x13, 0x68, ++ 0x23, 0xF4, 0x88, 0x73, 0x23, 0xF0, 0x01, 0x03, 0x13, 0x60, 0x4C, 0x4B, ++ 0x18, 0x60, 0x0A, 0xF0, 0xBD, 0xFF, 0x00, 0x20, 0x16, 0xF0, 0x8E, 0xF8, ++ 0x00, 0x28, 0x6C, 0xD0, 0x49, 0x4E, 0x09, 0xF0, 0xA1, 0xFB, 0xB3, 0x79, ++ 0x00, 0x2B, 0x4F, 0xD0, 0x47, 0x4B, 0x1B, 0x68, 0x1B, 0x78, 0x03, 0x2B, ++ 0x66, 0xD0, 0x33, 0x78, 0x00, 0x2B, 0x47, 0xD0, 0x44, 0x4B, 0x77, 0x79, ++ 0x1A, 0x68, 0x96, 0xF9, 0x07, 0x30, 0x96, 0xF9, 0x04, 0xE0, 0xDF, 0xF8, ++ 0x20, 0xC1, 0x41, 0x48, 0xDC, 0xF8, 0x00, 0x10, 0xD5, 0xF8, 0xE0, 0x81, ++ 0x37, 0x4D, 0x02, 0xF0, 0x0F, 0x02, 0x17, 0x44, 0x7F, 0xB2, 0x3B, 0x44, ++ 0x73, 0x45, 0xA8, 0xBF, 0x73, 0x46, 0x5F, 0xFA, 0x83, 0xFE, 0x21, 0xF0, ++ 0xFF, 0x01, 0x41, 0xEA, 0x0E, 0x01, 0xCC, 0xF8, 0x00, 0x10, 0x02, 0x68, ++ 0x22, 0xF0, 0xFF, 0x02, 0x42, 0xEA, 0x0E, 0x02, 0x02, 0x60, 0xDC, 0xF8, ++ 0x00, 0x10, 0xDA, 0x1E, 0x5F, 0xFA, 0x82, 0xFE, 0x21, 0xF4, 0x7F, 0x21, ++ 0x41, 0xEA, 0x0E, 0x31, 0xCC, 0xF8, 0x00, 0x10, 0x02, 0x68, 0xB6, 0xF8, ++ 0x08, 0xC0, 0x22, 0xF4, 0x7F, 0x22, 0x42, 0xEA, 0x0E, 0x32, 0x02, 0x60, ++ 0x2A, 0x69, 0x2A, 0x48, 0x5D, 0xB2, 0x4E, 0xF6, 0x60, 0x21, 0x01, 0xFB, ++ 0x0C, 0x21, 0xF5, 0x71, 0xC0, 0x47, 0x00, 0x23, 0x26, 0x48, 0xB3, 0x71, ++ 0x29, 0x46, 0x3A, 0x46, 0x17, 0xF0, 0xFC, 0xFB, 0x24, 0x49, 0x4F, 0xF4, ++ 0x80, 0x60, 0x17, 0xF0, 0x47, 0xFC, 0x08, 0xF0, 0x85, 0xFE, 0x18, 0xB1, ++ 0x4F, 0xF4, 0x80, 0x10, 0x16, 0xF0, 0x74, 0xF9, 0x23, 0x68, 0x33, 0xB1, ++ 0x0D, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x23, 0x60, 0x0B, 0xB9, 0x02, 0xB1, ++ 0x62, 0xB6, 0xBD, 0xE8, 0xF0, 0x81, 0x4F, 0xF0, 0x80, 0x60, 0x16, 0xF0, ++ 0x89, 0xF9, 0x8D, 0xE7, 0x17, 0x4B, 0x1B, 0x68, 0x00, 0x22, 0x1A, 0x60, ++ 0xF8, 0xF7, 0x8C, 0xFA, 0x33, 0x78, 0x00, 0x2B, 0xDA, 0xD0, 0xB3, 0x79, ++ 0x00, 0x2B, 0x8F, 0xD1, 0xD6, 0xE7, 0x00, 0xBF, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x30, 0x8E, 0x15, 0x00, 0xCC, 0xB5, 0x15, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x00, 0x04, 0x32, 0x40, 0x00, 0x10, 0x50, 0x40, ++ 0x18, 0x00, 0x34, 0x40, 0x10, 0x05, 0x32, 0x40, 0x00, 0x10, 0x34, 0x40, ++ 0x80, 0x35, 0x17, 0x00, 0x78, 0x36, 0x17, 0x00, 0x1C, 0x01, 0x32, 0x40, ++ 0xD4, 0xB3, 0x33, 0x40, 0x8C, 0x35, 0x17, 0x00, 0x30, 0x8D, 0x15, 0x00, ++ 0x40, 0x8D, 0x15, 0x00, 0x00, 0x38, 0x18, 0x00, 0x0C, 0x05, 0x32, 0x40, ++ 0xAC, 0xB3, 0x33, 0x40, 0x22, 0x4B, 0x1B, 0x68, 0x1B, 0x78, 0x03, 0x2B, ++ 0x01, 0xD0, 0x01, 0x20, 0x70, 0x47, 0x20, 0x4B, 0xD3, 0xF8, 0x04, 0x31, ++ 0x1A, 0x03, 0x10, 0xB5, 0x16, 0xD4, 0x00, 0x22, 0x93, 0x00, 0x03, 0xF1, ++ 0x60, 0x43, 0x03, 0xF5, 0x61, 0x43, 0x01, 0x2A, 0xD3, 0xF8, 0x00, 0x01, ++ 0x1B, 0x68, 0x00, 0xEA, 0x03, 0x00, 0x04, 0xD0, 0x30, 0xB9, 0x02, 0x2A, ++ 0x05, 0xD0, 0x01, 0x32, 0xEE, 0xE7, 0x30, 0xF4, 0x00, 0x23, 0xFA, 0xD0, ++ 0x01, 0x20, 0x10, 0xBD, 0x12, 0x4B, 0x1C, 0x68, 0x41, 0xF6, 0x33, 0x70, ++ 0x20, 0x40, 0xF7, 0xD1, 0x63, 0x00, 0x0F, 0xD4, 0x00, 0x2C, 0x07, 0xDA, ++ 0x0E, 0x4B, 0xD3, 0xF8, 0x68, 0x34, 0x98, 0x47, 0x0D, 0x4B, 0x4F, 0xF0, ++ 0x00, 0x42, 0x1A, 0x60, 0x08, 0x4B, 0x4F, 0xF4, 0x00, 0x22, 0xC3, 0xF8, ++ 0x84, 0x21, 0xD0, 0xE7, 0x07, 0x4B, 0xD3, 0xF8, 0x78, 0x34, 0x98, 0x47, ++ 0x06, 0x4B, 0x4F, 0xF0, 0x80, 0x42, 0x1A, 0x60, 0xE6, 0xE7, 0x00, 0xBF, ++ 0x78, 0x36, 0x17, 0x00, 0x00, 0xE1, 0x00, 0xE0, 0x1C, 0x41, 0x04, 0x40, ++ 0x88, 0x1A, 0x17, 0x00, 0x08, 0x41, 0x04, 0x40, 0x38, 0xB5, 0x3F, 0x4C, ++ 0x3F, 0x4D, 0x23, 0x68, 0x3F, 0x49, 0x03, 0xF0, 0x0F, 0x03, 0x02, 0x20, ++ 0x2B, 0x70, 0x17, 0xF0, 0x9F, 0xFB, 0x23, 0x68, 0x18, 0x07, 0x40, 0xD0, ++ 0x3B, 0x49, 0x3C, 0x4A, 0x0B, 0x68, 0x00, 0x20, 0x23, 0xF0, 0x00, 0x43, ++ 0x0B, 0x60, 0x20, 0x60, 0x13, 0x68, 0x59, 0x07, 0xFC, 0xD5, 0x38, 0x4B, ++ 0x35, 0x49, 0x38, 0x4A, 0x04, 0x20, 0x18, 0x60, 0x0B, 0x68, 0x43, 0xF0, ++ 0x00, 0x43, 0x0B, 0x60, 0x13, 0x68, 0x43, 0xF0, 0x00, 0x63, 0x13, 0x60, ++ 0x33, 0x4B, 0x1B, 0x78, 0x01, 0x22, 0x6A, 0x70, 0x9B, 0xB1, 0x32, 0x49, ++ 0x32, 0x4A, 0x0B, 0x68, 0x23, 0xF4, 0x00, 0x13, 0x0B, 0x60, 0x13, 0x68, ++ 0x00, 0x2B, 0xFC, 0xD0, 0x2F, 0x4B, 0x19, 0x68, 0x21, 0xF0, 0x01, 0x01, ++ 0x19, 0x60, 0x19, 0x68, 0x01, 0x20, 0x41, 0xF0, 0x02, 0x01, 0x19, 0x60, ++ 0x10, 0x60, 0x20, 0x4B, 0x2A, 0x4A, 0x2B, 0x49, 0x20, 0x20, 0x18, 0x60, ++ 0x13, 0x68, 0x43, 0xF0, 0x10, 0x03, 0x13, 0x60, 0x0B, 0x68, 0x1B, 0x78, ++ 0x03, 0x2B, 0x26, 0xD0, 0x01, 0x2B, 0x06, 0xD0, 0x38, 0xBD, 0x1E, 0x4A, ++ 0x13, 0x68, 0x23, 0xF0, 0x00, 0x63, 0x13, 0x60, 0xD0, 0xE7, 0x22, 0x4A, ++ 0x13, 0x68, 0x5B, 0x03, 0xFC, 0xD5, 0x21, 0x4A, 0x11, 0x69, 0x1C, 0x31, ++ 0x13, 0x69, 0xCB, 0x1A, 0x00, 0x2B, 0xFB, 0xDA, 0x1E, 0x49, 0x1F, 0x4A, ++ 0x0B, 0x68, 0x43, 0xF4, 0x00, 0x43, 0x0B, 0x60, 0x13, 0x6D, 0x43, 0xF4, ++ 0x00, 0x43, 0x13, 0x65, 0xD3, 0x6D, 0x23, 0xF0, 0x03, 0x03, 0x43, 0xF0, ++ 0x00, 0x43, 0x43, 0xF0, 0x01, 0x03, 0xD3, 0x65, 0x38, 0xBD, 0x17, 0x4B, ++ 0x1A, 0x68, 0x42, 0xF0, 0x01, 0x02, 0x1A, 0x60, 0x1B, 0x68, 0x5A, 0x07, ++ 0xD2, 0xD5, 0x14, 0x4B, 0x4F, 0xF4, 0x00, 0x72, 0x1A, 0x60, 0x38, 0xBD, ++ 0x38, 0x00, 0x32, 0x40, 0x70, 0x28, 0x17, 0x00, 0x50, 0x8D, 0x15, 0x00, ++ 0x74, 0x80, 0x32, 0x40, 0x6C, 0x80, 0x32, 0x40, 0x70, 0x80, 0x32, 0x40, ++ 0x48, 0x80, 0x32, 0x40, 0x3D, 0x61, 0x17, 0x00, 0x58, 0x40, 0x34, 0x40, ++ 0x40, 0x42, 0x04, 0x40, 0x18, 0x00, 0x58, 0x40, 0x10, 0x00, 0x58, 0x40, ++ 0x78, 0x36, 0x17, 0x00, 0x20, 0x10, 0x04, 0x40, 0x00, 0x10, 0x50, 0x40, ++ 0x14, 0x00, 0x24, 0x40, 0x00, 0x60, 0x50, 0x40, 0x84, 0x40, 0x04, 0x40, ++ 0x00, 0x41, 0x04, 0x40, 0x00, 0x28, 0x00, 0xF0, 0xE7, 0x80, 0x2D, 0xE9, ++ 0xF8, 0x4F, 0x90, 0xF8, 0x64, 0x30, 0x04, 0x46, 0x0B, 0xB9, 0xBD, 0xE8, ++ 0xF8, 0x8F, 0x83, 0x4B, 0x83, 0x4A, 0x84, 0x4F, 0xDF, 0xF8, 0x2C, 0x92, ++ 0xDF, 0xF8, 0x64, 0x82, 0x82, 0x4E, 0x83, 0x48, 0x0D, 0x46, 0x83, 0x49, ++ 0x4F, 0xF0, 0x02, 0x0B, 0xD1, 0xF8, 0x70, 0xC4, 0xC3, 0xF8, 0x80, 0xB1, ++ 0x92, 0x68, 0x80, 0x49, 0xC2, 0xF8, 0x44, 0xC0, 0x01, 0x22, 0xC3, 0xF8, ++ 0x00, 0xB0, 0x3A, 0x70, 0xD9, 0xF8, 0x10, 0x20, 0x0B, 0x68, 0x7A, 0x60, ++ 0x23, 0xF0, 0x02, 0x03, 0x0B, 0x60, 0xD8, 0xF8, 0x00, 0x10, 0xB6, 0xF8, ++ 0xB2, 0xC0, 0x8B, 0x8F, 0x01, 0x68, 0x63, 0x44, 0xB3, 0xEB, 0x41, 0x1F, ++ 0x4F, 0xEA, 0x41, 0x1A, 0xD1, 0xD2, 0x74, 0x49, 0x58, 0x46, 0x17, 0xF0, ++ 0xC9, 0xFA, 0xD9, 0xF8, 0x10, 0x20, 0xFB, 0x68, 0x9B, 0x1A, 0x00, 0x2B, ++ 0x80, 0xF2, 0xB6, 0x80, 0xB4, 0xF8, 0x68, 0x20, 0x6E, 0x4B, 0xA8, 0x68, ++ 0x41, 0xF2, 0x13, 0x31, 0x01, 0x2A, 0x5C, 0x5C, 0x40, 0xF2, 0x9F, 0x80, ++ 0x01, 0x3A, 0x00, 0xFB, 0x02, 0xAA, 0x41, 0xF2, 0x13, 0x31, 0x52, 0x46, ++ 0x5B, 0x5C, 0x68, 0x49, 0x02, 0x20, 0x17, 0xF0, 0xAD, 0xFA, 0xD8, 0xF8, ++ 0x00, 0x30, 0xB6, 0xF8, 0xB2, 0x00, 0x9A, 0x8F, 0x60, 0x49, 0x64, 0x4B, ++ 0xDF, 0xF8, 0xA8, 0xC1, 0x1C, 0x69, 0x0B, 0x68, 0x02, 0x44, 0xAA, 0xEB, ++ 0x02, 0x02, 0x22, 0xF0, 0x03, 0x05, 0x03, 0xF0, 0x03, 0x03, 0x2B, 0x43, ++ 0x5E, 0x4D, 0x0B, 0x60, 0x2B, 0x68, 0xBA, 0x60, 0x43, 0xF0, 0x01, 0x03, ++ 0x2B, 0x60, 0xDC, 0xF8, 0x00, 0x30, 0xDC, 0xF8, 0x00, 0x10, 0xC3, 0xF3, ++ 0x09, 0x03, 0x21, 0xF4, 0x7F, 0x71, 0x43, 0xF0, 0x01, 0x03, 0x21, 0xF0, ++ 0x03, 0x01, 0x0B, 0x43, 0xCC, 0xF8, 0x00, 0x30, 0x2B, 0x68, 0x22, 0x44, ++ 0x5B, 0x07, 0xFA, 0x60, 0x03, 0xD5, 0x52, 0x4B, 0x4F, 0xF4, 0x00, 0x72, ++ 0x1A, 0x60, 0x51, 0x49, 0x51, 0x4A, 0x0B, 0x68, 0x43, 0xF0, 0x08, 0x03, ++ 0x0B, 0x60, 0x13, 0x68, 0x00, 0x2B, 0xFC, 0xD0, 0x4E, 0x4C, 0x45, 0x49, ++ 0x23, 0x68, 0x43, 0xF0, 0x02, 0x03, 0x23, 0x60, 0x01, 0x23, 0x13, 0x60, ++ 0x0B, 0x68, 0x45, 0x4A, 0x43, 0xF0, 0x01, 0x03, 0x0B, 0x60, 0x11, 0x69, ++ 0x01, 0xF5, 0x96, 0x71, 0x13, 0x69, 0x5B, 0x1A, 0x00, 0x2B, 0xFB, 0xDB, ++ 0x45, 0x4B, 0x1B, 0x68, 0x1B, 0x78, 0x01, 0x2B, 0x7F, 0xF4, 0x5D, 0xAF, ++ 0x43, 0x49, 0x44, 0x4C, 0x4B, 0x6A, 0x24, 0x68, 0x23, 0xF0, 0xFF, 0x03, ++ 0x43, 0xF0, 0xDF, 0x03, 0x4B, 0x62, 0x4B, 0x6A, 0x23, 0xF4, 0x7F, 0x43, ++ 0x43, 0xF4, 0x5F, 0x43, 0x4B, 0x62, 0xB4, 0xB1, 0x3D, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x3F, 0xDB, 0xE3, 0x68, 0x62, 0x68, ++ 0x3A, 0x49, 0x02, 0x20, 0x17, 0xF0, 0x3C, 0xFA, 0xB6, 0xF8, 0xB2, 0x10, ++ 0xE2, 0x68, 0x2D, 0x4B, 0x52, 0x1A, 0x4F, 0xF4, 0x80, 0x20, 0x04, 0x21, ++ 0x98, 0x60, 0x1A, 0x63, 0x99, 0x60, 0x34, 0x49, 0x2F, 0x4A, 0x0B, 0x68, ++ 0x43, 0xF4, 0x00, 0x43, 0x0B, 0x60, 0x13, 0x6D, 0x43, 0xF4, 0x00, 0x43, ++ 0x13, 0x65, 0xD3, 0x6D, 0x23, 0xF0, 0x03, 0x03, 0x43, 0xF0, 0x00, 0x43, ++ 0x43, 0xF0, 0x01, 0x03, 0xD3, 0x65, 0x13, 0x68, 0x43, 0xF4, 0x80, 0x53, ++ 0x13, 0x60, 0x1E, 0xE7, 0x70, 0x47, 0x41, 0xF2, 0x14, 0x32, 0x9C, 0x5C, ++ 0x01, 0x2C, 0x7F, 0xF6, 0x5E, 0xAF, 0x5C, 0x5C, 0xDC, 0xB1, 0x5A, 0x5C, ++ 0x01, 0x3A, 0x00, 0xFB, 0x02, 0xAA, 0x56, 0xE7, 0x14, 0x4A, 0x22, 0x49, ++ 0x41, 0xF2, 0x13, 0x33, 0x58, 0x46, 0xD3, 0x5C, 0x52, 0x46, 0x17, 0xF0, ++ 0x03, 0xFA, 0x54, 0xE7, 0x12, 0x69, 0xE3, 0x68, 0x9A, 0x1A, 0x10, 0x1A, ++ 0x00, 0x28, 0xBA, 0xDA, 0x1B, 0x49, 0x1C, 0x48, 0x40, 0xF2, 0x4F, 0x22, ++ 0x17, 0xF0, 0x20, 0xFC, 0xB2, 0xE7, 0x9A, 0x5C, 0x3A, 0xE7, 0x00, 0xBF, ++ 0x00, 0xE1, 0x00, 0xE0, 0x00, 0xED, 0x00, 0xE0, 0x3C, 0x36, 0x17, 0x00, ++ 0x2C, 0x19, 0x17, 0x00, 0x40, 0x80, 0x32, 0x40, 0x88, 0x1A, 0x17, 0x00, ++ 0x84, 0x00, 0x32, 0x40, 0x54, 0x8D, 0x15, 0x00, 0x00, 0x40, 0x1E, 0x00, ++ 0x70, 0x8D, 0x15, 0x00, 0x00, 0x10, 0x50, 0x40, 0x84, 0x40, 0x04, 0x40, ++ 0x00, 0x41, 0x04, 0x40, 0x10, 0x00, 0x58, 0x40, 0x40, 0x42, 0x04, 0x40, ++ 0x18, 0x00, 0x58, 0x40, 0x78, 0x36, 0x17, 0x00, 0x00, 0x60, 0x50, 0x40, ++ 0xD0, 0x9C, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, 0xC8, 0x8D, 0x15, 0x00, ++ 0x14, 0x00, 0x24, 0x40, 0x5C, 0x8D, 0x15, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x80, 0x8D, 0x15, 0x00, 0xC8, 0x35, 0x17, 0x00, 0x70, 0xB5, 0x45, 0x4C, ++ 0x21, 0x68, 0x0B, 0x78, 0x73, 0xB9, 0x44, 0x4B, 0x44, 0x4D, 0x9B, 0x68, ++ 0x01, 0x22, 0x2A, 0x70, 0x00, 0x2B, 0x3E, 0xD1, 0x0A, 0x78, 0x42, 0x49, ++ 0x01, 0x23, 0x02, 0x20, 0x17, 0xF0, 0xAC, 0xF9, 0x01, 0x23, 0x2B, 0x70, ++ 0x3F, 0x4B, 0x1B, 0x68, 0x1B, 0x78, 0x01, 0x2B, 0x40, 0xD0, 0x02, 0x2B, ++ 0x28, 0xD0, 0x11, 0xF0, 0x8F, 0xFD, 0x28, 0xB3, 0x3B, 0x4B, 0xD3, 0xF8, ++ 0xF8, 0x31, 0x0B, 0xBB, 0x3A, 0x4B, 0x3B, 0x4D, 0x1B, 0x68, 0x95, 0xF8, ++ 0x24, 0x20, 0xC3, 0xF3, 0x40, 0x63, 0x13, 0x43, 0x18, 0xD0, 0x6B, 0x7F, ++ 0xB3, 0xB9, 0x37, 0x4E, 0xD6, 0xF8, 0xF4, 0x30, 0x98, 0x47, 0x88, 0xB1, ++ 0xF8, 0xF7, 0x7E, 0xFB, 0x34, 0x4A, 0xC0, 0xB2, 0x10, 0x70, 0x00, 0x28, ++ 0x35, 0xD0, 0x23, 0x68, 0x1B, 0x78, 0x01, 0x2B, 0x04, 0xD8, 0xD6, 0xF8, ++ 0xB4, 0x34, 0x98, 0x47, 0x23, 0x68, 0x1B, 0x78, 0x02, 0x2B, 0x22, 0xD0, ++ 0x70, 0xBD, 0x93, 0xF8, 0x64, 0x20, 0x42, 0xB9, 0x1B, 0x68, 0x00, 0x2B, ++ 0xC0, 0xD0, 0x93, 0xF8, 0x62, 0x20, 0x00, 0x2A, 0xF5, 0xD0, 0x02, 0x2A, ++ 0xF6, 0xD1, 0x0A, 0x78, 0x1F, 0x49, 0x00, 0x23, 0x02, 0x20, 0x17, 0xF0, ++ 0x67, 0xF9, 0x00, 0x23, 0x2B, 0x70, 0x70, 0xBD, 0x23, 0x68, 0x1B, 0x78, ++ 0x03, 0x2B, 0x15, 0xD0, 0xFB, 0xF7, 0x5A, 0xFA, 0x00, 0x28, 0xE1, 0xD0, ++ 0x1E, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0xB4, 0xD0, 0x70, 0xBD, 0x28, 0x6A, ++ 0xD6, 0xF8, 0xB8, 0x34, 0xD0, 0xF8, 0xE4, 0x10, 0xBD, 0xE8, 0x70, 0x40, ++ 0x18, 0x47, 0x19, 0x49, 0x02, 0x20, 0x17, 0xF0, 0x4B, 0xF9, 0xC4, 0xE7, ++ 0xF8, 0xF7, 0x3C, 0xFB, 0x13, 0x4B, 0x18, 0x70, 0xFB, 0xF7, 0x40, 0xFA, ++ 0x18, 0xB1, 0x10, 0x4B, 0xD3, 0xF8, 0xB4, 0x34, 0x98, 0x47, 0x12, 0x4A, ++ 0x13, 0x68, 0x5B, 0x03, 0xFC, 0xD5, 0x11, 0x4A, 0x11, 0x69, 0x1C, 0x31, ++ 0x13, 0x69, 0xCB, 0x1A, 0x00, 0x2B, 0xFB, 0xDA, 0x70, 0xBD, 0x00, 0xBF, ++ 0x74, 0x36, 0x17, 0x00, 0x00, 0x88, 0x17, 0x00, 0x3C, 0x61, 0x17, 0x00, ++ 0xD8, 0x8D, 0x15, 0x00, 0x78, 0x36, 0x17, 0x00, 0x20, 0x62, 0x17, 0x00, ++ 0x4C, 0x00, 0x32, 0x40, 0x1C, 0x9E, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x3D, 0x61, 0x17, 0x00, 0x9C, 0x4E, 0x17, 0x00, 0xD4, 0x8D, 0x15, 0x00, ++ 0x20, 0x10, 0x04, 0x40, 0x00, 0x10, 0x50, 0x40, 0x38, 0xB5, 0x43, 0x4D, ++ 0x6B, 0x78, 0x03, 0xB9, 0x38, 0xBD, 0x42, 0x48, 0x42, 0x49, 0x03, 0x68, ++ 0x42, 0x4A, 0x23, 0xF0, 0x10, 0x03, 0x03, 0x60, 0x4B, 0x6F, 0x43, 0xF0, ++ 0x10, 0x03, 0x4B, 0x67, 0x13, 0x68, 0x23, 0xF0, 0x00, 0x73, 0x13, 0x60, ++ 0x00, 0xBF, 0x00, 0xBF, 0x00, 0xBF, 0x3C, 0x4C, 0x3C, 0x49, 0x23, 0x68, ++ 0x43, 0xF0, 0x00, 0x43, 0x23, 0x60, 0x02, 0x20, 0x17, 0xF0, 0xF6, 0xF8, ++ 0x00, 0x23, 0x22, 0x46, 0x6B, 0x70, 0x13, 0x68, 0x5B, 0x00, 0xFC, 0xD5, ++ 0x36, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x3C, 0xDB, ++ 0x31, 0x4B, 0x34, 0x4A, 0x19, 0x68, 0x21, 0xF0, 0x80, 0x41, 0x19, 0x60, ++ 0x19, 0x68, 0x21, 0xF0, 0x00, 0x41, 0x19, 0x60, 0x13, 0x68, 0x00, 0x2B, ++ 0xFC, 0xD0, 0x2F, 0x4B, 0x2F, 0x48, 0x19, 0x68, 0x2F, 0x4C, 0x41, 0xF0, ++ 0x01, 0x01, 0x19, 0x60, 0x19, 0x68, 0x01, 0x25, 0x21, 0xF0, 0x02, 0x01, ++ 0x19, 0x60, 0x15, 0x60, 0x03, 0x68, 0x43, 0xF4, 0x00, 0x13, 0x03, 0x60, ++ 0x23, 0x68, 0x1B, 0x78, 0x03, 0x2B, 0x2E, 0xD0, 0x01, 0x2B, 0x26, 0xD0, ++ 0x26, 0x4B, 0x1B, 0x78, 0x53, 0xB1, 0x1D, 0x4A, 0x25, 0x49, 0x13, 0x68, ++ 0x43, 0xF0, 0x00, 0x73, 0x13, 0x60, 0x02, 0x20, 0xBD, 0xE8, 0x38, 0x40, ++ 0x17, 0xF0, 0xB8, 0xB8, 0x16, 0x4A, 0x20, 0x49, 0x53, 0x6F, 0x23, 0xF0, ++ 0x10, 0x03, 0x53, 0x67, 0x02, 0x20, 0xBD, 0xE8, 0x38, 0x40, 0x17, 0xF0, ++ 0xAD, 0xB8, 0x1C, 0x4B, 0x2A, 0x78, 0x1B, 0x68, 0x03, 0xF0, 0x0F, 0x03, ++ 0x9A, 0x42, 0xBB, 0xD0, 0x19, 0x49, 0x1A, 0x48, 0x4F, 0xF4, 0x3A, 0x72, ++ 0x17, 0xF0, 0xCA, 0xFA, 0xB4, 0xE7, 0x18, 0x4A, 0x13, 0x68, 0x23, 0xF4, ++ 0x00, 0x43, 0x13, 0x60, 0xD2, 0xE7, 0x16, 0x4A, 0x13, 0x68, 0x23, 0xF0, ++ 0x01, 0x03, 0x13, 0x60, 0x0D, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0xCC, 0xD1, ++ 0xD6, 0xE7, 0x00, 0xBF, 0x70, 0x28, 0x17, 0x00, 0x10, 0x00, 0x58, 0x40, ++ 0x00, 0x00, 0x50, 0x40, 0xE0, 0x50, 0x34, 0x40, 0x48, 0x80, 0x32, 0x40, ++ 0xEC, 0x8D, 0x15, 0x00, 0x38, 0x36, 0x17, 0x00, 0x40, 0x42, 0x04, 0x40, ++ 0x18, 0x00, 0x58, 0x40, 0x58, 0x40, 0x34, 0x40, 0x78, 0x36, 0x17, 0x00, ++ 0x4C, 0x36, 0x17, 0x00, 0x28, 0x8E, 0x15, 0x00, 0x38, 0x00, 0x32, 0x40, ++ 0x70, 0x79, 0x15, 0x00, 0xF0, 0x8D, 0x15, 0x00, 0x14, 0x00, 0x24, 0x40, ++ 0x84, 0x40, 0x04, 0x40, 0x2D, 0xE9, 0xF0, 0x47, 0x1F, 0x48, 0x20, 0x4D, ++ 0x15, 0xF0, 0x36, 0xFE, 0x1F, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0x28, 0xDB, 0x1D, 0x4E, 0x28, 0x68, 0xDF, 0xF8, 0x7C, 0x90, ++ 0xDF, 0xF8, 0x60, 0x80, 0xD9, 0xF8, 0x00, 0x30, 0x1A, 0x89, 0x54, 0x24, ++ 0x02, 0xFB, 0x04, 0x42, 0x00, 0x21, 0xF2, 0xF7, 0x91, 0xFD, 0x4F, 0xF0, ++ 0x00, 0x0A, 0x58, 0x27, 0x29, 0x68, 0x33, 0x68, 0x1F, 0xFA, 0x8A, 0xF2, ++ 0x04, 0xFB, 0x02, 0x11, 0x07, 0xFB, 0x02, 0x33, 0xCB, 0x64, 0x40, 0x46, ++ 0x15, 0xF0, 0x16, 0xFE, 0xD9, 0xF8, 0x00, 0x30, 0x0A, 0xF1, 0x01, 0x0A, ++ 0x1A, 0x89, 0x1F, 0xFA, 0x8A, 0xF3, 0x9A, 0x42, 0xEA, 0xD2, 0xBD, 0xE8, ++ 0xF0, 0x87, 0x28, 0x68, 0x08, 0x4E, 0x10, 0xB1, 0x33, 0x68, 0x00, 0x2B, ++ 0xD2, 0xD1, 0x07, 0x48, 0x07, 0x49, 0x5B, 0x22, 0x17, 0xF0, 0x54, 0xFA, ++ 0x28, 0x68, 0xCB, 0xE7, 0x20, 0x58, 0x17, 0x00, 0x40, 0x61, 0x17, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x14, 0x63, 0x18, 0x00, 0x40, 0x8E, 0x15, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x78, 0x36, 0x17, 0x00, 0x0D, 0x49, 0x00, 0xEB, ++ 0xC0, 0x03, 0x10, 0xB4, 0x9C, 0x00, 0x00, 0x22, 0x01, 0xEB, 0x83, 0x03, ++ 0x16, 0x30, 0x0A, 0x51, 0x01, 0xEB, 0xC0, 0x00, 0x4F, 0xF4, 0x55, 0x64, ++ 0x4F, 0xF0, 0xFF, 0x31, 0xC3, 0xE9, 0x02, 0x41, 0xC0, 0xE9, 0x01, 0x22, ++ 0x5D, 0xF8, 0x04, 0x4B, 0x5A, 0x60, 0x83, 0xF8, 0x20, 0x20, 0x5A, 0x61, ++ 0x19, 0x61, 0x70, 0x47, 0x44, 0x61, 0x17, 0x00, 0x10, 0xB5, 0x04, 0x46, ++ 0x80, 0x6C, 0x18, 0xB1, 0xF9, 0xF7, 0xCE, 0xFE, 0x00, 0x23, 0xA3, 0x64, ++ 0x10, 0xBD, 0x00, 0xBF, 0x2D, 0xE9, 0xF0, 0x41, 0x38, 0x4C, 0xDF, 0xF8, ++ 0xF0, 0x80, 0x38, 0x4F, 0x38, 0x4D, 0x04, 0xF5, 0x20, 0x76, 0xC4, 0xF8, ++ 0x00, 0x80, 0xF3, 0xF7, 0x0F, 0xFE, 0x80, 0x03, 0x60, 0x60, 0xF3, 0xF7, ++ 0x0B, 0xFE, 0x01, 0x23, 0x01, 0x30, 0x03, 0xFA, 0x00, 0xF0, 0x01, 0x38, ++ 0x00, 0x23, 0xC4, 0xE9, 0x02, 0x03, 0xC4, 0xE9, 0x05, 0x33, 0xC4, 0xE9, ++ 0x07, 0x33, 0x27, 0x61, 0x2B, 0x68, 0x2A, 0x68, 0x1B, 0x02, 0xD2, 0xB2, ++ 0x9B, 0xB2, 0x13, 0x43, 0x63, 0x62, 0x2B, 0x68, 0x2A, 0x68, 0x1B, 0x02, ++ 0xD2, 0xB2, 0x9B, 0xB2, 0x13, 0x43, 0xA3, 0x62, 0x2B, 0x68, 0x2A, 0x68, ++ 0x1B, 0x02, 0xD2, 0xB2, 0x9B, 0xB2, 0x13, 0x43, 0xE3, 0x62, 0x2B, 0x68, ++ 0x2A, 0x68, 0x1B, 0x02, 0xD2, 0xB2, 0x9B, 0xB2, 0x13, 0x43, 0x4F, 0xF4, ++ 0x08, 0x51, 0x4F, 0xF4, 0x7C, 0x12, 0xA2, 0x63, 0xC4, 0xE9, 0x0C, 0x31, ++ 0x40, 0x34, 0xB4, 0x42, 0xC5, 0xD1, 0x1B, 0x4C, 0x1B, 0x4F, 0x18, 0x4E, ++ 0xDF, 0xF8, 0x60, 0x80, 0x04, 0xF5, 0x80, 0x75, 0x27, 0x60, 0xF3, 0xF7, ++ 0xCF, 0xFD, 0x80, 0x03, 0x60, 0x60, 0xF3, 0xF7, 0xCB, 0xFD, 0x01, 0x23, ++ 0x01, 0x30, 0x03, 0xFA, 0x00, 0xF0, 0x01, 0x38, 0x00, 0x23, 0xC4, 0xE9, ++ 0x02, 0x03, 0xC4, 0xE9, 0x05, 0x33, 0xC4, 0xE9, 0x07, 0x33, 0x26, 0x61, ++ 0xD8, 0xF8, 0x00, 0x20, 0xD8, 0xF8, 0x00, 0x10, 0xA3, 0x62, 0x12, 0x02, ++ 0xC9, 0xB2, 0x92, 0xB2, 0x0A, 0x43, 0x4F, 0xF4, 0x7C, 0x11, 0x62, 0x62, ++ 0xC4, 0xE9, 0x0B, 0x33, 0xC4, 0xE9, 0x0D, 0x31, 0x40, 0x34, 0xAC, 0x42, ++ 0xD8, 0xD1, 0xBD, 0xE8, 0xF0, 0x81, 0x00, 0xBF, 0x04, 0x39, 0x18, 0x00, ++ 0x04, 0x07, 0xFF, 0xFF, 0xA0, 0x00, 0x32, 0x40, 0x04, 0x38, 0x18, 0x00, ++ 0x1E, 0xAB, 0xDC, 0xBA, 0xF0, 0xB5, 0x16, 0x4C, 0x24, 0x68, 0x24, 0x78, ++ 0x1D, 0x46, 0xE3, 0x07, 0x87, 0xB0, 0x16, 0x46, 0x06, 0xD5, 0x50, 0x19, ++ 0x00, 0x21, 0x08, 0x22, 0xF2, 0xF7, 0xA8, 0xFC, 0x07, 0xB0, 0xF0, 0xBD, ++ 0xC3, 0x7E, 0x00, 0x93, 0x02, 0xAC, 0x07, 0x46, 0x07, 0xF1, 0x12, 0x03, ++ 0x20, 0x46, 0x07, 0xF1, 0x0C, 0x02, 0x1A, 0xF0, 0xE7, 0xFF, 0x2A, 0x46, ++ 0x31, 0x46, 0x20, 0x46, 0x1B, 0xF0, 0x08, 0xF8, 0x20, 0x46, 0x1B, 0xF0, ++ 0xA3, 0xF8, 0x35, 0x44, 0x21, 0x46, 0x04, 0xAA, 0x60, 0x1A, 0x14, 0xF8, ++ 0x01, 0x3B, 0x43, 0x55, 0x94, 0x42, 0xF9, 0xD1, 0x07, 0xB0, 0xF0, 0xBD, ++ 0x34, 0x36, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, 0x83, 0x6C, 0x90, 0xF8, ++ 0x42, 0xA0, 0x90, 0xF8, 0x33, 0x40, 0x90, 0xF8, 0x35, 0x20, 0x87, 0x88, ++ 0x90, 0xF8, 0x32, 0x80, 0xD3, 0xF8, 0x24, 0xC0, 0xC6, 0x6C, 0x93, 0xF8, ++ 0x20, 0xE0, 0xA3, 0xEB, 0x0A, 0x05, 0xA8, 0x35, 0x22, 0x44, 0x01, 0x3F, ++ 0xAA, 0xEB, 0x04, 0x04, 0x3A, 0x44, 0x08, 0xEB, 0x05, 0x09, 0x2C, 0xF0, ++ 0x02, 0x07, 0x04, 0xEB, 0x09, 0x0B, 0x5F, 0x62, 0x54, 0x19, 0x03, 0xF1, ++ 0x0C, 0x0A, 0xB8, 0xF1, 0x00, 0x0F, 0x03, 0xD0, 0x09, 0xF1, 0xFF, 0x32, ++ 0xC6, 0xE9, 0x09, 0x52, 0xF2, 0x6C, 0xC3, 0xF8, 0x14, 0xB0, 0x00, 0x25, ++ 0x42, 0xF4, 0x80, 0x72, 0x1C, 0xF0, 0x01, 0x0F, 0x9C, 0x61, 0x1D, 0x61, ++ 0xC6, 0xF8, 0x20, 0xA0, 0xDD, 0x61, 0xF2, 0x64, 0x16, 0xD1, 0x40, 0x6A, ++ 0x00, 0xF4, 0x60, 0x14, 0xB4, 0xF5, 0x60, 0x1F, 0x01, 0xD0, 0x80, 0x02, ++ 0x0E, 0xD4, 0x09, 0x48, 0x71, 0x44, 0x01, 0xEB, 0xC1, 0x01, 0x00, 0xEB, ++ 0x81, 0x01, 0x47, 0xF0, 0x01, 0x07, 0x91, 0xF8, 0x20, 0x00, 0x5F, 0x62, ++ 0x01, 0x30, 0x81, 0xF8, 0x20, 0x00, 0xF2, 0x64, 0x00, 0x22, 0x1A, 0x61, ++ 0xBD, 0xE8, 0xF0, 0x8F, 0x44, 0x61, 0x17, 0x00, 0x0A, 0x88, 0x03, 0x7F, ++ 0x0A, 0x49, 0x12, 0xF4, 0x00, 0x5F, 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, ++ 0x03, 0x12, 0x4F, 0xF4, 0xA4, 0x60, 0x92, 0xF8, 0xDA, 0x20, 0x00, 0xFB, ++ 0x03, 0x13, 0x14, 0xBF, 0x42, 0xF0, 0x02, 0x02, 0x02, 0xF0, 0xFD, 0x02, ++ 0x83, 0xF8, 0xDA, 0x20, 0x70, 0x47, 0x00, 0xBF, 0x18, 0x88, 0x17, 0x00, ++ 0x43, 0x6A, 0x2D, 0xE9, 0xF0, 0x47, 0x91, 0x46, 0x9A, 0x02, 0xD0, 0xF8, ++ 0x48, 0x80, 0x06, 0x46, 0x0F, 0x46, 0x29, 0xD5, 0x03, 0xF4, 0x60, 0x13, ++ 0xB3, 0xF5, 0x20, 0x1F, 0x24, 0xD0, 0x50, 0x4C, 0x88, 0xF8, 0x20, 0x90, ++ 0xD4, 0xF8, 0x80, 0x33, 0x39, 0x46, 0x30, 0x46, 0x98, 0x47, 0x31, 0x8B, ++ 0x48, 0xF6, 0x88, 0x63, 0x99, 0x42, 0x68, 0xD0, 0x4A, 0x4B, 0xB1, 0x6C, ++ 0x93, 0xF8, 0x05, 0x31, 0x00, 0x2B, 0x59, 0xD1, 0xB3, 0x68, 0x00, 0x2B, ++ 0x49, 0xDB, 0x4B, 0x6A, 0x46, 0x4A, 0xCA, 0x60, 0x23, 0xF0, 0x10, 0x03, ++ 0x4B, 0x62, 0x30, 0x46, 0xD4, 0xF8, 0x04, 0x34, 0x8E, 0x60, 0x3A, 0x46, ++ 0x98, 0x47, 0x00, 0x20, 0xBD, 0xE8, 0xF0, 0x87, 0xD6, 0xF8, 0x2C, 0xA0, ++ 0x08, 0xF1, 0x24, 0x04, 0x0A, 0xF1, 0x40, 0x00, 0x53, 0x46, 0x53, 0xF8, ++ 0x04, 0x5B, 0x44, 0xF8, 0x04, 0x5F, 0x83, 0x42, 0xF9, 0xD1, 0xF3, 0x8B, ++ 0x9D, 0x04, 0xCA, 0xD5, 0x38, 0x4B, 0x39, 0x49, 0x1A, 0x68, 0x73, 0x7F, ++ 0xB2, 0xF9, 0x00, 0x20, 0x4F, 0xF4, 0x1E, 0x70, 0x00, 0xFB, 0x03, 0x13, ++ 0x00, 0x2A, 0xD3, 0xF8, 0x4C, 0x41, 0x38, 0xDB, 0x41, 0x46, 0xDA, 0xF8, ++ 0x14, 0x20, 0xD4, 0xF8, 0x9C, 0x30, 0xC8, 0xF8, 0x40, 0x20, 0xDA, 0xF8, ++ 0x24, 0x20, 0xC8, 0xF8, 0x50, 0x20, 0xC3, 0xF3, 0xC2, 0x22, 0x05, 0x2A, ++ 0xC8, 0xF8, 0x3C, 0x30, 0x31, 0xD0, 0xDA, 0xF8, 0x3C, 0x30, 0x5C, 0x07, ++ 0x5E, 0xBF, 0xD8, 0xF8, 0x2C, 0x30, 0x23, 0xF4, 0xC0, 0x73, 0xC8, 0xF8, ++ 0x2C, 0x30, 0x88, 0x46, 0x9F, 0xE7, 0x32, 0x8B, 0x33, 0x65, 0x48, 0xF6, ++ 0x88, 0x63, 0x9A, 0x42, 0xAF, 0xD1, 0x8B, 0x6B, 0x23, 0xF4, 0x7F, 0x43, ++ 0x43, 0xF4, 0x60, 0x63, 0x8B, 0x63, 0xA8, 0xE7, 0xF2, 0x8B, 0x10, 0x07, ++ 0xA5, 0xD4, 0xB2, 0x68, 0x52, 0x00, 0x58, 0xBF, 0x81, 0xF8, 0x39, 0x30, ++ 0x9F, 0xE7, 0xF3, 0x6C, 0x19, 0x48, 0xDA, 0x6A, 0x16, 0xF0, 0xFA, 0xFD, ++ 0x90, 0xE7, 0x00, 0x2C, 0xC4, 0xD1, 0x17, 0x49, 0x17, 0x48, 0x40, 0xF2, ++ 0x4B, 0x12, 0x17, 0xF0, 0x6B, 0xF8, 0xB1, 0x6C, 0xBD, 0xE7, 0x03, 0xF4, ++ 0xC0, 0x63, 0xD8, 0xF8, 0x4C, 0x20, 0x94, 0xF8, 0xA1, 0x00, 0xB3, 0xF5, ++ 0x80, 0x6F, 0x14, 0xBF, 0x4F, 0xF4, 0x80, 0x34, 0x4F, 0xF4, 0x00, 0x34, ++ 0x22, 0xF4, 0x40, 0x33, 0x23, 0x43, 0x20, 0xB1, 0x43, 0xF4, 0x80, 0x23, ++ 0xC8, 0xF8, 0x4C, 0x30, 0xB7, 0xE7, 0x23, 0xF4, 0x80, 0x23, 0xC8, 0xF8, ++ 0x4C, 0x30, 0xB2, 0xE7, 0x88, 0x1A, 0x17, 0x00, 0x2C, 0x19, 0x17, 0x00, ++ 0xDE, 0xFA, 0xFE, 0xCA, 0x38, 0x36, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, ++ 0x78, 0x8E, 0x15, 0x00, 0x70, 0x79, 0x15, 0x00, 0x68, 0x8E, 0x15, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x43, 0x43, 0x6A, 0x85, 0x6C, 0x13, 0xF4, 0x00, 0x18, ++ 0x83, 0xB0, 0x04, 0x46, 0x05, 0xF1, 0x28, 0x07, 0x08, 0xD0, 0x03, 0xF4, ++ 0x60, 0x13, 0xB3, 0xF5, 0x20, 0x1F, 0x00, 0xF0, 0x93, 0x80, 0x03, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x83, 0xC3, 0x8B, 0xC6, 0x6C, 0x1A, 0x07, 0x38, 0xD5, ++ 0xDF, 0xF8, 0x58, 0x92, 0xD9, 0xF8, 0x00, 0x20, 0xB2, 0xF9, 0x00, 0x20, ++ 0x00, 0x2A, 0xC0, 0xF2, 0xCF, 0x80, 0x71, 0x6A, 0x09, 0xB9, 0x32, 0x6A, ++ 0x91, 0x68, 0x18, 0x06, 0x09, 0xD5, 0x94, 0xF8, 0x33, 0x30, 0x00, 0x2B, ++ 0x40, 0xF0, 0xDD, 0x80, 0x94, 0xF8, 0x35, 0x30, 0x00, 0x2B, 0x40, 0xF0, ++ 0xDF, 0x80, 0xF3, 0x6C, 0x23, 0xF4, 0xF0, 0x03, 0xF3, 0x64, 0x0B, 0x79, ++ 0xB7, 0x63, 0x13, 0xF0, 0x01, 0x0F, 0x08, 0xBF, 0x4F, 0xF4, 0x00, 0x78, ++ 0x00, 0x23, 0xC6, 0xF8, 0x48, 0x80, 0x33, 0x65, 0xEB, 0x6A, 0x2A, 0x6E, ++ 0x72, 0x63, 0x43, 0xF0, 0x02, 0x03, 0xEB, 0x62, 0x20, 0x46, 0x06, 0xF0, ++ 0xBB, 0xF8, 0xA2, 0x6C, 0x53, 0x6A, 0x43, 0xF0, 0x10, 0x03, 0x53, 0x62, ++ 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x83, 0x74, 0x4B, 0xD3, 0xF8, 0x28, 0x34, ++ 0x98, 0x47, 0xEB, 0x6D, 0xB3, 0x64, 0x22, 0x7F, 0x71, 0x49, 0x4F, 0xF4, ++ 0xA4, 0x60, 0x00, 0xFB, 0x02, 0x12, 0x92, 0xF8, 0x62, 0x20, 0x5A, 0xBB, ++ 0x6E, 0x49, 0x62, 0x7F, 0x4F, 0xF4, 0x1E, 0x70, 0x00, 0xFB, 0x02, 0x12, ++ 0x52, 0x68, 0x91, 0x06, 0x22, 0xD5, 0xE2, 0x8B, 0x12, 0xF4, 0x00, 0x5F, ++ 0xE2, 0x6A, 0xD2, 0x6B, 0x14, 0xBF, 0xC2, 0xF3, 0x00, 0x12, 0xC2, 0xF3, ++ 0xC0, 0x02, 0xBA, 0xB9, 0x70, 0x6A, 0x02, 0x88, 0x91, 0xB2, 0x12, 0x04, ++ 0x12, 0xD5, 0xC1, 0xF3, 0x0E, 0x01, 0x01, 0x80, 0x94, 0xF8, 0x33, 0x10, ++ 0x94, 0xF8, 0x32, 0x20, 0x04, 0x39, 0x04, 0x3A, 0x84, 0xF8, 0x33, 0x10, ++ 0x84, 0xF8, 0x32, 0x20, 0xD6, 0xE9, 0x0A, 0x21, 0x04, 0x39, 0x04, 0x3A, ++ 0xC6, 0xE9, 0x0A, 0x21, 0xDF, 0xF8, 0x70, 0x81, 0xB7, 0x63, 0xD8, 0xF8, ++ 0x00, 0x20, 0xE7, 0x6C, 0xB2, 0xF9, 0x00, 0x20, 0x00, 0x2A, 0x4F, 0xDB, ++ 0x7A, 0x6A, 0x0A, 0xB9, 0x3A, 0x6A, 0x92, 0x68, 0x23, 0xF4, 0xC0, 0x63, ++ 0xB3, 0x64, 0x12, 0x79, 0xD2, 0x07, 0x5C, 0xBF, 0x43, 0xF4, 0x00, 0x73, ++ 0xB3, 0x64, 0x9B, 0xE7, 0x83, 0x6A, 0x46, 0x6C, 0xC3, 0xF3, 0xC2, 0x22, ++ 0x05, 0x2A, 0x37, 0x63, 0x15, 0xD1, 0x03, 0xF4, 0xC0, 0x63, 0xEA, 0x6C, ++ 0x90, 0xF8, 0x36, 0x10, 0xB3, 0xF5, 0x80, 0x6F, 0x14, 0xBF, 0x4F, 0xF4, ++ 0x80, 0x33, 0x4F, 0xF4, 0x00, 0x33, 0x22, 0xF4, 0x40, 0x32, 0x1A, 0x43, ++ 0x89, 0x06, 0x4C, 0xBF, 0x42, 0xF4, 0x80, 0x22, 0x22, 0xF4, 0x80, 0x22, ++ 0xEA, 0x64, 0x04, 0xF1, 0x28, 0x00, 0x04, 0xF0, 0xDD, 0xF9, 0xD4, 0xF8, ++ 0x48, 0xC0, 0xA2, 0x6A, 0xB0, 0x88, 0xDC, 0xF8, 0x24, 0x30, 0xE9, 0x6D, ++ 0xEA, 0x63, 0xEA, 0x6A, 0x40, 0xF0, 0x08, 0x04, 0xB4, 0x80, 0x41, 0xF4, ++ 0xC0, 0x60, 0x2C, 0x6E, 0xF4, 0x62, 0x42, 0xF0, 0x02, 0x02, 0x30, 0x64, ++ 0x43, 0xF0, 0x10, 0x03, 0xEA, 0x62, 0x39, 0x46, 0x06, 0xF5, 0x82, 0x70, ++ 0x34, 0x22, 0xCC, 0xF8, 0x24, 0x30, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x43, ++ 0x29, 0xF0, 0xFE, 0xB9, 0xA2, 0x6C, 0x00, 0x2A, 0x3C, 0xD0, 0x7A, 0x6A, ++ 0x00, 0x2A, 0xAD, 0xD1, 0x3A, 0x6A, 0x92, 0xB1, 0xB3, 0x6C, 0xA8, 0xE7, ++ 0x2D, 0xB3, 0x71, 0x6A, 0x00, 0x29, 0x7F, 0xF4, 0x30, 0xAF, 0x32, 0x6A, ++ 0x0A, 0xB1, 0xE3, 0x8B, 0x2A, 0xE7, 0x23, 0x49, 0x23, 0x48, 0x40, 0xF2, ++ 0xB9, 0x12, 0x16, 0xF0, 0x3F, 0xFF, 0x32, 0x6A, 0xF5, 0xE7, 0x1F, 0x49, ++ 0x1F, 0x48, 0x40, 0xF2, 0xB9, 0x12, 0x16, 0xF0, 0x37, 0xFF, 0x3A, 0x6A, ++ 0xE4, 0xE7, 0x20, 0x22, 0x20, 0x46, 0x01, 0x91, 0x22, 0xF0, 0xD8, 0xF8, ++ 0x01, 0x99, 0x20, 0xE7, 0xA2, 0x88, 0x01, 0x91, 0x20, 0x46, 0x23, 0xF0, ++ 0x87, 0xFA, 0x01, 0x99, 0x19, 0xE7, 0x14, 0x49, 0x15, 0x48, 0x4F, 0xF4, ++ 0xD9, 0x72, 0x16, 0xF0, 0x21, 0xFF, 0x71, 0x6A, 0xA9, 0xB9, 0xD9, 0xF8, ++ 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xCF, 0xDB, 0xD8, 0xE7, ++ 0x4F, 0xF4, 0xD9, 0x72, 0x0B, 0x49, 0x0D, 0x48, 0x16, 0xF0, 0x12, 0xFF, ++ 0x7A, 0x6A, 0x42, 0xB9, 0xD8, 0xF8, 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0xB7, 0xDB, 0xD1, 0xE7, 0xE3, 0x8B, 0xED, 0xE6, 0xB3, 0x6C, ++ 0x60, 0xE7, 0x00, 0xBF, 0x88, 0x1A, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0x68, 0x65, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0xAC, 0x8E, 0x15, 0x00, ++ 0x8C, 0x8E, 0x15, 0x00, 0x38, 0x36, 0x17, 0x00, 0x05, 0x28, 0x1C, 0xD8, ++ 0xDF, 0xE8, 0x00, 0xF0, 0x07, 0x0B, 0x0F, 0x13, 0x17, 0x03, 0x12, 0x4B, ++ 0x20, 0x22, 0x1A, 0x60, 0x70, 0x47, 0x10, 0x4B, 0x02, 0x22, 0x1A, 0x60, ++ 0x70, 0x47, 0x0E, 0x4B, 0x04, 0x22, 0x1A, 0x60, 0x70, 0x47, 0x0C, 0x4B, ++ 0x08, 0x22, 0x1A, 0x60, 0x70, 0x47, 0x0A, 0x4B, 0x10, 0x22, 0x1A, 0x60, ++ 0x70, 0x47, 0x08, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x70, 0x47, 0x07, 0x4B, ++ 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x00, 0xDB, 0x70, 0x47, ++ 0x04, 0x49, 0x05, 0x48, 0x4F, 0xF4, 0x77, 0x72, 0x16, 0xF0, 0xCA, 0xBE, ++ 0x80, 0x81, 0x32, 0x40, 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x64, 0x7D, 0x15, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, 0x05, 0x28, 0x85, 0xB0, ++ 0x06, 0x46, 0x00, 0xF0, 0xE5, 0x81, 0xAE, 0x4C, 0x00, 0xEB, 0x40, 0x03, ++ 0xC3, 0xEB, 0xC3, 0x03, 0x04, 0xEB, 0x83, 0x04, 0xAB, 0x4B, 0xAC, 0x4F, ++ 0xDF, 0xF8, 0xD4, 0x92, 0x01, 0x22, 0x19, 0x46, 0xB2, 0x40, 0x71, 0x18, ++ 0x00, 0x92, 0xA3, 0x7E, 0x02, 0x91, 0xD2, 0x43, 0x4F, 0xEA, 0x81, 0x08, ++ 0x01, 0x92, 0x00, 0x2B, 0x3A, 0xD0, 0x3B, 0x68, 0x65, 0x6A, 0x5B, 0x78, ++ 0xD5, 0xF8, 0x8C, 0x20, 0x00, 0x2B, 0x00, 0xF0, 0x8B, 0x80, 0x69, 0x6D, ++ 0x00, 0x29, 0x00, 0xF0, 0x11, 0x81, 0x00, 0x2A, 0x80, 0xF2, 0x29, 0x81, ++ 0x9D, 0x49, 0xD9, 0xF8, 0x00, 0x30, 0x51, 0xF8, 0x26, 0x10, 0x0B, 0x44, ++ 0x11, 0x02, 0xC8, 0xF8, 0x00, 0x30, 0x40, 0xF1, 0xA2, 0x80, 0xAB, 0x88, ++ 0x99, 0x06, 0x40, 0xF1, 0x43, 0x81, 0x97, 0x4A, 0x43, 0xF0, 0x10, 0x03, ++ 0x52, 0xF8, 0x26, 0x00, 0xAB, 0x80, 0x15, 0xF0, 0x87, 0xF9, 0x94, 0xF8, ++ 0x50, 0x30, 0x3A, 0x68, 0x01, 0x3B, 0x84, 0xF8, 0x50, 0x30, 0x00, 0x23, ++ 0xA3, 0x76, 0x63, 0x62, 0x53, 0x78, 0x00, 0x2B, 0x00, 0xF0, 0x8F, 0x80, ++ 0x6B, 0x6D, 0x00, 0x2B, 0x00, 0xF0, 0x8F, 0x80, 0xA5, 0x62, 0xEB, 0x7A, ++ 0x01, 0x33, 0xEB, 0x72, 0xE5, 0x68, 0x00, 0x2D, 0x00, 0xF0, 0x90, 0x81, ++ 0xD5, 0xF8, 0x4C, 0xB0, 0xDB, 0xF8, 0x50, 0xA0, 0xBA, 0xF1, 0x00, 0x0F, ++ 0x80, 0xF2, 0xA9, 0x81, 0x30, 0x46, 0xCB, 0xF8, 0x10, 0xA0, 0x04, 0xF0, ++ 0x03, 0xF9, 0x6A, 0x6A, 0x12, 0xF4, 0x00, 0x10, 0x11, 0xD1, 0xDB, 0xF8, ++ 0x18, 0x10, 0x00, 0x29, 0x00, 0xF0, 0x97, 0x80, 0x8B, 0x6B, 0x03, 0xF4, ++ 0x60, 0x13, 0xB3, 0xF5, 0x00, 0x1F, 0x8C, 0x46, 0x00, 0xF0, 0x29, 0x81, ++ 0xDC, 0xF8, 0x3C, 0x30, 0x00, 0x2B, 0x80, 0xF2, 0x9D, 0x81, 0x1A, 0xF4, ++ 0x00, 0x0F, 0x0B, 0xD0, 0x6B, 0x7F, 0x0D, 0x2B, 0x08, 0xD8, 0x73, 0x48, ++ 0x73, 0x49, 0x4F, 0xF4, 0x1E, 0x7C, 0x0C, 0xFB, 0x03, 0x03, 0x09, 0x69, ++ 0xC3, 0xF8, 0x58, 0x12, 0x02, 0xF4, 0x60, 0x12, 0xB2, 0xF5, 0x60, 0x1F, ++ 0x00, 0xF0, 0x9E, 0x80, 0x04, 0xF1, 0x0C, 0x00, 0x15, 0xF0, 0x18, 0xFA, ++ 0x6B, 0x6A, 0x9B, 0x02, 0x04, 0xD4, 0x94, 0xF8, 0x50, 0x30, 0x01, 0x3B, ++ 0x84, 0xF8, 0x50, 0x30, 0xAB, 0x88, 0x00, 0x2B, 0x5F, 0xD1, 0x28, 0x46, ++ 0x02, 0xF0, 0x4C, 0xF8, 0x60, 0x4A, 0xD9, 0xF8, 0x00, 0x30, 0x52, 0xF8, ++ 0x26, 0x20, 0x13, 0x44, 0xC8, 0xF8, 0x00, 0x30, 0xA3, 0x7E, 0x6A, 0xE7, ++ 0x29, 0x69, 0x00, 0x29, 0x00, 0xF0, 0xA4, 0x80, 0xAB, 0x6C, 0x00, 0x2B, ++ 0x80, 0xF2, 0x9D, 0x80, 0x57, 0x4B, 0xD9, 0xF8, 0x00, 0x20, 0x53, 0xF8, ++ 0x26, 0x10, 0xAB, 0x88, 0x0A, 0x44, 0xC8, 0xF8, 0x00, 0x20, 0x9A, 0x06, ++ 0x3F, 0xF5, 0x77, 0xAF, 0xDF, 0xF8, 0x6C, 0xB1, 0xDB, 0xF8, 0x9C, 0x32, ++ 0x98, 0x47, 0x4F, 0xF0, 0x04, 0x0A, 0xAB, 0x88, 0x99, 0x06, 0x3F, 0xF5, ++ 0x6C, 0xAF, 0xDB, 0xF8, 0x9C, 0x32, 0x98, 0x47, 0xBA, 0xF1, 0x01, 0x0A, ++ 0xF5, 0xD1, 0xAB, 0x88, 0x9A, 0x06, 0x3F, 0xF5, 0x62, 0xAF, 0x04, 0xF1, ++ 0x1C, 0x00, 0x15, 0xF0, 0xD3, 0xF9, 0xAB, 0x88, 0x5B, 0xE7, 0x2B, 0x69, ++ 0x00, 0x2B, 0x7F, 0xF4, 0x71, 0xAF, 0x46, 0x4B, 0x1B, 0x68, 0xEF, 0xF3, ++ 0x10, 0x82, 0xD0, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x43, 0x4A, 0x01, 0x21, ++ 0x11, 0x60, 0x43, 0x4A, 0x01, 0x99, 0x10, 0x68, 0x3F, 0x4D, 0x0B, 0x40, ++ 0x41, 0x1C, 0x11, 0x60, 0x2B, 0x60, 0x29, 0xB1, 0x3D, 0x4B, 0x10, 0x60, ++ 0x1B, 0x68, 0x08, 0xB9, 0x03, 0xB1, 0x62, 0xB6, 0x3C, 0x4B, 0x00, 0x9A, ++ 0x1A, 0x60, 0x00, 0x22, 0xA3, 0x7E, 0x22, 0x60, 0x17, 0xE7, 0x51, 0x46, ++ 0x28, 0x46, 0x32, 0x46, 0x01, 0xF0, 0xC6, 0xF9, 0x9C, 0xE7, 0x33, 0x4B, ++ 0x1B, 0x68, 0xEF, 0xF3, 0x10, 0x82, 0xD2, 0x07, 0x03, 0xD4, 0x72, 0xB6, ++ 0x30, 0x4A, 0x01, 0x21, 0x11, 0x60, 0xDF, 0xF8, 0xC0, 0xC0, 0x01, 0x99, ++ 0xDC, 0xF8, 0x00, 0x00, 0x2B, 0x4A, 0x0B, 0x40, 0x41, 0x1C, 0xCC, 0xF8, ++ 0x00, 0x10, 0x13, 0x60, 0x39, 0xB1, 0x29, 0x4B, 0xCC, 0xF8, 0x00, 0x00, ++ 0x1B, 0x68, 0x10, 0xB9, 0x00, 0x2B, 0x40, 0xF0, 0xA2, 0x80, 0x27, 0x4B, ++ 0x00, 0x9A, 0x1A, 0x60, 0x94, 0xF8, 0x50, 0x30, 0x00, 0x22, 0x01, 0x2B, ++ 0x22, 0x60, 0x7C, 0xD0, 0x6A, 0x6A, 0x4C, 0xE7, 0x6B, 0x6C, 0x63, 0x62, ++ 0x01, 0x23, 0x40, 0x20, 0xA3, 0x76, 0x15, 0xF0, 0x91, 0xF8, 0x59, 0xE7, ++ 0x94, 0xF8, 0x50, 0x10, 0x01, 0x29, 0x7F, 0xF4, 0xEA, 0xAE, 0xE1, 0x6A, ++ 0x00, 0x29, 0x3F, 0xF4, 0xE6, 0xAE, 0x21, 0x6B, 0x19, 0x48, 0x09, 0x7F, ++ 0x4F, 0xF0, 0xA4, 0x0C, 0x0C, 0xFB, 0x01, 0x61, 0x99, 0x31, 0x50, 0xF8, ++ 0x31, 0x10, 0x00, 0x29, 0x7B, 0xD0, 0x00, 0x2B, 0x3F, 0xF4, 0x62, 0xAF, ++ 0x00, 0x2A, 0xFF, 0xF6, 0xD7, 0xAE, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, ++ 0x94, 0xF8, 0x50, 0x10, 0x01, 0x29, 0x7F, 0xF4, 0x57, 0xAF, 0xE1, 0x6A, ++ 0x00, 0x29, 0xE2, 0xD1, 0x52, 0xE7, 0x00, 0xBF, 0x20, 0x62, 0x17, 0x00, ++ 0x4A, 0x80, 0x0C, 0x10, 0x34, 0x36, 0x17, 0x00, 0xB0, 0x35, 0x17, 0x00, ++ 0xC4, 0x90, 0x15, 0x00, 0x68, 0x65, 0x17, 0x00, 0x00, 0x10, 0x50, 0x40, ++ 0x8C, 0x80, 0x32, 0x40, 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x88, 0x80, 0x32, 0x40, 0x18, 0x88, 0x17, 0x00, 0x20, 0x01, 0x32, 0x40, ++ 0x88, 0x1A, 0x17, 0x00, 0xDF, 0xF8, 0x68, 0xB1, 0xDB, 0xF8, 0x9C, 0x32, ++ 0x98, 0x47, 0x4F, 0xF0, 0x04, 0x0A, 0xAB, 0x88, 0x9A, 0x06, 0x3F, 0xF5, ++ 0xB2, 0xAE, 0xDB, 0xF8, 0x9C, 0x32, 0x98, 0x47, 0xBA, 0xF1, 0x01, 0x0A, ++ 0xF5, 0xD1, 0x4D, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0xAB, 0x88, 0xBF, 0xF6, 0xA4, 0xAE, 0x98, 0x06, 0x3F, 0xF5, 0xA1, 0xAE, ++ 0x48, 0x49, 0x49, 0x48, 0x4F, 0xF4, 0xAC, 0x62, 0x05, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x4F, 0x16, 0xF0, 0xEB, 0xBC, 0x43, 0x48, 0x8B, 0x68, 0x01, 0x68, ++ 0xB1, 0xF9, 0x00, 0x10, 0x00, 0x29, 0x33, 0xDB, 0x60, 0x46, 0x9C, 0x46, ++ 0xCC, 0xE6, 0xE3, 0x6A, 0x00, 0x2B, 0x3F, 0xF4, 0x7F, 0xAF, 0x23, 0x6B, ++ 0x3E, 0x4A, 0x1B, 0x7F, 0xA4, 0x21, 0x01, 0xFB, 0x03, 0x63, 0x99, 0x33, ++ 0x52, 0xF8, 0x33, 0x30, 0x00, 0x2B, 0x7F, 0xF4, 0x73, 0xAF, 0x3A, 0x4B, ++ 0x93, 0xF8, 0xFF, 0x31, 0x00, 0x2B, 0x7F, 0xF4, 0x6D, 0xAF, 0x38, 0x4B, ++ 0x30, 0x46, 0xD3, 0xF8, 0x5C, 0x33, 0x98, 0x47, 0x66, 0xE7, 0x62, 0xB6, ++ 0x5B, 0xE7, 0x33, 0x49, 0x91, 0xF8, 0xFF, 0x11, 0x00, 0x29, 0x7F, 0xF4, ++ 0x7E, 0xAF, 0x31, 0x4B, 0x03, 0x92, 0xD3, 0xF8, 0x5C, 0x33, 0x30, 0x46, ++ 0x98, 0x47, 0x3B, 0x68, 0x03, 0x9A, 0x5B, 0x78, 0x00, 0x2B, 0x7F, 0xF4, ++ 0x75, 0xAF, 0xD5, 0xE6, 0x00, 0x2B, 0xC9, 0xD1, 0x25, 0x49, 0x2A, 0x48, ++ 0x00, 0x93, 0x40, 0xF2, 0x56, 0x42, 0x16, 0xF0, 0xD9, 0xFC, 0x00, 0x9B, ++ 0xDB, 0x6B, 0xFF, 0xDE, 0x26, 0x4C, 0x1F, 0xE6, 0x26, 0x4B, 0x25, 0x60, ++ 0x1B, 0x68, 0xEF, 0xF3, 0x10, 0x82, 0xD0, 0x07, 0x03, 0xD4, 0x72, 0xB6, ++ 0x23, 0x4A, 0x01, 0x21, 0x11, 0x60, 0x23, 0x4A, 0x01, 0x99, 0x10, 0x68, ++ 0x1F, 0x4C, 0x19, 0x40, 0x0B, 0x46, 0x41, 0x1C, 0x11, 0x60, 0x23, 0x60, ++ 0x29, 0xB1, 0x1D, 0x4B, 0x10, 0x60, 0x1B, 0x68, 0x08, 0xB9, 0x03, 0xB1, ++ 0x62, 0xB6, 0x1C, 0x4B, 0x00, 0x9A, 0x1A, 0x60, 0x05, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x8F, 0x6B, 0x6A, 0x03, 0xF4, 0x60, 0x13, 0xB3, 0xF5, 0x20, 0x1F, ++ 0x7F, 0xF4, 0x41, 0xAF, 0x68, 0x6C, 0x31, 0x46, 0x0C, 0x30, 0x05, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x4F, 0x03, 0xF0, 0x28, 0xBF, 0x10, 0xB1, 0x31, 0x46, ++ 0x03, 0xF0, 0x24, 0xFF, 0x10, 0x4B, 0x11, 0x4A, 0x53, 0xF8, 0x26, 0x10, ++ 0x02, 0x9B, 0x12, 0x68, 0x9B, 0x00, 0x0A, 0x44, 0x1A, 0x60, 0x2A, 0xE7, ++ 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0xD4, 0x8E, 0x15, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0x20, 0x62, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0xC0, 0x8E, 0x15, 0x00, 0xC4, 0x63, 0x17, 0x00, 0x8C, 0x80, 0x32, 0x40, ++ 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0x88, 0x80, 0x32, 0x40, ++ 0xB0, 0x35, 0x17, 0x00, 0x20, 0x01, 0x32, 0x40, 0x43, 0x6A, 0x9B, 0x02, ++ 0x03, 0xD5, 0x4B, 0x6A, 0x5B, 0x07, 0x07, 0xD4, 0x70, 0x47, 0xC1, 0x6C, ++ 0x05, 0x4B, 0x14, 0x31, 0xD3, 0xF8, 0x9C, 0x33, 0x08, 0x46, 0x18, 0x47, ++ 0x42, 0x6C, 0x93, 0x88, 0x43, 0xF0, 0x02, 0x03, 0x93, 0x80, 0x70, 0x47, ++ 0x88, 0x1A, 0x17, 0x00, 0x70, 0xB5, 0x43, 0x7F, 0x0B, 0x4E, 0x4F, 0xF4, ++ 0x1E, 0x75, 0x04, 0x46, 0x05, 0xFB, 0x03, 0xF5, 0x05, 0xF5, 0xFE, 0x70, ++ 0x01, 0x23, 0xE1, 0x76, 0x84, 0xF8, 0x5D, 0x30, 0x30, 0x44, 0x21, 0x46, ++ 0x14, 0xF0, 0xFE, 0xFF, 0x04, 0x4B, 0x71, 0x19, 0x20, 0x46, 0x5B, 0x69, ++ 0xBD, 0xE8, 0x70, 0x40, 0x18, 0x47, 0x00, 0xBF, 0x68, 0x65, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x83, 0x88, 0x2D, 0xE9, 0xF0, 0x41, 0x04, 0x46, ++ 0x0E, 0x46, 0x15, 0x46, 0xEB, 0xB1, 0x3A, 0x4B, 0xD0, 0xF8, 0x4C, 0x80, ++ 0x1A, 0x68, 0xB2, 0xF9, 0x00, 0x20, 0x00, 0x2A, 0x23, 0xDB, 0xD8, 0xF8, ++ 0x24, 0x70, 0x17, 0xB9, 0xD8, 0xF8, 0x20, 0x30, 0x9F, 0x68, 0x04, 0x2D, ++ 0x03, 0xD1, 0x39, 0x46, 0x20, 0x46, 0xFF, 0xF7, 0x13, 0xFB, 0xE3, 0x7E, ++ 0xFF, 0x2B, 0x25, 0xD0, 0x2F, 0x4F, 0x29, 0x46, 0xD7, 0xF8, 0x00, 0x34, ++ 0x20, 0x46, 0x98, 0x47, 0x05, 0xE0, 0x82, 0x6C, 0x2B, 0x4F, 0x53, 0x6A, ++ 0x43, 0xF0, 0x10, 0x03, 0x53, 0x62, 0xD7, 0xF8, 0xA4, 0x33, 0x2A, 0x46, ++ 0x31, 0x46, 0x20, 0x46, 0xBD, 0xE8, 0xF0, 0x41, 0x18, 0x47, 0x82, 0x6C, ++ 0x5A, 0xB3, 0xD8, 0xF8, 0x24, 0x70, 0x00, 0x2F, 0xDB, 0xD1, 0xD8, 0xF8, ++ 0x20, 0x30, 0x00, 0x2B, 0xD6, 0xD1, 0x21, 0x49, 0x21, 0x48, 0x40, 0xF2, ++ 0xB9, 0x12, 0x16, 0xF0, 0x03, 0xFC, 0xCD, 0xE7, 0xE3, 0x8B, 0x1A, 0x07, ++ 0x04, 0xD5, 0x3A, 0x88, 0x02, 0xF0, 0xDC, 0x02, 0x10, 0x2A, 0x25, 0xD0, ++ 0xBB, 0x7D, 0x13, 0xF0, 0x0F, 0x03, 0x07, 0xF1, 0x16, 0x07, 0x06, 0xD0, ++ 0x18, 0x4A, 0xB2, 0xF8, 0xFC, 0x21, 0x43, 0xEA, 0x02, 0x13, 0x3B, 0x80, ++ 0xC4, 0xE7, 0x15, 0x49, 0xB1, 0xF8, 0xFC, 0x21, 0x01, 0x32, 0x92, 0xB2, ++ 0xA1, 0xF8, 0xFC, 0x21, 0xF3, 0xE7, 0x0F, 0x49, 0x11, 0x48, 0x4F, 0xF4, ++ 0xD9, 0x72, 0x16, 0xF0, 0xDF, 0xFB, 0xD8, 0xF8, 0x24, 0x70, 0x00, 0x2F, ++ 0xA9, 0xD1, 0x08, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0xC7, 0xDB, 0x9F, 0xE7, 0x7A, 0x8B, 0x00, 0x2A, 0xD6, 0xD1, 0x43, 0xF0, ++ 0x20, 0x03, 0xE3, 0x83, 0x38, 0x1D, 0x20, 0xF0, 0xF9, 0xFE, 0xCF, 0xE7, ++ 0x38, 0x36, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0xAC, 0x8E, 0x15, 0x00, 0x20, 0x62, 0x17, 0x00, 0x8C, 0x8E, 0x15, 0x00, ++ 0x38, 0xB5, 0x0C, 0x46, 0x05, 0x29, 0x00, 0xF2, 0x33, 0x81, 0xDF, 0xE8, ++ 0x01, 0xF0, 0x36, 0x44, 0x51, 0x5E, 0x6B, 0x03, 0x9D, 0x4A, 0x13, 0x68, ++ 0xC3, 0xF3, 0x01, 0x63, 0x02, 0x2B, 0x00, 0xF0, 0x04, 0x81, 0x9B, 0x4A, ++ 0x9B, 0x4B, 0x10, 0x60, 0x4F, 0xF4, 0x80, 0x42, 0x1A, 0x60, 0x9A, 0x49, ++ 0x9A, 0x4A, 0x9B, 0x4B, 0x51, 0xF8, 0x24, 0x50, 0x12, 0x68, 0x9A, 0x48, ++ 0x23, 0x44, 0x9B, 0x00, 0x01, 0x21, 0x2A, 0x44, 0x01, 0xFA, 0x04, 0xF4, ++ 0x1A, 0x60, 0x04, 0x60, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x02, 0xD4, ++ 0x72, 0xB6, 0x94, 0x4B, 0x19, 0x60, 0x94, 0x4B, 0x94, 0x49, 0x18, 0x68, ++ 0x0D, 0x68, 0x42, 0x1C, 0x2C, 0x43, 0x1A, 0x60, 0x0C, 0x60, 0x2A, 0xB1, ++ 0x8E, 0x4A, 0x18, 0x60, 0x13, 0x68, 0x08, 0xB9, 0x03, 0xB1, 0x62, 0xB6, ++ 0x38, 0xBD, 0x84, 0x4A, 0x13, 0x68, 0xC3, 0xF3, 0x01, 0x13, 0x02, 0x2B, ++ 0x00, 0xF0, 0xAE, 0x80, 0x8A, 0x4A, 0x82, 0x4B, 0x10, 0x60, 0x4F, 0xF4, ++ 0x00, 0x72, 0x1A, 0x60, 0xCB, 0xE7, 0x7D, 0x4A, 0x13, 0x68, 0xC3, 0xF3, ++ 0x01, 0x23, 0x02, 0x2B, 0x7D, 0xD0, 0x85, 0x4A, 0x7B, 0x4B, 0x10, 0x60, ++ 0x4F, 0xF4, 0x80, 0x62, 0x1A, 0x60, 0xBE, 0xE7, 0x76, 0x4A, 0x13, 0x68, ++ 0xC3, 0xF3, 0x01, 0x33, 0x02, 0x2B, 0x4F, 0xD0, 0x7F, 0x4A, 0x75, 0x4B, ++ 0x10, 0x60, 0x4F, 0xF4, 0x00, 0x62, 0x1A, 0x60, 0xB1, 0xE7, 0x70, 0x4A, ++ 0x13, 0x68, 0xC3, 0xF3, 0x01, 0x43, 0x02, 0x2B, 0x21, 0xD0, 0x7A, 0x4A, ++ 0x6E, 0x4B, 0x10, 0x60, 0x4F, 0xF4, 0x80, 0x52, 0x1A, 0x60, 0xA4, 0xE7, ++ 0x77, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x06, 0xDB, ++ 0x75, 0x4A, 0x68, 0x4B, 0x10, 0x60, 0x4F, 0xF4, 0x80, 0x72, 0x1A, 0x60, ++ 0x97, 0xE7, 0x63, 0x4B, 0x1B, 0x68, 0x03, 0xF0, 0x03, 0x03, 0x02, 0x2B, ++ 0xF2, 0xD1, 0xBD, 0xE8, 0x38, 0x40, 0x6F, 0x49, 0x6F, 0x48, 0x4F, 0xF4, ++ 0xEC, 0x62, 0x16, 0xF0, 0xFF, 0xBA, 0x60, 0x49, 0x0D, 0x68, 0x02, 0x35, ++ 0x03, 0xE0, 0x0B, 0x68, 0x5B, 0x1B, 0x00, 0x2B, 0x04, 0xDA, 0x13, 0x68, ++ 0xC3, 0xF3, 0x01, 0x43, 0x02, 0x2B, 0xF6, 0xD0, 0x63, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xCA, 0xDA, 0x52, 0x4B, 0x1B, 0x68, ++ 0xC3, 0xF3, 0x01, 0x43, 0x02, 0x2B, 0xC4, 0xD1, 0xBD, 0xE8, 0x38, 0x40, ++ 0x5E, 0x49, 0x60, 0x48, 0x40, 0xF2, 0x6C, 0x72, 0x16, 0xF0, 0xDE, 0xBA, ++ 0x4F, 0x49, 0x0D, 0x68, 0x02, 0x35, 0x03, 0xE0, 0x0B, 0x68, 0x5B, 0x1B, ++ 0x00, 0x2B, 0x04, 0xDA, 0x13, 0x68, 0xC3, 0xF3, 0x01, 0x33, 0x02, 0x2B, ++ 0xF6, 0xD0, 0x53, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0x9C, 0xDA, 0x42, 0x4B, 0x1B, 0x68, 0xC3, 0xF3, 0x01, 0x33, 0x02, 0x2B, ++ 0x96, 0xD1, 0xBD, 0xE8, 0x38, 0x40, 0x4E, 0x49, 0x50, 0x48, 0x4F, 0xF4, ++ 0xEF, 0x62, 0x16, 0xF0, 0xBD, 0xBA, 0x3F, 0x49, 0x0D, 0x68, 0x02, 0x35, ++ 0x03, 0xE0, 0x0B, 0x68, 0x5B, 0x1B, 0x00, 0x2B, 0x04, 0xDA, 0x13, 0x68, ++ 0xC3, 0xF3, 0x01, 0x23, 0x02, 0x2B, 0xF6, 0xD0, 0x42, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xBF, 0xF6, 0x6E, 0xAF, 0x31, 0x4B, ++ 0x1B, 0x68, 0xC3, 0xF3, 0x01, 0x23, 0x02, 0x2B, 0x7F, 0xF4, 0x67, 0xAF, ++ 0xBD, 0xE8, 0x38, 0x40, 0x3C, 0x49, 0x40, 0x48, 0x40, 0xF2, 0x84, 0x72, ++ 0x16, 0xF0, 0x9A, 0xBA, 0x2D, 0x49, 0x0D, 0x68, 0x02, 0x35, 0x03, 0xE0, ++ 0x0B, 0x68, 0x5B, 0x1B, 0x00, 0x2B, 0x04, 0xDA, 0x13, 0x68, 0xC3, 0xF3, ++ 0x01, 0x13, 0x02, 0x2B, 0xF6, 0xD0, 0x31, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0xBF, 0xF6, 0x3E, 0xAF, 0x1F, 0x4B, 0x1B, 0x68, ++ 0xC3, 0xF3, 0x01, 0x13, 0x02, 0x2B, 0x7F, 0xF4, 0x37, 0xAF, 0xBD, 0xE8, ++ 0x38, 0x40, 0x2B, 0x49, 0x2F, 0x48, 0x4F, 0xF4, 0xF2, 0x62, 0x16, 0xF0, ++ 0x77, 0xBA, 0x1C, 0x49, 0x0D, 0x68, 0x02, 0x35, 0x03, 0xE0, 0x0B, 0x68, ++ 0x5B, 0x1B, 0x00, 0x2B, 0x04, 0xDA, 0x13, 0x68, 0xC3, 0xF3, 0x01, 0x63, ++ 0x02, 0x2B, 0xF6, 0xD0, 0x1F, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0xBF, 0xF6, 0xE8, 0xAE, 0x0E, 0x4B, 0x1B, 0x68, 0xC3, 0xF3, ++ 0x01, 0x63, 0x02, 0x2B, 0x7F, 0xF4, 0xE1, 0xAE, 0xBD, 0xE8, 0x38, 0x40, ++ 0x19, 0x49, 0x1F, 0x48, 0x40, 0xF2, 0x9C, 0x72, 0x16, 0xF0, 0x54, 0xBA, ++ 0x14, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xBF, 0xF6, ++ 0xD8, 0xAE, 0x13, 0x49, 0x19, 0x48, 0x40, 0xF2, 0xA2, 0x72, 0x16, 0xF0, ++ 0x79, 0xFA, 0xD0, 0xE6, 0x88, 0x81, 0x32, 0x40, 0x34, 0x83, 0x32, 0x40, ++ 0x80, 0x81, 0x32, 0x40, 0xB0, 0x35, 0x17, 0x00, 0x20, 0x01, 0x32, 0x40, ++ 0x4A, 0x80, 0x0C, 0x10, 0x88, 0x80, 0x32, 0x40, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x8C, 0x80, 0x32, 0x40, 0x9C, 0x81, 0x32, 0x40, ++ 0xA0, 0x81, 0x32, 0x40, 0xA4, 0x81, 0x32, 0x40, 0xA8, 0x81, 0x32, 0x40, ++ 0x38, 0x36, 0x17, 0x00, 0x98, 0x81, 0x32, 0x40, 0x70, 0x79, 0x15, 0x00, ++ 0xF8, 0x8E, 0x15, 0x00, 0x18, 0x8F, 0x15, 0x00, 0x38, 0x8F, 0x15, 0x00, ++ 0x58, 0x8F, 0x15, 0x00, 0x78, 0x8F, 0x15, 0x00, 0x98, 0x8F, 0x15, 0x00, ++ 0x64, 0x7D, 0x15, 0x00, 0x05, 0x2A, 0xF8, 0xB5, 0x06, 0x46, 0x0D, 0x46, ++ 0x35, 0xD0, 0x54, 0x21, 0x33, 0x4C, 0x01, 0xFB, 0x02, 0xF1, 0x02, 0xEB, ++ 0x42, 0x03, 0x61, 0x58, 0xC3, 0xEB, 0xC3, 0x03, 0x04, 0xEB, 0x83, 0x04, ++ 0x00, 0x29, 0x37, 0xD0, 0x2E, 0x4F, 0x3B, 0x68, 0x5B, 0x78, 0xF3, 0xB1, ++ 0x4E, 0x60, 0x05, 0x2A, 0x0B, 0xD0, 0x2C, 0x48, 0x02, 0xEB, 0x42, 0x01, ++ 0x00, 0xEB, 0x81, 0x01, 0x91, 0xF8, 0x2E, 0x10, 0x41, 0xB9, 0x90, 0xF8, ++ 0x8C, 0x10, 0x00, 0x29, 0x3E, 0xD1, 0x10, 0x46, 0xFF, 0xF7, 0x2A, 0xFB, ++ 0x3B, 0x68, 0x5B, 0x78, 0x3B, 0xB9, 0xAA, 0x6B, 0x92, 0x02, 0x46, 0xBF, ++ 0x01, 0x23, 0xC4, 0xE9, 0x01, 0x63, 0xC4, 0xE9, 0x01, 0x33, 0x25, 0x60, ++ 0xF8, 0xBD, 0xA0, 0x68, 0x00, 0x28, 0xDD, 0xD0, 0x61, 0x68, 0x4E, 0x60, ++ 0xDB, 0xE7, 0x19, 0x4C, 0xD4, 0xF8, 0xA4, 0x11, 0x04, 0xF5, 0xD2, 0x74, ++ 0x00, 0x29, 0xCF, 0xD1, 0x11, 0x46, 0x30, 0x46, 0xFF, 0xF7, 0x44, 0xFE, ++ 0x14, 0x4B, 0x1B, 0x68, 0x5B, 0x78, 0xDF, 0xE7, 0x13, 0x4B, 0x02, 0xEB, ++ 0x42, 0x00, 0x03, 0xEB, 0x80, 0x00, 0x51, 0x00, 0x90, 0xF8, 0x2E, 0x00, ++ 0x38, 0xB9, 0x93, 0xF8, 0x8C, 0x00, 0x93, 0xF8, 0x7E, 0x70, 0x00, 0x28, ++ 0xE8, 0xD0, 0xBA, 0x42, 0xE6, 0xD1, 0x0A, 0x44, 0x03, 0xEB, 0x82, 0x03, ++ 0x5A, 0x6A, 0x42, 0xB1, 0x07, 0x4B, 0x1B, 0x68, 0x5B, 0x78, 0xC5, 0xE7, ++ 0x90, 0xF8, 0x7E, 0x10, 0x91, 0x42, 0xBC, 0xD1, 0xC0, 0xE7, 0x03, 0x4A, ++ 0x5E, 0x62, 0x13, 0x68, 0x5B, 0x78, 0xBB, 0xE7, 0x20, 0x62, 0x17, 0x00, ++ 0x34, 0x36, 0x17, 0x00, 0x94, 0x64, 0x17, 0x00, 0x38, 0xB5, 0x83, 0x88, ++ 0x33, 0xB1, 0x04, 0x46, 0x80, 0x6C, 0x18, 0xB1, 0x63, 0x6A, 0x13, 0xF4, ++ 0x00, 0x15, 0x00, 0xD0, 0x38, 0xBD, 0xF8, 0xF7, 0x75, 0xFE, 0xA5, 0x64, ++ 0x38, 0xBD, 0x00, 0xBF, 0x70, 0xB5, 0x20, 0x4C, 0x20, 0x4D, 0x02, 0xF0, ++ 0xD9, 0xFC, 0xD4, 0xF8, 0x44, 0x33, 0x98, 0x47, 0xFE, 0xF7, 0x9E, 0xFF, ++ 0x00, 0xF0, 0xA8, 0xFD, 0xD4, 0xF8, 0xA8, 0x33, 0x00, 0x20, 0x98, 0x47, ++ 0x04, 0xF0, 0xBA, 0xFE, 0x4F, 0xF4, 0x01, 0x72, 0x00, 0x21, 0xA5, 0xF1, ++ 0x0C, 0x00, 0xF1, 0xF7, 0xC3, 0xFC, 0x05, 0xF5, 0xD2, 0x76, 0x00, 0x24, ++ 0x28, 0x46, 0x14, 0xF0, 0x4D, 0xFD, 0x45, 0xF8, 0x0C, 0x4C, 0xAC, 0x73, ++ 0x85, 0xF8, 0x44, 0x40, 0xC5, 0xE9, 0x06, 0x44, 0x05, 0xF1, 0x10, 0x00, ++ 0x54, 0x35, 0x14, 0xF0, 0x41, 0xFD, 0xB5, 0x42, 0xEE, 0xD1, 0x0C, 0x4D, ++ 0x05, 0xF5, 0xD8, 0x70, 0x14, 0xF0, 0x3A, 0xFD, 0x05, 0xF5, 0xE0, 0x70, ++ 0xC5, 0xE9, 0x72, 0x44, 0xC5, 0xF8, 0xA4, 0x41, 0x85, 0xF8, 0xBE, 0x41, ++ 0x85, 0xF8, 0xF4, 0x41, 0x14, 0xF0, 0x2E, 0xFD, 0xA5, 0xF8, 0xFC, 0x41, ++ 0x70, 0xBD, 0x00, 0xBF, 0x88, 0x1A, 0x17, 0x00, 0x2C, 0x62, 0x17, 0x00, ++ 0x20, 0x62, 0x17, 0x00, 0x0C, 0x4B, 0x93, 0xF8, 0xFE, 0x31, 0x0B, 0xB1, ++ 0x00, 0x20, 0x70, 0x47, 0x10, 0xB5, 0x04, 0x46, 0x10, 0xF0, 0xBC, 0xF8, ++ 0x20, 0xB1, 0x94, 0xF8, 0xC0, 0x34, 0x1B, 0xB9, 0x01, 0x20, 0x10, 0xBD, ++ 0x00, 0x20, 0x10, 0xBD, 0x94, 0xF8, 0xC1, 0x04, 0x11, 0xF0, 0x16, 0xFD, ++ 0x00, 0x38, 0x18, 0xBF, 0x01, 0x20, 0x10, 0xBD, 0x20, 0x62, 0x17, 0x00, ++ 0x45, 0x4B, 0x01, 0x22, 0x70, 0xB4, 0x1B, 0x68, 0x02, 0xFA, 0x00, 0xF6, ++ 0xEF, 0xF3, 0x10, 0x81, 0xC9, 0x07, 0x02, 0xD4, 0x72, 0xB6, 0x41, 0x49, ++ 0x0A, 0x60, 0x41, 0x4A, 0x3E, 0x4D, 0x14, 0x68, 0x23, 0xEA, 0x06, 0x03, ++ 0x61, 0x1C, 0x11, 0x60, 0x2B, 0x60, 0x29, 0xB1, 0x3B, 0x4B, 0x14, 0x60, ++ 0x1B, 0x68, 0x0C, 0xB9, 0x03, 0xB1, 0x62, 0xB6, 0x3A, 0x4B, 0x1E, 0x60, ++ 0x05, 0x28, 0x5D, 0xD8, 0xDF, 0xE8, 0x00, 0xF0, 0x12, 0x21, 0x3F, 0x30, ++ 0x4E, 0x03, 0x37, 0x4B, 0x37, 0x4A, 0x4F, 0xF4, 0x00, 0x11, 0x19, 0x60, ++ 0x13, 0x68, 0x13, 0xF0, 0x40, 0x7F, 0xFB, 0xD1, 0x34, 0x4B, 0x4F, 0xF4, ++ 0x00, 0x12, 0x70, 0xBC, 0x1A, 0x60, 0x70, 0x47, 0x2F, 0x4B, 0x30, 0x4A, ++ 0x4F, 0xF4, 0x80, 0x31, 0x19, 0x60, 0x13, 0x68, 0x13, 0xF0, 0x30, 0x0F, ++ 0xFB, 0xD1, 0x2D, 0x4B, 0x4F, 0xF4, 0x80, 0x32, 0x70, 0xBC, 0x1A, 0x60, ++ 0x70, 0x47, 0x28, 0x4B, 0x28, 0x4A, 0x4F, 0xF4, 0x00, 0x31, 0x19, 0x60, ++ 0x13, 0x68, 0x13, 0xF4, 0x40, 0x7F, 0xFB, 0xD1, 0x25, 0x4B, 0x4F, 0xF4, ++ 0x00, 0x32, 0x70, 0xBC, 0x1A, 0x60, 0x70, 0x47, 0x20, 0x4B, 0x21, 0x4A, ++ 0x4F, 0xF4, 0x00, 0x21, 0x19, 0x60, 0x13, 0x68, 0x13, 0xF4, 0x40, 0x3F, ++ 0xFB, 0xD1, 0x1E, 0x4B, 0x4F, 0xF4, 0x00, 0x22, 0x70, 0xBC, 0x1A, 0x60, ++ 0x70, 0x47, 0x19, 0x4B, 0x19, 0x4A, 0x4F, 0xF4, 0x80, 0x21, 0x19, 0x60, ++ 0x13, 0x68, 0x13, 0xF4, 0x40, 0x5F, 0xFB, 0xD1, 0x16, 0x4B, 0x4F, 0xF4, ++ 0x80, 0x22, 0x70, 0xBC, 0x1A, 0x60, 0x70, 0x47, 0x11, 0x4B, 0x12, 0x4A, ++ 0x4F, 0xF4, 0x00, 0x41, 0x19, 0x60, 0x13, 0x68, 0x9B, 0x07, 0xFC, 0xD1, ++ 0x0F, 0x4B, 0x4F, 0xF4, 0x00, 0x42, 0x1A, 0x60, 0x70, 0xBC, 0x70, 0x47, ++ 0x0D, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xF7, 0xDA, ++ 0x70, 0xBC, 0x0B, 0x49, 0x0B, 0x48, 0x40, 0xF6, 0xE7, 0x02, 0x16, 0xF0, ++ 0xD5, 0xB8, 0x00, 0xBF, 0x8C, 0x80, 0x32, 0x40, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x88, 0x80, 0x32, 0x40, 0x80, 0x81, 0x32, 0x40, ++ 0x88, 0x81, 0x32, 0x40, 0x84, 0x81, 0x32, 0x40, 0x38, 0x36, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x64, 0x7D, 0x15, 0x00, 0x70, 0xB5, 0x05, 0x28, ++ 0x82, 0xB0, 0x04, 0x46, 0x0A, 0x46, 0x3B, 0xD0, 0x1E, 0x4B, 0x00, 0xEB, ++ 0x40, 0x05, 0xC5, 0xEB, 0xC5, 0x05, 0x03, 0xEB, 0x85, 0x05, 0x1C, 0x4E, ++ 0x1C, 0x49, 0xD6, 0xF8, 0x84, 0x33, 0x01, 0x92, 0x01, 0xEB, 0xC4, 0x01, ++ 0x20, 0x46, 0x98, 0x47, 0x01, 0x9A, 0xD6, 0xF8, 0x84, 0x33, 0x05, 0xF1, ++ 0x0C, 0x01, 0x20, 0x46, 0x98, 0x47, 0x00, 0x23, 0x20, 0x46, 0x2B, 0x60, ++ 0x6B, 0x61, 0xFE, 0xF7, 0x59, 0xFE, 0x13, 0x4B, 0x01, 0x22, 0x1B, 0x68, ++ 0x02, 0xFA, 0x04, 0xF4, 0xEF, 0xF3, 0x10, 0x81, 0xC9, 0x07, 0x02, 0xD4, ++ 0x72, 0xB6, 0x0F, 0x49, 0x0A, 0x60, 0x0F, 0x4A, 0x0C, 0x4D, 0x11, 0x68, ++ 0x23, 0xEA, 0x04, 0x03, 0x48, 0x1C, 0x10, 0x60, 0x2B, 0x60, 0x28, 0xB1, ++ 0x09, 0x4B, 0x11, 0x60, 0x1B, 0x68, 0x09, 0xB9, 0x03, 0xB1, 0x62, 0xB6, ++ 0x08, 0x4B, 0x1C, 0x60, 0x02, 0xB0, 0x70, 0xBD, 0x07, 0x4D, 0xC8, 0xE7, ++ 0x20, 0x62, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x24, 0x64, 0x17, 0x00, ++ 0x8C, 0x80, 0x32, 0x40, 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x88, 0x80, 0x32, 0x40, 0xC4, 0x63, 0x17, 0x00, 0x70, 0xB5, 0x0E, 0x4E, ++ 0x82, 0xB0, 0x00, 0xF5, 0x9E, 0x64, 0x00, 0x25, 0xE8, 0xB2, 0x21, 0x46, ++ 0xD6, 0xF8, 0x84, 0x33, 0x01, 0x90, 0x4F, 0xF0, 0x80, 0x42, 0x98, 0x47, ++ 0x01, 0x35, 0xA4, 0xF1, 0x28, 0x01, 0x01, 0x98, 0xD6, 0xF8, 0x84, 0x33, ++ 0x4F, 0xF0, 0x80, 0x42, 0x98, 0x47, 0x05, 0x2D, 0x04, 0xF1, 0x08, 0x04, ++ 0xEA, 0xD1, 0x02, 0xB0, 0x70, 0xBD, 0x00, 0xBF, 0x88, 0x1A, 0x17, 0x00, ++ 0x05, 0x29, 0x2D, 0xE9, 0xF0, 0x41, 0x0E, 0x46, 0x04, 0x46, 0x64, 0xD0, ++ 0x33, 0x4D, 0x01, 0xEB, 0x41, 0x03, 0xC3, 0xEB, 0xC3, 0x03, 0x05, 0xEB, ++ 0x83, 0x05, 0x94, 0xF8, 0x35, 0x10, 0x94, 0xF8, 0x33, 0x20, 0xA3, 0x88, ++ 0x2E, 0x48, 0x0A, 0x44, 0x1A, 0x44, 0xE3, 0x6C, 0xE1, 0x8B, 0x58, 0x61, ++ 0x04, 0x32, 0xDA, 0x62, 0x00, 0x22, 0xC3, 0xE9, 0x0F, 0x22, 0xC3, 0xE9, ++ 0x06, 0x22, 0xC3, 0xE9, 0x08, 0x22, 0x5A, 0x64, 0x9A, 0x62, 0x9A, 0x63, ++ 0xDA, 0x64, 0x1A, 0x63, 0x1A, 0x65, 0xCA, 0x07, 0x05, 0xD4, 0x22, 0x4A, ++ 0xD2, 0xF8, 0xF8, 0x31, 0x01, 0x33, 0xC2, 0xF8, 0xF8, 0x31, 0x21, 0x4B, ++ 0x1B, 0x6A, 0x23, 0xB1, 0x20, 0x4A, 0x13, 0x68, 0x43, 0xF4, 0x80, 0x33, ++ 0x13, 0x60, 0xDF, 0xF8, 0x88, 0x80, 0x61, 0x7F, 0x20, 0x7F, 0x00, 0x22, ++ 0x12, 0xF0, 0x5A, 0xF9, 0xD8, 0xF8, 0x48, 0x32, 0xE1, 0x7E, 0x60, 0x7F, ++ 0x98, 0x47, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, ++ 0x16, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x16, 0x4F, 0xD8, 0xF8, 0x68, 0x33, ++ 0x3A, 0x68, 0x01, 0x32, 0x3A, 0x60, 0x31, 0x46, 0x20, 0x46, 0x98, 0x47, ++ 0xD8, 0xF8, 0x08, 0x34, 0x31, 0x46, 0x00, 0x22, 0x20, 0x46, 0x98, 0x47, ++ 0x21, 0x46, 0x05, 0xF1, 0x0C, 0x00, 0x14, 0xF0, 0x99, 0xFB, 0x3B, 0x68, ++ 0x33, 0xB1, 0x0A, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x3B, 0x60, 0x0B, 0xB9, ++ 0x02, 0xB1, 0x62, 0xB6, 0x00, 0x20, 0xBD, 0xE8, 0xF0, 0x81, 0x07, 0x4D, ++ 0x9F, 0xE7, 0x00, 0xBF, 0x20, 0x62, 0x17, 0x00, 0xBE, 0xBA, 0xFE, 0xCA, ++ 0x1C, 0x9E, 0x17, 0x00, 0x80, 0x00, 0x32, 0x40, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0xC4, 0x63, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x03, 0x4A, 0xD2, 0xF8, 0xF8, 0x31, 0x01, 0x33, 0xC2, 0xF8, 0xF8, 0x31, ++ 0x70, 0x47, 0x00, 0xBF, 0x20, 0x62, 0x17, 0x00, 0x05, 0x29, 0x2D, 0xE9, ++ 0xF0, 0x41, 0x0D, 0x46, 0x04, 0x46, 0x1C, 0xD0, 0x47, 0x4E, 0x01, 0xEB, ++ 0x41, 0x03, 0xC3, 0xEB, 0xC3, 0x03, 0x06, 0xEB, 0x83, 0x06, 0x22, 0x7F, ++ 0x44, 0x4B, 0xE7, 0x6C, 0x4F, 0xF4, 0xA4, 0x60, 0x00, 0xFB, 0x02, 0x30, ++ 0xFF, 0xF7, 0x32, 0xFE, 0x68, 0xB9, 0x63, 0x7F, 0xFF, 0x2B, 0x67, 0xD0, ++ 0x3F, 0x4B, 0x20, 0x46, 0xD3, 0xF8, 0x90, 0x33, 0x29, 0x46, 0x98, 0x47, ++ 0x01, 0x20, 0xBD, 0xE8, 0xF0, 0x81, 0x3C, 0x4E, 0xE7, 0xE7, 0x20, 0x46, ++ 0x1C, 0xF0, 0xEE, 0xFF, 0x00, 0x28, 0xEC, 0xD0, 0xFB, 0x6C, 0x43, 0xF4, ++ 0x80, 0x73, 0xFB, 0x64, 0xEF, 0xF3, 0x10, 0x83, 0xDA, 0x07, 0x03, 0xD4, ++ 0x72, 0xB6, 0x35, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x34, 0x4F, 0x96, 0xF8, ++ 0x50, 0x30, 0x3A, 0x68, 0xF1, 0x6A, 0xDF, 0xF8, 0xBC, 0x80, 0x01, 0x32, ++ 0x01, 0x33, 0x3A, 0x60, 0x86, 0xF8, 0x50, 0x30, 0x19, 0xB1, 0xD8, 0xF8, ++ 0x5C, 0x33, 0x28, 0x46, 0x98, 0x47, 0x73, 0x69, 0x00, 0x2B, 0x42, 0xD0, ++ 0x06, 0xF1, 0x0C, 0x00, 0x21, 0x46, 0x14, 0xF0, 0x21, 0xFB, 0x3B, 0x68, ++ 0x2B, 0xB1, 0x26, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x3B, 0x60, 0x00, 0x2B, ++ 0x31, 0xD0, 0x1F, 0x4A, 0x24, 0x49, 0xD2, 0xF8, 0xF8, 0x31, 0x09, 0x6A, ++ 0x01, 0x33, 0xC2, 0xF8, 0xF8, 0x31, 0x21, 0xB1, 0x21, 0x4A, 0x13, 0x68, ++ 0x43, 0xF4, 0x80, 0x33, 0x13, 0x60, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, ++ 0x03, 0xD4, 0x72, 0xB6, 0x19, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x3B, 0x68, ++ 0xD8, 0xF8, 0x04, 0x64, 0xA1, 0x6C, 0x01, 0x33, 0x3B, 0x60, 0x2A, 0x46, ++ 0x20, 0x46, 0xB0, 0x47, 0x3B, 0x68, 0x33, 0xB1, 0x12, 0x4A, 0x01, 0x3B, ++ 0x12, 0x68, 0x3B, 0x60, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0x01, 0x20, ++ 0xBD, 0xE8, 0xF0, 0x81, 0x20, 0x46, 0x00, 0x21, 0x01, 0xF0, 0x7E, 0xF9, ++ 0x00, 0x20, 0xBD, 0xE8, 0xF0, 0x81, 0x00, 0x2A, 0xCB, 0xD0, 0x62, 0xB6, ++ 0xC9, 0xE7, 0xA3, 0x6C, 0x0B, 0x49, 0x5A, 0x6A, 0x9C, 0x60, 0x22, 0xF0, ++ 0x10, 0x02, 0x5A, 0x62, 0xD9, 0x60, 0xB3, 0xE7, 0x20, 0x62, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0xC4, 0x63, 0x17, 0x00, ++ 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0x1C, 0x9E, 0x17, 0x00, ++ 0x80, 0x00, 0x32, 0x40, 0xDE, 0xFA, 0xFE, 0xCA, 0x70, 0x47, 0x00, 0xBF, ++ 0x20, 0x4B, 0x70, 0xB5, 0x1C, 0x68, 0xE1, 0x04, 0x2C, 0xD4, 0x1F, 0x4D, ++ 0x2C, 0x42, 0x24, 0xD1, 0x1E, 0x4B, 0x23, 0x40, 0x20, 0xD0, 0x22, 0x03, ++ 0x0B, 0xD5, 0x1D, 0x4B, 0x4F, 0xF4, 0x00, 0x22, 0x1A, 0x60, 0x05, 0x24, ++ 0x1B, 0x4B, 0x20, 0x46, 0xD3, 0xF8, 0xA0, 0x33, 0xBD, 0xE8, 0x70, 0x40, ++ 0x18, 0x47, 0x19, 0x4A, 0x12, 0x68, 0xB2, 0xF9, 0x00, 0x20, 0xB3, 0xFA, ++ 0x83, 0xF3, 0xC3, 0xF1, 0x19, 0x04, 0x00, 0x2A, 0xE4, 0xB2, 0x14, 0xDB, ++ 0x05, 0x2C, 0xE6, 0xD0, 0x10, 0x4A, 0xA1, 0x1D, 0x01, 0x23, 0x8B, 0x40, ++ 0x13, 0x60, 0xE5, 0xE7, 0x70, 0xBD, 0x04, 0xF0, 0x07, 0xFB, 0x0C, 0x4B, ++ 0x1D, 0x60, 0xD5, 0xE7, 0x04, 0xF0, 0x56, 0xFA, 0x09, 0x4B, 0x4F, 0xF4, ++ 0x80, 0x52, 0x1A, 0x60, 0xCB, 0xE7, 0x06, 0x2C, 0xE8, 0xD9, 0x09, 0x49, ++ 0x09, 0x48, 0x40, 0xF6, 0xC2, 0x22, 0x15, 0xF0, 0xD9, 0xFE, 0xE3, 0xE7, ++ 0x78, 0x80, 0x32, 0x40, 0x00, 0x08, 0x00, 0x20, 0xC0, 0x07, 0x08, 0x00, ++ 0x7C, 0x80, 0x32, 0x40, 0x88, 0x1A, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xB8, 0x8F, 0x15, 0x00, 0x38, 0xB5, 0x0D, 0x4B, ++ 0x0D, 0x4D, 0x1C, 0x68, 0xE3, 0x06, 0x05, 0xEA, 0x04, 0x05, 0x03, 0xD5, ++ 0x0B, 0x4B, 0xD3, 0xF8, 0xF0, 0x33, 0x98, 0x47, 0x14, 0xF4, 0x70, 0x04, ++ 0x08, 0xD0, 0x08, 0x4B, 0xB4, 0xFA, 0x84, 0xF4, 0xC4, 0xF1, 0x0B, 0x00, ++ 0xD3, 0xF8, 0x48, 0x33, 0xC0, 0xB2, 0x98, 0x47, 0x04, 0x4B, 0x1D, 0x60, ++ 0x38, 0xBD, 0x00, 0xBF, 0x78, 0x80, 0x32, 0x40, 0x1F, 0x00, 0xF0, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x7C, 0x80, 0x32, 0x40, 0xFF, 0xF7, 0xDA, 0xBF, ++ 0x2D, 0xE9, 0xF8, 0x43, 0xEF, 0xF3, 0x10, 0x83, 0xDA, 0x07, 0x03, 0xD4, ++ 0x72, 0xB6, 0x1C, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0xDF, 0xF8, 0x70, 0x90, ++ 0x1A, 0x4F, 0xD9, 0xF8, 0x00, 0x30, 0xDF, 0xF8, 0x6C, 0x80, 0x01, 0x33, ++ 0xC9, 0xF8, 0x00, 0x30, 0x3D, 0x46, 0x46, 0x46, 0x04, 0x24, 0x95, 0xF8, ++ 0x5E, 0x30, 0xE2, 0xB2, 0x63, 0xB9, 0x97, 0xF8, 0x8C, 0x30, 0x97, 0xF8, ++ 0x7E, 0x10, 0x10, 0x46, 0x0B, 0xB1, 0x91, 0x42, 0x04, 0xD0, 0xD6, 0xF8, ++ 0x50, 0x31, 0x0B, 0xB1, 0xFF, 0xF7, 0x1A, 0xFD, 0x01, 0x3C, 0x63, 0x1C, ++ 0xA5, 0xF1, 0x0C, 0x05, 0xA6, 0xF1, 0x54, 0x06, 0xE7, 0xD1, 0xD9, 0xF8, ++ 0x00, 0x30, 0x01, 0x22, 0x88, 0xF8, 0xFF, 0x21, 0x3B, 0xB1, 0x05, 0x4A, ++ 0x01, 0x3B, 0x12, 0x68, 0xC9, 0xF8, 0x00, 0x30, 0x0B, 0xB9, 0x02, 0xB1, ++ 0x62, 0xB6, 0xBD, 0xE8, 0xF8, 0x83, 0x00, 0xBF, 0x38, 0x61, 0x17, 0x00, ++ 0x94, 0x64, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0x20, 0x62, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0x83, 0xB0, 0xEF, 0xF3, 0x10, 0x83, 0xDA, 0x07, ++ 0x03, 0xD4, 0x72, 0xB6, 0x31, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x31, 0x4E, ++ 0x31, 0x4D, 0x33, 0x68, 0x31, 0x4F, 0xDF, 0xF8, 0xD0, 0xB0, 0xDF, 0xF8, ++ 0xD0, 0xA0, 0xDF, 0xF8, 0xD0, 0x80, 0x01, 0x33, 0x00, 0x22, 0x33, 0x60, ++ 0x85, 0xF8, 0xFF, 0x21, 0xB9, 0x46, 0x04, 0x24, 0x99, 0xF8, 0x5E, 0x30, ++ 0xE0, 0xB2, 0x00, 0x2B, 0x34, 0xD1, 0x97, 0xF8, 0x8C, 0x30, 0x97, 0xF8, ++ 0x7E, 0x20, 0x0B, 0xB1, 0x82, 0x42, 0x2D, 0xD0, 0xD5, 0xF8, 0x50, 0x31, ++ 0x43, 0xB3, 0x01, 0x90, 0xFE, 0xF7, 0x36, 0xFF, 0x5A, 0xF8, 0x24, 0x30, ++ 0xDB, 0xF8, 0x00, 0x20, 0x20, 0x48, 0x1A, 0x44, 0x40, 0xF8, 0x24, 0x20, ++ 0x01, 0x21, 0x1F, 0x4A, 0x01, 0xFA, 0x04, 0xF3, 0x13, 0x60, 0xEF, 0xF3, ++ 0x10, 0x82, 0x12, 0xF0, 0x01, 0x0F, 0x01, 0x98, 0x02, 0xD1, 0x72, 0xB6, ++ 0x14, 0x4A, 0x11, 0x60, 0x32, 0x68, 0xD8, 0xF8, 0x00, 0xC0, 0x51, 0x1C, ++ 0x43, 0xEA, 0x0C, 0x03, 0x31, 0x60, 0xC8, 0xF8, 0x00, 0x30, 0x29, 0xB1, ++ 0x0E, 0x4B, 0x32, 0x60, 0x1B, 0x68, 0x0A, 0xB9, 0x03, 0xB1, 0x62, 0xB6, ++ 0x03, 0xF0, 0x32, 0xF8, 0x01, 0x3C, 0x63, 0x1C, 0xA9, 0xF1, 0x0C, 0x09, ++ 0xA5, 0xF1, 0x54, 0x05, 0xBE, 0xD1, 0x33, 0x68, 0x33, 0xB1, 0x06, 0x4A, ++ 0x01, 0x3B, 0x12, 0x68, 0x33, 0x60, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, ++ 0x40, 0x20, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x4F, 0x14, 0xF0, 0xF8, 0xB8, ++ 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0x20, 0x62, 0x17, 0x00, ++ 0x94, 0x64, 0x17, 0x00, 0x28, 0x01, 0x32, 0x40, 0x88, 0x80, 0x32, 0x40, ++ 0x20, 0x01, 0x32, 0x40, 0xB0, 0x35, 0x17, 0x00, 0x8C, 0x80, 0x32, 0x40, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0x5D, 0x4E, 0xDF, 0xF8, 0x90, 0x91, 0xB6, 0xF8, ++ 0xFC, 0x31, 0x83, 0xB0, 0x4F, 0xF4, 0x78, 0x30, 0x00, 0x93, 0x06, 0xF1, ++ 0x0C, 0x05, 0x14, 0xF0, 0xFB, 0xF8, 0x01, 0x23, 0x86, 0xF8, 0xFE, 0x31, ++ 0xAA, 0x46, 0x4F, 0xF4, 0x9E, 0x67, 0x4F, 0xF0, 0x00, 0x0B, 0x01, 0x95, ++ 0x53, 0x49, 0xD9, 0xF8, 0x84, 0x33, 0x5F, 0xFA, 0x8B, 0xF8, 0x40, 0x46, ++ 0x4F, 0xF0, 0x80, 0x42, 0x39, 0x44, 0x98, 0x47, 0x4F, 0x4B, 0x9D, 0x68, ++ 0xA7, 0xF1, 0x28, 0x04, 0xC5, 0xB1, 0xE9, 0x19, 0xD9, 0xF8, 0x84, 0x33, ++ 0x4F, 0xF0, 0x80, 0x42, 0x40, 0x46, 0x98, 0x47, 0x29, 0x19, 0xD9, 0xF8, ++ 0x84, 0x33, 0x4F, 0xF0, 0x80, 0x42, 0x40, 0x46, 0x98, 0x47, 0x05, 0xF5, ++ 0xA3, 0x61, 0xD9, 0xF8, 0x84, 0x33, 0x4F, 0xF0, 0x80, 0x42, 0x40, 0x46, ++ 0x98, 0x47, 0x2D, 0x68, 0x00, 0x2D, 0xE6, 0xD1, 0x51, 0x46, 0xD9, 0xF8, ++ 0x84, 0x33, 0x40, 0x46, 0x08, 0x37, 0x4F, 0xF0, 0x80, 0x42, 0x98, 0x47, ++ 0xB7, 0xF5, 0xA3, 0x6F, 0x0B, 0xF1, 0x01, 0x0B, 0x0A, 0xF1, 0x54, 0x0A, ++ 0xC8, 0xD1, 0xD9, 0xF8, 0x84, 0x33, 0x39, 0x49, 0x01, 0x9D, 0x4F, 0xF0, ++ 0x80, 0x42, 0x05, 0x20, 0x98, 0x47, 0x37, 0x49, 0xD9, 0xF8, 0x84, 0x33, ++ 0x4F, 0xF0, 0x80, 0x42, 0x05, 0x20, 0x98, 0x47, 0x02, 0xF0, 0x30, 0xF9, ++ 0x00, 0xF0, 0x6A, 0xF9, 0xD9, 0xF8, 0xCC, 0x33, 0x98, 0x47, 0x2C, 0x48, ++ 0x4F, 0xF4, 0x01, 0x72, 0x00, 0x21, 0xF1, 0xF7, 0x89, 0xF8, 0x2B, 0x4B, ++ 0xD3, 0xF8, 0x08, 0x80, 0x00, 0x9B, 0xA6, 0xF8, 0xFC, 0x31, 0xB8, 0xF1, ++ 0x00, 0x0F, 0x17, 0xD0, 0x2B, 0x46, 0x45, 0x46, 0x98, 0x46, 0x05, 0xF5, ++ 0x9E, 0x64, 0x05, 0xF5, 0xA3, 0x67, 0x20, 0x46, 0x14, 0xF0, 0x06, 0xF9, ++ 0xA4, 0xF1, 0x28, 0x00, 0x08, 0x34, 0x14, 0xF0, 0x01, 0xF9, 0xBC, 0x42, ++ 0xF5, 0xD1, 0x20, 0x46, 0x14, 0xF0, 0xFC, 0xF8, 0x2D, 0x68, 0x00, 0x2D, ++ 0xEB, 0xD1, 0x45, 0x46, 0x1B, 0x4F, 0x00, 0x24, 0x28, 0x46, 0x14, 0xF0, ++ 0xF3, 0xF8, 0x45, 0xF8, 0x0C, 0x4C, 0xAC, 0x73, 0x85, 0xF8, 0x44, 0x40, ++ 0xC5, 0xE9, 0x06, 0x44, 0x05, 0xF1, 0x10, 0x00, 0x54, 0x35, 0x14, 0xF0, ++ 0xE7, 0xF8, 0xAF, 0x42, 0xEE, 0xD1, 0x12, 0x48, 0x14, 0xF0, 0xE2, 0xF8, ++ 0x12, 0x48, 0xC6, 0xF8, 0xA4, 0x41, 0xC6, 0xE9, 0x72, 0x44, 0x86, 0xF8, ++ 0xBE, 0x41, 0x86, 0xF8, 0xF4, 0x41, 0x14, 0xF0, 0xD7, 0xF8, 0x0E, 0x4A, ++ 0x00, 0x21, 0x02, 0xF5, 0xB4, 0x70, 0xA2, 0xF1, 0x24, 0x03, 0x43, 0xF8, ++ 0x04, 0x1B, 0x93, 0x42, 0xFB, 0xD1, 0x03, 0xF1, 0x24, 0x02, 0x90, 0x42, ++ 0xF5, 0xD1, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x20, 0x62, 0x17, 0x00, ++ 0x34, 0x5F, 0x17, 0x00, 0x00, 0x88, 0x17, 0x00, 0xD0, 0x63, 0x17, 0x00, ++ 0x4C, 0x64, 0x17, 0x00, 0xE0, 0x63, 0x17, 0x00, 0xD8, 0x56, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x03, 0x8C, 0x08, 0x8C, 0x83, 0x42, 0x08, 0xD8, ++ 0x05, 0xD2, 0xC0, 0x1A, 0x3F, 0x28, 0xCC, 0xBF, 0x00, 0x20, 0x01, 0x20, ++ 0x70, 0x47, 0x01, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0xBF, ++ 0x51, 0xB9, 0x81, 0x6C, 0x90, 0xF8, 0x42, 0x30, 0xCB, 0x1A, 0x93, 0xF8, ++ 0xB8, 0x30, 0xDB, 0x07, 0x02, 0xD4, 0x03, 0x8B, 0x08, 0x2B, 0x00, 0xD0, ++ 0x70, 0x47, 0x91, 0xF8, 0xA8, 0x30, 0x03, 0xF0, 0xF0, 0x03, 0x40, 0x2B, ++ 0xF8, 0xD1, 0x91, 0xF8, 0xB1, 0x30, 0x06, 0x2B, 0x01, 0xD0, 0x01, 0x2B, ++ 0xF2, 0xD1, 0x13, 0x68, 0x01, 0x33, 0x13, 0x60, 0xEE, 0xE7, 0x00, 0xBF, ++ 0x03, 0x6D, 0x00, 0x2B, 0x00, 0xDB, 0x70, 0x47, 0x2D, 0xE9, 0xF0, 0x43, ++ 0x56, 0x4A, 0x12, 0x68, 0x12, 0x78, 0x02, 0x2A, 0x83, 0xB0, 0x04, 0x46, ++ 0x0D, 0x46, 0x07, 0xD0, 0x01, 0x2A, 0x7E, 0xD0, 0x03, 0x2A, 0x00, 0xF0, ++ 0x8D, 0x80, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x83, 0xFB, 0xF7, 0x8A, 0xFB, ++ 0x06, 0x46, 0x00, 0x28, 0x00, 0xF0, 0x94, 0x80, 0xDF, 0xF8, 0x60, 0x91, ++ 0x42, 0xF2, 0x24, 0x03, 0x59, 0xF8, 0x03, 0x30, 0x00, 0x2B, 0x00, 0xF0, ++ 0x87, 0x80, 0x48, 0x48, 0x14, 0xF0, 0xA8, 0xF8, 0x4F, 0xF0, 0x00, 0x08, ++ 0x08, 0x22, 0x12, 0x23, 0x32, 0x70, 0x86, 0xF8, 0x01, 0x80, 0x86, 0xF8, ++ 0x03, 0x80, 0xB3, 0x70, 0x23, 0x6D, 0x29, 0x68, 0x00, 0x91, 0x23, 0xF0, ++ 0x40, 0x43, 0x07, 0x46, 0x69, 0x46, 0x30, 0x1D, 0x01, 0x93, 0x27, 0xF0, ++ 0x49, 0xFF, 0x42, 0xF2, 0x34, 0x03, 0x39, 0xF8, 0x03, 0x30, 0xB3, 0xF5, ++ 0xC3, 0x7F, 0x62, 0xD8, 0x03, 0xF1, 0x01, 0x0E, 0x1F, 0xFA, 0x8E, 0xFE, ++ 0xDA, 0x00, 0x37, 0x49, 0xBB, 0x81, 0x09, 0x68, 0x36, 0x4B, 0x01, 0xEB, ++ 0x02, 0x0C, 0x42, 0xF2, 0x34, 0x08, 0xCC, 0xF8, 0x04, 0x60, 0x88, 0x58, ++ 0x03, 0x40, 0x43, 0xF0, 0x80, 0x63, 0x43, 0xF0, 0x0C, 0x03, 0x8B, 0x50, ++ 0x99, 0xF8, 0x02, 0x3C, 0x29, 0xF8, 0x08, 0xE0, 0x01, 0x33, 0x01, 0x22, ++ 0x00, 0x20, 0x0C, 0x21, 0x89, 0xF8, 0x02, 0x3C, 0xC7, 0xF8, 0x04, 0xC0, ++ 0xBA, 0x73, 0x38, 0x60, 0xB9, 0x60, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, ++ 0x02, 0xD4, 0x72, 0xB6, 0x26, 0x4B, 0x1A, 0x60, 0x26, 0x4E, 0x2B, 0x68, ++ 0x31, 0x68, 0x22, 0x8C, 0x25, 0x48, 0x4D, 0x1C, 0x21, 0x46, 0x35, 0x60, ++ 0x15, 0xF0, 0xEC, 0xF9, 0x23, 0x48, 0x39, 0x46, 0x14, 0xF0, 0x0E, 0xF8, ++ 0x22, 0x4B, 0xD3, 0xF8, 0x44, 0x34, 0x98, 0x47, 0x33, 0x68, 0x00, 0x2B, ++ 0x8D, 0xD0, 0x1B, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x33, 0x60, 0x00, 0x2B, ++ 0x87, 0xD1, 0x00, 0x2A, 0x85, 0xD0, 0x62, 0xB6, 0x83, 0xE7, 0x0E, 0x68, ++ 0x00, 0x96, 0x23, 0xF0, 0x40, 0x43, 0x69, 0x46, 0x08, 0x22, 0x12, 0x20, ++ 0x01, 0x93, 0xF9, 0xF7, 0xD7, 0xFA, 0x2B, 0x68, 0x22, 0x8C, 0x15, 0x48, ++ 0x21, 0x46, 0x15, 0xF0, 0xC7, 0xF9, 0x72, 0xE7, 0x13, 0x4B, 0x0A, 0x68, ++ 0x1B, 0x68, 0x1A, 0x60, 0xF6, 0xF7, 0x72, 0xF8, 0x6B, 0xE7, 0x42, 0x46, ++ 0x43, 0x46, 0x4F, 0xF0, 0x01, 0x0E, 0x9C, 0xE7, 0x0E, 0x48, 0xF6, 0xF7, ++ 0xED, 0xFF, 0x62, 0xE7, 0x0D, 0x48, 0xF6, 0xF7, 0xE9, 0xFF, 0x5E, 0xE7, ++ 0x78, 0x36, 0x17, 0x00, 0xA0, 0x56, 0x17, 0x00, 0x54, 0x60, 0x17, 0x00, ++ 0x00, 0x00, 0xFF, 0x31, 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x00, 0x90, 0x15, 0x00, 0xA8, 0x56, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x20, 0x90, 0x15, 0x00, 0x00, 0x38, 0x18, 0x00, 0xDC, 0x8F, 0x15, 0x00, ++ 0xD8, 0x83, 0x15, 0x00, 0x7C, 0x36, 0x17, 0x00, 0x10, 0xB5, 0x0D, 0x4C, ++ 0x30, 0x22, 0x00, 0x21, 0x20, 0x46, 0xF0, 0xF7, 0x21, 0xFF, 0x20, 0x46, ++ 0x13, 0xF0, 0xAE, 0xFF, 0x04, 0xF1, 0x08, 0x00, 0x13, 0xF0, 0xAA, 0xFF, ++ 0x04, 0xF1, 0x10, 0x00, 0x13, 0xF0, 0xA6, 0xFF, 0x04, 0xF1, 0x18, 0x00, ++ 0x13, 0xF0, 0xA2, 0xFF, 0x04, 0xF1, 0x20, 0x00, 0xBD, 0xE8, 0x10, 0x40, ++ 0x13, 0xF0, 0x9C, 0xBF, 0x24, 0x64, 0x17, 0x00, 0x38, 0xB5, 0xC3, 0x6C, ++ 0x04, 0x46, 0x09, 0x48, 0x19, 0x61, 0x00, 0xEB, 0xC2, 0x00, 0x21, 0x46, ++ 0x15, 0x46, 0x13, 0xF0, 0x93, 0xFF, 0x63, 0x6A, 0x9B, 0x02, 0x00, 0xD5, ++ 0x38, 0xBD, 0x04, 0x4B, 0x53, 0xF8, 0x25, 0x00, 0xBD, 0xE8, 0x38, 0x40, ++ 0x13, 0xF0, 0xE6, 0xBE, 0x24, 0x64, 0x17, 0x00, 0xC4, 0x90, 0x15, 0x00, ++ 0x38, 0xB5, 0x38, 0x4B, 0x93, 0xF8, 0x8C, 0x20, 0x05, 0x46, 0x00, 0x2A, ++ 0x42, 0xD1, 0x43, 0x6D, 0xC3, 0xF3, 0xC1, 0x23, 0x54, 0x22, 0x1C, 0x21, ++ 0x33, 0x48, 0x12, 0xFB, 0x03, 0x13, 0x18, 0x44, 0x13, 0xF0, 0xB6, 0xFF, ++ 0x04, 0x46, 0x31, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x20, 0x00, 0x2A, ++ 0x01, 0xDB, 0x14, 0xB9, 0x38, 0xBD, 0x00, 0x2C, 0x4C, 0xD0, 0xA2, 0x88, ++ 0x68, 0x6D, 0x42, 0xF0, 0x20, 0x02, 0x81, 0x01, 0xA2, 0x80, 0xF5, 0xD5, ++ 0xB3, 0xF9, 0x00, 0x20, 0x00, 0x2A, 0xC0, 0xF3, 0xCF, 0x31, 0xC0, 0xF3, ++ 0xC9, 0x33, 0x26, 0xDB, 0x62, 0x7A, 0x10, 0x3B, 0x93, 0x42, 0xE9, 0xD1, ++ 0xEB, 0x69, 0x99, 0x68, 0x0B, 0x8A, 0x03, 0xF0, 0x1E, 0x02, 0x16, 0x2A, ++ 0x25, 0xD0, 0x82, 0x05, 0xE0, 0xD4, 0x2A, 0x8E, 0x1C, 0x2A, 0xDD, 0xD1, ++ 0xA2, 0x7A, 0xB2, 0xEB, 0x13, 0x3F, 0xD9, 0xD1, 0x04, 0xF1, 0xE0, 0x05, ++ 0x12, 0x31, 0x28, 0x46, 0x0A, 0x22, 0x27, 0xF0, 0x37, 0xFE, 0xC4, 0xF8, ++ 0xDC, 0x50, 0x1A, 0xE0, 0x93, 0xF8, 0x7E, 0x30, 0x05, 0x2B, 0xBB, 0xD1, ++ 0x14, 0x48, 0x13, 0xF0, 0x77, 0xFF, 0x04, 0x46, 0xBF, 0xE7, 0x11, 0xF4, ++ 0x7C, 0x7F, 0xD5, 0xD1, 0xBD, 0xE8, 0x38, 0x40, 0x10, 0x49, 0x11, 0x48, ++ 0xD0, 0x22, 0x15, 0xF0, 0x49, 0xBB, 0x10, 0x4B, 0x28, 0x46, 0xD3, 0xF8, ++ 0xB4, 0x33, 0x21, 0x46, 0x98, 0x47, 0x00, 0x28, 0xB4, 0xD0, 0xA3, 0x88, ++ 0x43, 0xF0, 0x40, 0x03, 0xA3, 0x80, 0x38, 0xBD, 0xBD, 0xE8, 0x38, 0x40, ++ 0x06, 0x49, 0x09, 0x48, 0x40, 0xF2, 0x5F, 0x12, 0x15, 0xF0, 0x34, 0xBB, ++ 0x94, 0x64, 0x17, 0x00, 0x20, 0x62, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0xE0, 0x63, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x50, 0x90, 0x15, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x3C, 0x90, 0x15, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0xB0, 0x4B, 0xB1, 0x4C, 0x1B, 0x68, 0xB1, 0x4A, 0xB3, 0xF9, 0x00, 0x30, ++ 0x2D, 0xED, 0x02, 0x8B, 0x87, 0xB0, 0x01, 0x46, 0x01, 0x90, 0x00, 0x2B, ++ 0x04, 0xEB, 0xC0, 0x00, 0x08, 0xEE, 0x10, 0x0A, 0x52, 0xF8, 0x21, 0x40, ++ 0xC0, 0xF2, 0x38, 0x83, 0x20, 0x46, 0x13, 0xF0, 0x6B, 0xFE, 0xA6, 0x4B, ++ 0x01, 0x9A, 0x53, 0xF8, 0x32, 0x40, 0x00, 0x2C, 0x00, 0xF0, 0xAD, 0x80, ++ 0x00, 0x23, 0xCD, 0xE9, 0x04, 0x33, 0x9B, 0x46, 0x98, 0x46, 0xA2, 0x4B, ++ 0x62, 0x7F, 0x93, 0xF8, 0x00, 0x32, 0x03, 0x92, 0x01, 0x2B, 0x22, 0x7F, ++ 0xE6, 0x6C, 0x67, 0x6C, 0x02, 0x92, 0x00, 0xF0, 0xA1, 0x80, 0x00, 0x2F, ++ 0x00, 0xF0, 0xA8, 0x80, 0x3B, 0x79, 0xD8, 0x06, 0x40, 0xF1, 0x95, 0x80, ++ 0x35, 0x69, 0x59, 0x06, 0x25, 0xF4, 0x00, 0x05, 0x0B, 0xF1, 0x01, 0x0B, ++ 0x35, 0x61, 0x00, 0xF1, 0x9B, 0x81, 0xDF, 0xF8, 0x70, 0xA2, 0x00, 0x21, ++ 0xDA, 0xF8, 0x18, 0x34, 0x20, 0x46, 0x98, 0x47, 0x63, 0x6A, 0x03, 0xF4, ++ 0x60, 0x13, 0xB3, 0xF5, 0x20, 0x1F, 0x08, 0xBF, 0xA0, 0x46, 0xEF, 0xF3, ++ 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x8B, 0x4B, 0x01, 0x22, ++ 0x1A, 0x60, 0xDF, 0xF8, 0x38, 0x92, 0xD9, 0xF8, 0x00, 0x30, 0x18, 0xEE, ++ 0x10, 0x0A, 0x01, 0x33, 0xC9, 0xF8, 0x00, 0x30, 0x13, 0xF0, 0xE4, 0xFE, ++ 0x63, 0x6A, 0x03, 0xF4, 0x60, 0x13, 0xB3, 0xF5, 0x60, 0x1F, 0x00, 0xF0, ++ 0x5F, 0x81, 0xD9, 0xF8, 0x00, 0x30, 0x3B, 0xB1, 0x7F, 0x4A, 0x01, 0x3B, ++ 0x12, 0x68, 0xC9, 0xF8, 0x00, 0x30, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, ++ 0x22, 0x8B, 0x48, 0xF6, 0x88, 0x63, 0x9A, 0x42, 0x00, 0xF0, 0x30, 0x81, ++ 0xE2, 0x6A, 0xD3, 0x6B, 0x98, 0x06, 0x40, 0xF1, 0xFD, 0x80, 0x15, 0xF4, ++ 0x00, 0x05, 0x00, 0xF0, 0x7E, 0x81, 0xE1, 0x6C, 0x4F, 0x6A, 0x39, 0x88, ++ 0x88, 0xB2, 0x09, 0x04, 0x00, 0xF1, 0xEB, 0x81, 0x71, 0x4F, 0x3B, 0x68, ++ 0x1B, 0x78, 0x00, 0x2B, 0x36, 0xD0, 0x63, 0x7F, 0x09, 0x2B, 0x0E, 0xD8, ++ 0xE2, 0x7E, 0x08, 0x2A, 0x0B, 0xD8, 0x03, 0xEB, 0xC3, 0x03, 0x13, 0x44, ++ 0x6B, 0x49, 0xA0, 0x88, 0x03, 0xF6, 0x0E, 0x03, 0x51, 0xF8, 0x23, 0x20, ++ 0x12, 0x1A, 0x41, 0xF8, 0x23, 0x20, 0x68, 0x4B, 0x93, 0xF8, 0x04, 0x31, ++ 0x13, 0xB1, 0x00, 0x2D, 0x40, 0xF0, 0x33, 0x82, 0x06, 0xF1, 0x10, 0x01, ++ 0x20, 0x46, 0xFF, 0xF7, 0xC9, 0xFD, 0xE3, 0x8B, 0xDA, 0x07, 0x00, 0xF1, ++ 0x93, 0x81, 0xA0, 0x6C, 0x30, 0xB1, 0xF7, 0xF7, 0x4F, 0xFF, 0x3B, 0x68, ++ 0x1D, 0x78, 0x01, 0x2D, 0x00, 0xF0, 0xCB, 0x81, 0x9D, 0xF8, 0x04, 0x00, ++ 0x21, 0x46, 0x15, 0xF0, 0x5B, 0xFB, 0x63, 0x6A, 0x03, 0xF4, 0x60, 0x13, ++ 0xB3, 0xF5, 0x60, 0x1F, 0x00, 0xF0, 0x74, 0x81, 0x4F, 0x4B, 0x01, 0x9A, ++ 0x53, 0xF8, 0x32, 0x40, 0x00, 0x2C, 0x7F, 0xF4, 0x58, 0xAF, 0x07, 0xB0, ++ 0xBD, 0xEC, 0x02, 0x8B, 0xBD, 0xE8, 0xF0, 0x8F, 0x4B, 0x4A, 0x00, 0x23, ++ 0x40, 0x20, 0x82, 0xF8, 0x00, 0x32, 0x13, 0xF0, 0x87, 0xFD, 0x00, 0x2F, ++ 0x7F, 0xF4, 0x58, 0xAF, 0xEF, 0xF3, 0x10, 0x83, 0xDD, 0x07, 0x03, 0xD4, ++ 0x72, 0xB6, 0x45, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x47, 0x4D, 0x2B, 0x68, ++ 0x18, 0xEE, 0x10, 0x0A, 0x01, 0x33, 0x2B, 0x60, 0x13, 0xF0, 0x5A, 0xFE, ++ 0x2B, 0x68, 0x3B, 0xB1, 0x3E, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x2B, 0x60, ++ 0x13, 0xB9, 0x00, 0x2A, 0x40, 0xF0, 0xF3, 0x81, 0x20, 0x46, 0xD6, 0xF8, ++ 0x10, 0x90, 0x94, 0xF8, 0x1C, 0xA0, 0x23, 0xF0, 0x95, 0xFF, 0xE2, 0x6A, ++ 0xD3, 0x6B, 0x98, 0x06, 0x40, 0xF1, 0x8C, 0x80, 0x19, 0xF4, 0x00, 0x0F, ++ 0x0C, 0xD0, 0xE1, 0x6C, 0x4D, 0x6A, 0x29, 0x88, 0x88, 0xB2, 0x09, 0x04, ++ 0x00, 0xF1, 0xFE, 0x81, 0x32, 0x4B, 0x93, 0xF8, 0x04, 0x31, 0x00, 0x2B, ++ 0x40, 0xF0, 0x86, 0x80, 0x31, 0x4D, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, ++ 0x0A, 0x53, 0x93, 0xF8, 0xC0, 0x24, 0x42, 0xB1, 0x93, 0xF8, 0xC1, 0x34, ++ 0x2D, 0x4F, 0x03, 0xEB, 0x83, 0x03, 0xC3, 0xEB, 0xC3, 0x03, 0x07, 0xEB, ++ 0x83, 0x07, 0x63, 0x7F, 0x09, 0x2B, 0x08, 0xD8, 0xE3, 0x8B, 0x18, 0x07, ++ 0x05, 0xD4, 0x09, 0xF4, 0x01, 0x09, 0xB9, 0xF5, 0x80, 0x3F, 0x00, 0xF0, ++ 0x2B, 0x82, 0x25, 0x4F, 0x9D, 0xF8, 0x04, 0x50, 0xD7, 0xF8, 0x18, 0x34, ++ 0x00, 0x21, 0x20, 0x46, 0x98, 0x47, 0xD7, 0xF8, 0xAC, 0x33, 0x00, 0x22, ++ 0x29, 0x46, 0x20, 0x46, 0x98, 0x47, 0x22, 0x8B, 0x48, 0xF6, 0x88, 0x63, ++ 0x9A, 0x42, 0x00, 0xF0, 0x05, 0x81, 0x63, 0x7F, 0x09, 0x2B, 0x0E, 0xD8, ++ 0xE2, 0x7E, 0x08, 0x2A, 0x0B, 0xD8, 0x03, 0xEB, 0xC3, 0x03, 0x13, 0x44, ++ 0x11, 0x49, 0xA0, 0x88, 0x03, 0xF6, 0x0E, 0x03, 0x51, 0xF8, 0x23, 0x20, ++ 0x12, 0x1A, 0x41, 0xF8, 0x23, 0x20, 0x06, 0xF1, 0x10, 0x01, 0x20, 0x46, ++ 0xFF, 0xF7, 0x1C, 0xFD, 0xE3, 0x8B, 0xDB, 0x07, 0x00, 0xF1, 0x08, 0x81, ++ 0x21, 0x46, 0x28, 0x46, 0x15, 0xF0, 0xB8, 0xFA, 0x62, 0xE7, 0x00, 0xBF, ++ 0x38, 0x36, 0x17, 0x00, 0x24, 0x64, 0x17, 0x00, 0xC4, 0x90, 0x15, 0x00, ++ 0x20, 0x62, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, 0x78, 0x36, 0x17, 0x00, ++ 0x7C, 0x36, 0x17, 0x00, 0x2C, 0x19, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0x48, 0x9E, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0xB7, 0x4F, 0x3B, 0x68, 0x1B, 0x78, 0x00, 0x2B, 0x3F, 0xF4, 0x44, 0xAF, ++ 0x15, 0xF4, 0x00, 0x05, 0x7F, 0xF4, 0x09, 0xAF, 0xB4, 0xF9, 0x1E, 0x30, ++ 0xE2, 0x8B, 0x00, 0x2B, 0xC0, 0xF2, 0x81, 0x80, 0x00, 0x25, 0x00, 0xE7, ++ 0xAF, 0x4B, 0x93, 0xF8, 0x04, 0x31, 0x00, 0x2B, 0x3F, 0xF4, 0x7E, 0xAF, ++ 0x19, 0xF4, 0x00, 0x0F, 0x3F, 0xF4, 0x7A, 0xAF, 0xE3, 0x8B, 0x1D, 0x07, ++ 0x3F, 0xF5, 0x76, 0xAF, 0x23, 0x7F, 0xA9, 0x4D, 0x4F, 0xF4, 0xA4, 0x62, ++ 0x02, 0xFB, 0x03, 0x53, 0x03, 0xF1, 0x98, 0x02, 0x93, 0xF8, 0x62, 0x10, ++ 0x20, 0x46, 0xFF, 0xF7, 0xAF, 0xFC, 0x68, 0xE7, 0x33, 0x69, 0x03, 0xF0, ++ 0x0F, 0x03, 0x09, 0x2B, 0x7F, 0xF4, 0xCA, 0xAE, 0x03, 0x9B, 0xA0, 0x48, ++ 0x4F, 0xF4, 0x1E, 0x72, 0x02, 0xFB, 0x03, 0x00, 0x90, 0xF8, 0x5D, 0x32, ++ 0x01, 0x2B, 0x3F, 0xF6, 0xBF, 0xAE, 0xE2, 0x6C, 0xB0, 0xF8, 0x5E, 0x12, ++ 0xD2, 0x6A, 0x8A, 0x42, 0x3F, 0xF4, 0xB8, 0xAE, 0x01, 0x33, 0x80, 0xF8, ++ 0x5D, 0x32, 0xA0, 0xF8, 0x5E, 0x22, 0xB1, 0xE6, 0x95, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xC0, 0xF2, 0x9B, 0x80, 0x59, 0x46, ++ 0x40, 0x46, 0x04, 0x9A, 0x23, 0xF0, 0xCA, 0xFE, 0x38, 0x46, 0x02, 0xF0, ++ 0x9D, 0xF8, 0x00, 0x23, 0x04, 0x93, 0x9B, 0x46, 0x98, 0x46, 0x8C, 0xE6, ++ 0xD7, 0xF8, 0xDC, 0x20, 0xDA, 0xB1, 0x11, 0x88, 0x23, 0x8C, 0xA3, 0xEB, ++ 0x11, 0x13, 0xC3, 0xF3, 0x0B, 0x03, 0x40, 0xF2, 0xFE, 0x71, 0x8B, 0x42, ++ 0x0C, 0xD8, 0x3F, 0x2B, 0x4F, 0xEA, 0x13, 0x11, 0x08, 0xD8, 0x02, 0xEB, ++ 0x41, 0x02, 0x03, 0xF0, 0x0F, 0x03, 0x52, 0x88, 0x42, 0xFA, 0x03, 0xF3, ++ 0xDA, 0x07, 0x04, 0xD4, 0x4F, 0xF4, 0x80, 0x23, 0x1D, 0x43, 0x35, 0x61, ++ 0x45, 0xE6, 0x04, 0x9B, 0x01, 0x33, 0x04, 0x93, 0x4F, 0xF4, 0x04, 0x03, ++ 0xF6, 0xE7, 0x75, 0x4F, 0x3B, 0x68, 0x1B, 0x78, 0x00, 0x2B, 0x3F, 0xF4, ++ 0xBF, 0xAE, 0xB4, 0xF9, 0x1E, 0x30, 0xE2, 0x8B, 0x00, 0x2B, 0xBF, 0xF6, ++ 0x7F, 0xAF, 0x71, 0x4D, 0x02, 0x99, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, ++ 0x01, 0x53, 0x93, 0xF8, 0x64, 0x30, 0x00, 0x2B, 0x3F, 0xF4, 0x74, 0xAF, ++ 0xE6, 0x6C, 0x01, 0x98, 0x00, 0x21, 0xC2, 0xF3, 0x0E, 0x03, 0x31, 0x65, ++ 0x43, 0xF0, 0x01, 0x03, 0x61, 0x64, 0x31, 0x61, 0x02, 0x9E, 0xE3, 0x83, ++ 0x9E, 0x30, 0xA4, 0x23, 0x13, 0xFB, 0x06, 0x00, 0xE1, 0x62, 0x61, 0x62, ++ 0x65, 0x4A, 0x05, 0xEB, 0xC0, 0x00, 0x21, 0x46, 0x13, 0xF0, 0x60, 0xFD, ++ 0x63, 0x6A, 0x03, 0xF4, 0x60, 0x13, 0xB3, 0xF5, 0x60, 0x1F, 0x00, 0xF0, ++ 0xE4, 0x80, 0x01, 0x23, 0x05, 0x93, 0x8B, 0xE6, 0x05, 0x9B, 0x00, 0x2B, ++ 0x40, 0xF0, 0xDC, 0x80, 0x40, 0x20, 0x13, 0xF0, 0x1F, 0xFC, 0x00, 0x23, ++ 0x05, 0x93, 0x81, 0xE6, 0x40, 0x20, 0x13, 0xF0, 0x19, 0xFC, 0x68, 0xE6, ++ 0x33, 0x69, 0x03, 0xF0, 0x0F, 0x03, 0x09, 0x2B, 0x7F, 0xF4, 0xF5, 0xAE, ++ 0x03, 0x9B, 0x51, 0x48, 0x4F, 0xF4, 0x1E, 0x72, 0x02, 0xFB, 0x03, 0x00, ++ 0x90, 0xF8, 0x5D, 0x32, 0x01, 0x2B, 0x3F, 0xF6, 0xEA, 0xAE, 0xE2, 0x6C, ++ 0xB0, 0xF8, 0x5E, 0x12, 0xD2, 0x6A, 0x8A, 0x42, 0x3F, 0xF4, 0xE3, 0xAE, ++ 0x01, 0x33, 0x80, 0xF8, 0x5D, 0x32, 0xA0, 0xF8, 0x5E, 0x22, 0xDC, 0xE6, ++ 0x40, 0x20, 0x13, 0xF0, 0xF7, 0xFB, 0xF3, 0xE6, 0xB8, 0xF1, 0x00, 0x0F, ++ 0x7F, 0xF4, 0x61, 0xAF, 0x44, 0x49, 0x45, 0x48, 0x40, 0xF2, 0x3D, 0x22, ++ 0x15, 0xF0, 0xE2, 0xF8, 0x59, 0xE7, 0x00, 0xF0, 0x0C, 0x00, 0x08, 0x28, ++ 0x7F, 0xF4, 0x10, 0xAE, 0xD7, 0xF8, 0x1A, 0x10, 0x01, 0xF0, 0x3F, 0x01, ++ 0x07, 0x29, 0x7F, 0xF4, 0x09, 0xAE, 0x23, 0xF0, 0x20, 0x03, 0xD3, 0x63, ++ 0x04, 0xE6, 0x3B, 0x4B, 0xD3, 0xE9, 0x01, 0x02, 0x13, 0x69, 0x98, 0x47, ++ 0x06, 0x46, 0x00, 0x28, 0x3F, 0xF4, 0x2C, 0xAE, 0xF7, 0xF7, 0x96, 0xFE, ++ 0x07, 0x46, 0x00, 0x28, 0x00, 0xF0, 0x02, 0x81, 0x00, 0x22, 0x34, 0x4B, ++ 0x02, 0x60, 0x1B, 0x68, 0x42, 0x60, 0x1E, 0x44, 0x82, 0x60, 0x06, 0x60, ++ 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x02, 0xD4, 0x72, 0xB6, 0x2F, 0x4B, ++ 0x1D, 0x60, 0x2F, 0x49, 0xD9, 0xF8, 0x00, 0x20, 0x0B, 0x68, 0x01, 0x32, ++ 0x43, 0xF0, 0x01, 0x03, 0xC9, 0xF8, 0x00, 0x20, 0x0B, 0x60, 0x2A, 0x4B, ++ 0x1B, 0x68, 0x9E, 0x07, 0xFB, 0xD4, 0x29, 0x4B, 0x1B, 0x68, 0x00, 0x2B, ++ 0x40, 0xF0, 0xE4, 0x80, 0x27, 0x4B, 0x1B, 0x68, 0x00, 0x2B, 0x40, 0xF0, ++ 0xF0, 0x80, 0x25, 0x4B, 0x25, 0x4D, 0x1F, 0x60, 0x22, 0x48, 0xA9, 0x89, ++ 0x03, 0x68, 0x6F, 0x60, 0x01, 0x31, 0xA9, 0x81, 0x01, 0x33, 0x1E, 0x49, ++ 0x03, 0x60, 0x0B, 0x68, 0x23, 0xF0, 0x01, 0x03, 0x0B, 0x60, 0x00, 0x2A, ++ 0x3F, 0xF4, 0xEC, 0xAD, 0x18, 0x4B, 0x01, 0x3A, 0x1B, 0x68, 0xC9, 0xF8, ++ 0x00, 0x20, 0x00, 0x2A, 0x7F, 0xF4, 0xE4, 0xAD, 0x00, 0x2B, 0x3F, 0xF4, ++ 0xE1, 0xAD, 0x62, 0xB6, 0xDE, 0xE5, 0x23, 0x7F, 0x09, 0x4D, 0x4F, 0xF4, ++ 0xA4, 0x62, 0x02, 0xFB, 0x03, 0x55, 0x05, 0xF1, 0x98, 0x02, 0x95, 0xF8, ++ 0x62, 0x10, 0x20, 0x46, 0xFF, 0xF7, 0x70, 0xFB, 0xBE, 0xE5, 0x62, 0xB6, ++ 0x0A, 0xE6, 0x00, 0xBF, 0x78, 0x36, 0x17, 0x00, 0x2C, 0x19, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x61, 0xF1, 0x12, 0x00, 0x70, 0x79, 0x15, 0x00, 0x90, 0x90, 0x15, 0x00, ++ 0x28, 0x60, 0x17, 0x00, 0x34, 0x1A, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, ++ 0x60, 0x00, 0x24, 0x40, 0x64, 0x00, 0x24, 0x40, 0x68, 0x00, 0x24, 0x40, ++ 0x10, 0x60, 0x17, 0x00, 0x00, 0xF0, 0x0C, 0x00, 0x08, 0x28, 0x7F, 0xF4, ++ 0xFD, 0xAD, 0xD5, 0xF8, 0x1A, 0x10, 0x01, 0xF0, 0x3F, 0x01, 0x07, 0x29, ++ 0x7F, 0xF4, 0xF6, 0xAD, 0x23, 0xF0, 0x20, 0x03, 0xD3, 0x63, 0xF1, 0xE5, ++ 0x4E, 0x4D, 0x02, 0x9B, 0x4F, 0xF4, 0xA4, 0x60, 0x00, 0xFB, 0x03, 0x50, ++ 0xFE, 0xF7, 0xB8, 0xFE, 0x00, 0x28, 0x3F, 0xF4, 0x19, 0xAF, 0x4A, 0x4B, ++ 0x93, 0xF8, 0xFF, 0x31, 0x00, 0x2B, 0x7F, 0xF4, 0x13, 0xAF, 0x01, 0x9A, ++ 0x02, 0x99, 0xA4, 0x23, 0x02, 0xF1, 0x9E, 0x06, 0x13, 0xFB, 0x01, 0x66, ++ 0x03, 0xFB, 0x01, 0x23, 0x03, 0xF1, 0x9E, 0x04, 0x05, 0xEB, 0xC6, 0x06, ++ 0xD7, 0xB2, 0xA1, 0x46, 0x0C, 0xE0, 0x13, 0xF0, 0x09, 0xFC, 0xDA, 0xF8, ++ 0x24, 0x34, 0x20, 0x46, 0x39, 0x46, 0x98, 0x47, 0x3B, 0x4B, 0x93, 0xF8, ++ 0xFF, 0x31, 0x00, 0x2B, 0x7F, 0xF4, 0xF6, 0xAE, 0x55, 0xF8, 0x39, 0x40, ++ 0x30, 0x46, 0x00, 0x2C, 0xED, 0xD1, 0xEF, 0xE6, 0x36, 0x4B, 0x1B, 0x68, ++ 0x1C, 0x42, 0x7F, 0xF4, 0xC3, 0xAC, 0x35, 0x49, 0x35, 0x48, 0x4F, 0xF4, ++ 0xF2, 0x72, 0x14, 0xF0, 0xFD, 0xFF, 0xBB, 0xE4, 0x4F, 0xF4, 0xA4, 0x69, ++ 0x09, 0xFB, 0x0A, 0x59, 0x99, 0xF8, 0x64, 0x10, 0x00, 0x29, 0x3F, 0xF4, ++ 0xCC, 0xAD, 0x2F, 0x48, 0x03, 0x99, 0x4F, 0xF4, 0x1E, 0x7C, 0x0C, 0xFB, ++ 0x01, 0x01, 0x91, 0xF8, 0x24, 0x10, 0x01, 0x29, 0x0F, 0xD0, 0x99, 0x07, ++ 0x2F, 0xD4, 0x00, 0x2A, 0x3F, 0xF4, 0xBD, 0xAD, 0x97, 0xF8, 0x70, 0x30, ++ 0x01, 0x2B, 0x7F, 0xF4, 0xB8, 0xAD, 0x97, 0xF8, 0x85, 0x30, 0x00, 0x2B, ++ 0x7F, 0xF4, 0xB3, 0xAD, 0xE3, 0x8B, 0xE1, 0x6C, 0x01, 0x98, 0x22, 0x4A, ++ 0xC3, 0xF3, 0x0E, 0x03, 0x00, 0x26, 0x43, 0xF0, 0x01, 0x03, 0x0E, 0x65, ++ 0x0E, 0x61, 0x9E, 0x30, 0xE3, 0x83, 0xA4, 0x23, 0x13, 0xFB, 0x0A, 0x00, ++ 0x05, 0xEB, 0xC0, 0x00, 0xE6, 0x62, 0x21, 0x46, 0x13, 0xF0, 0xFE, 0xFB, ++ 0x40, 0x20, 0x13, 0xF0, 0xCB, 0xFA, 0x2F, 0xE5, 0x30, 0x46, 0xF7, 0xF7, ++ 0x6B, 0xFC, 0x1F, 0xE5, 0x15, 0x4D, 0x6B, 0x68, 0x9B, 0xB1, 0x5F, 0x60, ++ 0x1E, 0xE7, 0xB4, 0xF8, 0x40, 0x00, 0x20, 0xF0, 0x75, 0xFC, 0x00, 0x28, ++ 0xD6, 0xD0, 0x99, 0xF8, 0xC0, 0x24, 0x00, 0x2A, 0x3F, 0xF4, 0x85, 0xAD, ++ 0xC6, 0xE7, 0x0E, 0x48, 0x14, 0xF0, 0x2E, 0xFD, 0xD9, 0xF8, 0x00, 0x20, ++ 0x09, 0xE7, 0x0C, 0x48, 0x14, 0xF0, 0x28, 0xFD, 0xD9, 0xF8, 0x00, 0x20, ++ 0x06, 0xE7, 0x00, 0xBF, 0x18, 0x88, 0x17, 0x00, 0x20, 0x62, 0x17, 0x00, ++ 0x80, 0xB6, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x78, 0x90, 0x15, 0x00, ++ 0x68, 0x65, 0x17, 0x00, 0x61, 0xF1, 0x12, 0x00, 0x10, 0x60, 0x17, 0x00, ++ 0xA8, 0x90, 0x15, 0x00, 0xB0, 0x90, 0x15, 0x00, 0x2D, 0xE9, 0xF0, 0x47, ++ 0x27, 0x4F, 0xDF, 0xF8, 0xA0, 0xA0, 0x91, 0x46, 0x06, 0x46, 0x0D, 0x46, ++ 0x42, 0xF0, 0x70, 0x58, 0x28, 0x46, 0x13, 0xF0, 0x6D, 0xFB, 0x04, 0x46, ++ 0x80, 0xB1, 0x42, 0x6C, 0xC1, 0x6C, 0x00, 0x2A, 0x38, 0xD0, 0xC1, 0xF8, ++ 0x10, 0x80, 0xA2, 0x88, 0x62, 0xB9, 0x20, 0x46, 0x00, 0xF0, 0xA2, 0xF9, ++ 0x28, 0x46, 0x13, 0xF0, 0x5D, 0xFB, 0x04, 0x46, 0x00, 0x28, 0xEE, 0xD1, ++ 0xBD, 0xE8, 0xF0, 0x47, 0x00, 0xF0, 0xBC, 0xB9, 0x0A, 0x69, 0x42, 0xF4, ++ 0x00, 0x02, 0x41, 0xF8, 0x10, 0x2F, 0x20, 0x46, 0xFF, 0xF7, 0x7E, 0xFA, ++ 0xD7, 0xF8, 0x18, 0x34, 0x01, 0x21, 0x20, 0x46, 0x98, 0x47, 0x63, 0x7F, ++ 0x09, 0x2B, 0x0D, 0xD8, 0xE2, 0x7E, 0x08, 0x2A, 0x0A, 0xD8, 0x03, 0xEB, ++ 0xC3, 0x03, 0x13, 0x44, 0x03, 0xF6, 0x0E, 0x03, 0xA1, 0x88, 0x5A, 0xF8, ++ 0x23, 0x20, 0x52, 0x1A, 0x4A, 0xF8, 0x23, 0x20, 0x31, 0x46, 0x20, 0x46, ++ 0xD7, 0xF8, 0x78, 0x33, 0x98, 0x47, 0x21, 0x46, 0x30, 0x46, 0x15, 0xF0, ++ 0x03, 0xF8, 0xBD, 0xE7, 0x0A, 0x69, 0x00, 0x2A, 0xA8, 0xBF, 0xC1, 0xF8, ++ 0x10, 0x90, 0xC2, 0xE7, 0x88, 0x1A, 0x17, 0x00, 0x7C, 0x36, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x47, 0xDF, 0xF8, 0x6C, 0x80, 0x92, 0x46, 0x06, 0x46, ++ 0x0F, 0x46, 0x42, 0xF0, 0x70, 0x59, 0x38, 0x46, 0x13, 0xF0, 0x18, 0xFB, ++ 0x04, 0x46, 0xF0, 0xB1, 0x42, 0x6C, 0xC3, 0x6C, 0x12, 0xB3, 0xC3, 0xF8, ++ 0x10, 0x90, 0xA2, 0x88, 0x00, 0x21, 0x20, 0x46, 0xCA, 0xB1, 0x1D, 0x69, ++ 0x45, 0xF4, 0x00, 0x05, 0x1D, 0x61, 0xD8, 0xF8, 0x18, 0x34, 0x98, 0x47, ++ 0xD8, 0xF8, 0x78, 0x33, 0x20, 0x46, 0x31, 0x46, 0x98, 0x47, 0x21, 0x46, ++ 0x30, 0x46, 0x14, 0xF0, 0xD1, 0xFF, 0x38, 0x46, 0x13, 0xF0, 0xFA, 0xFA, ++ 0x04, 0x46, 0x00, 0x28, 0xE0, 0xD1, 0xBD, 0xE8, 0xF0, 0x47, 0x00, 0xF0, ++ 0x59, 0xB9, 0x00, 0xF0, 0x33, 0xF9, 0xD4, 0xE7, 0x1A, 0x69, 0x00, 0x2A, ++ 0xA8, 0xBF, 0xC3, 0xF8, 0x10, 0xA0, 0xD8, 0xE7, 0x88, 0x1A, 0x17, 0x00, ++ 0xF8, 0xB5, 0x14, 0x46, 0x05, 0x46, 0x0F, 0x46, 0x60, 0x22, 0x00, 0x21, ++ 0x1E, 0x46, 0xF0, 0xF7, 0x07, 0xFA, 0x4F, 0xF0, 0x01, 0x0C, 0x85, 0xF8, ++ 0x5C, 0xC0, 0x00, 0x23, 0x07, 0x49, 0x08, 0x4A, 0xAF, 0x64, 0x07, 0xF1, ++ 0x68, 0x00, 0xEE, 0x62, 0xEC, 0x64, 0xC4, 0xE9, 0x0F, 0x33, 0x60, 0x62, ++ 0x61, 0x61, 0x23, 0x63, 0x63, 0x64, 0x32, 0x60, 0xF8, 0xBD, 0x00, 0xBF, ++ 0xBE, 0xBA, 0xFE, 0xCA, 0x1E, 0xAB, 0xDC, 0xBA, 0x2D, 0xE9, 0xF8, 0x4F, ++ 0x07, 0x46, 0x3C, 0x48, 0x3C, 0x4C, 0xDF, 0xF8, 0x08, 0xA1, 0x3C, 0x4E, ++ 0x3C, 0x4D, 0xDF, 0xF8, 0x04, 0xB1, 0x81, 0x46, 0x13, 0xF0, 0x70, 0xFA, ++ 0x09, 0xF1, 0x08, 0x00, 0x13, 0xF0, 0x6C, 0xFA, 0x04, 0xF5, 0xC0, 0x78, ++ 0x00, 0x21, 0x20, 0x46, 0x60, 0x22, 0x17, 0xB1, 0x94, 0xF8, 0x5D, 0x30, ++ 0xC3, 0xB9, 0xF0, 0xF7, 0xD1, 0xF9, 0x00, 0x22, 0x32, 0x4B, 0xC4, 0xF8, ++ 0x48, 0xA0, 0x0A, 0xF1, 0x68, 0x0C, 0xC5, 0xE9, 0x0F, 0x22, 0x21, 0x46, ++ 0x48, 0x46, 0xE6, 0x62, 0xE5, 0x64, 0xC5, 0xF8, 0x14, 0xB0, 0x33, 0x60, ++ 0x84, 0xF8, 0x5C, 0x20, 0x2A, 0x63, 0x6A, 0x64, 0xC5, 0xF8, 0x24, 0xC0, ++ 0x13, 0xF0, 0x4E, 0xFA, 0x60, 0x34, 0xA0, 0x45, 0x0A, 0xF5, 0xF4, 0x7A, ++ 0x06, 0xF1, 0x40, 0x06, 0x05, 0xF1, 0x58, 0x05, 0xD6, 0xD1, 0x24, 0x4E, ++ 0xDF, 0xF8, 0x88, 0x90, 0xC6, 0xF8, 0x00, 0x90, 0x00, 0x24, 0xC6, 0xE9, ++ 0x0D, 0x44, 0xF4, 0x63, 0xF1, 0xF7, 0x8E, 0xFA, 0x80, 0x03, 0x70, 0x60, ++ 0xF1, 0xF7, 0x8A, 0xFA, 0x01, 0x27, 0x43, 0x1C, 0x07, 0xFA, 0x03, 0xF3, ++ 0x1B, 0x4D, 0xDF, 0xF8, 0x78, 0x80, 0xF4, 0x60, 0x01, 0x3B, 0xB3, 0x60, ++ 0x4F, 0xF4, 0x80, 0x63, 0xC6, 0xE9, 0x04, 0x83, 0xC6, 0xE9, 0x06, 0x44, ++ 0x34, 0x62, 0xC5, 0xF8, 0x00, 0x90, 0xC6, 0xE9, 0x0A, 0x44, 0xC5, 0xE9, ++ 0x0D, 0x44, 0x34, 0x63, 0xEC, 0x63, 0xF1, 0xF7, 0x6F, 0xFA, 0x80, 0x03, ++ 0x68, 0x60, 0xF1, 0xF7, 0x6B, 0xFA, 0x38, 0x44, 0x87, 0x40, 0x01, 0x3F, ++ 0x04, 0x23, 0xC5, 0xE9, 0x02, 0x74, 0xC5, 0xE9, 0x06, 0x44, 0xC5, 0xE9, ++ 0x0A, 0x44, 0xC5, 0xF8, 0x10, 0x80, 0x2C, 0x62, 0x2C, 0x63, 0x6B, 0x61, ++ 0xBD, 0xE8, 0xF8, 0x8F, 0x54, 0x64, 0x17, 0x00, 0x90, 0x28, 0x17, 0x00, ++ 0x84, 0x3B, 0x18, 0x00, 0x04, 0x3D, 0x18, 0x00, 0x1E, 0xAB, 0xDC, 0xBA, ++ 0xC4, 0x3C, 0x18, 0x00, 0x84, 0x3C, 0x18, 0x00, 0x4C, 0x50, 0x18, 0x00, ++ 0xBE, 0xBA, 0xFE, 0xCA, 0x04, 0x07, 0xFF, 0xFF, 0xF8, 0xB5, 0xD0, 0xE9, ++ 0x12, 0x64, 0x63, 0x6A, 0x05, 0x46, 0x50, 0x1E, 0x03, 0x44, 0x04, 0x32, ++ 0xC4, 0xE9, 0x0A, 0x32, 0xC1, 0xB1, 0x01, 0x29, 0x1A, 0xD0, 0x06, 0xF1, ++ 0x28, 0x01, 0x0F, 0x46, 0x34, 0x22, 0x38, 0x46, 0x27, 0xF0, 0xD8, 0xF8, ++ 0x0B, 0x4A, 0x13, 0x68, 0x12, 0x68, 0x1B, 0x02, 0xD2, 0xB2, 0x9B, 0xB2, ++ 0x13, 0x43, 0x00, 0x22, 0xF3, 0x64, 0xC4, 0xE9, 0x0D, 0x27, 0xE2, 0x64, ++ 0x22, 0x62, 0xC5, 0xE9, 0x15, 0x22, 0xF8, 0xBD, 0x04, 0x49, 0x06, 0xF1, ++ 0x28, 0x07, 0xE7, 0xE7, 0x03, 0x49, 0x06, 0xF1, 0x28, 0x07, 0xE3, 0xE7, ++ 0xA0, 0x00, 0x32, 0x40, 0xC4, 0x3C, 0x18, 0x00, 0x84, 0x3C, 0x18, 0x00, ++ 0x70, 0xB5, 0x05, 0x46, 0x05, 0x48, 0x0E, 0x46, 0x13, 0xF0, 0xFE, 0xF9, ++ 0x04, 0x46, 0x18, 0xB1, 0x32, 0x46, 0x29, 0x46, 0xFF, 0xF7, 0xC2, 0xFF, ++ 0x20, 0x46, 0x70, 0xBD, 0x54, 0x64, 0x17, 0x00, 0x16, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x2D, 0xE9, 0xF0, 0x41, 0xC4, 0x6C, 0x00, 0x2B, ++ 0x62, 0x6A, 0x05, 0x46, 0x0E, 0x46, 0x16, 0xDB, 0xE3, 0x6C, 0x11, 0x4F, ++ 0x23, 0xF4, 0xF0, 0x03, 0xE3, 0x64, 0x00, 0x23, 0xC4, 0xE9, 0x06, 0x33, ++ 0x12, 0x79, 0x23, 0x65, 0x12, 0xF0, 0x01, 0x0F, 0x08, 0xBF, 0x4F, 0xF4, ++ 0x00, 0x73, 0xA3, 0x64, 0xD7, 0xF8, 0x98, 0x33, 0x31, 0x46, 0x28, 0x46, ++ 0xBD, 0xE8, 0xF0, 0x41, 0x18, 0x47, 0xD3, 0x07, 0xE6, 0xD5, 0x4F, 0xF4, ++ 0xB1, 0x72, 0x05, 0x49, 0x05, 0x48, 0x14, 0xF0, 0xD9, 0xFD, 0x62, 0x6A, ++ 0xDE, 0xE7, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xDC, 0x90, 0x15, 0x00, 0x08, 0xB5, 0x01, 0x46, ++ 0x04, 0x48, 0x13, 0xF0, 0x75, 0xF9, 0xBD, 0xE8, 0x08, 0x40, 0x4F, 0xF4, ++ 0x80, 0x20, 0x13, 0xF0, 0xCD, 0xB8, 0x00, 0xBF, 0x5C, 0x64, 0x17, 0x00, ++ 0x70, 0xB5, 0x90, 0xF8, 0x5C, 0x30, 0x04, 0x46, 0x0D, 0x46, 0x43, 0xB1, ++ 0x35, 0xB1, 0x63, 0x6D, 0x23, 0xB1, 0xA0, 0x6D, 0x00, 0x21, 0xBD, 0xE8, ++ 0x70, 0x40, 0x18, 0x47, 0x70, 0xBD, 0x01, 0x46, 0x01, 0x48, 0x13, 0xF0, ++ 0x59, 0xF9, 0xF1, 0xE7, 0x54, 0x64, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x41, ++ 0x4F, 0xF4, 0x80, 0x20, 0x13, 0xF0, 0xD2, 0xF8, 0xDF, 0xF8, 0x88, 0x80, ++ 0x1D, 0x4F, 0x1E, 0x4E, 0x1E, 0x4D, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, ++ 0x02, 0xD4, 0x72, 0xB6, 0x01, 0x23, 0x3B, 0x60, 0xD8, 0xF8, 0x00, 0x30, ++ 0x30, 0x46, 0x01, 0x33, 0xC8, 0xF8, 0x00, 0x30, 0x13, 0xF0, 0x80, 0xF9, ++ 0xD8, 0xF8, 0x00, 0x30, 0x04, 0x46, 0x33, 0xB1, 0x01, 0x3B, 0x3A, 0x68, ++ 0xC8, 0xF8, 0x00, 0x30, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0xD4, 0xB1, ++ 0xD5, 0xF8, 0xF8, 0x31, 0x62, 0x6D, 0x01, 0x3B, 0xC5, 0xF8, 0xF8, 0x31, ++ 0x32, 0xB1, 0xE3, 0x6C, 0xA0, 0x6D, 0x19, 0x6D, 0x90, 0x47, 0x94, 0xF8, ++ 0x5E, 0x30, 0x43, 0xB9, 0x94, 0xF8, 0x5C, 0x30, 0x00, 0x2B, 0xD2, 0xD1, ++ 0x08, 0x48, 0x21, 0x46, 0x13, 0xF0, 0x1A, 0xF9, 0xCD, 0xE7, 0x00, 0x23, ++ 0x84, 0xF8, 0x5E, 0x30, 0xC9, 0xE7, 0xBD, 0xE8, 0xF0, 0x81, 0x00, 0xBF, ++ 0x38, 0x61, 0x17, 0x00, 0x5C, 0x64, 0x17, 0x00, 0x20, 0x62, 0x17, 0x00, ++ 0x54, 0x64, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x47, ++ 0xDF, 0xF8, 0x78, 0x91, 0x58, 0x4D, 0x80, 0x46, 0x4F, 0xF4, 0x1E, 0x70, ++ 0x00, 0xFB, 0x08, 0x90, 0x4F, 0xF4, 0xA4, 0x63, 0x90, 0xF8, 0x22, 0xA0, ++ 0x03, 0xFB, 0x0A, 0x53, 0x0F, 0x46, 0x1B, 0x6C, 0x16, 0x46, 0x00, 0x2B, ++ 0x00, 0xF0, 0x98, 0x80, 0x50, 0x49, 0x1A, 0x79, 0x0B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0x5A, 0xDB, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, ++ 0x0A, 0x53, 0x18, 0x21, 0x93, 0xF8, 0xC0, 0x34, 0x13, 0x43, 0x14, 0xBF, ++ 0x01, 0x20, 0x00, 0x20, 0xFF, 0xF7, 0x1E, 0xFF, 0x04, 0x46, 0x00, 0x28, ++ 0x59, 0xD0, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x0A, 0x55, 0x28, 0x46, ++ 0x21, 0x46, 0x12, 0xF0, 0x11, 0xF8, 0x95, 0xF8, 0x62, 0x20, 0xA3, 0x6C, ++ 0x02, 0x2A, 0x4F, 0xD0, 0x4F, 0xF4, 0x1E, 0x72, 0x02, 0xFB, 0x08, 0x92, ++ 0xE8, 0x6D, 0x52, 0xF8, 0x26, 0x1F, 0xB5, 0xF8, 0x60, 0xC0, 0xB2, 0xF8, ++ 0x04, 0xE0, 0x15, 0x68, 0xD9, 0x66, 0x91, 0x88, 0xA3, 0xF8, 0x7C, 0x10, ++ 0x00, 0x22, 0x9D, 0x67, 0x01, 0x21, 0x48, 0x25, 0xA3, 0xF8, 0x70, 0xE0, ++ 0xC3, 0xF8, 0x72, 0x00, 0xA3, 0xF8, 0x76, 0xC0, 0x83, 0xF8, 0x6A, 0x20, ++ 0x83, 0xF8, 0x6B, 0x20, 0x83, 0xF8, 0x68, 0x50, 0x83, 0xF8, 0x69, 0x10, ++ 0x2E, 0x49, 0xB1, 0xF8, 0xFC, 0x51, 0x4F, 0xF4, 0x1E, 0x72, 0x02, 0xFB, ++ 0x08, 0x99, 0x01, 0x35, 0xAD, 0xB2, 0xA1, 0xF8, 0xFC, 0x51, 0x99, 0xF8, ++ 0x22, 0x20, 0x2D, 0x01, 0xA3, 0xF8, 0x7E, 0x50, 0x20, 0x46, 0xC4, 0xE9, ++ 0x15, 0x76, 0x22, 0x77, 0x84, 0xF8, 0x1D, 0x80, 0x05, 0x21, 0xFF, 0xF7, ++ 0xE3, 0xFE, 0x00, 0x20, 0xBD, 0xE8, 0xF0, 0x87, 0x02, 0x2A, 0xA2, 0xD1, ++ 0x20, 0x49, 0x21, 0x48, 0x4F, 0xF4, 0x09, 0x72, 0x14, 0xF0, 0xDC, 0xFC, ++ 0x01, 0x20, 0x18, 0x21, 0xFF, 0xF7, 0xC4, 0xFE, 0x04, 0x46, 0x00, 0x28, ++ 0xA5, 0xD1, 0x01, 0x20, 0xBD, 0xE8, 0xF0, 0x87, 0x4F, 0xF4, 0x1E, 0x71, ++ 0x01, 0xFB, 0x08, 0x91, 0xE8, 0x6D, 0x51, 0xF8, 0x26, 0xEF, 0x83, 0xF8, ++ 0x69, 0x20, 0x89, 0x88, 0xA3, 0xF8, 0x70, 0x10, 0x00, 0x22, 0xB5, 0xF8, ++ 0x60, 0x10, 0xC3, 0xF8, 0x72, 0x00, 0x4F, 0xF0, 0x48, 0x0C, 0xE8, 0x6D, ++ 0x83, 0xF8, 0x6A, 0x20, 0x83, 0xF8, 0x6B, 0x20, 0xB5, 0xF8, 0x60, 0x20, ++ 0xC3, 0xF8, 0x6C, 0xE0, 0x83, 0xF8, 0x68, 0xC0, 0xA3, 0xF8, 0x76, 0x10, ++ 0x98, 0x67, 0xA3, 0xF8, 0x7C, 0x20, 0xAD, 0xE7, 0x04, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xCB, 0xDA, 0xC4, 0xE7, 0x00, 0xBF, ++ 0x18, 0x88, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, 0x20, 0x62, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xFC, 0x90, 0x15, 0x00, 0x68, 0x65, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF8, 0x4F, 0xDF, 0xF8, 0x38, 0xB1, 0x49, 0x4C, 0x4F, 0xF4, ++ 0x1E, 0x75, 0x05, 0xFB, 0x00, 0xB5, 0x06, 0x46, 0x95, 0xF8, 0x22, 0x70, ++ 0x4F, 0xF4, 0xA4, 0x60, 0x00, 0xFB, 0x07, 0x40, 0x98, 0x46, 0x00, 0x6C, ++ 0x43, 0x4B, 0x8A, 0x46, 0x91, 0x46, 0x00, 0x28, 0x7A, 0xD0, 0x1B, 0x68, ++ 0x02, 0x79, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x62, 0xDB, 0x4F, 0xF4, ++ 0xA4, 0x63, 0x03, 0xFB, 0x07, 0x43, 0x1A, 0x21, 0x93, 0xF8, 0xC0, 0x34, ++ 0x13, 0x43, 0x14, 0xBF, 0x01, 0x20, 0x00, 0x20, 0xFF, 0xF7, 0x5C, 0xFE, ++ 0x05, 0x46, 0x00, 0x28, 0x61, 0xD0, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, ++ 0x07, 0x47, 0x38, 0x46, 0x29, 0x46, 0x11, 0xF0, 0x4F, 0xFF, 0x4F, 0xF4, ++ 0x1E, 0x73, 0x03, 0xFB, 0x06, 0xB3, 0xAC, 0x6C, 0x53, 0xF8, 0x26, 0x1F, ++ 0x97, 0xF8, 0x62, 0xC0, 0xB3, 0xF8, 0x04, 0xE0, 0xF8, 0x6D, 0xB7, 0xF8, ++ 0x60, 0x20, 0xA4, 0xF8, 0x76, 0x20, 0x00, 0x23, 0xA4, 0xF8, 0x70, 0xE0, ++ 0xE1, 0x66, 0xC4, 0xF8, 0x72, 0x00, 0x84, 0xF8, 0x6A, 0x30, 0x84, 0xF8, ++ 0x6B, 0x30, 0xBC, 0xF1, 0x00, 0x0F, 0x22, 0xD0, 0xF8, 0x6D, 0xA0, 0x67, ++ 0x6F, 0xF0, 0x37, 0x01, 0x02, 0x23, 0xA4, 0xF8, 0x7C, 0x20, 0x84, 0xF8, ++ 0x68, 0x10, 0x84, 0xF8, 0x69, 0x30, 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, ++ 0x06, 0xBB, 0x00, 0x27, 0x9B, 0xF8, 0x22, 0x30, 0xA4, 0xF8, 0x80, 0xA0, ++ 0x84, 0xF8, 0x7E, 0x70, 0x84, 0xF8, 0x7F, 0x70, 0x28, 0x46, 0xC5, 0xE9, ++ 0x15, 0x98, 0x2B, 0x77, 0x6E, 0x77, 0x05, 0x21, 0xFF, 0xF7, 0x24, 0xFE, ++ 0x38, 0x46, 0xBD, 0xE8, 0xF8, 0x8F, 0x6F, 0xF0, 0x37, 0x02, 0x01, 0x23, ++ 0xA1, 0x67, 0xA4, 0xF8, 0x7C, 0xE0, 0x84, 0xF8, 0x68, 0x20, 0x84, 0xF8, ++ 0x69, 0x30, 0xDC, 0xE7, 0x02, 0x2A, 0x9A, 0xD1, 0x0C, 0x49, 0x0D, 0x48, ++ 0x4F, 0xF4, 0x09, 0x72, 0x14, 0xF0, 0x12, 0xFC, 0x01, 0x20, 0x1A, 0x21, ++ 0xFF, 0xF7, 0xFA, 0xFD, 0x05, 0x46, 0x00, 0x28, 0x9D, 0xD1, 0x01, 0x20, ++ 0xBD, 0xE8, 0xF8, 0x8F, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0xF0, 0xDA, 0xE9, 0xE7, 0x18, 0x88, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xFC, 0x90, 0x15, 0x00, 0x68, 0x65, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0xDF, 0xF8, 0x9C, 0xA1, 0xDF, 0xF8, 0x9C, 0x81, ++ 0x4F, 0xF4, 0x1E, 0x76, 0x06, 0xFB, 0x00, 0xA6, 0x05, 0x46, 0x96, 0xF8, ++ 0x22, 0x90, 0x4F, 0xF4, 0xA4, 0x60, 0x00, 0xFB, 0x09, 0x80, 0x83, 0xB0, ++ 0x00, 0x6C, 0x00, 0x93, 0x0E, 0x1E, 0x17, 0x46, 0x9D, 0xF8, 0x30, 0x40, ++ 0x9D, 0xF8, 0x34, 0xB0, 0x55, 0x4A, 0x0C, 0xBF, 0x1E, 0x23, 0x1D, 0x23, ++ 0x00, 0x28, 0x00, 0xF0, 0x9D, 0x80, 0x12, 0x68, 0x01, 0x79, 0xB2, 0xF9, ++ 0x00, 0x20, 0x00, 0x2A, 0xC0, 0xF2, 0x85, 0x80, 0x4F, 0xF4, 0xA4, 0x62, ++ 0x02, 0xFB, 0x09, 0x82, 0x92, 0xF8, 0xC0, 0x24, 0x0A, 0x43, 0x14, 0xBF, ++ 0x01, 0x20, 0x00, 0x20, 0x19, 0x46, 0xFF, 0xF7, 0xAF, 0xFD, 0x03, 0x46, ++ 0x00, 0x28, 0x00, 0xF0, 0x81, 0x80, 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, ++ 0x09, 0x88, 0xD0, 0xF8, 0x48, 0x90, 0x01, 0x93, 0x40, 0x46, 0x19, 0x46, ++ 0x11, 0xF0, 0x9E, 0xFE, 0xD9, 0xF8, 0x38, 0x00, 0x01, 0x9B, 0x40, 0x4A, ++ 0x99, 0x6C, 0xB8, 0xF8, 0x60, 0xE0, 0x00, 0x0C, 0x4F, 0xF0, 0x00, 0x0C, ++ 0x46, 0xEA, 0x07, 0x17, 0x00, 0x04, 0xC9, 0xF8, 0x38, 0x00, 0xD8, 0xF8, ++ 0x5C, 0x00, 0x8F, 0x67, 0x81, 0xF8, 0x7C, 0xC0, 0x81, 0xF8, 0x7D, 0xC0, ++ 0x81, 0xF8, 0x7E, 0xC0, 0x81, 0xF8, 0x7F, 0xC0, 0x92, 0xF8, 0x43, 0x70, ++ 0xDF, 0xF8, 0xE8, 0x80, 0xC1, 0xF8, 0x72, 0x00, 0x24, 0x20, 0xB8, 0xF8, ++ 0x04, 0x20, 0xA1, 0xF8, 0x76, 0xE0, 0x81, 0xF8, 0x68, 0x00, 0xD8, 0xF8, ++ 0x00, 0xE0, 0xA1, 0xF8, 0x70, 0x20, 0xB8, 0x06, 0xC1, 0xF8, 0x6C, 0xE0, ++ 0x81, 0xF8, 0x69, 0xC0, 0x81, 0xF8, 0x6A, 0xC0, 0x81, 0xF8, 0x6B, 0xC0, ++ 0xC7, 0xF3, 0x40, 0x12, 0x0B, 0xD5, 0x27, 0x48, 0x4F, 0xF4, 0x1E, 0x72, ++ 0x02, 0xFB, 0x05, 0x02, 0x52, 0x78, 0x12, 0xF0, 0x20, 0x0F, 0x0C, 0xBF, ++ 0x62, 0x46, 0x4F, 0xF4, 0x80, 0x12, 0x4F, 0xF4, 0x1E, 0x70, 0x00, 0xFB, ++ 0x05, 0xA5, 0x64, 0x05, 0x28, 0x8C, 0x00, 0x9D, 0x44, 0xEA, 0x45, 0x34, ++ 0x04, 0x43, 0x14, 0x43, 0xD8, 0x22, 0xC1, 0xF8, 0x80, 0x40, 0x81, 0xF8, ++ 0x84, 0x20, 0x6E, 0xB1, 0x0E, 0x9A, 0x5A, 0x65, 0x0F, 0x9A, 0x9A, 0x65, ++ 0x59, 0x46, 0x18, 0x46, 0xFF, 0xF7, 0x54, 0xFD, 0xB0, 0xFA, 0x80, 0xF0, ++ 0x40, 0x09, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x12, 0x4A, 0x12, 0xF8, ++ 0x0B, 0x20, 0x92, 0x01, 0x81, 0xF8, 0x85, 0x20, 0xEA, 0xE7, 0x02, 0x29, ++ 0x7F, 0xF4, 0x78, 0xAF, 0x0E, 0x48, 0x0F, 0x49, 0x01, 0x93, 0x4F, 0xF4, ++ 0x09, 0x72, 0x14, 0xF0, 0x41, 0xFB, 0x01, 0x9B, 0x01, 0x20, 0x77, 0xE7, ++ 0x01, 0x20, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x12, 0x68, 0xB2, 0xF9, ++ 0x00, 0x20, 0x00, 0x2A, 0xEC, 0xDB, 0x01, 0x20, 0x6C, 0xE7, 0x00, 0xBF, ++ 0x38, 0x36, 0x17, 0x00, 0xE4, 0xB8, 0x17, 0x00, 0x62, 0x66, 0x17, 0x00, ++ 0xA0, 0xB2, 0x15, 0x00, 0xFC, 0x90, 0x15, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x68, 0x65, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, 0xAC, 0xB2, 0x15, 0x00, ++ 0x2D, 0xE9, 0xF8, 0x43, 0x90, 0xF8, 0x62, 0x30, 0x02, 0x2B, 0x77, 0xD1, ++ 0x03, 0x6C, 0x04, 0x46, 0x89, 0x46, 0x00, 0x2B, 0x79, 0xD0, 0x40, 0x4A, ++ 0x1B, 0x79, 0x12, 0x68, 0xB2, 0xF9, 0x00, 0x20, 0x00, 0x2A, 0x51, 0xDB, ++ 0x94, 0xF8, 0xC0, 0x24, 0xDF, 0xF8, 0x08, 0x81, 0x13, 0x43, 0xB8, 0xF8, ++ 0x00, 0x10, 0x14, 0xBF, 0x01, 0x20, 0x00, 0x20, 0xFF, 0xF7, 0xEE, 0xFC, ++ 0x06, 0x46, 0x00, 0x28, 0x54, 0xD0, 0x01, 0x46, 0x20, 0x46, 0x11, 0xF0, ++ 0xE5, 0xFD, 0xB5, 0x6C, 0x00, 0x27, 0x50, 0x23, 0x49, 0x46, 0x85, 0xF8, ++ 0x68, 0x30, 0x85, 0xF8, 0x69, 0x70, 0x85, 0xF8, 0x6A, 0x70, 0x85, 0xF8, ++ 0x6B, 0x70, 0x05, 0xF1, 0x6C, 0x00, 0x06, 0x22, 0x26, 0xF0, 0x90, 0xFD, ++ 0x2B, 0x49, 0xE0, 0x6D, 0xB1, 0xF8, 0xFC, 0x31, 0xB4, 0xF8, 0x60, 0xC0, ++ 0xB8, 0xF8, 0x00, 0x20, 0xB4, 0xF8, 0x60, 0xE0, 0xC5, 0xF8, 0x72, 0x00, ++ 0x01, 0x33, 0x9B, 0xB2, 0xE0, 0x6D, 0xA5, 0xF8, 0x76, 0xC0, 0x4F, 0xEA, ++ 0x03, 0x1C, 0xA8, 0x67, 0xA5, 0xF8, 0x7C, 0xE0, 0x18, 0x3A, 0xA1, 0xF8, ++ 0xFC, 0x31, 0x05, 0xF1, 0x80, 0x00, 0xA5, 0xF8, 0x7E, 0xC0, 0x1E, 0x49, ++ 0x26, 0xF0, 0x70, 0xFD, 0xC6, 0xE9, 0x15, 0x77, 0x94, 0xF8, 0x63, 0x30, ++ 0x33, 0x77, 0xFF, 0x23, 0x73, 0x77, 0x30, 0x46, 0x05, 0x21, 0xFF, 0xF7, ++ 0xBB, 0xFC, 0x38, 0x46, 0xBD, 0xE8, 0xF8, 0x83, 0x02, 0x2B, 0xAB, 0xD1, ++ 0x15, 0x49, 0x16, 0x48, 0x4F, 0xF4, 0x09, 0x72, 0x14, 0xF0, 0xB4, 0xFA, ++ 0xDF, 0xF8, 0x58, 0x80, 0x01, 0x20, 0xB8, 0xF8, 0x00, 0x10, 0xFF, 0xF7, ++ 0x99, 0xFC, 0x06, 0x46, 0x00, 0x28, 0xAA, 0xD1, 0xB8, 0xF8, 0x00, 0x10, ++ 0x0E, 0x48, 0x14, 0xF0, 0x2B, 0xF8, 0x01, 0x20, 0xBD, 0xE8, 0xF8, 0x83, ++ 0x0C, 0x48, 0x19, 0x46, 0x14, 0xF0, 0x24, 0xF8, 0x01, 0x20, 0xBD, 0xE8, ++ 0xF8, 0x83, 0x03, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0xE0, 0xDA, 0xD9, 0xE7, 0x38, 0x36, 0x17, 0x00, 0x20, 0x62, 0x17, 0x00, ++ 0x2C, 0x2A, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0xFC, 0x90, 0x15, 0x00, ++ 0x28, 0x91, 0x15, 0x00, 0x14, 0x91, 0x15, 0x00, 0x14, 0x2C, 0x17, 0x00, ++ 0x02, 0x4B, 0x40, 0xEA, 0x41, 0x01, 0x33, 0xF8, 0x11, 0x00, 0x70, 0x47, ++ 0xA0, 0x92, 0x15, 0x00, 0x02, 0x4B, 0x40, 0xEA, 0x41, 0x01, 0x58, 0x5C, ++ 0x70, 0x47, 0x00, 0xBF, 0x40, 0x93, 0x15, 0x00, 0xF0, 0xB4, 0x1D, 0x4C, ++ 0x1D, 0x4D, 0x1E, 0x4F, 0x4F, 0xF4, 0x1E, 0x76, 0x06, 0xFB, 0x02, 0x42, ++ 0x16, 0x46, 0x92, 0xF8, 0x22, 0x40, 0x4F, 0xF4, 0xA4, 0x6C, 0x0C, 0xFB, ++ 0x04, 0x54, 0x56, 0xF8, 0x26, 0x5F, 0xB4, 0xF8, 0x60, 0xC0, 0x02, 0x46, ++ 0xE0, 0x6D, 0xB4, 0x88, 0xA2, 0xF8, 0x9C, 0x40, 0x00, 0x24, 0x54, 0x65, ++ 0xC2, 0xF8, 0x8C, 0x40, 0x3C, 0x68, 0x3E, 0x68, 0x9D, 0xF8, 0x10, 0x70, ++ 0xC2, 0xF8, 0x9E, 0x00, 0x24, 0x02, 0xF6, 0xB2, 0x1B, 0x03, 0xA4, 0xB2, ++ 0x40, 0xF6, 0x08, 0x00, 0x34, 0x43, 0x40, 0xEA, 0xC7, 0x10, 0x43, 0xF0, ++ 0x04, 0x03, 0x09, 0x01, 0xC2, 0xF8, 0x98, 0x50, 0xC2, 0xF8, 0xCC, 0x40, ++ 0xA2, 0xF8, 0xA2, 0xC0, 0xF0, 0xBC, 0xA2, 0xF8, 0xA4, 0x30, 0xA2, 0xF8, ++ 0xA6, 0x10, 0xC2, 0xF8, 0xBC, 0x00, 0x70, 0x47, 0x68, 0x65, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0xA0, 0x00, 0x32, 0x40, 0xC2, 0x6C, 0x53, 0x6A, ++ 0x13, 0xB3, 0x12, 0x49, 0x12, 0x4B, 0xC9, 0x6E, 0x10, 0xB5, 0x04, 0x46, ++ 0x18, 0x68, 0x63, 0x6A, 0x92, 0x6A, 0x03, 0xF4, 0x60, 0x13, 0xB3, 0xF5, ++ 0x60, 0x1F, 0x42, 0xF8, 0x03, 0x1C, 0x08, 0xD0, 0xB0, 0xF9, 0x00, 0x30, ++ 0x24, 0x68, 0x00, 0x2B, 0x04, 0xDB, 0xE2, 0x6C, 0x53, 0x6A, 0x00, 0x2B, ++ 0xED, 0xD1, 0x10, 0xBD, 0x00, 0x2C, 0xF8, 0xD1, 0x06, 0x49, 0x07, 0x48, ++ 0x40, 0xF2, 0xF9, 0x22, 0x14, 0xF0, 0x0E, 0xFA, 0xE3, 0x6C, 0xFF, 0xDE, ++ 0x70, 0x47, 0x00, 0xBF, 0x94, 0x64, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x3C, 0x91, 0x15, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0x89, 0xB0, 0x04, 0x46, 0x9D, 0xF8, 0x48, 0x00, 0x67, 0x6C, 0x07, 0x90, ++ 0x9B, 0x46, 0x05, 0x28, 0x4F, 0xF0, 0x00, 0x03, 0x06, 0x91, 0x03, 0x92, ++ 0x9A, 0x46, 0x00, 0xF0, 0x12, 0x81, 0xAA, 0x4A, 0x00, 0xEB, 0x40, 0x03, ++ 0xC3, 0xEB, 0xC3, 0x03, 0x02, 0xEB, 0x83, 0x03, 0x04, 0x93, 0xDF, 0xF8, ++ 0xC8, 0x92, 0xA6, 0x48, 0x12, 0xF0, 0xD4, 0xFD, 0xD9, 0xF8, 0x00, 0x30, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x05, 0x46, 0xC0, 0xF2, 0xF3, 0x80, ++ 0xBB, 0x88, 0xAB, 0x80, 0x7B, 0x7A, 0x6B, 0x72, 0xBB, 0x7A, 0xAB, 0x72, ++ 0x01, 0x23, 0xEB, 0x72, 0xD7, 0xE9, 0x10, 0xC0, 0xFE, 0x6A, 0x79, 0x69, ++ 0x3A, 0x6B, 0xEE, 0x62, 0x00, 0x23, 0x1E, 0x46, 0x69, 0x61, 0x6B, 0x62, ++ 0x19, 0x46, 0x98, 0x46, 0x02, 0x93, 0x05, 0xF1, 0x0C, 0x03, 0xC5, 0xE9, ++ 0x10, 0xC0, 0x2A, 0x63, 0x05, 0x93, 0x01, 0x96, 0x53, 0xE0, 0x9B, 0x45, ++ 0x40, 0xF2, 0xB4, 0x80, 0xAB, 0xEB, 0x03, 0x0A, 0x1F, 0xFA, 0x8A, 0xFA, ++ 0x0A, 0xF1, 0x03, 0x0A, 0x4F, 0xEA, 0x9A, 0x0A, 0x03, 0xEB, 0x8A, 0x03, ++ 0x9B, 0xB2, 0x03, 0x9E, 0x19, 0x44, 0xB1, 0x42, 0x5A, 0xD8, 0xB8, 0xF1, ++ 0x00, 0x0F, 0x57, 0xD1, 0xDE, 0xF8, 0x24, 0x00, 0x28, 0xB1, 0x87, 0x4E, ++ 0xDE, 0xF8, 0x28, 0x00, 0xF6, 0x6E, 0x40, 0xF8, 0x03, 0x6C, 0xDC, 0x45, ++ 0x65, 0x64, 0x0D, 0xD2, 0xDE, 0xF8, 0x4C, 0x20, 0x22, 0xF4, 0xFF, 0x22, ++ 0x22, 0xF4, 0xC0, 0x62, 0x42, 0xEA, 0x4A, 0x22, 0x42, 0xF4, 0x80, 0x70, ++ 0x62, 0x62, 0x63, 0x46, 0xCE, 0xF8, 0x4C, 0x00, 0x69, 0x62, 0x79, 0x6A, ++ 0x02, 0xF4, 0x60, 0x12, 0xCB, 0x1A, 0xB2, 0xF5, 0x60, 0x1F, 0x7B, 0x62, ++ 0x00, 0xF0, 0xAA, 0x80, 0x77, 0x4A, 0xD9, 0xF8, 0x00, 0x30, 0x11, 0x68, ++ 0x76, 0x4A, 0x91, 0xF8, 0x3E, 0x80, 0x12, 0x68, 0xB3, 0xF9, 0x00, 0x10, ++ 0x23, 0x68, 0x02, 0xF0, 0x3F, 0x02, 0x90, 0x45, 0x94, 0xBF, 0x4F, 0xF0, ++ 0x00, 0x08, 0x4F, 0xF0, 0x01, 0x08, 0x00, 0x29, 0x5D, 0xDB, 0x01, 0x9A, ++ 0x69, 0x6A, 0x02, 0x94, 0x01, 0x32, 0x01, 0x92, 0x1C, 0x46, 0xD4, 0xF8, ++ 0x4C, 0xE0, 0x62, 0x6A, 0xDE, 0xF8, 0x2C, 0x30, 0x9D, 0xF8, 0x04, 0x00, ++ 0x03, 0x33, 0x23, 0xF0, 0x03, 0x03, 0x04, 0x33, 0x9B, 0xB2, 0xC2, 0xF3, ++ 0x49, 0x2C, 0x03, 0xEB, 0x8C, 0x0C, 0x1F, 0xFA, 0x8C, 0xFC, 0xDC, 0x45, ++ 0x97, 0xD3, 0x03, 0x9E, 0x63, 0x46, 0x19, 0x44, 0xB1, 0x42, 0xA4, 0xD9, ++ 0x02, 0x9B, 0x00, 0x2B, 0x00, 0xF0, 0xA2, 0x80, 0x02, 0x9B, 0x5B, 0x6A, ++ 0x03, 0xF4, 0x60, 0x12, 0xB2, 0xF5, 0x20, 0x1F, 0x41, 0xD0, 0x02, 0x9E, ++ 0xF2, 0x6C, 0x43, 0xF4, 0x60, 0x11, 0x43, 0xF4, 0x60, 0x13, 0x50, 0x73, ++ 0xC5, 0xF8, 0x38, 0x61, 0x73, 0x62, 0xD9, 0xF8, 0x00, 0x30, 0xB3, 0xF9, ++ 0x00, 0x30, 0x41, 0xF4, 0x80, 0x71, 0x00, 0x20, 0x00, 0x2B, 0xD1, 0x64, ++ 0xD0, 0x61, 0x3D, 0xDB, 0x04, 0x9A, 0x92, 0xF8, 0x50, 0x30, 0x01, 0x33, ++ 0x82, 0xF8, 0x50, 0x30, 0x63, 0x6A, 0x03, 0xF4, 0x60, 0x13, 0xB3, 0xF5, ++ 0x60, 0x1F, 0x73, 0xD0, 0x1C, 0x32, 0x16, 0x46, 0x48, 0x4B, 0x06, 0x9A, ++ 0x1B, 0x68, 0x14, 0x60, 0x5B, 0x78, 0x13, 0xB9, 0x63, 0x6C, 0x0C, 0x33, ++ 0x2B, 0x61, 0x29, 0x46, 0x30, 0x46, 0x12, 0xF0, 0xE7, 0xFC, 0x05, 0x98, ++ 0x09, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x00, 0x2B, 0x9F, 0xD1, 0x40, 0x49, ++ 0x40, 0x48, 0x02, 0x93, 0x40, 0xF2, 0xBD, 0x32, 0x14, 0xF0, 0x0A, 0xF9, ++ 0x02, 0x9B, 0x96, 0xE7, 0x4F, 0xF0, 0x00, 0x0A, 0x53, 0xE7, 0x02, 0x9E, ++ 0x3B, 0x4B, 0x01, 0x21, 0xD3, 0xF8, 0x58, 0x33, 0x30, 0x46, 0x98, 0x47, ++ 0xF3, 0x6C, 0x75, 0x64, 0x14, 0x33, 0x05, 0x93, 0xD9, 0xF8, 0x00, 0x30, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xC1, 0xDA, 0x04, 0x9B, 0xDB, 0x69, ++ 0x9F, 0x42, 0xBD, 0xD0, 0x2F, 0x49, 0x32, 0x48, 0x40, 0xF2, 0xC3, 0x32, ++ 0x14, 0xF0, 0xEA, 0xF8, 0xB6, 0xE7, 0x00, 0x28, 0x7F, 0xF4, 0x0A, 0xAF, ++ 0x2A, 0x49, 0x2E, 0x48, 0x40, 0xF2, 0x27, 0x32, 0x14, 0xF0, 0xE0, 0xF8, ++ 0x02, 0xE7, 0x2C, 0x4B, 0x04, 0x93, 0xF2, 0xE6, 0xD9, 0xF8, 0x00, 0x30, ++ 0xC5, 0xF8, 0x38, 0x41, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x16, 0xDB, ++ 0x04, 0x9E, 0x1C, 0x36, 0x30, 0x46, 0x12, 0xF0, 0xBF, 0xFC, 0x1E, 0x4B, ++ 0x1B, 0x68, 0x5B, 0x78, 0x0B, 0xB9, 0x3B, 0x69, 0x2B, 0x61, 0x39, 0x46, ++ 0xD7, 0xF8, 0x48, 0x01, 0x12, 0xF0, 0x70, 0xFC, 0x06, 0x99, 0x22, 0x68, ++ 0xE3, 0x6C, 0x0A, 0x60, 0x00, 0x22, 0xDA, 0x61, 0xA1, 0xE7, 0x04, 0x9B, ++ 0xDB, 0x69, 0xBB, 0x42, 0xE4, 0xD0, 0x14, 0x49, 0x16, 0x48, 0x40, 0xF2, ++ 0xC3, 0x32, 0x14, 0xF0, 0xB3, 0xF8, 0xDD, 0xE7, 0x04, 0x9E, 0x1C, 0x36, ++ 0x30, 0x46, 0x12, 0xF0, 0x9D, 0xFC, 0x87, 0xE7, 0x0F, 0x4B, 0x07, 0x99, ++ 0xD3, 0xF8, 0xBC, 0x33, 0x07, 0xF1, 0x0C, 0x00, 0x98, 0x47, 0x02, 0x9B, ++ 0xD5, 0xF8, 0x48, 0x01, 0x05, 0x93, 0x29, 0x46, 0x12, 0xF0, 0x4A, 0xFC, ++ 0x85, 0xE7, 0x00, 0xBF, 0x20, 0x62, 0x17, 0x00, 0x8C, 0x64, 0x17, 0x00, ++ 0x94, 0x64, 0x17, 0x00, 0xC8, 0x35, 0x17, 0x00, 0x54, 0x83, 0x32, 0x40, ++ 0x34, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x3C, 0x91, 0x15, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x64, 0x91, 0x15, 0x00, 0x4C, 0x91, 0x15, 0x00, ++ 0xC4, 0x63, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0x0C, 0x46, 0x41, 0x7F, 0x63, 0x7F, 0x99, 0x42, 0x85, 0xB0, 0x05, 0xD1, ++ 0xE3, 0x7E, 0x16, 0x46, 0xC2, 0x7E, 0x9A, 0x42, 0x05, 0x46, 0x03, 0xD0, ++ 0x00, 0x20, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xD4, 0xE9, 0x11, 0x73, ++ 0x00, 0x2B, 0x00, 0xF0, 0x8F, 0x80, 0xBB, 0x88, 0x13, 0xF0, 0x08, 0x00, ++ 0xF3, 0xD0, 0x13, 0xF0, 0x02, 0x00, 0xF0, 0xD0, 0x13, 0xF0, 0x01, 0x00, ++ 0x40, 0xF0, 0x86, 0x80, 0xDF, 0xF8, 0x4C, 0x91, 0x54, 0x23, 0x03, 0xFB, ++ 0x06, 0x93, 0x93, 0xF8, 0x4D, 0x20, 0x01, 0x2A, 0xE3, 0xD0, 0xD3, 0xF8, ++ 0x34, 0x80, 0xD8, 0xE9, 0x12, 0xBA, 0xBB, 0xF1, 0x00, 0x0F, 0x05, 0xD0, ++ 0xDA, 0xF8, 0x20, 0x20, 0x46, 0x4B, 0x12, 0x68, 0x9A, 0x42, 0xD6, 0xD1, ++ 0x45, 0x4A, 0x46, 0x4B, 0x11, 0x68, 0x1A, 0x68, 0x91, 0xF8, 0x3E, 0x30, ++ 0x91, 0xF8, 0x3F, 0x10, 0x02, 0xF0, 0x3F, 0x02, 0x0B, 0x44, 0x9A, 0x42, ++ 0xC8, 0xDD, 0xD8, 0xF8, 0x24, 0x20, 0x54, 0x23, 0x03, 0xFB, 0x06, 0x93, ++ 0x42, 0xF4, 0x60, 0x12, 0x18, 0x6B, 0xC8, 0xF8, 0x24, 0x20, 0xC7, 0xF8, ++ 0x38, 0x81, 0x03, 0x93, 0x03, 0xF0, 0xE0, 0xF8, 0x39, 0x4A, 0x03, 0x9B, ++ 0x12, 0x68, 0x93, 0xF8, 0x4D, 0x10, 0x8A, 0xF8, 0x0D, 0x10, 0x52, 0x78, ++ 0x00, 0x2A, 0x4F, 0xD1, 0xEB, 0x6C, 0x3A, 0x61, 0xD9, 0x6C, 0xCA, 0xE9, ++ 0x06, 0x22, 0x8A, 0x02, 0x44, 0xD5, 0x6B, 0x6C, 0x07, 0xF1, 0x0C, 0x01, ++ 0x19, 0x61, 0x54, 0x23, 0x03, 0xFB, 0x06, 0xF3, 0x0A, 0xF1, 0x14, 0x00, ++ 0x09, 0xEB, 0x03, 0x02, 0x49, 0xF8, 0x03, 0x00, 0x01, 0x23, 0xC2, 0xE9, ++ 0x01, 0x13, 0xD8, 0xF8, 0x24, 0x30, 0xBA, 0x88, 0x43, 0xF4, 0x80, 0x73, ++ 0xCA, 0xF8, 0x4C, 0x30, 0x42, 0xF0, 0x01, 0x03, 0xBB, 0x80, 0xBB, 0xF1, ++ 0x00, 0x0F, 0x08, 0xD0, 0x50, 0x07, 0x06, 0xD4, 0x11, 0x07, 0x37, 0xD4, ++ 0xA1, 0x6C, 0x4A, 0x6A, 0x42, 0xF0, 0x04, 0x02, 0x4A, 0x62, 0x9B, 0x07, ++ 0x06, 0xD5, 0x54, 0x23, 0x03, 0xFB, 0x06, 0x93, 0x3A, 0x6B, 0x1B, 0x6B, ++ 0x9B, 0x6A, 0x53, 0x61, 0x54, 0x24, 0x04, 0xFB, 0x06, 0x90, 0x04, 0xFB, ++ 0x06, 0x96, 0x1C, 0x30, 0x39, 0x46, 0x12, 0xF0, 0x91, 0xFB, 0x96, 0xF8, ++ 0x50, 0x30, 0x00, 0x22, 0x01, 0x33, 0xF2, 0x62, 0x86, 0xF8, 0x50, 0x30, ++ 0x01, 0x20, 0x68, 0xE7, 0xBB, 0x88, 0x72, 0xE7, 0x01, 0x20, 0x64, 0xE7, ++ 0x07, 0xF1, 0x0C, 0x01, 0x99, 0x61, 0xBA, 0xE7, 0xB8, 0x7A, 0x93, 0xF8, ++ 0x4E, 0x30, 0x7A, 0x7A, 0xB8, 0xF8, 0x22, 0x10, 0x00, 0x93, 0x03, 0x46, ++ 0x38, 0x46, 0xFF, 0xF7, 0x55, 0xFD, 0x07, 0xF1, 0x50, 0x03, 0xCA, 0xF8, ++ 0x1C, 0x30, 0xB6, 0xE7, 0x42, 0xF0, 0x03, 0x03, 0xBB, 0x80, 0xC8, 0xE7, ++ 0xDE, 0xFA, 0xFE, 0xCA, 0xC8, 0x35, 0x17, 0x00, 0x54, 0x83, 0x32, 0x40, ++ 0x34, 0x36, 0x17, 0x00, 0x20, 0x62, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x47, ++ 0x45, 0x6C, 0x0C, 0x68, 0x6E, 0x7A, 0x60, 0x7F, 0x9D, 0xF8, 0x20, 0x70, ++ 0x86, 0x42, 0x03, 0xD1, 0xAE, 0x7A, 0xE0, 0x7E, 0x86, 0x42, 0x02, 0xD0, ++ 0x00, 0x20, 0xBD, 0xE8, 0xF0, 0x87, 0xE6, 0x6C, 0xD5, 0xF8, 0x38, 0xE1, ++ 0xD6, 0xF8, 0x24, 0xC0, 0xDE, 0xF8, 0x4C, 0x80, 0xBC, 0xF1, 0x00, 0x0F, ++ 0x00, 0xF0, 0x82, 0x80, 0xBC, 0xF8, 0x00, 0x90, 0x19, 0xF4, 0x00, 0x4F, ++ 0x1F, 0xFA, 0x89, 0xF0, 0x7A, 0xD1, 0x6F, 0xEA, 0x40, 0x40, 0x6F, 0xEA, ++ 0x50, 0x40, 0xAC, 0xF8, 0x00, 0x00, 0x94, 0xF8, 0x33, 0x90, 0x94, 0xF8, ++ 0x32, 0x00, 0x09, 0xF1, 0x04, 0x09, 0x04, 0x30, 0x84, 0xF8, 0x33, 0x90, ++ 0x84, 0xF8, 0x32, 0x00, 0xF0, 0x6A, 0x00, 0xF1, 0x04, 0x0A, 0xB0, 0x6A, ++ 0x00, 0xF1, 0x04, 0x09, 0xC6, 0xE9, 0x0A, 0x9A, 0x0A, 0xF1, 0x03, 0x00, ++ 0x20, 0xF0, 0x03, 0x00, 0x04, 0x30, 0x80, 0xB2, 0x83, 0x42, 0x5C, 0xD9, ++ 0xA3, 0xEB, 0x00, 0x09, 0x1F, 0xFA, 0x89, 0xF9, 0x09, 0xF1, 0x03, 0x09, ++ 0x4F, 0xEA, 0x99, 0x09, 0x00, 0xEB, 0x89, 0x00, 0x80, 0xB2, 0x6B, 0x6A, ++ 0x18, 0x44, 0x90, 0x42, 0xBA, 0xD8, 0x28, 0x4A, 0xDE, 0xF8, 0x24, 0x30, ++ 0x4F, 0xF0, 0x54, 0x0A, 0x0A, 0xFB, 0x07, 0x27, 0x23, 0xF4, 0xC0, 0x13, ++ 0x97, 0xF8, 0x50, 0x20, 0xDF, 0xF8, 0x90, 0xA0, 0x01, 0x3A, 0x87, 0xF8, ++ 0x50, 0x20, 0x43, 0xF4, 0x40, 0x12, 0xCE, 0xF8, 0x24, 0x20, 0x62, 0x6A, ++ 0xDA, 0xF8, 0x00, 0x70, 0xD4, 0xF8, 0x00, 0xE0, 0x22, 0xF4, 0xC0, 0x12, ++ 0x42, 0xEA, 0x49, 0x29, 0x43, 0xF4, 0x40, 0x13, 0x49, 0xF4, 0xF0, 0x0A, ++ 0x43, 0xF4, 0x80, 0x73, 0xC8, 0xF8, 0x4C, 0x30, 0x49, 0xF4, 0xF0, 0x02, ++ 0x00, 0x23, 0x4A, 0xF4, 0x80, 0x7A, 0x06, 0xF1, 0x14, 0x09, 0xC8, 0xF8, ++ 0x1C, 0x90, 0x62, 0x62, 0xC6, 0xF8, 0x4C, 0xA0, 0xB3, 0x61, 0xB3, 0x63, ++ 0x68, 0x62, 0x65, 0x64, 0xC5, 0xF8, 0x38, 0x41, 0xC1, 0xF8, 0x00, 0xE0, ++ 0x7B, 0x78, 0x03, 0xB9, 0x2B, 0x61, 0xBC, 0xF1, 0x00, 0x0F, 0x04, 0xD0, ++ 0x09, 0x4A, 0xB3, 0x6A, 0xD2, 0x6E, 0x43, 0xF8, 0x03, 0x2C, 0x98, 0xF8, ++ 0x0D, 0x30, 0x01, 0x33, 0x73, 0x73, 0x01, 0x20, 0xBD, 0xE8, 0xF0, 0x87, ++ 0xD6, 0xF8, 0x2C, 0xA0, 0x9A, 0xE7, 0x4F, 0xF0, 0x00, 0x09, 0xAA, 0xE7, ++ 0x20, 0x62, 0x17, 0x00, 0x94, 0x64, 0x17, 0x00, 0x34, 0x36, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0x85, 0xB0, 0xD1, 0xF8, 0x00, 0xB0, 0x9D, 0xF8, ++ 0x38, 0x90, 0xDF, 0xF8, 0x20, 0xA1, 0xDB, 0xF8, 0x44, 0x60, 0xDA, 0xF8, ++ 0x60, 0x43, 0x03, 0x93, 0x0F, 0x46, 0x90, 0x46, 0x59, 0x46, 0x4A, 0x46, ++ 0x05, 0x46, 0xA0, 0x47, 0x00, 0x28, 0x60, 0xD0, 0xE9, 0x6C, 0x03, 0x9B, ++ 0xCA, 0x6A, 0x02, 0xF1, 0x03, 0x0E, 0x2E, 0xF0, 0x03, 0x0E, 0x0E, 0xF1, ++ 0x04, 0x0E, 0x1F, 0xFA, 0x8E, 0xFE, 0x73, 0x45, 0x01, 0xF1, 0x14, 0x0C, ++ 0x54, 0xD8, 0x00, 0x20, 0x72, 0x6A, 0x0E, 0xEB, 0x02, 0x03, 0x43, 0x45, ++ 0x05, 0xD9, 0x34, 0x4A, 0x12, 0x68, 0x02, 0xF0, 0x3F, 0x02, 0x11, 0x2A, ++ 0x5D, 0xD9, 0x32, 0x4A, 0x6C, 0x6A, 0x4F, 0xF0, 0x54, 0x0E, 0x0E, 0xFB, ++ 0x09, 0x22, 0x24, 0xF4, 0xC0, 0x14, 0x92, 0xF8, 0x50, 0xE0, 0x44, 0xEA, ++ 0x40, 0x24, 0x0E, 0xF1, 0xFF, 0x30, 0x82, 0xF8, 0x50, 0x00, 0x44, 0xF4, ++ 0xD0, 0x0E, 0x72, 0x69, 0xCA, 0x61, 0xC6, 0xF8, 0x14, 0xC0, 0x73, 0x62, ++ 0xC5, 0xF8, 0x24, 0xE0, 0xDB, 0xF8, 0x24, 0x20, 0xD6, 0xF8, 0x38, 0xC1, ++ 0x6E, 0x64, 0x22, 0xF4, 0xC0, 0x12, 0x74, 0x46, 0x42, 0xF4, 0x40, 0x10, ++ 0xDB, 0xF8, 0x4C, 0xE0, 0xDC, 0xF8, 0x4C, 0xC0, 0x44, 0xF4, 0x80, 0x74, ++ 0xCC, 0x64, 0x42, 0xF4, 0x40, 0x12, 0x40, 0xF4, 0x80, 0x70, 0x00, 0x24, ++ 0x8C, 0x63, 0xCB, 0xF8, 0x24, 0x20, 0xCE, 0xF8, 0x4C, 0x00, 0x9C, 0xF8, ++ 0x0D, 0x20, 0x43, 0x45, 0x02, 0xF1, 0x01, 0x02, 0x8C, 0xF8, 0x0D, 0x20, ++ 0x16, 0xD9, 0xDA, 0xF8, 0x70, 0x63, 0x03, 0x9B, 0xCD, 0xF8, 0x00, 0x90, ++ 0x42, 0x46, 0x39, 0x46, 0x28, 0x46, 0xB0, 0x47, 0x20, 0x46, 0x05, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x8F, 0xA3, 0xEB, 0x0E, 0x04, 0xA4, 0xB2, 0x03, 0x34, ++ 0xA0, 0x08, 0x0E, 0xEB, 0x80, 0x0E, 0x1F, 0xFA, 0x8E, 0xFE, 0xA1, 0xE7, ++ 0x58, 0x46, 0xFF, 0xF7, 0x53, 0xFC, 0xD6, 0xF8, 0x38, 0x31, 0x1B, 0x68, ++ 0x3B, 0x60, 0x01, 0x20, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x00, 0x20, ++ 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x00, 0xBF, 0x54, 0x83, 0x32, 0x40, ++ 0x20, 0x62, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0x2D, 0xED, 0x02, 0x8B, 0x05, 0x46, 0x89, 0xB0, 0x6E, 0x6C, 0x9D, 0xF8, ++ 0x50, 0x40, 0x04, 0x91, 0x0F, 0x46, 0x1C, 0x20, 0x54, 0x21, 0x11, 0xFB, ++ 0x04, 0x01, 0xD6, 0xF8, 0x38, 0x01, 0x06, 0x90, 0xAB, 0x48, 0x05, 0x94, ++ 0x41, 0x18, 0x3C, 0x68, 0x01, 0x92, 0x08, 0x46, 0x08, 0xEE, 0x10, 0x1A, ++ 0x07, 0x93, 0xD4, 0xF8, 0x44, 0x80, 0xD4, 0xF8, 0x4C, 0x90, 0x12, 0xF0, ++ 0x41, 0xFA, 0xA5, 0x4B, 0x05, 0x9A, 0xD3, 0xF8, 0x60, 0x33, 0x28, 0x46, ++ 0x21, 0x46, 0x98, 0x47, 0x00, 0x23, 0x02, 0x93, 0x00, 0x28, 0x00, 0xF0, ++ 0xF8, 0x80, 0xDF, 0xF8, 0x98, 0xA2, 0x9F, 0x48, 0xDA, 0xF8, 0x00, 0x20, ++ 0x03, 0x68, 0x92, 0xF8, 0x3E, 0x20, 0x03, 0xF0, 0x3F, 0x03, 0x9A, 0x42, ++ 0x00, 0xF2, 0xFD, 0x80, 0x06, 0x9A, 0x04, 0x9D, 0x53, 0x6A, 0x2D, 0x68, ++ 0x03, 0x90, 0x17, 0x46, 0x23, 0xF4, 0xC0, 0x13, 0xD2, 0x6C, 0x43, 0xF4, ++ 0x40, 0x11, 0x09, 0xF1, 0x14, 0x0C, 0x92, 0xF8, 0x0D, 0xB0, 0xC2, 0xF8, ++ 0x1C, 0xC0, 0x79, 0x62, 0x61, 0x6A, 0x07, 0x9F, 0x43, 0xF4, 0x40, 0x13, ++ 0x21, 0xF4, 0xC0, 0x11, 0x43, 0xF4, 0x80, 0x73, 0x41, 0xF4, 0x40, 0x11, ++ 0xD3, 0x64, 0x61, 0x62, 0x6B, 0x6A, 0x43, 0xF4, 0x80, 0x73, 0xC9, 0xF8, ++ 0x4C, 0x30, 0x02, 0x9B, 0x99, 0x46, 0x4C, 0xE0, 0x9F, 0x42, 0x40, 0xF2, ++ 0x93, 0x80, 0xFA, 0x1A, 0x92, 0xB2, 0x03, 0x32, 0x4F, 0xEA, 0x92, 0x09, ++ 0x03, 0xEB, 0x89, 0x03, 0x9B, 0xB2, 0x72, 0x6A, 0x01, 0x98, 0x1A, 0x44, ++ 0x82, 0x42, 0x53, 0xD8, 0x03, 0x9D, 0xDA, 0xF8, 0x00, 0x00, 0x2D, 0x68, ++ 0x90, 0xF8, 0x3E, 0x00, 0x05, 0xF0, 0x3F, 0x05, 0xA8, 0x42, 0x49, 0xD8, ++ 0xDC, 0xF8, 0x24, 0x00, 0x28, 0xB1, 0x79, 0x4D, 0xDC, 0xF8, 0x28, 0x00, ++ 0xED, 0x6E, 0x40, 0xF8, 0x03, 0x5C, 0xBE, 0x45, 0x66, 0x64, 0x0D, 0xD2, ++ 0xDC, 0xF8, 0x4C, 0x10, 0x21, 0xF4, 0xFF, 0x21, 0x21, 0xF4, 0xC0, 0x61, ++ 0x41, 0xEA, 0x49, 0x21, 0x41, 0xF4, 0x80, 0x70, 0x61, 0x62, 0x73, 0x46, ++ 0xCC, 0xF8, 0x4C, 0x00, 0x72, 0x62, 0xD8, 0xF8, 0x24, 0x20, 0x01, 0xF4, ++ 0x60, 0x11, 0xD3, 0x1A, 0xB1, 0xF5, 0x60, 0x1F, 0xC8, 0xF8, 0x24, 0x30, ++ 0x59, 0xD0, 0x69, 0x4B, 0x25, 0x68, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x0B, 0xF1, 0x01, 0x0B, 0x00, 0x2B, 0x5F, 0xFA, 0x8B, 0xFB, 0x42, 0xDB, ++ 0x69, 0x6A, 0x02, 0x94, 0x2C, 0x46, 0xD4, 0xF8, 0x4C, 0xC0, 0xDC, 0xF8, ++ 0x2C, 0x30, 0x03, 0x33, 0x23, 0xF0, 0x03, 0x03, 0x04, 0x33, 0x9B, 0xB2, ++ 0xC1, 0xF3, 0x49, 0x2E, 0x03, 0xEB, 0x8E, 0x0E, 0x1F, 0xFA, 0x8E, 0xFE, ++ 0xBE, 0x45, 0xA1, 0xD3, 0x72, 0x6A, 0x01, 0x98, 0x73, 0x46, 0x1A, 0x44, ++ 0x82, 0x42, 0xAB, 0xD9, 0xDD, 0xF8, 0x08, 0x90, 0xB9, 0xF1, 0x00, 0x0F, ++ 0x7E, 0xD0, 0xD9, 0xF8, 0x4C, 0x10, 0x81, 0xF8, 0x0D, 0xB0, 0xD9, 0xF8, ++ 0x24, 0x30, 0xC6, 0xF8, 0x38, 0x91, 0x43, 0xF4, 0x60, 0x12, 0xC9, 0xF8, ++ 0x24, 0x20, 0x62, 0x6A, 0x43, 0xF4, 0x60, 0x13, 0x02, 0xF4, 0x60, 0x12, ++ 0x43, 0xF4, 0x80, 0x73, 0x00, 0x20, 0xB2, 0xF5, 0x60, 0x1F, 0xCB, 0x64, ++ 0xC8, 0x61, 0x60, 0xD0, 0x48, 0x4B, 0x04, 0x9A, 0x1B, 0x68, 0x14, 0x60, ++ 0x5D, 0x78, 0x00, 0x2D, 0x47, 0xD1, 0x63, 0x6C, 0x0C, 0x33, 0x33, 0x61, ++ 0x2C, 0xE0, 0x00, 0x2D, 0xBA, 0xD1, 0x43, 0x49, 0x43, 0x48, 0x40, 0xF2, ++ 0xF4, 0x52, 0x13, 0xF0, 0x7D, 0xFD, 0xB3, 0xE7, 0x4F, 0xF0, 0x00, 0x09, ++ 0x71, 0xE7, 0x05, 0x9A, 0x11, 0x46, 0x37, 0x4A, 0x54, 0x23, 0x03, 0xFB, ++ 0x01, 0x23, 0x3A, 0x49, 0x93, 0xF8, 0x50, 0x20, 0x09, 0x68, 0xC6, 0xF8, ++ 0x38, 0x41, 0x01, 0x3A, 0x83, 0xF8, 0x50, 0x20, 0x4B, 0x78, 0x43, 0xB3, ++ 0x18, 0xEE, 0x10, 0x0A, 0x12, 0xF0, 0x54, 0xF9, 0x41, 0x46, 0xD8, 0xF8, ++ 0x48, 0x01, 0x12, 0xF0, 0x0B, 0xF9, 0x04, 0x99, 0x22, 0x68, 0xE3, 0x6C, ++ 0x0A, 0x60, 0x00, 0x22, 0xDA, 0x61, 0x01, 0x25, 0x18, 0xEE, 0x10, 0x0A, ++ 0x31, 0x46, 0x12, 0xF0, 0x23, 0xF9, 0x28, 0x46, 0x09, 0xB0, 0xBD, 0xEC, ++ 0x02, 0x8B, 0xBD, 0xE8, 0xF0, 0x8F, 0x05, 0x46, 0x31, 0x46, 0x18, 0xEE, ++ 0x10, 0x0A, 0x12, 0xF0, 0x17, 0xF9, 0x28, 0x46, 0x09, 0xB0, 0xBD, 0xEC, ++ 0x02, 0x8B, 0xBD, 0xE8, 0xF0, 0x8F, 0x00, 0x25, 0xE6, 0xE7, 0xD8, 0xF8, ++ 0x10, 0x30, 0x33, 0x61, 0xD2, 0xE7, 0x18, 0xEE, 0x10, 0x0A, 0x31, 0x46, ++ 0x12, 0xF0, 0x06, 0xF9, 0x02, 0x9D, 0x28, 0x46, 0x09, 0xB0, 0xBD, 0xEC, ++ 0x02, 0x8B, 0xBD, 0xE8, 0xF0, 0x8F, 0x18, 0xEE, 0x10, 0x0A, 0x12, 0xF0, ++ 0x1B, 0xF9, 0x99, 0xE7, 0x06, 0x99, 0x4A, 0x6A, 0xCD, 0x6C, 0x42, 0xF4, ++ 0x60, 0x13, 0xC5, 0xF8, 0x1C, 0x90, 0x4B, 0x62, 0x63, 0x6A, 0x23, 0xF4, ++ 0xC0, 0x13, 0x43, 0xF4, 0x20, 0x17, 0x42, 0xF4, 0x60, 0x12, 0x43, 0xF4, ++ 0x20, 0x13, 0x42, 0xF4, 0x80, 0x72, 0x47, 0xF4, 0x80, 0x77, 0xEA, 0x64, ++ 0x18, 0xEE, 0x10, 0x0A, 0x63, 0x62, 0x31, 0x46, 0xCC, 0xF8, 0x4C, 0x70, ++ 0x12, 0xF0, 0xDC, 0xF8, 0x04, 0x9B, 0x4D, 0x46, 0x1C, 0x60, 0xB4, 0xE7, ++ 0x20, 0x62, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x54, 0x83, 0x32, 0x40, ++ 0x94, 0x64, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, 0x34, 0x36, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xA4, 0x91, 0x15, 0x00, 0xC8, 0x35, 0x17, 0x00, ++ 0x82, 0x69, 0x03, 0x32, 0x22, 0xF0, 0x03, 0x02, 0x04, 0x32, 0x93, 0xB2, ++ 0x99, 0x42, 0x04, 0xD9, 0xC8, 0x1A, 0x80, 0xB2, 0x03, 0x30, 0x80, 0x08, ++ 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0xBF, 0x2D, 0xE9, 0xF8, 0x4F, ++ 0x43, 0x4A, 0x44, 0x4B, 0x11, 0x68, 0x18, 0x68, 0x88, 0x42, 0x08, 0xD0, ++ 0xD2, 0xE9, 0x01, 0x54, 0xD2, 0xE9, 0x03, 0x02, 0xC3, 0xE9, 0x00, 0x15, ++ 0xC3, 0xE9, 0x02, 0x40, 0x1A, 0x61, 0x3E, 0x48, 0x3C, 0x4D, 0x3E, 0x4F, ++ 0xDF, 0xF8, 0x04, 0x81, 0x30, 0x22, 0x00, 0x21, 0x06, 0x46, 0xEE, 0xF7, ++ 0xE3, 0xFF, 0x05, 0xF1, 0x18, 0x09, 0x3B, 0x68, 0x55, 0xF8, 0x04, 0x0B, ++ 0x4F, 0xF4, 0xAC, 0x72, 0x02, 0xFB, 0x03, 0xF2, 0x00, 0x21, 0xEE, 0xF7, ++ 0xD7, 0xFF, 0x57, 0xF8, 0x04, 0x3B, 0x00, 0x2B, 0x58, 0xDD, 0x4F, 0xF0, ++ 0x00, 0x0B, 0xDA, 0x46, 0x55, 0xF8, 0x04, 0x4C, 0x30, 0x4B, 0x5C, 0x44, ++ 0x05, 0x20, 0x04, 0xF1, 0xA8, 0x01, 0x63, 0x64, 0x2E, 0x4B, 0xC4, 0xF8, ++ 0xA8, 0x30, 0x84, 0xF8, 0x97, 0x00, 0x04, 0xF1, 0x94, 0x03, 0x04, 0xF1, ++ 0xAB, 0x00, 0x61, 0x67, 0x18, 0x21, 0x6F, 0xF0, 0x7B, 0x0C, 0x23, 0x66, ++ 0x60, 0x66, 0x4F, 0xF4, 0xC0, 0x63, 0x40, 0xF2, 0x43, 0x10, 0xA1, 0x66, ++ 0x00, 0x21, 0xC4, 0xE9, 0x21, 0x30, 0xC4, 0xE9, 0x0D, 0x11, 0xC4, 0xE9, ++ 0x16, 0x11, 0xC4, 0xE9, 0x1E, 0x11, 0x84, 0xF8, 0x94, 0xC0, 0x84, 0xF8, ++ 0x95, 0x10, 0x84, 0xF8, 0x96, 0x10, 0xA1, 0x62, 0xE1, 0x63, 0xE1, 0x66, ++ 0xC4, 0xF8, 0x80, 0x10, 0x21, 0x67, 0xC4, 0xF8, 0x48, 0x61, 0xC4, 0xF8, ++ 0x0C, 0x80, 0xC4, 0xF8, 0x50, 0x80, 0xF0, 0xF7, 0x7F, 0xF8, 0x80, 0x03, ++ 0xC4, 0xF8, 0xAC, 0x00, 0xF0, 0xF7, 0x7A, 0xF8, 0x4F, 0xF0, 0x01, 0x0C, ++ 0x01, 0x30, 0x0C, 0xFA, 0x00, 0xF0, 0x12, 0x4B, 0xC4, 0xF8, 0xB8, 0x30, ++ 0x01, 0x38, 0x00, 0x21, 0xC4, 0xE9, 0x2C, 0x01, 0x21, 0x46, 0x30, 0x46, ++ 0x12, 0xF0, 0x16, 0xF8, 0x57, 0xF8, 0x04, 0x1C, 0x0A, 0xF1, 0x01, 0x0A, ++ 0x8A, 0x45, 0x0B, 0xF5, 0xAC, 0x7B, 0xA9, 0xDB, 0x4D, 0x45, 0x06, 0xF1, ++ 0x08, 0x06, 0x94, 0xD1, 0xBD, 0xE8, 0xF8, 0x8F, 0xEC, 0x57, 0x18, 0x00, ++ 0x74, 0x1F, 0x17, 0x00, 0x64, 0x64, 0x17, 0x00, 0x8C, 0x1F, 0x17, 0x00, ++ 0x00, 0x01, 0x20, 0x00, 0x1E, 0xAB, 0xDC, 0xBA, 0x04, 0x07, 0xFF, 0xFF, ++ 0xBE, 0xBA, 0xFE, 0xCA, 0x2D, 0xE9, 0xF8, 0x43, 0x18, 0x4A, 0x19, 0x4B, ++ 0x11, 0x68, 0x18, 0x68, 0x88, 0x42, 0x08, 0xD0, 0xD2, 0xE9, 0x01, 0x54, ++ 0xD2, 0xE9, 0x03, 0x02, 0xC3, 0xE9, 0x00, 0x15, 0xC3, 0xE9, 0x02, 0x40, ++ 0x1A, 0x61, 0x13, 0x4C, 0x13, 0x4F, 0x11, 0x4E, 0x04, 0xF1, 0x30, 0x09, ++ 0x20, 0x46, 0x11, 0xF0, 0xDB, 0xFF, 0x57, 0xF8, 0x04, 0x3B, 0x00, 0x2B, ++ 0x0E, 0xDD, 0x00, 0x25, 0xA8, 0x46, 0x31, 0x68, 0x20, 0x46, 0x29, 0x44, ++ 0x11, 0xF0, 0xD4, 0xFF, 0x57, 0xF8, 0x04, 0x3C, 0x08, 0xF1, 0x01, 0x08, ++ 0x98, 0x45, 0x05, 0xF5, 0xAC, 0x75, 0xF2, 0xDB, 0x08, 0x34, 0x4C, 0x45, ++ 0x06, 0xF1, 0x04, 0x06, 0xE4, 0xD1, 0xBD, 0xE8, 0xF8, 0x83, 0x00, 0xBF, ++ 0xEC, 0x57, 0x18, 0x00, 0x74, 0x1F, 0x17, 0x00, 0x64, 0x64, 0x17, 0x00, ++ 0x8C, 0x1F, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x47, 0x05, 0x28, 0x82, 0xB0, ++ 0x06, 0x46, 0x00, 0xF0, 0xBD, 0x80, 0x6A, 0x4C, 0x00, 0xEB, 0x40, 0x03, ++ 0xC3, 0xEB, 0xC3, 0x03, 0x04, 0xEB, 0x83, 0x04, 0x94, 0xF8, 0x4D, 0x30, ++ 0xE7, 0x6A, 0x65, 0x6B, 0x01, 0x2B, 0x69, 0xD1, 0xD5, 0xE9, 0x12, 0x38, ++ 0x00, 0x22, 0x4F, 0xF4, 0x80, 0x71, 0x6A, 0x62, 0xC8, 0xF8, 0x1C, 0x20, ++ 0xC8, 0xF8, 0x4C, 0x10, 0x00, 0x2B, 0x4C, 0xD0, 0xBA, 0x88, 0x11, 0x07, ++ 0x49, 0xD5, 0xD3, 0xE9, 0x17, 0x21, 0x28, 0x33, 0xC8, 0xF8, 0x34, 0x10, ++ 0xC8, 0xF8, 0x48, 0x20, 0xC8, 0xF8, 0x38, 0x30, 0x2B, 0x7F, 0x58, 0x4A, ++ 0x4F, 0xF4, 0xA4, 0x61, 0x01, 0xFB, 0x03, 0x23, 0x93, 0xF8, 0x62, 0x30, ++ 0x63, 0xBB, 0x55, 0x4A, 0x6B, 0x7F, 0x4F, 0xF4, 0x1E, 0x71, 0x01, 0xFB, ++ 0x03, 0x23, 0x5B, 0x68, 0x9A, 0x06, 0x23, 0xD5, 0xEB, 0x8B, 0x13, 0xF4, ++ 0x00, 0x5F, 0xEB, 0x6A, 0xDB, 0x6B, 0x14, 0xBF, 0xC3, 0xF3, 0x00, 0x13, ++ 0xC3, 0xF3, 0xC0, 0x03, 0xC3, 0xB9, 0xD8, 0xF8, 0x24, 0x10, 0x0B, 0x88, ++ 0x9A, 0xB2, 0x1B, 0x04, 0x12, 0xD5, 0xC2, 0xF3, 0x0E, 0x02, 0x0A, 0x80, ++ 0x95, 0xF8, 0x33, 0x20, 0x95, 0xF8, 0x32, 0x30, 0x04, 0x3A, 0x04, 0x3B, ++ 0x85, 0xF8, 0x33, 0x20, 0x85, 0xF8, 0x32, 0x30, 0xD8, 0xE9, 0x0A, 0x32, ++ 0x04, 0x3A, 0x04, 0x3B, 0xC8, 0xE9, 0x0A, 0x32, 0x28, 0x46, 0x02, 0xF0, ++ 0x71, 0xFC, 0x3E, 0x4B, 0x08, 0xF1, 0x14, 0x01, 0xD3, 0xF8, 0x9C, 0x33, ++ 0x32, 0x46, 0x08, 0x46, 0x98, 0x47, 0xD7, 0xF8, 0x48, 0x01, 0x39, 0x46, ++ 0x11, 0xF0, 0x4A, 0xFF, 0x00, 0x23, 0x6B, 0x64, 0x94, 0xF8, 0x50, 0x30, ++ 0x00, 0x22, 0x01, 0x33, 0x84, 0xF8, 0x50, 0x30, 0xE2, 0x62, 0x02, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x87, 0x6B, 0x6A, 0xDF, 0xF8, 0xCC, 0x90, 0x20, 0x6B, ++ 0xD5, 0xE9, 0x12, 0xA8, 0x43, 0xF4, 0x60, 0x13, 0x6B, 0x62, 0xC7, 0xF8, ++ 0x38, 0x51, 0x02, 0xF0, 0x37, 0xFC, 0x94, 0xF8, 0x4D, 0x20, 0xD9, 0xF8, ++ 0x00, 0x30, 0x88, 0xF8, 0x0D, 0x20, 0x5B, 0x78, 0x00, 0x2B, 0x34, 0xD1, ++ 0x3B, 0x61, 0x6B, 0x6A, 0xB9, 0x88, 0x43, 0xF4, 0x80, 0x73, 0x41, 0xF0, ++ 0x01, 0x02, 0xC8, 0xF8, 0x4C, 0x30, 0xBA, 0x80, 0xBA, 0xF1, 0x00, 0x0F, ++ 0x09, 0xD0, 0x4D, 0x07, 0x07, 0xD4, 0x08, 0x07, 0x31, 0xD4, 0x23, 0x6B, ++ 0x99, 0x6C, 0x4B, 0x6A, 0x43, 0xF0, 0x04, 0x03, 0x4B, 0x62, 0x93, 0x07, ++ 0x10, 0xD5, 0xD9, 0xF8, 0x00, 0x30, 0x5B, 0x78, 0xA3, 0xB9, 0x08, 0xF1, ++ 0x14, 0x01, 0x23, 0x6B, 0x3A, 0x6B, 0x98, 0x6A, 0x15, 0x4B, 0x50, 0x61, ++ 0xD3, 0xF8, 0x9C, 0x33, 0x32, 0x46, 0x07, 0xF1, 0x0C, 0x00, 0x98, 0x47, ++ 0x39, 0x46, 0x04, 0xF1, 0x1C, 0x00, 0x11, 0xF0, 0xF9, 0xFE, 0xAF, 0xE7, ++ 0x0F, 0x4C, 0x47, 0xE7, 0x07, 0xF1, 0x50, 0x01, 0xE9, 0xE7, 0x94, 0xF8, ++ 0x4E, 0x00, 0xBB, 0x7A, 0x7A, 0x7A, 0x69, 0x8C, 0x00, 0x90, 0x38, 0x46, ++ 0xFF, 0xF7, 0xCA, 0xF8, 0x07, 0xF1, 0x50, 0x03, 0xC8, 0xF8, 0x1C, 0x30, ++ 0xBD, 0xE7, 0x41, 0xF0, 0x03, 0x02, 0xBA, 0x80, 0xCF, 0xE7, 0x00, 0xBF, ++ 0x20, 0x62, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0xC4, 0x63, 0x17, 0x00, 0x34, 0x36, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0xD0, 0xF8, 0x4C, 0x90, 0x8B, 0xB0, 0x09, 0xF1, ++ 0x14, 0x03, 0x05, 0x29, 0x04, 0x46, 0x0E, 0x46, 0x00, 0x93, 0x00, 0xF0, ++ 0xAD, 0x81, 0x57, 0x4D, 0x01, 0xEB, 0x41, 0x03, 0xC3, 0xEB, 0xC3, 0x03, ++ 0x05, 0xEB, 0x83, 0x05, 0x94, 0xF8, 0x1B, 0xB0, 0x94, 0xF8, 0x1D, 0xA0, ++ 0xEF, 0xF3, 0x10, 0x83, 0xDF, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x50, 0x4B, ++ 0x01, 0x22, 0x1A, 0x60, 0xDF, 0xF8, 0x40, 0x81, 0xEA, 0x6A, 0xD8, 0xF8, ++ 0x00, 0x30, 0x01, 0x33, 0xC8, 0xF8, 0x00, 0x30, 0x00, 0x2A, 0x79, 0xD0, ++ 0x4A, 0x4F, 0x06, 0xE0, 0xD7, 0xF8, 0x5C, 0x33, 0x30, 0x46, 0x98, 0x47, ++ 0xEA, 0x6A, 0x00, 0x2A, 0x70, 0xD0, 0x63, 0x6A, 0x99, 0x02, 0xF5, 0xD5, ++ 0x03, 0xF4, 0x60, 0x11, 0xB1, 0xF5, 0x20, 0x1F, 0xF0, 0xD0, 0x50, 0x7A, ++ 0x61, 0x7F, 0x88, 0x42, 0xEC, 0xD1, 0x90, 0x7A, 0xE1, 0x7E, 0x88, 0x42, ++ 0xE8, 0xD1, 0xD9, 0xF8, 0x2C, 0x10, 0xB5, 0xF8, 0x48, 0x00, 0x03, 0x31, ++ 0x21, 0xF0, 0x03, 0x01, 0x04, 0x31, 0x89, 0xB2, 0x88, 0x42, 0x00, 0xF2, ++ 0x5D, 0x81, 0x00, 0x20, 0x03, 0x90, 0x05, 0x90, 0x86, 0x46, 0x68, 0x6B, ++ 0x01, 0x90, 0x50, 0x6A, 0x02, 0x90, 0x01, 0x98, 0x95, 0xF8, 0x4F, 0xC0, ++ 0xC0, 0x6C, 0x04, 0x90, 0x03, 0x98, 0xA5, 0xF8, 0x4A, 0xE0, 0x08, 0x44, ++ 0x02, 0x99, 0x05, 0xEB, 0x8C, 0x0E, 0x08, 0x44, 0x4F, 0xEA, 0x8C, 0x01, ++ 0x03, 0x91, 0xDE, 0xF8, 0x38, 0x10, 0x88, 0x42, 0x40, 0xF2, 0x82, 0x81, ++ 0x95, 0xF8, 0x4E, 0x10, 0x61, 0x45, 0xBB, 0xD9, 0x95, 0xF8, 0x4D, 0x10, ++ 0x01, 0x29, 0xB7, 0xD0, 0xDE, 0xF8, 0x3C, 0xE0, 0x70, 0x45, 0xB3, 0xD8, ++ 0x03, 0x9F, 0x17, 0x44, 0xBB, 0x46, 0x01, 0x9F, 0xCB, 0xF8, 0x3C, 0x71, ++ 0x0C, 0xF1, 0x01, 0x0C, 0x02, 0x9F, 0xCB, 0xF8, 0x34, 0x70, 0x85, 0xF8, ++ 0x4F, 0xC0, 0x05, 0x9F, 0x62, 0x64, 0x43, 0xEA, 0x47, 0x23, 0x23, 0xF4, ++ 0xC0, 0x13, 0x43, 0xF4, 0xE0, 0x03, 0x63, 0x62, 0xC9, 0xF8, 0x4C, 0x30, ++ 0x04, 0x9B, 0x1F, 0x46, 0x00, 0x9B, 0xFB, 0x61, 0x50, 0x62, 0x95, 0xF8, ++ 0x4C, 0x20, 0x6C, 0x63, 0x4B, 0x1C, 0xDB, 0xB2, 0x9A, 0x42, 0x85, 0xF8, ++ 0x4D, 0x30, 0x0D, 0xD8, 0x10, 0x4B, 0x30, 0x46, 0xD3, 0xF8, 0x5C, 0x33, ++ 0x98, 0x47, 0x07, 0xE0, 0x63, 0x6A, 0x98, 0x02, 0x1C, 0xD4, 0x95, 0xF8, ++ 0x50, 0x30, 0x01, 0x33, 0x85, 0xF8, 0x50, 0x30, 0xD8, 0xF8, 0x00, 0x30, ++ 0x3B, 0xB1, 0x07, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0xC8, 0xF8, 0x00, 0x30, ++ 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0x00, 0x20, 0x0B, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x8F, 0x00, 0xBF, 0x20, 0x62, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0xA3, 0x6A, 0xDB, 0x0A, ++ 0x13, 0xF0, 0x06, 0x0F, 0xDD, 0xD0, 0xB0, 0x48, 0x00, 0xEB, 0xC6, 0x00, ++ 0x11, 0xF0, 0x4A, 0xFE, 0xE8, 0x62, 0x00, 0x28, 0x00, 0xF0, 0xEA, 0x80, ++ 0xAC, 0x4F, 0x80, 0xF8, 0x0A, 0xB0, 0x00, 0x23, 0x01, 0x21, 0x3A, 0x68, ++ 0x80, 0xF8, 0x09, 0xA0, 0x03, 0x72, 0x43, 0x60, 0xC1, 0x72, 0xA3, 0x6A, ++ 0xB2, 0xF9, 0x00, 0x20, 0x61, 0x7F, 0x03, 0x91, 0xC3, 0xF3, 0xC1, 0x1B, ++ 0xC3, 0xF3, 0xC7, 0x21, 0x00, 0x2A, 0xC3, 0xF3, 0xC2, 0x23, 0x01, 0x93, ++ 0xC0, 0xF2, 0xD2, 0x80, 0x01, 0x9B, 0x05, 0x2B, 0x00, 0xF0, 0xD9, 0x80, ++ 0xD4, 0xF8, 0x28, 0xA0, 0x63, 0x7F, 0x05, 0x93, 0x0A, 0xF0, 0x7F, 0x03, ++ 0x04, 0x93, 0xCA, 0xF3, 0x40, 0x23, 0x06, 0x93, 0x01, 0x9B, 0x04, 0x2B, ++ 0x3B, 0x68, 0x00, 0xF0, 0xF2, 0x80, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0xC0, 0xF2, 0x01, 0x81, 0x94, 0x4A, 0x05, 0x99, 0x02, 0x92, 0x4F, 0xF4, ++ 0x1E, 0x73, 0x03, 0xFB, 0x01, 0x23, 0x04, 0x9A, 0x9B, 0x8A, 0x08, 0x93, ++ 0xC2, 0xF3, 0xC1, 0x02, 0x01, 0x32, 0x09, 0x92, 0x0A, 0xF0, 0x07, 0x0A, ++ 0x8D, 0x4B, 0x05, 0x93, 0x8D, 0x4B, 0x9C, 0x46, 0x06, 0x9B, 0x00, 0x27, ++ 0x43, 0xEA, 0xCA, 0x0A, 0x5F, 0xFA, 0x8B, 0xF3, 0x19, 0x46, 0x05, 0xF1, ++ 0x38, 0x0B, 0x04, 0x93, 0x85, 0xF8, 0x4E, 0x10, 0x00, 0x23, 0x31, 0x1D, ++ 0xCD, 0xF8, 0x18, 0x90, 0x07, 0x94, 0xD1, 0x46, 0x85, 0xF8, 0x4F, 0x30, ++ 0xDA, 0x46, 0x1E, 0x46, 0x64, 0x46, 0x8B, 0x46, 0x01, 0x2A, 0xF1, 0xB2, ++ 0x00, 0xF0, 0xA8, 0x80, 0x48, 0x46, 0xA0, 0x47, 0x7E, 0x4B, 0x09, 0x9A, ++ 0x33, 0xF8, 0x1B, 0xC0, 0x08, 0x99, 0x02, 0xFB, 0x0C, 0xFC, 0x00, 0xFB, ++ 0x0C, 0xF0, 0xF8, 0x40, 0x81, 0x42, 0x28, 0xBF, 0x01, 0x46, 0x4A, 0xF8, ++ 0x04, 0x1B, 0x95, 0xF8, 0x4E, 0x10, 0x01, 0x36, 0x8E, 0x42, 0xE5, 0xDD, ++ 0xCA, 0x46, 0x04, 0x99, 0x05, 0x9B, 0x50, 0x46, 0xDD, 0xE9, 0x06, 0x94, ++ 0x98, 0x47, 0x03, 0x9B, 0xD5, 0xF8, 0x38, 0xC0, 0x1E, 0x46, 0x02, 0x9B, ++ 0x4F, 0xF4, 0x1E, 0x72, 0x02, 0xFB, 0x06, 0x32, 0x09, 0x9B, 0x16, 0x7F, ++ 0xEA, 0x6A, 0x03, 0xFB, 0x06, 0xF6, 0x00, 0xFB, 0x06, 0xF6, 0xFE, 0x40, ++ 0xB6, 0xB2, 0xA5, 0xF8, 0x48, 0x60, 0xE1, 0x7E, 0x63, 0x7F, 0xEF, 0x6B, ++ 0x9E, 0x20, 0x00, 0xFB, 0x03, 0x13, 0x02, 0x99, 0x28, 0x6C, 0x01, 0xEB, ++ 0x83, 0x03, 0x4F, 0xF0, 0x01, 0x0E, 0x93, 0xF8, 0x5A, 0x31, 0x85, 0xF8, ++ 0x4C, 0x30, 0xD9, 0xF8, 0x2C, 0x10, 0x00, 0x9B, 0x53, 0x61, 0x03, 0x31, ++ 0x21, 0xF0, 0x03, 0x01, 0x04, 0x31, 0x00, 0x23, 0x89, 0xB2, 0x51, 0x62, ++ 0xC2, 0xF8, 0x54, 0x01, 0xC2, 0xE9, 0x53, 0xC7, 0xC2, 0xE9, 0x0D, 0x33, ++ 0x93, 0x64, 0x93, 0x61, 0xD3, 0x63, 0x85, 0xF8, 0x4D, 0xE0, 0xD9, 0xF8, ++ 0x2C, 0x00, 0x03, 0x30, 0x20, 0xF0, 0x03, 0x00, 0x04, 0x30, 0x80, 0xB2, ++ 0xB0, 0x42, 0x57, 0xD2, 0x30, 0x1A, 0x80, 0xB2, 0x03, 0x30, 0x83, 0x10, ++ 0x01, 0xEB, 0x83, 0x01, 0x80, 0x08, 0x5B, 0x02, 0x66, 0x6A, 0xA5, 0xF8, ++ 0x4A, 0x00, 0x33, 0x43, 0x23, 0xF4, 0xC0, 0x13, 0x43, 0xF4, 0xD0, 0x03, ++ 0x51, 0x62, 0xC5, 0xE9, 0x0C, 0x44, 0x63, 0x62, 0x62, 0x64, 0xC9, 0xF8, ++ 0x4C, 0x30, 0xFF, 0xE6, 0xA0, 0xEB, 0x01, 0x0E, 0x1F, 0xFA, 0x8E, 0xFE, ++ 0x0E, 0xF1, 0x03, 0x0E, 0x4F, 0xEA, 0xAE, 0x00, 0x05, 0x90, 0x80, 0x00, ++ 0x4F, 0xEA, 0x9E, 0x0E, 0x03, 0x90, 0x98, 0xE6, 0x3D, 0x4D, 0x57, 0xE6, ++ 0x60, 0x62, 0xE8, 0xE6, 0x11, 0xF0, 0x06, 0x0F, 0x7F, 0xF4, 0x2A, 0xAF, ++ 0x3A, 0x49, 0x3B, 0x48, 0x4F, 0xF4, 0xEA, 0x72, 0x13, 0xF0, 0x60, 0xF9, ++ 0x22, 0xE7, 0x09, 0xAB, 0x08, 0xAA, 0x01, 0x99, 0x20, 0x46, 0x02, 0xF0, ++ 0x39, 0xF9, 0x36, 0x4B, 0x05, 0x93, 0x36, 0x4B, 0x94, 0xF8, 0x36, 0x70, ++ 0x09, 0x9A, 0x9C, 0x46, 0x2B, 0x4B, 0x02, 0x93, 0x82, 0x46, 0xC7, 0xF3, ++ 0x40, 0x17, 0x3F, 0xE7, 0x01, 0x9B, 0x04, 0x2B, 0x7F, 0xF4, 0x54, 0xAF, ++ 0x4F, 0xEA, 0xE9, 0x02, 0x00, 0x2E, 0x7F, 0xF4, 0x4F, 0xAF, 0x09, 0x2A, ++ 0x04, 0xBF, 0x09, 0xF0, 0x07, 0x03, 0x43, 0xF0, 0x40, 0x09, 0x47, 0xE7, ++ 0x18, 0x46, 0xAD, 0xE7, 0x95, 0xF8, 0x4D, 0x10, 0x93, 0xE6, 0x04, 0x9A, ++ 0xB3, 0xF9, 0x00, 0x30, 0x11, 0x09, 0x4A, 0x1C, 0x00, 0x2B, 0x0A, 0xF0, ++ 0x0F, 0x0A, 0x09, 0x92, 0x14, 0xDB, 0x19, 0x49, 0x05, 0x98, 0x02, 0x91, ++ 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, 0x00, 0x13, 0x1B, 0x69, 0x08, 0x93, ++ 0x0E, 0xE7, 0x1A, 0xF0, 0x60, 0x0F, 0x3F, 0xF4, 0xFB, 0xAE, 0x17, 0x49, ++ 0x1A, 0x48, 0x4F, 0xF4, 0xD2, 0x72, 0x13, 0xF0, 0x19, 0xF9, 0xF3, 0xE6, ++ 0x03, 0x29, 0x04, 0xD8, 0xBA, 0xF1, 0x09, 0x0F, 0x0D, 0xD8, 0x09, 0x9A, ++ 0xE3, 0xE7, 0x10, 0x49, 0x14, 0x48, 0x40, 0xF2, 0x9B, 0x12, 0x13, 0xF0, ++ 0x0B, 0xF9, 0x3B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xEF, 0xDB, ++ 0xF1, 0xE7, 0x0A, 0x49, 0x0F, 0x48, 0x4F, 0xF4, 0xCE, 0x72, 0x13, 0xF0, ++ 0xFF, 0xF8, 0xEA, 0xE7, 0x64, 0x64, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x68, 0x65, 0x17, 0x00, 0x85, 0x06, 0x13, 0x00, 0x75, 0x06, 0x13, 0x00, ++ 0x98, 0x9C, 0x17, 0x00, 0xC4, 0x63, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0xB8, 0x91, 0x15, 0x00, 0x21, 0x3B, 0x13, 0x00, 0x05, 0x3B, 0x13, 0x00, ++ 0x0C, 0x92, 0x15, 0x00, 0xE0, 0x91, 0x15, 0x00, 0xFC, 0x91, 0x15, 0x00, ++ 0xC3, 0x7A, 0x01, 0x3B, 0xDB, 0xB2, 0xC3, 0x72, 0x03, 0xB1, 0x70, 0x47, ++ 0x01, 0x46, 0xD0, 0xF8, 0x48, 0x01, 0x11, 0xF0, 0x83, 0xBC, 0x00, 0xBF, ++ 0x2D, 0xE9, 0xF0, 0x47, 0xD0, 0xE9, 0x12, 0x67, 0x00, 0x23, 0x4F, 0xF4, ++ 0x80, 0x72, 0x43, 0x62, 0x43, 0x64, 0xFB, 0x61, 0xFA, 0x64, 0x00, 0x2E, ++ 0x00, 0xF0, 0x81, 0x80, 0xD0, 0xF8, 0x2C, 0x80, 0x8A, 0x46, 0x05, 0x46, ++ 0x06, 0xF1, 0x28, 0x09, 0x08, 0xF1, 0x40, 0x01, 0x43, 0x46, 0x06, 0xF1, ++ 0x24, 0x02, 0x53, 0xF8, 0x04, 0x4B, 0x42, 0xF8, 0x04, 0x4F, 0x8B, 0x42, ++ 0xF9, 0xD1, 0xEB, 0x8B, 0x9C, 0x04, 0x22, 0xD5, 0x48, 0x4B, 0x49, 0x49, ++ 0x1A, 0x68, 0x6B, 0x7F, 0xB2, 0xF9, 0x00, 0x20, 0x4F, 0xF4, 0x1E, 0x70, ++ 0x00, 0xFB, 0x03, 0x13, 0x00, 0x2A, 0xD3, 0xF8, 0x4C, 0x41, 0x61, 0xDB, ++ 0xD8, 0xF8, 0x14, 0x20, 0xD4, 0xF8, 0x9C, 0x30, 0x32, 0x64, 0xD8, 0xF8, ++ 0x24, 0x20, 0x32, 0x65, 0xC3, 0xF3, 0xC2, 0x22, 0x05, 0x2A, 0xF3, 0x63, ++ 0x5D, 0xD0, 0xD8, 0xF8, 0x3C, 0x30, 0x58, 0x07, 0x03, 0xD4, 0xF3, 0x6A, ++ 0x23, 0xF4, 0xC0, 0x73, 0xF3, 0x62, 0x39, 0x4A, 0x2B, 0x7F, 0x4F, 0xF4, ++ 0xA4, 0x61, 0x01, 0xFB, 0x03, 0x23, 0x93, 0xF8, 0x62, 0x30, 0x7B, 0xB1, ++ 0x73, 0x6A, 0x43, 0xF0, 0x10, 0x03, 0x28, 0x46, 0x73, 0x62, 0x02, 0xF0, ++ 0x47, 0xF9, 0xD6, 0xE9, 0x17, 0x23, 0x07, 0xF1, 0x14, 0x00, 0xC7, 0xE9, ++ 0x0D, 0x39, 0xBA, 0x64, 0xBD, 0xE8, 0xF0, 0x87, 0x2B, 0x4A, 0x6B, 0x7F, ++ 0x4F, 0xF4, 0x1E, 0x71, 0x01, 0xFB, 0x03, 0x23, 0x5B, 0x68, 0x99, 0x06, ++ 0xE6, 0xD5, 0xBA, 0xF1, 0x00, 0x0F, 0xE3, 0xD1, 0xEB, 0x8B, 0x13, 0xF4, ++ 0x00, 0x5F, 0xEB, 0x6A, 0xDB, 0x6B, 0x14, 0xBF, 0xC3, 0xF3, 0x00, 0x13, ++ 0xC3, 0xF3, 0xC0, 0x03, 0x00, 0x2B, 0xD7, 0xD1, 0x79, 0x6A, 0x0A, 0x88, ++ 0x93, 0xB2, 0x12, 0x04, 0xD2, 0xD5, 0xC3, 0xF3, 0x0E, 0x03, 0x0B, 0x80, ++ 0x95, 0xF8, 0x33, 0x20, 0x95, 0xF8, 0x32, 0x30, 0x04, 0x3A, 0x04, 0x3B, ++ 0x85, 0xF8, 0x33, 0x20, 0x85, 0xF8, 0x32, 0x30, 0xD7, 0xE9, 0x0A, 0x32, ++ 0x04, 0x3A, 0x04, 0x3B, 0xC7, 0xE9, 0x0A, 0x32, 0xBE, 0xE7, 0x30, 0x46, ++ 0xBD, 0xE8, 0xF0, 0x87, 0x00, 0x2C, 0x9B, 0xD1, 0x12, 0x49, 0x13, 0x48, ++ 0x40, 0xF2, 0x4B, 0x12, 0x13, 0xF0, 0x3C, 0xF8, 0x94, 0xE7, 0x03, 0xF4, ++ 0xC0, 0x63, 0xF2, 0x6C, 0x94, 0xF8, 0xA1, 0x10, 0xB3, 0xF5, 0x80, 0x6F, ++ 0x14, 0xBF, 0x4F, 0xF4, 0x80, 0x30, 0x4F, 0xF4, 0x00, 0x30, 0x22, 0xF4, ++ 0x40, 0x33, 0x03, 0x43, 0x19, 0xB1, 0x43, 0xF4, 0x80, 0x23, 0xF3, 0x64, ++ 0x8D, 0xE7, 0x23, 0xF4, 0x80, 0x23, 0xF3, 0x64, 0x89, 0xE7, 0x00, 0xBF, ++ 0x38, 0x36, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x68, 0x8E, 0x15, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0x05, 0x28, 0x89, 0xB0, 0x81, 0x46, 0x00, 0xF0, 0x79, 0x81, 0xBE, 0x4A, ++ 0x00, 0xEB, 0x40, 0x03, 0xC3, 0xEB, 0xC3, 0x03, 0x02, 0xEB, 0x83, 0x03, ++ 0x03, 0x93, 0x03, 0x9B, 0xDC, 0x68, 0xBA, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0x09, 0xDA, 0x5D, 0xE1, 0xE3, 0x6C, 0x1B, 0x6D, ++ 0x00, 0x2B, 0x80, 0xF2, 0xFE, 0x80, 0x24, 0x68, 0x00, 0x2C, 0x00, 0xF0, ++ 0xFA, 0x80, 0x63, 0x6A, 0x9A, 0x02, 0xF3, 0xD5, 0xB0, 0x4D, 0x2A, 0x68, ++ 0xB2, 0xF9, 0x00, 0x20, 0x00, 0x2A, 0xC0, 0xF2, 0x80, 0x81, 0xAE, 0x4B, ++ 0x67, 0x6C, 0x1B, 0x68, 0xDB, 0xB2, 0x07, 0xEB, 0x83, 0x03, 0xD3, 0xF8, ++ 0x3C, 0x41, 0xE5, 0x6C, 0x63, 0x6A, 0xAA, 0x49, 0x43, 0xF4, 0x60, 0x10, ++ 0x09, 0x68, 0x60, 0x62, 0x49, 0x78, 0x23, 0xF4, 0xC0, 0x13, 0x00, 0x29, ++ 0x40, 0xF0, 0x58, 0x81, 0x43, 0xF4, 0x60, 0x13, 0x43, 0xF4, 0x80, 0x73, ++ 0x00, 0x2A, 0x26, 0x68, 0xEB, 0x64, 0xE9, 0x61, 0xC0, 0xF2, 0x57, 0x81, ++ 0x72, 0x6A, 0x02, 0xF4, 0x60, 0x1A, 0xBA, 0xF5, 0x60, 0x1F, 0x00, 0xF0, ++ 0xEC, 0x80, 0x9D, 0x48, 0x50, 0xF8, 0x39, 0x30, 0x00, 0x2B, 0x00, 0xF0, ++ 0xE6, 0x80, 0x00, 0xEB, 0xC9, 0x00, 0x11, 0xF0, 0xAD, 0xFB, 0xBB, 0x88, ++ 0x83, 0x80, 0x7B, 0x7A, 0x43, 0x72, 0xBB, 0x7A, 0x83, 0x72, 0x01, 0x23, ++ 0xC3, 0x72, 0x72, 0x6A, 0xD6, 0xF8, 0x4C, 0xA0, 0xF9, 0x6A, 0xD7, 0xF8, ++ 0x4C, 0xB1, 0xB5, 0x6C, 0x05, 0x95, 0x04, 0x46, 0xD7, 0xE9, 0x10, 0x03, ++ 0x22, 0xF4, 0xC0, 0x12, 0xE1, 0x62, 0x42, 0xF4, 0x20, 0x12, 0x00, 0x21, ++ 0xC4, 0xE9, 0x10, 0x03, 0xA1, 0x64, 0x3B, 0x6B, 0x72, 0x62, 0xCA, 0xF8, ++ 0x4C, 0x20, 0xC4, 0xF8, 0x4C, 0xB1, 0x06, 0x93, 0xD7, 0xF8, 0x50, 0x31, ++ 0xC4, 0xF8, 0x50, 0x31, 0xD7, 0xF8, 0x54, 0x31, 0xC4, 0xF8, 0x54, 0x31, ++ 0x04, 0xF1, 0x0C, 0x03, 0x0A, 0xF1, 0x14, 0x0C, 0x28, 0x35, 0xC4, 0xE9, ++ 0x0D, 0x11, 0xA1, 0x61, 0xE1, 0x63, 0x61, 0x62, 0x04, 0x93, 0x04, 0xF5, ++ 0x82, 0x73, 0xC4, 0xF8, 0x14, 0xC0, 0x25, 0x63, 0xBC, 0x46, 0x08, 0x46, ++ 0x57, 0x46, 0x07, 0x93, 0xAA, 0x46, 0x8E, 0x46, 0x25, 0x46, 0x0C, 0x46, ++ 0x06, 0xE0, 0x5A, 0x6A, 0xDF, 0x6C, 0xD8, 0xF8, 0x34, 0x00, 0xD8, 0xF8, ++ 0x4C, 0xB1, 0x1E, 0x46, 0xFB, 0x6A, 0x03, 0x33, 0xC2, 0xF3, 0x49, 0x28, ++ 0x23, 0xF0, 0x03, 0x03, 0x03, 0xEB, 0x88, 0x03, 0x04, 0x33, 0x9B, 0xB2, ++ 0x18, 0x44, 0x01, 0x31, 0x58, 0x45, 0x02, 0xF4, 0x60, 0x12, 0xC9, 0xB2, ++ 0x06, 0xD9, 0x05, 0xEB, 0x8E, 0x00, 0x0E, 0xF1, 0x01, 0x0E, 0x44, 0x63, ++ 0x5F, 0xFA, 0x8E, 0xFE, 0x05, 0xEB, 0x8E, 0x08, 0x1C, 0x44, 0xC8, 0xF8, ++ 0x3C, 0x61, 0xB2, 0xF5, 0x60, 0x1F, 0x33, 0x68, 0x75, 0x64, 0x6C, 0x62, ++ 0x00, 0xF0, 0x18, 0x81, 0x00, 0x2B, 0xD2, 0xD1, 0x2C, 0x46, 0x98, 0x46, ++ 0x55, 0x46, 0xC4, 0xF8, 0x38, 0x61, 0xBA, 0x46, 0x67, 0x46, 0x03, 0x98, ++ 0x8A, 0xF8, 0x0D, 0x10, 0x90, 0xF8, 0x50, 0x30, 0x03, 0xF1, 0x01, 0x0C, ++ 0x03, 0x46, 0x22, 0x46, 0x1C, 0x30, 0x83, 0xF8, 0x50, 0xC0, 0x39, 0x46, ++ 0x11, 0xF0, 0xA0, 0xFB, 0x53, 0x4B, 0x1B, 0x68, 0x58, 0x78, 0x00, 0x28, ++ 0x40, 0xF0, 0x11, 0x81, 0xD7, 0xF8, 0x38, 0x11, 0xF2, 0x6C, 0xDF, 0xF8, ++ 0x30, 0xC1, 0xC9, 0x6C, 0xD0, 0x61, 0x54, 0x23, 0x03, 0xFB, 0x09, 0xF3, ++ 0x3A, 0x69, 0x5C, 0xF8, 0x03, 0x00, 0x22, 0x61, 0x14, 0x31, 0x04, 0x9A, ++ 0x3A, 0x61, 0x88, 0x42, 0x63, 0x44, 0x00, 0xF0, 0x2A, 0x81, 0x06, 0x9B, ++ 0x07, 0x9A, 0xA3, 0xF1, 0x28, 0x00, 0x05, 0x9B, 0xC0, 0x1A, 0x03, 0xF1, ++ 0x5C, 0x01, 0x2B, 0x18, 0x1C, 0x68, 0x45, 0xF8, 0x04, 0x4B, 0x1B, 0x68, ++ 0x42, 0xF8, 0x04, 0x3B, 0x8D, 0x42, 0xF6, 0xD1, 0x3B, 0x4C, 0x48, 0x46, ++ 0xFC, 0xF7, 0x10, 0xF8, 0x23, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0xD7, 0xF8, 0x38, 0x31, 0x04, 0xDB, 0xB3, 0x42, 0x1C, 0xD1, 0x09, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x8F, 0xB3, 0x42, 0xFA, 0xD0, 0x36, 0x49, 0x37, 0x48, ++ 0x40, 0xF6, 0x2A, 0x42, 0x12, 0xF0, 0xF2, 0xFE, 0xD7, 0xF8, 0x38, 0x31, ++ 0xB3, 0x42, 0xF0, 0xD0, 0x23, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0x08, 0xDA, 0xB8, 0xF1, 0x00, 0x0F, 0x05, 0xD1, 0x2D, 0x49, 0x2F, 0x48, ++ 0x4F, 0xF4, 0x43, 0x62, 0x12, 0xF0, 0xE0, 0xFE, 0xD8, 0xF8, 0x24, 0x20, ++ 0x46, 0x46, 0x02, 0xF4, 0x60, 0x1A, 0x26, 0x4B, 0x1B, 0x68, 0x5B, 0x78, ++ 0x00, 0x2B, 0x58, 0xD1, 0xD7, 0xF8, 0x38, 0x31, 0xD7, 0xF8, 0x10, 0x80, ++ 0xDB, 0x6C, 0x07, 0xF1, 0x0C, 0x05, 0x03, 0xF1, 0x14, 0x07, 0x1C, 0x4B, ++ 0x04, 0x97, 0x54, 0x24, 0x04, 0xFB, 0x09, 0x34, 0x57, 0x46, 0xDF, 0xF8, ++ 0x88, 0xB0, 0xDF, 0xF8, 0x7C, 0x90, 0xA2, 0x46, 0x03, 0x9C, 0x94, 0xF8, ++ 0x50, 0x10, 0xDB, 0xF8, 0x58, 0x33, 0x01, 0x31, 0x84, 0xF8, 0x50, 0x10, ++ 0x30, 0x46, 0x00, 0x21, 0x98, 0x47, 0x58, 0xB1, 0x13, 0x4B, 0x68, 0x60, ++ 0x1B, 0x68, 0x59, 0x78, 0xDA, 0xF8, 0x00, 0x30, 0x00, 0x29, 0x65, 0xD0, ++ 0xAB, 0x42, 0x00, 0xF0, 0xAD, 0x80, 0x05, 0x46, 0xB7, 0xF5, 0x60, 0x1F, ++ 0x65, 0xD1, 0xC0, 0xF8, 0x04, 0x80, 0x09, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, ++ 0x00, 0x2C, 0x7F, 0xF4, 0xA8, 0xAE, 0x0A, 0x49, 0x0B, 0x48, 0x40, 0xF6, ++ 0x8B, 0x32, 0x12, 0xF0, 0x99, 0xFE, 0xA0, 0xE6, 0x09, 0x4B, 0x03, 0x93, ++ 0x8B, 0xE6, 0x00, 0xBF, 0x20, 0x62, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x30, 0x83, 0x32, 0x40, 0x34, 0x36, 0x17, 0x00, 0x64, 0x64, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x4C, 0x92, 0x15, 0x00, 0x3C, 0x91, 0x15, 0x00, ++ 0xC4, 0x63, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x07, 0xF1, 0x50, 0x01, ++ 0xA4, 0xE6, 0xD7, 0xF8, 0x54, 0x80, 0x07, 0xF1, 0x50, 0x05, 0x00, 0x27, ++ 0xA9, 0xE7, 0x00, 0x2E, 0x7F, 0xF4, 0xA6, 0xAE, 0x49, 0x49, 0x4A, 0x48, ++ 0x40, 0xF6, 0xB6, 0x32, 0x12, 0xF0, 0x6E, 0xFE, 0x9E, 0xE6, 0x03, 0xF4, ++ 0x60, 0x13, 0xB3, 0xF5, 0x20, 0x1F, 0x3E, 0xD0, 0x40, 0xF6, 0x9B, 0x32, ++ 0x42, 0x49, 0x44, 0x48, 0x12, 0xF0, 0x62, 0xFE, 0x43, 0x4B, 0x67, 0x6C, ++ 0x1B, 0x68, 0x2A, 0x68, 0xDB, 0xB2, 0x07, 0xEB, 0x83, 0x03, 0xB2, 0xF9, ++ 0x00, 0x20, 0xD3, 0xF8, 0x3C, 0x41, 0x00, 0x2A, 0xE5, 0x6C, 0xBF, 0xF6, ++ 0x6F, 0xAE, 0x63, 0x6A, 0x03, 0xF4, 0x60, 0x12, 0xB2, 0xF5, 0x60, 0x1F, ++ 0x60, 0xD0, 0x3A, 0x4A, 0x12, 0x68, 0xB2, 0xF9, 0x00, 0x20, 0x64, 0xE6, ++ 0x04, 0x9A, 0x93, 0x42, 0x99, 0xD1, 0xCA, 0xE9, 0x01, 0x11, 0x05, 0x46, ++ 0x96, 0xE7, 0x34, 0x4B, 0x36, 0x68, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0x3F, 0xDB, 0x77, 0x6A, 0x07, 0xF4, 0x60, 0x17, 0x74, 0xE7, ++ 0x20, 0x46, 0x2C, 0x46, 0x04, 0xEB, 0x8E, 0x0E, 0x55, 0x46, 0xC4, 0xF8, ++ 0x38, 0x61, 0xBA, 0x46, 0x98, 0x46, 0x67, 0x46, 0xCE, 0xF8, 0x34, 0x00, ++ 0xE3, 0xE6, 0x27, 0x4B, 0x67, 0x6C, 0x1B, 0x68, 0xDB, 0xB2, 0x07, 0xEB, ++ 0x83, 0x03, 0xD3, 0xF8, 0x3C, 0x41, 0xE5, 0x6C, 0xCB, 0xE7, 0xB0, 0x6A, ++ 0xA3, 0x7A, 0x62, 0x7A, 0x71, 0x8C, 0xC0, 0xF3, 0xC1, 0x10, 0x00, 0x90, ++ 0x20, 0x46, 0xFE, 0xF7, 0xA1, 0xFB, 0x54, 0x23, 0x1E, 0x49, 0xF2, 0x6C, ++ 0xD7, 0xF8, 0x54, 0xE0, 0x03, 0xFB, 0x09, 0xF3, 0x04, 0xF1, 0x50, 0x00, ++ 0x51, 0xF8, 0x03, 0xC0, 0xD0, 0x61, 0x07, 0xF1, 0x50, 0x02, 0xC4, 0xF8, ++ 0x54, 0xE0, 0x94, 0x45, 0x04, 0x9C, 0x7C, 0x65, 0x7F, 0xF4, 0xE5, 0xAE, ++ 0xC8, 0x50, 0xE2, 0xE6, 0xCA, 0xF8, 0x00, 0x00, 0x05, 0x46, 0x4F, 0xE7, ++ 0x00, 0x2E, 0xBD, 0xD1, 0x0B, 0x49, 0x40, 0xF6, 0x62, 0x42, 0x48, 0x46, ++ 0x12, 0xF0, 0xF2, 0xFD, 0xB6, 0xE7, 0x04, 0x99, 0x01, 0x22, 0xC3, 0xE9, ++ 0x01, 0x12, 0xD0, 0xE6, 0x40, 0xF6, 0xA5, 0x32, 0x04, 0x49, 0x0A, 0x48, ++ 0x12, 0xF0, 0xE6, 0xFD, 0x06, 0x4B, 0x1A, 0x68, 0x63, 0x6A, 0xB2, 0xF9, ++ 0x00, 0x20, 0xFC, 0xE5, 0x70, 0x79, 0x15, 0x00, 0x3C, 0x91, 0x15, 0x00, ++ 0x1C, 0x92, 0x15, 0x00, 0x30, 0x83, 0x32, 0x40, 0x38, 0x36, 0x17, 0x00, ++ 0x20, 0x62, 0x17, 0x00, 0x34, 0x92, 0x15, 0x00, 0x05, 0x28, 0x10, 0xB5, ++ 0x25, 0xD0, 0x14, 0x4A, 0x00, 0xEB, 0x40, 0x03, 0xC3, 0xEB, 0xC3, 0x03, ++ 0x02, 0xEB, 0x83, 0x02, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, ++ 0x72, 0xB6, 0x0F, 0x4B, 0x01, 0x21, 0x19, 0x60, 0x0E, 0x4C, 0x92, 0xF8, ++ 0x50, 0x10, 0x23, 0x68, 0x01, 0x33, 0x23, 0x60, 0x31, 0xB9, 0xD2, 0x6A, ++ 0x22, 0xB1, 0x0B, 0x4B, 0xD3, 0xF8, 0x5C, 0x33, 0x98, 0x47, 0x23, 0x68, ++ 0x33, 0xB1, 0x06, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x23, 0x60, 0x0B, 0xB9, ++ 0x02, 0xB1, 0x62, 0xB6, 0x10, 0xBD, 0x05, 0x4A, 0xDE, 0xE7, 0x00, 0xBF, ++ 0x20, 0x62, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0xC4, 0x63, 0x17, 0x00, 0x03, 0x68, 0x13, 0xF4, ++ 0xE0, 0x3F, 0x1A, 0xD1, 0x9A, 0x04, 0x4C, 0xBF, 0x03, 0xF0, 0x0F, 0x02, ++ 0x03, 0xF0, 0x07, 0x02, 0x02, 0x2A, 0xC3, 0xF3, 0xC1, 0x11, 0x88, 0xBF, ++ 0x4F, 0xF4, 0x80, 0x12, 0x23, 0xF0, 0xFF, 0x53, 0x98, 0xBF, 0x4F, 0xF4, ++ 0x00, 0x22, 0x23, 0xF4, 0xFE, 0x13, 0x42, 0xEA, 0x01, 0x62, 0x13, 0x43, ++ 0x43, 0xF0, 0x80, 0x63, 0x43, 0xF4, 0x00, 0x43, 0x03, 0x60, 0x70, 0x47, ++ 0xC3, 0x6B, 0x00, 0x2B, 0x00, 0xDB, 0x70, 0x47, 0x10, 0xB4, 0x0E, 0x4C, ++ 0x42, 0x6A, 0x24, 0x68, 0xB4, 0xF9, 0x00, 0x40, 0x00, 0x2C, 0x01, 0xDA, ++ 0xDB, 0x03, 0x0B, 0xD5, 0x53, 0x69, 0x23, 0xF4, 0xE0, 0x33, 0x00, 0x24, ++ 0x43, 0xF4, 0x80, 0x43, 0xC4, 0x63, 0x5D, 0xF8, 0x04, 0x4B, 0x53, 0x61, ++ 0xFC, 0xF7, 0xA4, 0xB9, 0x04, 0x49, 0x05, 0x48, 0x5D, 0xF8, 0x04, 0x4B, ++ 0x40, 0xF6, 0xD9, 0x42, 0x12, 0xF0, 0x28, 0xBD, 0x38, 0x36, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x78, 0x92, 0x15, 0x00, 0x05, 0x28, 0x10, 0xB5, ++ 0x17, 0xD0, 0x0D, 0x4C, 0x00, 0xEB, 0x40, 0x00, 0xC0, 0xEB, 0xC0, 0x00, ++ 0x04, 0xEB, 0x80, 0x04, 0xA1, 0x6A, 0x31, 0xB1, 0xCB, 0x7A, 0x01, 0x3B, ++ 0xDB, 0xB2, 0xCB, 0x72, 0x13, 0xB1, 0x00, 0x23, 0xA3, 0x62, 0x10, 0xBD, ++ 0xD1, 0xF8, 0x48, 0x01, 0x11, 0xF0, 0xE8, 0xF8, 0x00, 0x23, 0xA3, 0x62, ++ 0xF7, 0xE7, 0x02, 0x4C, 0xEC, 0xE7, 0x00, 0xBF, 0x20, 0x62, 0x17, 0x00, ++ 0xC4, 0x63, 0x17, 0x00, 0xF0, 0xB4, 0xC5, 0x6C, 0x42, 0x6A, 0xEB, 0x6C, ++ 0xD0, 0xE9, 0x11, 0x67, 0x22, 0xF4, 0xC0, 0x12, 0x23, 0xF4, 0x60, 0x13, ++ 0x05, 0xF1, 0x14, 0x0C, 0x42, 0xF4, 0x20, 0x14, 0x43, 0xF4, 0x20, 0x12, ++ 0x06, 0xF5, 0x82, 0x73, 0xC6, 0xF8, 0x14, 0xC0, 0x33, 0x63, 0x44, 0x62, ++ 0xEA, 0x64, 0x06, 0xF1, 0x0C, 0x00, 0x07, 0xF1, 0x24, 0x02, 0x06, 0xF5, ++ 0x9C, 0x75, 0x53, 0xF8, 0x04, 0x4B, 0x42, 0xF8, 0x04, 0x4F, 0xAB, 0x42, ++ 0xF9, 0xD1, 0x77, 0xB1, 0x09, 0x4B, 0x1B, 0x68, 0x5B, 0x78, 0x33, 0xB9, ++ 0xD6, 0xF8, 0x38, 0x31, 0xDB, 0x6C, 0x14, 0x33, 0x0B, 0x60, 0xF0, 0xBC, ++ 0x70, 0x47, 0x50, 0x36, 0x0E, 0x60, 0xF0, 0xBC, 0x70, 0x47, 0x01, 0x23, ++ 0x38, 0x46, 0x73, 0x60, 0xF5, 0xE7, 0x00, 0xBF, 0x34, 0x36, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0x47, 0x6A, 0xD0, 0xF8, 0x4C, 0xE0, 0x85, 0xB0, ++ 0x17, 0xF4, 0x00, 0x1C, 0x9D, 0xF8, 0x38, 0x90, 0x04, 0x46, 0x0E, 0xF1, ++ 0x14, 0x08, 0x0D, 0x46, 0x16, 0x46, 0x9A, 0x46, 0x2A, 0xD0, 0x07, 0xF4, ++ 0x60, 0x17, 0xB7, 0xF5, 0x20, 0x1F, 0x40, 0xF0, 0xBB, 0x80, 0xD0, 0xF8, ++ 0x44, 0xB0, 0xBB, 0xF8, 0x04, 0x70, 0x07, 0xF0, 0x03, 0x07, 0x03, 0x2F, ++ 0x40, 0xF0, 0xB2, 0x80, 0xDF, 0xF8, 0x30, 0xC2, 0x83, 0x4F, 0xDC, 0xF8, ++ 0x00, 0xC0, 0x3F, 0x68, 0x9C, 0xF8, 0x3E, 0xC0, 0x07, 0xF0, 0x3F, 0x07, ++ 0xBC, 0x45, 0x00, 0xF2, 0xA5, 0x80, 0xDB, 0xF8, 0x24, 0x70, 0x97, 0x42, ++ 0x40, 0xF2, 0xC1, 0x80, 0x7C, 0x4C, 0xCD, 0xF8, 0x38, 0x90, 0xD4, 0xF8, ++ 0x70, 0x43, 0xA4, 0x46, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x4F, 0x60, 0x47, ++ 0x83, 0x6C, 0x00, 0x2B, 0x00, 0xF0, 0x92, 0x80, 0x5B, 0x6A, 0x13, 0xF0, ++ 0x10, 0x03, 0x00, 0xF0, 0x8D, 0x80, 0x82, 0x88, 0x00, 0x2A, 0x00, 0xF0, ++ 0x8F, 0x80, 0xC3, 0x8B, 0x1F, 0x07, 0x00, 0xF1, 0x8B, 0x80, 0xDE, 0xF8, ++ 0x24, 0x10, 0x00, 0x29, 0x00, 0xF0, 0xB9, 0x80, 0x08, 0x88, 0x83, 0xB2, ++ 0x00, 0x04, 0x00, 0xF1, 0xB4, 0x80, 0x6F, 0xEA, 0x43, 0x43, 0x6F, 0xEA, ++ 0x53, 0x43, 0x0B, 0x80, 0x94, 0xF8, 0x33, 0x20, 0x94, 0xF8, 0x32, 0x30, ++ 0x04, 0x32, 0x04, 0x33, 0x84, 0xF8, 0x32, 0x30, 0x84, 0xF8, 0x33, 0x20, ++ 0xDE, 0xE9, 0x0A, 0x12, 0xD3, 0x1D, 0x23, 0xF0, 0x03, 0x03, 0x04, 0x33, ++ 0x9B, 0xB2, 0x04, 0x32, 0x04, 0x31, 0xB3, 0x42, 0xCE, 0xE9, 0x0A, 0x12, ++ 0x6D, 0xD8, 0xA2, 0x88, 0x32, 0xB1, 0xE3, 0x8B, 0x1F, 0x07, 0x03, 0xD4, ++ 0x5A, 0x4B, 0xDB, 0x6E, 0x41, 0xF8, 0x03, 0x3C, 0x23, 0x68, 0x2B, 0x60, ++ 0x00, 0x2B, 0x36, 0xD0, 0x11, 0x46, 0xDF, 0xF8, 0x70, 0xB1, 0x54, 0x4F, ++ 0x32, 0x46, 0x00, 0x29, 0x2C, 0xD0, 0xE1, 0x8B, 0x0E, 0x07, 0x29, 0xD4, ++ 0x99, 0x88, 0x39, 0xB3, 0xD9, 0x8B, 0x08, 0x07, 0x24, 0xD4, 0x4D, 0x49, ++ 0xDB, 0xF8, 0x00, 0x00, 0x09, 0x68, 0x90, 0xF8, 0x3E, 0x60, 0x01, 0xF0, ++ 0x3F, 0x01, 0x8E, 0x42, 0x1A, 0xD8, 0x5B, 0x6A, 0xBC, 0xF1, 0x00, 0x0F, ++ 0x4C, 0xD1, 0x9B, 0x02, 0x17, 0xD5, 0xCD, 0xF8, 0x00, 0x90, 0xD7, 0xF8, ++ 0x54, 0x63, 0x03, 0x92, 0x53, 0x46, 0x29, 0x46, 0x20, 0x46, 0xB0, 0x47, ++ 0x03, 0x9A, 0x00, 0x28, 0x77, 0xD0, 0x2B, 0x68, 0x00, 0x2B, 0x74, 0xD0, ++ 0x60, 0x6A, 0xA1, 0x88, 0x00, 0xF4, 0x00, 0x1C, 0x00, 0x29, 0xD2, 0xD1, ++ 0xBC, 0xF1, 0x00, 0x0F, 0x47, 0xD1, 0x63, 0x6C, 0xD3, 0xB9, 0x3B, 0x48, ++ 0x11, 0xF0, 0x2C, 0xF8, 0x3A, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0x05, 0x46, 0x56, 0xDB, 0x54, 0x23, 0x1C, 0x22, 0x37, 0x48, ++ 0x13, 0xFB, 0x09, 0x29, 0x00, 0x22, 0x01, 0x23, 0xAA, 0x80, 0xEB, 0x72, ++ 0x48, 0x44, 0x29, 0x46, 0x65, 0x64, 0x10, 0xF0, 0xF7, 0xFF, 0x01, 0xE0, ++ 0x4F, 0xF0, 0x00, 0x08, 0x40, 0x46, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, ++ 0xDE, 0xF8, 0x2C, 0x30, 0x03, 0x33, 0x23, 0xF0, 0x03, 0x03, 0x04, 0x33, ++ 0x9B, 0xB2, 0x9E, 0x42, 0x9A, 0xD2, 0x25, 0x4B, 0x40, 0x46, 0xD3, 0xF8, ++ 0xBC, 0x33, 0x49, 0x46, 0x98, 0x47, 0x4F, 0xF0, 0x00, 0x08, 0xE9, 0xE7, ++ 0xCD, 0xF8, 0x00, 0x90, 0x99, 0x02, 0x54, 0xBF, 0xD7, 0xF8, 0x50, 0x63, ++ 0xD7, 0xF8, 0x4C, 0x63, 0xAF, 0xE7, 0xFE, 0xF7, 0xD1, 0xF9, 0xDB, 0xF8, ++ 0x38, 0x31, 0x67, 0x6A, 0x1B, 0x68, 0x2B, 0x60, 0x5B, 0xB3, 0xA2, 0x88, ++ 0x07, 0xF4, 0x00, 0x1C, 0x80, 0xE7, 0x63, 0x6C, 0xD3, 0xF8, 0x38, 0x21, ++ 0x03, 0xF1, 0x0C, 0x08, 0xD2, 0x6C, 0x00, 0x21, 0x40, 0x46, 0xD1, 0x61, ++ 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xDE, 0xF8, 0x2C, 0x30, 0x03, 0x33, ++ 0x23, 0xF0, 0x03, 0x03, 0x04, 0x33, 0x9B, 0xB2, 0x9E, 0x42, 0xCC, 0xD3, ++ 0x00, 0x29, 0x3F, 0xF4, 0x65, 0xAF, 0xDE, 0xF8, 0x28, 0x10, 0x5D, 0xE7, ++ 0x00, 0x28, 0xA6, 0xD1, 0x0C, 0x49, 0x0D, 0x48, 0x40, 0xF6, 0x92, 0x52, ++ 0x12, 0xF0, 0xD6, 0xFB, 0x9F, 0xE7, 0x67, 0x6A, 0x07, 0xF4, 0x00, 0x1C, ++ 0x8C, 0xE7, 0x07, 0xF4, 0x00, 0x1C, 0x89, 0xE7, 0x54, 0x83, 0x32, 0x40, ++ 0x88, 0x1A, 0x17, 0x00, 0x94, 0x64, 0x17, 0x00, 0x8C, 0x64, 0x17, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x20, 0x62, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x3C, 0x90, 0x15, 0x00, 0xC8, 0x35, 0x17, 0x00, 0x08, 0xB5, 0x04, 0x28, ++ 0x2C, 0xD8, 0xDF, 0xE8, 0x00, 0xF0, 0x0B, 0x23, 0x13, 0x1B, 0x03, 0x00, ++ 0x1B, 0x4B, 0x1B, 0x68, 0x13, 0xF0, 0x03, 0x0F, 0x0C, 0xBF, 0x01, 0x20, ++ 0x00, 0x20, 0x08, 0xBD, 0x17, 0x4B, 0x1B, 0x68, 0x13, 0xF0, 0x30, 0x0F, ++ 0x0C, 0xBF, 0x01, 0x20, 0x00, 0x20, 0x08, 0xBD, 0x13, 0x4B, 0x1B, 0x68, ++ 0x13, 0xF4, 0x40, 0x5F, 0x0C, 0xBF, 0x01, 0x20, 0x00, 0x20, 0x08, 0xBD, ++ 0x0F, 0x4B, 0x1B, 0x68, 0x13, 0xF4, 0x40, 0x3F, 0x0C, 0xBF, 0x01, 0x20, ++ 0x00, 0x20, 0x08, 0xBD, 0x0B, 0x4B, 0x1B, 0x68, 0x13, 0xF4, 0x40, 0x7F, ++ 0x0C, 0xBF, 0x01, 0x20, 0x00, 0x20, 0x08, 0xBD, 0x08, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x01, 0xDB, 0x00, 0x20, 0x08, 0xBD, ++ 0x05, 0x49, 0x06, 0x48, 0x40, 0xF2, 0xF3, 0x12, 0x12, 0xF0, 0x7E, 0xFB, ++ 0x00, 0x20, 0x08, 0xBD, 0x88, 0x81, 0x32, 0x40, 0x38, 0x36, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x64, 0x7D, 0x15, 0x00, 0x90, 0xF8, 0x25, 0x30, ++ 0xE3, 0xB1, 0x10, 0xB5, 0x0F, 0x4A, 0x10, 0x4B, 0x11, 0x69, 0xD3, 0xF8, ++ 0xE0, 0x31, 0x01, 0xF5, 0x9C, 0x51, 0x84, 0xB0, 0x04, 0x46, 0x08, 0x31, ++ 0x0C, 0x48, 0x98, 0x47, 0x00, 0x21, 0x02, 0x22, 0x05, 0x23, 0x94, 0xF8, ++ 0x23, 0x00, 0xCD, 0xE9, 0x00, 0x32, 0xCD, 0xE9, 0x02, 0x11, 0x25, 0x23, ++ 0x40, 0xF6, 0xC4, 0x12, 0xFD, 0xF7, 0x5E, 0xFF, 0x04, 0xB0, 0x10, 0xBD, ++ 0x03, 0x4A, 0xC2, 0xE9, 0x01, 0x33, 0x70, 0x47, 0x00, 0x10, 0x50, 0x40, ++ 0x88, 0x1A, 0x17, 0x00, 0x94, 0x64, 0x17, 0x00, 0x03, 0x68, 0x70, 0xB4, ++ 0xC3, 0xF3, 0xC2, 0x24, 0x05, 0x2C, 0x01, 0xD0, 0x70, 0xBC, 0x70, 0x47, ++ 0xC3, 0xF3, 0x00, 0x26, 0x75, 0x00, 0x03, 0xF0, 0x7F, 0x04, 0x35, 0x44, ++ 0x04, 0xEB, 0x44, 0x04, 0x05, 0xEB, 0x44, 0x04, 0xC3, 0xF3, 0x41, 0x25, ++ 0x2C, 0x44, 0x16, 0x4D, 0x35, 0xF8, 0x14, 0x50, 0xC3, 0xF3, 0xC0, 0x14, ++ 0x05, 0xFA, 0x04, 0xF4, 0x01, 0x3A, 0x02, 0xFB, 0x04, 0xF2, 0x8A, 0x42, ++ 0xC3, 0xF3, 0xC1, 0x14, 0xE2, 0xD2, 0x13, 0xF4, 0xE0, 0x3F, 0x06, 0xD0, ++ 0x23, 0xF4, 0xE0, 0x33, 0x43, 0xF4, 0x00, 0x43, 0x70, 0xBC, 0x03, 0x60, ++ 0x70, 0x47, 0x03, 0xF0, 0x0F, 0x02, 0x02, 0x2A, 0x23, 0xF0, 0xFF, 0x53, ++ 0x8C, 0xBF, 0x4F, 0xF4, 0x80, 0x12, 0x4F, 0xF4, 0x00, 0x22, 0x23, 0xF4, ++ 0xFE, 0x13, 0x42, 0xEA, 0x04, 0x62, 0x13, 0x43, 0x43, 0xF0, 0x80, 0x63, ++ 0x43, 0xF4, 0x00, 0x43, 0xE8, 0xE7, 0x00, 0xBF, 0xE0, 0x94, 0x15, 0x00, ++ 0x70, 0xB5, 0x0C, 0x4D, 0x00, 0xEB, 0x40, 0x03, 0x05, 0xEB, 0x83, 0x03, ++ 0x93, 0xF8, 0x2E, 0x20, 0x72, 0xB1, 0x04, 0x46, 0x46, 0x00, 0x58, 0x6A, ++ 0x00, 0x22, 0x83, 0xF8, 0x2E, 0x20, 0x10, 0xB1, 0x21, 0x46, 0xFB, 0xF7, ++ 0x35, 0xFF, 0x34, 0x44, 0x05, 0xEB, 0x84, 0x05, 0x00, 0x23, 0x6B, 0x62, ++ 0x70, 0xBD, 0x00, 0xBF, 0x94, 0x64, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0x83, 0xB0, 0xEF, 0xF3, 0x10, 0x83, 0xDA, 0x07, 0x03, 0xD4, 0x72, 0xB6, ++ 0x41, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x41, 0x4F, 0x41, 0x4E, 0x3B, 0x68, ++ 0xDF, 0xF8, 0x0C, 0x81, 0x01, 0x33, 0x00, 0x24, 0x3B, 0x60, 0x35, 0x46, ++ 0xA2, 0x46, 0x4F, 0xF0, 0x01, 0x0B, 0x96, 0xF8, 0x60, 0x10, 0x0B, 0xFA, ++ 0x04, 0xF3, 0x0B, 0x42, 0x5F, 0xFA, 0x83, 0xF9, 0x4D, 0xD1, 0x96, 0xF8, ++ 0x61, 0x10, 0x11, 0xEA, 0x09, 0x0F, 0x30, 0xD0, 0xA8, 0x6A, 0x21, 0xEA, ++ 0x03, 0x03, 0x86, 0xF8, 0x61, 0x30, 0x03, 0x07, 0x4F, 0xD0, 0x33, 0x4B, ++ 0x43, 0xF8, 0x24, 0x00, 0xE0, 0xB2, 0xD8, 0xF8, 0xD0, 0x33, 0x98, 0x47, ++ 0x95, 0xF8, 0x2C, 0x30, 0x85, 0xF8, 0x2D, 0x30, 0x49, 0xEA, 0x0A, 0x0A, ++ 0x01, 0x34, 0x04, 0x2C, 0x05, 0xF1, 0x0C, 0x05, 0xD9, 0xD1, 0xBA, 0xF1, ++ 0x00, 0x0F, 0x47, 0xD0, 0x29, 0x4A, 0x2A, 0x4B, 0x11, 0x69, 0xD3, 0xF8, ++ 0xE0, 0x31, 0x29, 0x48, 0x01, 0xF5, 0x00, 0x51, 0x98, 0x47, 0x3B, 0x68, ++ 0x33, 0xB1, 0x20, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x3B, 0x60, 0x0B, 0xB9, ++ 0x02, 0xB1, 0x62, 0xB6, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x95, 0xF8, ++ 0x2D, 0x30, 0x00, 0x2B, 0xDE, 0xD0, 0x01, 0x3B, 0xDB, 0xB2, 0x85, 0xF8, ++ 0x2D, 0x30, 0x5B, 0xB9, 0x32, 0x69, 0xA3, 0x1C, 0xE0, 0xB2, 0x52, 0xF8, ++ 0x23, 0x30, 0x17, 0x4A, 0x42, 0xF8, 0x24, 0x30, 0xD8, 0xF8, 0xD0, 0x33, ++ 0x98, 0x47, 0xCD, 0xE7, 0x49, 0xEA, 0x0A, 0x0A, 0xCA, 0xE7, 0xE0, 0xB2, ++ 0x01, 0x93, 0xFF, 0xF7, 0xBD, 0xFE, 0x01, 0x9B, 0x00, 0x28, 0xF5, 0xD0, ++ 0x96, 0xF8, 0x60, 0x10, 0x21, 0xEA, 0x03, 0x01, 0x86, 0xF8, 0x60, 0x10, ++ 0xA3, 0xE7, 0x95, 0xF8, 0x2E, 0x30, 0x00, 0x2B, 0xB2, 0xD1, 0x85, 0xF8, ++ 0x2E, 0xB0, 0x96, 0xF8, 0x60, 0x30, 0x49, 0xEA, 0x03, 0x03, 0x86, 0xF8, ++ 0x60, 0x30, 0xA9, 0xE7, 0xC6, 0xF8, 0x18, 0xA0, 0xBD, 0xE7, 0x00, 0xBF, ++ 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0x94, 0x64, 0x17, 0x00, ++ 0x00, 0x02, 0x32, 0x40, 0x00, 0x10, 0x50, 0x40, 0x88, 0x1A, 0x17, 0x00, ++ 0xA8, 0x64, 0x17, 0x00, 0x70, 0xB5, 0x14, 0x4C, 0x94, 0xF8, 0x62, 0x20, ++ 0x4A, 0xB1, 0x94, 0xF8, 0x61, 0x20, 0xA5, 0x69, 0x01, 0x21, 0x01, 0xFA, ++ 0x00, 0xF3, 0x13, 0x43, 0x84, 0xF8, 0x61, 0x30, 0x05, 0xB1, 0x70, 0xBD, ++ 0x0D, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x07, 0xDB, ++ 0x0B, 0x4B, 0x0C, 0x48, 0xD3, 0xF8, 0xC8, 0x33, 0xA3, 0x61, 0xBD, 0xE8, ++ 0x70, 0x40, 0x18, 0x47, 0xFF, 0xF7, 0x74, 0xFE, 0x00, 0x28, 0xF3, 0xD1, ++ 0xBD, 0xE8, 0x70, 0x40, 0x06, 0x49, 0x07, 0x48, 0x4F, 0xF4, 0x22, 0x72, ++ 0x12, 0xF0, 0xF4, 0xB9, 0x94, 0x64, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0xA8, 0x64, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x90, 0x93, 0x15, 0x00, 0x2D, 0xE9, 0xF8, 0x43, 0x1D, 0x4D, 0x1E, 0x4E, ++ 0x1E, 0x4F, 0xDF, 0xF8, 0x80, 0x80, 0xDF, 0xF8, 0x80, 0x90, 0x2B, 0x68, ++ 0x00, 0x24, 0x01, 0x2C, 0x11, 0xD0, 0x53, 0xF8, 0x24, 0x30, 0x1B, 0xB9, ++ 0x33, 0x69, 0xA2, 0x1C, 0x53, 0xF8, 0x22, 0x30, 0x47, 0xF8, 0x24, 0x30, ++ 0xE0, 0xB2, 0xFF, 0xF7, 0xFB, 0xFE, 0x03, 0x2C, 0x0D, 0xD0, 0x01, 0x34, ++ 0x01, 0x2C, 0x2B, 0x68, 0xED, 0xD1, 0x5B, 0x68, 0x73, 0xB9, 0x33, 0x69, ++ 0xDB, 0x68, 0xC8, 0xF8, 0x00, 0x30, 0x01, 0x20, 0xFF, 0xF7, 0xEC, 0xFE, ++ 0xF1, 0xE7, 0x0D, 0x48, 0x08, 0xF0, 0x3C, 0xFC, 0x00, 0x23, 0xB3, 0x61, ++ 0xBD, 0xE8, 0xF8, 0x83, 0xC3, 0xF3, 0x0B, 0x02, 0x00, 0x2A, 0xEE, 0xD1, ++ 0x32, 0x69, 0xD2, 0x68, 0x03, 0xEA, 0x09, 0x03, 0xC2, 0xF3, 0x0B, 0x02, ++ 0x13, 0x43, 0xC8, 0xF8, 0x00, 0x30, 0xE6, 0xE7, 0xAC, 0x35, 0x17, 0x00, ++ 0x94, 0x64, 0x17, 0x00, 0x00, 0x02, 0x32, 0x40, 0xA8, 0x64, 0x17, 0x00, ++ 0x04, 0x02, 0x32, 0x40, 0x00, 0xF0, 0xFF, 0xFF, 0x1A, 0x4A, 0x1B, 0x4B, ++ 0xF0, 0xB4, 0x02, 0xF1, 0x74, 0x04, 0x94, 0xE8, 0x03, 0x00, 0x16, 0x69, ++ 0xC3, 0xF8, 0xE0, 0x03, 0xF0, 0x6D, 0xA3, 0xF8, 0xE4, 0x13, 0xB6, 0xF8, ++ 0x60, 0x10, 0xC3, 0xF8, 0xE6, 0x03, 0xA3, 0xF8, 0xEA, 0x13, 0x94, 0xE8, ++ 0x03, 0x00, 0xD3, 0xF8, 0xD4, 0x53, 0xA3, 0xF8, 0xF0, 0x13, 0xD1, 0x6E, ++ 0xC3, 0xF8, 0xEC, 0x03, 0xC3, 0xF8, 0xF6, 0x13, 0x0D, 0x4F, 0x0E, 0x48, ++ 0x03, 0xF5, 0x88, 0x64, 0x00, 0x21, 0x82, 0xF8, 0x88, 0x10, 0xC3, 0xF8, ++ 0xBC, 0x43, 0x05, 0xF4, 0x7F, 0x45, 0x03, 0xF5, 0x66, 0x74, 0x4F, 0xF4, ++ 0x00, 0x52, 0xC3, 0xF8, 0xD4, 0x53, 0xC3, 0xF8, 0x9C, 0x13, 0x3C, 0x60, ++ 0xF0, 0xBC, 0x02, 0x60, 0x70, 0x47, 0x00, 0xBF, 0x94, 0x64, 0x17, 0x00, ++ 0x60, 0x5D, 0x18, 0x00, 0xAC, 0x81, 0x32, 0x40, 0x80, 0x81, 0x32, 0x40, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0xDF, 0xF8, 0x68, 0xB2, 0x03, 0x68, 0x90, 0x4C, ++ 0xDB, 0xF8, 0x10, 0x20, 0x80, 0x46, 0x53, 0xF8, 0x26, 0x0F, 0xA0, 0x64, ++ 0xD0, 0x6D, 0x9D, 0x88, 0xC4, 0xF8, 0x4E, 0x00, 0x18, 0x68, 0xB8, 0xF8, ++ 0x12, 0x10, 0x9B, 0x88, 0xB2, 0xF8, 0x60, 0x20, 0x60, 0x65, 0x00, 0x27, ++ 0x83, 0xB0, 0x04, 0xF1, 0x5C, 0x00, 0xA4, 0xF8, 0x4C, 0x50, 0xA4, 0xF8, ++ 0x52, 0x20, 0xA4, 0xF8, 0x58, 0x30, 0xA7, 0x61, 0xFE, 0xF7, 0x78, 0xFC, ++ 0x63, 0x6F, 0xD8, 0xF8, 0x00, 0x10, 0x80, 0x4A, 0x91, 0xF8, 0x23, 0xC0, ++ 0xA5, 0x69, 0xDE, 0x1C, 0x42, 0xF2, 0x38, 0x0E, 0x26, 0xF0, 0x03, 0x06, ++ 0x24, 0x23, 0x39, 0x46, 0x04, 0x36, 0x13, 0xFB, 0x0C, 0xE7, 0x06, 0xEB, ++ 0x80, 0x06, 0x4F, 0xEA, 0x40, 0x2E, 0x17, 0x44, 0xB6, 0xB2, 0x89, 0x46, ++ 0x04, 0xF1, 0x5C, 0x02, 0xA4, 0x46, 0x4F, 0xF4, 0x20, 0x10, 0xF2, 0x46, ++ 0x01, 0x97, 0x1C, 0xE0, 0x0F, 0x33, 0x1B, 0x09, 0x1B, 0x02, 0x43, 0xF0, ++ 0x30, 0x03, 0x9B, 0xB2, 0x4A, 0xEA, 0x00, 0x00, 0x0B, 0x43, 0x90, 0x63, ++ 0xC2, 0xF8, 0x24, 0x90, 0xC2, 0xF8, 0x3C, 0x90, 0xA2, 0xF8, 0x58, 0x30, ++ 0xCC, 0xF8, 0x08, 0x20, 0xA5, 0x69, 0x35, 0x44, 0xA5, 0x61, 0x94, 0x46, ++ 0x4F, 0xF4, 0x40, 0x10, 0x01, 0x31, 0x09, 0x29, 0x02, 0xF1, 0x5C, 0x02, ++ 0x22, 0xD0, 0x01, 0x9F, 0x57, 0xF8, 0x04, 0x3B, 0x01, 0x97, 0x00, 0x2B, ++ 0xF4, 0xD0, 0xD8, 0xF8, 0x08, 0x70, 0x06, 0xEB, 0x05, 0x0E, 0xBE, 0x45, ++ 0x16, 0xD8, 0xB3, 0xF5, 0x7C, 0x7F, 0xD3, 0xD9, 0xB3, 0xF5, 0x80, 0x6F, ++ 0x0D, 0xD9, 0xB3, 0xF5, 0x86, 0x4F, 0x45, 0xD8, 0x6F, 0xF4, 0x7C, 0x75, ++ 0x2B, 0x44, 0xC3, 0xF3, 0x07, 0x13, 0x1B, 0x02, 0x43, 0xF4, 0x80, 0x43, ++ 0x43, 0xF0, 0x30, 0x03, 0xC8, 0xE7, 0x44, 0xF2, 0x30, 0x03, 0xC5, 0xE7, ++ 0x00, 0x2D, 0x3B, 0xD0, 0xDC, 0xF8, 0x38, 0x30, 0x03, 0xF4, 0x60, 0x11, ++ 0x00, 0x22, 0xB1, 0xF5, 0x20, 0x1F, 0xCC, 0xF8, 0x08, 0x20, 0x63, 0xD0, ++ 0x4C, 0x49, 0x4D, 0x4A, 0x4D, 0x4E, 0x43, 0xF4, 0x60, 0x13, 0xCC, 0xF8, ++ 0x38, 0x30, 0x0D, 0x68, 0x10, 0x68, 0x04, 0x35, 0xC0, 0xF3, 0x05, 0x20, ++ 0x06, 0xE0, 0x33, 0x68, 0xDB, 0x04, 0x08, 0xD4, 0x0B, 0x68, 0x5B, 0x1B, ++ 0x00, 0x2B, 0x04, 0xDA, 0x13, 0x68, 0x03, 0xF0, 0x3F, 0x03, 0x98, 0x42, ++ 0xF3, 0xD0, 0xE3, 0x6B, 0x42, 0x48, 0x43, 0x49, 0x43, 0x4A, 0x04, 0x60, ++ 0x03, 0xF4, 0x7F, 0x43, 0xE3, 0x63, 0x4F, 0xF4, 0x00, 0x50, 0x00, 0x23, ++ 0x08, 0x60, 0x63, 0x60, 0x8B, 0xF8, 0x88, 0x30, 0x62, 0x62, 0x03, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x8F, 0xB3, 0xF5, 0x88, 0x4F, 0x1F, 0xD8, 0x48, 0xF2, ++ 0x30, 0x03, 0x87, 0xE7, 0xD4, 0xF8, 0x98, 0x30, 0x37, 0x4A, 0x35, 0x4E, ++ 0x35, 0x49, 0xC4, 0xF8, 0x94, 0x50, 0x03, 0xF4, 0x7F, 0x43, 0xC4, 0xF8, ++ 0x98, 0x30, 0xA2, 0xF5, 0x79, 0x73, 0xC4, 0xE9, 0x18, 0x55, 0x8B, 0xF8, ++ 0x88, 0x50, 0x4F, 0xF4, 0x00, 0x50, 0x33, 0x60, 0x30, 0x23, 0x08, 0x60, ++ 0xA4, 0xF8, 0xB4, 0x30, 0xC4, 0xF8, 0x80, 0x20, 0x03, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x8F, 0xB3, 0xF5, 0x0F, 0x3F, 0x2A, 0xD9, 0xB3, 0xF5, 0x11, 0x3F, ++ 0x32, 0xD9, 0x28, 0x4D, 0xAB, 0x42, 0x32, 0xD8, 0xA3, 0xF1, 0x01, 0x13, ++ 0xA3, 0xF5, 0x44, 0x43, 0xC3, 0xF3, 0xC7, 0x33, 0x1B, 0x02, 0x43, 0xF4, ++ 0x40, 0x43, 0x43, 0xF0, 0x30, 0x03, 0x55, 0xE7, 0xDC, 0xF8, 0x3C, 0x30, ++ 0xCC, 0xF8, 0x38, 0x20, 0xCC, 0xF8, 0x04, 0x20, 0x8B, 0xF8, 0x88, 0x20, ++ 0x19, 0x48, 0x1A, 0x49, 0x1A, 0x4A, 0xCC, 0xF8, 0x24, 0x20, 0x03, 0xF4, ++ 0x7F, 0x43, 0xCC, 0xF8, 0x3C, 0x30, 0x4F, 0xF4, 0x00, 0x53, 0xC0, 0xF8, ++ 0x00, 0xC0, 0x0B, 0x60, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xA3, 0xF5, ++ 0x70, 0x53, 0x01, 0x3B, 0xC3, 0xF3, 0xC7, 0x23, 0x1B, 0x02, 0x43, 0xF4, ++ 0x00, 0x43, 0x43, 0xF0, 0x30, 0x03, 0x31, 0xE7, 0x4C, 0xF2, 0x30, 0x03, ++ 0x2E, 0xE7, 0x4F, 0xF6, 0x30, 0x65, 0x4F, 0xF6, 0x30, 0x77, 0xB3, 0xF1, ++ 0xFF, 0x3F, 0x08, 0xBF, 0x3D, 0x46, 0x2B, 0x46, 0x24, 0xE7, 0x00, 0xBF, ++ 0x60, 0x5D, 0x18, 0x00, 0x7C, 0x36, 0x17, 0x00, 0x20, 0x01, 0x32, 0x40, ++ 0x54, 0x83, 0x32, 0x40, 0x78, 0x80, 0x32, 0x40, 0xAC, 0x81, 0x32, 0x40, ++ 0x80, 0x81, 0x32, 0x40, 0xA0, 0x61, 0x18, 0x00, 0x00, 0xC4, 0x20, 0x00, ++ 0x94, 0x64, 0x17, 0x00, 0x1C, 0x4A, 0x1D, 0x49, 0x13, 0x68, 0xF0, 0xB4, ++ 0x03, 0xF5, 0xDA, 0x53, 0x1B, 0x4F, 0x1C, 0x4E, 0x1C, 0x4C, 0x1D, 0x4D, ++ 0x18, 0x33, 0x3B, 0x60, 0x40, 0x23, 0x33, 0x60, 0x23, 0x68, 0x43, 0xF0, ++ 0x40, 0x03, 0x23, 0x60, 0x17, 0x68, 0x0C, 0x68, 0x01, 0x23, 0x10, 0x3E, ++ 0x04, 0x37, 0xC4, 0xF3, 0x05, 0x24, 0x85, 0xF8, 0x8C, 0x30, 0x06, 0xE0, ++ 0x33, 0x68, 0xDB, 0x04, 0x08, 0xD4, 0x13, 0x68, 0xDB, 0x1B, 0x00, 0x2B, ++ 0x04, 0xDA, 0x0B, 0x68, 0x03, 0xF0, 0x3F, 0x03, 0x9C, 0x42, 0xF3, 0xD0, ++ 0xC3, 0x6B, 0x0E, 0x4C, 0x0E, 0x4A, 0x0F, 0x49, 0x42, 0x62, 0x03, 0xF4, ++ 0x7F, 0x43, 0xC3, 0x63, 0x00, 0x22, 0x4F, 0xF4, 0x00, 0x53, 0x42, 0x60, ++ 0x85, 0xF8, 0x88, 0x20, 0x20, 0x60, 0xF0, 0xBC, 0x0B, 0x60, 0x70, 0x47, ++ 0x20, 0x01, 0x32, 0x40, 0x54, 0x83, 0x32, 0x40, 0x40, 0x01, 0x32, 0x40, ++ 0x88, 0x80, 0x32, 0x40, 0x8C, 0x80, 0x32, 0x40, 0x94, 0x64, 0x17, 0x00, ++ 0xAC, 0x81, 0x32, 0x40, 0xA0, 0x61, 0x18, 0x00, 0x80, 0x81, 0x32, 0x40, ++ 0x2D, 0xE9, 0xF0, 0x41, 0x10, 0x4F, 0x0C, 0x23, 0x0E, 0x46, 0x54, 0x25, ++ 0x04, 0x46, 0x15, 0xFB, 0x01, 0x30, 0x05, 0xFB, 0x06, 0x75, 0x38, 0x44, ++ 0xD4, 0xF8, 0x4C, 0x80, 0x10, 0xF0, 0xEC, 0xFB, 0x95, 0xF8, 0x50, 0x30, ++ 0xA2, 0x88, 0x01, 0x3B, 0x85, 0xF8, 0x50, 0x30, 0x22, 0xB9, 0x20, 0x46, ++ 0xBD, 0xE8, 0xF0, 0x41, 0xFD, 0xF7, 0x22, 0xBA, 0xD8, 0xF8, 0x50, 0x10, ++ 0x32, 0x46, 0x20, 0x46, 0xBD, 0xE8, 0xF0, 0x41, 0xFC, 0xF7, 0xF6, 0xBB, ++ 0x20, 0x62, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x47, 0x00, 0x23, 0x2E, 0x4D, ++ 0x03, 0x60, 0x95, 0xF8, 0x8C, 0x30, 0x82, 0xB0, 0x00, 0x2B, 0x37, 0xD1, ++ 0x95, 0xF8, 0x85, 0x30, 0x03, 0x2B, 0x33, 0xD8, 0x29, 0x4E, 0xDF, 0xF8, ++ 0xB4, 0xA0, 0x81, 0x46, 0x4F, 0xF0, 0x03, 0x08, 0x14, 0xE0, 0x95, 0xF8, ++ 0x7E, 0x30, 0xDA, 0xF8, 0x64, 0x73, 0x00, 0x93, 0x2A, 0x6F, 0xB5, 0xF8, ++ 0x7A, 0x30, 0x49, 0x46, 0x20, 0x46, 0xB8, 0x47, 0x07, 0x46, 0x20, 0xBB, ++ 0x95, 0xF8, 0x85, 0x30, 0x08, 0xF1, 0xFF, 0x38, 0x98, 0x45, 0xA6, 0xF1, ++ 0x54, 0x06, 0x17, 0xDB, 0x96, 0xF8, 0x16, 0x31, 0x5F, 0xFA, 0x88, 0xF7, ++ 0x01, 0x2B, 0x85, 0xF8, 0x7E, 0x70, 0x0F, 0xD0, 0xD6, 0xF8, 0x08, 0x41, ++ 0x00, 0x2C, 0xEB, 0xD0, 0x63, 0x6A, 0x9B, 0x02, 0xDB, 0xD4, 0xE3, 0x6C, ++ 0x1B, 0x6D, 0x00, 0x2B, 0xD7, 0xDA, 0x20, 0x46, 0x39, 0x46, 0xFF, 0xF7, ++ 0x99, 0xFF, 0xEF, 0xE7, 0x00, 0x27, 0x38, 0x46, 0x02, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x87, 0x0E, 0x4B, 0x64, 0x6C, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0x07, 0xDB, 0xA3, 0x88, 0x38, 0x46, 0x43, 0xF4, 0x00, 0x73, ++ 0xA3, 0x80, 0x02, 0xB0, 0xBD, 0xE8, 0xF0, 0x87, 0x00, 0x2C, 0xF5, 0xD1, ++ 0x06, 0x49, 0x07, 0x48, 0x40, 0xF2, 0xDF, 0x42, 0x11, 0xF0, 0x88, 0xFF, ++ 0xEE, 0xE7, 0x00, 0xBF, 0x94, 0x64, 0x17, 0x00, 0x20, 0x62, 0x17, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x3C, 0x90, 0x15, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, 0xDF, 0xF8, 0x8C, 0x92, ++ 0x99, 0xF8, 0x7E, 0x80, 0x83, 0xB0, 0x04, 0x46, 0x00, 0x27, 0x40, 0x46, ++ 0x01, 0x97, 0xFB, 0xF7, 0x0D, 0xFE, 0x99, 0xF8, 0x7E, 0x00, 0xFF, 0xF7, ++ 0x15, 0xFA, 0x00, 0x2C, 0x00, 0xF0, 0xA4, 0x80, 0x63, 0x6A, 0x9E, 0x02, ++ 0x76, 0xD5, 0x03, 0xF4, 0x60, 0x10, 0xB0, 0xF5, 0x60, 0x1F, 0x65, 0x6C, ++ 0x00, 0xF0, 0xE1, 0x80, 0xB0, 0xF5, 0x40, 0x1F, 0x00, 0xF0, 0xCE, 0x80, ++ 0xAA, 0x88, 0x02, 0xF0, 0x03, 0x02, 0x03, 0x2A, 0x8E, 0x4A, 0x12, 0x68, ++ 0x92, 0xF8, 0x01, 0xC0, 0x00, 0xF0, 0xFF, 0x80, 0x2A, 0x6B, 0x52, 0x69, ++ 0x00, 0x21, 0xC2, 0xF3, 0xC1, 0x1E, 0xC5, 0xE9, 0x0E, 0x11, 0x69, 0x63, ++ 0x0E, 0x46, 0x0A, 0x46, 0x14, 0xE0, 0xD1, 0xF8, 0x4C, 0x31, 0x9A, 0x45, ++ 0x02, 0xF1, 0x01, 0x03, 0x22, 0xD9, 0xDA, 0xB2, 0x05, 0xEB, 0x82, 0x03, ++ 0xB0, 0xF5, 0x60, 0x1F, 0x4E, 0x63, 0x56, 0x46, 0xC3, 0xF8, 0x3C, 0x41, ++ 0x20, 0xD0, 0x24, 0x68, 0x34, 0xB3, 0x63, 0x6A, 0x03, 0xF4, 0x60, 0x10, ++ 0xE1, 0x6C, 0xD1, 0xF8, 0x2C, 0xA0, 0xC3, 0xF3, 0x49, 0x2B, 0x0A, 0xF1, ++ 0x03, 0x03, 0x23, 0xF0, 0x03, 0x03, 0x0B, 0xF1, 0x01, 0x0A, 0x03, 0xEB, ++ 0x8A, 0x03, 0x9B, 0xB2, 0x96, 0x45, 0x05, 0xEB, 0x82, 0x01, 0x03, 0xEB, ++ 0x06, 0x0A, 0xD6, 0xD8, 0x05, 0xEB, 0x82, 0x03, 0xB0, 0xF5, 0x60, 0x1F, ++ 0x56, 0x46, 0xC3, 0xF8, 0x3C, 0x41, 0xDE, 0xD1, 0x6B, 0x6A, 0xB3, 0x42, ++ 0x00, 0xF0, 0xCE, 0x80, 0x00, 0x23, 0xC5, 0xE9, 0x0D, 0x33, 0xEB, 0x63, ++ 0x00, 0x2F, 0x49, 0xD0, 0x08, 0xEB, 0x48, 0x03, 0x09, 0xEB, 0x83, 0x09, ++ 0x01, 0x9A, 0xC9, 0xF8, 0x24, 0x70, 0xBC, 0xF1, 0x00, 0x0F, 0x30, 0xD1, ++ 0x93, 0x6B, 0x9B, 0x02, 0x00, 0xF1, 0x97, 0x80, 0x53, 0x68, 0x00, 0x2B, ++ 0x4B, 0xD1, 0x61, 0x49, 0x54, 0x23, 0x03, 0xFB, 0x08, 0xF8, 0x01, 0xEB, ++ 0x08, 0x03, 0xC3, 0xE9, 0x01, 0xCC, 0x41, 0xF8, 0x08, 0x20, 0x40, 0xE0, ++ 0xA3, 0x6C, 0x3B, 0xB3, 0xE3, 0x8B, 0xE2, 0x6C, 0x13, 0xF4, 0x00, 0x5F, ++ 0xE3, 0x6A, 0xDB, 0x6B, 0x02, 0xF1, 0x14, 0x07, 0x14, 0xBF, 0xC3, 0xF3, ++ 0x00, 0x13, 0xC3, 0xF3, 0xC0, 0x03, 0x01, 0x97, 0x93, 0xB3, 0x52, 0x4B, ++ 0x1B, 0x68, 0x93, 0xF8, 0x01, 0xC0, 0x3A, 0x46, 0x08, 0xEB, 0x48, 0x03, ++ 0x09, 0xEB, 0x83, 0x09, 0xC9, 0xF8, 0x24, 0x70, 0xBC, 0xF1, 0x00, 0x0F, ++ 0xCE, 0xD0, 0x53, 0x68, 0xFB, 0xB9, 0x54, 0x23, 0x03, 0xFB, 0x08, 0xF8, ++ 0x49, 0x4B, 0x43, 0xF8, 0x08, 0x20, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, ++ 0x45, 0x4B, 0x1B, 0x68, 0x93, 0xF8, 0x01, 0xC0, 0x44, 0x4B, 0x54, 0x22, ++ 0x08, 0xEB, 0x48, 0x01, 0x09, 0xEB, 0x81, 0x09, 0x02, 0xFB, 0x08, 0xF8, ++ 0x00, 0x22, 0x43, 0xF8, 0x08, 0x20, 0xC9, 0xF8, 0x24, 0x20, 0x43, 0x44, ++ 0xBC, 0xF1, 0x00, 0x0F, 0x01, 0xD1, 0xC3, 0xE9, 0x01, 0xCC, 0x03, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x8F, 0x50, 0x6A, 0x03, 0x88, 0x1D, 0x04, 0x99, 0xB2, ++ 0xC7, 0xD5, 0xC1, 0xF3, 0x0E, 0x01, 0x01, 0x80, 0x94, 0xF8, 0x33, 0x10, ++ 0x94, 0xF8, 0x32, 0x30, 0x32, 0x48, 0x04, 0x39, 0x04, 0x3B, 0x84, 0xF8, ++ 0x33, 0x10, 0x84, 0xF8, 0x32, 0x30, 0xD2, 0xE9, 0x0A, 0x31, 0x04, 0x39, ++ 0x04, 0x3B, 0xC2, 0xE9, 0x0A, 0x31, 0x00, 0x68, 0x3A, 0x46, 0x90, 0xF8, ++ 0x01, 0xC0, 0xB3, 0xE7, 0x2B, 0x4B, 0x01, 0xA9, 0xD3, 0xF8, 0x6C, 0x33, ++ 0x20, 0x46, 0x98, 0x47, 0x26, 0x4A, 0x63, 0x6A, 0x12, 0x68, 0x07, 0x46, ++ 0x92, 0xF8, 0x01, 0xC0, 0x03, 0xF4, 0x60, 0x10, 0x2C, 0xE7, 0x24, 0x4B, ++ 0x21, 0x4E, 0xD3, 0xF8, 0x58, 0x33, 0x39, 0x46, 0x20, 0x46, 0x98, 0x47, ++ 0x33, 0x68, 0x01, 0x90, 0x5B, 0x78, 0x07, 0x46, 0xD3, 0xB1, 0x08, 0xB1, ++ 0x6B, 0x6D, 0x43, 0x60, 0xD5, 0xF8, 0x48, 0x01, 0x29, 0x46, 0x10, 0xF0, ++ 0x13, 0xFA, 0x33, 0x68, 0x93, 0xF8, 0x01, 0xC0, 0x58, 0xE7, 0x7B, 0x68, ++ 0x00, 0x2B, 0xB4, 0xD1, 0x15, 0x49, 0x54, 0x23, 0x03, 0xFB, 0x08, 0xF8, ++ 0x01, 0xEB, 0x08, 0x03, 0x01, 0x20, 0xC3, 0xE9, 0x01, 0x70, 0x41, 0xF8, ++ 0x08, 0x20, 0xA8, 0xE7, 0x00, 0x28, 0xE5, 0xD0, 0x2B, 0x69, 0x43, 0x60, ++ 0xE2, 0xE7, 0x05, 0xF1, 0x0C, 0x07, 0xBC, 0xF1, 0x00, 0x0F, 0x03, 0xD0, ++ 0x05, 0xF1, 0x50, 0x02, 0x01, 0x92, 0xF7, 0xE6, 0xD5, 0xF8, 0x38, 0x21, ++ 0xD2, 0x6C, 0x14, 0x32, 0x01, 0x92, 0xF1, 0xE6, 0xD5, 0xF8, 0x38, 0x31, ++ 0xA3, 0x42, 0x7F, 0xF4, 0x2D, 0xAF, 0x05, 0xEB, 0x82, 0x02, 0x56, 0x63, ++ 0x2C, 0xE7, 0x00, 0xBF, 0x34, 0x36, 0x17, 0x00, 0x20, 0x62, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x94, 0x64, 0x17, 0x00, 0x70, 0xB5, 0x1E, 0x48, ++ 0x82, 0xB0, 0x90, 0xF8, 0x88, 0x30, 0x00, 0x22, 0x01, 0x92, 0x93, 0xB1, ++ 0x90, 0xF8, 0x7F, 0x30, 0x04, 0x2B, 0x2A, 0xD0, 0x19, 0x4C, 0x01, 0xA8, ++ 0xD4, 0xF8, 0xE8, 0x33, 0x98, 0x47, 0x08, 0xB3, 0xD4, 0xF8, 0xF8, 0x33, ++ 0x98, 0x47, 0xD4, 0xF8, 0xD4, 0x33, 0x01, 0x98, 0x98, 0x47, 0x02, 0xB0, ++ 0x70, 0xBD, 0x13, 0x4A, 0x13, 0x4D, 0xD2, 0xF8, 0x38, 0x14, 0x13, 0x4C, ++ 0x80, 0xF8, 0x88, 0x30, 0xC2, 0xF8, 0x00, 0x34, 0x01, 0xF4, 0x7F, 0x41, ++ 0x02, 0xF5, 0x88, 0x66, 0x02, 0xF5, 0x7F, 0x70, 0x4F, 0xF4, 0x00, 0x53, ++ 0xC2, 0xF8, 0x38, 0x14, 0xC2, 0xF8, 0x20, 0x64, 0x28, 0x60, 0x23, 0x60, ++ 0x02, 0xB0, 0x70, 0xBD, 0xFF, 0xF7, 0x28, 0xFC, 0xE1, 0xE7, 0x04, 0x4B, ++ 0x68, 0x30, 0xD3, 0xF8, 0xF4, 0x33, 0x98, 0x47, 0x02, 0xB0, 0x70, 0xBD, ++ 0x94, 0x64, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x60, 0x5D, 0x18, 0x00, ++ 0xAC, 0x81, 0x32, 0x40, 0x80, 0x81, 0x32, 0x40, 0xF8, 0xB5, 0x2C, 0x4C, ++ 0x2C, 0x4D, 0x40, 0xF2, 0x74, 0x42, 0x20, 0x46, 0x00, 0x21, 0x26, 0x46, ++ 0xED, 0xF7, 0xF4, 0xF8, 0x4F, 0xF4, 0xE4, 0x73, 0x28, 0x4A, 0x26, 0xF8, ++ 0x44, 0x3F, 0x4F, 0xF6, 0x30, 0x70, 0x48, 0xF2, 0xC8, 0x13, 0x04, 0xF5, ++ 0x77, 0x77, 0x4F, 0xF0, 0x22, 0x0C, 0x04, 0xF2, 0xFD, 0x31, 0xC4, 0xF8, ++ 0x40, 0x24, 0xA4, 0xF8, 0xDC, 0x33, 0xA4, 0xF8, 0xF4, 0x03, 0x04, 0xF5, ++ 0x88, 0x63, 0x00, 0x20, 0x4F, 0xF4, 0x00, 0x12, 0xDF, 0xF8, 0x74, 0xE0, ++ 0xC4, 0xF8, 0xB0, 0xC3, 0xC4, 0xE9, 0xEA, 0x71, 0xC4, 0xF8, 0xBC, 0x33, ++ 0xC4, 0xF8, 0x20, 0x34, 0x63, 0x62, 0xA2, 0x63, 0xC4, 0xF8, 0x98, 0x53, ++ 0xC4, 0xF8, 0xFC, 0x53, 0x25, 0x60, 0xC4, 0xF8, 0xA4, 0x03, 0xC4, 0xF8, ++ 0xCC, 0x03, 0xC4, 0xF8, 0x30, 0x04, 0x04, 0xF1, 0x5B, 0x0C, 0x04, 0xF1, ++ 0xB4, 0x03, 0x1E, 0x27, 0x04, 0xF5, 0x7C, 0x74, 0xA3, 0xF1, 0x14, 0x01, ++ 0x5A, 0x1C, 0x43, 0xF8, 0x58, 0x5C, 0x43, 0xF8, 0x40, 0x7C, 0x43, 0xF8, ++ 0x24, 0x0C, 0x43, 0xF8, 0x14, 0xEC, 0x43, 0xF8, 0x4C, 0x1C, 0x43, 0xF8, ++ 0x08, 0x2C, 0x43, 0xE9, 0x12, 0x6C, 0x43, 0xF8, 0x0C, 0x3C, 0x5C, 0x33, ++ 0x9C, 0x42, 0xE9, 0xD1, 0xF8, 0xBD, 0x00, 0xBF, 0x60, 0x5D, 0x18, 0x00, ++ 0xBE, 0xBA, 0xFE, 0xCA, 0x1E, 0xAB, 0xDC, 0xBA, 0xDE, 0xFA, 0xFE, 0xCA, ++ 0x2D, 0xE9, 0xF0, 0x41, 0x13, 0x4A, 0x14, 0x4B, 0x92, 0xF8, 0x7E, 0x40, ++ 0xD3, 0xF8, 0xAC, 0x33, 0x12, 0x4F, 0x00, 0x22, 0x0E, 0x46, 0x21, 0x46, ++ 0x05, 0x46, 0x4F, 0xF0, 0x54, 0x08, 0x98, 0x47, 0x0C, 0x20, 0x18, 0xFB, ++ 0x04, 0x00, 0x38, 0x44, 0x10, 0xF0, 0x5E, 0xF9, 0x22, 0x46, 0x31, 0x46, ++ 0x28, 0x46, 0xFC, 0xF7, 0x77, 0xF9, 0x6B, 0x6A, 0x03, 0xF4, 0x60, 0x13, ++ 0xB3, 0xF5, 0x60, 0x1F, 0x05, 0xD1, 0x08, 0xFB, 0x04, 0x74, 0x6B, 0x6C, ++ 0x63, 0x62, 0x02, 0x23, 0xA3, 0x76, 0xBD, 0xE8, 0xF0, 0x81, 0x00, 0xBF, ++ 0x94, 0x64, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x20, 0x62, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0x90, 0xF8, 0x62, 0x40, 0x87, 0xB0, 0x84, 0xB9, ++ 0x90, 0xF8, 0x64, 0x30, 0x6B, 0xB1, 0x90, 0xF8, 0x6C, 0x30, 0x58, 0x4A, ++ 0x01, 0x93, 0x4F, 0xF4, 0x1E, 0x75, 0x05, 0xFB, 0x03, 0x25, 0x95, 0xF8, ++ 0x25, 0x30, 0x13, 0xB1, 0x6B, 0x68, 0x9B, 0x06, 0x02, 0xD4, 0x07, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x8F, 0x10, 0x22, 0x21, 0x46, 0x02, 0xA8, 0xED, 0xF7, ++ 0x4D, 0xF8, 0x95, 0xF8, 0x23, 0x30, 0x4E, 0x4A, 0x4E, 0x49, 0x00, 0x94, ++ 0x42, 0xF2, 0x34, 0x06, 0x03, 0xEB, 0xC3, 0x03, 0x06, 0xEB, 0x83, 0x03, ++ 0x9E, 0x18, 0x01, 0xF1, 0x08, 0x0B, 0xA6, 0x46, 0x22, 0x46, 0xA2, 0x46, ++ 0x20, 0x46, 0x56, 0xF8, 0x04, 0x3F, 0xB3, 0xF5, 0xFE, 0x0F, 0x1F, 0x46, ++ 0x04, 0xF1, 0x01, 0x08, 0x28, 0xBF, 0x4F, 0xF4, 0xFE, 0x07, 0xF3, 0xB1, ++ 0x42, 0x4C, 0x0B, 0x78, 0xE3, 0x5C, 0x06, 0xAC, 0x04, 0xEB, 0x83, 0x0C, ++ 0x22, 0xFA, 0x03, 0xF9, 0x5C, 0xF8, 0x10, 0x5C, 0x3D, 0x44, 0x55, 0x45, ++ 0x84, 0xBF, 0xAA, 0x46, 0x00, 0x93, 0x19, 0xF0, 0x01, 0x0F, 0x5F, 0xFA, ++ 0x88, 0xF4, 0x38, 0x44, 0x4C, 0xF8, 0x10, 0x5C, 0x07, 0xD1, 0x01, 0x25, ++ 0x05, 0xFA, 0x03, 0xF3, 0x1A, 0x43, 0xAE, 0x44, 0xD2, 0xB2, 0x5F, 0xFA, ++ 0x8E, 0xFE, 0x01, 0x31, 0x8B, 0x45, 0xD2, 0xD1, 0x08, 0x2C, 0x41, 0xD0, ++ 0xA4, 0xEB, 0x0E, 0x04, 0xE4, 0xB2, 0xA4, 0x02, 0x92, 0x01, 0xB0, 0xF5, ++ 0x7D, 0x6F, 0x1E, 0xD8, 0x0F, 0x30, 0x0A, 0xF1, 0x0F, 0x0A, 0xC0, 0xF3, ++ 0x07, 0x13, 0xCA, 0xF3, 0x07, 0x1A, 0x00, 0x21, 0x00, 0x98, 0x1B, 0x06, ++ 0x43, 0xEA, 0x00, 0x33, 0x13, 0x43, 0x23, 0x43, 0x0B, 0x43, 0x01, 0x99, ++ 0x08, 0x46, 0x21, 0x49, 0x4F, 0xF4, 0x1E, 0x72, 0x43, 0xEA, 0x0A, 0x43, ++ 0x02, 0xFB, 0x00, 0x12, 0x43, 0xF0, 0x0F, 0x03, 0xC2, 0xF8, 0x04, 0x32, ++ 0x07, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xB0, 0xF5, 0x7D, 0x4F, 0x0D, 0xD9, ++ 0xB0, 0xF5, 0xFD, 0x2F, 0x18, 0xD8, 0x00, 0xF2, 0xFF, 0x70, 0x0A, 0xF2, ++ 0xFF, 0x7A, 0xC0, 0xF3, 0xC7, 0x23, 0xCA, 0xF3, 0xC7, 0x2A, 0x4F, 0xF4, ++ 0x00, 0x41, 0xD7, 0xE7, 0xFF, 0x30, 0x0A, 0xF1, 0xFF, 0x0A, 0xC0, 0xF3, ++ 0x07, 0x23, 0xCA, 0xF3, 0x07, 0x2A, 0x4F, 0xF4, 0x80, 0x41, 0xCD, 0xE7, ++ 0x4F, 0xF4, 0x40, 0x64, 0x00, 0x22, 0xBE, 0xE7, 0x47, 0xF6, 0xFF, 0x73, ++ 0xBA, 0xF5, 0xFE, 0x0F, 0x94, 0xBF, 0x9A, 0x44, 0x03, 0xF5, 0xFE, 0x0A, ++ 0xB0, 0xF5, 0xFE, 0x0F, 0x94, 0xBF, 0x18, 0x18, 0x03, 0xF5, 0xFE, 0x00, ++ 0xC0, 0xF3, 0xC7, 0x33, 0xCA, 0xF3, 0xC7, 0x3A, 0x4F, 0xF4, 0x40, 0x41, ++ 0xB4, 0xE7, 0x00, 0xBF, 0x68, 0x65, 0x17, 0x00, 0x7C, 0x36, 0x17, 0x00, ++ 0xC0, 0xB2, 0x15, 0x00, 0xA0, 0xB2, 0x15, 0x00, 0x49, 0x4B, 0x4A, 0x4A, ++ 0x4F, 0xF4, 0x80, 0x11, 0x2D, 0xE9, 0xF0, 0x47, 0x19, 0x60, 0x13, 0x68, ++ 0x13, 0xF4, 0x40, 0x1F, 0xFB, 0xD1, 0xDF, 0xF8, 0x34, 0x81, 0x45, 0x4A, ++ 0x98, 0xF8, 0x8C, 0x30, 0x4F, 0xF4, 0x80, 0x11, 0x11, 0x60, 0x00, 0x2B, ++ 0x6E, 0xD0, 0x98, 0xF8, 0x7E, 0x60, 0xDF, 0xF8, 0x20, 0x91, 0x54, 0x23, ++ 0x03, 0xFB, 0x06, 0x93, 0x9A, 0x7E, 0x00, 0x2A, 0x38, 0xD0, 0x54, 0x20, ++ 0x00, 0xFB, 0x06, 0x94, 0x20, 0x46, 0x62, 0x6A, 0x93, 0x88, 0x43, 0xF0, ++ 0x10, 0x03, 0x93, 0x80, 0x1C, 0x30, 0x10, 0xF0, 0x55, 0xF8, 0x37, 0x4B, ++ 0x53, 0xF8, 0x26, 0x00, 0x0F, 0xF0, 0x6A, 0xFF, 0x00, 0x23, 0xA3, 0x76, ++ 0x63, 0x62, 0x06, 0xEB, 0x46, 0x04, 0x08, 0xEB, 0x84, 0x04, 0x94, 0xF8, ++ 0x2E, 0x50, 0x2D, 0xB9, 0x60, 0x6A, 0x18, 0xB1, 0x31, 0x46, 0xFB, 0xF7, ++ 0x93, 0xF8, 0x65, 0x62, 0x2D, 0x4A, 0x2E, 0x49, 0x13, 0x68, 0x23, 0xF0, ++ 0x40, 0x03, 0x13, 0x60, 0x54, 0x23, 0x03, 0xFB, 0x06, 0x99, 0x40, 0x22, ++ 0x0A, 0x60, 0x99, 0xF8, 0x50, 0x30, 0x00, 0x22, 0x01, 0x3B, 0x30, 0x46, ++ 0x89, 0xF8, 0x50, 0x30, 0x88, 0xF8, 0x8C, 0x20, 0xBD, 0xE8, 0xF0, 0x47, ++ 0xFE, 0xF7, 0x66, 0xBE, 0xDC, 0x68, 0x62, 0x6A, 0x92, 0x02, 0x2D, 0xD4, ++ 0x54, 0x25, 0xDF, 0xF8, 0x98, 0xA0, 0x20, 0x4F, 0x05, 0xFB, 0x06, 0x95, ++ 0x11, 0xE0, 0xE3, 0x6C, 0x62, 0x6A, 0x19, 0x6D, 0x41, 0xF0, 0x00, 0x41, ++ 0x41, 0xF4, 0x80, 0x01, 0x19, 0x65, 0x93, 0x02, 0x20, 0x46, 0x17, 0xD5, ++ 0xD7, 0xF8, 0xD8, 0x33, 0x98, 0x47, 0xAB, 0x7E, 0xEC, 0x68, 0x00, 0x2B, ++ 0xA9, 0xD1, 0xDA, 0xF8, 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0xE7, 0xDA, 0x00, 0x2C, 0xE5, 0xD1, 0x12, 0x49, 0x12, 0x48, 0x40, 0xF2, ++ 0xB3, 0x72, 0x11, 0xF0, 0x0D, 0xFC, 0xDE, 0xE7, 0xBD, 0xE8, 0xF0, 0x87, ++ 0xD7, 0xF8, 0xE4, 0x33, 0x98, 0x47, 0xA8, 0xE7, 0x5A, 0x69, 0x61, 0x6C, ++ 0x52, 0x6C, 0x8A, 0x42, 0xCC, 0xD1, 0xD2, 0xF8, 0x38, 0x21, 0x12, 0x68, ++ 0x5A, 0x61, 0xC7, 0xE7, 0x80, 0x81, 0x32, 0x40, 0x88, 0x81, 0x32, 0x40, ++ 0x84, 0x81, 0x32, 0x40, 0xC4, 0x90, 0x15, 0x00, 0x8C, 0x80, 0x32, 0x40, ++ 0x88, 0x80, 0x32, 0x40, 0x88, 0x1A, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x3C, 0x91, 0x15, 0x00, 0x94, 0x64, 0x17, 0x00, 0x20, 0x62, 0x17, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x47, 0x69, 0x4F, 0xDF, 0xF8, ++ 0xCC, 0x81, 0x97, 0xF8, 0x7E, 0x60, 0x54, 0x25, 0x05, 0xFB, 0x06, 0x85, ++ 0xAB, 0x7E, 0x53, 0xBB, 0xDF, 0xF8, 0xA0, 0xA1, 0xDF, 0xF8, 0xAC, 0x91, ++ 0x15, 0xE0, 0xD4, 0xF8, 0x4C, 0xC0, 0xDF, 0xF8, 0xA0, 0xE1, 0xDC, 0xF8, ++ 0x50, 0x30, 0x43, 0xF4, 0x80, 0x02, 0x00, 0x2B, 0x20, 0x46, 0x11, 0x46, ++ 0x26, 0xDA, 0x63, 0x6A, 0xCC, 0xF8, 0x50, 0x20, 0x9C, 0x02, 0x23, 0xD5, ++ 0xDE, 0xF8, 0xD8, 0x33, 0x98, 0x47, 0xAB, 0x7E, 0x7B, 0xB9, 0xDA, 0xF8, ++ 0x00, 0x30, 0xEC, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xE2, 0xDA, ++ 0x00, 0x2C, 0xE0, 0xD1, 0x53, 0x48, 0x4F, 0xF4, 0x02, 0x62, 0x49, 0x46, ++ 0x11, 0xF0, 0xAE, 0xFB, 0xD9, 0xE7, 0x54, 0x22, 0x02, 0xFB, 0x06, 0x82, ++ 0x02, 0x2B, 0x54, 0x6A, 0x0C, 0xBF, 0x04, 0xF1, 0x0C, 0x03, 0x04, 0xF1, ++ 0x50, 0x03, 0xDB, 0x6B, 0x00, 0x2B, 0x29, 0xDB, 0xBD, 0xE8, 0xF0, 0x87, ++ 0xDE, 0xF8, 0xE4, 0x33, 0x98, 0x47, 0x06, 0xEB, 0x46, 0x04, 0x07, 0xEB, ++ 0x84, 0x04, 0x94, 0xF8, 0x2E, 0x50, 0x2D, 0xB9, 0x60, 0x6A, 0x18, 0xB1, ++ 0x31, 0x46, 0xFA, 0xF7, 0xD1, 0xFF, 0x65, 0x62, 0x41, 0x4A, 0x42, 0x49, ++ 0x13, 0x68, 0x23, 0xF0, 0x40, 0x03, 0x13, 0x60, 0x54, 0x23, 0x03, 0xFB, ++ 0x06, 0x88, 0x40, 0x22, 0x0A, 0x60, 0x98, 0xF8, 0x50, 0x30, 0x00, 0x22, ++ 0x01, 0x3B, 0x30, 0x46, 0x88, 0xF8, 0x50, 0x30, 0x87, 0xF8, 0x8C, 0x20, ++ 0xBD, 0xE8, 0xF0, 0x47, 0xFE, 0xF7, 0xA4, 0xBD, 0x18, 0x02, 0x35, 0xD5, ++ 0xA3, 0x88, 0x99, 0x06, 0x13, 0xD4, 0xDF, 0xF8, 0xE0, 0x90, 0xD9, 0xF8, ++ 0x9C, 0x32, 0x98, 0x47, 0x04, 0x25, 0xA3, 0x88, 0x9A, 0x06, 0x0A, 0xD4, ++ 0xD9, 0xF8, 0x9C, 0x32, 0x98, 0x47, 0x01, 0x3D, 0xF7, 0xD1, 0x2E, 0x4B, ++ 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x42, 0xDB, 0x97, 0xF8, ++ 0x87, 0x30, 0x00, 0x2B, 0x37, 0xD0, 0x2A, 0x49, 0x97, 0xF8, 0x64, 0x30, ++ 0x0A, 0x68, 0x1B, 0x06, 0x22, 0xF0, 0xE0, 0x62, 0x03, 0xF0, 0xE0, 0x63, ++ 0x13, 0x43, 0x0B, 0x60, 0xA3, 0x88, 0x25, 0x4A, 0x43, 0xF0, 0x10, 0x03, ++ 0x52, 0xF8, 0x26, 0x00, 0xA3, 0x80, 0x0F, 0xF0, 0x4F, 0xFE, 0x54, 0x23, ++ 0x03, 0xFB, 0x06, 0x83, 0x00, 0x22, 0x9A, 0x76, 0x5A, 0x62, 0xA2, 0xE7, ++ 0x54, 0x20, 0x00, 0xFB, 0x06, 0x80, 0x1C, 0x30, 0x0F, 0xF0, 0x28, 0xFF, ++ 0x97, 0xF8, 0x87, 0x30, 0x00, 0x2B, 0xE5, 0xD0, 0x17, 0x4A, 0x97, 0xF8, ++ 0x65, 0x00, 0x13, 0x68, 0x11, 0x68, 0xC3, 0xF3, 0x02, 0x63, 0x01, 0x33, ++ 0x83, 0x42, 0x28, 0xBF, 0x03, 0x46, 0x1B, 0x06, 0x03, 0xF0, 0xE0, 0x63, ++ 0x21, 0xF0, 0xE0, 0x61, 0x0B, 0x43, 0x13, 0x60, 0xD2, 0xE7, 0x10, 0x4B, ++ 0x97, 0xF8, 0x7E, 0x00, 0xD3, 0xF8, 0xC0, 0x33, 0x98, 0x47, 0xCB, 0xE7, ++ 0xA3, 0x88, 0x9B, 0x06, 0xB9, 0xD4, 0xBD, 0xE8, 0xF0, 0x47, 0x0B, 0x49, ++ 0x0B, 0x48, 0x40, 0xF6, 0x6A, 0x02, 0x11, 0xF0, 0xDD, 0xBA, 0x00, 0xBF, ++ 0x94, 0x64, 0x17, 0x00, 0x3C, 0x91, 0x15, 0x00, 0x8C, 0x80, 0x32, 0x40, ++ 0x88, 0x80, 0x32, 0x40, 0x38, 0x36, 0x17, 0x00, 0x54, 0x83, 0x32, 0x40, ++ 0xC4, 0x90, 0x15, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0xD4, 0x8E, 0x15, 0x00, 0x20, 0x62, 0x17, 0x00, 0x10, 0xB5, 0x0D, 0x4C, ++ 0x90, 0x22, 0x00, 0x21, 0x20, 0x46, 0xEC, 0xF7, 0x09, 0xFE, 0xFF, 0xF7, ++ 0x09, 0xFD, 0x40, 0xF2, 0xD3, 0x13, 0xE3, 0x66, 0xED, 0xF7, 0xA4, 0xFE, ++ 0x07, 0x4A, 0x13, 0x68, 0x23, 0xF0, 0x70, 0x43, 0x18, 0xB1, 0x43, 0xF0, ++ 0x30, 0x43, 0x13, 0x60, 0x10, 0xBD, 0x43, 0xF0, 0x10, 0x43, 0x13, 0x60, ++ 0x10, 0xBD, 0x00, 0xBF, 0x94, 0x64, 0x17, 0x00, 0x54, 0x83, 0x32, 0x40, ++ 0x2D, 0xE9, 0xF0, 0x43, 0x2A, 0x4C, 0x65, 0x68, 0x95, 0xB0, 0x00, 0x2D, ++ 0x44, 0xD0, 0x29, 0x4E, 0xA7, 0x68, 0xD6, 0xF8, 0xD8, 0x31, 0x20, 0x46, ++ 0x98, 0x47, 0xD4, 0xF8, 0x10, 0x80, 0xB8, 0xF1, 0x00, 0x0F, 0x26, 0xD0, ++ 0x01, 0x25, 0x24, 0x49, 0x68, 0x46, 0x50, 0x22, 0x23, 0xF0, 0x66, 0xFD, ++ 0xA3, 0x69, 0x94, 0xF8, 0x62, 0x90, 0x23, 0xB1, 0x1E, 0x4E, 0x1F, 0x48, ++ 0xD6, 0xF8, 0xD8, 0x31, 0x98, 0x47, 0xFF, 0xF7, 0xBD, 0xFF, 0xC4, 0xF8, ++ 0x10, 0x80, 0x84, 0xF8, 0x62, 0x90, 0x18, 0x4C, 0x6B, 0x46, 0x22, 0x46, ++ 0x0C, 0xAE, 0x58, 0x69, 0x19, 0x7E, 0x90, 0x62, 0x0C, 0x33, 0xB3, 0x42, ++ 0x82, 0xF8, 0x2C, 0x10, 0x02, 0xF1, 0x0C, 0x02, 0xF5, 0xD1, 0xFD, 0xB9, ++ 0x15, 0xB0, 0xBD, 0xE8, 0xF0, 0x83, 0xFF, 0xF7, 0xA5, 0xFF, 0xC4, 0xF8, ++ 0x10, 0x80, 0x10, 0x4B, 0x10, 0x4A, 0x19, 0x69, 0x0B, 0x48, 0xD6, 0xF8, ++ 0xE0, 0x31, 0xA7, 0x60, 0x01, 0xF5, 0x9C, 0x51, 0x08, 0x31, 0x62, 0x60, ++ 0x15, 0xB0, 0xBD, 0xE8, 0xF0, 0x43, 0x18, 0x47, 0xD4, 0xF8, 0x10, 0x80, ++ 0xB8, 0xF1, 0x00, 0x0F, 0xC1, 0xD1, 0xFF, 0xF7, 0x8D, 0xFF, 0xC4, 0xF8, ++ 0x10, 0x80, 0xDF, 0xE7, 0x01, 0x4E, 0xE4, 0xE7, 0x94, 0x64, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0xA8, 0x64, 0x17, 0x00, 0x00, 0x10, 0x50, 0x40, ++ 0x95, 0x24, 0x13, 0x00, 0x2D, 0xE9, 0xF8, 0x43, 0x42, 0x6D, 0xC3, 0x69, ++ 0x91, 0xF8, 0x09, 0xC0, 0x9D, 0x68, 0x03, 0x8E, 0x88, 0x46, 0x91, 0x05, ++ 0x02, 0xD5, 0x12, 0xF4, 0x80, 0x60, 0x3B, 0xD0, 0x12, 0x3B, 0x01, 0x2B, ++ 0x05, 0xF1, 0x12, 0x05, 0x3A, 0xDD, 0x28, 0x4A, 0xDF, 0xF8, 0xA0, 0x90, ++ 0x4F, 0xF4, 0x1E, 0x71, 0x01, 0xFB, 0x0C, 0x2C, 0x40, 0xF2, 0xFD, 0x7E, ++ 0x15, 0xE0, 0x03, 0x2B, 0x2A, 0xDD, 0x6A, 0x88, 0x12, 0xF0, 0x08, 0x06, ++ 0xC2, 0xF3, 0x42, 0x01, 0x24, 0xD1, 0x19, 0xF8, 0x01, 0x20, 0x04, 0x32, ++ 0x9A, 0x42, 0x2B, 0xDC, 0xBC, 0xF8, 0x20, 0x10, 0xB9, 0x42, 0xA3, 0xEB, ++ 0x02, 0x03, 0x11, 0xD0, 0x01, 0x2B, 0x15, 0x44, 0x1A, 0xDD, 0x2C, 0x88, ++ 0xC4, 0xF3, 0x0A, 0x07, 0x77, 0x45, 0x13, 0xD0, 0x14, 0xF4, 0x00, 0x60, ++ 0xE1, 0xD0, 0xBC, 0xF8, 0x20, 0x10, 0x02, 0x22, 0xB9, 0x42, 0xA3, 0xEB, ++ 0x02, 0x03, 0xED, 0xD1, 0x14, 0xF4, 0x00, 0x60, 0x0B, 0xD1, 0x98, 0xF8, ++ 0x0A, 0x30, 0xB3, 0xEB, 0x14, 0x3F, 0x0D, 0xD0, 0xBD, 0xE8, 0xF8, 0x83, ++ 0x0C, 0x22, 0xDB, 0xE7, 0x00, 0x20, 0xBD, 0xE8, 0xF8, 0x83, 0x00, 0x23, ++ 0xC8, 0xF8, 0xDC, 0x30, 0x01, 0x20, 0xF3, 0xE7, 0x30, 0x46, 0xF1, 0xE7, ++ 0x08, 0xF1, 0xE0, 0x04, 0x02, 0x3A, 0xA9, 0x1C, 0x20, 0x46, 0x23, 0xF0, ++ 0xBD, 0xFC, 0xC8, 0xF8, 0xDC, 0x40, 0x01, 0x20, 0xE6, 0xE7, 0x00, 0xBF, ++ 0x68, 0x65, 0x17, 0x00, 0x00, 0x96, 0x15, 0x00, 0x85, 0x4B, 0x86, 0x4A, ++ 0x19, 0x68, 0x43, 0x6D, 0x2D, 0xE9, 0xF0, 0x4F, 0x00, 0x24, 0xC5, 0x69, ++ 0x82, 0xF8, 0x88, 0x40, 0xB1, 0xF9, 0x00, 0x10, 0xA1, 0x42, 0x83, 0xB0, ++ 0xC0, 0xF2, 0xC6, 0x80, 0x9E, 0x01, 0x40, 0xF1, 0xAD, 0x80, 0x00, 0x29, ++ 0xC3, 0xF3, 0xCF, 0x30, 0xC3, 0xF3, 0xC9, 0x33, 0xC0, 0xF2, 0xB3, 0x80, ++ 0x7A, 0x49, 0x10, 0x3B, 0xDB, 0xB2, 0x4F, 0xF4, 0x1E, 0x74, 0x04, 0xFB, ++ 0x03, 0x14, 0x94, 0xF8, 0x25, 0x00, 0x00, 0x28, 0x00, 0xF0, 0x9A, 0x80, ++ 0x94, 0xF8, 0x22, 0x50, 0x54, 0xF8, 0x26, 0x0F, 0x50, 0x67, 0x73, 0x48, ++ 0x73, 0x4E, 0xA4, 0x88, 0x84, 0x80, 0x4F, 0xF4, 0xA4, 0x67, 0x10, 0x69, ++ 0x07, 0xFB, 0x05, 0x65, 0xA8, 0x42, 0x40, 0xF0, 0x93, 0x80, 0x6F, 0x48, ++ 0x00, 0x68, 0x00, 0xF0, 0x3F, 0x00, 0x09, 0x28, 0x40, 0xF2, 0x8C, 0x80, ++ 0x6C, 0x4C, 0x6D, 0x48, 0x24, 0x68, 0x05, 0x68, 0xD2, 0xF8, 0x68, 0x80, ++ 0xC4, 0xF3, 0x0B, 0x10, 0x04, 0xF0, 0x0F, 0x09, 0xC4, 0xF3, 0x01, 0x4E, ++ 0x24, 0x03, 0x00, 0x90, 0xA2, 0xF8, 0x7C, 0x00, 0x82, 0xF8, 0x7F, 0x90, ++ 0x82, 0xF8, 0x83, 0xE0, 0xC5, 0xF3, 0x03, 0x10, 0x05, 0xF0, 0x07, 0x06, ++ 0x40, 0xF1, 0x8B, 0x80, 0x4F, 0xF0, 0x02, 0x0B, 0x4F, 0xF4, 0x80, 0x64, ++ 0x5F, 0x46, 0x01, 0x94, 0xC5, 0xF3, 0x00, 0x34, 0xC5, 0xF3, 0x42, 0x2C, ++ 0x82, 0xF8, 0x80, 0x70, 0xF7, 0xB2, 0x82, 0xF8, 0x81, 0x00, 0x82, 0xF8, ++ 0x87, 0x40, 0x82, 0xF8, 0x82, 0xC0, 0x82, 0xF8, 0x84, 0x70, 0xB9, 0xF1, ++ 0x00, 0x0F, 0x79, 0xD0, 0x92, 0xF8, 0x86, 0x50, 0xDF, 0xF8, 0x64, 0x91, ++ 0xD9, 0xF8, 0x00, 0x40, 0x00, 0x2C, 0xFB, 0xDA, 0xD9, 0xF8, 0x00, 0x90, ++ 0x50, 0x4C, 0x02, 0x2E, 0x09, 0xEA, 0x04, 0x04, 0x76, 0xD8, 0x4F, 0x4F, ++ 0x00, 0xEB, 0x40, 0x09, 0x57, 0xF8, 0x26, 0x70, 0xD9, 0x44, 0x37, 0xF8, ++ 0x19, 0x90, 0xD8, 0xF8, 0x0C, 0x70, 0xDF, 0xF8, 0x3C, 0xA1, 0xBC, 0x42, ++ 0x28, 0xBF, 0x3C, 0x46, 0x14, 0x67, 0xDA, 0xF8, 0x00, 0xB0, 0x01, 0x9F, ++ 0x98, 0xF8, 0x1C, 0x80, 0x4F, 0xF4, 0x1E, 0x7A, 0x0A, 0xFB, 0x03, 0x13, ++ 0x07, 0x43, 0x01, 0x21, 0x47, 0xEA, 0xCE, 0x1E, 0x01, 0xFA, 0x05, 0xF5, ++ 0x4F, 0xEA, 0x1B, 0x67, 0xD3, 0xF8, 0x4C, 0x11, 0x93, 0x66, 0x00, 0x9B, ++ 0x27, 0x2C, 0x4E, 0xEA, 0x0C, 0x1C, 0x4F, 0xEA, 0x87, 0x17, 0x18, 0xFB, ++ 0x05, 0xF8, 0x4C, 0xF4, 0x40, 0x5C, 0x46, 0xEA, 0xC3, 0x06, 0x94, 0xBF, ++ 0x00, 0x24, 0x01, 0x24, 0x47, 0xF0, 0x13, 0x07, 0x18, 0xFB, 0x09, 0xF9, ++ 0x82, 0xF8, 0x88, 0x40, 0xD7, 0x66, 0xA1, 0xF8, 0x82, 0xC0, 0xA1, 0xF8, ++ 0x84, 0x60, 0xA2, 0xF8, 0x7A, 0x90, 0x09, 0xE0, 0xAB, 0x68, 0x59, 0x89, ++ 0xA2, 0xF8, 0x74, 0x10, 0x99, 0x89, 0xA2, 0xF8, 0x76, 0x10, 0xDB, 0x89, ++ 0xA2, 0xF8, 0x78, 0x30, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x10, 0xF4, ++ 0x7C, 0x7F, 0x7F, 0xF4, 0x49, 0xAF, 0x27, 0x49, 0x27, 0x48, 0x40, 0xF6, ++ 0x53, 0x12, 0x07, 0xE0, 0x00, 0x8E, 0x1C, 0x28, 0x3F, 0xF6, 0x36, 0xAF, ++ 0x22, 0x49, 0x24, 0x48, 0x40, 0xF6, 0x46, 0x12, 0x03, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x4F, 0x11, 0xF0, 0xF9, 0xB8, 0x4F, 0xF0, 0x01, 0x0B, 0x4F, 0xF4, ++ 0x00, 0x74, 0x5F, 0x46, 0x01, 0x94, 0x73, 0xE7, 0xAC, 0x0F, 0xDF, 0xF8, ++ 0x7C, 0x90, 0xC5, 0xF3, 0x01, 0x65, 0x19, 0xF8, 0x04, 0x40, 0x82, 0xF8, ++ 0x85, 0x40, 0x82, 0xF8, 0x86, 0x50, 0x7B, 0xE7, 0x03, 0x3F, 0x00, 0xEB, ++ 0x40, 0x09, 0xC7, 0xF3, 0x46, 0x0A, 0x0B, 0xEB, 0x49, 0x09, 0x4F, 0xF0, ++ 0x03, 0x0B, 0x1B, 0xFB, 0x0A, 0x99, 0xDF, 0xF8, 0x54, 0xA0, 0x3A, 0xF8, ++ 0x19, 0x90, 0x07, 0xF0, 0x01, 0x07, 0x09, 0xFA, 0x07, 0xF9, 0x1F, 0xFA, ++ 0x89, 0xF9, 0x7A, 0xE7, 0x38, 0x36, 0x17, 0x00, 0x94, 0x64, 0x17, 0x00, ++ 0x68, 0x65, 0x17, 0x00, 0x08, 0x65, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0x54, 0x83, 0x32, 0x40, 0x58, 0x83, 0x32, 0x40, 0x5C, 0x83, 0x32, 0x40, ++ 0xFC, 0xFF, 0x0F, 0x00, 0x04, 0x96, 0x15, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x50, 0x90, 0x15, 0x00, 0xB0, 0x93, 0x15, 0x00, 0x60, 0x83, 0x32, 0x40, ++ 0x64, 0x83, 0x32, 0x40, 0xA8, 0xB2, 0x15, 0x00, 0x70, 0x95, 0x15, 0x00, ++ 0x10, 0xB5, 0x04, 0x4C, 0xD4, 0xF8, 0x9C, 0x32, 0x98, 0x47, 0xD4, 0xF8, ++ 0xEC, 0x33, 0xBD, 0xE8, 0x10, 0x40, 0x18, 0x47, 0x88, 0x1A, 0x17, 0x00, ++ 0x10, 0xB5, 0x03, 0xF0, 0x85, 0xFB, 0x08, 0x4B, 0x1B, 0x68, 0x1B, 0x04, ++ 0x03, 0xD4, 0x07, 0x4B, 0x00, 0x24, 0x1C, 0x61, 0x10, 0xBD, 0x04, 0x46, ++ 0xED, 0xF7, 0x62, 0xFC, 0x00, 0x28, 0xF6, 0xD0, 0x02, 0x4B, 0x1C, 0x61, ++ 0x10, 0xBD, 0x00, 0xBF, 0x04, 0x00, 0x32, 0x40, 0x94, 0x64, 0x17, 0x00, ++ 0x18, 0x4B, 0x1B, 0x69, 0x63, 0xB3, 0x93, 0xF8, 0x64, 0x20, 0x4A, 0xB3, ++ 0x16, 0x4A, 0x93, 0xF8, 0x6C, 0x30, 0x10, 0x68, 0x15, 0x49, 0x40, 0xF0, ++ 0x10, 0x00, 0x30, 0xB4, 0x10, 0x60, 0x10, 0x68, 0x13, 0x4D, 0x14, 0x4C, ++ 0x40, 0xF4, 0x00, 0x60, 0x10, 0x60, 0x10, 0x68, 0x40, 0xF4, 0x80, 0x50, ++ 0x10, 0x60, 0x2A, 0x68, 0x10, 0x48, 0xC4, 0xF8, 0x50, 0x04, 0x42, 0xF4, ++ 0x00, 0x72, 0x2A, 0x60, 0x0A, 0x68, 0x42, 0xF4, 0x80, 0x32, 0x0A, 0x60, ++ 0x0A, 0x68, 0x10, 0x33, 0xDB, 0xB2, 0x43, 0xEA, 0x83, 0x23, 0x22, 0xF4, ++ 0x00, 0x32, 0xC4, 0xF8, 0x4C, 0x34, 0x30, 0xBC, 0x0A, 0x60, 0x70, 0x47, ++ 0x70, 0x47, 0x00, 0xBF, 0x94, 0x64, 0x17, 0x00, 0x80, 0x80, 0x32, 0x40, ++ 0x54, 0x83, 0x32, 0x40, 0x24, 0x03, 0x32, 0x40, 0x60, 0x5D, 0x18, 0x00, ++ 0x04, 0x07, 0xFF, 0xFF, 0x08, 0xB5, 0x0F, 0x4B, 0x1B, 0x69, 0x1B, 0xB1, ++ 0x0E, 0x4B, 0xD3, 0xF8, 0xC4, 0x33, 0x98, 0x47, 0x0D, 0x48, 0x0E, 0x4B, ++ 0x02, 0x68, 0x0E, 0x49, 0x22, 0xF4, 0x00, 0x72, 0x02, 0x60, 0x1A, 0x68, ++ 0x22, 0xF0, 0x10, 0x02, 0x1A, 0x60, 0x1A, 0x68, 0x22, 0xF4, 0x00, 0x62, ++ 0x1A, 0x60, 0x1A, 0x68, 0x22, 0xF4, 0x80, 0x52, 0x1A, 0x60, 0x0B, 0x68, ++ 0x23, 0xF4, 0x80, 0x33, 0x0B, 0x60, 0x08, 0xBD, 0x94, 0x64, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x24, 0x03, 0x32, 0x40, 0x80, 0x80, 0x32, 0x40, ++ 0x54, 0x83, 0x32, 0x40, 0x43, 0x6C, 0x13, 0xB1, 0x9B, 0x88, 0x9A, 0x05, ++ 0x0C, 0xD4, 0xC3, 0x6A, 0xDB, 0x6B, 0x9B, 0x06, 0x43, 0xBF, 0x91, 0xF8, ++ 0x2D, 0x31, 0x48, 0xF2, 0x07, 0x00, 0x40, 0xEA, 0x43, 0x20, 0xD1, 0xF8, ++ 0x04, 0x02, 0x70, 0x47, 0x01, 0x4B, 0xD8, 0x6E, 0x70, 0x47, 0x00, 0xBF, ++ 0x94, 0x64, 0x17, 0x00, 0x4B, 0x08, 0x03, 0x22, 0x02, 0xFB, 0x03, 0x00, ++ 0x03, 0x4B, 0x33, 0xF8, 0x10, 0x00, 0x01, 0xF0, 0x01, 0x01, 0x88, 0x40, ++ 0x70, 0x47, 0x00, 0xBF, 0xE0, 0x94, 0x15, 0x00, 0x4B, 0x08, 0x03, 0x22, ++ 0x02, 0xFB, 0x03, 0x00, 0x03, 0x4B, 0x33, 0xF8, 0x10, 0x00, 0x01, 0xF0, ++ 0x01, 0x01, 0x88, 0x40, 0x80, 0xB2, 0x70, 0x47, 0x70, 0x95, 0x15, 0x00, ++ 0x2D, 0xE9, 0xF8, 0x43, 0x2B, 0x4F, 0x84, 0x6A, 0x3D, 0x68, 0x90, 0xF8, ++ 0x1D, 0x80, 0xB5, 0xF9, 0x00, 0xC0, 0xBC, 0xF1, 0x00, 0x0F, 0x16, 0x46, ++ 0x99, 0x46, 0xC4, 0xF3, 0x41, 0x25, 0x12, 0xDB, 0xC4, 0xF3, 0x02, 0x12, ++ 0x01, 0x32, 0x1A, 0x60, 0x04, 0xF0, 0x0F, 0x04, 0x22, 0x4A, 0x4F, 0xF4, ++ 0x1E, 0x73, 0x03, 0xFB, 0x08, 0x23, 0x04, 0xEB, 0x44, 0x04, 0xDB, 0x68, ++ 0x33, 0x60, 0x05, 0xEB, 0x44, 0x00, 0xBD, 0xE8, 0xF8, 0x83, 0x05, 0x29, ++ 0x1E, 0xD0, 0x1C, 0x49, 0x1C, 0x48, 0x40, 0xF6, 0xF5, 0x12, 0x10, 0xF0, ++ 0xF5, 0xFF, 0x39, 0x68, 0xB1, 0xF9, 0x00, 0x10, 0xC4, 0xF3, 0x02, 0x12, ++ 0x01, 0x32, 0x00, 0x29, 0x4F, 0xEA, 0x14, 0x13, 0xC9, 0xF8, 0x00, 0x20, ++ 0x04, 0xF0, 0x0F, 0x04, 0xDC, 0xDA, 0x5B, 0x07, 0x11, 0xD4, 0x0B, 0x2C, ++ 0xD8, 0xD9, 0x10, 0x49, 0x11, 0x48, 0x40, 0xF6, 0xFF, 0x12, 0x10, 0xF0, ++ 0xDD, 0xFF, 0xD1, 0xE7, 0xC4, 0xF3, 0x02, 0x12, 0x01, 0x32, 0x1A, 0x60, ++ 0x23, 0x09, 0x5B, 0x07, 0x04, 0xF0, 0x0F, 0x04, 0xED, 0xD5, 0x08, 0x49, ++ 0x0A, 0x48, 0x40, 0xF6, 0xFE, 0x12, 0x10, 0xF0, 0xCD, 0xFF, 0x3B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xE2, 0xDB, 0xBC, 0xE7, 0x00, 0xBF, ++ 0x38, 0x36, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0xD8, 0x93, 0x15, 0x00, 0xF8, 0x93, 0x15, 0x00, 0xE0, 0x91, 0x15, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x41, 0x14, 0x4E, 0xDF, 0xF8, 0x54, 0xC0, 0x35, 0x69, ++ 0x04, 0x38, 0x31, 0x46, 0x05, 0xF1, 0x08, 0x04, 0x05, 0xF1, 0x18, 0x0E, ++ 0x00, 0x27, 0x50, 0xF8, 0x04, 0x2F, 0x13, 0x09, 0x02, 0xF0, 0x0F, 0x08, ++ 0x03, 0xF4, 0x7F, 0x63, 0x43, 0xEA, 0x08, 0x03, 0x12, 0x0C, 0x8B, 0x62, ++ 0x81, 0xF8, 0x2C, 0x20, 0x25, 0xB1, 0x22, 0x68, 0x02, 0xEA, 0x0C, 0x02, ++ 0x13, 0x43, 0x8B, 0x62, 0x04, 0x34, 0xA6, 0x45, 0x4F, 0x62, 0x01, 0xF1, ++ 0x0C, 0x01, 0xE6, 0xD1, 0x01, 0x23, 0x86, 0xF8, 0x62, 0x30, 0xBD, 0xE8, ++ 0xF0, 0x81, 0x00, 0xBF, 0x94, 0x64, 0x17, 0x00, 0x00, 0xF0, 0xFF, 0xFF, ++ 0x03, 0x4B, 0x02, 0x78, 0x83, 0xF8, 0x64, 0x20, 0x42, 0x78, 0x83, 0xF8, ++ 0x65, 0x20, 0x70, 0x47, 0x94, 0x64, 0x17, 0x00, 0x0A, 0x4B, 0x9A, 0x69, ++ 0x8A, 0xB1, 0x30, 0xB4, 0x01, 0xEB, 0x41, 0x02, 0x03, 0xEB, 0x82, 0x02, ++ 0x4C, 0x00, 0x92, 0xF8, 0x2E, 0x50, 0x05, 0xB1, 0x50, 0x62, 0x21, 0x44, ++ 0x03, 0xEB, 0x81, 0x03, 0x01, 0x22, 0x30, 0xBC, 0x83, 0xF8, 0x2D, 0x20, ++ 0x70, 0x47, 0x70, 0x47, 0x94, 0x64, 0x17, 0x00, 0x08, 0x4A, 0x09, 0x4B, ++ 0x11, 0x69, 0x09, 0x4A, 0x10, 0xB4, 0x01, 0xF5, 0x9C, 0x51, 0x08, 0x4C, ++ 0x5C, 0x60, 0x98, 0x60, 0x5D, 0xF8, 0x04, 0x4B, 0x18, 0x46, 0x08, 0x31, ++ 0xD2, 0xF8, 0xE0, 0x31, 0x18, 0x47, 0x00, 0xBF, 0x00, 0x10, 0x50, 0x40, ++ 0x94, 0x64, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x95, 0x24, 0x13, 0x00, ++ 0x08, 0x4A, 0x03, 0x7F, 0x4F, 0xF4, 0xA4, 0x61, 0x01, 0xFB, 0x03, 0x23, ++ 0x40, 0xF2, 0xFF, 0x31, 0xB3, 0xF8, 0xBE, 0x24, 0x8A, 0x42, 0x00, 0xD1, ++ 0x70, 0x47, 0x43, 0x6C, 0x28, 0x30, 0x59, 0x6A, 0xFE, 0xF7, 0xF2, 0xBB, ++ 0x18, 0x88, 0x17, 0x00, 0xF8, 0xB5, 0x0E, 0x4A, 0x03, 0x7F, 0x4F, 0xF4, ++ 0xA4, 0x61, 0x01, 0xFB, 0x03, 0x23, 0x40, 0xF2, 0xFF, 0x31, 0xB3, 0xF8, ++ 0xBE, 0x24, 0x8A, 0x42, 0x0F, 0xD0, 0xD0, 0xE9, 0x12, 0x67, 0x1D, 0x46, ++ 0x06, 0xF1, 0x3C, 0x04, 0x4C, 0x36, 0x20, 0x46, 0xF9, 0x6A, 0x04, 0x34, ++ 0xFE, 0xF7, 0xD8, 0xFB, 0xB4, 0x42, 0x02, 0xD0, 0xB5, 0xF8, 0xBE, 0x24, ++ 0xF5, 0xE7, 0xF8, 0xBD, 0x18, 0x88, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0x9C, 0x4E, 0xD0, 0xF8, 0x44, 0xB0, 0xC7, 0x6C, 0x96, 0xF8, 0x7E, 0x50, ++ 0x96, 0xF8, 0x87, 0x30, 0x11, 0xF4, 0x00, 0x09, 0x83, 0xB0, 0x04, 0x46, ++ 0x8A, 0x46, 0x3E, 0xD0, 0x7B, 0xBB, 0xDF, 0xF8, 0x58, 0x82, 0x28, 0x46, ++ 0xD8, 0xF8, 0xC0, 0x33, 0x98, 0x47, 0xD8, 0xF8, 0x9C, 0x32, 0x98, 0x47, ++ 0xBB, 0xF8, 0x04, 0x30, 0x99, 0x06, 0x49, 0xD5, 0x13, 0xF0, 0x40, 0x02, ++ 0x69, 0xD0, 0x58, 0x46, 0xFD, 0xF7, 0x14, 0xFE, 0x00, 0x23, 0xDF, 0xF8, ++ 0x4C, 0x82, 0x63, 0x64, 0xB9, 0xF1, 0x00, 0x0F, 0x4D, 0xD0, 0x89, 0x4B, ++ 0x00, 0x22, 0xD3, 0xF8, 0xAC, 0x33, 0x29, 0x46, 0x20, 0x46, 0x98, 0x47, ++ 0x54, 0x20, 0x00, 0xFB, 0x05, 0x80, 0x0C, 0x30, 0x0F, 0xF0, 0xD2, 0xFA, ++ 0xA3, 0x88, 0x00, 0x2B, 0x47, 0xD1, 0x20, 0x46, 0x03, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x4F, 0xFC, 0xF7, 0x0B, 0xB9, 0x7F, 0x48, 0x96, 0xF8, 0x64, 0x30, ++ 0x01, 0x68, 0xDF, 0xF8, 0xF0, 0x81, 0x1B, 0x06, 0x21, 0xF0, 0xE0, 0x61, ++ 0x03, 0xF0, 0xE0, 0x63, 0x0B, 0x43, 0x03, 0x60, 0xC7, 0xE7, 0x00, 0x2B, ++ 0xC8, 0xD0, 0x77, 0x48, 0x96, 0xF8, 0x65, 0xE0, 0x01, 0x68, 0x02, 0x68, ++ 0xC1, 0xF3, 0x02, 0x61, 0x4B, 0x1C, 0x73, 0x45, 0x28, 0xBF, 0x73, 0x46, ++ 0x1B, 0x06, 0x03, 0xF0, 0xE0, 0x63, 0x22, 0xF0, 0xE0, 0x6C, 0x43, 0xEA, ++ 0x0C, 0x03, 0x03, 0x60, 0xBB, 0xF8, 0x04, 0x30, 0x99, 0x06, 0xB5, 0xD4, ++ 0x1C, 0x23, 0xDF, 0xF8, 0xC4, 0x81, 0x54, 0x20, 0x10, 0xFB, 0x05, 0x30, ++ 0x40, 0x44, 0x0F, 0xF0, 0x99, 0xFA, 0x58, 0x46, 0xFD, 0xF7, 0xC4, 0xFD, ++ 0x00, 0x23, 0x63, 0x64, 0xB9, 0xF1, 0x00, 0x0F, 0xB1, 0xD1, 0xCA, 0xF3, ++ 0x07, 0x29, 0xB9, 0xF1, 0x04, 0x0F, 0x1F, 0xD9, 0x3B, 0x6D, 0x43, 0xF4, ++ 0x80, 0x33, 0x3B, 0x65, 0xA7, 0xE7, 0x2A, 0x46, 0x51, 0x46, 0x20, 0x46, ++ 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x4F, 0xFB, 0xF7, 0x9D, 0xBA, 0x3B, 0x6D, ++ 0x00, 0x92, 0x23, 0xF4, 0x00, 0x03, 0x2A, 0xF4, 0x00, 0x0A, 0x58, 0x46, ++ 0x3B, 0x65, 0xCA, 0xF3, 0x07, 0x29, 0xFD, 0xF7, 0xA1, 0xFD, 0x00, 0x9A, ++ 0xDF, 0xF8, 0x64, 0x81, 0x62, 0x64, 0xB9, 0xF1, 0x04, 0x0F, 0xDF, 0xD8, ++ 0xD4, 0xF8, 0x48, 0xA0, 0xB9, 0xF1, 0x00, 0x0F, 0x25, 0xD0, 0x0A, 0xF1, ++ 0x28, 0x0B, 0x05, 0xEB, 0x45, 0x03, 0x06, 0xEB, 0x83, 0x03, 0x09, 0xF1, ++ 0x01, 0x09, 0x59, 0x6A, 0xDA, 0xE9, 0x17, 0x32, 0xBB, 0x64, 0x4F, 0xEA, ++ 0x09, 0x23, 0xC7, 0xE9, 0x0D, 0x2B, 0x3B, 0x65, 0x07, 0xF1, 0x14, 0x02, ++ 0x6B, 0x00, 0x00, 0x29, 0x4B, 0xD0, 0xB9, 0x61, 0x54, 0x20, 0x00, 0xFB, ++ 0x05, 0x88, 0x1D, 0x44, 0x98, 0xF8, 0x50, 0x30, 0x06, 0xEB, 0x85, 0x06, ++ 0x01, 0x33, 0x72, 0x62, 0x88, 0xF8, 0x50, 0x30, 0x03, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x8F, 0xE3, 0x6A, 0x0A, 0xF1, 0x28, 0x0B, 0x03, 0xF1, 0x40, 0x0C, ++ 0x1A, 0x46, 0x0A, 0xF1, 0x24, 0x01, 0x52, 0xF8, 0x04, 0x0B, 0x41, 0xF8, ++ 0x04, 0x0F, 0x62, 0x45, 0xF9, 0xD1, 0xE2, 0x8B, 0x92, 0x04, 0x26, 0xD5, ++ 0x33, 0x4A, 0x34, 0x48, 0x11, 0x68, 0x62, 0x7F, 0xB1, 0xF9, 0x00, 0x10, ++ 0x4F, 0xF4, 0x1E, 0x7C, 0x0C, 0xFB, 0x02, 0x02, 0x00, 0x29, 0xD2, 0xF8, ++ 0x4C, 0x21, 0x00, 0x92, 0x29, 0xDB, 0x00, 0x9A, 0x59, 0x69, 0xD2, 0xF8, ++ 0x9C, 0x20, 0xCA, 0xF8, 0x40, 0x10, 0x59, 0x6A, 0xCA, 0xF8, 0x50, 0x10, ++ 0xC2, 0xF3, 0xC2, 0x21, 0x05, 0x29, 0xCA, 0xF8, 0x3C, 0x20, 0x25, 0xD0, ++ 0xDB, 0x6B, 0x5B, 0x07, 0x05, 0xD4, 0xDA, 0xF8, 0x2C, 0x30, 0x23, 0xF4, ++ 0xC0, 0x73, 0xCA, 0xF8, 0x2C, 0x30, 0x20, 0x46, 0xFF, 0xF7, 0xDC, 0xFE, ++ 0x9F, 0xE7, 0x54, 0x21, 0x01, 0xFB, 0x05, 0xF1, 0x1E, 0x48, 0x48, 0xF8, ++ 0x01, 0x20, 0x00, 0x68, 0x40, 0x78, 0x41, 0x44, 0x00, 0x28, 0xA9, 0xD1, ++ 0xC1, 0xE9, 0x01, 0x00, 0xA6, 0xE7, 0x00, 0x2A, 0xD3, 0xD1, 0x19, 0x49, ++ 0x19, 0x48, 0x01, 0x93, 0x40, 0xF2, 0x4B, 0x12, 0x10, 0xF0, 0xFE, 0xFD, ++ 0x01, 0x9B, 0xCA, 0xE7, 0x00, 0x98, 0xDA, 0xF8, 0x4C, 0x10, 0x90, 0xF8, ++ 0xA1, 0x00, 0x02, 0xF4, 0xC0, 0x62, 0xB2, 0xF5, 0x80, 0x6F, 0x14, 0xBF, ++ 0x4F, 0xF4, 0x80, 0x3C, 0x4F, 0xF4, 0x00, 0x3C, 0x21, 0xF4, 0x40, 0x32, ++ 0x42, 0xEA, 0x0C, 0x02, 0x20, 0xB1, 0x42, 0xF4, 0x80, 0x22, 0xCA, 0xF8, ++ 0x4C, 0x20, 0xC1, 0xE7, 0x22, 0xF4, 0x80, 0x22, 0xCA, 0xF8, 0x4C, 0x20, ++ 0xBC, 0xE7, 0x00, 0xBF, 0x94, 0x64, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x54, 0x83, 0x32, 0x40, 0x38, 0x36, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, ++ 0x34, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x68, 0x8E, 0x15, 0x00, ++ 0x20, 0x62, 0x17, 0x00, 0x10, 0xB5, 0x05, 0x4C, 0x20, 0x46, 0x0F, 0xF0, ++ 0x6F, 0xF9, 0x10, 0xF0, 0x25, 0xFE, 0x01, 0x38, 0xC0, 0xB2, 0xE0, 0x72, ++ 0xA0, 0x72, 0x10, 0xBD, 0x24, 0x65, 0x17, 0x00, 0xC2, 0x4B, 0x2D, 0xE9, ++ 0xF0, 0x4F, 0x4F, 0xF4, 0xA4, 0x67, 0x07, 0xFB, 0x02, 0x38, 0x85, 0xB0, ++ 0x98, 0xF8, 0x62, 0x30, 0x02, 0x2B, 0x17, 0xD1, 0x4F, 0xF4, 0x1E, 0x79, ++ 0x93, 0x46, 0x0C, 0x46, 0x09, 0xFB, 0x01, 0xF2, 0xBA, 0x49, 0x01, 0x92, ++ 0x8E, 0x18, 0xB0, 0xF8, 0x00, 0xA0, 0x96, 0xF8, 0x24, 0x90, 0xB9, 0xF1, ++ 0x01, 0x0F, 0x05, 0x46, 0x41, 0xF2, 0x04, 0x42, 0x07, 0xD0, 0x0A, 0xEA, ++ 0x02, 0x0A, 0xBA, 0xF5, 0x80, 0x5F, 0x5A, 0xD0, 0x05, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x8F, 0x1A, 0xEA, 0x02, 0x02, 0x00, 0xF0, 0x6B, 0x81, 0x0A, 0xF0, ++ 0xFC, 0x03, 0xA4, 0x2B, 0x00, 0xF0, 0x75, 0x82, 0x0A, 0xF0, 0x8C, 0x03, ++ 0x88, 0x2B, 0xEF, 0xD1, 0x0A, 0xF4, 0x40, 0x7A, 0xBA, 0xF5, 0x40, 0x7F, ++ 0x0C, 0xBF, 0xEF, 0x8B, 0x2F, 0x8B, 0xA7, 0x4B, 0xA5, 0x49, 0xA7, 0x4A, ++ 0x07, 0xF0, 0x07, 0x07, 0x4F, 0xF4, 0x1E, 0x75, 0xDB, 0x5D, 0x05, 0xFB, ++ 0x04, 0x15, 0xD2, 0x5C, 0x95, 0xF8, 0x2E, 0x31, 0x1A, 0x42, 0xD9, 0xD0, ++ 0x95, 0xF8, 0x31, 0x30, 0x13, 0xF0, 0x0C, 0x0F, 0x00, 0xF0, 0x7E, 0x82, ++ 0x95, 0xF8, 0x32, 0x20, 0x12, 0xF0, 0x06, 0x0F, 0xCE, 0xD1, 0x18, 0x07, ++ 0x95, 0xF8, 0x2F, 0x91, 0x40, 0xF1, 0x8A, 0x82, 0x99, 0x4B, 0x02, 0x22, ++ 0x85, 0xF8, 0x32, 0x20, 0xD3, 0xF8, 0x20, 0x33, 0x31, 0x46, 0x40, 0x46, ++ 0x4A, 0x46, 0x98, 0x47, 0xB9, 0xF1, 0x00, 0x0F, 0x00, 0xF0, 0x7A, 0x82, ++ 0xA9, 0xEB, 0x00, 0x09, 0xB9, 0xF1, 0x00, 0x0F, 0x00, 0xF3, 0x74, 0x82, ++ 0x8C, 0x4A, 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, 0x04, 0x24, 0x00, 0x23, ++ 0x1A, 0x46, 0x94, 0xF8, 0x23, 0x00, 0x47, 0xF0, 0x10, 0x01, 0xFC, 0xF7, ++ 0xA9, 0xF8, 0x00, 0x23, 0x84, 0xF8, 0x32, 0x30, 0xA4, 0xE7, 0x00, 0x22, ++ 0x0C, 0x21, 0x49, 0x20, 0x0E, 0xF0, 0x58, 0xFC, 0x4F, 0xF0, 0x01, 0x09, ++ 0x86, 0xF8, 0x24, 0x90, 0x04, 0x70, 0x80, 0xF8, 0x01, 0x90, 0x0E, 0xF0, ++ 0x7F, 0xFC, 0x96, 0xF8, 0x24, 0x30, 0x00, 0x2B, 0x58, 0xD1, 0x96, 0xF8, ++ 0x23, 0x30, 0x09, 0x2B, 0x54, 0xD8, 0x96, 0xF8, 0x22, 0x20, 0x77, 0x48, ++ 0x7B, 0x4D, 0xCD, 0xF8, 0x08, 0x90, 0x9E, 0x23, 0xA4, 0x21, 0x11, 0xFB, ++ 0x02, 0x31, 0x07, 0xFB, 0x02, 0x07, 0x4F, 0x23, 0x46, 0x22, 0x13, 0xFB, ++ 0x04, 0x24, 0x71, 0x4A, 0x02, 0xF5, 0x16, 0x73, 0x02, 0xEB, 0xC4, 0x04, ++ 0x01, 0x9A, 0x1A, 0x44, 0x00, 0xEB, 0xC1, 0x0A, 0x91, 0x46, 0xD6, 0xF8, ++ 0x08, 0x32, 0x1B, 0xB3, 0xEF, 0xF3, 0x10, 0x83, 0xDA, 0x07, 0x03, 0xD4, ++ 0x72, 0xB6, 0x6D, 0x4B, 0x02, 0x9A, 0x1A, 0x60, 0x2B, 0x68, 0xA4, 0xF1, ++ 0x28, 0x00, 0x01, 0x33, 0xAA, 0xF1, 0x28, 0x01, 0x01, 0x90, 0x2B, 0x60, ++ 0x0F, 0xF0, 0x98, 0xF9, 0xD6, 0xE9, 0x82, 0x23, 0x01, 0x98, 0xC7, 0xF8, ++ 0xC8, 0x24, 0xC7, 0xF8, 0xCC, 0x34, 0x0F, 0xF0, 0x99, 0xF8, 0x2B, 0x68, ++ 0x5A, 0x1E, 0x2B, 0xB1, 0x60, 0x4B, 0x2A, 0x60, 0x1B, 0x68, 0x0A, 0xB9, ++ 0x03, 0xB1, 0x62, 0xB6, 0xD6, 0xF8, 0x30, 0x32, 0x50, 0x46, 0x21, 0x46, ++ 0x08, 0x36, 0x0A, 0xF1, 0x08, 0x0A, 0x08, 0x37, 0x23, 0xB1, 0x0F, 0xF0, ++ 0x7B, 0xF9, 0x20, 0x46, 0x0F, 0xF0, 0x82, 0xF8, 0x08, 0x34, 0x4C, 0x45, ++ 0xC7, 0xD1, 0x40, 0x20, 0x0E, 0xF0, 0xDE, 0xFF, 0x4D, 0x4B, 0x4F, 0xF4, ++ 0xA4, 0x67, 0x07, 0xFB, 0x0B, 0x36, 0x96, 0xF8, 0xDE, 0x20, 0x00, 0x2A, ++ 0x40, 0xF0, 0x82, 0x80, 0x0B, 0xF1, 0x0A, 0x05, 0x48, 0x4B, 0xED, 0xB2, ++ 0x4F, 0xF4, 0x1E, 0x79, 0x09, 0xFB, 0x05, 0xF9, 0x03, 0xEB, 0x09, 0x04, ++ 0x94, 0xF8, 0x24, 0x30, 0x01, 0x2B, 0x73, 0xD0, 0x02, 0x23, 0x0C, 0x21, ++ 0x49, 0x20, 0x0E, 0xF0, 0xD5, 0xFB, 0x4F, 0xF0, 0x01, 0x0A, 0x84, 0xF8, ++ 0x24, 0xA0, 0x05, 0x70, 0x80, 0xF8, 0x01, 0xA0, 0x0E, 0xF0, 0xFC, 0xFB, ++ 0x94, 0xF8, 0x24, 0x30, 0x00, 0x2B, 0x40, 0xF0, 0xA9, 0x81, 0x94, 0xF8, ++ 0x23, 0x30, 0x09, 0x2B, 0x00, 0xF2, 0xA4, 0x81, 0x94, 0xF8, 0x22, 0x00, ++ 0xCD, 0xF8, 0x08, 0xA0, 0xA4, 0x21, 0x9E, 0x23, 0x11, 0xFB, 0x00, 0x33, ++ 0x4F, 0xF0, 0x46, 0x0A, 0x4F, 0x21, 0x11, 0xFB, 0x05, 0xAA, 0x36, 0x4A, ++ 0x2E, 0x4E, 0x2E, 0x49, 0x07, 0xFB, 0x00, 0x67, 0x01, 0xEB, 0xC3, 0x05, ++ 0x30, 0x4E, 0xA2, 0xF5, 0x16, 0x73, 0x03, 0xEB, 0xCA, 0x0A, 0x91, 0x44, ++ 0xD4, 0xF8, 0x08, 0x32, 0x1B, 0xB3, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, ++ 0x03, 0xD4, 0x72, 0xB6, 0x2A, 0x4B, 0x02, 0x9A, 0x1A, 0x60, 0x33, 0x68, ++ 0xAA, 0xF1, 0x28, 0x00, 0x01, 0x33, 0xA5, 0xF1, 0x28, 0x01, 0x01, 0x90, ++ 0x33, 0x60, 0x0F, 0xF0, 0x13, 0xF9, 0xD4, 0xE9, 0x82, 0x23, 0x01, 0x98, ++ 0xC7, 0xF8, 0xC8, 0x24, 0xC7, 0xF8, 0xCC, 0x34, 0x0F, 0xF0, 0x14, 0xF8, ++ 0x33, 0x68, 0x5A, 0x1E, 0x2B, 0xB1, 0x1E, 0x4B, 0x32, 0x60, 0x1B, 0x68, ++ 0x0A, 0xB9, 0x03, 0xB1, 0x62, 0xB6, 0xD4, 0xF8, 0x30, 0x32, 0x28, 0x46, ++ 0x51, 0x46, 0x08, 0x34, 0x08, 0x35, 0x08, 0x37, 0x23, 0xB1, 0x0F, 0xF0, ++ 0xF7, 0xF8, 0x50, 0x46, 0x0E, 0xF0, 0xFE, 0xFF, 0x0A, 0xF1, 0x08, 0x0A, ++ 0xCA, 0x45, 0xC7, 0xD1, 0x40, 0x20, 0x0E, 0xF0, 0x59, 0xFF, 0x0B, 0x4A, ++ 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x0B, 0x23, 0x93, 0xF8, 0xDE, 0x20, ++ 0x07, 0x48, 0x0B, 0x49, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x0B, 0x03, ++ 0x01, 0x32, 0x83, 0xF8, 0xDE, 0x20, 0xD1, 0xF8, 0x0C, 0x32, 0x40, 0x46, ++ 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x4F, 0x18, 0x47, 0x18, 0x88, 0x17, 0x00, ++ 0x68, 0x65, 0x17, 0x00, 0xC0, 0xB2, 0x15, 0x00, 0xA4, 0xB2, 0x15, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, ++ 0xC0, 0x67, 0x17, 0x00, 0x0C, 0x21, 0x49, 0x20, 0x02, 0x92, 0x0E, 0xF0, ++ 0x41, 0xFB, 0x02, 0x9A, 0x86, 0xF8, 0x24, 0x20, 0x04, 0x70, 0x42, 0x70, ++ 0x0E, 0xF0, 0x6A, 0xFB, 0x96, 0xF8, 0x24, 0x30, 0x00, 0x2B, 0x60, 0xD1, ++ 0x96, 0xF8, 0x23, 0x30, 0x09, 0x2B, 0x5C, 0xD8, 0x96, 0xF8, 0x22, 0x20, ++ 0xA8, 0x48, 0xCD, 0xF8, 0x08, 0x90, 0xA4, 0x21, 0x9E, 0x23, 0x11, 0xFB, ++ 0x02, 0x33, 0xA6, 0x49, 0xDF, 0xF8, 0xA0, 0xA2, 0x03, 0x94, 0x07, 0xFB, ++ 0x02, 0x19, 0x4F, 0x25, 0x01, 0xEB, 0xC3, 0x07, 0x46, 0x22, 0x01, 0x9B, ++ 0x15, 0xFB, 0x04, 0x25, 0x00, 0xF5, 0x16, 0x72, 0x13, 0x44, 0x3C, 0x46, ++ 0x00, 0xEB, 0xC5, 0x05, 0x1F, 0x46, 0xD6, 0xF8, 0x08, 0x22, 0x3A, 0xB3, ++ 0xEF, 0xF3, 0x10, 0x82, 0xD2, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x99, 0x4B, ++ 0x02, 0x9A, 0x1A, 0x60, 0xDA, 0xF8, 0x00, 0x20, 0xA5, 0xF1, 0x28, 0x00, ++ 0x01, 0x32, 0xA4, 0xF1, 0x28, 0x01, 0x01, 0x90, 0xCA, 0xF8, 0x00, 0x20, ++ 0x0F, 0xF0, 0x7E, 0xF8, 0xD6, 0xE9, 0x82, 0x21, 0x01, 0x98, 0xC9, 0xF8, ++ 0xC8, 0x24, 0xC9, 0xF8, 0xCC, 0x14, 0x0E, 0xF0, 0x7F, 0xFF, 0xDA, 0xF8, ++ 0x00, 0x20, 0x51, 0x1E, 0x32, 0xB1, 0x8B, 0x4B, 0xCA, 0xF8, 0x00, 0x10, ++ 0x1A, 0x68, 0x09, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0xD6, 0xF8, 0x30, 0x22, ++ 0x20, 0x46, 0x29, 0x46, 0x08, 0x36, 0x08, 0x34, 0x09, 0xF1, 0x08, 0x09, ++ 0x22, 0xB1, 0x0F, 0xF0, 0x5F, 0xF8, 0x28, 0x46, 0x0E, 0xF0, 0x66, 0xFF, ++ 0x08, 0x35, 0xBD, 0x42, 0xC3, 0xD1, 0x40, 0x20, 0x03, 0x9C, 0x0E, 0xF0, ++ 0xC1, 0xFE, 0x7E, 0x4D, 0x21, 0x46, 0xEB, 0x68, 0x40, 0x46, 0x98, 0x47, ++ 0x79, 0x4B, 0x4F, 0xF4, 0xA4, 0x67, 0x07, 0xFB, 0x0B, 0x33, 0x93, 0xF8, ++ 0xDE, 0xA0, 0x0A, 0xF1, 0xFF, 0x3A, 0x5F, 0xFA, 0x8A, 0xFA, 0x83, 0xF8, ++ 0xDE, 0xA0, 0xBA, 0xF1, 0x00, 0x0F, 0x40, 0xF0, 0x84, 0x80, 0x0B, 0xF1, ++ 0x0A, 0x06, 0x6F, 0x49, 0xF6, 0xB2, 0x4F, 0xF4, 0x1E, 0x79, 0x09, 0xFB, ++ 0x06, 0xF9, 0x01, 0xEB, 0x09, 0x04, 0x94, 0xF8, 0x24, 0x30, 0x00, 0x2B, ++ 0x71, 0xD0, 0x02, 0x23, 0x52, 0x46, 0x0C, 0x21, 0x49, 0x20, 0x0E, 0xF0, ++ 0xAB, 0xFA, 0x84, 0xF8, 0x24, 0xA0, 0x06, 0x70, 0x80, 0xF8, 0x01, 0xA0, ++ 0x0E, 0xF0, 0xD4, 0xFA, 0x94, 0xF8, 0x24, 0x30, 0x00, 0x2B, 0x60, 0xD1, ++ 0x94, 0xF8, 0x23, 0x30, 0x09, 0x2B, 0x5C, 0xD8, 0x94, 0xF8, 0x22, 0x10, ++ 0x5E, 0x4A, 0xDF, 0xF8, 0x88, 0xC1, 0xDF, 0xF8, 0x80, 0xA1, 0x02, 0x96, ++ 0x9E, 0x23, 0xA4, 0x20, 0x10, 0xFB, 0x01, 0x30, 0x07, 0xFB, 0x01, 0x27, ++ 0x4F, 0x23, 0x46, 0x21, 0x13, 0xFB, 0x06, 0x13, 0xAC, 0xF5, 0x16, 0x71, ++ 0x02, 0xEB, 0xC0, 0x0B, 0xE1, 0x44, 0x01, 0xEB, 0xC3, 0x03, 0x5E, 0x46, ++ 0xCB, 0x46, 0xB9, 0x46, 0x1F, 0x46, 0xD4, 0xF8, 0x08, 0x22, 0x3A, 0xB3, ++ 0xEF, 0xF3, 0x10, 0x82, 0xD3, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x4E, 0x4B, ++ 0x01, 0x22, 0x1A, 0x60, 0xDA, 0xF8, 0x00, 0x20, 0xA7, 0xF1, 0x28, 0x00, ++ 0x01, 0x32, 0xA6, 0xF1, 0x28, 0x01, 0x01, 0x90, 0xCA, 0xF8, 0x00, 0x20, ++ 0x0E, 0xF0, 0xE8, 0xFF, 0xD4, 0xE9, 0x82, 0x21, 0x01, 0x98, 0xC9, 0xF8, ++ 0xC8, 0x24, 0xC9, 0xF8, 0xCC, 0x14, 0x0E, 0xF0, 0xE9, 0xFE, 0xDA, 0xF8, ++ 0x00, 0x20, 0x51, 0x1E, 0x32, 0xB1, 0x40, 0x4B, 0xCA, 0xF8, 0x00, 0x10, ++ 0x1A, 0x68, 0x09, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0xD4, 0xF8, 0x30, 0x22, ++ 0x30, 0x46, 0x39, 0x46, 0x08, 0x34, 0x08, 0x36, 0x09, 0xF1, 0x08, 0x09, ++ 0x22, 0xB1, 0x0E, 0xF0, 0xC9, 0xFF, 0x38, 0x46, 0x0E, 0xF0, 0xD0, 0xFE, ++ 0x08, 0x37, 0x5F, 0x45, 0xC3, 0xD1, 0x40, 0x20, 0x02, 0x9E, 0x0E, 0xF0, ++ 0x2B, 0xFE, 0xEB, 0x68, 0x31, 0x46, 0x40, 0x46, 0x98, 0x47, 0xD5, 0xF8, ++ 0x0C, 0x32, 0x40, 0x46, 0xDC, 0xE6, 0x96, 0xF8, 0x31, 0x20, 0x12, 0xF0, ++ 0x02, 0x07, 0x16, 0xD0, 0x96, 0xF8, 0x32, 0x30, 0x2B, 0x49, 0x43, 0xF0, ++ 0x01, 0x03, 0x86, 0xF8, 0x32, 0x30, 0x4A, 0x46, 0xD1, 0xF8, 0x20, 0x33, ++ 0x40, 0x46, 0x31, 0x46, 0x98, 0x47, 0x96, 0xF8, 0x32, 0x30, 0x23, 0xF0, ++ 0x01, 0x03, 0x86, 0xF8, 0x32, 0x30, 0x71, 0xE5, 0x96, 0xF8, 0xDE, 0x20, ++ 0xB4, 0xE6, 0x04, 0x23, 0x3A, 0x46, 0x0C, 0x21, 0x4A, 0x20, 0x0E, 0xF0, ++ 0x15, 0xFA, 0x04, 0x70, 0x80, 0xF8, 0x01, 0x90, 0x87, 0x70, 0x0E, 0xF0, ++ 0x3F, 0xFA, 0x61, 0xE5, 0x95, 0xF8, 0x32, 0x30, 0x13, 0xF0, 0x06, 0x04, ++ 0x7F, 0xF4, 0x50, 0xAD, 0x02, 0x26, 0x95, 0xF8, 0x23, 0x00, 0x85, 0xF8, ++ 0x32, 0x60, 0x47, 0xF0, 0x10, 0x01, 0x23, 0x46, 0x22, 0x46, 0xFB, 0xF7, ++ 0x45, 0xFE, 0x85, 0xF8, 0x32, 0x40, 0x41, 0xE5, 0x95, 0xF8, 0x31, 0x30, ++ 0x59, 0x07, 0x7F, 0xF5, 0x87, 0xAD, 0x0B, 0x4B, 0x4F, 0xF4, 0x1E, 0x70, ++ 0x00, 0xFB, 0x04, 0x30, 0x04, 0x23, 0x80, 0xF8, 0x32, 0x30, 0x00, 0x22, ++ 0x0C, 0x21, 0x4A, 0x20, 0x0E, 0xF0, 0xE8, 0xF9, 0x01, 0x22, 0x04, 0x70, ++ 0x80, 0xF8, 0x01, 0x90, 0x82, 0x70, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x4F, ++ 0x0E, 0xF0, 0x0E, 0xBA, 0x68, 0x65, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0x38, 0x61, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0xC0, 0x67, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, 0x05, 0x8E, 0x87, 0xB0, ++ 0xAD, 0xB1, 0x7A, 0x4B, 0xC6, 0x69, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0x04, 0x46, 0x11, 0xDB, 0x77, 0x4A, 0x65, 0x6D, 0x12, 0x68, ++ 0x12, 0x78, 0x92, 0x07, 0x03, 0xD5, 0x05, 0xF0, 0x3C, 0x02, 0x3C, 0x2A, ++ 0x77, 0xD0, 0x73, 0x4A, 0xAA, 0x43, 0x0E, 0xD0, 0x01, 0x25, 0x28, 0x46, ++ 0x07, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x00, 0x2E, 0xEB, 0xD1, 0x6F, 0x49, ++ 0x6F, 0x48, 0x4F, 0xF4, 0xD4, 0x72, 0x35, 0x46, 0x10, 0xF0, 0x5A, 0xFA, ++ 0xF1, 0xE7, 0x00, 0x2B, 0xC5, 0xF3, 0xCF, 0x30, 0xC5, 0xF3, 0xC9, 0x31, ++ 0x68, 0xDB, 0x6A, 0x4A, 0x10, 0x39, 0xC9, 0xB2, 0x4F, 0xF4, 0x1E, 0x73, ++ 0x03, 0xFB, 0x01, 0x23, 0x93, 0xF8, 0x25, 0x00, 0x00, 0x28, 0x68, 0xD0, ++ 0xD6, 0xF8, 0x08, 0xB0, 0x0D, 0x29, 0xBB, 0xF8, 0x00, 0x00, 0x00, 0x90, ++ 0x69, 0xD9, 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, 0x01, 0x22, 0x13, 0x8C, ++ 0xFF, 0x2B, 0x67, 0xD0, 0x01, 0x92, 0x01, 0x9B, 0xDF, 0xF8, 0x88, 0x81, ++ 0x93, 0xF8, 0x22, 0x90, 0xDF, 0xF8, 0x84, 0xA1, 0x02, 0x91, 0x4F, 0xF4, ++ 0xA4, 0x67, 0x07, 0xFB, 0x09, 0x87, 0xDA, 0xF8, 0xB8, 0x32, 0x97, 0xF8, ++ 0x63, 0x20, 0x58, 0x46, 0x98, 0x47, 0x97, 0xF8, 0x64, 0x30, 0x00, 0x2B, ++ 0xBA, 0xD0, 0x00, 0x9B, 0x13, 0xF0, 0x04, 0x03, 0x03, 0x93, 0x05, 0xD1, ++ 0x02, 0x99, 0x97, 0xF8, 0x63, 0x00, 0x01, 0x22, 0x0C, 0xF0, 0x96, 0xFB, ++ 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x09, 0x88, 0x98, 0xF8, 0x62, 0x30, ++ 0x00, 0x2B, 0xA7, 0xD1, 0x00, 0x9A, 0x02, 0xF0, 0xFC, 0x07, 0x80, 0x2F, ++ 0x4A, 0xD0, 0x50, 0x2F, 0x67, 0xD0, 0x03, 0x9B, 0x00, 0x2B, 0x9D, 0xD1, ++ 0xDA, 0xF8, 0x44, 0x32, 0x29, 0x46, 0x58, 0x46, 0x42, 0x46, 0x98, 0x47, ++ 0x98, 0xF8, 0xC0, 0x34, 0x00, 0x2B, 0x93, 0xD0, 0xD0, 0x2F, 0x91, 0xD1, ++ 0xB1, 0x68, 0x63, 0x6B, 0x22, 0x8E, 0x40, 0x46, 0x0B, 0xF0, 0x5C, 0xFF, ++ 0x8A, 0xE7, 0x37, 0x4A, 0x25, 0xF0, 0x40, 0x05, 0x45, 0xF4, 0x00, 0x55, ++ 0xAA, 0x43, 0x65, 0x65, 0x82, 0xD1, 0x90, 0xE7, 0x10, 0xF4, 0x7C, 0x73, ++ 0x93, 0xD1, 0x32, 0x49, 0x34, 0x48, 0x40, 0xF2, 0xE3, 0x12, 0x1D, 0x46, ++ 0x10, 0xF0, 0xE0, 0xF9, 0x77, 0xE7, 0x25, 0xF0, 0x00, 0x75, 0x65, 0x65, ++ 0x01, 0x25, 0x28, 0x46, 0x07, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x2E, 0x48, ++ 0x00, 0x69, 0xC3, 0xF8, 0x58, 0x02, 0x90, 0xE7, 0x00, 0x9B, 0x03, 0xF0, ++ 0xFC, 0x03, 0x80, 0x2B, 0xED, 0xD1, 0xD3, 0x6A, 0x01, 0x93, 0x93, 0xF8, ++ 0x23, 0x20, 0x25, 0xF0, 0xFF, 0x73, 0x10, 0x32, 0x23, 0xF4, 0xC0, 0x33, ++ 0x43, 0xEA, 0xC2, 0x33, 0x63, 0x65, 0x86, 0xE7, 0x04, 0xF1, 0x14, 0x07, ++ 0x01, 0x9A, 0xDA, 0xF8, 0x98, 0x51, 0x05, 0x93, 0x41, 0x46, 0x05, 0xAB, ++ 0x38, 0x46, 0xA8, 0x47, 0xDA, 0xF8, 0x40, 0x32, 0x21, 0x8E, 0x05, 0x46, ++ 0x42, 0x46, 0x05, 0x98, 0x98, 0x47, 0xDA, 0xF8, 0x4C, 0x34, 0x40, 0x46, ++ 0x98, 0x47, 0x00, 0x2D, 0x3F, 0xF4, 0x41, 0xAF, 0xDA, 0xF8, 0xE4, 0x31, ++ 0x3A, 0x46, 0x31, 0x46, 0x40, 0x46, 0x98, 0x47, 0x39, 0xE7, 0x14, 0x4B, ++ 0x5A, 0x7F, 0x07, 0x2A, 0x7F, 0xF4, 0x34, 0xAF, 0x93, 0xF8, 0x24, 0x00, ++ 0x00, 0x28, 0x7F, 0xF4, 0x2F, 0xAF, 0x10, 0x4C, 0x10, 0x4D, 0x58, 0x77, ++ 0xD4, 0xE9, 0x00, 0x12, 0x22, 0xF4, 0x00, 0x72, 0x01, 0x20, 0x11, 0x43, ++ 0x62, 0x60, 0x29, 0x60, 0x83, 0xF8, 0x24, 0x00, 0x05, 0x46, 0x20, 0xE7, ++ 0x38, 0x36, 0x17, 0x00, 0x34, 0x36, 0x17, 0x00, 0x00, 0x20, 0x00, 0x02, ++ 0x70, 0x79, 0x15, 0x00, 0x10, 0x96, 0x15, 0x00, 0x68, 0x65, 0x17, 0x00, ++ 0x50, 0x90, 0x15, 0x00, 0x00, 0x10, 0x50, 0x40, 0x1C, 0x9E, 0x17, 0x00, ++ 0x98, 0x9C, 0x17, 0x00, 0x60, 0x00, 0x32, 0x40, 0x18, 0x88, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x10, 0xB5, 0x07, 0x4C, 0xA3, 0x7A, 0xE2, 0x7A, ++ 0x01, 0x33, 0xDB, 0xB2, 0x9A, 0x42, 0xA3, 0x72, 0x00, 0xD3, 0x10, 0xBD, ++ 0x10, 0xF0, 0xF6, 0xF9, 0x00, 0x23, 0xA3, 0x72, 0x10, 0xBD, 0x00, 0xBF, ++ 0x24, 0x65, 0x17, 0x00, 0x10, 0xB5, 0x10, 0x4C, 0xA3, 0x7A, 0xD3, 0xB9, ++ 0xE3, 0x7A, 0xA3, 0x72, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, ++ 0x72, 0xB6, 0x0C, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x0B, 0x4A, 0x0C, 0x4C, ++ 0x11, 0x68, 0x23, 0x68, 0x48, 0x1C, 0x23, 0xF4, 0x80, 0x73, 0x10, 0x60, ++ 0x23, 0x60, 0x28, 0xB1, 0x05, 0x4B, 0x11, 0x60, 0x1B, 0x68, 0x09, 0xB9, ++ 0x03, 0xB1, 0x62, 0xB6, 0x10, 0xBD, 0x10, 0xF0, 0xCF, 0xF9, 0xE1, 0xE7, ++ 0x24, 0x65, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x8C, 0x80, 0x32, 0x40, 0x08, 0xB5, 0x00, 0xF0, 0x29, 0xFC, 0xFF, 0xF7, ++ 0x93, 0xFB, 0xBD, 0xE8, 0x08, 0x40, 0x1A, 0xF0, 0x9F, 0xB8, 0x00, 0xBF, ++ 0x0A, 0x4A, 0x0B, 0x4B, 0x10, 0xB5, 0xD2, 0xE9, 0x20, 0x04, 0xD2, 0xE9, ++ 0x22, 0x12, 0x04, 0x44, 0x0A, 0x44, 0xC3, 0xE9, 0x01, 0x40, 0xC3, 0xE9, ++ 0x03, 0x12, 0x18, 0x60, 0x59, 0x61, 0xFF, 0xF7, 0x7D, 0xFB, 0xBD, 0xE8, ++ 0x10, 0x40, 0x1A, 0xF0, 0x89, 0xB8, 0x00, 0xBF, 0x2C, 0x19, 0x17, 0x00, ++ 0xEC, 0x34, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, 0xDF, 0xF8, 0x68, 0x81, ++ 0xDF, 0xF8, 0x68, 0x91, 0xDF, 0xF8, 0x68, 0xA1, 0xDF, 0xF8, 0x68, 0xB1, ++ 0x4D, 0x4F, 0x87, 0xB0, 0x00, 0x25, 0x3C, 0xE0, 0xDA, 0xF8, 0x00, 0x30, ++ 0xB3, 0xF5, 0x80, 0x1F, 0x4E, 0xD8, 0x20, 0x2D, 0x4C, 0xD0, 0x10, 0xF0, ++ 0x8D, 0xF9, 0x00, 0x28, 0x61, 0xD0, 0x1A, 0xF0, 0x81, 0xFC, 0x00, 0x28, ++ 0x5D, 0xD0, 0x62, 0x69, 0x5A, 0x45, 0x0E, 0xD0, 0x43, 0x4B, 0xB9, 0x68, ++ 0x1E, 0x68, 0x53, 0xF8, 0x04, 0x0C, 0x7B, 0x68, 0xCD, 0xE9, 0x02, 0x60, ++ 0xCD, 0xE9, 0x00, 0x31, 0x3F, 0x48, 0x3B, 0x68, 0x21, 0x46, 0x0F, 0xF0, ++ 0x97, 0xFE, 0x20, 0x46, 0x3D, 0x4E, 0x01, 0xF0, 0x41, 0xF9, 0x00, 0x22, ++ 0xD6, 0xF8, 0x94, 0x32, 0x8D, 0xF8, 0x17, 0x20, 0x0D, 0xF1, 0x17, 0x01, ++ 0x20, 0x46, 0x98, 0x47, 0x58, 0xBB, 0x9D, 0xF8, 0x17, 0x30, 0x73, 0xB3, ++ 0x36, 0x4B, 0x1B, 0x68, 0x1B, 0x78, 0x02, 0x2B, 0x31, 0xD0, 0x03, 0x2B, ++ 0x02, 0xD1, 0xD6, 0xF8, 0x8C, 0x32, 0x98, 0x47, 0x01, 0x35, 0x01, 0xF0, ++ 0x09, 0xF9, 0x4F, 0xF4, 0x80, 0x33, 0xC9, 0xF8, 0x00, 0x30, 0x04, 0x46, ++ 0x4F, 0xF4, 0x80, 0x10, 0x0E, 0xF0, 0x18, 0xFC, 0x98, 0xF8, 0xB8, 0x30, ++ 0x94, 0xB3, 0x00, 0x2B, 0xB2, 0xD1, 0xDA, 0xF8, 0x00, 0x30, 0xB3, 0xF5, ++ 0x80, 0x1F, 0x01, 0xD8, 0x03, 0x2D, 0xB2, 0xDD, 0x4F, 0xF4, 0x80, 0x10, ++ 0x0E, 0xF0, 0xE4, 0xFB, 0x07, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xD6, 0xF8, ++ 0xC8, 0x32, 0x20, 0x46, 0x98, 0x47, 0x00, 0x28, 0xD0, 0xD1, 0x20, 0x46, ++ 0x01, 0xF0, 0xC4, 0xF8, 0x1D, 0x4B, 0x1B, 0x68, 0x1B, 0x78, 0x02, 0x2B, ++ 0xCD, 0xD1, 0xD6, 0xF8, 0x90, 0x32, 0x98, 0x47, 0xCE, 0xE7, 0x1A, 0x4B, ++ 0x01, 0x22, 0x83, 0xF8, 0x45, 0x20, 0x1A, 0xF0, 0x1B, 0xFC, 0xB0, 0xFA, ++ 0x80, 0xF2, 0x17, 0x49, 0x52, 0x09, 0x4F, 0xF4, 0x80, 0x60, 0x0F, 0xF0, ++ 0x8D, 0xFE, 0x07, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x1B, 0xB1, 0x13, 0x4D, ++ 0x95, 0xF8, 0x21, 0x30, 0x3B, 0xB9, 0x12, 0x4A, 0x13, 0x68, 0x43, 0xF4, ++ 0x80, 0x33, 0x13, 0x60, 0x07, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xD5, 0xE9, ++ 0x05, 0x12, 0x28, 0x69, 0xF3, 0xF7, 0x5E, 0xFE, 0x6C, 0x61, 0xEC, 0x61, ++ 0x2C, 0x61, 0xAC, 0x61, 0x85, 0xF8, 0x21, 0x40, 0xEB, 0xE7, 0x00, 0xBF, ++ 0xEC, 0x34, 0x17, 0x00, 0xD4, 0x81, 0x32, 0x40, 0x3C, 0x96, 0x15, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x78, 0x36, 0x17, 0x00, 0xB0, 0xDE, 0x17, 0x00, ++ 0x28, 0x96, 0x15, 0x00, 0x30, 0x65, 0x17, 0x00, 0x80, 0x80, 0x32, 0x40, ++ 0x2C, 0x19, 0x17, 0x00, 0x7C, 0x80, 0x32, 0x40, 0x80, 0xB6, 0x17, 0x00, ++ 0x0D, 0xF0, 0xAD, 0xBA, 0x4F, 0xF4, 0x80, 0x00, 0x0E, 0xF0, 0x86, 0xBB, ++ 0x2D, 0xE9, 0xF8, 0x43, 0x30, 0x4D, 0x2C, 0x68, 0x4F, 0xF4, 0x80, 0x00, ++ 0x0E, 0xF0, 0xA2, 0xFB, 0x00, 0x2C, 0x31, 0xD0, 0xDF, 0xF8, 0xC4, 0x90, ++ 0x2C, 0x4F, 0x2E, 0x46, 0x4F, 0xF0, 0x01, 0x08, 0x23, 0x7C, 0xD9, 0x07, ++ 0x02, 0xD4, 0x2B, 0x89, 0x01, 0x33, 0x2B, 0x81, 0x30, 0x46, 0x0E, 0xF0, ++ 0x53, 0xFC, 0xEF, 0xF3, 0x10, 0x83, 0xDA, 0x07, 0x02, 0xD4, 0x72, 0xB6, ++ 0xC7, 0xF8, 0x00, 0x80, 0xD9, 0xF8, 0x00, 0x30, 0x62, 0x68, 0x01, 0x33, ++ 0x00, 0x21, 0xC9, 0xF8, 0x00, 0x30, 0x21, 0x74, 0x0A, 0xB1, 0xA0, 0x68, ++ 0x90, 0x47, 0xE0, 0x68, 0x08, 0xB1, 0x00, 0xF0, 0x77, 0xFB, 0xD9, 0xF8, ++ 0x00, 0x30, 0x33, 0xB1, 0x01, 0x3B, 0x3A, 0x68, 0xC9, 0xF8, 0x00, 0x30, ++ 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0x2C, 0x68, 0x00, 0x2C, 0xD3, 0xD1, ++ 0xAA, 0x7A, 0xEB, 0x7A, 0x9A, 0x42, 0x20, 0xD0, 0x13, 0x4B, 0x14, 0x48, ++ 0x1B, 0x69, 0x14, 0x4A, 0xC8, 0x33, 0x4F, 0xF4, 0x80, 0x71, 0x03, 0x60, ++ 0x11, 0x60, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, ++ 0x0B, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x0E, 0x4A, 0x0E, 0x4C, 0x11, 0x68, ++ 0x23, 0x68, 0x48, 0x1C, 0x43, 0xF4, 0x80, 0x73, 0x10, 0x60, 0x23, 0x60, ++ 0x28, 0xB1, 0x05, 0x4B, 0x11, 0x60, 0x1B, 0x68, 0x09, 0xB9, 0x03, 0xB1, ++ 0x62, 0xB6, 0xBD, 0xE8, 0xF8, 0x83, 0x00, 0xBF, 0x24, 0x65, 0x17, 0x00, ++ 0x38, 0x61, 0x17, 0x00, 0x00, 0x10, 0x50, 0x40, 0x48, 0x01, 0x32, 0x40, ++ 0x88, 0x80, 0x32, 0x40, 0x6C, 0x28, 0x17, 0x00, 0x8C, 0x80, 0x32, 0x40, ++ 0x2D, 0xE9, 0xF8, 0x43, 0x27, 0x4D, 0x2C, 0x68, 0x4F, 0xF4, 0x80, 0x00, ++ 0x0E, 0xF0, 0x30, 0xFB, 0x9C, 0xB3, 0xDF, 0xF8, 0x9C, 0x80, 0xDF, 0xF8, ++ 0x9C, 0x90, 0x00, 0x27, 0x2E, 0x46, 0x27, 0xE0, 0x01, 0x27, 0x30, 0x46, ++ 0x0E, 0xF0, 0xE6, 0xFB, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, ++ 0x72, 0xB6, 0x01, 0x23, 0xC8, 0xF8, 0x00, 0x30, 0xD9, 0xF8, 0x00, 0x30, ++ 0x62, 0x68, 0x01, 0x33, 0x00, 0x21, 0xC9, 0xF8, 0x00, 0x30, 0x21, 0x74, ++ 0x0A, 0xB1, 0xA0, 0x68, 0x90, 0x47, 0xE0, 0x68, 0x08, 0xB1, 0x00, 0xF0, ++ 0x09, 0xFB, 0xD9, 0xF8, 0x00, 0x30, 0x3B, 0xB1, 0x01, 0x3B, 0xD8, 0xF8, ++ 0x00, 0x20, 0xC9, 0xF8, 0x00, 0x30, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, ++ 0x2C, 0x68, 0x24, 0xB1, 0x23, 0x7C, 0xDA, 0x07, 0xD5, 0xD4, 0x00, 0x2F, ++ 0xD2, 0xD0, 0x0B, 0x4C, 0x94, 0xF8, 0x45, 0x30, 0x0B, 0xB9, 0xBD, 0xE8, ++ 0xF8, 0x83, 0x4F, 0xF4, 0x80, 0x10, 0x0E, 0xF0, 0xCD, 0xFA, 0x07, 0x49, ++ 0x4F, 0xF4, 0x80, 0x60, 0x0F, 0xF0, 0x94, 0xFD, 0x00, 0x23, 0x84, 0xF8, ++ 0x45, 0x30, 0xBD, 0xE8, 0xF8, 0x83, 0x00, 0xBF, 0x24, 0x65, 0x17, 0x00, ++ 0xB0, 0xDE, 0x17, 0x00, 0x88, 0x96, 0x15, 0x00, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x2D, 0xE9, 0xF8, 0x43, 0x2B, 0x4E, 0x34, 0x68, ++ 0x4F, 0xF4, 0x80, 0x00, 0x0E, 0xF0, 0xD4, 0xFA, 0x00, 0x2C, 0x3F, 0xD0, ++ 0x28, 0x4D, 0x2B, 0x88, 0x00, 0x2B, 0x3B, 0xD0, 0xDF, 0xF8, 0xA4, 0x80, ++ 0xDF, 0xF8, 0xA4, 0x90, 0x37, 0x46, 0x23, 0x7C, 0xD9, 0x07, 0x01, 0xD4, ++ 0x2B, 0x88, 0x6B, 0xB3, 0x38, 0x46, 0x0E, 0xF0, 0x83, 0xFB, 0xEF, 0xF3, ++ 0x10, 0x83, 0xDA, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x01, 0x23, 0xC8, 0xF8, ++ 0x00, 0x30, 0xD9, 0xF8, 0x00, 0x30, 0x22, 0x7C, 0x01, 0x33, 0xC9, 0xF8, ++ 0x00, 0x30, 0xD3, 0x07, 0x02, 0xD4, 0x2B, 0x88, 0x01, 0x3B, 0x2B, 0x80, ++ 0x63, 0x68, 0x00, 0x22, 0x22, 0x74, 0x0B, 0xB1, 0xA0, 0x68, 0x98, 0x47, ++ 0xE0, 0x68, 0x08, 0xB1, 0x00, 0xF0, 0xA0, 0xFA, 0xD9, 0xF8, 0x00, 0x30, ++ 0x3B, 0xB1, 0x01, 0x3B, 0xD8, 0xF8, 0x00, 0x20, 0xC9, 0xF8, 0x00, 0x30, ++ 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0x34, 0x68, 0x00, 0x2C, 0xCC, 0xD1, ++ 0x0B, 0x4C, 0x94, 0xF8, 0x45, 0x30, 0x0B, 0xB9, 0xBD, 0xE8, 0xF8, 0x83, ++ 0x4F, 0xF4, 0x80, 0x10, 0x0E, 0xF0, 0x68, 0xFA, 0x07, 0x49, 0x4F, 0xF4, ++ 0x80, 0x60, 0x0F, 0xF0, 0x2F, 0xFD, 0x00, 0x23, 0x84, 0xF8, 0x45, 0x30, ++ 0xBD, 0xE8, 0xF8, 0x83, 0x24, 0x65, 0x17, 0x00, 0x54, 0x28, 0x17, 0x00, ++ 0xB0, 0xDE, 0x17, 0x00, 0x88, 0x96, 0x15, 0x00, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0xF8, 0xB5, 0x0D, 0x4E, 0x35, 0x68, 0x95, 0xB1, ++ 0x34, 0x89, 0x01, 0x34, 0xA4, 0xB2, 0x37, 0x46, 0x38, 0x46, 0x0E, 0xF0, ++ 0x2D, 0xFB, 0x6B, 0x68, 0x0B, 0xB1, 0xA8, 0x68, 0x98, 0x47, 0x0F, 0xF0, ++ 0x99, 0xFF, 0x35, 0x68, 0x34, 0x81, 0x01, 0x34, 0xA4, 0xB2, 0x00, 0x2D, ++ 0xF0, 0xD1, 0xBD, 0xE8, 0xF8, 0x40, 0x00, 0xF0, 0xF5, 0xB9, 0x00, 0xBF, ++ 0x24, 0x65, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, 0x44, 0x4F, 0x06, 0x68, ++ 0x15, 0x88, 0xDF, 0xF8, 0x20, 0x91, 0xDF, 0xF8, 0x20, 0xA1, 0xDF, 0xF8, ++ 0x20, 0xB1, 0x85, 0xB0, 0x4F, 0xF0, 0x00, 0x08, 0xCD, 0xE9, 0x02, 0x02, ++ 0x87, 0xF8, 0x02, 0x80, 0xCD, 0xF8, 0x04, 0x80, 0x4A, 0xE0, 0xC4, 0x1A, ++ 0x2C, 0x44, 0x0C, 0x44, 0x55, 0x1B, 0xA9, 0xB2, 0xA4, 0xB2, 0x00, 0x25, ++ 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x36, 0x4A, ++ 0x01, 0x23, 0x13, 0x60, 0xBA, 0xF8, 0x00, 0x30, 0xDB, 0xF8, 0x00, 0x20, ++ 0xD9, 0xF8, 0x00, 0xC0, 0x00, 0x92, 0x02, 0xEB, 0xC3, 0x00, 0xB2, 0x68, ++ 0x42, 0x60, 0x00, 0x9A, 0x0C, 0xF1, 0x01, 0x0E, 0xC9, 0xF8, 0x00, 0xE0, ++ 0x42, 0xF8, 0x33, 0x10, 0xFA, 0x78, 0x01, 0x33, 0x01, 0x32, 0x88, 0x44, ++ 0xAA, 0xF8, 0x00, 0x30, 0xFA, 0x70, 0x64, 0xBB, 0xC3, 0x78, 0xA7, 0xF8, ++ 0x00, 0x80, 0x43, 0xF0, 0x04, 0x03, 0x01, 0x22, 0xC3, 0x70, 0xBA, 0x70, ++ 0xB8, 0x60, 0xBE, 0xF1, 0x00, 0x0F, 0x38, 0xD0, 0x21, 0x4B, 0xC9, 0xF8, ++ 0x00, 0xC0, 0x1B, 0x68, 0xBC, 0xF1, 0x00, 0x0F, 0x31, 0xD1, 0x00, 0x2B, ++ 0x2F, 0xD0, 0x62, 0xB6, 0x00, 0x2C, 0x2C, 0xD0, 0x1C, 0x4B, 0x1A, 0x68, ++ 0x73, 0x68, 0xB2, 0xF9, 0x00, 0x20, 0x00, 0x2A, 0x1A, 0xDB, 0x01, 0x96, ++ 0x21, 0x46, 0x1E, 0x46, 0xF3, 0x68, 0x30, 0x89, 0x01, 0x33, 0x9B, 0xB2, ++ 0x1A, 0x1A, 0x92, 0xB2, 0x4C, 0x19, 0x94, 0x42, 0xAB, 0xDA, 0x00, 0x24, ++ 0xB0, 0xE7, 0xBE, 0xF1, 0x00, 0x0F, 0xE7, 0xD0, 0x0F, 0x4B, 0xC9, 0xF8, ++ 0x00, 0xC0, 0x1B, 0x68, 0xBC, 0xF1, 0x00, 0x0F, 0xE0, 0xD1, 0x00, 0x2B, ++ 0xDB, 0xD1, 0xDD, 0xE7, 0x00, 0x2B, 0xE2, 0xD1, 0x0B, 0x49, 0x0C, 0x48, ++ 0x00, 0x93, 0x4F, 0xF4, 0x17, 0x72, 0x0F, 0xF0, 0xA9, 0xFE, 0x00, 0x9B, ++ 0xD9, 0xE7, 0x02, 0x9B, 0x01, 0x98, 0x1E, 0x60, 0x03, 0x9B, 0x1D, 0x80, ++ 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x00, 0xBF, 0x54, 0x65, 0x17, 0x00, ++ 0x38, 0x61, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0xA0, 0x96, 0x15, 0x00, 0x6C, 0x28, 0x17, 0x00, 0xB0, 0x56, 0x17, 0x00, ++ 0x54, 0x60, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, 0x41, 0x4F, 0xB2, 0xF8, ++ 0x00, 0xA0, 0x06, 0x68, 0xDF, 0xF8, 0x0C, 0xB1, 0x87, 0xB0, 0x4F, 0xF0, ++ 0x00, 0x08, 0xCD, 0xE9, 0x04, 0x02, 0x01, 0x22, 0x0B, 0x46, 0x87, 0xF8, ++ 0x20, 0x20, 0xC1, 0x46, 0xCD, 0xF8, 0x0C, 0x80, 0x39, 0xE0, 0x05, 0x44, ++ 0xAD, 0x1A, 0xA1, 0xEB, 0x0A, 0x03, 0xAD, 0xB2, 0x9B, 0xB2, 0x00, 0x2D, ++ 0x02, 0x93, 0x08, 0xBF, 0x4F, 0xF0, 0x01, 0x09, 0xF2, 0xF7, 0x3C, 0xFC, ++ 0x4F, 0xF0, 0x00, 0x0A, 0x02, 0x9B, 0x04, 0x46, 0x00, 0x28, 0x3A, 0xD0, ++ 0x7A, 0x68, 0x02, 0xB9, 0x38, 0x60, 0xDB, 0xF8, 0x00, 0x00, 0xF9, 0x68, ++ 0xB0, 0xF9, 0x00, 0x00, 0x19, 0x44, 0x01, 0x32, 0x00, 0x28, 0xF9, 0x60, ++ 0x7A, 0x60, 0xB1, 0x68, 0x36, 0xDB, 0xCD, 0xF8, 0x00, 0x90, 0x00, 0x22, ++ 0x20, 0x46, 0xF3, 0xF7, 0x6F, 0xFC, 0xB8, 0xF1, 0x00, 0x0F, 0x01, 0xD0, ++ 0xC8, 0xF8, 0x04, 0x40, 0xBC, 0x60, 0x05, 0xB3, 0xDB, 0xF8, 0x00, 0x20, ++ 0x73, 0x68, 0xB2, 0xF9, 0x00, 0x20, 0x00, 0x2A, 0x2E, 0xDB, 0x03, 0x96, ++ 0xA0, 0x46, 0x1E, 0x46, 0x2B, 0x46, 0xF2, 0x68, 0x35, 0x89, 0x01, 0x32, ++ 0x92, 0xB2, 0x51, 0x1B, 0x89, 0xB2, 0x03, 0xEB, 0x0A, 0x00, 0x88, 0x42, ++ 0xBB, 0xDA, 0x02, 0x93, 0xF2, 0xF7, 0x02, 0xFC, 0x00, 0x25, 0x02, 0x9B, ++ 0x4F, 0xF0, 0x01, 0x09, 0x04, 0x46, 0x00, 0x28, 0xC4, 0xD1, 0x87, 0xF8, ++ 0x20, 0x00, 0x04, 0x9B, 0x03, 0x98, 0x1E, 0x60, 0x05, 0x9B, 0xA3, 0xF8, ++ 0x00, 0xA0, 0x07, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x00, 0x29, 0xC6, 0xD1, ++ 0x0B, 0x49, 0x0C, 0x48, 0x02, 0x93, 0x40, 0xF2, 0x9E, 0x22, 0x0F, 0xF0, ++ 0x17, 0xFE, 0xB1, 0x68, 0x02, 0x9B, 0xBC, 0xE7, 0x00, 0x2B, 0xCE, 0xD1, ++ 0x05, 0x49, 0x07, 0x48, 0x02, 0x93, 0x40, 0xF2, 0xB3, 0x22, 0x0F, 0xF0, ++ 0x0B, 0xFE, 0x02, 0x9B, 0xC5, 0xE7, 0x00, 0xBF, 0x30, 0x65, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xAC, 0x96, 0x15, 0x00, 0xA0, 0x96, 0x15, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, 0xDF, 0xF8, 0x08, 0x91, ++ 0x07, 0x68, 0xD9, 0xF8, 0x00, 0x40, 0x1D, 0x88, 0x94, 0xF8, 0x00, 0xC0, ++ 0xDF, 0xF8, 0xFC, 0xA0, 0x85, 0xB0, 0xB1, 0xF5, 0xC8, 0x6F, 0x0E, 0x9E, ++ 0x03, 0x93, 0x06, 0xEB, 0x46, 0x06, 0x28, 0xBF, 0x4F, 0xF4, 0xC8, 0x61, ++ 0xBC, 0xF1, 0x03, 0x0F, 0x08, 0xBF, 0x34, 0x4B, 0x02, 0x90, 0x07, 0xEB, ++ 0x06, 0x16, 0x06, 0xF1, 0x14, 0x06, 0x90, 0x46, 0x08, 0xBF, 0x1E, 0x60, ++ 0x00, 0x20, 0x2C, 0xE0, 0xAE, 0xEB, 0x03, 0x04, 0x2C, 0x44, 0x0C, 0x44, ++ 0x52, 0x1B, 0xA4, 0xB2, 0x91, 0xB2, 0x00, 0x25, 0xBC, 0xF1, 0x03, 0x0F, ++ 0x0D, 0xD1, 0xB1, 0xF5, 0x00, 0x6F, 0x0B, 0x46, 0x28, 0xBF, 0x4F, 0xF4, ++ 0x00, 0x63, 0x43, 0xF0, 0x23, 0x43, 0x4F, 0xF0, 0x04, 0x12, 0xB3, 0x60, ++ 0xF1, 0x60, 0x31, 0x61, 0x72, 0x61, 0x88, 0x44, 0xA4, 0xB3, 0xDA, 0xF8, ++ 0x00, 0x20, 0x7B, 0x68, 0xB2, 0xF9, 0x00, 0x20, 0x00, 0x2A, 0x03, 0xF1, ++ 0x14, 0x0B, 0x1C, 0xDB, 0xBC, 0xF1, 0x03, 0x0F, 0x01, 0xD1, 0xC6, 0xF8, ++ 0x20, 0xB0, 0x38, 0x46, 0x5E, 0x46, 0x1F, 0x46, 0x21, 0x46, 0xD7, 0xE9, ++ 0x02, 0x43, 0x01, 0x33, 0x1F, 0xFA, 0x84, 0xFE, 0x9B, 0xB2, 0xA3, 0xEB, ++ 0x0E, 0x02, 0x05, 0xEB, 0x04, 0x0B, 0x92, 0xB2, 0x4C, 0x19, 0x94, 0x42, ++ 0xC6, 0xF8, 0x04, 0x80, 0xC6, 0xF8, 0x00, 0xB0, 0xC0, 0xDA, 0x00, 0x24, ++ 0xC6, 0xE7, 0x00, 0x2B, 0xE0, 0xD1, 0x4F, 0xF4, 0x4A, 0x72, 0x0D, 0x49, ++ 0x0D, 0x48, 0x01, 0x93, 0x0F, 0xF0, 0x90, 0xFD, 0xD9, 0xF8, 0x00, 0x20, ++ 0x01, 0x9B, 0x92, 0xF8, 0x00, 0xC0, 0xD3, 0xE7, 0xBC, 0xF1, 0x03, 0x0F, ++ 0x02, 0xD1, 0x05, 0x4B, 0x34, 0x62, 0x5E, 0x60, 0x02, 0x9B, 0x1F, 0x60, ++ 0x03, 0x9B, 0x1D, 0x80, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x00, 0xBF, ++ 0x60, 0x65, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0xA0, 0x96, 0x15, 0x00, ++ 0x78, 0x36, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, 0x61, 0xB3, 0x0B, 0x8A, ++ 0xDA, 0x07, 0x12, 0xD4, 0x16, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x20, ++ 0x02, 0xE0, 0x0B, 0x8A, 0xDB, 0x07, 0x0A, 0xD4, 0x00, 0x2A, 0x49, 0x68, ++ 0xF9, 0xDA, 0x00, 0x29, 0xF7, 0xD1, 0x11, 0x49, 0x11, 0x48, 0x40, 0xF2, ++ 0xE6, 0x32, 0x0F, 0xF0, 0x29, 0xBD, 0xCB, 0x68, 0x23, 0xF0, 0x03, 0x03, ++ 0x04, 0x33, 0x0E, 0x49, 0x4A, 0x68, 0x9A, 0x42, 0x8A, 0x68, 0x08, 0xBF, ++ 0x0B, 0x68, 0xC0, 0xF8, 0x98, 0x30, 0x22, 0xF0, 0x00, 0x40, 0x83, 0x42, ++ 0x02, 0xF0, 0x00, 0x42, 0x38, 0xBF, 0x02, 0xF1, 0x00, 0x42, 0x13, 0x43, ++ 0x8B, 0x60, 0x70, 0x47, 0x00, 0xF1, 0xA0, 0x03, 0xE9, 0xE7, 0x00, 0xBF, ++ 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0xA0, 0x96, 0x15, 0x00, ++ 0xEC, 0x34, 0x17, 0x00, 0x18, 0x4B, 0x19, 0x4A, 0x18, 0x68, 0x19, 0x49, ++ 0xDF, 0xF8, 0x7C, 0xC0, 0xF0, 0xB5, 0xD0, 0xE9, 0x00, 0x34, 0x17, 0x4D, ++ 0x13, 0x60, 0x1C, 0x44, 0x2B, 0x60, 0x25, 0x1F, 0x0D, 0x60, 0x15, 0x4E, ++ 0x15, 0x4D, 0x11, 0x68, 0x31, 0x60, 0x29, 0x60, 0xD0, 0xE9, 0x02, 0x10, ++ 0xDF, 0xF8, 0x5C, 0xE0, 0x12, 0x4F, 0x54, 0x60, 0x08, 0x44, 0x69, 0x60, ++ 0x11, 0x4C, 0x93, 0x60, 0x11, 0x4E, 0x03, 0x1F, 0xCE, 0xF8, 0x00, 0x30, ++ 0xCC, 0xF8, 0x00, 0x10, 0x39, 0x60, 0x6E, 0x61, 0x23, 0x68, 0x10, 0x61, ++ 0x03, 0xF4, 0x00, 0x23, 0x43, 0xF4, 0xF0, 0x23, 0x43, 0xF0, 0x25, 0x03, ++ 0xD1, 0x60, 0x51, 0x61, 0x23, 0x60, 0xF0, 0xBD, 0x30, 0x36, 0x17, 0x00, ++ 0xEC, 0x34, 0x17, 0x00, 0xCC, 0x81, 0x32, 0x40, 0xC8, 0x81, 0x32, 0x40, ++ 0xD0, 0x81, 0x32, 0x40, 0xD4, 0x81, 0x32, 0x40, 0xE4, 0x81, 0x32, 0x40, ++ 0x0C, 0x01, 0x32, 0x40, 0x05, 0x12, 0x00, 0x0C, 0xE0, 0x81, 0x32, 0x40, ++ 0xDC, 0x81, 0x32, 0x40, 0x10, 0xB4, 0x0A, 0x4C, 0x0A, 0x49, 0x22, 0x68, ++ 0x83, 0x02, 0x03, 0xF4, 0x80, 0x63, 0x22, 0xF4, 0x80, 0x62, 0x13, 0x43, ++ 0x23, 0x60, 0x0B, 0x68, 0x5D, 0xF8, 0x04, 0x4B, 0xC0, 0x04, 0x00, 0xF4, ++ 0x00, 0x20, 0x23, 0xF4, 0x00, 0x23, 0x18, 0x43, 0x08, 0x60, 0x70, 0x47, ++ 0x24, 0x03, 0x32, 0x40, 0x0C, 0x01, 0x32, 0x40, 0x90, 0xF8, 0x9C, 0x20, ++ 0xD0, 0xF8, 0x98, 0x30, 0x6A, 0xB9, 0x0E, 0x4A, 0x12, 0x68, 0x22, 0xF0, ++ 0x00, 0x41, 0x8B, 0x42, 0x02, 0xF0, 0x00, 0x42, 0x0A, 0x49, 0x38, 0xBF, ++ 0x02, 0xF1, 0x00, 0x42, 0x13, 0x43, 0x0B, 0x60, 0x70, 0x47, 0x08, 0x4A, ++ 0x12, 0x68, 0x22, 0xF0, 0x00, 0x41, 0x8B, 0x42, 0x02, 0xF0, 0x00, 0x42, ++ 0x04, 0x49, 0x38, 0xBF, 0x02, 0xF1, 0x00, 0x42, 0x13, 0x43, 0x0B, 0x60, ++ 0x70, 0x47, 0x00, 0xBF, 0xD0, 0x81, 0x32, 0x40, 0xE0, 0x81, 0x32, 0x40, ++ 0x10, 0xB5, 0x03, 0x8E, 0x82, 0xB0, 0xC3, 0xB1, 0x2D, 0x4B, 0xC4, 0x69, ++ 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x38, 0xDB, 0xA3, 0x68, ++ 0x42, 0x6D, 0x1B, 0x88, 0x03, 0xF0, 0xFC, 0x03, 0x24, 0x2B, 0x43, 0xD0, ++ 0x94, 0x2B, 0x03, 0xD1, 0x42, 0xF2, 0x02, 0x03, 0x93, 0x43, 0x36, 0xD0, ++ 0xE3, 0x68, 0x23, 0xF0, 0x03, 0x03, 0x04, 0x33, 0x07, 0xE0, 0x21, 0x4B, ++ 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x18, 0xDB, 0x00, 0xF1, ++ 0xA0, 0x03, 0x1E, 0x49, 0x0A, 0x69, 0x9A, 0x42, 0x4A, 0x69, 0x08, 0xBF, ++ 0xCB, 0x68, 0xC0, 0xF8, 0x98, 0x30, 0x22, 0xF0, 0x00, 0x44, 0xA3, 0x42, ++ 0x02, 0xF0, 0x00, 0x42, 0x38, 0xBF, 0x02, 0xF1, 0x00, 0x42, 0x13, 0x43, ++ 0x4B, 0x61, 0x02, 0xB0, 0xBD, 0xE8, 0x10, 0x40, 0xFF, 0xF7, 0x9E, 0xBF, ++ 0xC3, 0x69, 0x00, 0x2B, 0xE3, 0xD0, 0x12, 0x49, 0x12, 0x48, 0x4F, 0xF4, ++ 0xD7, 0x72, 0x05, 0xE0, 0x00, 0x2C, 0xC4, 0xD1, 0x0E, 0x49, 0x10, 0x48, ++ 0x4F, 0xF4, 0xC2, 0x72, 0x02, 0xB0, 0xBD, 0xE8, 0x10, 0x40, 0x0F, 0xF0, ++ 0x2F, 0xBC, 0x0D, 0x4B, 0x01, 0x90, 0xD3, 0xF8, 0x74, 0x33, 0x98, 0x47, ++ 0x01, 0x98, 0xC1, 0xE7, 0x93, 0x04, 0xBF, 0xD5, 0x08, 0x4B, 0x01, 0x90, ++ 0xD3, 0xF8, 0xFC, 0x33, 0x98, 0x47, 0x01, 0x98, 0xB8, 0xE7, 0x00, 0xBF, ++ 0x38, 0x36, 0x17, 0x00, 0xEC, 0x34, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0xC8, 0x96, 0x15, 0x00, 0xA0, 0x96, 0x15, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x00, 0x29, 0x46, 0xD0, 0x2D, 0xE9, 0xF8, 0x4F, 0x07, 0x46, 0xDF, 0xF8, ++ 0x8C, 0xA0, 0xDF, 0xF8, 0x8C, 0xB0, 0x08, 0x46, 0x1F, 0x49, 0x99, 0x46, ++ 0x4F, 0xF0, 0x00, 0x08, 0xD7, 0xE9, 0x02, 0x45, 0x01, 0x35, 0xAB, 0xB2, ++ 0xA6, 0xB2, 0x9D, 0x1B, 0xAD, 0xB2, 0xAD, 0x1A, 0xA8, 0x42, 0x23, 0xDB, ++ 0xF6, 0x1A, 0x16, 0x44, 0x06, 0x44, 0xB6, 0xB2, 0xA8, 0xB2, 0xC5, 0x1C, ++ 0x4F, 0xEA, 0x98, 0x03, 0xAD, 0x08, 0x14, 0x44, 0x09, 0xEB, 0x83, 0x03, ++ 0x08, 0xD0, 0x1A, 0x46, 0x03, 0xEB, 0x85, 0x05, 0xE3, 0x1A, 0xD4, 0x58, ++ 0x42, 0xF8, 0x04, 0x4B, 0xAA, 0x42, 0xFA, 0xD1, 0xBE, 0xB1, 0xDA, 0xF8, ++ 0x00, 0x30, 0x7F, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x80, 0x44, 0x00, 0x2B, ++ 0x1F, 0xFA, 0x88, 0xF8, 0x04, 0xDB, 0x30, 0x46, 0x00, 0x22, 0xD1, 0xE7, ++ 0x00, 0x26, 0xDE, 0xE7, 0x00, 0x2F, 0xF8, 0xD1, 0x40, 0xF2, 0x2D, 0x42, ++ 0x58, 0x46, 0x0F, 0xF0, 0xFF, 0xFB, 0x02, 0x49, 0xF1, 0xE7, 0xBD, 0xE8, ++ 0xF8, 0x8F, 0x70, 0x47, 0x70, 0x79, 0x15, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0xEC, 0x96, 0x15, 0x00, 0x38, 0xB5, 0x13, 0x4C, 0x94, 0xF8, 0x21, 0x30, ++ 0xA3, 0xB9, 0x20, 0x61, 0x11, 0x48, 0xE3, 0x69, 0xE2, 0x68, 0x61, 0x69, ++ 0x65, 0x68, 0x90, 0xF8, 0xB9, 0x00, 0x13, 0x44, 0x29, 0x44, 0xA2, 0x68, ++ 0x61, 0x61, 0x01, 0x25, 0xB3, 0xEB, 0x40, 0x2F, 0xE3, 0x61, 0x84, 0xF8, ++ 0x21, 0x50, 0xA2, 0x61, 0x03, 0xD2, 0x38, 0xBD, 0xA3, 0x69, 0x58, 0x60, ++ 0xE8, 0xE7, 0x20, 0x69, 0xF3, 0xF7, 0x90, 0xF9, 0x00, 0x23, 0xC4, 0xE9, ++ 0x04, 0x33, 0xC4, 0xE9, 0x06, 0x33, 0x84, 0xF8, 0x21, 0x30, 0x38, 0xBD, ++ 0x30, 0x65, 0x17, 0x00, 0x2C, 0x19, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x47, ++ 0xAB, 0x4E, 0xD0, 0xF8, 0x1C, 0xC0, 0x35, 0x68, 0x86, 0xB0, 0x04, 0x46, ++ 0xCD, 0xF8, 0x14, 0xC0, 0xAD, 0xF8, 0x0E, 0x30, 0x2B, 0x78, 0x02, 0x2B, ++ 0x91, 0x46, 0x00, 0xF0, 0xAD, 0x80, 0x01, 0x2B, 0xDF, 0xF8, 0xC4, 0x82, ++ 0x22, 0xD0, 0x01, 0x20, 0x00, 0x23, 0xD8, 0xF8, 0xAC, 0x52, 0x4A, 0x46, ++ 0xCD, 0xE9, 0x00, 0x30, 0x0D, 0xF1, 0x0E, 0x03, 0x05, 0xA8, 0xA8, 0x47, ++ 0x33, 0x68, 0x1B, 0x78, 0x02, 0x2B, 0x05, 0x46, 0x1F, 0xD0, 0x01, 0x2B, ++ 0x59, 0xD0, 0xD8, 0xF8, 0x98, 0x32, 0x05, 0x99, 0x20, 0x46, 0x2A, 0x46, ++ 0x98, 0x47, 0x0E, 0x9B, 0x63, 0x60, 0x0F, 0x9B, 0x95, 0x48, 0xA3, 0x60, ++ 0x21, 0x46, 0x0D, 0xF0, 0x3F, 0xFF, 0x06, 0xB0, 0xBD, 0xE8, 0xF0, 0x87, ++ 0xD8, 0xF8, 0xB0, 0x52, 0x00, 0x23, 0x00, 0x93, 0x0D, 0xF1, 0x0E, 0x02, ++ 0x05, 0xA8, 0xA8, 0x47, 0x33, 0x68, 0x1B, 0x78, 0x02, 0x2B, 0x05, 0x46, ++ 0xDF, 0xD1, 0xDF, 0xF8, 0x64, 0x92, 0x99, 0xF8, 0x02, 0x30, 0x00, 0x2B, ++ 0xDB, 0xD0, 0xB9, 0xF8, 0x00, 0x30, 0x7A, 0x68, 0x3A, 0x33, 0xBB, 0x60, ++ 0xD3, 0x78, 0x6F, 0xF3, 0x87, 0x13, 0xD3, 0x70, 0x99, 0xF8, 0x03, 0x30, ++ 0xBB, 0x73, 0x00, 0x23, 0x3B, 0x60, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, ++ 0x03, 0xD4, 0x72, 0xB6, 0x7F, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0xDF, 0xF8, ++ 0x20, 0xA2, 0x7E, 0x48, 0xDA, 0xF8, 0x00, 0x30, 0x39, 0x46, 0x01, 0x33, ++ 0xCA, 0xF8, 0x00, 0x30, 0x0D, 0xF0, 0x08, 0xFF, 0xD8, 0xF8, 0x44, 0x34, ++ 0x98, 0x47, 0xDA, 0xF8, 0x00, 0x30, 0x3B, 0xB1, 0x75, 0x4A, 0x01, 0x3B, ++ 0x12, 0x68, 0xCA, 0xF8, 0x00, 0x30, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, ++ 0x00, 0x23, 0xC9, 0xE9, 0x00, 0x33, 0x32, 0x68, 0x13, 0x78, 0x01, 0x2B, ++ 0xA5, 0xD1, 0xF2, 0xF7, 0x15, 0xF9, 0x07, 0x46, 0x00, 0x28, 0x00, 0xF0, ++ 0x92, 0x80, 0x6D, 0x4E, 0x96, 0xF8, 0x20, 0x30, 0x00, 0x2B, 0x00, 0xF0, ++ 0x96, 0x80, 0x73, 0x68, 0x81, 0x68, 0x32, 0x68, 0x03, 0xF1, 0x01, 0x0C, ++ 0x4F, 0xEA, 0x0C, 0x63, 0x21, 0xF0, 0xFE, 0x41, 0x03, 0xF0, 0xFE, 0x43, ++ 0x0B, 0x43, 0x00, 0x21, 0x83, 0x60, 0x00, 0x91, 0x3A, 0x23, 0x04, 0xF1, ++ 0x30, 0x01, 0xC6, 0xF8, 0x04, 0xC0, 0xF3, 0xF7, 0x43, 0xF9, 0x60, 0x4A, ++ 0xF3, 0x68, 0x92, 0xF8, 0xB8, 0x20, 0x3A, 0x33, 0xF3, 0x60, 0x38, 0x46, ++ 0x00, 0x2A, 0x40, 0xF0, 0xA7, 0x80, 0xD6, 0xE9, 0x01, 0x12, 0xF3, 0xF7, ++ 0xD3, 0xF8, 0x5A, 0x49, 0x0A, 0x78, 0x00, 0x23, 0x42, 0xF0, 0x01, 0x02, ++ 0x0A, 0x70, 0x73, 0x60, 0xF3, 0x60, 0x33, 0x60, 0xB3, 0x60, 0x86, 0xF8, ++ 0x20, 0x30, 0x68, 0xE7, 0x54, 0x4D, 0x42, 0xF2, 0x24, 0x03, 0xEA, 0x58, ++ 0x00, 0x2A, 0x68, 0xD0, 0xEF, 0xF3, 0x10, 0x83, 0xDA, 0x07, 0x03, 0xD4, ++ 0x72, 0xB6, 0x4A, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x42, 0xF2, 0x34, 0x02, ++ 0xDF, 0xF8, 0x44, 0x81, 0xA8, 0x5A, 0xD8, 0xF8, 0x00, 0x30, 0x02, 0x91, ++ 0x01, 0x33, 0xB0, 0xF5, 0xC3, 0x7F, 0xC8, 0xF8, 0x00, 0x30, 0x48, 0x48, ++ 0xDF, 0xF8, 0x3C, 0xA1, 0x84, 0xBF, 0x00, 0x23, 0xAB, 0x52, 0x0D, 0xF0, ++ 0xD7, 0xFE, 0x45, 0x4A, 0x02, 0x99, 0xD2, 0xF8, 0x00, 0xC0, 0x42, 0xF2, ++ 0x34, 0x0E, 0x07, 0x46, 0x35, 0xF8, 0x0E, 0x30, 0xBB, 0x81, 0x0C, 0xEB, ++ 0xC3, 0x00, 0x04, 0xF1, 0x30, 0x02, 0x42, 0x60, 0x4C, 0xF8, 0x33, 0xA0, ++ 0xDF, 0xF8, 0x08, 0xC1, 0x78, 0x60, 0x95, 0xF8, 0x02, 0xAC, 0x9C, 0xF8, ++ 0x03, 0x00, 0xD8, 0xF8, 0x00, 0x20, 0x01, 0x33, 0x0A, 0xF1, 0x01, 0x0A, ++ 0x01, 0x30, 0x25, 0xF8, 0x0E, 0x30, 0x85, 0xF8, 0x02, 0xAC, 0x8C, 0xF8, ++ 0x03, 0x00, 0x3A, 0xB1, 0x2B, 0x4B, 0x01, 0x3A, 0x1B, 0x68, 0xC8, 0xF8, ++ 0x00, 0x20, 0x0A, 0xB9, 0x00, 0x2B, 0x48, 0xD1, 0x33, 0x68, 0x1B, 0x78, ++ 0x02, 0x2B, 0x7F, 0xF4, 0xFE, 0xAE, 0xDF, 0xF8, 0xC4, 0x80, 0x00, 0x23, ++ 0xD8, 0xF8, 0xB4, 0x52, 0x21, 0xE7, 0x23, 0x7C, 0x29, 0x48, 0x43, 0xF0, ++ 0x01, 0x03, 0x23, 0x74, 0x0F, 0xF0, 0x2E, 0xF8, 0x20, 0x4B, 0x83, 0xF8, ++ 0x20, 0x70, 0x26, 0x49, 0x4F, 0xF4, 0x80, 0x60, 0x0F, 0xF0, 0x76, 0xF8, ++ 0x23, 0x7C, 0x43, 0xF0, 0x01, 0x03, 0x23, 0x74, 0xF9, 0xE6, 0x03, 0x7C, ++ 0xDF, 0xF8, 0x8C, 0x80, 0x43, 0xF0, 0x01, 0x03, 0x03, 0x74, 0xD8, 0xF8, ++ 0x98, 0x32, 0x61, 0x46, 0x98, 0x47, 0xEF, 0xF3, 0x10, 0x83, 0xD9, 0x07, ++ 0x03, 0xD4, 0x72, 0xB6, 0x10, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x19, 0x4C, ++ 0xD8, 0xF8, 0x44, 0x24, 0x23, 0x68, 0x01, 0x33, 0x23, 0x60, 0x90, 0x47, ++ 0x23, 0x68, 0x01, 0x46, 0x33, 0xB1, 0x0A, 0x4A, 0x01, 0x3B, 0x12, 0x68, ++ 0x23, 0x60, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0x11, 0x48, 0xF0, 0xF7, ++ 0x31, 0xFE, 0xE0, 0xE6, 0xFF, 0xF7, 0x7E, 0xFE, 0x59, 0xE7, 0x62, 0xB6, ++ 0xB4, 0xE7, 0x00, 0xBF, 0x78, 0x36, 0x17, 0x00, 0x24, 0x65, 0x17, 0x00, ++ 0x38, 0x61, 0x17, 0x00, 0xA8, 0x56, 0x17, 0x00, 0x30, 0x65, 0x17, 0x00, ++ 0x2C, 0x19, 0x17, 0x00, 0x9C, 0x4E, 0x17, 0x00, 0x7C, 0x36, 0x17, 0x00, ++ 0xA0, 0x56, 0x17, 0x00, 0x54, 0x60, 0x17, 0x00, 0x0C, 0x97, 0x15, 0x00, ++ 0x20, 0x97, 0x15, 0x00, 0x6C, 0x28, 0x17, 0x00, 0xF8, 0x96, 0x15, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x54, 0x65, 0x17, 0x00, 0x3C, 0x00, 0x00, 0xC0, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0xAE, 0x4B, 0xDF, 0xF8, 0x00, 0xA3, 0xC1, 0x69, ++ 0x9A, 0xF8, 0x32, 0x20, 0x1B, 0x68, 0x87, 0xB0, 0x04, 0x46, 0x05, 0x91, ++ 0xAD, 0xF8, 0x12, 0x20, 0x1B, 0x78, 0x03, 0x2B, 0x00, 0xF0, 0x3F, 0x81, ++ 0x02, 0x2B, 0x77, 0xD0, 0xA6, 0x4A, 0x27, 0x8E, 0x12, 0x68, 0xB2, 0xF9, ++ 0x00, 0x20, 0x00, 0x2A, 0xC0, 0xF2, 0xBF, 0x80, 0x01, 0x2B, 0xA3, 0x4E, ++ 0x4F, 0xF0, 0x00, 0x03, 0x00, 0xF0, 0x3A, 0x81, 0xCD, 0xE9, 0x00, 0x33, ++ 0x39, 0x46, 0xD6, 0xF8, 0xAC, 0x52, 0x0D, 0xF1, 0x12, 0x03, 0x5A, 0x46, ++ 0x05, 0xA8, 0xA8, 0x47, 0x07, 0xEB, 0x0B, 0x01, 0xCA, 0xF8, 0x1C, 0x10, ++ 0x07, 0x46, 0x00, 0x21, 0x04, 0xF1, 0x58, 0x00, 0xEB, 0xF7, 0x7E, 0xFD, ++ 0x94, 0x4B, 0x1B, 0x68, 0x1B, 0x78, 0x03, 0x2B, 0x00, 0xF0, 0xB8, 0x80, ++ 0x01, 0x2B, 0x00, 0xF0, 0x49, 0x81, 0x02, 0x2B, 0x41, 0xD1, 0xDF, 0xF8, ++ 0x88, 0xA2, 0x9A, 0xF8, 0x02, 0x30, 0x00, 0x2B, 0x3B, 0xD0, 0xBA, 0xF8, ++ 0x00, 0x30, 0xD8, 0xF8, 0x04, 0x20, 0x3A, 0x33, 0xC8, 0xF8, 0x08, 0x30, ++ 0xD3, 0x78, 0x6F, 0xF3, 0x87, 0x13, 0xD3, 0x70, 0x9A, 0xF8, 0x03, 0x30, ++ 0x88, 0xF8, 0x0E, 0x30, 0x00, 0x23, 0xC8, 0xF8, 0x00, 0x30, 0xEF, 0xF3, ++ 0x10, 0x83, 0xDD, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x83, 0x4B, 0x01, 0x22, ++ 0x1A, 0x60, 0xDF, 0xF8, 0x14, 0xB2, 0x82, 0x48, 0xDB, 0xF8, 0x00, 0x30, ++ 0x41, 0x46, 0x01, 0x33, 0xCB, 0xF8, 0x00, 0x30, 0x0D, 0xF0, 0x8C, 0xFD, ++ 0xD6, 0xF8, 0x44, 0x34, 0x98, 0x47, 0xDB, 0xF8, 0x00, 0x30, 0x3B, 0xB1, ++ 0x79, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0xCB, 0xF8, 0x00, 0x30, 0x0B, 0xB9, ++ 0x02, 0xB1, 0x62, 0xB6, 0x72, 0x4B, 0x1A, 0x68, 0x00, 0x23, 0xCA, 0xE9, ++ 0x00, 0x33, 0x13, 0x78, 0x03, 0x2B, 0x00, 0xF0, 0x9E, 0x81, 0xD6, 0xF8, ++ 0x98, 0x32, 0x05, 0x99, 0x3A, 0x46, 0x20, 0x46, 0x98, 0x47, 0x07, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x8F, 0x6E, 0x4E, 0x42, 0xF2, 0x24, 0x03, 0xF2, 0x58, ++ 0x00, 0x2A, 0x00, 0xF0, 0x60, 0x81, 0xEF, 0xF3, 0x10, 0x83, 0xDF, 0x07, ++ 0x03, 0xD4, 0x72, 0xB6, 0x66, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x42, 0xF2, ++ 0x34, 0x02, 0x67, 0x4F, 0xB1, 0x5A, 0x3B, 0x68, 0x66, 0x48, 0x01, 0x33, ++ 0xB1, 0xF5, 0xC3, 0x7F, 0x3B, 0x60, 0x84, 0xBF, 0x00, 0x23, 0xB3, 0x52, ++ 0x0D, 0xF0, 0x92, 0xFD, 0x62, 0x4A, 0x42, 0xF2, 0x34, 0x0E, 0xD2, 0xF8, ++ 0x00, 0xC0, 0x36, 0xF8, 0x0E, 0x30, 0x83, 0x81, 0x0C, 0xEB, 0xC3, 0x01, ++ 0x04, 0xF1, 0x30, 0x02, 0x4A, 0x60, 0x5D, 0x4A, 0x4C, 0xF8, 0x33, 0x20, ++ 0xDF, 0xF8, 0x94, 0xC1, 0x41, 0x60, 0x96, 0xF8, 0x02, 0x1C, 0x9C, 0xF8, ++ 0x03, 0x20, 0x80, 0x46, 0x38, 0x68, 0x01, 0x33, 0x01, 0x31, 0x01, 0x32, ++ 0x26, 0xF8, 0x0E, 0x30, 0x86, 0xF8, 0x02, 0x1C, 0x8C, 0xF8, 0x03, 0x20, ++ 0x30, 0xB1, 0x4C, 0x4B, 0x01, 0x38, 0x1B, 0x68, 0x38, 0x60, 0x08, 0xB9, ++ 0x03, 0xB1, 0x62, 0xB6, 0x46, 0x4B, 0x27, 0x8E, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0x06, 0xDA, 0x00, 0x2F, 0x00, 0xF0, 0x07, 0x81, ++ 0xB7, 0xF5, 0x40, 0x5F, 0x00, 0xF2, 0x0A, 0x81, 0x3E, 0x4B, 0x1B, 0x68, ++ 0x1B, 0x78, 0x02, 0x2B, 0x7F, 0xF4, 0x34, 0xAF, 0x3D, 0x4E, 0x39, 0x46, ++ 0xD6, 0xF8, 0xB4, 0x72, 0x00, 0x23, 0x00, 0x93, 0x0D, 0xF1, 0x12, 0x02, ++ 0x05, 0xA8, 0xB8, 0x47, 0x07, 0x46, 0x3C, 0xE7, 0x3F, 0x4A, 0x40, 0x48, ++ 0x53, 0x68, 0x60, 0x66, 0x04, 0xF1, 0x30, 0x00, 0xA0, 0x66, 0x04, 0xF1, ++ 0x68, 0x00, 0x3D, 0x49, 0xC4, 0xF8, 0x6C, 0x90, 0x18, 0x62, 0x3A, 0x23, ++ 0x21, 0x67, 0x63, 0x67, 0x4F, 0xF0, 0x04, 0x11, 0xA3, 0x67, 0x00, 0x23, ++ 0x03, 0x90, 0xE1, 0x67, 0xC4, 0xF8, 0x88, 0x30, 0x10, 0x68, 0x03, 0x99, ++ 0x05, 0x22, 0xF0, 0xF7, 0xC5, 0xF9, 0x34, 0x4A, 0x13, 0x68, 0x18, 0x05, ++ 0xFC, 0xD5, 0x13, 0x68, 0x59, 0x03, 0x03, 0xD5, 0x11, 0x68, 0x41, 0xF0, ++ 0x80, 0x61, 0x11, 0x60, 0x1A, 0x05, 0x21, 0xD5, 0xEF, 0xF3, 0x05, 0x80, ++ 0x2D, 0x49, 0x41, 0xF2, 0x4C, 0x12, 0x8B, 0x58, 0x43, 0xF0, 0x00, 0x63, ++ 0x8B, 0x50, 0x00, 0x28, 0x40, 0xF0, 0xF3, 0x80, 0xEF, 0xF3, 0x10, 0x83, ++ 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x1B, 0x4B, 0x01, 0x22, 0x1A, 0x60, ++ 0x1C, 0x4B, 0x25, 0x48, 0x19, 0x68, 0x00, 0x25, 0x4A, 0x1C, 0x1A, 0x60, ++ 0x45, 0x61, 0x2A, 0xB1, 0x15, 0x4A, 0x19, 0x60, 0x13, 0x68, 0x09, 0xB9, ++ 0x03, 0xB1, 0x62, 0xB6, 0x1F, 0x4D, 0x2B, 0x68, 0x00, 0x2B, 0xFC, 0xD0, ++ 0x1E, 0x4B, 0x18, 0x68, 0xA9, 0xF1, 0x14, 0x01, 0x00, 0xF5, 0x0B, 0x70, ++ 0x0D, 0xF0, 0xAC, 0xFC, 0x01, 0x23, 0x2B, 0x60, 0xEF, 0xF7, 0x2E, 0xFD, ++ 0x31, 0xE7, 0x0A, 0xF1, 0x40, 0x00, 0x0F, 0xF0, 0x67, 0xF9, 0x05, 0x4B, ++ 0x1B, 0x68, 0x81, 0x46, 0x1B, 0x78, 0x00, 0xF1, 0x3C, 0x0B, 0xB5, 0xE6, ++ 0x39, 0x46, 0xD6, 0xF8, 0xB0, 0x72, 0x8C, 0xE7, 0x78, 0x36, 0x17, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, ++ 0xA8, 0x56, 0x17, 0x00, 0x7C, 0x36, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0xA0, 0x56, 0x17, 0x00, 0x54, 0x60, 0x17, 0x00, 0x3C, 0x00, 0x00, 0xC0, ++ 0x60, 0x65, 0x17, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0x3A, 0x00, 0x00, 0xA3, ++ 0x4C, 0x11, 0x07, 0x40, 0x00, 0x00, 0x07, 0x40, 0x48, 0x35, 0x17, 0x00, ++ 0x54, 0x40, 0x04, 0x40, 0x00, 0x38, 0x18, 0x00, 0xB0, 0xDE, 0x17, 0x00, ++ 0x54, 0x65, 0x17, 0x00, 0xF1, 0xF7, 0x92, 0xFE, 0x83, 0x46, 0x00, 0x28, ++ 0x3D, 0xD0, 0xDF, 0xF8, 0x38, 0xA1, 0x9A, 0xF8, 0x20, 0x30, 0x00, 0x2B, ++ 0x41, 0xD0, 0xDA, 0xF8, 0x04, 0x30, 0x81, 0x68, 0xDA, 0xF8, 0x00, 0x20, ++ 0x03, 0xF1, 0x01, 0x0C, 0x4F, 0xEA, 0x0C, 0x63, 0x21, 0xF0, 0xFE, 0x41, ++ 0x03, 0xF0, 0xFE, 0x43, 0x0B, 0x43, 0x00, 0x21, 0x83, 0x60, 0x00, 0x91, ++ 0x3A, 0x23, 0x04, 0xF1, 0x30, 0x01, 0xCA, 0xF8, 0x04, 0xC0, 0xF2, 0xF7, ++ 0xBF, 0xFE, 0x3C, 0x4A, 0xDA, 0xF8, 0x0C, 0x30, 0x92, 0xF8, 0xB8, 0x20, ++ 0x3A, 0x33, 0xCA, 0xF8, 0x0C, 0x30, 0x58, 0x46, 0x00, 0x2A, 0x63, 0xD1, ++ 0xDA, 0xE9, 0x01, 0x12, 0xF2, 0xF7, 0x4E, 0xFE, 0x35, 0x49, 0x0A, 0x78, ++ 0x00, 0x23, 0x42, 0xF0, 0x01, 0x02, 0x0A, 0x70, 0xCA, 0xF8, 0x04, 0x30, ++ 0xCA, 0xF8, 0x0C, 0x30, 0xCA, 0xF8, 0x00, 0x30, 0xCA, 0xF8, 0x08, 0x30, ++ 0x8A, 0xF8, 0x20, 0x30, 0x12, 0xE0, 0x23, 0x7C, 0x2D, 0x48, 0x43, 0xF0, ++ 0x01, 0x03, 0x23, 0x74, 0x0E, 0xF0, 0x00, 0xFE, 0x2B, 0x4B, 0x83, 0xF8, ++ 0x20, 0xB0, 0x2B, 0x49, 0x4F, 0xF4, 0x80, 0x60, 0x0E, 0xF0, 0x48, 0xFE, ++ 0x23, 0x7C, 0x43, 0xF0, 0x01, 0x03, 0x23, 0x74, 0x27, 0x4B, 0x1B, 0x68, ++ 0x1B, 0x78, 0x02, 0x2B, 0x3F, 0xF4, 0x5D, 0xAE, 0x9A, 0xE6, 0x25, 0x49, ++ 0x25, 0x48, 0x40, 0xF2, 0x21, 0x52, 0x0F, 0xF0, 0x2F, 0xF8, 0x9C, 0xE6, ++ 0x21, 0x49, 0x23, 0x48, 0x40, 0xF2, 0x23, 0x52, 0x0F, 0xF0, 0x28, 0xF8, ++ 0x95, 0xE6, 0x23, 0x7C, 0x20, 0x4E, 0x05, 0x99, 0x43, 0xF0, 0x01, 0x03, ++ 0x23, 0x74, 0xD6, 0xF8, 0x98, 0x32, 0x20, 0x46, 0x98, 0x47, 0xEF, 0xF3, ++ 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x1A, 0x4B, 0x01, 0x22, ++ 0x1A, 0x60, 0x1A, 0x4C, 0xD6, 0xF8, 0x44, 0x24, 0x23, 0x68, 0x01, 0x33, ++ 0x23, 0x60, 0x90, 0x47, 0x23, 0x68, 0x01, 0x46, 0x33, 0xB1, 0x14, 0x4A, ++ 0x01, 0x3B, 0x12, 0x68, 0x23, 0x60, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, ++ 0x12, 0x48, 0xF0, 0xF7, 0xEF, 0xFB, 0x6E, 0xE6, 0xFF, 0xF7, 0x3C, 0xFC, ++ 0x9C, 0xE7, 0x10, 0x4B, 0x00, 0x22, 0x5A, 0x61, 0x1E, 0xE7, 0x0F, 0x4A, ++ 0xE8, 0xE6, 0x00, 0xBF, 0x2C, 0x19, 0x17, 0x00, 0x9C, 0x4E, 0x17, 0x00, ++ 0x0C, 0x97, 0x15, 0x00, 0x30, 0x65, 0x17, 0x00, 0x20, 0x97, 0x15, 0x00, ++ 0x78, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x34, 0x97, 0x15, 0x00, ++ 0x44, 0x97, 0x15, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0xFC, 0x96, 0x15, 0x00, 0x48, 0x35, 0x17, 0x00, ++ 0x60, 0x65, 0x17, 0x00, 0x0D, 0x4B, 0xC1, 0x69, 0xD3, 0xF8, 0x98, 0x32, ++ 0x10, 0xB5, 0x00, 0x22, 0x04, 0x46, 0x98, 0x47, 0x0A, 0x48, 0x03, 0x68, ++ 0x53, 0xB1, 0x23, 0x7C, 0x43, 0xF0, 0x01, 0x03, 0x00, 0x22, 0x23, 0x74, ++ 0x62, 0x60, 0x21, 0x46, 0xBD, 0xE8, 0x10, 0x40, 0x0D, 0xF0, 0xA0, 0xBB, ++ 0x20, 0x46, 0xBD, 0xE8, 0x10, 0x40, 0xFF, 0xF7, 0x19, 0xBB, 0x00, 0xBF, ++ 0x88, 0x1A, 0x17, 0x00, 0x24, 0x65, 0x17, 0x00, 0x0C, 0x4A, 0x0D, 0x49, ++ 0x93, 0x68, 0x09, 0x68, 0x8B, 0x42, 0x11, 0xD0, 0x51, 0x68, 0x23, 0xF0, ++ 0x00, 0x40, 0x09, 0x1A, 0x9F, 0x29, 0x0C, 0xD8, 0x11, 0x68, 0x03, 0xF0, ++ 0x00, 0x43, 0x88, 0x42, 0x88, 0xBF, 0x03, 0xF1, 0x00, 0x43, 0x0B, 0x43, ++ 0x93, 0x60, 0x23, 0xF0, 0x00, 0x40, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, ++ 0xEC, 0x34, 0x17, 0x00, 0xD4, 0x81, 0x32, 0x40, 0x1E, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x10, 0xB5, 0x04, 0x46, 0x21, 0xDB, ++ 0x1B, 0x4B, 0x1B, 0x68, 0x1B, 0x78, 0x9B, 0x07, 0x04, 0xD5, 0x63, 0x6D, ++ 0x03, 0xF0, 0x3C, 0x03, 0x3C, 0x2B, 0x25, 0xD0, 0x23, 0x8E, 0x53, 0xB1, ++ 0x62, 0x6D, 0x02, 0xF0, 0x7C, 0x02, 0x08, 0x2A, 0x0D, 0xD0, 0x0C, 0x2A, ++ 0x19, 0xD0, 0x04, 0x2A, 0x09, 0xD0, 0x04, 0x3B, 0x23, 0x86, 0x00, 0x23, ++ 0x10, 0x4A, 0x23, 0x74, 0x84, 0xF8, 0x9C, 0x30, 0xE4, 0x60, 0x62, 0x60, ++ 0x10, 0xBD, 0x08, 0x3B, 0x23, 0x86, 0xF4, 0xE7, 0x0C, 0x4B, 0x42, 0x69, ++ 0x9A, 0x42, 0xD9, 0xD0, 0x0B, 0x49, 0x0C, 0x48, 0x40, 0xF2, 0x14, 0x62, ++ 0x0E, 0xF0, 0x98, 0xFF, 0xD2, 0xE7, 0x0C, 0x3B, 0x23, 0x86, 0xE6, 0xE7, ++ 0x23, 0x8E, 0x04, 0x3B, 0x9B, 0xB2, 0x23, 0x86, 0xD5, 0xE7, 0x00, 0xBF, ++ 0x38, 0x36, 0x17, 0x00, 0x34, 0x36, 0x17, 0x00, 0x3D, 0x48, 0x13, 0x00, ++ 0x0D, 0xF0, 0xAD, 0xBA, 0x70, 0x79, 0x15, 0x00, 0x64, 0x97, 0x15, 0x00, ++ 0x06, 0x4B, 0x07, 0x4A, 0x4F, 0xF4, 0x80, 0x31, 0x19, 0x60, 0x13, 0x68, ++ 0x23, 0xF4, 0x80, 0x33, 0x13, 0x60, 0x4F, 0xF4, 0x80, 0x10, 0x0D, 0xF0, ++ 0x7F, 0xBA, 0x00, 0xBF, 0x7C, 0x80, 0x32, 0x40, 0x80, 0x80, 0x32, 0x40, ++ 0x2D, 0xE9, 0xF0, 0x47, 0x21, 0x4D, 0x22, 0x4E, 0x6B, 0x69, 0x32, 0x68, ++ 0x93, 0x42, 0x84, 0xB0, 0x38, 0xD0, 0xDF, 0xF8, 0x88, 0x80, 0x1F, 0x4F, ++ 0xDF, 0xF8, 0x84, 0x90, 0x20, 0xE0, 0x6B, 0x69, 0x1D, 0x48, 0x23, 0xF0, ++ 0x00, 0x44, 0x21, 0x46, 0x62, 0x69, 0xBA, 0x42, 0x0A, 0xD0, 0xD6, 0xF8, ++ 0x00, 0xE0, 0xD9, 0xF8, 0x00, 0xA0, 0xCD, 0xE9, 0x00, 0xC3, 0xCD, 0xE9, ++ 0x02, 0xEA, 0xEB, 0x68, 0x0E, 0xF0, 0xD4, 0xFC, 0x20, 0x46, 0xFF, 0xF7, ++ 0x7F, 0xFF, 0x01, 0x23, 0x84, 0xF8, 0x9C, 0x30, 0xD8, 0xF8, 0xC0, 0x32, ++ 0x20, 0x46, 0x98, 0x47, 0x6B, 0x69, 0x32, 0x68, 0x93, 0x42, 0x11, 0xD0, ++ 0xD5, 0xF8, 0x10, 0xC0, 0x23, 0xF0, 0x00, 0x41, 0xAC, 0xEB, 0x01, 0x02, ++ 0x9F, 0x2A, 0x03, 0xF0, 0x00, 0x43, 0xD4, 0xD8, 0xEA, 0x68, 0x91, 0x42, ++ 0x88, 0xBF, 0x03, 0xF1, 0x00, 0x43, 0x13, 0x43, 0x6B, 0x61, 0xCD, 0xE7, ++ 0x04, 0xB0, 0xBD, 0xE8, 0xF0, 0x87, 0x00, 0xBF, 0xEC, 0x34, 0x17, 0x00, ++ 0xE4, 0x81, 0x32, 0x40, 0x0D, 0xF0, 0xAD, 0xBA, 0x90, 0x97, 0x15, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0xE0, 0x81, 0x32, 0x40, 0x00, 0xB5, 0x10, 0x4A, ++ 0x10, 0x4B, 0x12, 0x68, 0x89, 0xB0, 0x08, 0x33, 0x03, 0x92, 0x53, 0xF8, ++ 0x08, 0x2C, 0x04, 0x92, 0x53, 0xF8, 0x04, 0x2C, 0x05, 0x92, 0x1B, 0x68, ++ 0x06, 0x93, 0x01, 0xA8, 0x00, 0x21, 0xEB, 0xF7, 0x73, 0xFA, 0x03, 0x9B, ++ 0x03, 0xF0, 0x0F, 0x03, 0x02, 0x2B, 0x02, 0xD0, 0x09, 0xB0, 0x5D, 0xF8, ++ 0x04, 0xFB, 0x01, 0xA8, 0x0E, 0xF0, 0x8C, 0xFF, 0x09, 0xB0, 0x5D, 0xF8, ++ 0x04, 0xFB, 0x00, 0xBF, 0xB0, 0x10, 0x34, 0x40, 0xB4, 0x10, 0x34, 0x40, ++ 0x38, 0xB5, 0xD0, 0xF8, 0xFC, 0x31, 0x04, 0x46, 0x00, 0xF5, 0xFE, 0x75, ++ 0x4B, 0xB1, 0x28, 0x46, 0x0D, 0xF0, 0xDE, 0xFA, 0x01, 0x21, 0xFA, 0xF7, ++ 0x2B, 0xF9, 0xD4, 0xF8, 0xFC, 0x31, 0x00, 0x2B, 0xF5, 0xD1, 0x4F, 0xF4, ++ 0x1E, 0x72, 0x00, 0x21, 0x20, 0x46, 0xEA, 0xF7, 0xF9, 0xF9, 0x23, 0x46, ++ 0x04, 0xF1, 0x48, 0x01, 0x21, 0x22, 0x83, 0xF8, 0xA4, 0x21, 0x83, 0xF8, ++ 0xA5, 0x21, 0x08, 0x33, 0x8B, 0x42, 0xF8, 0xD1, 0xFF, 0x23, 0x84, 0xF8, ++ 0x22, 0x30, 0x38, 0xBD, 0x2D, 0xE9, 0xF0, 0x43, 0x49, 0x48, 0x4A, 0x4F, ++ 0x83, 0xB0, 0x81, 0x46, 0x0D, 0xF0, 0x72, 0xFA, 0x07, 0xF5, 0x0C, 0x75, ++ 0x00, 0x26, 0x40, 0xF2, 0x16, 0x38, 0xA5, 0xF5, 0x0C, 0x71, 0x08, 0x46, ++ 0x01, 0x91, 0xFF, 0xF7, 0xC7, 0xFF, 0x01, 0x99, 0x48, 0x46, 0x0D, 0xF0, ++ 0x67, 0xFA, 0xA5, 0xF1, 0x28, 0x04, 0x20, 0x46, 0x0D, 0xF0, 0x5E, 0xFA, ++ 0x04, 0xF1, 0x28, 0x00, 0x08, 0x34, 0x0D, 0xF0, 0x59, 0xFA, 0xAC, 0x42, ++ 0xF5, 0xD1, 0x4F, 0x36, 0x46, 0x45, 0x04, 0xF5, 0x1E, 0x75, 0xE4, 0xD1, ++ 0x38, 0x4D, 0x40, 0xF2, 0x52, 0x48, 0xA5, 0xF1, 0x28, 0x04, 0x20, 0x46, ++ 0x0D, 0xF0, 0x4A, 0xFA, 0x04, 0xF1, 0x28, 0x00, 0x08, 0x34, 0x0D, 0xF0, ++ 0x45, 0xFA, 0xAC, 0x42, 0xF5, 0xD1, 0x4F, 0x36, 0x46, 0x45, 0x04, 0xF5, ++ 0x1E, 0x75, 0xEE, 0xD1, 0x2F, 0x48, 0x30, 0x4D, 0x30, 0x4C, 0x00, 0xF1, ++ 0x30, 0x06, 0xFF, 0xF7, 0x97, 0xFF, 0x41, 0xF6, 0xF8, 0x12, 0x4F, 0xF0, ++ 0x00, 0x08, 0x41, 0xF6, 0x64, 0x11, 0x41, 0xF6, 0xD0, 0x03, 0xBD, 0x50, ++ 0x06, 0xF5, 0x12, 0x70, 0x86, 0xF8, 0x00, 0x80, 0x4F, 0xF0, 0x20, 0x62, ++ 0x7C, 0x50, 0xFA, 0x50, 0xFF, 0xF7, 0x84, 0xFF, 0x41, 0xF6, 0x58, 0x30, ++ 0x41, 0xF6, 0x70, 0x41, 0x07, 0xF8, 0x00, 0x80, 0x41, 0xF6, 0xDC, 0x32, ++ 0x05, 0xF1, 0x40, 0x00, 0x78, 0x50, 0x41, 0xF6, 0x48, 0x33, 0x04, 0xF5, ++ 0xA4, 0x61, 0xB9, 0x50, 0x06, 0xF5, 0x98, 0x60, 0x1C, 0x4A, 0xFA, 0x50, ++ 0xFF, 0xF7, 0x6E, 0xFF, 0x41, 0xF6, 0xD0, 0x52, 0x41, 0xF6, 0xE8, 0x61, ++ 0x41, 0xF6, 0x54, 0x63, 0x18, 0x48, 0x07, 0xF8, 0x02, 0x80, 0xC6, 0xF8, ++ 0xE0, 0x04, 0x04, 0xF5, 0x24, 0x62, 0x06, 0xF5, 0xE7, 0x60, 0x05, 0xF1, ++ 0x80, 0x06, 0x7E, 0x50, 0xFA, 0x50, 0xFF, 0xF7, 0x59, 0xFF, 0x42, 0xF2, ++ 0x60, 0x16, 0x11, 0x4A, 0x42, 0xF2, 0xCC, 0x00, 0x42, 0xF2, 0x48, 0x01, ++ 0x42, 0xF2, 0x38, 0x03, 0xC0, 0x35, 0x04, 0xF5, 0x76, 0x64, 0xBD, 0x51, ++ 0x3C, 0x50, 0x07, 0xF8, 0x01, 0x80, 0xFA, 0x50, 0x03, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x83, 0x00, 0xBF, 0xF8, 0x87, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, ++ 0x48, 0x80, 0x17, 0x00, 0x18, 0x7E, 0x17, 0x00, 0x04, 0x38, 0x18, 0x00, ++ 0xC0, 0x8C, 0x17, 0x00, 0x00, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x02, 0x0C, ++ 0x00, 0x00, 0x03, 0x0D, 0x2D, 0xE9, 0xF0, 0x41, 0x05, 0x46, 0x79, 0x48, ++ 0x95, 0xF8, 0x19, 0x80, 0x0E, 0x46, 0x0D, 0xF0, 0x11, 0xFA, 0x00, 0x28, ++ 0x00, 0xF0, 0xE1, 0x80, 0x6B, 0x7F, 0x04, 0x46, 0x00, 0x2B, 0x40, 0xF0, ++ 0xA5, 0x80, 0x73, 0x4F, 0x05, 0xF1, 0x12, 0x02, 0x11, 0x68, 0x2B, 0x68, ++ 0x92, 0x88, 0x62, 0x85, 0xC4, 0xF8, 0x26, 0x10, 0x63, 0x60, 0x28, 0x7E, ++ 0x6E, 0x4B, 0x6F, 0x4A, 0x6F, 0x49, 0x10, 0x28, 0x38, 0xBF, 0x10, 0x20, ++ 0x20, 0x77, 0x28, 0x8A, 0xA0, 0x82, 0xA8, 0x68, 0x20, 0x61, 0x68, 0x68, ++ 0xE0, 0x60, 0xE8, 0x68, 0xA0, 0x61, 0xE0, 0x1B, 0xC0, 0x10, 0x03, 0xFB, ++ 0x00, 0xF3, 0xDB, 0xB2, 0x68, 0x7E, 0x84, 0xF8, 0x22, 0x00, 0x33, 0x70, ++ 0x4F, 0xF4, 0x80, 0x70, 0x84, 0xF8, 0x23, 0x30, 0x0E, 0xF0, 0xC6, 0xFB, ++ 0x62, 0x48, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x08, 0x03, 0x4F, 0xF4, ++ 0xC8, 0x31, 0x93, 0xF8, 0xC0, 0x24, 0xA1, 0x60, 0x22, 0xB1, 0x93, 0xF8, ++ 0xC2, 0x24, 0x01, 0x32, 0x83, 0xF8, 0xC2, 0x24, 0x4F, 0xF6, 0xFF, 0x71, ++ 0xA4, 0xF8, 0xE8, 0x11, 0x04, 0xF5, 0xF4, 0x72, 0x23, 0x46, 0x04, 0xF5, ++ 0xFD, 0x75, 0x22, 0xF8, 0x02, 0x1F, 0xAA, 0x42, 0xFB, 0xD1, 0x4F, 0xF4, ++ 0xA4, 0x62, 0x02, 0xFB, 0x08, 0xF8, 0x00, 0xEB, 0x08, 0x05, 0x00, 0x22, ++ 0x31, 0x78, 0x84, 0xF8, 0x30, 0x20, 0xD5, 0xF8, 0xB0, 0x54, 0x4F, 0x4A, ++ 0x02, 0xEB, 0x81, 0x12, 0x29, 0x07, 0xC4, 0xF8, 0x48, 0x21, 0x4D, 0x49, ++ 0x56, 0xBF, 0x08, 0xF5, 0x95, 0x62, 0x04, 0xF1, 0xB0, 0x02, 0x12, 0x18, ++ 0xC4, 0xF8, 0xB4, 0x20, 0x0A, 0x69, 0xA2, 0xF5, 0x74, 0x22, 0xA2, 0xF5, ++ 0x10, 0x72, 0x04, 0xF1, 0x48, 0x01, 0xC3, 0xF8, 0xA0, 0x21, 0x08, 0x33, ++ 0x8B, 0x42, 0xFA, 0xD1, 0xEA, 0x06, 0x03, 0xD5, 0x63, 0x68, 0x43, 0xF0, ++ 0x08, 0x03, 0x63, 0x60, 0x08, 0xF1, 0xE4, 0x08, 0x40, 0x44, 0x21, 0x46, ++ 0x0D, 0xF0, 0x4C, 0xF9, 0x3D, 0x4B, 0xC4, 0xF8, 0x04, 0x32, 0xEF, 0xF3, ++ 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x3A, 0x4B, 0x01, 0x22, ++ 0x1A, 0x60, 0x3A, 0x4B, 0xE0, 0x6A, 0x1A, 0x68, 0x01, 0x25, 0x51, 0x19, ++ 0x19, 0x60, 0x84, 0xF8, 0x25, 0x50, 0x08, 0xB1, 0x80, 0xF8, 0x25, 0x50, ++ 0x21, 0xB1, 0x33, 0x49, 0x1A, 0x60, 0x0B, 0x68, 0x00, 0x2A, 0x42, 0xD0, ++ 0xF6, 0xB2, 0x0D, 0x2E, 0x07, 0xD8, 0x4F, 0xF4, 0x1E, 0x73, 0x2C, 0x4A, ++ 0x06, 0xFB, 0x03, 0x76, 0x13, 0x69, 0xC6, 0xF8, 0x58, 0x32, 0x00, 0x20, ++ 0x84, 0xF8, 0x5C, 0x02, 0xBD, 0xE8, 0xF0, 0x81, 0x1F, 0x48, 0x0D, 0xF0, ++ 0x61, 0xF9, 0x00, 0x28, 0x34, 0xD0, 0x2A, 0x46, 0xE0, 0x62, 0xC4, 0x62, ++ 0xA9, 0x7F, 0x52, 0xF8, 0x12, 0x3F, 0x95, 0xF8, 0x1D, 0xC0, 0xC0, 0xF8, ++ 0x26, 0x30, 0x01, 0x23, 0x8B, 0x40, 0x91, 0x88, 0x41, 0x85, 0x01, 0x3B, ++ 0x41, 0x8D, 0x16, 0x4F, 0x1B, 0x02, 0x1B, 0xB2, 0x21, 0xEA, 0x03, 0x01, ++ 0x09, 0xB2, 0x41, 0x85, 0xB5, 0xF8, 0x16, 0xE0, 0xAE, 0xEB, 0x0C, 0x2C, ++ 0x03, 0xEA, 0x0C, 0x03, 0xA0, 0xEB, 0x07, 0x0E, 0xDF, 0xF8, 0x3C, 0xC0, ++ 0x4F, 0xEA, 0xEE, 0x0E, 0x0B, 0x43, 0x0C, 0xFB, 0x0E, 0xF1, 0x4F, 0xF0, ++ 0xFF, 0x0C, 0x43, 0x85, 0x80, 0xF8, 0x23, 0x10, 0xA0, 0xF8, 0x20, 0xC0, ++ 0x2A, 0xE7, 0x00, 0x2B, 0xBA, 0xD0, 0x62, 0xB6, 0xB8, 0xE7, 0x01, 0x20, ++ 0xBD, 0xE8, 0xF0, 0x81, 0x02, 0x48, 0x21, 0x46, 0x0D, 0xF0, 0xE2, 0xF8, ++ 0x01, 0x20, 0xBD, 0xE7, 0xF8, 0x87, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, ++ 0xAF, 0x16, 0x37, 0x61, 0xEC, 0x97, 0x15, 0x00, 0xDC, 0x97, 0x15, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0x04, 0x39, 0x18, 0x00, 0x00, 0x10, 0x50, 0x40, ++ 0x0F, 0xCC, 0xFF, 0xFF, 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x41, 0x33, 0x4F, 0xDF, 0xF8, 0xE4, 0x80, 0x4F, 0xF4, ++ 0x1E, 0x74, 0x04, 0xFB, 0x00, 0x74, 0x4F, 0xF4, 0xA4, 0x63, 0x94, 0xF8, ++ 0x22, 0x60, 0x03, 0xFB, 0x06, 0x83, 0x05, 0x46, 0x93, 0xF8, 0xC0, 0x24, ++ 0x22, 0xB1, 0x93, 0xF8, 0xC2, 0x24, 0x01, 0x3A, 0x83, 0xF8, 0xC2, 0x24, ++ 0x29, 0x4A, 0x2A, 0x49, 0x2B, 0x46, 0x4F, 0xF4, 0x80, 0x70, 0x0E, 0xF0, ++ 0xD5, 0xFA, 0x4F, 0xF4, 0xA4, 0x60, 0x00, 0xFB, 0x06, 0x80, 0xE4, 0x30, ++ 0x21, 0x46, 0x0D, 0xF0, 0xF3, 0xF8, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, ++ 0x03, 0xD4, 0x72, 0xB6, 0x21, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x21, 0x4A, ++ 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, 0x05, 0x73, 0x11, 0x68, 0xD8, 0x6A, ++ 0x4E, 0x1C, 0x4F, 0xF0, 0x00, 0x0C, 0x16, 0x60, 0x83, 0xF8, 0x25, 0xC0, ++ 0xD8, 0xB1, 0x80, 0xF8, 0x25, 0xC0, 0x96, 0xB9, 0xFF, 0xF7, 0xE4, 0xFD, ++ 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, 0x05, 0x75, 0x16, 0x48, 0xE9, 0x6A, ++ 0x0D, 0xF0, 0x80, 0xF8, 0x20, 0x46, 0xFF, 0xF7, 0xD9, 0xFD, 0x21, 0x46, ++ 0x12, 0x48, 0xBD, 0xE8, 0xF0, 0x41, 0x0D, 0xF0, 0x77, 0xB8, 0x0E, 0x48, ++ 0x11, 0x60, 0x02, 0x68, 0x41, 0xB1, 0xD8, 0x6A, 0xE6, 0xE7, 0x00, 0x2E, ++ 0xEE, 0xD0, 0x0A, 0x4B, 0x11, 0x60, 0x1A, 0x68, 0x00, 0x29, 0xE9, 0xD1, ++ 0x02, 0xB1, 0x62, 0xB6, 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, 0x05, 0x73, ++ 0xD8, 0x6A, 0x00, 0x28, 0xE0, 0xD0, 0xD5, 0xE7, 0x68, 0x65, 0x17, 0x00, ++ 0x00, 0x98, 0x15, 0x00, 0xDC, 0x97, 0x15, 0x00, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0xF8, 0x87, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF8, 0x43, 0x44, 0x78, 0xDF, 0xF8, 0x14, 0x81, 0x4F, 0xF4, ++ 0x1E, 0x76, 0x06, 0xFB, 0x04, 0xF6, 0x08, 0xEB, 0x06, 0x07, 0x38, 0x36, ++ 0x87, 0xF8, 0x9A, 0x10, 0x90, 0xF8, 0x28, 0x30, 0x87, 0xF8, 0x98, 0x30, ++ 0x03, 0x78, 0x87, 0xF8, 0x99, 0x30, 0x46, 0x44, 0x05, 0x46, 0x48, 0x22, ++ 0x30, 0x46, 0x00, 0x21, 0x97, 0xF8, 0x22, 0x90, 0xE9, 0xF7, 0xA0, 0xFF, ++ 0x97, 0xF8, 0x98, 0x30, 0x04, 0x2B, 0x55, 0xD8, 0xDF, 0xE8, 0x03, 0xF0, ++ 0x03, 0x3F, 0x54, 0x03, 0x27, 0x00, 0x21, 0xF0, 0x29, 0xF8, 0x4F, 0xF4, ++ 0x1E, 0x73, 0x03, 0xFB, 0x04, 0x83, 0x03, 0xF1, 0x80, 0x02, 0x20, 0xF0, ++ 0x7F, 0x40, 0xC3, 0xF8, 0x80, 0x00, 0x00, 0x23, 0x53, 0x60, 0x4F, 0xF4, ++ 0x1E, 0x73, 0x03, 0xFB, 0x04, 0x83, 0x01, 0x22, 0xD5, 0xE9, 0x02, 0x40, ++ 0x29, 0x69, 0x83, 0xF8, 0x9B, 0x20, 0x6A, 0x69, 0xC3, 0xF8, 0xB0, 0x60, ++ 0xC3, 0xE9, 0x27, 0x40, 0xC3, 0xE9, 0x29, 0x12, 0x2A, 0x79, 0x83, 0xF8, ++ 0xAC, 0x20, 0xBD, 0xE8, 0xF8, 0x83, 0x20, 0x4B, 0x4F, 0xF4, 0xA4, 0x62, ++ 0x02, 0xFB, 0x09, 0x39, 0x19, 0xA3, 0xD3, 0xE9, 0x00, 0x23, 0x99, 0xF8, ++ 0x62, 0x00, 0x4F, 0xF4, 0x1E, 0x71, 0x01, 0xFB, 0x04, 0x81, 0x02, 0x28, ++ 0xC1, 0xE9, 0x20, 0x23, 0xD7, 0xD1, 0x15, 0xA3, 0xD3, 0xE9, 0x00, 0x23, ++ 0xC1, 0xE9, 0x20, 0x23, 0xD1, 0xE7, 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, ++ 0x04, 0x83, 0xAA, 0x69, 0xC3, 0xF8, 0x88, 0x20, 0xEA, 0x69, 0xC3, 0xF8, ++ 0x8C, 0x20, 0x2A, 0x6A, 0xC3, 0xF8, 0x90, 0x20, 0x00, 0x20, 0x6A, 0x6A, ++ 0xC3, 0xF8, 0x94, 0x20, 0x00, 0x21, 0xC3, 0xE9, 0x20, 0x01, 0xBC, 0xE7, ++ 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, 0x04, 0x83, 0x00, 0x20, 0x00, 0x21, ++ 0xC3, 0xE9, 0x20, 0x01, 0xB3, 0xE7, 0x00, 0xBF, 0xAF, 0xF3, 0x00, 0x80, ++ 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x37, 0x5C, 0x36, 0x5C, ++ 0x36, 0x5C, 0x36, 0x5C, 0x18, 0x88, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, ++ 0x00, 0x23, 0x01, 0x22, 0x80, 0xF8, 0x30, 0x20, 0x80, 0xF8, 0x9B, 0x30, ++ 0xC0, 0xF8, 0xB0, 0x30, 0x70, 0x47, 0x00, 0xBF, 0x2D, 0xE9, 0xF0, 0x47, ++ 0xD1, 0xF8, 0xFC, 0xA1, 0x82, 0xB0, 0xBA, 0xF1, 0x00, 0x0F, 0x32, 0xD0, ++ 0x00, 0x24, 0xDF, 0xF8, 0x6C, 0x80, 0x0D, 0x46, 0x06, 0x46, 0x91, 0x46, ++ 0x27, 0x46, 0x10, 0xE0, 0x80, 0xF8, 0x5D, 0x70, 0xD8, 0xF8, 0x98, 0x33, ++ 0xC1, 0x7E, 0x01, 0x34, 0x98, 0x47, 0xB9, 0xF1, 0x00, 0x0F, 0x01, 0xD0, ++ 0x4C, 0x45, 0x1F, 0xD0, 0xD5, 0xF8, 0xFC, 0xA1, 0xBA, 0xF1, 0x00, 0x0F, ++ 0x1A, 0xD0, 0x30, 0x46, 0x01, 0x97, 0xF8, 0xF7, 0x6B, 0xFA, 0x03, 0x46, ++ 0x50, 0x46, 0x9B, 0xB1, 0x15, 0xF0, 0x34, 0xFC, 0x03, 0x46, 0x01, 0xAA, ++ 0x29, 0x46, 0x30, 0x46, 0x63, 0xB1, 0xD8, 0xF8, 0x10, 0x30, 0x98, 0x47, ++ 0x01, 0x9B, 0x3B, 0xB9, 0x00, 0x28, 0xD9, 0xD1, 0x05, 0xF5, 0xFE, 0x70, ++ 0x0C, 0xF0, 0xC2, 0xFF, 0xD4, 0xE7, 0x54, 0x46, 0x20, 0x46, 0x02, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x87, 0x88, 0x1A, 0x17, 0x00, 0x0A, 0x4B, 0x9B, 0x68, ++ 0x93, 0xF8, 0x62, 0x20, 0x7A, 0xB9, 0x93, 0xF8, 0x64, 0x20, 0x62, 0xB1, ++ 0x93, 0xF8, 0x6D, 0x20, 0x4A, 0xB1, 0x93, 0xF8, 0x6E, 0x20, 0x08, 0x2A, ++ 0x05, 0xD8, 0x01, 0x23, 0x93, 0x40, 0x01, 0x3B, 0x02, 0x4A, 0x1B, 0x02, ++ 0x13, 0x60, 0x70, 0x47, 0x00, 0x88, 0x17, 0x00, 0x2C, 0x00, 0x32, 0x40, ++ 0x10, 0xB5, 0x90, 0xF8, 0xC0, 0x34, 0x04, 0x46, 0x00, 0x2B, 0x2D, 0xD1, ++ 0x23, 0x6C, 0x1B, 0xB1, 0x1B, 0x4B, 0x20, 0x46, 0x1B, 0x6B, 0x98, 0x47, ++ 0x63, 0x68, 0xD8, 0x07, 0x1A, 0xD5, 0x19, 0x4A, 0x11, 0x68, 0x89, 0x01, ++ 0x17, 0xD5, 0x23, 0xF0, 0x01, 0x03, 0x63, 0x60, 0x16, 0x4A, 0x41, 0xF2, ++ 0x14, 0x33, 0xD3, 0x5C, 0x01, 0x2B, 0x41, 0xF2, 0x13, 0x33, 0x8C, 0xBF, ++ 0x01, 0x21, 0x00, 0x21, 0xD1, 0x54, 0x12, 0x4B, 0x93, 0xF8, 0xB6, 0x30, ++ 0x23, 0xB1, 0x11, 0x4B, 0x1B, 0x68, 0x1B, 0x78, 0x02, 0x2B, 0x0C, 0xD0, ++ 0x10, 0xBD, 0x12, 0x68, 0x92, 0x01, 0xFB, 0xD4, 0x0D, 0x4A, 0x92, 0xF8, ++ 0x24, 0x20, 0x00, 0x2A, 0xF6, 0xD0, 0xDE, 0xE7, 0x0A, 0xF0, 0x34, 0xF8, ++ 0xCE, 0xE7, 0xF8, 0xF7, 0x1D, 0xFD, 0x09, 0x4A, 0x13, 0x68, 0x23, 0xF0, ++ 0x01, 0x03, 0x13, 0x60, 0x10, 0xBD, 0x00, 0xBF, 0x88, 0x1A, 0x17, 0x00, ++ 0x4C, 0x00, 0x32, 0x40, 0x00, 0x40, 0x1E, 0x00, 0x2C, 0x19, 0x17, 0x00, ++ 0x74, 0x36, 0x17, 0x00, 0x1C, 0x9E, 0x17, 0x00, 0x8C, 0x00, 0x32, 0x40, ++ 0x19, 0x48, 0x2D, 0xE9, 0xF0, 0x41, 0x18, 0x22, 0x80, 0x46, 0x00, 0x21, ++ 0xE9, 0xF7, 0x72, 0xFE, 0x40, 0x46, 0x0C, 0xF0, 0xFF, 0xFE, 0x08, 0xF1, ++ 0x08, 0x00, 0x14, 0x4C, 0x14, 0x4F, 0x0C, 0xF0, 0xF9, 0xFE, 0x04, 0xF5, ++ 0xA4, 0x56, 0x45, 0x46, 0x4F, 0xF4, 0xA4, 0x62, 0x00, 0x21, 0x20, 0x46, ++ 0xE9, 0xF7, 0x60, 0xFE, 0x7F, 0x23, 0xD7, 0xF8, 0x50, 0x24, 0x24, 0x63, ++ 0x05, 0x21, 0x84, 0xF8, 0x62, 0x10, 0x84, 0xF8, 0x65, 0x30, 0x84, 0xF8, ++ 0x66, 0x30, 0xE2, 0x62, 0x21, 0x46, 0x28, 0x46, 0x04, 0xF5, 0xA4, 0x64, ++ 0x0C, 0xF0, 0xE2, 0xFE, 0xB4, 0x42, 0xE5, 0xD1, 0xFF, 0x23, 0x88, 0xF8, ++ 0x10, 0x30, 0xBD, 0xE8, 0xF0, 0x81, 0x00, 0xBF, 0x00, 0x88, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x38, 0xB5, 0x06, 0x4B, ++ 0x9C, 0x68, 0x3C, 0xB1, 0x05, 0x4D, 0xD5, 0xF8, 0x5C, 0x34, 0x20, 0x46, ++ 0x98, 0x47, 0x24, 0x68, 0x00, 0x2C, 0xF8, 0xD1, 0x38, 0xBD, 0x00, 0xBF, ++ 0x00, 0x88, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0xAC, 0x4D, 0x8D, 0xB0, 0x2C, 0x68, 0x05, 0x90, 0x88, 0x46, 0x17, 0x46, ++ 0x04, 0x93, 0x00, 0x2C, 0x00, 0xF0, 0xA4, 0x80, 0x00, 0x2A, 0x40, 0xF0, ++ 0x9E, 0x80, 0xAC, 0x68, 0x00, 0x2C, 0x00, 0xF0, 0x42, 0x81, 0x05, 0x9B, ++ 0xA4, 0x48, 0x1A, 0x68, 0x9B, 0x88, 0x06, 0x92, 0x4F, 0xF0, 0x00, 0x09, ++ 0x07, 0x93, 0xCB, 0x46, 0xBA, 0x46, 0xE7, 0x6D, 0xB4, 0xF8, 0x60, 0x60, ++ 0x94, 0xF8, 0xC0, 0x34, 0x39, 0x46, 0x32, 0x46, 0x0E, 0xF0, 0x76, 0xF8, ++ 0x94, 0xF8, 0xC0, 0x34, 0x9A, 0x48, 0x1B, 0xB9, 0x8B, 0xEA, 0x07, 0x0B, ++ 0x89, 0xEA, 0x06, 0x09, 0x24, 0x68, 0x00, 0x2C, 0xEB, 0xD1, 0x57, 0x46, ++ 0x00, 0x2F, 0x00, 0xF0, 0x99, 0x80, 0x95, 0x4B, 0x95, 0x48, 0x49, 0xF4, ++ 0x40, 0x74, 0xDD, 0xE9, 0x06, 0x12, 0x1C, 0x60, 0xC0, 0xF8, 0x00, 0xB0, ++ 0x5B, 0x46, 0xCD, 0xE9, 0x00, 0x97, 0x91, 0x48, 0x0E, 0xF0, 0x58, 0xF8, ++ 0x8B, 0x48, 0x0C, 0xF0, 0xBF, 0xFE, 0x05, 0x99, 0x8E, 0x4A, 0x80, 0xF8, ++ 0x62, 0x80, 0x04, 0x46, 0x8D, 0x4B, 0x82, 0x1A, 0x08, 0x68, 0xE0, 0x65, ++ 0x52, 0x11, 0x89, 0x88, 0xA4, 0xF8, 0x60, 0x10, 0x03, 0xFB, 0x02, 0xF2, ++ 0xD3, 0xB2, 0x40, 0xF6, 0x47, 0x21, 0x40, 0xF6, 0x43, 0x22, 0xA1, 0x60, ++ 0xE2, 0x60, 0x86, 0x49, 0x86, 0x4A, 0x21, 0x61, 0x62, 0x61, 0x40, 0xF2, ++ 0xFF, 0x31, 0x00, 0x22, 0x84, 0xF8, 0xC0, 0x74, 0xA4, 0xF8, 0xBE, 0x14, ++ 0x84, 0xF8, 0x63, 0x30, 0x84, 0xF8, 0x4C, 0x30, 0x22, 0x64, 0x84, 0xF8, ++ 0x84, 0x20, 0x17, 0xB1, 0xEA, 0x7C, 0x01, 0x32, 0xEA, 0x74, 0xB8, 0xF1, ++ 0x02, 0x0F, 0x00, 0xF0, 0x89, 0x80, 0xB8, 0xF1, 0x04, 0x0F, 0x00, 0xF0, ++ 0xC3, 0x80, 0xB8, 0xF1, 0x00, 0x0F, 0x00, 0xF0, 0x9C, 0x80, 0x6B, 0x7C, ++ 0xAA, 0x7C, 0x13, 0x44, 0x01, 0x2B, 0x78, 0xDD, 0x74, 0x48, 0x75, 0x4E, ++ 0xD0, 0xE9, 0x00, 0x12, 0x42, 0xF4, 0x80, 0x72, 0x11, 0x43, 0x42, 0x60, ++ 0x31, 0x60, 0x01, 0x2B, 0x4D, 0xD0, 0x00, 0x2F, 0x52, 0xD1, 0x04, 0x9A, ++ 0x94, 0xF8, 0x63, 0x30, 0x6E, 0x48, 0x13, 0x70, 0x21, 0x46, 0x0C, 0xF0, ++ 0x29, 0xFE, 0x04, 0xF5, 0x99, 0x66, 0x04, 0xF5, 0x9E, 0x69, 0x30, 0x46, ++ 0x0C, 0xF0, 0x1E, 0xFE, 0x06, 0xF1, 0x28, 0x00, 0x08, 0x36, 0x0C, 0xF0, ++ 0x19, 0xFE, 0x4E, 0x45, 0xF5, 0xD1, 0x04, 0xF5, 0xA3, 0x60, 0x0C, 0xF0, ++ 0x13, 0xFE, 0x00, 0x24, 0x03, 0xE0, 0x63, 0x4B, 0x1B, 0x78, 0x23, 0xB3, ++ 0x01, 0x24, 0xAA, 0x7C, 0x6B, 0x7C, 0x61, 0x49, 0x13, 0x44, 0x00, 0x20, ++ 0x01, 0x2B, 0x08, 0x60, 0x04, 0xDC, 0xFF, 0xF7, 0x91, 0xFE, 0xAA, 0x7C, ++ 0x6B, 0x7C, 0x13, 0x44, 0x04, 0x99, 0x09, 0x78, 0x4F, 0xF4, 0x80, 0x70, ++ 0xCD, 0xE9, 0x02, 0x71, 0xCD, 0xE9, 0x00, 0x28, 0x58, 0x49, 0x59, 0x4A, ++ 0x0E, 0xF0, 0x22, 0xF8, 0x20, 0x46, 0x0D, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, ++ 0x06, 0x9B, 0x8B, 0xEA, 0x03, 0x0B, 0x07, 0x9B, 0x89, 0xEA, 0x03, 0x09, ++ 0x5F, 0xE7, 0xAC, 0x68, 0x00, 0x2C, 0x7C, 0xD0, 0xEB, 0x7C, 0x02, 0x2B, ++ 0x7F, 0xF4, 0x37, 0xAF, 0xD2, 0xE7, 0x4F, 0x4A, 0x13, 0x68, 0x43, 0xF0, ++ 0x01, 0x03, 0x13, 0x60, 0x00, 0x2F, 0xAC, 0xD0, 0xB8, 0xF1, 0x00, 0x01, ++ 0x18, 0xBF, 0x01, 0x21, 0x94, 0xF8, 0x63, 0x00, 0x09, 0xF0, 0x22, 0xFD, ++ 0x48, 0x4B, 0x84, 0xF8, 0xC1, 0x04, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0x9C, 0xDA, 0xFF, 0x28, 0x9A, 0xD1, 0x44, 0x49, 0x45, 0x48, ++ 0x40, 0xF2, 0x0B, 0x22, 0x0E, 0xF0, 0x1A, 0xFA, 0x93, 0xE7, 0x00, 0x2A, ++ 0x8D, 0xD0, 0x83, 0xE7, 0xAA, 0x7C, 0x00, 0x2A, 0x00, 0xF0, 0xA8, 0x80, ++ 0x39, 0x46, 0x3F, 0x48, 0x0A, 0x33, 0x4F, 0xF4, 0x1E, 0x76, 0x06, 0xFB, ++ 0x03, 0x03, 0x01, 0x32, 0x01, 0x20, 0xAA, 0x74, 0x83, 0xF8, 0x25, 0x00, ++ 0x11, 0xB1, 0x3A, 0x4B, 0xC4, 0xE9, 0x07, 0x34, 0x39, 0x4B, 0x20, 0x46, ++ 0xD3, 0xF8, 0x80, 0x31, 0x98, 0x47, 0x6B, 0x7C, 0x64, 0xE7, 0x36, 0x4B, ++ 0x36, 0x49, 0xD3, 0xF8, 0xCC, 0x31, 0xE3, 0x61, 0xFF, 0x23, 0x84, 0xF8, ++ 0x6C, 0x30, 0x34, 0x4A, 0x6B, 0x7C, 0x24, 0x62, 0xA4, 0xF8, 0x8A, 0x80, ++ 0xC4, 0xF8, 0xB8, 0x40, 0xC4, 0xF8, 0xB4, 0x10, 0x01, 0x33, 0x92, 0xF8, ++ 0x04, 0x21, 0xDB, 0xB2, 0x6B, 0x74, 0x00, 0x2A, 0x3F, 0xF4, 0x4C, 0xAF, ++ 0x2C, 0x4A, 0xC4, 0xF8, 0xA4, 0x40, 0xC4, 0xE9, 0x24, 0x88, 0xC4, 0xF8, ++ 0x98, 0x80, 0xC4, 0xF8, 0xA0, 0x20, 0x41, 0xE7, 0x2A, 0x7C, 0xFF, 0x2A, ++ 0x17, 0xD1, 0xAA, 0x68, 0x2B, 0x74, 0x00, 0x2A, 0x4C, 0xD0, 0x14, 0x49, ++ 0x24, 0x4B, 0x4E, 0x68, 0x12, 0x6C, 0x13, 0x48, 0x0B, 0x60, 0x33, 0x43, ++ 0x03, 0x60, 0x00, 0x2A, 0x3F, 0xF4, 0x2F, 0xAF, 0x1B, 0x4B, 0x10, 0x7E, ++ 0x1B, 0x6D, 0x98, 0x47, 0x29, 0xE7, 0x05, 0x98, 0x01, 0xF0, 0x4E, 0xFE, ++ 0xEA, 0xE6, 0x01, 0x24, 0x6E, 0xE7, 0x00, 0xBF, 0x00, 0x88, 0x17, 0x00, ++ 0x14, 0x98, 0x15, 0x00, 0x1C, 0x00, 0x32, 0x40, 0x18, 0x00, 0x32, 0x40, ++ 0x2C, 0x98, 0x15, 0x00, 0x18, 0x88, 0x17, 0x00, 0x19, 0x9C, 0x8F, 0xC1, ++ 0x32, 0xE4, 0x05, 0x00, 0x22, 0xF3, 0x02, 0x00, 0x98, 0x9C, 0x17, 0x00, ++ 0x60, 0x00, 0x32, 0x40, 0x08, 0x88, 0x17, 0x00, 0x44, 0x9E, 0x17, 0x00, ++ 0x2C, 0x00, 0x32, 0x40, 0x74, 0x98, 0x15, 0x00, 0xC8, 0x98, 0x15, 0x00, ++ 0x94, 0x40, 0x04, 0x40, 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x50, 0x98, 0x15, 0x00, 0x68, 0x65, 0x17, 0x00, 0xB1, 0x7F, 0x13, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0xD5, 0x65, 0x12, 0x00, 0x2C, 0x19, 0x17, 0x00, ++ 0x81, 0x66, 0x12, 0x00, 0xDC, 0xFF, 0xFF, 0x7F, 0x10, 0x4E, 0x11, 0x4A, ++ 0x09, 0x92, 0x40, 0xF6, 0x85, 0x12, 0xD6, 0xF8, 0xE8, 0x30, 0x0A, 0x92, ++ 0x98, 0x47, 0x73, 0x6C, 0x0D, 0xF1, 0x23, 0x01, 0x09, 0xA8, 0x98, 0x47, ++ 0x00, 0x28, 0xB6, 0xD1, 0x63, 0x68, 0x32, 0x6D, 0x9D, 0xF8, 0x23, 0x00, ++ 0x43, 0xF0, 0x80, 0x03, 0x63, 0x60, 0x90, 0x47, 0x6B, 0x7C, 0xD3, 0xE6, ++ 0x01, 0xF0, 0x32, 0xFE, 0xAA, 0x7C, 0x94, 0xF8, 0x63, 0x30, 0x94, 0xF8, ++ 0xC0, 0x14, 0x50, 0xE7, 0x88, 0x1A, 0x17, 0x00, 0x00, 0x00, 0x85, 0x09, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0x02, 0x46, 0x6A, 0x4D, 0x4F, 0xF4, 0xA4, 0x63, ++ 0x03, 0xFB, 0x02, 0xF3, 0x8B, 0xB0, 0xEF, 0x18, 0x04, 0x90, 0x39, 0x46, ++ 0x66, 0x48, 0x06, 0x93, 0x0C, 0xF0, 0x4A, 0xFD, 0x97, 0xF8, 0x62, 0x30, ++ 0x02, 0x2B, 0x00, 0xF0, 0xDD, 0x80, 0x04, 0x2B, 0x00, 0xF0, 0x98, 0x80, ++ 0xDF, 0xF8, 0x98, 0xA1, 0x60, 0x4C, 0x00, 0x2B, 0x00, 0xF0, 0x89, 0x80, ++ 0x9A, 0xF8, 0x12, 0x30, 0x9A, 0xF8, 0x11, 0x20, 0x1A, 0x44, 0x01, 0x2A, ++ 0x5E, 0xD0, 0x0A, 0xB9, 0x5B, 0x4B, 0x1A, 0x60, 0x06, 0x9E, 0xD4, 0xF8, ++ 0xD8, 0x31, 0x06, 0xF1, 0x18, 0x00, 0x28, 0x44, 0x98, 0x47, 0x06, 0xF1, ++ 0x28, 0x00, 0xD4, 0xF8, 0xD8, 0x31, 0x28, 0x44, 0x98, 0x47, 0x04, 0x9A, ++ 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x02, 0x53, 0x93, 0xF8, 0xC0, 0x24, ++ 0x00, 0x2A, 0x3A, 0xD1, 0x04, 0x9A, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, ++ 0x02, 0x53, 0x05, 0x26, 0x93, 0xF8, 0x63, 0x00, 0x0A, 0xF0, 0x02, 0xFA, ++ 0x4B, 0x4B, 0x1A, 0x69, 0xBA, 0x42, 0x04, 0xBF, 0x00, 0x22, 0x1A, 0x61, ++ 0x00, 0x21, 0x4F, 0xF4, 0xA4, 0x62, 0x38, 0x46, 0xE9, 0xF7, 0x22, 0xFC, ++ 0x04, 0x99, 0x9A, 0xF8, 0x11, 0x20, 0x9A, 0xF8, 0x12, 0x30, 0xD4, 0xF8, ++ 0x50, 0xC4, 0x01, 0x91, 0x4F, 0xF4, 0xA4, 0x60, 0x00, 0xFB, 0x01, 0x55, ++ 0x7F, 0x24, 0x00, 0x93, 0x3F, 0x49, 0xC5, 0xF8, 0x2C, 0xC0, 0x13, 0x44, ++ 0x4F, 0xF4, 0x80, 0x70, 0x3D, 0x4A, 0x2F, 0x63, 0x85, 0xF8, 0x62, 0x60, ++ 0x85, 0xF8, 0x65, 0x40, 0x85, 0xF8, 0x66, 0x40, 0x0D, 0xF0, 0xC2, 0xFE, ++ 0x39, 0x48, 0x39, 0x46, 0x0B, 0xB0, 0xBD, 0xE8, 0xF0, 0x4F, 0x0C, 0xF0, ++ 0x91, 0xBC, 0x93, 0xF8, 0xC1, 0x04, 0x01, 0x21, 0x09, 0xF0, 0x2E, 0xFC, ++ 0x9A, 0xF8, 0x13, 0x30, 0x01, 0x3B, 0x8A, 0xF8, 0x13, 0x30, 0xB9, 0xE7, ++ 0x31, 0x4A, 0xDA, 0xF8, 0x08, 0x60, 0xDF, 0xF8, 0xC8, 0xE0, 0xDF, 0xF8, ++ 0xC8, 0x90, 0xDF, 0xF8, 0xC8, 0x80, 0xD2, 0xE9, 0x00, 0x01, 0x21, 0xF0, ++ 0x10, 0x0C, 0x4C, 0xEA, 0x00, 0x00, 0xC2, 0xF8, 0x04, 0xC0, 0xCE, 0xF8, ++ 0x00, 0x00, 0xB0, 0x6B, 0xB6, 0x8F, 0xC9, 0xF8, 0x00, 0x00, 0xC8, 0xF8, ++ 0x00, 0x60, 0x00, 0x2B, 0x88, 0xD1, 0x13, 0x68, 0x21, 0xF4, 0x88, 0x71, ++ 0x0B, 0x43, 0x51, 0x60, 0xCE, 0xF8, 0x00, 0x30, 0x80, 0xE7, 0x9A, 0xF8, ++ 0x11, 0x20, 0x9A, 0xF8, 0x12, 0x30, 0x01, 0x3A, 0xD2, 0xB2, 0x8A, 0xF8, ++ 0x11, 0x20, 0x71, 0xE7, 0xEA, 0xF7, 0x50, 0xFC, 0x00, 0x28, 0x40, 0xF0, ++ 0x28, 0x81, 0xDF, 0xF8, 0x60, 0xA0, 0x12, 0x4C, 0x9A, 0xF8, 0x10, 0x00, ++ 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x00, 0x53, 0x5A, 0x68, 0x19, 0x6C, ++ 0x22, 0xF0, 0x80, 0x02, 0x5A, 0x60, 0x09, 0xB1, 0x63, 0x6D, 0x98, 0x47, ++ 0x9A, 0xF8, 0x12, 0x30, 0x00, 0x2B, 0x40, 0xF0, 0x0D, 0x81, 0x0E, 0x48, ++ 0x0E, 0x49, 0x42, 0x68, 0x0E, 0x4E, 0x01, 0x60, 0x0A, 0x43, 0x32, 0x60, ++ 0xFF, 0x21, 0x9A, 0xF8, 0x11, 0x20, 0x8A, 0xF8, 0x10, 0x10, 0x49, 0xE7, ++ 0x18, 0x88, 0x17, 0x00, 0x08, 0x88, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x94, 0x40, 0x04, 0x40, 0x94, 0x64, 0x17, 0x00, 0xB8, 0x98, 0x15, 0x00, ++ 0xDC, 0x98, 0x15, 0x00, 0x00, 0x88, 0x17, 0x00, 0x98, 0x9C, 0x17, 0x00, ++ 0x8C, 0x84, 0x03, 0x35, 0x60, 0x00, 0x32, 0x40, 0x20, 0x00, 0x32, 0x40, ++ 0x24, 0x00, 0x32, 0x40, 0x04, 0x9E, 0xDF, 0xF8, 0x28, 0xA2, 0x7F, 0x49, ++ 0x9A, 0xF8, 0x12, 0x20, 0x7E, 0x4C, 0xDF, 0xF8, 0x20, 0xB2, 0x06, 0xF1, ++ 0x0A, 0x08, 0x08, 0xEB, 0x88, 0x03, 0x4F, 0xF4, 0x1E, 0x70, 0xC8, 0xEB, ++ 0x03, 0x13, 0x4F, 0xF0, 0xA4, 0x0C, 0x00, 0xFB, 0x08, 0x18, 0x46, 0x33, ++ 0x9E, 0x20, 0xCD, 0xE9, 0x08, 0x7A, 0x1C, 0xFB, 0x06, 0x06, 0x01, 0x3A, ++ 0x00, 0x20, 0x01, 0xEB, 0xC3, 0x03, 0x03, 0x93, 0x8A, 0xF8, 0x12, 0x20, ++ 0x88, 0xF8, 0x25, 0x00, 0x05, 0x90, 0x05, 0xEB, 0xC6, 0x06, 0xB9, 0x46, ++ 0xD8, 0xF8, 0x08, 0x32, 0x9D, 0xF8, 0x14, 0x70, 0x3B, 0xB1, 0x03, 0x99, ++ 0xD4, 0xF8, 0x84, 0x33, 0x4F, 0xF0, 0x80, 0x42, 0x28, 0x39, 0x38, 0x46, ++ 0x98, 0x47, 0xD8, 0xF8, 0x30, 0x32, 0x33, 0xB1, 0xD4, 0xF8, 0x84, 0x33, ++ 0x03, 0x99, 0x4F, 0xF0, 0x80, 0x42, 0x38, 0x46, 0x98, 0x47, 0xD9, 0xF8, ++ 0xF0, 0x34, 0x00, 0x2B, 0x00, 0xF0, 0x93, 0x80, 0x30, 0x46, 0x0C, 0xF0, ++ 0x55, 0xFC, 0xA6, 0xF1, 0x28, 0x0A, 0x07, 0x90, 0x50, 0x46, 0x0C, 0xF0, ++ 0x4F, 0xFC, 0x07, 0x99, 0x02, 0x46, 0x5B, 0x48, 0x0D, 0xF0, 0xA0, 0xFD, ++ 0xEF, 0xF3, 0x10, 0x83, 0xD8, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x58, 0x4A, ++ 0x01, 0x23, 0x13, 0x60, 0xDB, 0xF8, 0x00, 0x20, 0xD4, 0xF8, 0x84, 0x33, ++ 0x01, 0x32, 0xCB, 0xF8, 0x00, 0x20, 0x31, 0x46, 0x4F, 0xF0, 0x80, 0x42, ++ 0x38, 0x46, 0x98, 0x47, 0xD4, 0xF8, 0x84, 0x33, 0x51, 0x46, 0x38, 0x46, ++ 0x4F, 0xF0, 0x80, 0x42, 0x98, 0x47, 0xDB, 0xF8, 0x00, 0x30, 0x3B, 0xB1, ++ 0x4B, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0xCB, 0xF8, 0x00, 0x30, 0x0B, 0xB9, ++ 0x00, 0x2A, 0x66, 0xD1, 0x05, 0x9B, 0x03, 0x9A, 0x01, 0x33, 0x08, 0x32, ++ 0x05, 0x2B, 0x05, 0x93, 0x08, 0xF1, 0x08, 0x08, 0x06, 0xF1, 0x08, 0x06, ++ 0x09, 0xF1, 0x08, 0x09, 0x03, 0x92, 0xA1, 0xD1, 0x04, 0x9A, 0x4F, 0xF4, ++ 0xA4, 0x63, 0x03, 0xFB, 0x02, 0x53, 0xDD, 0xE9, 0x08, 0x7A, 0xD3, 0xF8, ++ 0x18, 0x35, 0x00, 0x2B, 0x4F, 0xD0, 0x06, 0x9B, 0x03, 0xF5, 0xA3, 0x66, ++ 0x2E, 0x44, 0x30, 0x46, 0x0C, 0xF0, 0x04, 0xFC, 0x01, 0x46, 0x38, 0x48, ++ 0x0D, 0xF0, 0x56, 0xFD, 0xEF, 0xF3, 0x10, 0x83, 0xD9, 0x07, 0x03, 0xD4, ++ 0x72, 0xB6, 0x33, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0xDB, 0xF8, 0x00, 0x20, ++ 0xD4, 0xF8, 0x84, 0x33, 0x01, 0x32, 0xCB, 0xF8, 0x00, 0x20, 0x31, 0x46, ++ 0x4F, 0xF0, 0x80, 0x42, 0x05, 0x20, 0x98, 0x47, 0xDB, 0xF8, 0x00, 0x30, ++ 0x3B, 0xB1, 0x2A, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0xCB, 0xF8, 0x00, 0x30, ++ 0x0B, 0xB9, 0x00, 0x2A, 0x43, 0xD1, 0x9A, 0xF8, 0x12, 0x20, 0x00, 0x2A, ++ 0x3C, 0xD0, 0x9A, 0xF8, 0x11, 0x30, 0x13, 0x44, 0x01, 0x2B, 0x7F, 0xF4, ++ 0x71, 0xAE, 0x23, 0x49, 0xDA, 0xF8, 0x08, 0x00, 0x22, 0x4E, 0xD1, 0xE9, ++ 0x00, 0x23, 0x23, 0xF0, 0x10, 0x03, 0x4B, 0x60, 0x1A, 0x43, 0x20, 0x49, ++ 0x20, 0x4B, 0x32, 0x60, 0x86, 0x6B, 0x82, 0x8F, 0x0E, 0x60, 0x1A, 0x60, ++ 0x5E, 0xE6, 0xD9, 0xF8, 0xC8, 0x34, 0x00, 0x2B, 0x7F, 0xF4, 0x68, 0xAF, ++ 0xA6, 0xF1, 0x28, 0x0A, 0x72, 0xE7, 0x62, 0xB6, 0x96, 0xE7, 0x06, 0x9B, ++ 0x03, 0xF5, 0xA3, 0x66, 0x2E, 0x44, 0xB5, 0xE7, 0x01, 0xF0, 0x4E, 0xFC, ++ 0x9A, 0xF8, 0x12, 0x30, 0xF4, 0xE6, 0x00, 0x20, 0xEA, 0xF7, 0x2C, 0xFB, ++ 0x12, 0x4B, 0x1A, 0x68, 0xD2, 0x05, 0x7F, 0xF5, 0xD0, 0xAE, 0x4F, 0xF4, ++ 0x80, 0x72, 0xC3, 0xF8, 0x80, 0x20, 0xBF, 0xF3, 0x4F, 0x8F, 0xBF, 0xF3, ++ 0x6F, 0x8F, 0xC6, 0xE6, 0x01, 0xF0, 0x5E, 0xFC, 0x2C, 0xE6, 0x62, 0xB6, ++ 0xB9, 0xE7, 0x00, 0xBF, 0x68, 0x65, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x88, 0x98, 0x15, 0x00, 0x38, 0x61, 0x17, 0x00, 0xA0, 0x98, 0x15, 0x00, ++ 0x98, 0x9C, 0x17, 0x00, 0x60, 0x00, 0x32, 0x40, 0x20, 0x00, 0x32, 0x40, ++ 0x24, 0x00, 0x32, 0x40, 0x00, 0xE1, 0x00, 0xE0, 0x00, 0x88, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x47, 0x05, 0x46, 0x4F, 0xF4, ++ 0xA4, 0x60, 0x2E, 0x78, 0x95, 0xF8, 0x29, 0x80, 0x4F, 0x4C, 0x00, 0xFB, ++ 0x08, 0xF0, 0xC6, 0xEB, 0x06, 0x17, 0x00, 0xEB, 0xC7, 0x07, 0x27, 0x44, ++ 0x4F, 0xF0, 0x78, 0x0A, 0x1A, 0xFB, 0x06, 0x0A, 0x87, 0xF8, 0x3A, 0x12, ++ 0x0A, 0xF5, 0xEC, 0x79, 0x95, 0xF8, 0x28, 0x30, 0x87, 0xF8, 0x38, 0x32, ++ 0xA1, 0x44, 0x87, 0xF8, 0x39, 0x62, 0x48, 0x46, 0x48, 0x22, 0x00, 0x21, ++ 0xE9, 0xF7, 0x46, 0xFA, 0x97, 0xF8, 0x38, 0x32, 0x37, 0x01, 0x05, 0x2B, ++ 0x0C, 0xD8, 0xDF, 0xE8, 0x03, 0xF0, 0x41, 0x51, 0x0B, 0x41, 0x6A, 0x03, ++ 0x0A, 0xF5, 0x0A, 0x70, 0x20, 0x44, 0x10, 0x22, 0x05, 0xF1, 0x08, 0x01, ++ 0x20, 0xF0, 0xC2, 0xF9, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x08, 0xF3, ++ 0xBA, 0x1B, 0x03, 0xEB, 0xC2, 0x03, 0x23, 0x44, 0x00, 0x20, 0x00, 0x21, ++ 0xC3, 0xE9, 0x88, 0x01, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x08, 0xF3, ++ 0xBA, 0x1B, 0x03, 0xEB, 0xC2, 0x02, 0x22, 0x44, 0x23, 0x44, 0x92, 0xF8, ++ 0x38, 0x12, 0x05, 0x29, 0x4F, 0xF0, 0x01, 0x00, 0x0C, 0xBF, 0xC3, 0xF8, ++ 0xAC, 0x94, 0xC3, 0xF8, 0xA8, 0x94, 0x4F, 0xF4, 0xA4, 0x63, 0x82, 0xF8, ++ 0x3B, 0x02, 0x03, 0xFB, 0x08, 0xF8, 0xD5, 0xE9, 0x02, 0x01, 0xD5, 0xE9, ++ 0x04, 0x23, 0xBF, 0x1B, 0x08, 0xEB, 0xC7, 0x07, 0x3C, 0x44, 0xC4, 0xE9, ++ 0x8F, 0x01, 0xC4, 0xE9, 0x91, 0x23, 0x2B, 0x79, 0x84, 0xF8, 0x4C, 0x32, ++ 0xBD, 0xE8, 0xF0, 0x87, 0x20, 0xF0, 0x90, 0xFA, 0x4F, 0xF4, 0xA4, 0x63, ++ 0x03, 0xFB, 0x08, 0xF3, 0xBA, 0x1B, 0x03, 0xEB, 0xC2, 0x03, 0x23, 0x44, ++ 0x20, 0xF0, 0x7F, 0x40, 0x00, 0x21, 0xC3, 0xE9, 0x88, 0x01, 0xC5, 0xE7, ++ 0x4F, 0xF4, 0xA4, 0x60, 0xBB, 0x1B, 0x00, 0xFB, 0x08, 0xF0, 0x00, 0xEB, ++ 0xC3, 0x00, 0x20, 0x44, 0xA9, 0x69, 0xC0, 0xF8, 0x28, 0x12, 0xE9, 0x69, ++ 0xC0, 0xF8, 0x2C, 0x12, 0x29, 0x6A, 0xC0, 0xF8, 0x30, 0x12, 0x00, 0x22, ++ 0x69, 0x6A, 0xC0, 0xF8, 0x34, 0x12, 0x00, 0x23, 0xC0, 0xE9, 0x88, 0x23, ++ 0xAC, 0xE7, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x08, 0xF2, 0x05, 0xA1, ++ 0xD1, 0xE9, 0x00, 0x01, 0xBB, 0x1B, 0x02, 0xEB, 0xC3, 0x03, 0x23, 0x44, ++ 0xC3, 0xE9, 0x88, 0x01, 0x9E, 0xE7, 0x00, 0xBF, 0x36, 0x5C, 0x36, 0x5C, ++ 0x36, 0x5C, 0x36, 0x5C, 0x18, 0x88, 0x17, 0x00, 0x78, 0x22, 0x10, 0xB4, ++ 0xC1, 0xEB, 0x01, 0x13, 0xD0, 0xF8, 0xA8, 0x44, 0x02, 0xFB, 0x01, 0x01, ++ 0x00, 0xEB, 0xC3, 0x03, 0x01, 0xF5, 0xEC, 0x71, 0x00, 0x22, 0x8C, 0x42, ++ 0x83, 0xF8, 0x3B, 0x22, 0x06, 0xD0, 0xD0, 0xF8, 0xAC, 0x34, 0x8B, 0x42, ++ 0x1C, 0xD0, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, 0x90, 0xF8, 0x3B, 0x32, ++ 0xC0, 0xF8, 0xA8, 0x24, 0x00, 0xF5, 0xEC, 0x71, 0x7B, 0xB9, 0x90, 0xF8, ++ 0xB3, 0x32, 0x00, 0xF5, 0x14, 0x71, 0x53, 0xB9, 0x90, 0xF8, 0x2B, 0x33, ++ 0x00, 0xF5, 0x32, 0x71, 0x2B, 0xB9, 0x90, 0xF8, 0xA3, 0x33, 0x00, 0xF5, ++ 0x50, 0x71, 0x00, 0x2B, 0xE1, 0xD0, 0xC0, 0xF8, 0xA8, 0x14, 0xE2, 0xE7, ++ 0x90, 0xF8, 0x1B, 0x34, 0x00, 0x22, 0xC0, 0xF8, 0xAC, 0x24, 0x43, 0xB9, ++ 0x90, 0xF8, 0x93, 0x34, 0x00, 0x2B, 0xD8, 0xD0, 0x00, 0xF5, 0x86, 0x63, ++ 0xC0, 0xF8, 0xAC, 0x34, 0xD3, 0xE7, 0x00, 0xF5, 0x6E, 0x73, 0xF9, 0xE7, ++ 0x70, 0xB5, 0xD0, 0xF8, 0xE4, 0x40, 0x54, 0xB1, 0x05, 0x4E, 0x05, 0x46, ++ 0x21, 0x46, 0xD6, 0xF8, 0x20, 0x33, 0x00, 0x22, 0x28, 0x46, 0x98, 0x47, ++ 0x24, 0x68, 0x00, 0x2C, 0xF6, 0xD1, 0x70, 0xBD, 0x88, 0x1A, 0x17, 0x00, ++ 0x04, 0x4A, 0x05, 0x4B, 0x11, 0x69, 0xD3, 0xF8, 0xE0, 0x31, 0x01, 0xF5, ++ 0x1C, 0x51, 0x28, 0x30, 0x10, 0x31, 0x18, 0x47, 0x00, 0x10, 0x50, 0x40, ++ 0x88, 0x1A, 0x17, 0x00, 0x0B, 0x4B, 0x1A, 0x78, 0x02, 0xB9, 0x70, 0x47, ++ 0x5B, 0x68, 0x1B, 0x07, 0xFB, 0xD4, 0x43, 0x68, 0x70, 0xB5, 0x04, 0x46, ++ 0x03, 0xB1, 0x70, 0xBD, 0x06, 0x4D, 0x28, 0x30, 0xD5, 0xF8, 0xD8, 0x31, ++ 0x98, 0x47, 0xD5, 0xF8, 0x50, 0x34, 0x20, 0x46, 0xBD, 0xE8, 0x70, 0x40, ++ 0x18, 0x47, 0x00, 0xBF, 0x1C, 0x9E, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0xF0, 0xB4, 0xA0, 0xF8, 0xD2, 0x10, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, ++ 0x03, 0xD4, 0x72, 0xB6, 0x1F, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x1F, 0x4D, ++ 0x1F, 0x4B, 0x2E, 0x68, 0x9A, 0x7C, 0x77, 0x1C, 0x01, 0x2A, 0x2F, 0x60, ++ 0x2B, 0xD9, 0x1D, 0x4C, 0x1A, 0x7D, 0x4F, 0xF4, 0xA4, 0x6C, 0x0C, 0xFB, ++ 0x02, 0x42, 0xB2, 0xF8, 0xD2, 0x40, 0xA1, 0x42, 0x1C, 0xD3, 0x9B, 0x68, ++ 0x5B, 0xB1, 0x01, 0x21, 0xB3, 0xF8, 0xD2, 0x20, 0x83, 0xF8, 0xD5, 0x10, ++ 0xB2, 0xFB, 0xF4, 0xF2, 0x83, 0xF8, 0xD4, 0x20, 0x1B, 0x68, 0x00, 0x2B, ++ 0xF4, 0xD1, 0x12, 0x4A, 0x13, 0x68, 0x1B, 0x0C, 0x1B, 0x04, 0x23, 0x43, ++ 0x13, 0x60, 0x2F, 0xB1, 0x0A, 0x4B, 0x2E, 0x60, 0x1B, 0x68, 0x0E, 0xB9, ++ 0x03, 0xB1, 0x62, 0xB6, 0xF0, 0xBC, 0x70, 0x47, 0x90, 0xF8, 0x63, 0x20, ++ 0x1A, 0x75, 0x0C, 0x46, 0xDD, 0xE7, 0x90, 0xF8, 0x63, 0x20, 0x1A, 0x75, ++ 0x40, 0xF2, 0x01, 0x13, 0x0C, 0x46, 0xA0, 0xF8, 0xD4, 0x30, 0xE2, 0xE7, ++ 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0x00, 0x88, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0x64, 0x00, 0x32, 0x40, 0x2D, 0xE9, 0xF0, 0x41, ++ 0x0C, 0x21, 0x04, 0x46, 0x82, 0xB0, 0x03, 0x23, 0x00, 0x22, 0x58, 0x20, ++ 0x0B, 0xF0, 0xEA, 0xFC, 0x3B, 0x4F, 0xFF, 0x22, 0x7B, 0x6D, 0x8D, 0xF8, ++ 0x07, 0x20, 0x05, 0x46, 0x94, 0xF8, 0x63, 0x00, 0x98, 0x47, 0xB4, 0xF8, ++ 0xB6, 0x14, 0x94, 0xF8, 0xB4, 0x04, 0x10, 0xF0, 0xED, 0xF9, 0x94, 0xF8, ++ 0xB5, 0x24, 0xB4, 0xF8, 0xB8, 0x64, 0xB4, 0xF8, 0xBA, 0x14, 0x84, 0xF8, ++ 0xC5, 0x21, 0x04, 0x2A, 0x08, 0xBF, 0x03, 0x22, 0x03, 0x46, 0xC4, 0xF8, ++ 0x90, 0x01, 0xA4, 0xF8, 0x94, 0x61, 0xA4, 0xF8, 0x96, 0x11, 0x84, 0xF8, ++ 0xC4, 0x21, 0x00, 0x28, 0x50, 0xD0, 0x1B, 0x79, 0x84, 0xF8, 0xBC, 0x34, ++ 0x7B, 0x6C, 0x0D, 0xF1, 0x07, 0x01, 0x04, 0xF2, 0xB4, 0x40, 0x98, 0x47, ++ 0x9D, 0xF8, 0x07, 0x10, 0x68, 0x70, 0xA9, 0x70, 0x06, 0x46, 0x94, 0xF8, ++ 0x63, 0x00, 0x28, 0x70, 0x94, 0xF8, 0x62, 0x30, 0x2B, 0xBB, 0x84, 0xF8, ++ 0x8A, 0x30, 0x7E, 0xBB, 0xFB, 0x6C, 0x94, 0xF8, 0x6C, 0x80, 0x98, 0x47, ++ 0xD7, 0xF8, 0xD8, 0x31, 0x04, 0xF1, 0x28, 0x00, 0x98, 0x47, 0x1A, 0x4A, ++ 0x1A, 0x49, 0xD7, 0xF8, 0xE0, 0x31, 0x09, 0x69, 0x4F, 0xF4, 0x1E, 0x70, ++ 0x00, 0xFB, 0x08, 0x28, 0x04, 0xF1, 0x18, 0x00, 0xD8, 0xF8, 0x08, 0x20, ++ 0x11, 0x44, 0x98, 0x47, 0x01, 0x23, 0x84, 0xF8, 0x78, 0x60, 0x84, 0xF8, ++ 0x8B, 0x30, 0x28, 0x46, 0x0B, 0xF0, 0xBE, 0xFC, 0x02, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x81, 0x02, 0x2B, 0xF7, 0xD1, 0x00, 0x23, 0x84, 0xF8, 0xDB, 0x30, ++ 0x00, 0x2E, 0xF2, 0xD1, 0xFB, 0x6C, 0x98, 0x47, 0x0A, 0x4B, 0x01, 0x22, ++ 0x5A, 0x72, 0xEC, 0xE7, 0xD7, 0xF8, 0xBC, 0x31, 0x20, 0x46, 0x98, 0x47, ++ 0x28, 0x46, 0x0B, 0xF0, 0xA7, 0xFC, 0x02, 0xB0, 0xBD, 0xE8, 0xF0, 0x81, ++ 0x1B, 0x79, 0xFF, 0xDE, 0x88, 0x1A, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, ++ 0x00, 0x10, 0x50, 0x40, 0xD8, 0x9C, 0x17, 0x00, 0x07, 0x4A, 0x93, 0x7C, ++ 0x51, 0x7C, 0x0B, 0x44, 0x01, 0x2B, 0x06, 0xD1, 0x90, 0x68, 0x90, 0xF8, ++ 0x62, 0x30, 0x00, 0x2B, 0x18, 0xBF, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, ++ 0x70, 0x47, 0x00, 0xBF, 0x00, 0x88, 0x17, 0x00, 0x05, 0x4A, 0x06, 0x49, ++ 0x93, 0x7C, 0x50, 0x7C, 0x03, 0x44, 0x00, 0x22, 0x01, 0x2B, 0x0A, 0x60, ++ 0x01, 0xDC, 0xFF, 0xF7, 0x65, 0xB9, 0x70, 0x47, 0x00, 0x88, 0x17, 0x00, ++ 0x2C, 0x00, 0x32, 0x40, 0x13, 0x4B, 0x00, 0x22, 0x02, 0x70, 0x9B, 0x68, ++ 0x03, 0xB3, 0x10, 0xB4, 0x01, 0x46, 0x01, 0x24, 0x10, 0x46, 0x08, 0xE0, ++ 0x93, 0xF8, 0x64, 0x20, 0x1A, 0xB1, 0x93, 0xF8, 0xC0, 0x24, 0x72, 0xB9, ++ 0x01, 0x30, 0x1B, 0x68, 0x7B, 0xB1, 0x93, 0xF8, 0x62, 0x20, 0x00, 0x2A, ++ 0xF2, 0xD0, 0x93, 0xF8, 0x64, 0x20, 0x00, 0x2A, 0xF5, 0xD0, 0x93, 0xF8, ++ 0xC0, 0x24, 0x00, 0x2A, 0xF1, 0xD0, 0x0C, 0x70, 0x1B, 0x68, 0x00, 0x2B, ++ 0xEF, 0xD1, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, 0x18, 0x46, 0x70, 0x47, ++ 0x00, 0x88, 0x17, 0x00, 0x10, 0xB5, 0x04, 0x23, 0x04, 0x46, 0xFF, 0x22, ++ 0x00, 0x21, 0x87, 0x20, 0x0B, 0xF0, 0x16, 0xFC, 0x04, 0x60, 0xBD, 0xE8, ++ 0x10, 0x40, 0x0B, 0xF0, 0x41, 0xBC, 0x00, 0xBF, 0x11, 0xF4, 0x00, 0x01, ++ 0x70, 0xB5, 0x04, 0x46, 0x16, 0xD0, 0x00, 0x25, 0x2A, 0x4B, 0x80, 0xF8, ++ 0x78, 0x50, 0x19, 0x69, 0x29, 0x48, 0x2A, 0x4B, 0x80, 0xF8, 0x24, 0x50, ++ 0x40, 0xF2, 0x01, 0x72, 0x01, 0xF5, 0x1C, 0x51, 0x44, 0x61, 0x82, 0x83, ++ 0xD3, 0xF8, 0xE0, 0x31, 0x10, 0x31, 0x0C, 0x30, 0x98, 0x47, 0x84, 0xF8, ++ 0x6B, 0x50, 0x70, 0xBD, 0x90, 0xF8, 0x6B, 0x30, 0x21, 0x4A, 0x01, 0x33, ++ 0xDB, 0xB2, 0x12, 0x68, 0x80, 0xF8, 0x6B, 0x30, 0x52, 0x78, 0x9A, 0x42, ++ 0x25, 0xD0, 0x90, 0xF8, 0x64, 0x30, 0xC3, 0xB9, 0x1C, 0x4B, 0x5B, 0x78, ++ 0x23, 0xB1, 0x1C, 0x4A, 0x13, 0x68, 0x23, 0xF0, 0x00, 0x43, 0x13, 0x60, ++ 0x15, 0x4B, 0x1A, 0x7A, 0x0A, 0xB1, 0x01, 0x3A, 0x1A, 0x72, 0x14, 0x4A, ++ 0x17, 0x48, 0xD2, 0xF8, 0xD8, 0x21, 0x01, 0x21, 0x99, 0x83, 0x90, 0x47, ++ 0x63, 0x68, 0x23, 0xF4, 0x00, 0x73, 0x63, 0x60, 0x70, 0xBD, 0x0E, 0x4B, ++ 0x90, 0xF8, 0x63, 0x00, 0xD3, 0xF8, 0x94, 0x34, 0x10, 0x49, 0x22, 0x46, ++ 0xBD, 0xE8, 0x70, 0x40, 0x18, 0x47, 0x80, 0xF8, 0x6B, 0x10, 0x4F, 0xF4, ++ 0x80, 0x60, 0x0D, 0x49, 0x0D, 0xF0, 0x74, 0xFA, 0x05, 0x4B, 0x20, 0x46, ++ 0xD3, 0xF8, 0xBC, 0x31, 0xBD, 0xE8, 0x70, 0x40, 0x18, 0x47, 0x00, 0xBF, ++ 0x00, 0x10, 0x50, 0x40, 0x1C, 0x9E, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0xC8, 0x35, 0x17, 0x00, 0x4C, 0x36, 0x17, 0x00, 0x34, 0x04, 0x32, 0x40, ++ 0x28, 0x9E, 0x17, 0x00, 0x99, 0x71, 0x13, 0x00, 0xF0, 0x98, 0x15, 0x00, ++ 0x30, 0xB4, 0x01, 0x25, 0x00, 0x24, 0x1D, 0x70, 0x14, 0x70, 0x04, 0x28, ++ 0x20, 0xD8, 0xDF, 0xE8, 0x00, 0xF0, 0x03, 0x18, 0x09, 0x05, 0x14, 0x00, ++ 0x00, 0x21, 0x19, 0x70, 0x01, 0x23, 0x13, 0x70, 0x30, 0xBC, 0x70, 0x47, ++ 0x09, 0x78, 0x10, 0x29, 0x0F, 0xD0, 0x20, 0x29, 0x01, 0xD1, 0x02, 0x21, ++ 0x19, 0x70, 0x03, 0x23, 0x13, 0x70, 0x30, 0xBC, 0x70, 0x47, 0x04, 0x23, ++ 0x13, 0x70, 0x30, 0xBC, 0x70, 0x47, 0x02, 0x23, 0x13, 0x70, 0x30, 0xBC, ++ 0x70, 0x47, 0x00, 0x21, 0x19, 0x70, 0xF0, 0xE7, 0x05, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xE1, 0xDA, 0x30, 0xBC, 0x03, 0x49, ++ 0x03, 0x48, 0xAD, 0x22, 0x0D, 0xF0, 0x50, 0xBC, 0x38, 0x36, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x64, 0x7D, 0x15, 0x00, 0x22, 0x4A, 0x13, 0x68, ++ 0xC3, 0xF3, 0x0F, 0x33, 0x23, 0xB1, 0x13, 0x68, 0xC3, 0xF3, 0x0F, 0x33, ++ 0x96, 0x2B, 0x36, 0xD9, 0x96, 0x20, 0x1E, 0x49, 0x1E, 0x4B, 0x0A, 0x68, ++ 0x18, 0x81, 0xC2, 0xF3, 0x0F, 0x32, 0x22, 0xB1, 0x0A, 0x68, 0xC2, 0xF3, ++ 0x0F, 0x32, 0x96, 0x2A, 0x25, 0xD9, 0x96, 0x22, 0x19, 0x49, 0x5A, 0x81, ++ 0x0A, 0x68, 0xC2, 0xF3, 0x0F, 0x32, 0x22, 0xB1, 0x0A, 0x68, 0xC2, 0xF3, ++ 0x0F, 0x32, 0x96, 0x2A, 0x15, 0xD9, 0x96, 0x22, 0x14, 0x49, 0x9A, 0x81, ++ 0x0A, 0x68, 0xC2, 0xF3, 0x0F, 0x32, 0x22, 0xB1, 0x0A, 0x68, 0xC2, 0xF3, ++ 0x0F, 0x32, 0x96, 0x2A, 0x03, 0xD9, 0x96, 0x22, 0xDA, 0x81, 0x1A, 0x82, ++ 0x70, 0x47, 0x0A, 0x68, 0xC2, 0xF3, 0x0F, 0x32, 0xDA, 0x81, 0x1A, 0x82, ++ 0x70, 0x47, 0x0A, 0x68, 0xC2, 0xF3, 0x0F, 0x32, 0xE6, 0xE7, 0x0A, 0x68, ++ 0xC2, 0xF3, 0x0F, 0x32, 0xD6, 0xE7, 0x10, 0x68, 0xC0, 0xF3, 0x0F, 0x30, ++ 0xC5, 0xE7, 0x00, 0xBF, 0x00, 0x02, 0x32, 0x40, 0x04, 0x02, 0x32, 0x40, ++ 0x98, 0x9C, 0x17, 0x00, 0x08, 0x02, 0x32, 0x40, 0x0C, 0x02, 0x32, 0x40, ++ 0x38, 0xB5, 0x0B, 0x4C, 0x34, 0x22, 0x00, 0x21, 0x20, 0x46, 0xE8, 0xF7, ++ 0x0B, 0xFF, 0x09, 0x48, 0x09, 0x4A, 0x0A, 0x49, 0x22, 0x60, 0x01, 0x25, ++ 0x00, 0x23, 0xE5, 0x77, 0x02, 0x60, 0x63, 0x82, 0x63, 0x60, 0xD1, 0xF8, ++ 0xA0, 0x31, 0x98, 0x47, 0x05, 0x4B, 0x63, 0x62, 0x38, 0xBD, 0x00, 0xBF, ++ 0x98, 0x9C, 0x17, 0x00, 0x60, 0x00, 0x32, 0x40, 0xDE, 0xFF, 0xFF, 0x7F, ++ 0x88, 0x1A, 0x17, 0x00, 0x7D, 0x71, 0x13, 0x00, 0x38, 0xB5, 0x51, 0x4D, ++ 0x51, 0x4C, 0xAB, 0x78, 0x13, 0xB9, 0xD4, 0xF8, 0xE4, 0x30, 0x98, 0x47, ++ 0xFF, 0xF7, 0xD4, 0xFF, 0xFF, 0xF7, 0x6A, 0xF8, 0xFE, 0xF7, 0xF8, 0xFC, ++ 0x09, 0xF0, 0xDC, 0xFC, 0x07, 0xF0, 0x78, 0xFD, 0x08, 0xF0, 0xAA, 0xFE, ++ 0xD4, 0xF8, 0x8C, 0x33, 0x98, 0x47, 0xAB, 0x78, 0x00, 0x2B, 0x00, 0xF0, ++ 0x82, 0x80, 0xFD, 0xF7, 0x61, 0xFA, 0x45, 0x4D, 0x2B, 0x68, 0x1B, 0x78, ++ 0x9B, 0x07, 0x7D, 0xD4, 0x03, 0xF0, 0x70, 0xFD, 0x09, 0xF0, 0x7C, 0xFE, ++ 0x63, 0x6E, 0x98, 0x47, 0xD4, 0xF8, 0x7C, 0x31, 0x98, 0x47, 0xEF, 0xF7, ++ 0x0D, 0xF8, 0xEF, 0xF7, 0x0D, 0xF8, 0xEF, 0xF7, 0x0D, 0xF8, 0x3C, 0x4B, ++ 0x93, 0xF8, 0xFA, 0x30, 0x00, 0x2B, 0x62, 0xD1, 0xD4, 0xF8, 0xE4, 0x34, ++ 0x98, 0x47, 0x39, 0x4A, 0x29, 0x68, 0x13, 0x68, 0x38, 0x48, 0x39, 0x4D, ++ 0xC3, 0xF3, 0x15, 0x03, 0x43, 0xF0, 0x20, 0x73, 0x13, 0x60, 0x8B, 0x78, ++ 0x02, 0x68, 0xDC, 0x06, 0x4C, 0xBF, 0x22, 0xF0, 0x00, 0x42, 0x42, 0xF0, ++ 0x00, 0x42, 0x02, 0x60, 0x32, 0x4A, 0x33, 0x4C, 0x33, 0x48, 0x13, 0xF0, ++ 0x01, 0x0F, 0x13, 0x68, 0x14, 0xBF, 0x43, 0xF4, 0x80, 0x23, 0x23, 0xF4, ++ 0x80, 0x23, 0x13, 0x60, 0x22, 0x68, 0x2F, 0x4B, 0x42, 0xF0, 0x00, 0x62, ++ 0x22, 0x60, 0x02, 0x68, 0x2D, 0x4C, 0x22, 0xF4, 0x70, 0x02, 0x42, 0xF4, ++ 0x00, 0x12, 0x02, 0x60, 0x1A, 0x68, 0x22, 0xF4, 0xE0, 0x62, 0x42, 0xF4, ++ 0xC0, 0x62, 0x1A, 0x60, 0x1A, 0x68, 0x22, 0xF4, 0x60, 0x52, 0x42, 0xF4, ++ 0x00, 0x52, 0x1A, 0x60, 0x1A, 0x68, 0x22, 0xF4, 0xE0, 0x32, 0x42, 0xF4, ++ 0x40, 0x42, 0x1A, 0x60, 0x1A, 0x68, 0x42, 0xF4, 0x60, 0x22, 0x1A, 0x60, ++ 0x2B, 0x68, 0x20, 0x4A, 0x23, 0x40, 0x43, 0xF4, 0xBB, 0x63, 0xA0, 0xF5, ++ 0x66, 0x70, 0x43, 0xF0, 0x04, 0x03, 0x2B, 0x60, 0x03, 0x68, 0xA5, 0xF1, ++ 0xF6, 0x55, 0xA5, 0xF5, 0x32, 0x25, 0x23, 0x40, 0x43, 0xF0, 0x3F, 0x03, ++ 0xA5, 0xF6, 0xFF, 0x15, 0x03, 0x60, 0x15, 0x60, 0x4B, 0x78, 0x2B, 0xB1, ++ 0xD2, 0xF8, 0x24, 0x31, 0x43, 0xF0, 0x40, 0x03, 0xC2, 0xF8, 0x24, 0x31, ++ 0x38, 0xBD, 0x12, 0x4B, 0x00, 0x22, 0x1A, 0x70, 0x9B, 0xE7, 0xFD, 0xF7, ++ 0xD5, 0xF9, 0x7C, 0xE7, 0x03, 0x20, 0xEE, 0xF7, 0x8B, 0xFC, 0x7D, 0xE7, ++ 0x3C, 0x36, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x34, 0x36, 0x17, 0x00, ++ 0x2C, 0x19, 0x17, 0x00, 0xF0, 0x00, 0x32, 0x40, 0x80, 0x04, 0x32, 0x40, ++ 0x20, 0x04, 0x32, 0x40, 0x10, 0x03, 0x32, 0x40, 0x40, 0x04, 0x32, 0x40, ++ 0x34, 0x04, 0x32, 0x40, 0x2C, 0x04, 0x32, 0x40, 0x00, 0x00, 0xFF, 0xFF, ++ 0x00, 0x01, 0x32, 0x40, 0x80, 0x35, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0x1C, 0x46, 0x05, 0x8C, 0x93, 0xF8, 0x62, 0x30, 0xD2, 0xF8, 0x20, 0x90, ++ 0x87, 0x69, 0xD0, 0xF8, 0x1C, 0xB0, 0x89, 0xB0, 0x16, 0x46, 0xAD, 0x02, ++ 0xDD, 0xE9, 0x12, 0x20, 0xD3, 0xB9, 0xB4, 0xF8, 0x68, 0xC0, 0xBC, 0xF1, ++ 0x00, 0x0F, 0x15, 0xD0, 0xD2, 0x8B, 0xB3, 0x6A, 0x0C, 0xFB, 0x02, 0xF2, ++ 0x05, 0x92, 0x18, 0x07, 0x05, 0xFB, 0x0C, 0xF2, 0x06, 0x92, 0x19, 0xD0, ++ 0x00, 0x23, 0xB7, 0xEB, 0x09, 0x0A, 0x4F, 0xF4, 0xFA, 0x76, 0x07, 0x93, ++ 0x05, 0x9B, 0x03, 0xF5, 0xC8, 0x73, 0xC4, 0xE9, 0x1F, 0xA3, 0x74, 0xE0, ++ 0x00, 0x28, 0x40, 0xF0, 0xC1, 0x80, 0x06, 0x95, 0x4F, 0xF0, 0x01, 0x0A, ++ 0xD0, 0x8B, 0xB2, 0x6A, 0x0A, 0xFB, 0x00, 0xF0, 0x12, 0x07, 0x05, 0x90, ++ 0x40, 0xF0, 0x32, 0x81, 0xF2, 0x6A, 0xDF, 0xF8, 0x94, 0xC2, 0xDF, 0xF8, ++ 0xD4, 0x82, 0xDC, 0xF8, 0x00, 0x30, 0x9F, 0x48, 0xC2, 0xF3, 0x03, 0x12, ++ 0x23, 0xF0, 0x7F, 0x03, 0x18, 0xF8, 0x02, 0x20, 0x02, 0xF0, 0x7F, 0x02, ++ 0x13, 0x43, 0xCC, 0xF8, 0x00, 0x30, 0xB3, 0x6A, 0x99, 0x4A, 0xC3, 0xF3, ++ 0xC0, 0x13, 0x41, 0xEA, 0x03, 0x51, 0x4F, 0xF0, 0x00, 0x43, 0x01, 0x60, ++ 0x13, 0x60, 0xBF, 0xF3, 0x4F, 0x8F, 0x00, 0xBF, 0x13, 0x68, 0x58, 0x00, ++ 0xFC, 0xD5, 0x93, 0x4B, 0x19, 0x68, 0xB1, 0xF9, 0x00, 0x10, 0x00, 0x29, ++ 0xC0, 0xF2, 0xB4, 0x80, 0x8E, 0x4A, 0x12, 0x68, 0x1F, 0xFA, 0x82, 0xFA, ++ 0xB2, 0x6A, 0x12, 0x07, 0x40, 0xF0, 0xA3, 0x80, 0xF2, 0x6A, 0x8C, 0x49, ++ 0x88, 0x48, 0xD1, 0xF8, 0x00, 0xC0, 0xC2, 0xF3, 0x03, 0x12, 0x2C, 0xF0, ++ 0x7F, 0x0C, 0x18, 0xF8, 0x02, 0x20, 0x02, 0xF0, 0x7F, 0x02, 0x42, 0xEA, ++ 0x0C, 0x02, 0x0A, 0x60, 0xB2, 0x6A, 0xC2, 0xF3, 0xC0, 0x12, 0x08, 0x31, ++ 0x12, 0x05, 0x42, 0xF0, 0x18, 0x02, 0x4F, 0xF0, 0x00, 0x46, 0x02, 0x60, ++ 0x0E, 0x60, 0xBF, 0xF3, 0x4F, 0x8F, 0x00, 0xBF, 0x0A, 0x68, 0x56, 0x00, ++ 0xFC, 0xD5, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x73, 0xDB, ++ 0x77, 0x4A, 0x94, 0xF8, 0x62, 0x30, 0x16, 0x68, 0x00, 0x22, 0xB6, 0xB2, ++ 0xAA, 0xEB, 0x06, 0x0A, 0x07, 0x92, 0xB7, 0xEB, 0x09, 0x09, 0x19, 0xEB, ++ 0x0A, 0x0A, 0x00, 0x2B, 0x84, 0xD0, 0x4F, 0xEA, 0xE5, 0x79, 0x2A, 0x46, ++ 0x4B, 0x46, 0x38, 0x46, 0x59, 0x46, 0x1F, 0xF0, 0x67, 0xFB, 0xBA, 0x1B, ++ 0x02, 0x92, 0x07, 0x9A, 0x00, 0xFB, 0x09, 0xF3, 0x6B, 0xEB, 0x02, 0x02, ++ 0x05, 0xFB, 0x01, 0x33, 0x03, 0x92, 0xA0, 0xFB, 0x05, 0x01, 0x19, 0x44, ++ 0xDD, 0xE9, 0x02, 0x23, 0x99, 0x42, 0x08, 0xBF, 0x90, 0x42, 0x38, 0xBF, ++ 0xCD, 0xE9, 0x02, 0x01, 0x64, 0x4B, 0x06, 0x9A, 0x1B, 0x68, 0xDD, 0xE9, ++ 0x02, 0x67, 0xB6, 0x18, 0x99, 0x01, 0x34, 0xD4, 0x05, 0x9B, 0xF1, 0x1A, ++ 0xA1, 0xF5, 0xC8, 0x71, 0x5F, 0x4F, 0x60, 0x4B, 0x3E, 0x69, 0x1B, 0x68, ++ 0xF6, 0x1A, 0x0E, 0x44, 0xE9, 0xF7, 0xDC, 0xFD, 0x3B, 0x69, 0xF3, 0x1A, ++ 0xA3, 0xF5, 0x86, 0x53, 0x0C, 0x3B, 0x18, 0x1A, 0x00, 0x28, 0x63, 0x6A, ++ 0xB8, 0xBF, 0x76, 0x19, 0xB3, 0x42, 0x24, 0xD0, 0x57, 0x4B, 0x1A, 0x6A, ++ 0xA2, 0x42, 0x43, 0xD0, 0x56, 0x4D, 0x31, 0x46, 0xD5, 0xF8, 0xE0, 0x31, ++ 0x04, 0xF1, 0x18, 0x00, 0x98, 0x47, 0xD5, 0xF8, 0xA8, 0x30, 0x20, 0x46, ++ 0x09, 0xB0, 0xBD, 0xE8, 0xF0, 0x4F, 0x18, 0x47, 0x90, 0xF8, 0x02, 0xA0, ++ 0xBA, 0xF1, 0x00, 0x0F, 0x01, 0xD1, 0x90, 0xF8, 0x03, 0xA0, 0x05, 0xFB, ++ 0x0A, 0xF0, 0x06, 0x90, 0x36, 0xE7, 0x4B, 0x49, 0x05, 0x9B, 0xC9, 0x1A, ++ 0xA1, 0xEB, 0x0A, 0x0A, 0x0A, 0xEB, 0x06, 0x01, 0xC6, 0xE7, 0x09, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x8F, 0x0B, 0x68, 0x58, 0x00, 0x88, 0xD4, 0x45, 0x49, ++ 0x45, 0x48, 0x4F, 0xF4, 0xBE, 0x72, 0x0D, 0xF0, 0xD7, 0xF9, 0x00, 0x22, ++ 0x94, 0xF8, 0x62, 0x30, 0x07, 0x92, 0xAA, 0xF5, 0xFA, 0x7A, 0x4F, 0xF4, ++ 0xFA, 0x76, 0x82, 0xE7, 0x12, 0x68, 0x51, 0x00, 0x3F, 0xF5, 0x48, 0xAF, ++ 0x3B, 0x49, 0x3C, 0x48, 0x4F, 0xF4, 0xBE, 0x72, 0x0D, 0xF0, 0xC4, 0xF9, ++ 0x4F, 0xF4, 0xFA, 0x7A, 0x2F, 0x4B, 0x41, 0xE7, 0x30, 0x4A, 0x66, 0x62, ++ 0x12, 0x68, 0x92, 0x01, 0xB6, 0xD4, 0x36, 0x4A, 0x36, 0x4D, 0x12, 0x68, ++ 0x93, 0xF8, 0x24, 0x10, 0x41, 0xF2, 0x13, 0x30, 0xC2, 0xF3, 0x07, 0x42, ++ 0x2A, 0x54, 0x00, 0x29, 0x32, 0xD1, 0x32, 0x4A, 0x32, 0x49, 0x12, 0x68, ++ 0x09, 0x68, 0x41, 0xF2, 0x14, 0x30, 0xD2, 0xB2, 0x2A, 0x54, 0x01, 0x22, ++ 0x83, 0xF8, 0x24, 0x20, 0x0B, 0x78, 0x93, 0x42, 0x06, 0xD1, 0x2D, 0x49, ++ 0x2D, 0x4A, 0x0B, 0x60, 0x13, 0x68, 0x43, 0xF0, 0x01, 0x03, 0x13, 0x60, ++ 0x41, 0xF2, 0x13, 0x32, 0x41, 0xF2, 0x14, 0x33, 0xA8, 0x5C, 0xE9, 0x5C, ++ 0x88, 0x42, 0x1D, 0xD2, 0x17, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0x0F, 0xDA, 0x41, 0xF2, 0x13, 0x32, 0x41, 0xF2, 0x14, 0x33, ++ 0xAA, 0x5C, 0xEB, 0x5C, 0x9A, 0x42, 0x07, 0xD3, 0x18, 0x49, 0x20, 0x48, ++ 0x15, 0x4D, 0x40, 0xF2, 0xD7, 0x12, 0x0D, 0xF0, 0xAF, 0xF9, 0x7E, 0xE7, ++ 0x12, 0x4D, 0x7C, 0xE7, 0x00, 0x22, 0x4F, 0xF4, 0xFA, 0x76, 0x07, 0x92, ++ 0x92, 0x46, 0x28, 0xE7, 0x12, 0x4E, 0x14, 0x48, 0xA9, 0x5C, 0xEA, 0x5C, ++ 0x33, 0x68, 0x06, 0x68, 0x16, 0x48, 0xF6, 0xB2, 0x1B, 0x0C, 0x00, 0x96, ++ 0x0C, 0xF0, 0x20, 0xFF, 0xD4, 0xE7, 0x00, 0xBF, 0x60, 0x81, 0x32, 0x40, ++ 0x6C, 0x81, 0x32, 0x40, 0x38, 0x36, 0x17, 0x00, 0x64, 0x81, 0x32, 0x40, ++ 0x4C, 0x00, 0x32, 0x40, 0x00, 0x10, 0x50, 0x40, 0xA4, 0x80, 0x32, 0x40, ++ 0x1C, 0x9E, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x70, 0xFE, 0xFF, 0xFF, ++ 0x70, 0x79, 0x15, 0x00, 0x04, 0x99, 0x15, 0x00, 0x44, 0x80, 0x32, 0x40, ++ 0x00, 0x40, 0x1E, 0x00, 0x90, 0x00, 0x32, 0x40, 0x74, 0x36, 0x17, 0x00, ++ 0x70, 0x80, 0x32, 0x40, 0x74, 0x80, 0x32, 0x40, 0x3C, 0x99, 0x15, 0x00, ++ 0x28, 0x99, 0x15, 0x00, 0x40, 0xA9, 0x15, 0x00, 0x0B, 0x02, 0x10, 0xB5, ++ 0x04, 0x46, 0x03, 0xD5, 0x00, 0x23, 0x80, 0xF8, 0x78, 0x30, 0x10, 0xBD, ++ 0x4F, 0xF4, 0x80, 0x60, 0x04, 0x49, 0x0C, 0xF0, 0x37, 0xFF, 0x04, 0x4B, ++ 0x20, 0x46, 0xD3, 0xF8, 0xBC, 0x31, 0xBD, 0xE8, 0x10, 0x40, 0x18, 0x47, ++ 0xB0, 0x99, 0x15, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0xDF, 0xF8, 0x70, 0x93, 0xD9, 0xF8, 0x20, 0xB0, 0x83, 0xB0, 0x4F, 0xF4, ++ 0x00, 0x20, 0x0B, 0xF0, 0x79, 0xFC, 0xBB, 0xF1, 0x00, 0x0F, 0x00, 0xF0, ++ 0xF5, 0x80, 0xBA, 0x4C, 0xDF, 0xF8, 0x58, 0xA3, 0xA1, 0x7F, 0xB9, 0x4F, ++ 0xDF, 0xF8, 0x54, 0x83, 0xB8, 0x4E, 0x00, 0x29, 0x00, 0xF0, 0xEA, 0x80, ++ 0x08, 0x07, 0x0E, 0xD5, 0xB6, 0x4B, 0xDB, 0xF8, 0x70, 0x00, 0x1B, 0x68, ++ 0xDA, 0xF8, 0x10, 0x20, 0x5B, 0x68, 0x03, 0x44, 0x9B, 0x1A, 0x00, 0x2B, ++ 0xC0, 0xF2, 0xCB, 0x80, 0x01, 0xF0, 0xF7, 0x01, 0xA1, 0x77, 0x4A, 0x07, ++ 0x00, 0xF1, 0x99, 0x80, 0x8B, 0x07, 0x15, 0xD5, 0xDB, 0xF8, 0x04, 0x30, ++ 0x23, 0xF0, 0x02, 0x03, 0xCB, 0xF8, 0x04, 0x30, 0x99, 0xF8, 0x1D, 0x30, ++ 0x05, 0x2B, 0x08, 0xD1, 0xA8, 0x4D, 0xA9, 0x48, 0xD5, 0xF8, 0xD8, 0x31, ++ 0x98, 0x47, 0x00, 0x23, 0xA1, 0x7F, 0x89, 0xF8, 0x1D, 0x30, 0x01, 0xF0, ++ 0xFD, 0x01, 0xA1, 0x77, 0xCD, 0x07, 0x2E, 0xD5, 0x33, 0x68, 0x58, 0x01, ++ 0x40, 0xF1, 0xA3, 0x80, 0x31, 0x68, 0x09, 0x0C, 0x11, 0xF4, 0x7C, 0x7F, ++ 0x00, 0xF0, 0xAA, 0x80, 0x9E, 0x4A, 0x10, 0x39, 0x01, 0xF0, 0xFF, 0x01, ++ 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, 0x01, 0x23, 0x93, 0xF8, 0x25, 0x20, ++ 0x00, 0x2A, 0x00, 0xF0, 0xA1, 0x80, 0x99, 0x4A, 0x93, 0xF8, 0x22, 0x10, ++ 0x13, 0x68, 0x98, 0x4A, 0xB3, 0xF9, 0x00, 0x30, 0x4F, 0xF4, 0xA4, 0x60, ++ 0x00, 0xFB, 0x01, 0x22, 0x00, 0x2B, 0x00, 0x92, 0xC0, 0xF2, 0x9F, 0x80, ++ 0x3B, 0x68, 0x13, 0xF4, 0xE0, 0x2F, 0x00, 0xF0, 0xA8, 0x80, 0xA1, 0x7F, ++ 0x01, 0xF0, 0xFE, 0x01, 0xA1, 0x77, 0x8A, 0x06, 0x9D, 0xD5, 0x8E, 0x4E, ++ 0x8E, 0x49, 0x35, 0x68, 0xC5, 0xF3, 0x41, 0x17, 0x3A, 0x46, 0x02, 0x20, ++ 0x0C, 0xF0, 0xAA, 0xFE, 0x00, 0x23, 0xC5, 0xF3, 0x47, 0x15, 0x8B, 0xF8, ++ 0x78, 0x30, 0x00, 0x2F, 0x40, 0xF0, 0xB2, 0x80, 0x87, 0x4B, 0x80, 0x4E, ++ 0x5A, 0x78, 0x1A, 0x70, 0x86, 0x4A, 0x87, 0x4D, 0x13, 0x68, 0x23, 0xF4, ++ 0x00, 0x73, 0x13, 0x60, 0xDB, 0xF8, 0x04, 0x30, 0xD6, 0xF8, 0xD8, 0x21, ++ 0x23, 0xF0, 0x01, 0x03, 0xCB, 0xF8, 0x04, 0x30, 0x0B, 0xF1, 0x28, 0x00, ++ 0x90, 0x47, 0x2A, 0x68, 0x13, 0x78, 0x02, 0x2B, 0x00, 0xF0, 0x24, 0x81, ++ 0x78, 0x49, 0x0B, 0x68, 0x23, 0xF0, 0x01, 0x03, 0x0B, 0x60, 0x13, 0x78, ++ 0x01, 0x2B, 0x12, 0xD1, 0x01, 0xF5, 0xFF, 0x41, 0x34, 0x31, 0x78, 0x4A, ++ 0xDA, 0xF8, 0x10, 0x30, 0x08, 0x68, 0xB2, 0xF8, 0xB2, 0x10, 0xD6, 0xF8, ++ 0xE0, 0x21, 0x03, 0xEB, 0x40, 0x13, 0x59, 0x1A, 0x0B, 0xF1, 0x18, 0x00, ++ 0x90, 0x47, 0x2B, 0x68, 0x1B, 0x78, 0x02, 0x2B, 0x00, 0xF0, 0x00, 0x81, ++ 0xA1, 0x7F, 0x01, 0xF0, 0xDF, 0x01, 0xA1, 0x77, 0x4B, 0xE7, 0x6D, 0x49, ++ 0x61, 0x4D, 0x02, 0x20, 0x0C, 0xF0, 0x60, 0xFE, 0x6B, 0x49, 0x63, 0x68, ++ 0x0A, 0x68, 0x22, 0xF0, 0x04, 0x02, 0x0A, 0x60, 0x22, 0x68, 0x43, 0xF4, ++ 0x00, 0x73, 0x1A, 0x43, 0x4A, 0x61, 0xD5, 0xF8, 0x98, 0x14, 0x63, 0x60, ++ 0x9B, 0xF8, 0x63, 0x00, 0xD5, 0xF8, 0x94, 0x34, 0x5A, 0x46, 0x98, 0x47, ++ 0x3B, 0x68, 0xA1, 0x7F, 0x23, 0xF0, 0x7C, 0x73, 0x3B, 0x60, 0xD8, 0xF8, ++ 0x00, 0x30, 0x01, 0xF0, 0xFB, 0x01, 0x43, 0xF4, 0x80, 0x03, 0xC8, 0xF8, ++ 0x00, 0x30, 0xA1, 0x77, 0x3E, 0xE7, 0x5B, 0x48, 0x0C, 0xF0, 0xEA, 0xFD, ++ 0x7F, 0xE7, 0x00, 0x22, 0x9B, 0xF8, 0x6C, 0x00, 0x11, 0x46, 0xF8, 0xF7, ++ 0x01, 0xFB, 0x60, 0xB1, 0xA1, 0x7F, 0x2B, 0xE7, 0x55, 0x48, 0x0C, 0xF0, ++ 0xDD, 0xFD, 0x72, 0xE7, 0x54, 0x48, 0x0C, 0xF0, 0xD9, 0xFD, 0x6E, 0xE7, ++ 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xDA, 0xF8, 0x10, 0x30, 0xA1, 0x7F, ++ 0xCB, 0xF8, 0x70, 0x30, 0x1A, 0xE7, 0x93, 0x45, 0x3F, 0xF4, 0x5E, 0xAF, ++ 0x4D, 0x49, 0x4E, 0x48, 0x40, 0xF2, 0x22, 0x32, 0x0D, 0xF0, 0x40, 0xF8, ++ 0x3B, 0x68, 0x13, 0xF4, 0xE0, 0x2F, 0x7F, 0xF4, 0x58, 0xAF, 0x32, 0x68, ++ 0x33, 0x68, 0x49, 0x49, 0xD0, 0x0F, 0xC3, 0xF3, 0x80, 0x73, 0x05, 0x46, ++ 0x02, 0x46, 0x02, 0x20, 0x01, 0x93, 0x0C, 0xF0, 0x05, 0xFE, 0x01, 0x9B, ++ 0x53, 0xEA, 0x05, 0x02, 0x28, 0x46, 0x3F, 0xF4, 0x46, 0xAF, 0x2F, 0x4D, ++ 0x00, 0x9A, 0x19, 0x46, 0xD5, 0xF8, 0x3C, 0x32, 0x98, 0x47, 0x33, 0x68, ++ 0x23, 0xF0, 0x00, 0x43, 0x33, 0x60, 0x33, 0x68, 0x23, 0xF0, 0x80, 0x43, ++ 0x33, 0x60, 0x36, 0xE7, 0xDA, 0xF8, 0x10, 0x10, 0x01, 0xF5, 0x9C, 0x51, ++ 0x32, 0x46, 0x08, 0x31, 0x05, 0xE0, 0xDA, 0xF8, 0x10, 0x30, 0xCB, 0x1A, ++ 0x00, 0x2B, 0xC0, 0xF2, 0xC2, 0x80, 0x13, 0x68, 0x1B, 0x07, 0xF6, 0xD5, ++ 0xDF, 0xF8, 0x90, 0x80, 0xD8, 0xF8, 0x00, 0x30, 0x23, 0xF0, 0x08, 0x03, ++ 0xC8, 0xF8, 0x00, 0x30, 0xD8, 0xF8, 0x00, 0x30, 0xDE, 0x06, 0x19, 0xD5, ++ 0x2C, 0x49, 0x19, 0x4E, 0x02, 0x20, 0x0C, 0xF0, 0xCF, 0xFD, 0x2B, 0x4B, ++ 0xDF, 0xF8, 0x74, 0xC0, 0x1A, 0x68, 0xD6, 0xF8, 0x3C, 0x32, 0x12, 0x0C, ++ 0x8C, 0xF8, 0x00, 0x20, 0x05, 0xF0, 0x01, 0x01, 0x78, 0x08, 0x5A, 0x46, ++ 0x98, 0x47, 0xD8, 0xF8, 0x00, 0x30, 0x23, 0xF0, 0x10, 0x03, 0xC8, 0xF8, ++ 0x00, 0x30, 0x1B, 0xE7, 0x21, 0x4B, 0x22, 0x49, 0x0B, 0x4E, 0x01, 0x25, ++ 0x1D, 0x60, 0x02, 0x20, 0x0C, 0xF0, 0xB2, 0xFD, 0x0F, 0x4A, 0x1F, 0x49, ++ 0x53, 0x78, 0x0D, 0x60, 0xAB, 0x42, 0x94, 0xBF, 0x00, 0x23, 0x01, 0x23, ++ 0x13, 0x70, 0x09, 0xE7, 0x98, 0x9C, 0x17, 0x00, 0x74, 0x00, 0x32, 0x40, ++ 0x70, 0x00, 0x32, 0x40, 0xC8, 0x35, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x28, 0x9E, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0x8C, 0x00, 0x32, 0x40, 0x20, 0x9A, 0x15, 0x00, ++ 0x13, 0x53, 0x1E, 0x00, 0x90, 0xB3, 0x33, 0x40, 0x74, 0x36, 0x17, 0x00, ++ 0x2C, 0x19, 0x17, 0x00, 0xC0, 0x99, 0x15, 0x00, 0x4C, 0x00, 0x32, 0x40, ++ 0xC4, 0x99, 0x15, 0x00, 0xDC, 0x99, 0x15, 0x00, 0xF0, 0x99, 0x15, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x04, 0x9A, 0x15, 0x00, 0x14, 0x9A, 0x15, 0x00, ++ 0x40, 0x9A, 0x15, 0x00, 0x44, 0x80, 0x32, 0x40, 0x64, 0x85, 0x32, 0x40, ++ 0x4C, 0x9A, 0x15, 0x00, 0x68, 0x85, 0x32, 0x40, 0x1C, 0x9E, 0x17, 0x00, ++ 0x00, 0x10, 0x50, 0x40, 0x6C, 0x00, 0x32, 0x40, 0x36, 0x4B, 0x30, 0x22, ++ 0x1A, 0x60, 0xF7, 0xF7, 0x35, 0xF9, 0xF9, 0xE6, 0xEF, 0xF3, 0x10, 0x83, ++ 0xD8, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x32, 0x4B, 0x01, 0x22, 0x1A, 0x60, ++ 0x31, 0x4B, 0x2F, 0x4F, 0x1A, 0x68, 0x01, 0x32, 0x1A, 0x60, 0x00, 0x21, ++ 0x3A, 0x68, 0x39, 0x60, 0x02, 0xF0, 0x0F, 0x08, 0xDA, 0xF8, 0x10, 0x20, ++ 0x31, 0x46, 0x16, 0x46, 0x0A, 0x46, 0x47, 0xF2, 0x30, 0x50, 0x04, 0xE0, ++ 0xDA, 0xF8, 0x10, 0x10, 0x89, 0x1B, 0x81, 0x42, 0x1B, 0xD8, 0x39, 0x68, ++ 0x09, 0x07, 0xF7, 0xD1, 0x25, 0x48, 0x26, 0x49, 0xD0, 0xF8, 0x00, 0xC0, ++ 0x0F, 0x68, 0x16, 0x46, 0xDA, 0xF8, 0x10, 0x20, 0xB8, 0xF1, 0x00, 0x0F, ++ 0x1A, 0xD1, 0x22, 0x4A, 0x04, 0x21, 0x11, 0x60, 0x1A, 0x68, 0x32, 0xB1, ++ 0x1B, 0x49, 0x01, 0x3A, 0x1A, 0x60, 0x0B, 0x68, 0x0A, 0xB9, 0x03, 0xB1, ++ 0x62, 0xB6, 0x2A, 0x68, 0xA0, 0xE6, 0x1C, 0x49, 0x00, 0x92, 0x02, 0x20, ++ 0x0C, 0xF0, 0x24, 0xFD, 0x15, 0x4B, 0x00, 0x9A, 0xD3, 0xE7, 0x19, 0x49, ++ 0x02, 0x20, 0x0C, 0xF0, 0x1D, 0xFD, 0x3B, 0xE7, 0x07, 0xEA, 0x0C, 0x07, ++ 0x7F, 0x07, 0xE0, 0xD4, 0xCD, 0xE9, 0x00, 0x16, 0x80, 0x46, 0x16, 0x46, ++ 0x01, 0xE0, 0x7A, 0x07, 0x12, 0xD4, 0x00, 0x9A, 0xD8, 0xF8, 0x00, 0x70, ++ 0x12, 0x68, 0xDA, 0xF8, 0x10, 0x10, 0x47, 0xF2, 0x30, 0x50, 0x89, 0x1B, ++ 0x81, 0x42, 0x07, 0xEA, 0x02, 0x07, 0xF0, 0xD9, 0x0B, 0x49, 0x02, 0x20, ++ 0x0C, 0xF0, 0x00, 0xFD, 0x03, 0x4B, 0xEA, 0xE7, 0x01, 0x9E, 0xC4, 0xE7, ++ 0x38, 0x00, 0x32, 0x40, 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x6C, 0x80, 0x32, 0x40, 0x74, 0x80, 0x32, 0x40, 0x70, 0x80, 0x32, 0x40, ++ 0x5C, 0x9A, 0x15, 0x00, 0x2C, 0x9A, 0x15, 0x00, 0x68, 0x9A, 0x15, 0x00, ++ 0x10, 0xB5, 0x00, 0x20, 0x0B, 0xF0, 0xD0, 0xF8, 0x01, 0x28, 0x05, 0xD1, ++ 0x05, 0x4B, 0xBD, 0xE8, 0x10, 0x40, 0xD3, 0xF8, 0x60, 0x31, 0x18, 0x47, ++ 0x00, 0x21, 0xBD, 0xE8, 0x10, 0x40, 0x08, 0x46, 0x0B, 0xF0, 0x1A, 0xB8, ++ 0x88, 0x1A, 0x17, 0x00, 0x03, 0x4B, 0x30, 0x22, 0x1A, 0x60, 0x01, 0x21, ++ 0x00, 0x20, 0x0B, 0xF0, 0x11, 0xB8, 0x00, 0xBF, 0x38, 0x00, 0x32, 0x40, ++ 0xF8, 0xB5, 0x90, 0xF8, 0x64, 0x30, 0x00, 0x2B, 0x46, 0xD0, 0x90, 0xF8, ++ 0x8A, 0x30, 0x04, 0x46, 0x00, 0x2B, 0x42, 0xD1, 0x3D, 0x4E, 0x3E, 0x49, ++ 0x94, 0xF8, 0x6C, 0x30, 0x3D, 0x4A, 0x67, 0x6A, 0x4F, 0xF4, 0x1E, 0x70, ++ 0x00, 0xFB, 0x03, 0x13, 0x9D, 0x68, 0x13, 0x6A, 0xA3, 0x42, 0x3D, 0x44, ++ 0x54, 0xD0, 0xD6, 0xF8, 0xE0, 0x31, 0x29, 0x46, 0x04, 0xF1, 0x18, 0x00, ++ 0x98, 0x47, 0x20, 0x46, 0xFF, 0xF7, 0x82, 0xF8, 0xD4, 0xF8, 0x80, 0x10, ++ 0xD6, 0xF8, 0x14, 0x32, 0x39, 0x44, 0x20, 0x46, 0x98, 0x47, 0xD6, 0xF8, ++ 0xA4, 0x30, 0x2A, 0x46, 0x39, 0x46, 0x20, 0x46, 0x98, 0x47, 0xD8, 0xB9, ++ 0x94, 0xF8, 0x78, 0x30, 0x62, 0x68, 0x2C, 0x49, 0x01, 0x33, 0xDB, 0xB2, ++ 0x42, 0xF0, 0x01, 0x02, 0x09, 0x68, 0x84, 0xF8, 0x78, 0x30, 0x62, 0x60, ++ 0x0A, 0x78, 0x93, 0x42, 0x21, 0xD8, 0x39, 0xD0, 0xB3, 0xEB, 0x52, 0x0F, ++ 0x26, 0xD0, 0xB3, 0xEB, 0x92, 0x0F, 0x4F, 0xEA, 0x92, 0x01, 0x21, 0xD0, ++ 0x01, 0xEB, 0x41, 0x01, 0x8B, 0x42, 0x1D, 0xD0, 0xF8, 0xBD, 0x90, 0xF8, ++ 0x8C, 0x20, 0x00, 0x2A, 0xB8, 0xD0, 0x01, 0x3B, 0xDB, 0xB2, 0x01, 0x2B, ++ 0x80, 0xF8, 0x8A, 0x30, 0x29, 0xD9, 0x02, 0x2B, 0x16, 0x4E, 0xB0, 0xD1, ++ 0x90, 0xF8, 0x63, 0x00, 0xD6, 0xF8, 0xC0, 0x31, 0x00, 0x21, 0x98, 0x47, ++ 0xA9, 0xE7, 0xD6, 0xF8, 0x64, 0x11, 0x94, 0xF8, 0x6C, 0x00, 0x22, 0x46, ++ 0xBD, 0xE8, 0xF8, 0x40, 0xF8, 0xF7, 0x30, 0xB9, 0xBD, 0xE8, 0xF8, 0x40, ++ 0xEA, 0xF7, 0x5A, 0xBE, 0x0F, 0x4B, 0x65, 0x62, 0x93, 0xF8, 0xB5, 0x30, ++ 0x00, 0x2B, 0xAA, 0xD1, 0x0D, 0x4B, 0x1B, 0x68, 0x1B, 0x78, 0x02, 0x2B, ++ 0x9F, 0xD1, 0xA4, 0xE7, 0xEA, 0xF7, 0x4C, 0xFE, 0x20, 0x46, 0xBD, 0xE8, ++ 0xF8, 0x40, 0x06, 0xF0, 0x47, 0xBD, 0xBD, 0xE8, 0xF8, 0x40, 0xFF, 0xF7, ++ 0x9B, 0xB8, 0x00, 0xBF, 0x88, 0x1A, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, ++ 0x1C, 0x9E, 0x17, 0x00, 0xC8, 0x35, 0x17, 0x00, 0x2C, 0x19, 0x17, 0x00, ++ 0x74, 0x36, 0x17, 0x00, 0x38, 0x4B, 0x2D, 0xE9, 0xF0, 0x47, 0x9C, 0x68, ++ 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x35, 0x4B, ++ 0x01, 0x22, 0x1A, 0x60, 0x34, 0x4D, 0x2B, 0x68, 0x04, 0x20, 0x01, 0x33, ++ 0x2B, 0x60, 0xF6, 0xF7, 0xF1, 0xFC, 0x4F, 0xF0, 0x80, 0x41, 0x04, 0x20, ++ 0xF6, 0xF7, 0x8C, 0xFD, 0x2B, 0x68, 0x2B, 0xB1, 0x2C, 0x4A, 0x01, 0x3B, ++ 0x12, 0x68, 0x2B, 0x60, 0x00, 0x2B, 0x4C, 0xD0, 0xDF, 0xF8, 0xB4, 0x80, ++ 0x00, 0x2C, 0x43, 0xD0, 0x29, 0x4F, 0x2A, 0x4E, 0x40, 0xF6, 0xE7, 0x35, ++ 0x02, 0xE0, 0x24, 0x68, 0x00, 0x2C, 0x3B, 0xD0, 0x94, 0xF8, 0x62, 0x30, ++ 0x02, 0x2B, 0xF8, 0xD1, 0x94, 0xF8, 0xD5, 0x30, 0x01, 0x3B, 0xDB, 0xB2, ++ 0x84, 0xF8, 0xD5, 0x30, 0x00, 0x2B, 0xF0, 0xD1, 0x94, 0xF8, 0xD4, 0x30, ++ 0x84, 0xF8, 0xD5, 0x30, 0x20, 0x46, 0xFE, 0xF7, 0xD3, 0xFF, 0x61, 0x6A, ++ 0xD8, 0xF8, 0x14, 0x32, 0x01, 0xF6, 0xE8, 0x31, 0x20, 0x46, 0x98, 0x47, ++ 0x3B, 0x68, 0xB4, 0xF8, 0xD2, 0x20, 0x59, 0x01, 0xB5, 0xEB, 0x43, 0x1F, ++ 0x28, 0xBF, 0x01, 0xEB, 0x82, 0x21, 0x32, 0x69, 0x23, 0x6C, 0xA2, 0xF6, ++ 0xE8, 0x39, 0x89, 0x44, 0x20, 0x46, 0x4A, 0x46, 0x1B, 0xB1, 0xD8, 0xF8, ++ 0xA4, 0x30, 0x61, 0x6A, 0x98, 0x47, 0x94, 0xF8, 0xC0, 0x34, 0x04, 0xF1, ++ 0x18, 0x00, 0x49, 0x46, 0x00, 0x2B, 0xC6, 0xD0, 0xD8, 0xF8, 0xE0, 0x31, ++ 0x98, 0x47, 0x24, 0x68, 0x00, 0x2C, 0xC3, 0xD1, 0xD8, 0xF8, 0x84, 0x31, ++ 0xBD, 0xE8, 0xF0, 0x47, 0x18, 0x47, 0x00, 0x2A, 0xB0, 0xD0, 0x62, 0xB6, ++ 0xAE, 0xE7, 0x00, 0xBF, 0x00, 0x88, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x40, 0x80, 0x32, 0x40, 0x00, 0x10, 0x50, 0x40, ++ 0x88, 0x1A, 0x17, 0x00, 0x08, 0xF0, 0x4A, 0xBE, 0x14, 0x4B, 0x15, 0x4A, ++ 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x10, 0xB5, 0x14, 0x68, 0x00, 0x2B, ++ 0x04, 0xF0, 0x40, 0x74, 0x14, 0xDB, 0x20, 0x46, 0x0B, 0xF0, 0x04, 0xF9, ++ 0x0F, 0x4B, 0x9B, 0x7C, 0x3B, 0xB9, 0x0F, 0x4A, 0x0F, 0x4B, 0x10, 0x6A, ++ 0xD3, 0xF8, 0xCC, 0x31, 0xBD, 0xE8, 0x10, 0x40, 0x18, 0x47, 0x0C, 0x4B, ++ 0x20, 0x46, 0xD3, 0xF8, 0x68, 0x31, 0xBD, 0xE8, 0x10, 0x40, 0x18, 0x47, ++ 0xB4, 0xF1, 0x40, 0x7F, 0xE7, 0xD1, 0x08, 0x49, 0x08, 0x48, 0x4F, 0xF4, ++ 0x9D, 0x62, 0x0C, 0xF0, 0xBB, 0xFD, 0xE0, 0xE7, 0x38, 0x36, 0x17, 0x00, ++ 0x80, 0xB6, 0x17, 0x00, 0x00, 0x88, 0x17, 0x00, 0x1C, 0x9E, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x78, 0x9A, 0x15, 0x00, ++ 0xF0, 0xB5, 0x2D, 0x4E, 0x2D, 0x4B, 0xDF, 0xF8, 0xC8, 0xE0, 0xDF, 0xF8, ++ 0xC8, 0xC0, 0x2C, 0x4F, 0x4F, 0xF4, 0x1E, 0x72, 0x02, 0xFB, 0x00, 0x62, ++ 0x15, 0x8D, 0xD4, 0x8C, 0x44, 0xEA, 0x05, 0x44, 0x1C, 0x60, 0x52, 0x8D, ++ 0x27, 0x4D, 0x5A, 0x60, 0x00, 0x24, 0x27, 0x4A, 0xCE, 0xF8, 0x00, 0x40, ++ 0x4F, 0xF0, 0x00, 0x53, 0xCC, 0xF8, 0x00, 0x40, 0x2C, 0x60, 0x00, 0xF1, ++ 0x10, 0x05, 0x3C, 0x60, 0xEC, 0xB2, 0x13, 0x60, 0x13, 0x68, 0x9F, 0x00, ++ 0xFC, 0xD4, 0xDD, 0x00, 0x26, 0xD4, 0x15, 0x68, 0xC5, 0xF3, 0x07, 0x43, ++ 0xA3, 0x42, 0x4F, 0xEA, 0x15, 0x45, 0x1F, 0xD0, 0xED, 0xB2, 0xDF, 0xF8, ++ 0x5C, 0xE0, 0xDF, 0xF8, 0x68, 0xC0, 0x18, 0x4F, 0x2D, 0x04, 0x4F, 0xF0, ++ 0xFF, 0x33, 0x45, 0xF0, 0x80, 0x45, 0xCE, 0xF8, 0x00, 0x30, 0xCC, 0xF8, ++ 0x00, 0x30, 0x15, 0x60, 0x3B, 0x68, 0x5A, 0x00, 0xFC, 0xD4, 0x4F, 0xF4, ++ 0x1E, 0x73, 0x03, 0xFB, 0x00, 0x63, 0x0C, 0x48, 0x1D, 0x8D, 0xDA, 0x8C, ++ 0x42, 0xEA, 0x05, 0x42, 0x02, 0x60, 0x0D, 0x4A, 0x5B, 0x8D, 0x13, 0x60, ++ 0x0B, 0x01, 0x43, 0xEA, 0x04, 0x43, 0x09, 0x4A, 0x43, 0xF0, 0x80, 0x43, ++ 0x43, 0xF0, 0x02, 0x03, 0x13, 0x60, 0x13, 0x68, 0x5B, 0x00, 0xFC, 0xD4, ++ 0x20, 0x46, 0xF0, 0xBD, 0x68, 0x65, 0x17, 0x00, 0xBC, 0x00, 0x32, 0x40, ++ 0xB8, 0x00, 0x32, 0x40, 0xB4, 0x00, 0x32, 0x40, 0xC4, 0x00, 0x32, 0x40, ++ 0xC0, 0x00, 0x32, 0x40, 0xAC, 0x00, 0x32, 0x40, 0xB0, 0x00, 0x32, 0x40, ++ 0x2D, 0xE9, 0xF0, 0x41, 0x82, 0xB0, 0x47, 0x78, 0x90, 0xF8, 0x29, 0x60, ++ 0x01, 0x23, 0x8D, 0xF8, 0x06, 0x30, 0xFF, 0x2F, 0x4F, 0xF0, 0x00, 0x03, ++ 0x04, 0x46, 0x00, 0xF1, 0x04, 0x08, 0x8D, 0xF8, 0x07, 0x30, 0x00, 0xF0, ++ 0x83, 0x80, 0x74, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0x73, 0xDB, 0x3A, 0x46, 0x94, 0xF8, 0x28, 0x30, 0x70, 0x49, 0x4F, 0xF4, ++ 0x80, 0x70, 0x0C, 0xF0, 0xF5, 0xFA, 0x07, 0xF1, 0x10, 0x05, 0x6E, 0x4B, ++ 0xED, 0xB2, 0xD3, 0xF8, 0x18, 0x33, 0x29, 0x46, 0x20, 0x46, 0x98, 0x47, ++ 0x6B, 0x4A, 0x6C, 0x48, 0x6C, 0x49, 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, ++ 0x07, 0x22, 0x17, 0x8D, 0xD3, 0x8C, 0x43, 0xEA, 0x07, 0x43, 0x03, 0x60, ++ 0x53, 0x8D, 0x0B, 0x60, 0x0D, 0xF1, 0x06, 0x03, 0x0D, 0xF1, 0x07, 0x02, ++ 0x94, 0xF8, 0x28, 0x00, 0x41, 0x46, 0xFF, 0xF7, 0x7B, 0xF8, 0x63, 0x4B, ++ 0xA2, 0x68, 0x1A, 0x60, 0xE2, 0x68, 0x5A, 0x60, 0x22, 0x69, 0x9A, 0x60, ++ 0x62, 0x69, 0xDA, 0x60, 0x9D, 0xF8, 0x07, 0x30, 0x04, 0x2B, 0x65, 0xD0, ++ 0x5D, 0x4A, 0x12, 0x68, 0x02, 0x2B, 0x12, 0x78, 0x1F, 0xD1, 0xD1, 0x07, ++ 0x00, 0xF1, 0x85, 0x80, 0x5A, 0x48, 0x01, 0x68, 0x21, 0xF0, 0x01, 0x01, ++ 0x01, 0x60, 0x92, 0x07, 0x17, 0xD5, 0x9D, 0xF8, 0x06, 0x00, 0x94, 0xF8, ++ 0x2A, 0x10, 0x56, 0x4A, 0x2B, 0x04, 0x43, 0xEA, 0x00, 0x33, 0x43, 0xEA, ++ 0x06, 0x13, 0x43, 0xEA, 0x81, 0x03, 0x43, 0xF0, 0x80, 0x43, 0x13, 0x60, ++ 0x13, 0x68, 0x5C, 0x00, 0xFC, 0xD4, 0x28, 0x46, 0x02, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x81, 0x97, 0x07, 0x6F, 0xD4, 0x9D, 0xF8, 0x06, 0x00, 0x94, 0xF8, ++ 0x2A, 0x10, 0x4A, 0x4A, 0x1B, 0x02, 0x43, 0xEA, 0x00, 0x33, 0x43, 0xEA, ++ 0x05, 0x43, 0x43, 0xEA, 0x06, 0x13, 0x43, 0xEA, 0x81, 0x03, 0x43, 0xF0, ++ 0x80, 0x43, 0x13, 0x60, 0x13, 0x68, 0x59, 0x00, 0xFC, 0xD4, 0x28, 0x46, ++ 0x02, 0xB0, 0xBD, 0xE8, 0xF0, 0x81, 0x0D, 0x2F, 0x89, 0xD9, 0x40, 0x49, ++ 0x40, 0x48, 0x40, 0xF2, 0x5C, 0x52, 0x0C, 0xF0, 0xAB, 0xFC, 0x82, 0xE7, ++ 0x90, 0xF8, 0x28, 0x30, 0x05, 0x2B, 0x4E, 0xD0, 0x34, 0x48, 0x35, 0x4A, ++ 0x25, 0x78, 0x3B, 0x49, 0x4F, 0xF0, 0xFF, 0x33, 0x03, 0x60, 0x13, 0x60, ++ 0x94, 0xF8, 0x28, 0x30, 0x94, 0xF8, 0x29, 0x20, 0x4F, 0xF4, 0x80, 0x70, ++ 0x0C, 0xF0, 0x6C, 0xFA, 0x05, 0xEB, 0x86, 0x05, 0x29, 0x4B, 0xED, 0xB2, ++ 0xD3, 0xF8, 0x48, 0x34, 0x29, 0x46, 0x20, 0x46, 0x98, 0x47, 0x83, 0xE7, ++ 0x30, 0x4A, 0xA1, 0x69, 0x11, 0x60, 0xE1, 0x69, 0x51, 0x60, 0x21, 0x6A, ++ 0x91, 0x60, 0x27, 0x4A, 0x2D, 0x49, 0x60, 0x6A, 0x12, 0x68, 0x08, 0x60, ++ 0x12, 0x78, 0x90, 0x07, 0xB1, 0xD5, 0x9D, 0xF8, 0x06, 0x00, 0x94, 0xF8, ++ 0x2A, 0x10, 0x23, 0x4A, 0x1B, 0x02, 0x43, 0xEA, 0x00, 0x33, 0x43, 0xEA, ++ 0x05, 0x43, 0x43, 0xEA, 0x06, 0x13, 0x43, 0xEA, 0x81, 0x03, 0x43, 0xF0, ++ 0x80, 0x43, 0x13, 0x60, 0x13, 0x68, 0x58, 0x00, 0xFC, 0xD4, 0x28, 0x46, ++ 0x02, 0xB0, 0xBD, 0xE8, 0xF0, 0x81, 0x1D, 0x49, 0xA0, 0x69, 0x08, 0x60, ++ 0xE0, 0x69, 0x48, 0x60, 0x20, 0x6A, 0x88, 0x60, 0x60, 0x6A, 0xC8, 0x60, ++ 0x75, 0xE7, 0x5A, 0x1E, 0x01, 0x2A, 0xDA, 0xD8, 0x73, 0xE7, 0x18, 0x4B, ++ 0x05, 0x78, 0x1B, 0x68, 0x09, 0x4A, 0x1B, 0x0E, 0x03, 0x3B, 0x2B, 0x44, ++ 0x03, 0xEB, 0x46, 0x03, 0xDD, 0xB2, 0x29, 0x46, 0xD2, 0xF8, 0x48, 0x34, ++ 0x98, 0x47, 0x28, 0x46, 0x02, 0xB0, 0xBD, 0xE8, 0xF0, 0x81, 0x00, 0xBF, ++ 0x38, 0x36, 0x17, 0x00, 0xB4, 0x9A, 0x15, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x68, 0x65, 0x17, 0x00, 0xBC, 0x00, 0x32, 0x40, 0xC0, 0x00, 0x32, 0x40, ++ 0xAC, 0x00, 0x32, 0x40, 0x34, 0x36, 0x17, 0x00, 0x64, 0x05, 0x32, 0x40, ++ 0xC4, 0x00, 0x32, 0x40, 0x70, 0x79, 0x15, 0x00, 0xA0, 0x9A, 0x15, 0x00, ++ 0x90, 0x9A, 0x15, 0x00, 0xC8, 0x00, 0x32, 0x40, 0xD4, 0x00, 0x32, 0x40, ++ 0xD8, 0x00, 0x32, 0x40, 0x33, 0x4A, 0x13, 0x68, 0xB0, 0xEB, 0x13, 0x6F, ++ 0x70, 0xB5, 0x04, 0x46, 0x46, 0xD8, 0x0F, 0x28, 0x24, 0xD8, 0x30, 0x4B, ++ 0x30, 0x4D, 0x31, 0x49, 0x31, 0x48, 0x4F, 0xF0, 0xFF, 0x32, 0x1A, 0x60, ++ 0xA3, 0x10, 0x2A, 0x60, 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, 0x03, 0x00, ++ 0xD1, 0xF8, 0x54, 0x34, 0x04, 0xF0, 0x03, 0x01, 0x98, 0x47, 0x2B, 0x4A, ++ 0x2B, 0x49, 0x2C, 0x4E, 0x2C, 0x4D, 0x2D, 0x48, 0x24, 0x04, 0x00, 0x23, ++ 0x44, 0xF0, 0x80, 0x44, 0x33, 0x60, 0x2B, 0x60, 0x13, 0x60, 0x03, 0x60, ++ 0x0A, 0x46, 0x0C, 0x60, 0x13, 0x68, 0x5B, 0x00, 0xFC, 0xD4, 0x70, 0xBD, ++ 0xA0, 0xF1, 0x10, 0x05, 0x25, 0x48, 0x4F, 0xF4, 0x1E, 0x73, 0xED, 0xB2, ++ 0x03, 0xFB, 0x05, 0x05, 0x28, 0x46, 0x95, 0xF8, 0x22, 0x60, 0xFD, 0xF7, ++ 0xD3, 0xFF, 0x1A, 0x4B, 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, 0x06, 0x36, ++ 0x96, 0xF8, 0x62, 0x30, 0x02, 0x2B, 0xE8, 0xD0, 0x28, 0x8D, 0xEB, 0x8C, ++ 0x11, 0x49, 0x12, 0x4A, 0x43, 0xEA, 0x00, 0x43, 0x0B, 0x60, 0x6B, 0x8D, ++ 0x13, 0x60, 0xCC, 0xE7, 0x13, 0x68, 0x15, 0x68, 0x0F, 0x48, 0x0E, 0x4A, ++ 0x1B, 0x0E, 0x01, 0x33, 0xE3, 0x1A, 0x61, 0x1E, 0xA1, 0xEB, 0x15, 0x61, ++ 0x03, 0xEB, 0xD3, 0x73, 0x5B, 0x10, 0x4F, 0xF4, 0xA4, 0x64, 0x01, 0xF0, ++ 0x01, 0x01, 0x04, 0xFB, 0x03, 0x00, 0x04, 0x31, 0xBD, 0xE8, 0x70, 0x40, ++ 0xD2, 0xF8, 0x54, 0x34, 0x18, 0x47, 0x00, 0xBF, 0xD8, 0x00, 0x32, 0x40, ++ 0xBC, 0x00, 0x32, 0x40, 0xC0, 0x00, 0x32, 0x40, 0x88, 0x1A, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0xB4, 0x00, 0x32, 0x40, 0xC4, 0x00, 0x32, 0x40, ++ 0xAC, 0x00, 0x32, 0x40, 0xB0, 0x00, 0x32, 0x40, 0xB8, 0x00, 0x32, 0x40, ++ 0x68, 0x65, 0x17, 0x00, 0xF0, 0xB4, 0x0E, 0x49, 0x0E, 0x4F, 0x0F, 0x4E, ++ 0x0F, 0x4D, 0x10, 0x4C, 0x4F, 0xF0, 0xFF, 0x32, 0x00, 0xF1, 0x10, 0x03, ++ 0x0E, 0x48, 0x3A, 0x60, 0xDB, 0xB2, 0x0A, 0x60, 0x00, 0x21, 0x01, 0x60, ++ 0x1B, 0x04, 0x18, 0x30, 0x43, 0xF0, 0x80, 0x43, 0x31, 0x60, 0x02, 0x46, ++ 0x29, 0x60, 0x21, 0x60, 0x03, 0x60, 0x13, 0x68, 0x5B, 0x00, 0xFC, 0xD4, ++ 0xF0, 0xBC, 0x70, 0x47, 0xC0, 0x00, 0x32, 0x40, 0xBC, 0x00, 0x32, 0x40, ++ 0xB0, 0x00, 0x32, 0x40, 0xB4, 0x00, 0x32, 0x40, 0xB8, 0x00, 0x32, 0x40, ++ 0xAC, 0x00, 0x32, 0x40, 0x08, 0xB5, 0x4F, 0xF0, 0x80, 0x60, 0x0A, 0xF0, ++ 0xA5, 0xFE, 0x00, 0x21, 0xBD, 0xE8, 0x08, 0x40, 0x08, 0x46, 0x0A, 0xF0, ++ 0x89, 0xBC, 0x00, 0xBF, 0x14, 0x4B, 0x15, 0x49, 0x1A, 0x68, 0x22, 0xF0, ++ 0x02, 0x02, 0xF0, 0xB4, 0x1A, 0x60, 0x1A, 0x68, 0x12, 0x4F, 0x13, 0x4E, ++ 0x13, 0x4D, 0x14, 0x4C, 0x42, 0xF0, 0x01, 0x02, 0x1A, 0x60, 0x4F, 0xF4, ++ 0x40, 0x72, 0x3A, 0x60, 0x07, 0x68, 0x82, 0x88, 0x00, 0x20, 0x30, 0x60, ++ 0x28, 0x60, 0x27, 0x60, 0x0E, 0x4C, 0x0A, 0x60, 0x19, 0x68, 0x62, 0x68, ++ 0x0D, 0x4D, 0xA6, 0xF5, 0x00, 0x46, 0x44, 0x3E, 0x2A, 0x43, 0x21, 0xF4, ++ 0xE0, 0x61, 0x19, 0x60, 0x25, 0x60, 0x32, 0x60, 0xF0, 0xBC, 0xFC, 0xF7, ++ 0x57, 0xBE, 0x00, 0xBF, 0x4C, 0x00, 0x32, 0x40, 0x14, 0x00, 0x32, 0x40, ++ 0x1C, 0x00, 0x32, 0x40, 0xA4, 0x80, 0x32, 0x40, 0xA8, 0x80, 0x32, 0x40, ++ 0x10, 0x00, 0x32, 0x40, 0x98, 0x9C, 0x17, 0x00, 0x8C, 0x84, 0x03, 0x35, ++ 0x0B, 0x49, 0x0C, 0x48, 0x38, 0xB5, 0x02, 0x68, 0x4B, 0x68, 0x0B, 0x4C, ++ 0x0B, 0x4D, 0x42, 0xF0, 0x02, 0x02, 0x23, 0x43, 0x02, 0x60, 0x0C, 0x60, ++ 0x00, 0x20, 0x2B, 0x60, 0xFC, 0xF7, 0x36, 0xFE, 0x07, 0x4B, 0x08, 0x49, ++ 0x08, 0x4A, 0x19, 0x60, 0x13, 0x68, 0x0B, 0x43, 0x13, 0x60, 0x38, 0xBD, ++ 0x98, 0x9C, 0x17, 0x00, 0x4C, 0x00, 0x32, 0x40, 0x8C, 0xA4, 0x07, 0x35, ++ 0x60, 0x00, 0x32, 0x40, 0x70, 0x80, 0x32, 0x40, 0x01, 0x00, 0x04, 0x00, ++ 0x74, 0x80, 0x32, 0x40, 0x0D, 0x49, 0x0E, 0x48, 0x38, 0xB5, 0x02, 0x68, ++ 0x4B, 0x68, 0x0D, 0x4C, 0x0D, 0x4D, 0x22, 0xF0, 0x02, 0x02, 0x23, 0x43, ++ 0x02, 0x60, 0x0C, 0x60, 0x00, 0x20, 0x2B, 0x60, 0xFC, 0xF7, 0x10, 0xFE, ++ 0x09, 0x4B, 0x0A, 0x4A, 0x0A, 0x49, 0x19, 0x60, 0x13, 0x68, 0x23, 0xF4, ++ 0x80, 0x23, 0x23, 0xF0, 0x01, 0x03, 0x13, 0x60, 0x38, 0xBD, 0x00, 0xBF, ++ 0x98, 0x9C, 0x17, 0x00, 0x4C, 0x00, 0x32, 0x40, 0x8C, 0x84, 0x03, 0x35, ++ 0x60, 0x00, 0x32, 0x40, 0x70, 0x80, 0x32, 0x40, 0x74, 0x80, 0x32, 0x40, ++ 0x01, 0x00, 0x04, 0x00, 0x00, 0xEB, 0x80, 0x03, 0xC0, 0xEB, 0x03, 0x10, ++ 0x04, 0x4B, 0x08, 0x44, 0x03, 0xEB, 0xC0, 0x00, 0x90, 0xF8, 0xA5, 0x01, ++ 0x21, 0x38, 0x18, 0xBF, 0x01, 0x20, 0x70, 0x47, 0x68, 0x65, 0x17, 0x00, ++ 0x00, 0xEB, 0x80, 0x03, 0xC0, 0xEB, 0x03, 0x10, 0x04, 0x4B, 0x08, 0x44, ++ 0x03, 0xEB, 0xC0, 0x00, 0x90, 0xF8, 0xA4, 0x01, 0x21, 0x38, 0x18, 0xBF, ++ 0x01, 0x20, 0x70, 0x47, 0x68, 0x65, 0x17, 0x00, 0xF8, 0xB5, 0x37, 0x4A, ++ 0x37, 0x4B, 0x92, 0xF8, 0x30, 0x10, 0x1B, 0x68, 0x00, 0x29, 0x45, 0xD1, ++ 0x00, 0x28, 0x40, 0xD0, 0x9B, 0xB2, 0x01, 0x21, 0x80, 0xEA, 0xE0, 0x76, ++ 0x00, 0x28, 0x4F, 0xEA, 0x83, 0x23, 0x82, 0xF8, 0x30, 0x10, 0xA6, 0xEB, ++ 0xE0, 0x76, 0x4E, 0xDD, 0xB6, 0xEB, 0x53, 0x0F, 0x23, 0xFA, 0x01, 0xF4, ++ 0x98, 0xBF, 0x04, 0x46, 0xEF, 0xF3, 0x10, 0x81, 0xC9, 0x07, 0x03, 0xD4, ++ 0x72, 0xB6, 0x29, 0x49, 0x01, 0x20, 0x08, 0x60, 0x28, 0x4D, 0x29, 0x4F, ++ 0x29, 0x68, 0x29, 0x48, 0x01, 0x31, 0x00, 0x68, 0x29, 0x60, 0x39, 0x69, ++ 0x00, 0x2C, 0x4F, 0xEA, 0x40, 0x17, 0x01, 0xEB, 0x40, 0x11, 0x4F, 0xEA, ++ 0x93, 0x00, 0x25, 0xDD, 0xB8, 0x42, 0x1A, 0xD8, 0x64, 0x36, 0xDB, 0x1B, ++ 0x9E, 0x42, 0x31, 0xD9, 0x20, 0x4B, 0x94, 0x62, 0x09, 0x1A, 0xD3, 0xF8, ++ 0xE0, 0x31, 0x1F, 0x48, 0x98, 0x47, 0x2B, 0x68, 0x43, 0xB1, 0x18, 0x4A, ++ 0x01, 0x3B, 0x12, 0x68, 0x2B, 0x60, 0x1B, 0xB9, 0x12, 0xB1, 0x62, 0xB6, ++ 0x00, 0xE0, 0x04, 0x46, 0x20, 0x46, 0xF8, 0xBD, 0x00, 0x24, 0x20, 0x46, ++ 0xF8, 0xBD, 0x15, 0x4E, 0x94, 0x62, 0x19, 0x44, 0x09, 0x1A, 0xD6, 0xF8, ++ 0xE0, 0x31, 0x13, 0x48, 0x98, 0x47, 0xE6, 0xE7, 0x30, 0x44, 0xB8, 0x42, ++ 0x0E, 0xD3, 0x0F, 0x4B, 0x0F, 0x48, 0xD3, 0xF8, 0xE0, 0x31, 0x94, 0x62, ++ 0x64, 0x31, 0x98, 0x47, 0xDB, 0xE7, 0x5C, 0x08, 0xB6, 0xEB, 0x53, 0x0F, ++ 0x8C, 0xBF, 0x64, 0x42, 0x04, 0x46, 0xAF, 0xE7, 0x20, 0x46, 0xFE, 0xF7, ++ 0x57, 0xFD, 0xD0, 0xE7, 0x98, 0x9C, 0x17, 0x00, 0x64, 0x00, 0x32, 0x40, ++ 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0x00, 0x10, 0x50, 0x40, ++ 0x40, 0x80, 0x32, 0x40, 0x88, 0x1A, 0x17, 0x00, 0xB8, 0x9C, 0x17, 0x00, ++ 0x13, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x10, 0xB5, ++ 0x0E, 0xDB, 0x11, 0x4B, 0xDB, 0x7F, 0x2B, 0xB1, 0x10, 0x4A, 0x93, 0x7C, ++ 0x52, 0x7C, 0x13, 0x44, 0x01, 0x2B, 0x11, 0xDD, 0x0E, 0x4B, 0xBD, 0xE8, ++ 0x10, 0x40, 0xD3, 0xF8, 0x60, 0x31, 0x18, 0x47, 0x00, 0x20, 0x0A, 0xF0, ++ 0xED, 0xFB, 0x03, 0x28, 0xEB, 0xD0, 0x0A, 0x49, 0x0A, 0x48, 0x40, 0xF2, ++ 0x06, 0x72, 0x0C, 0xF0, 0x25, 0xFA, 0xE4, 0xE7, 0x00, 0x21, 0xBD, 0xE8, ++ 0x10, 0x40, 0x08, 0x46, 0x0A, 0xF0, 0x36, 0xBB, 0x38, 0x36, 0x17, 0x00, ++ 0x98, 0x9C, 0x17, 0x00, 0x00, 0x88, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xC4, 0x9A, 0x15, 0x00, 0x2D, 0xE9, 0xF8, 0x43, ++ 0x39, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x61, 0xDB, ++ 0x37, 0x49, 0x04, 0x20, 0x0B, 0xF0, 0xDC, 0xFF, 0xEF, 0xF3, 0x10, 0x83, ++ 0xD8, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x34, 0x4B, 0x01, 0x22, 0x1A, 0x60, ++ 0xDF, 0xF8, 0xFC, 0x80, 0x32, 0x4C, 0xD8, 0xF8, 0x00, 0x30, 0x32, 0x4D, ++ 0x01, 0x33, 0x00, 0x22, 0xC8, 0xF8, 0x00, 0x30, 0x23, 0x68, 0x22, 0x60, ++ 0x2F, 0x69, 0x03, 0xF0, 0x0F, 0x09, 0x47, 0xF2, 0x30, 0x56, 0x05, 0xE0, ++ 0xF6, 0xF7, 0x22, 0xFB, 0x2B, 0x69, 0xDB, 0x1B, 0xB3, 0x42, 0x2C, 0xD8, ++ 0x23, 0x68, 0x19, 0x07, 0xF6, 0xD1, 0x28, 0x4A, 0x28, 0x48, 0x53, 0x68, ++ 0x28, 0x49, 0x04, 0x68, 0x23, 0xF0, 0x04, 0x03, 0x53, 0x60, 0x0B, 0x68, ++ 0xB9, 0xF1, 0x00, 0x0F, 0x22, 0xD1, 0x25, 0x4B, 0x25, 0x49, 0x04, 0x20, ++ 0x18, 0x60, 0x0B, 0xF0, 0xA7, 0xFF, 0x24, 0x4B, 0x93, 0xF8, 0x5A, 0x30, ++ 0x0B, 0xBB, 0x03, 0x21, 0x00, 0x20, 0x0A, 0xF0, 0xE1, 0xFA, 0x21, 0x4A, ++ 0xD8, 0xF8, 0x00, 0x30, 0x00, 0x21, 0x51, 0x82, 0x3B, 0xB1, 0x15, 0x4A, ++ 0x01, 0x3B, 0x12, 0x68, 0xC8, 0xF8, 0x00, 0x30, 0x0B, 0xB9, 0x02, 0xB1, ++ 0x62, 0xB6, 0xBD, 0xE8, 0xF8, 0x83, 0x1A, 0x49, 0x04, 0x20, 0x0B, 0xF0, ++ 0x8B, 0xFF, 0xC4, 0xE7, 0x23, 0x40, 0x5A, 0x07, 0xD9, 0xD4, 0x02, 0x68, ++ 0x0B, 0x68, 0x13, 0x40, 0x5B, 0x07, 0xFA, 0xD5, 0xD3, 0xE7, 0xF6, 0xF7, ++ 0x07, 0xFB, 0xDA, 0xE7, 0x00, 0x20, 0x0A, 0xF0, 0x65, 0xFB, 0x04, 0x28, ++ 0x98, 0xD1, 0x10, 0x49, 0x10, 0x48, 0x40, 0xF2, 0x14, 0x72, 0x0C, 0xF0, ++ 0x9D, 0xF9, 0x91, 0xE7, 0x38, 0x36, 0x17, 0x00, 0x14, 0x9B, 0x15, 0x00, ++ 0x38, 0x61, 0x17, 0x00, 0x38, 0x00, 0x32, 0x40, 0x00, 0x10, 0x50, 0x40, ++ 0x1C, 0x9E, 0x17, 0x00, 0x6C, 0x80, 0x32, 0x40, 0x74, 0x80, 0x32, 0x40, ++ 0x70, 0x80, 0x32, 0x40, 0x28, 0x9B, 0x15, 0x00, 0x30, 0x9D, 0x17, 0x00, ++ 0x98, 0x9C, 0x17, 0x00, 0x5C, 0x9A, 0x15, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0xF0, 0x9A, 0x15, 0x00, 0x6C, 0x28, 0x17, 0x00, 0x24, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x10, 0xB5, 0x31, 0xDB, 0x00, 0x20, ++ 0x0A, 0xF0, 0x32, 0xFB, 0x02, 0x28, 0x05, 0xD0, 0xBD, 0xE8, 0x10, 0x40, ++ 0x04, 0x21, 0x00, 0x20, 0x0A, 0xF0, 0x82, 0xBA, 0x1C, 0x4B, 0x30, 0x22, ++ 0x1A, 0x60, 0xEF, 0xF3, 0x10, 0x83, 0xDA, 0x07, 0x03, 0xD4, 0x72, 0xB6, ++ 0x19, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x19, 0x4C, 0x23, 0x68, 0x4F, 0xF0, ++ 0x80, 0x60, 0x01, 0x33, 0x23, 0x60, 0x0A, 0xF0, 0x85, 0xFC, 0x16, 0x4B, ++ 0x1B, 0x68, 0x5B, 0x07, 0x02, 0xD5, 0x15, 0x4B, 0x04, 0x22, 0x1A, 0x60, ++ 0x23, 0x68, 0x00, 0x2B, 0xDC, 0xD0, 0x0F, 0x4A, 0x01, 0x3B, 0x12, 0x68, ++ 0x23, 0x60, 0x00, 0x2B, 0xD6, 0xD1, 0x00, 0x2A, 0xD4, 0xD0, 0x62, 0xB6, ++ 0xD2, 0xE7, 0x00, 0x20, 0x0A, 0xF0, 0x00, 0xFB, 0x03, 0x28, 0x04, 0xD0, ++ 0x00, 0x20, 0x0A, 0xF0, 0xFB, 0xFA, 0x00, 0x28, 0xC3, 0xD1, 0x09, 0x49, ++ 0x09, 0x48, 0x40, 0xF2, 0x4F, 0x72, 0x0C, 0xF0, 0x33, 0xF9, 0xBC, 0xE7, ++ 0x38, 0x36, 0x17, 0x00, 0x38, 0x00, 0x32, 0x40, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x6C, 0x80, 0x32, 0x40, 0x70, 0x80, 0x32, 0x40, ++ 0x70, 0x79, 0x15, 0x00, 0x3C, 0x9B, 0x15, 0x00, 0x08, 0xB5, 0x00, 0x20, ++ 0x0A, 0xF0, 0xDE, 0xFA, 0x04, 0x28, 0x00, 0xD0, 0x08, 0xBD, 0xBD, 0xE8, ++ 0x08, 0x40, 0x01, 0x21, 0x00, 0x20, 0x0A, 0xF0, 0x2D, 0xBA, 0x00, 0xBF, ++ 0x2D, 0xE9, 0xF0, 0x47, 0xDF, 0xF8, 0x78, 0xA0, 0xDA, 0xF8, 0x1C, 0x33, ++ 0x17, 0x46, 0x05, 0x46, 0x0E, 0x46, 0x98, 0x47, 0x04, 0x46, 0x60, 0xBB, ++ 0x96, 0xF8, 0x00, 0x90, 0x16, 0x4A, 0x95, 0xF8, 0x19, 0x80, 0xDA, 0xF8, ++ 0xB0, 0x31, 0x4F, 0xF4, 0x1E, 0x71, 0x01, 0xFB, 0x09, 0x29, 0x41, 0x46, ++ 0x89, 0xF8, 0x5D, 0x02, 0xA9, 0xF8, 0x5E, 0x02, 0x30, 0x78, 0x98, 0x47, ++ 0x38, 0x70, 0xD9, 0xF8, 0x2C, 0x30, 0x2B, 0xB1, 0xDA, 0xF8, 0xB0, 0x21, ++ 0x93, 0xF8, 0x23, 0x00, 0x69, 0x7E, 0x90, 0x47, 0x0A, 0x49, 0x4F, 0xF4, ++ 0xA4, 0x63, 0x03, 0xFB, 0x08, 0x11, 0x91, 0xF8, 0x62, 0x30, 0x43, 0xB9, ++ 0x33, 0x78, 0x81, 0xF8, 0x6C, 0x30, 0x6B, 0x7F, 0x81, 0xF8, 0x6D, 0x30, ++ 0xAB, 0x7F, 0x81, 0xF8, 0x6E, 0x30, 0x20, 0x46, 0xBD, 0xE8, 0xF0, 0x87, ++ 0x68, 0x65, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0x7C, 0x4E, 0x7D, 0x4C, 0x4F, 0xF4, 0x1E, 0x77, ++ 0x07, 0xFB, 0x00, 0x67, 0x4F, 0xF0, 0x4F, 0x08, 0x46, 0x23, 0x18, 0xFB, ++ 0x00, 0x38, 0x97, 0xF8, 0x22, 0xB0, 0x85, 0xB0, 0x05, 0x46, 0x06, 0xEB, ++ 0xC8, 0x08, 0x4F, 0xF0, 0x00, 0x09, 0xD7, 0xF8, 0x08, 0x32, 0x5F, 0xFA, ++ 0x89, 0xFA, 0xA8, 0xF1, 0x28, 0x01, 0x4F, 0xF0, 0x80, 0x42, 0x09, 0xF1, ++ 0x01, 0x09, 0x50, 0x46, 0x13, 0xB1, 0xD4, 0xF8, 0x84, 0x33, 0x98, 0x47, ++ 0xD7, 0xF8, 0x30, 0x32, 0x41, 0x46, 0x08, 0x37, 0x08, 0xF1, 0x08, 0x08, ++ 0x4F, 0xF0, 0x80, 0x42, 0x50, 0x46, 0x13, 0xB1, 0xD4, 0xF8, 0x84, 0x33, ++ 0x98, 0x47, 0xB9, 0xF1, 0x05, 0x0F, 0xE0, 0xD1, 0x65, 0x4B, 0x4F, 0xF4, ++ 0xA4, 0x67, 0x07, 0xFB, 0x0B, 0x33, 0x93, 0xF8, 0x62, 0x10, 0xC1, 0xB9, ++ 0xFF, 0x22, 0x83, 0xF8, 0x6C, 0x20, 0xD4, 0xF8, 0xAC, 0x31, 0x28, 0x46, ++ 0x98, 0x47, 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, 0x05, 0x66, 0xF3, 0x6A, ++ 0x23, 0xB1, 0x93, 0xF8, 0x23, 0x00, 0xD4, 0xF8, 0xAC, 0x31, 0x98, 0x47, ++ 0xD4, 0xF8, 0x24, 0x33, 0x28, 0x46, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x4F, ++ 0x18, 0x47, 0x4F, 0xF4, 0x1E, 0x78, 0x08, 0xFB, 0x05, 0x62, 0x92, 0xF8, ++ 0x24, 0x90, 0xB9, 0xF1, 0x01, 0x0F, 0x02, 0xD0, 0x02, 0x29, 0xED, 0xD0, ++ 0xDD, 0xE7, 0x93, 0xF8, 0xDE, 0x20, 0x01, 0x3A, 0xD2, 0xB2, 0x83, 0xF8, ++ 0xDE, 0x20, 0x00, 0x2A, 0xF4, 0xD1, 0x93, 0xF8, 0x63, 0xA0, 0x0A, 0xF1, ++ 0x0A, 0x0A, 0x5F, 0xFA, 0x8A, 0xFA, 0x08, 0xFB, 0x0A, 0xF3, 0x06, 0xEB, ++ 0x03, 0x08, 0x00, 0x93, 0x98, 0xF8, 0x24, 0x30, 0x73, 0xB9, 0x44, 0x4B, ++ 0x4F, 0xF4, 0xA4, 0x67, 0x07, 0xFB, 0x0B, 0x37, 0x38, 0x46, 0x97, 0xF8, ++ 0x63, 0x10, 0xE3, 0x68, 0x0A, 0x31, 0xC9, 0xB2, 0x98, 0x47, 0x97, 0xF8, ++ 0x62, 0x10, 0xD7, 0xE7, 0x02, 0x23, 0x0C, 0x21, 0x49, 0x20, 0x01, 0x92, ++ 0x09, 0xF0, 0x64, 0xFF, 0x01, 0x9A, 0x88, 0xF8, 0x24, 0x20, 0x80, 0xF8, ++ 0x00, 0xA0, 0x42, 0x70, 0x09, 0xF0, 0x8C, 0xFF, 0x98, 0xF8, 0x24, 0x30, ++ 0x00, 0x2B, 0xDE, 0xD1, 0x98, 0xF8, 0x23, 0x30, 0x09, 0x2B, 0xDA, 0xD8, ++ 0x98, 0xF8, 0x22, 0x00, 0x31, 0x4B, 0xCD, 0xF8, 0x04, 0x90, 0x9E, 0x22, ++ 0xA4, 0x21, 0x11, 0xFB, 0x00, 0x21, 0x2D, 0x4A, 0x03, 0x95, 0x07, 0xFB, ++ 0x00, 0x27, 0x2B, 0x48, 0x02, 0x97, 0x4F, 0xF0, 0x4F, 0x0C, 0x46, 0x27, ++ 0x1C, 0xFB, 0x0A, 0x77, 0x00, 0xEB, 0xC1, 0x0A, 0x00, 0x99, 0x28, 0x4A, ++ 0x02, 0x9D, 0xC1, 0x46, 0x88, 0x46, 0x06, 0xEB, 0xC7, 0x07, 0x98, 0x44, ++ 0xD9, 0xF8, 0x08, 0x12, 0x31, 0xB3, 0xEF, 0xF3, 0x10, 0x81, 0xCB, 0x07, ++ 0x03, 0xD4, 0x72, 0xB6, 0x21, 0x4B, 0x01, 0x99, 0x19, 0x60, 0x11, 0x68, ++ 0xA7, 0xF1, 0x28, 0x00, 0x4B, 0x1C, 0xAA, 0xF1, 0x28, 0x01, 0x13, 0x60, ++ 0x00, 0x90, 0x0A, 0xF0, 0xA1, 0xFC, 0xD9, 0xF8, 0x08, 0x12, 0xD9, 0xF8, ++ 0x0C, 0x32, 0x00, 0x98, 0xC5, 0xF8, 0xC8, 0x14, 0xC5, 0xF8, 0xCC, 0x34, ++ 0x0A, 0xF0, 0xA0, 0xFB, 0x14, 0x4A, 0x11, 0x68, 0x48, 0x1E, 0x29, 0xB1, ++ 0x13, 0x4B, 0x10, 0x60, 0x19, 0x68, 0x08, 0xB9, 0x01, 0xB1, 0x62, 0xB6, ++ 0xD9, 0xF8, 0x30, 0x32, 0x50, 0x46, 0x39, 0x46, 0x09, 0xF1, 0x08, 0x09, ++ 0x0A, 0xF1, 0x08, 0x0A, 0x08, 0x35, 0x2B, 0xB1, 0x0A, 0xF0, 0x80, 0xFC, ++ 0x38, 0x46, 0x0A, 0xF0, 0x87, 0xFB, 0x08, 0x4A, 0x08, 0x37, 0x47, 0x45, ++ 0xC2, 0xD1, 0x40, 0x20, 0x03, 0x9D, 0x0A, 0xF0, 0xE1, 0xFA, 0x7A, 0xE7, ++ 0x68, 0x65, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0xC0, 0x67, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, ++ 0x10, 0xB5, 0x01, 0x23, 0x04, 0x46, 0x00, 0x22, 0x06, 0x21, 0x43, 0x20, ++ 0x09, 0xF0, 0xE0, 0xFE, 0x94, 0xF8, 0x63, 0x30, 0x03, 0x70, 0xBD, 0xE8, ++ 0x10, 0x40, 0x09, 0xF0, 0x09, 0xBF, 0x00, 0xBF, 0x70, 0xB5, 0x90, 0xF9, ++ 0x87, 0x30, 0x04, 0x46, 0x90, 0xF9, 0x86, 0x00, 0x94, 0xF8, 0x88, 0x20, ++ 0x94, 0xF8, 0x89, 0x60, 0x84, 0xF8, 0x86, 0x10, 0xBB, 0xB1, 0x0D, 0x46, ++ 0x52, 0xB2, 0xAE, 0xB9, 0x88, 0x42, 0x10, 0xDD, 0x9B, 0x1A, 0x99, 0x42, ++ 0x0D, 0xDA, 0x01, 0x26, 0x00, 0x22, 0x03, 0x23, 0x0C, 0x21, 0x57, 0x20, ++ 0x09, 0xF0, 0xBC, 0xFE, 0x94, 0xF8, 0x63, 0x20, 0x02, 0x70, 0x46, 0x70, ++ 0x85, 0x70, 0x09, 0xF0, 0xE5, 0xFE, 0x84, 0xF8, 0x89, 0x60, 0x70, 0xBD, ++ 0x01, 0x2E, 0xFA, 0xD1, 0x88, 0x42, 0xF8, 0xDA, 0x13, 0x44, 0x99, 0x42, ++ 0xF5, 0xDD, 0x00, 0x26, 0xE6, 0xE7, 0x00, 0xBF, 0x14, 0x4B, 0x93, 0xF9, ++ 0x00, 0x20, 0x22, 0xB3, 0x30, 0xB4, 0x9C, 0x78, 0x90, 0xF9, 0x86, 0x00, ++ 0x93, 0xF9, 0x01, 0x50, 0x6C, 0xB9, 0x88, 0x42, 0x08, 0xDD, 0x52, 0x1B, ++ 0x91, 0x42, 0x05, 0xDA, 0x0D, 0x49, 0x0A, 0x68, 0x42, 0xF4, 0x00, 0x72, ++ 0x0A, 0x60, 0x01, 0x24, 0x9C, 0x70, 0x30, 0xBC, 0x70, 0x47, 0x01, 0x2C, ++ 0xFA, 0xD1, 0x88, 0x42, 0xF8, 0xDA, 0x2A, 0x44, 0x91, 0x42, 0xF5, 0xDD, ++ 0x05, 0x49, 0x0A, 0x68, 0x00, 0x24, 0x22, 0xF4, 0x00, 0x72, 0x0A, 0x60, ++ 0x9C, 0x70, 0x30, 0xBC, 0x70, 0x47, 0x70, 0x47, 0xA4, 0x1F, 0x17, 0x00, ++ 0xB0, 0xB3, 0x33, 0x40, 0x2D, 0xE9, 0xF0, 0x4F, 0x0C, 0x46, 0x06, 0x46, ++ 0x80, 0x68, 0x91, 0xF8, 0x8B, 0x10, 0xD0, 0xF8, 0x08, 0x80, 0x60, 0x6F, ++ 0xB6, 0xF8, 0x1C, 0xB0, 0xDF, 0xF8, 0x1C, 0xA1, 0x87, 0xB0, 0x00, 0x25, ++ 0x05, 0x90, 0x03, 0x92, 0x1F, 0x46, 0x84, 0xF8, 0x78, 0x50, 0x49, 0xB1, ++ 0x94, 0xF8, 0x63, 0x00, 0xDA, 0xF8, 0xC0, 0x31, 0x01, 0x21, 0x98, 0x47, ++ 0xA4, 0xF8, 0x8A, 0x50, 0x84, 0xF8, 0x8C, 0x50, 0x3A, 0x4B, 0x3B, 0x4D, ++ 0x1B, 0x68, 0x22, 0x6F, 0x5B, 0x68, 0x01, 0x21, 0x84, 0xF8, 0x85, 0x10, ++ 0x29, 0x69, 0x5B, 0x1A, 0xD3, 0x42, 0x58, 0xD4, 0x96, 0xF9, 0x2D, 0x10, ++ 0x04, 0x91, 0xE8, 0xF7, 0x35, 0xFB, 0x34, 0x4B, 0x04, 0x99, 0x5B, 0x7C, ++ 0x01, 0x2B, 0x59, 0xD0, 0xDA, 0xF8, 0x9C, 0x31, 0x20, 0x46, 0xAB, 0xF1, ++ 0x24, 0x05, 0x98, 0x47, 0xAD, 0xB2, 0x00, 0x22, 0x04, 0x21, 0x08, 0xF1, ++ 0x20, 0x00, 0x0A, 0xF0, 0x19, 0xFC, 0x00, 0x23, 0x01, 0x2D, 0x3B, 0x60, ++ 0x08, 0xF1, 0x24, 0x02, 0x22, 0xD9, 0x04, 0x96, 0x3E, 0x46, 0x27, 0x46, ++ 0x2C, 0x46, 0x09, 0xE0, 0x32, 0x60, 0xC9, 0xF5, 0x7F, 0x42, 0xFE, 0x32, ++ 0x14, 0x44, 0xA4, 0xB2, 0x01, 0x2C, 0x05, 0xEB, 0x09, 0x02, 0x10, 0xD9, ++ 0x92, 0xF8, 0x01, 0x90, 0x15, 0x46, 0x09, 0xF1, 0x01, 0x0C, 0xA4, 0x45, ++ 0x15, 0xF8, 0x02, 0x1B, 0x07, 0xDA, 0x05, 0x29, 0xEA, 0xD0, 0x02, 0x46, ++ 0x49, 0x46, 0x28, 0x46, 0x0A, 0xF0, 0xF4, 0xFB, 0xE5, 0xE7, 0x3C, 0x46, ++ 0x37, 0x46, 0x04, 0x9E, 0x60, 0x67, 0x3B, 0x68, 0x01, 0x93, 0x03, 0x9B, ++ 0x00, 0x93, 0x32, 0x46, 0x59, 0x46, 0x40, 0x46, 0x23, 0x46, 0xDA, 0xF8, ++ 0xD0, 0x51, 0xA8, 0x47, 0x04, 0x20, 0x0A, 0xF0, 0xA1, 0xF8, 0x01, 0x28, ++ 0x04, 0xD0, 0x60, 0x6F, 0x05, 0x9B, 0xC0, 0x1A, 0x18, 0xBF, 0x01, 0x20, ++ 0x07, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x00, 0x22, 0x94, 0xF8, 0x6C, 0x00, ++ 0x11, 0x46, 0xF7, 0xF7, 0x75, 0xF9, 0x00, 0x28, 0x9E, 0xD1, 0x2B, 0x69, ++ 0x23, 0x67, 0x9B, 0xE7, 0x20, 0x46, 0xFF, 0xF7, 0x3F, 0xFF, 0x04, 0x99, ++ 0xA0, 0xE7, 0x00, 0xBF, 0xC8, 0x35, 0x17, 0x00, 0x00, 0x10, 0x50, 0x40, ++ 0x00, 0x88, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x38, 0xB5, 0x00, 0x22, ++ 0x05, 0x46, 0x0C, 0x46, 0x02, 0x23, 0x0C, 0x21, 0x59, 0x20, 0x09, 0xF0, ++ 0xD3, 0xFD, 0x05, 0x70, 0x44, 0x70, 0xBD, 0xE8, 0x38, 0x40, 0x09, 0xF0, ++ 0xFD, 0xBD, 0x00, 0xBF, 0x08, 0xB5, 0x03, 0x4B, 0x08, 0x46, 0xD3, 0xF8, ++ 0x74, 0x31, 0x98, 0x47, 0x01, 0x20, 0x08, 0xBD, 0x88, 0x1A, 0x17, 0x00, ++ 0x08, 0xB5, 0x04, 0x4A, 0x08, 0x78, 0xD2, 0xF8, 0x5C, 0x22, 0x19, 0x46, ++ 0x90, 0x47, 0x00, 0x20, 0x08, 0xBD, 0x00, 0xBF, 0x88, 0x1A, 0x17, 0x00, ++ 0xF8, 0xB5, 0x0E, 0x46, 0x2F, 0x20, 0x19, 0x46, 0x02, 0x23, 0x34, 0x78, ++ 0x09, 0xF0, 0xAE, 0xFD, 0x0D, 0x49, 0x76, 0x78, 0x0D, 0x4B, 0x4F, 0xF4, ++ 0xA4, 0x67, 0x05, 0x46, 0x07, 0xFB, 0x04, 0x10, 0x29, 0x46, 0x90, 0xF8, ++ 0x65, 0x20, 0x80, 0xF8, 0x66, 0x60, 0x01, 0xF8, 0x01, 0x2F, 0x7F, 0x22, ++ 0xD3, 0xF8, 0x40, 0x33, 0x80, 0xF8, 0x65, 0x20, 0x2A, 0x46, 0x98, 0x47, ++ 0x28, 0x46, 0x09, 0xF0, 0xC5, 0xFD, 0x00, 0x20, 0xF8, 0xBD, 0x00, 0xBF, ++ 0x18, 0x88, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x18, 0x46, 0x38, 0xB5, ++ 0x0D, 0x46, 0x03, 0x23, 0x01, 0x46, 0x0B, 0x20, 0x09, 0xF0, 0x86, 0xFD, ++ 0x06, 0x4B, 0x04, 0x46, 0xD3, 0xF8, 0xC4, 0x31, 0xA2, 0x1C, 0x61, 0x1C, ++ 0x28, 0x46, 0x98, 0x47, 0x20, 0x70, 0x20, 0x46, 0x09, 0xF0, 0xAA, 0xFD, ++ 0x00, 0x20, 0x38, 0xBD, 0x88, 0x1A, 0x17, 0x00, 0xF8, 0xB5, 0x0E, 0x4E, ++ 0x0D, 0x46, 0x1C, 0x46, 0x19, 0x46, 0x28, 0x46, 0xD6, 0xF8, 0x80, 0x30, ++ 0x17, 0x46, 0x98, 0x47, 0x0C, 0xB9, 0x00, 0x20, 0xF8, 0xBD, 0x06, 0x46, ++ 0x3A, 0x46, 0x21, 0x46, 0x03, 0x23, 0x47, 0x20, 0x09, 0xF0, 0x62, 0xFD, ++ 0x2A, 0x78, 0x02, 0x70, 0x04, 0x22, 0x46, 0x70, 0x82, 0x70, 0x09, 0xF0, ++ 0x8B, 0xFD, 0x00, 0x20, 0xF8, 0xBD, 0x00, 0xBF, 0x88, 0x1A, 0x17, 0x00, ++ 0x38, 0xB5, 0x0C, 0x46, 0x76, 0x20, 0x19, 0x46, 0x0C, 0x23, 0x09, 0xF0, ++ 0x4F, 0xFD, 0x23, 0x78, 0x0C, 0x4A, 0x0D, 0x4C, 0x4F, 0xF4, 0x1E, 0x71, ++ 0x01, 0xFB, 0x03, 0x23, 0x4F, 0xF4, 0xA4, 0x65, 0x93, 0xF8, 0x22, 0x20, ++ 0xD3, 0xF8, 0x48, 0x11, 0x05, 0xFB, 0x02, 0x42, 0x49, 0x69, 0x92, 0xF8, ++ 0x86, 0x20, 0x02, 0x72, 0x00, 0x24, 0xC0, 0xE9, 0x00, 0x14, 0x09, 0xF0, ++ 0x67, 0xFD, 0x20, 0x46, 0x38, 0xBD, 0x00, 0xBF, 0x68, 0x65, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0xF0, 0xB5, 0x00, 0x22, 0x0D, 0x46, 0x85, 0xB0, ++ 0x01, 0x23, 0x0C, 0x21, 0x53, 0x20, 0x09, 0xF0, 0x27, 0xFD, 0x01, 0x22, ++ 0x02, 0x70, 0x04, 0x46, 0x28, 0x78, 0x04, 0x28, 0x28, 0xD8, 0x1D, 0x4B, ++ 0x4F, 0xF4, 0xA4, 0x61, 0x01, 0xFB, 0x00, 0x30, 0x90, 0xF8, 0xC0, 0x34, ++ 0x03, 0xB3, 0xAB, 0x78, 0x23, 0xB3, 0x19, 0x4A, 0x19, 0x49, 0x16, 0x68, ++ 0x09, 0x69, 0x17, 0x68, 0xB0, 0xF8, 0xD2, 0x20, 0xC9, 0x1B, 0x92, 0x02, ++ 0xEF, 0x68, 0xB6, 0xFB, 0xF2, 0xF6, 0x06, 0xFB, 0x02, 0x22, 0x14, 0x4E, ++ 0x39, 0x44, 0x6F, 0x68, 0xD6, 0xF8, 0x04, 0x62, 0x01, 0x97, 0x0A, 0x44, ++ 0xA9, 0x68, 0x00, 0x91, 0x02, 0x92, 0xEA, 0x78, 0x00, 0x21, 0xB0, 0x47, ++ 0xFF, 0x28, 0x01, 0xD0, 0x00, 0x23, 0x23, 0x70, 0x20, 0x46, 0x09, 0xF0, ++ 0x25, 0xFD, 0x00, 0x20, 0x05, 0xB0, 0xF0, 0xBD, 0x08, 0x4B, 0x69, 0x78, ++ 0xD3, 0xF8, 0x08, 0x32, 0x98, 0x47, 0x20, 0x70, 0x20, 0x46, 0x09, 0xF0, ++ 0x19, 0xFD, 0x00, 0x20, 0x05, 0xB0, 0xF0, 0xBD, 0x18, 0x88, 0x17, 0x00, ++ 0xA4, 0x80, 0x32, 0x40, 0x00, 0x10, 0x50, 0x40, 0x88, 0x1A, 0x17, 0x00, ++ 0x38, 0xB5, 0x19, 0x46, 0x05, 0x20, 0x1C, 0x23, 0x09, 0xF0, 0xD8, 0xFC, ++ 0x2C, 0x4D, 0x2D, 0x4B, 0x03, 0x60, 0x2A, 0x68, 0x2C, 0x4B, 0x42, 0x60, ++ 0x1B, 0x68, 0x83, 0x60, 0x0A, 0x22, 0x04, 0x23, 0x83, 0x76, 0x02, 0x83, ++ 0x04, 0x46, 0x00, 0xF1, 0x10, 0x01, 0x0C, 0x30, 0xE8, 0xF7, 0x9E, 0xF8, ++ 0x26, 0x4B, 0x63, 0x61, 0x2B, 0x68, 0x98, 0x03, 0x24, 0xD4, 0x21, 0x4B, ++ 0x1B, 0x68, 0x99, 0x03, 0x2C, 0xD4, 0x1F, 0x4B, 0x1B, 0x68, 0x9A, 0x04, ++ 0x03, 0xD5, 0x63, 0x69, 0x43, 0xF4, 0x00, 0x23, 0x63, 0x61, 0xE8, 0xF7, ++ 0x2F, 0xF9, 0x18, 0xB1, 0x63, 0x69, 0x43, 0xF4, 0x80, 0x33, 0x63, 0x61, ++ 0x17, 0x4B, 0x1B, 0x68, 0x1B, 0x04, 0x22, 0xD4, 0xE8, 0xF7, 0x2E, 0xF9, ++ 0x63, 0x69, 0x08, 0xB1, 0x43, 0xF0, 0x80, 0x63, 0x43, 0xF0, 0x40, 0x53, ++ 0x20, 0x46, 0x63, 0x61, 0x09, 0xF0, 0xCE, 0xFC, 0x00, 0x20, 0x38, 0xBD, ++ 0xE8, 0xF7, 0x3E, 0xF9, 0x00, 0x28, 0xD6, 0xD0, 0x63, 0x69, 0x43, 0xF4, ++ 0x00, 0x33, 0x63, 0x61, 0x0A, 0x4B, 0x1B, 0x68, 0x99, 0x03, 0xD2, 0xD5, ++ 0xE8, 0xF7, 0x3A, 0xF9, 0x00, 0x28, 0xCE, 0xD0, 0x63, 0x69, 0x43, 0xF4, ++ 0x00, 0x13, 0x63, 0x61, 0xC9, 0xE7, 0xE8, 0xF7, 0x03, 0xF9, 0x00, 0x28, ++ 0xD8, 0xD0, 0x63, 0x69, 0x43, 0xF0, 0x80, 0x43, 0x63, 0x61, 0xD3, 0xE7, ++ 0x04, 0x00, 0x32, 0x40, 0x01, 0x03, 0x04, 0x06, 0x08, 0x00, 0x32, 0x40, ++ 0x5F, 0xFA, 0x10, 0x00, 0xF0, 0xB5, 0x23, 0x48, 0x4D, 0x79, 0x00, 0x68, ++ 0x8C, 0x79, 0x50, 0xF8, 0x25, 0xC0, 0x21, 0x4F, 0x0E, 0x68, 0x4F, 0xF4, ++ 0xA4, 0x70, 0x00, 0xFB, 0x04, 0x50, 0x02, 0x30, 0x83, 0xB0, 0x47, 0xF8, ++ 0x20, 0x60, 0x19, 0x46, 0xBC, 0xF1, 0x00, 0x0F, 0x0A, 0xD0, 0xCC, 0xF3, ++ 0x0B, 0x03, 0x1B, 0xBB, 0x2C, 0xF4, 0x7F, 0x6C, 0x2C, 0xF0, 0x0F, 0x0C, ++ 0xC6, 0xF3, 0x0B, 0x06, 0x4C, 0xEA, 0x06, 0x06, 0x4F, 0xF4, 0xA4, 0x63, ++ 0x03, 0xFB, 0x04, 0x74, 0x94, 0xF8, 0x64, 0x30, 0x73, 0xB1, 0x01, 0x2D, ++ 0x1A, 0xD0, 0x02, 0x2D, 0x12, 0xD0, 0xA5, 0xB1, 0x0F, 0x4B, 0x1E, 0x60, ++ 0x0F, 0x4B, 0xD3, 0xF8, 0xA0, 0x31, 0xCD, 0xE9, 0x00, 0x21, 0x98, 0x47, ++ 0xDD, 0xE9, 0x00, 0x21, 0x1B, 0x20, 0x09, 0xF0, 0xA5, 0xFC, 0x00, 0x20, ++ 0x03, 0xB0, 0xF0, 0xBD, 0x66, 0x46, 0xE1, 0xE7, 0x08, 0x4B, 0x1E, 0x60, ++ 0xEC, 0xE7, 0x08, 0x4B, 0x1E, 0x60, 0xE9, 0xE7, 0x07, 0x4B, 0x1E, 0x60, ++ 0xE6, 0xE7, 0x00, 0xBF, 0xAC, 0x35, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0x0C, 0x02, 0x32, 0x40, 0x88, 0x1A, 0x17, 0x00, 0x08, 0x02, 0x32, 0x40, ++ 0x00, 0x02, 0x32, 0x40, 0x04, 0x02, 0x32, 0x40, 0x38, 0xB5, 0x07, 0x48, ++ 0x8C, 0x78, 0x0D, 0x88, 0x4F, 0xF4, 0xA4, 0x61, 0x01, 0xFB, 0x04, 0x04, ++ 0x19, 0x46, 0x70, 0x20, 0xA4, 0xF8, 0xBE, 0x54, 0x09, 0xF0, 0x7A, 0xFC, ++ 0x00, 0x20, 0x38, 0xBD, 0x18, 0x88, 0x17, 0x00, 0x10, 0xB5, 0x08, 0x4C, ++ 0x08, 0x78, 0xD4, 0xF8, 0xC8, 0x41, 0x82, 0xB0, 0x01, 0x92, 0x00, 0x93, ++ 0xA0, 0x47, 0xDD, 0xE9, 0x00, 0x12, 0x0D, 0x20, 0x09, 0xF0, 0x68, 0xFC, ++ 0x00, 0x20, 0x02, 0xB0, 0x10, 0xBD, 0x00, 0xBF, 0x88, 0x1A, 0x17, 0x00, ++ 0x10, 0xB5, 0x07, 0x4C, 0x08, 0x78, 0x64, 0x6D, 0x82, 0xB0, 0x01, 0x92, ++ 0x00, 0x93, 0xA0, 0x47, 0xDD, 0xE9, 0x00, 0x12, 0x3A, 0x20, 0x09, 0xF0, ++ 0x55, 0xFC, 0x00, 0x20, 0x02, 0xB0, 0x10, 0xBD, 0x88, 0x1A, 0x17, 0x00, ++ 0x70, 0xB5, 0x0C, 0x78, 0x08, 0x46, 0x19, 0x46, 0x24, 0xB1, 0x25, 0x4B, ++ 0x93, 0xF8, 0xA9, 0x30, 0x00, 0x2B, 0x36, 0xD1, 0x23, 0x4B, 0x24, 0x4E, ++ 0x24, 0x4D, 0x00, 0x24, 0x1C, 0x70, 0x34, 0x68, 0x24, 0xF0, 0x00, 0x74, ++ 0x34, 0x60, 0x6C, 0x6F, 0x24, 0xF0, 0x10, 0x04, 0x6C, 0x67, 0x1E, 0x4D, ++ 0x2C, 0x68, 0x24, 0xF4, 0x00, 0x64, 0x2C, 0x60, 0xC4, 0x78, 0x9C, 0x70, ++ 0x84, 0x78, 0x00, 0x25, 0x5D, 0x70, 0xC4, 0xB1, 0x1A, 0x4C, 0x23, 0x68, ++ 0x43, 0xF0, 0x00, 0x43, 0x23, 0x60, 0x03, 0x79, 0x63, 0xB1, 0x18, 0x4C, ++ 0x85, 0x68, 0x18, 0x4B, 0x25, 0x60, 0x1C, 0x68, 0xC4, 0xF3, 0x13, 0x04, ++ 0x1C, 0x60, 0xC4, 0x68, 0x18, 0x68, 0x40, 0xEA, 0x04, 0x50, 0x18, 0x60, ++ 0x66, 0x20, 0x09, 0xF0, 0x17, 0xFC, 0x00, 0x20, 0x70, 0xBD, 0x0E, 0x4C, ++ 0x23, 0x68, 0x23, 0xF0, 0x00, 0x43, 0x23, 0x60, 0xE5, 0xE7, 0x08, 0x4B, ++ 0x08, 0x4E, 0x09, 0x4D, 0x01, 0x24, 0x1C, 0x70, 0x34, 0x68, 0x44, 0xF0, ++ 0x00, 0x74, 0x34, 0x60, 0x6C, 0x6F, 0x44, 0xF0, 0x10, 0x04, 0x6C, 0x67, ++ 0xC7, 0xE7, 0x00, 0xBF, 0x2C, 0x19, 0x17, 0x00, 0x4C, 0x36, 0x17, 0x00, ++ 0xE0, 0x50, 0x34, 0x40, 0x00, 0x00, 0x50, 0x40, 0x48, 0x30, 0x34, 0x40, ++ 0xF4, 0x00, 0x60, 0x40, 0xF8, 0x00, 0x60, 0x40, 0x70, 0xB5, 0x08, 0x46, ++ 0x07, 0x4C, 0x09, 0x68, 0x46, 0x68, 0x05, 0x89, 0xC4, 0xF8, 0xBD, 0x10, ++ 0x78, 0x20, 0x19, 0x46, 0xC4, 0xF8, 0xC1, 0x60, 0xA4, 0xF8, 0xC5, 0x50, ++ 0x09, 0xF0, 0xE2, 0xFB, 0x00, 0x20, 0x70, 0xBD, 0x2C, 0x19, 0x17, 0x00, ++ 0x38, 0xB5, 0x08, 0x46, 0x0E, 0x49, 0x44, 0x78, 0x0C, 0x70, 0x84, 0x78, ++ 0x4C, 0x70, 0xC4, 0x78, 0x8C, 0x70, 0x0C, 0x4C, 0x05, 0x79, 0x41, 0x79, ++ 0x61, 0x70, 0x25, 0x70, 0xC1, 0x79, 0x85, 0x79, 0xA5, 0x70, 0xE1, 0x70, ++ 0x08, 0x4C, 0x41, 0x68, 0x05, 0x68, 0xC4, 0xF8, 0xCB, 0x10, 0x7A, 0x20, ++ 0x19, 0x46, 0xC4, 0xF8, 0xC7, 0x50, 0x09, 0xF0, 0xC1, 0xFB, 0x00, 0x20, ++ 0x38, 0xBD, 0x00, 0xBF, 0x68, 0x25, 0x17, 0x00, 0x6C, 0x25, 0x17, 0x00, ++ 0x2C, 0x19, 0x17, 0x00, 0x08, 0xB5, 0x04, 0x48, 0x09, 0x68, 0x01, 0x60, ++ 0x19, 0x46, 0x72, 0x20, 0x09, 0xF0, 0xB0, 0xFB, 0x00, 0x20, 0x08, 0xBD, ++ 0x34, 0x00, 0x32, 0x40, 0x30, 0xB5, 0x19, 0x46, 0x83, 0xB0, 0xEF, 0xF3, ++ 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x16, 0x4B, 0x01, 0x20, ++ 0x18, 0x60, 0x16, 0x4C, 0x16, 0x4D, 0x23, 0x68, 0x01, 0x33, 0xCD, 0xE9, ++ 0x00, 0x21, 0x23, 0x60, 0x08, 0xF0, 0x12, 0xFA, 0xE7, 0xF7, 0x96, 0xFF, ++ 0x09, 0xF0, 0x02, 0xFB, 0x0E, 0xF0, 0x22, 0xF8, 0xD5, 0xF8, 0x10, 0x34, ++ 0x98, 0x47, 0xD5, 0xF8, 0xA8, 0x31, 0x98, 0x47, 0x23, 0x68, 0xDD, 0xE9, ++ 0x00, 0x21, 0x33, 0xB1, 0x08, 0x48, 0x01, 0x3B, 0x00, 0x68, 0x23, 0x60, ++ 0x0B, 0xB9, 0x00, 0xB1, 0x62, 0xB6, 0x01, 0x20, 0x09, 0xF0, 0x7E, 0xFB, ++ 0x00, 0x21, 0x08, 0x46, 0x09, 0xF0, 0x0C, 0xFD, 0x00, 0x20, 0x03, 0xB0, ++ 0x30, 0xBD, 0x00, 0xBF, 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x70, 0xB5, 0x18, 0x46, 0x21, 0x4E, 0x02, 0x23, ++ 0x0D, 0x46, 0x01, 0x46, 0x25, 0x20, 0x09, 0xF0, 0xFF, 0xFA, 0x33, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x04, 0x46, 0x0C, 0xDB, 0x1C, 0x4B, ++ 0x28, 0x46, 0xD3, 0xF8, 0xB8, 0x31, 0x98, 0x47, 0x00, 0x25, 0x60, 0x70, ++ 0x25, 0x70, 0x20, 0x46, 0x09, 0xF0, 0x1E, 0xFB, 0x28, 0x46, 0x70, 0xBD, ++ 0x2B, 0x78, 0x05, 0x2B, 0x19, 0xD8, 0x2B, 0x79, 0x20, 0x2B, 0x0A, 0xD8, ++ 0x95, 0xF8, 0x28, 0x30, 0x05, 0x2B, 0xE8, 0xD9, 0x11, 0x49, 0x12, 0x48, ++ 0x40, 0xF2, 0xFB, 0x62, 0x0B, 0xF0, 0xBE, 0xFB, 0xE1, 0xE7, 0x0E, 0x49, ++ 0x0F, 0x48, 0x4F, 0xF4, 0xDF, 0x62, 0x0B, 0xF0, 0xB7, 0xFB, 0x33, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xE9, 0xDB, 0xD5, 0xE7, 0x08, 0x49, ++ 0x0A, 0x48, 0x40, 0xF2, 0xF2, 0x62, 0x0B, 0xF0, 0xAB, 0xFB, 0x33, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xDA, 0xDB, 0xC9, 0xE7, 0x00, 0xBF, ++ 0x38, 0x36, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0xE4, 0x9B, 0x15, 0x00, 0xBC, 0x9B, 0x15, 0x00, 0x90, 0x9B, 0x15, 0x00, ++ 0x11, 0x48, 0x00, 0x68, 0xB0, 0xF9, 0x00, 0x00, 0x00, 0x28, 0x70, 0xB5, ++ 0x0C, 0x46, 0x16, 0x46, 0x1D, 0x46, 0x0B, 0xDB, 0x20, 0x78, 0x0D, 0x4B, ++ 0xD3, 0xF8, 0xB4, 0x31, 0x98, 0x47, 0x32, 0x46, 0x29, 0x46, 0x27, 0x20, ++ 0x09, 0xF0, 0x0A, 0xFB, 0x00, 0x20, 0x70, 0xBD, 0x08, 0x4B, 0x08, 0x78, ++ 0x1B, 0x68, 0x1B, 0x0E, 0x09, 0x33, 0x98, 0x42, 0xED, 0xDD, 0x06, 0x49, ++ 0x06, 0x48, 0x40, 0xF2, 0x22, 0x72, 0x0B, 0xF0, 0x75, 0xFB, 0xE5, 0xE7, ++ 0x38, 0x36, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0xD8, 0x00, 0x32, 0x40, ++ 0x70, 0x79, 0x15, 0x00, 0x14, 0x9C, 0x15, 0x00, 0x16, 0x48, 0x2D, 0xE9, ++ 0xF0, 0x41, 0x00, 0x68, 0x15, 0x4F, 0x0C, 0x46, 0xB0, 0xF9, 0x00, 0x10, ++ 0x25, 0x78, 0x00, 0x29, 0x16, 0x46, 0x98, 0x46, 0x11, 0xDB, 0x4F, 0xF4, ++ 0xA4, 0x60, 0x00, 0xFB, 0x05, 0x70, 0x62, 0x88, 0xA0, 0xF8, 0x68, 0x20, ++ 0x23, 0x79, 0x80, 0xF8, 0x6A, 0x30, 0x32, 0x46, 0x41, 0x46, 0x4C, 0x20, ++ 0x09, 0xF0, 0xD4, 0xFA, 0x00, 0x20, 0xBD, 0xE8, 0xF0, 0x81, 0x4F, 0xF4, ++ 0xA4, 0x62, 0x02, 0xFB, 0x05, 0x72, 0x92, 0xF8, 0x62, 0x20, 0x00, 0x2A, ++ 0xE5, 0xD0, 0x05, 0x49, 0x05, 0x48, 0x40, 0xF6, 0x5B, 0x22, 0x0B, 0xF0, ++ 0x3D, 0xFB, 0xDE, 0xE7, 0x38, 0x36, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x40, 0x9C, 0x15, 0x00, 0x13, 0x4B, 0x70, 0xB5, ++ 0x1B, 0x68, 0x0C, 0x78, 0xB3, 0xF9, 0x00, 0x30, 0x11, 0x4E, 0x00, 0x2B, ++ 0x0D, 0x46, 0x0D, 0xDB, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x04, 0x63, ++ 0x6A, 0x78, 0x83, 0xF8, 0x87, 0x20, 0xAA, 0x78, 0x83, 0xF8, 0x88, 0x20, ++ 0x00, 0x20, 0x83, 0xF8, 0x89, 0x00, 0x70, 0xBD, 0x4F, 0xF4, 0xA4, 0x63, ++ 0x03, 0xFB, 0x04, 0x63, 0x93, 0xF8, 0x62, 0x30, 0x00, 0x2B, 0xE9, 0xD0, ++ 0x05, 0x49, 0x06, 0x48, 0x40, 0xF6, 0x78, 0x52, 0x0B, 0xF0, 0x0E, 0xFB, ++ 0xE2, 0xE7, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x40, 0x9C, 0x15, 0x00, 0x20, 0x48, 0x2D, 0xE9, ++ 0xF0, 0x41, 0x00, 0x68, 0xB0, 0xF9, 0x00, 0x00, 0x00, 0x28, 0x84, 0xB0, ++ 0x0E, 0x46, 0x15, 0x46, 0x98, 0x46, 0x29, 0xDB, 0x30, 0x46, 0xE7, 0xF7, ++ 0xAB, 0xFD, 0x00, 0x24, 0x19, 0x4F, 0x00, 0x94, 0x40, 0xF6, 0xB4, 0x13, ++ 0x21, 0x46, 0x1A, 0x46, 0x20, 0x46, 0xCD, 0xE9, 0x01, 0x44, 0xE7, 0xF7, ++ 0xEB, 0xFD, 0xD7, 0xF8, 0x3C, 0x33, 0x0F, 0x20, 0x98, 0x47, 0x13, 0x4B, ++ 0xB6, 0xF8, 0x44, 0x20, 0x9A, 0x83, 0x41, 0x46, 0x2A, 0x46, 0x03, 0x20, ++ 0x09, 0xF0, 0x62, 0xFA, 0xD7, 0xF8, 0x60, 0x31, 0x98, 0x47, 0xD7, 0xF8, ++ 0xE0, 0x30, 0x98, 0x47, 0x28, 0x46, 0x02, 0x21, 0x09, 0xF0, 0xEA, 0xFB, ++ 0x20, 0x46, 0x04, 0xB0, 0xBD, 0xE8, 0xF0, 0x81, 0x10, 0x46, 0x09, 0xF0, ++ 0x8B, 0xFC, 0x00, 0x28, 0xD0, 0xD0, 0x06, 0x49, 0x06, 0x48, 0x4F, 0xF4, ++ 0xA7, 0x72, 0x0B, 0xF0, 0xC3, 0xFA, 0xC9, 0xE7, 0x38, 0x36, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x98, 0x9C, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x58, 0x9C, 0x15, 0x00, 0x70, 0xB5, 0x0C, 0x46, 0x49, 0x78, 0x16, 0x46, ++ 0x1D, 0x46, 0xE1, 0xB1, 0x01, 0x29, 0x63, 0x88, 0x3C, 0xD0, 0x02, 0x29, ++ 0x32, 0xD0, 0x03, 0x29, 0x0C, 0xBF, 0x20, 0x48, 0x20, 0x48, 0xA2, 0x88, ++ 0x18, 0x44, 0x04, 0xF1, 0x08, 0x01, 0x1D, 0xF0, 0x49, 0xFD, 0xE3, 0x88, ++ 0x23, 0xB1, 0x1D, 0x4B, 0x20, 0x78, 0xD3, 0xF8, 0x80, 0x34, 0x98, 0x47, ++ 0x32, 0x46, 0x29, 0x46, 0x68, 0x20, 0x09, 0xF0, 0x1D, 0xFA, 0x00, 0x20, ++ 0x70, 0xBD, 0x04, 0xF1, 0x08, 0x01, 0x4F, 0xF4, 0x40, 0x72, 0x16, 0x48, ++ 0x1D, 0xF0, 0x34, 0xFD, 0x04, 0xF5, 0x42, 0x71, 0x4F, 0xF4, 0x00, 0x72, ++ 0x13, 0x48, 0x1D, 0xF0, 0x2D, 0xFD, 0x04, 0xF5, 0xA1, 0x61, 0x80, 0x22, ++ 0x0C, 0x48, 0x1D, 0xF0, 0x27, 0xFD, 0x40, 0x22, 0x04, 0xF5, 0xB1, 0x61, ++ 0x0A, 0x48, 0x1D, 0xF0, 0x21, 0xFD, 0xD6, 0xE7, 0x0B, 0x48, 0xA2, 0x88, ++ 0x18, 0x44, 0x04, 0xF1, 0x08, 0x01, 0x1D, 0xF0, 0x19, 0xFD, 0xCE, 0xE7, ++ 0x06, 0x48, 0xA2, 0x88, 0x18, 0x44, 0x04, 0xF1, 0x08, 0x01, 0x1D, 0xF0, ++ 0x11, 0xFD, 0xC6, 0xE7, 0x1C, 0x18, 0x17, 0x00, 0x9C, 0x18, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x1C, 0x13, 0x17, 0x00, 0x1C, 0x16, 0x17, 0x00, ++ 0x38, 0xB5, 0x19, 0x46, 0x81, 0x20, 0x40, 0x23, 0x09, 0xF0, 0x78, 0xF9, ++ 0x00, 0x25, 0x04, 0x46, 0x08, 0x49, 0x00, 0xF8, 0x01, 0x5B, 0x24, 0x22, ++ 0x1D, 0xF0, 0xF8, 0xFC, 0x23, 0x78, 0x24, 0x33, 0xDB, 0xB2, 0xE2, 0x18, ++ 0x23, 0x70, 0x20, 0x46, 0x55, 0x70, 0x09, 0xF0, 0x97, 0xF9, 0x28, 0x46, ++ 0x38, 0xBD, 0x00, 0xBF, 0xDC, 0xD1, 0x15, 0x00, 0x10, 0xB5, 0x82, 0xB0, ++ 0x08, 0x46, 0x1C, 0x46, 0x01, 0x92, 0xFA, 0xF7, 0x83, 0xFA, 0x06, 0x49, ++ 0x4F, 0xF4, 0x80, 0x70, 0x0B, 0xF0, 0x0E, 0xF8, 0x01, 0x9A, 0x21, 0x46, ++ 0x6C, 0x20, 0x09, 0xF0, 0xB9, 0xF9, 0x00, 0x20, 0x02, 0xB0, 0x10, 0xBD, ++ 0x7C, 0x9C, 0x15, 0x00, 0x25, 0x48, 0x2D, 0xE9, 0xF8, 0x43, 0x00, 0x68, ++ 0xDF, 0xF8, 0xA0, 0x90, 0x0C, 0x46, 0xB0, 0xF9, 0x00, 0x10, 0x65, 0x79, ++ 0x00, 0x29, 0x17, 0x46, 0x1E, 0x46, 0x2D, 0xDB, 0x4F, 0xF4, 0xA4, 0x60, ++ 0x00, 0xFB, 0x05, 0xF0, 0x09, 0xEB, 0x00, 0x08, 0x21, 0x79, 0x98, 0xF8, ++ 0xAC, 0x20, 0x23, 0x68, 0xC8, 0xF8, 0xC4, 0x34, 0x01, 0x2A, 0x88, 0xF8, ++ 0xC3, 0x14, 0x0A, 0xD1, 0x17, 0x4B, 0xB0, 0x30, 0xD3, 0xF8, 0xD8, 0x31, ++ 0x48, 0x44, 0x98, 0x47, 0x00, 0x22, 0xD8, 0xF8, 0xC4, 0x34, 0x88, 0xF8, ++ 0xAC, 0x20, 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, 0x05, 0x95, 0x11, 0x49, ++ 0x95, 0xF8, 0xC3, 0x24, 0x4F, 0xF4, 0x80, 0x70, 0x0A, 0xF0, 0xD0, 0xFF, ++ 0x3A, 0x46, 0x31, 0x46, 0x62, 0x20, 0x09, 0xF0, 0x7B, 0xF9, 0x00, 0x20, ++ 0xBD, 0xE8, 0xF8, 0x83, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x05, 0x93, ++ 0x93, 0xF8, 0x62, 0x30, 0x00, 0x2B, 0xC9, 0xD0, 0x06, 0x49, 0x07, 0x48, ++ 0x4F, 0xF4, 0x27, 0x62, 0x0B, 0xF0, 0xE4, 0xF9, 0xC2, 0xE7, 0x00, 0xBF, ++ 0x38, 0x36, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x8C, 0x9C, 0x15, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x40, 0x9C, 0x15, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0x00, 0xB5, 0x83, 0xB0, 0x08, 0x46, 0x01, 0x92, 0x00, 0x93, 0xFA, 0xF7, ++ 0x45, 0xFA, 0xDD, 0xE9, 0x00, 0x12, 0x6E, 0x20, 0x09, 0xF0, 0x50, 0xF9, ++ 0x00, 0x20, 0x03, 0xB0, 0x5D, 0xF8, 0x04, 0xFB, 0xF0, 0xB5, 0x0C, 0x46, ++ 0x0E, 0x78, 0x60, 0x78, 0x89, 0x78, 0x83, 0xB0, 0x1D, 0x46, 0x01, 0x92, ++ 0x9E, 0xB9, 0xFE, 0xF7, 0xD5, 0xFE, 0x01, 0x9A, 0x00, 0xBB, 0x03, 0x26, ++ 0x29, 0x46, 0x03, 0x23, 0x2B, 0x20, 0x09, 0xF0, 0xD1, 0xF8, 0x62, 0x78, ++ 0x02, 0x70, 0xA2, 0x78, 0x42, 0x70, 0x86, 0x70, 0x09, 0xF0, 0xFA, 0xF8, ++ 0x00, 0x20, 0x03, 0xB0, 0xF0, 0xBD, 0xFE, 0xF7, 0xD1, 0xFE, 0x01, 0x9A, ++ 0x00, 0x28, 0xEA, 0xD0, 0x60, 0x78, 0x14, 0x4B, 0xA1, 0x78, 0x4F, 0xF4, ++ 0x1E, 0x76, 0x06, 0xFB, 0x00, 0x30, 0x15, 0xF0, 0x9D, 0xFC, 0x02, 0x26, ++ 0x01, 0x9A, 0xDF, 0xE7, 0x61, 0x78, 0x94, 0xF8, 0x02, 0xC0, 0x0D, 0x48, ++ 0x0D, 0x4F, 0x01, 0xEB, 0x81, 0x03, 0xC1, 0xEB, 0x03, 0x13, 0x63, 0x44, ++ 0x00, 0xEB, 0xC3, 0x03, 0x4F, 0xF0, 0x9E, 0x0E, 0x93, 0xF8, 0xA5, 0x31, ++ 0x0E, 0xFB, 0x01, 0xC1, 0x03, 0xEB, 0x43, 0x03, 0x00, 0xEB, 0x81, 0x01, ++ 0x07, 0xEB, 0xC3, 0x03, 0x81, 0xF8, 0x5A, 0x61, 0x1E, 0x81, 0x02, 0x26, ++ 0xC2, 0xE7, 0x00, 0xBF, 0x68, 0x65, 0x17, 0x00, 0xF4, 0xE4, 0x17, 0x00, ++ 0x08, 0xB5, 0x08, 0x46, 0x02, 0xF0, 0x0C, 0xFA, 0x01, 0x20, 0x08, 0xBD, ++ 0x70, 0xB5, 0x48, 0x78, 0xFF, 0x28, 0x0C, 0x46, 0x16, 0x46, 0x1D, 0x46, ++ 0x01, 0xD0, 0x17, 0xF0, 0xB3, 0xF9, 0x21, 0x78, 0xA0, 0x78, 0x0A, 0x4B, ++ 0x0A, 0x4A, 0x00, 0x39, 0x18, 0xBF, 0x01, 0x21, 0x00, 0x38, 0x18, 0xBF, ++ 0x01, 0x20, 0x18, 0x70, 0x11, 0x70, 0x02, 0x46, 0x06, 0x48, 0x0A, 0xF0, ++ 0xDD, 0xFE, 0x32, 0x46, 0x29, 0x46, 0x64, 0x20, 0x09, 0xF0, 0xD8, 0xF8, ++ 0x00, 0x20, 0x70, 0xBD, 0xB9, 0x34, 0x17, 0x00, 0xB8, 0x34, 0x17, 0x00, ++ 0x9C, 0x9C, 0x15, 0x00, 0xF8, 0xB5, 0x19, 0x46, 0x74, 0x20, 0x06, 0x23, ++ 0x09, 0xF0, 0x62, 0xF8, 0x4F, 0xF4, 0xD2, 0x77, 0x04, 0x46, 0x3B, 0x68, ++ 0x08, 0x20, 0x98, 0x47, 0x3B, 0x68, 0x06, 0x46, 0x09, 0x20, 0x98, 0x47, ++ 0x36, 0x0C, 0x36, 0x04, 0x56, 0xEA, 0x00, 0x03, 0x1A, 0xD1, 0x3B, 0x68, ++ 0x07, 0x20, 0x98, 0x47, 0x3B, 0x68, 0x05, 0x46, 0x08, 0x20, 0x98, 0x47, ++ 0x83, 0xB2, 0x19, 0x0A, 0x28, 0x0A, 0x2A, 0x0C, 0x63, 0x70, 0x2B, 0x0E, ++ 0x21, 0x70, 0x20, 0x71, 0xE2, 0x70, 0xA3, 0x70, 0xEA, 0xB2, 0x07, 0x48, ++ 0x65, 0x71, 0x0A, 0xF0, 0xA5, 0xFE, 0x20, 0x46, 0x09, 0xF0, 0x6A, 0xF8, ++ 0x00, 0x20, 0xF8, 0xBD, 0x05, 0x04, 0x45, 0xEA, 0x16, 0x45, 0x03, 0x0C, ++ 0xE7, 0xE7, 0x00, 0xBF, 0xC0, 0x9C, 0x15, 0x00, 0x2D, 0xE9, 0xF0, 0x41, ++ 0x0C, 0x46, 0x48, 0x7A, 0x09, 0x7A, 0x16, 0x46, 0xE2, 0x88, 0x84, 0xB0, ++ 0xCD, 0xE9, 0x00, 0x21, 0x02, 0x90, 0x62, 0x88, 0x5E, 0x48, 0x21, 0x88, ++ 0x1D, 0x46, 0xA3, 0x88, 0x0A, 0xF0, 0x86, 0xFE, 0xB4, 0xF8, 0x00, 0xC0, ++ 0x67, 0x88, 0xA0, 0x88, 0xE2, 0x88, 0x5A, 0x4B, 0xBC, 0xF1, 0x00, 0x0F, ++ 0x00, 0xF0, 0x9E, 0x80, 0x19, 0x68, 0xDF, 0xF8, 0x70, 0x81, 0x0B, 0x68, ++ 0xDF, 0xF8, 0x6C, 0xE1, 0x03, 0xEA, 0x08, 0x03, 0x43, 0xEA, 0x0C, 0x33, ++ 0x0B, 0x60, 0xDE, 0xF8, 0x00, 0x30, 0x03, 0xEA, 0x08, 0x03, 0x43, 0xEA, ++ 0x0C, 0x33, 0xCE, 0xF8, 0x00, 0x30, 0x00, 0x2F, 0x79, 0xD0, 0x4B, 0x68, ++ 0xDF, 0xF8, 0x44, 0xE1, 0xDF, 0xF8, 0x48, 0xC1, 0x03, 0xEA, 0x0E, 0x03, ++ 0x43, 0xEA, 0x07, 0x33, 0x4B, 0x60, 0xDC, 0xF8, 0x00, 0x30, 0x03, 0xEA, ++ 0x0E, 0x03, 0x43, 0xEA, 0x07, 0x33, 0xCC, 0xF8, 0x00, 0x30, 0x00, 0x28, ++ 0x3F, 0xD0, 0x8F, 0x68, 0xDF, 0xF8, 0x1C, 0xE1, 0xDF, 0xF8, 0x14, 0xC1, ++ 0x07, 0xEA, 0x0E, 0x07, 0x47, 0xEA, 0x00, 0x37, 0x8F, 0x60, 0xDC, 0xF8, ++ 0x00, 0x30, 0x03, 0xEA, 0x0E, 0x03, 0x43, 0xEA, 0x00, 0x33, 0xCC, 0xF8, ++ 0x00, 0x30, 0x00, 0x2A, 0x38, 0xD0, 0xC8, 0x68, 0xDF, 0xF8, 0xF4, 0xC0, ++ 0x38, 0x4F, 0x00, 0xEA, 0x0C, 0x00, 0x40, 0xEA, 0x02, 0x30, 0xC8, 0x60, ++ 0x3B, 0x68, 0x03, 0xEA, 0x0C, 0x03, 0x43, 0xEA, 0x02, 0x33, 0x3B, 0x60, ++ 0x23, 0x7A, 0x33, 0x4A, 0x00, 0x2B, 0x31, 0xD0, 0x13, 0x68, 0x43, 0xF0, ++ 0x10, 0x03, 0x13, 0x60, 0x63, 0x7A, 0x2F, 0x4A, 0x00, 0x2B, 0x31, 0xD0, ++ 0x13, 0x68, 0x43, 0xF0, 0x02, 0x03, 0x13, 0x60, 0x2C, 0x4B, 0xD3, 0xF8, ++ 0xA0, 0x31, 0x98, 0x47, 0x32, 0x46, 0x29, 0x46, 0x7F, 0x20, 0x09, 0xF0, ++ 0x17, 0xF8, 0x00, 0x20, 0x04, 0xB0, 0xBD, 0xE8, 0xF0, 0x81, 0x88, 0x68, ++ 0xDF, 0xF8, 0x9C, 0xC0, 0x25, 0x4F, 0x00, 0xEA, 0x0C, 0x00, 0x88, 0x60, ++ 0x3B, 0x68, 0x03, 0xEA, 0x0C, 0x03, 0x3B, 0x60, 0x00, 0x2A, 0xC6, 0xD1, ++ 0xCA, 0x68, 0x21, 0x4F, 0x1C, 0x48, 0x3A, 0x40, 0xCA, 0x60, 0x03, 0x68, ++ 0x1B, 0x4A, 0x3B, 0x40, 0x03, 0x60, 0x23, 0x7A, 0x00, 0x2B, 0xCD, 0xD1, ++ 0x13, 0x68, 0x23, 0xF0, 0x10, 0x03, 0x13, 0x60, 0x63, 0x7A, 0x16, 0x4A, ++ 0x00, 0x2B, 0xCD, 0xD1, 0x13, 0x68, 0x23, 0xF0, 0x02, 0x03, 0x13, 0x60, ++ 0xCC, 0xE7, 0x4F, 0x68, 0xDF, 0xF8, 0x50, 0xE0, 0xDF, 0xF8, 0x54, 0xC0, ++ 0x07, 0xEA, 0x0E, 0x07, 0x4F, 0x60, 0xDC, 0xF8, 0x00, 0x30, 0x03, 0xEA, ++ 0x0E, 0x03, 0xCC, 0xF8, 0x00, 0x30, 0x88, 0xE7, 0x19, 0x68, 0xDF, 0xF8, ++ 0x34, 0xE0, 0x0B, 0x68, 0xDF, 0xF8, 0x30, 0xC0, 0x03, 0xEA, 0x0E, 0x03, ++ 0x0B, 0x60, 0xDC, 0xF8, 0x00, 0x30, 0x03, 0xEA, 0x0E, 0x03, 0xCC, 0xF8, ++ 0x00, 0x30, 0x64, 0xE7, 0xD8, 0x9C, 0x15, 0x00, 0xAC, 0x35, 0x17, 0x00, ++ 0x0C, 0x02, 0x32, 0x40, 0x24, 0x02, 0x32, 0x40, 0x88, 0x1A, 0x17, 0x00, ++ 0x08, 0x02, 0x32, 0x40, 0xFF, 0x0F, 0x00, 0xF0, 0x00, 0x02, 0x32, 0x40, ++ 0x04, 0x02, 0x32, 0x40, 0x2D, 0xE9, 0xF0, 0x4F, 0x8A, 0x46, 0x83, 0xB0, ++ 0x49, 0x7C, 0x28, 0x48, 0xDF, 0xF8, 0xBC, 0x90, 0x27, 0x4F, 0x16, 0x46, ++ 0xDA, 0xF8, 0x0C, 0x20, 0x00, 0x92, 0x01, 0x91, 0x9A, 0xF8, 0x10, 0xB0, ++ 0xDA, 0xF8, 0x00, 0x10, 0x1D, 0x46, 0xDA, 0xE9, 0x01, 0x23, 0x0A, 0xF0, ++ 0xA5, 0xFD, 0x21, 0x4A, 0x21, 0x49, 0x9A, 0xF8, 0x11, 0x00, 0x82, 0xF8, ++ 0x05, 0x01, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x0B, 0xF3, 0x03, 0xF1, ++ 0x08, 0x02, 0x01, 0xEB, 0x02, 0x08, 0x01, 0xEB, 0x03, 0x0B, 0xAA, 0xF1, ++ 0x04, 0x0A, 0x00, 0x24, 0x5A, 0xF8, 0x04, 0x0F, 0xE3, 0xB2, 0x90, 0xB1, ++ 0x48, 0xF8, 0x24, 0x00, 0x16, 0x4A, 0x9B, 0xF8, 0x64, 0x10, 0x12, 0x68, ++ 0x42, 0xF8, 0x24, 0x00, 0x49, 0xB1, 0x01, 0x2C, 0x13, 0xD0, 0x02, 0x2B, ++ 0x17, 0xD0, 0x9B, 0xB1, 0x38, 0x60, 0x11, 0x4B, 0xD3, 0xF8, 0xA0, 0x31, ++ 0x98, 0x47, 0x01, 0x34, 0x04, 0x2C, 0xE5, 0xD1, 0x32, 0x46, 0x29, 0x46, ++ 0x83, 0x20, 0x08, 0xF0, 0x73, 0xFF, 0x00, 0x20, 0x03, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x8F, 0xC9, 0xF8, 0x00, 0x00, 0xEC, 0xE7, 0x08, 0x4B, 0x18, 0x60, ++ 0xE9, 0xE7, 0x08, 0x4B, 0x18, 0x60, 0xE6, 0xE7, 0x18, 0x9D, 0x15, 0x00, ++ 0x0C, 0x02, 0x32, 0x40, 0x2C, 0x19, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0xAC, 0x35, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x00, 0x02, 0x32, 0x40, ++ 0x08, 0x02, 0x32, 0x40, 0x04, 0x02, 0x32, 0x40, 0xF8, 0xB5, 0x7C, 0x20, ++ 0x0C, 0x46, 0x19, 0x46, 0x02, 0x23, 0x08, 0xF0, 0xE5, 0xFE, 0x23, 0x78, ++ 0x05, 0x46, 0x00, 0x2B, 0x5F, 0xD0, 0x35, 0x48, 0x0A, 0xF0, 0x46, 0xFD, ++ 0x34, 0x4B, 0x1B, 0x68, 0x00, 0x22, 0x1A, 0x70, 0x4F, 0xF4, 0xD2, 0x73, ++ 0x0F, 0x20, 0x1B, 0x68, 0x98, 0x47, 0x68, 0x70, 0x62, 0x78, 0x06, 0x46, ++ 0x00, 0x2A, 0x45, 0xD0, 0x2E, 0x4F, 0xC0, 0xF3, 0x40, 0x11, 0x42, 0x06, ++ 0x87, 0xF8, 0xB4, 0x10, 0x4F, 0xD4, 0x2C, 0x48, 0x0F, 0x22, 0x01, 0x21, ++ 0xE8, 0xF7, 0x1C, 0xFC, 0x02, 0x22, 0x11, 0x46, 0x29, 0x48, 0xE8, 0xF7, ++ 0x17, 0xFC, 0x02, 0x22, 0x11, 0x46, 0x28, 0x48, 0xE8, 0xF7, 0x12, 0xFC, ++ 0x4F, 0xF4, 0x00, 0x52, 0x11, 0x46, 0x24, 0x48, 0xE8, 0xF7, 0x0C, 0xFC, ++ 0x4F, 0xF4, 0x00, 0x52, 0x11, 0x46, 0x22, 0x48, 0xE8, 0xF7, 0x06, 0xFC, ++ 0x02, 0x22, 0x11, 0x46, 0x20, 0x48, 0xE8, 0xF7, 0x01, 0xFC, 0x4F, 0xF4, ++ 0x00, 0x52, 0x00, 0x21, 0x1D, 0x48, 0xE8, 0xF7, 0xFB, 0xFB, 0x97, 0xF8, ++ 0xB4, 0x10, 0x01, 0x22, 0x23, 0x78, 0x6B, 0xB1, 0xE3, 0x78, 0x2B, 0xB1, ++ 0xB7, 0xF8, 0xAA, 0x30, 0x43, 0xF4, 0x80, 0x43, 0xA7, 0xF8, 0xAA, 0x30, ++ 0x16, 0x48, 0xF3, 0xB2, 0x0A, 0xF0, 0xFA, 0xFC, 0x97, 0xF8, 0xB4, 0x10, ++ 0x29, 0x70, 0x28, 0x46, 0x08, 0xF0, 0xBC, 0xFE, 0x00, 0x20, 0xF8, 0xBD, ++ 0xA3, 0x78, 0x0B, 0x4F, 0xC3, 0xF3, 0x40, 0x11, 0x5B, 0x06, 0x87, 0xF8, ++ 0xB4, 0x10, 0xB8, 0xD5, 0xE0, 0xE7, 0x0D, 0x48, 0x0A, 0xF0, 0xE6, 0xFC, ++ 0x04, 0x4B, 0x1B, 0x68, 0x03, 0x22, 0x1A, 0x70, 0x9E, 0xE7, 0x00, 0x22, ++ 0xD6, 0xE7, 0x00, 0xBF, 0x48, 0x9D, 0x15, 0x00, 0x74, 0x36, 0x17, 0x00, ++ 0x2C, 0x19, 0x17, 0x00, 0x04, 0x20, 0x01, 0x50, 0x04, 0x10, 0x01, 0x50, ++ 0x08, 0x10, 0x01, 0x50, 0x00, 0x10, 0x01, 0x50, 0x68, 0x9D, 0x15, 0x00, ++ 0x58, 0x9D, 0x15, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, 0x18, 0x46, 0xB1, 0xB0, ++ 0x0C, 0x46, 0x10, 0x23, 0x01, 0x46, 0x6A, 0x20, 0x04, 0x94, 0x08, 0xF0, ++ 0x59, 0xFE, 0x4F, 0xF4, 0xD2, 0x73, 0x02, 0x46, 0x1B, 0x68, 0x05, 0x92, ++ 0x06, 0x20, 0x98, 0x47, 0x04, 0x46, 0x01, 0x46, 0x91, 0x48, 0x0A, 0xF0, ++ 0xB5, 0xFC, 0x14, 0xF4, 0x7F, 0x4F, 0xC4, 0xF3, 0x07, 0x25, 0x6F, 0xD1, ++ 0x26, 0x0E, 0xE5, 0xB2, 0x6E, 0xD0, 0xF4, 0xB2, 0x00, 0x2D, 0x6F, 0xD1, ++ 0x04, 0x9B, 0x19, 0x7D, 0x00, 0x29, 0x40, 0xF0, 0x83, 0x80, 0x00, 0x2E, ++ 0x40, 0xF0, 0x89, 0x80, 0x59, 0x7D, 0x31, 0xB1, 0x86, 0x48, 0x0A, 0xF0, ++ 0x9D, 0xFC, 0x04, 0x9B, 0x5C, 0x7D, 0x00, 0x2C, 0x7F, 0xD1, 0x04, 0x9B, ++ 0xDB, 0x68, 0x00, 0x2B, 0x40, 0xF0, 0x8D, 0x80, 0x04, 0x9B, 0xDF, 0xF8, ++ 0x40, 0xB2, 0x99, 0x68, 0x1A, 0x68, 0x7F, 0x4B, 0xDF, 0xF8, 0x38, 0xA2, ++ 0xD3, 0xF8, 0x70, 0x32, 0x7D, 0x4C, 0xCD, 0xE9, 0x08, 0x21, 0x08, 0xA8, ++ 0x0A, 0xA9, 0x98, 0x47, 0x1A, 0xAE, 0x6F, 0xF0, 0x3F, 0x08, 0x09, 0xAF, ++ 0x0A, 0xAB, 0x07, 0x97, 0xA8, 0xEB, 0x03, 0x08, 0x35, 0x46, 0x0D, 0xF1, ++ 0x78, 0x09, 0x06, 0x96, 0xE3, 0x79, 0x00, 0x93, 0x08, 0xEB, 0x05, 0x02, ++ 0x23, 0x68, 0x03, 0x92, 0x59, 0x46, 0x4F, 0xF4, 0x00, 0x50, 0x0A, 0xF0, ++ 0xBD, 0xFC, 0x15, 0xF8, 0x01, 0x6B, 0x57, 0xF8, 0x04, 0x3F, 0x03, 0x9A, ++ 0x00, 0x96, 0x51, 0x46, 0x23, 0x60, 0xE6, 0x71, 0x4F, 0xF4, 0x00, 0x50, ++ 0x0A, 0xF0, 0xB0, 0xFC, 0x4D, 0x45, 0x04, 0xF1, 0x10, 0x04, 0xE3, 0xD1, ++ 0xDF, 0xF8, 0xD8, 0xB1, 0x06, 0x9E, 0x9B, 0xF8, 0xB4, 0x30, 0x00, 0x2B, ++ 0x52, 0xD1, 0xDF, 0xF8, 0xD0, 0xA1, 0x61, 0x4B, 0x00, 0x20, 0xD3, 0xF8, ++ 0xB0, 0x34, 0x98, 0x47, 0x05, 0x98, 0x5F, 0x4C, 0x5F, 0x4A, 0x60, 0x4B, ++ 0x82, 0x60, 0xC0, 0xE9, 0x00, 0x4A, 0xC3, 0x60, 0x08, 0xF0, 0x0C, 0xFE, ++ 0x00, 0x20, 0x31, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x23, 0x0E, 0x0B, 0xD1, ++ 0x26, 0x0C, 0xF4, 0xB2, 0x00, 0x2D, 0x8F, 0xD0, 0x3C, 0xB9, 0x04, 0x9B, ++ 0x59, 0x7D, 0x00, 0x29, 0x40, 0xF0, 0x99, 0x80, 0x00, 0x24, 0x00, 0xE0, ++ 0xDC, 0xB2, 0x1F, 0x2D, 0x28, 0xBF, 0x1F, 0x25, 0xE9, 0x06, 0x41, 0xEA, ++ 0x85, 0x51, 0x51, 0x4A, 0x51, 0x48, 0xE8, 0xF7, 0x17, 0xFB, 0x51, 0x48, ++ 0x29, 0x46, 0x0A, 0xF0, 0x23, 0xFC, 0x86, 0xE7, 0x4F, 0x48, 0x0A, 0xF0, ++ 0x1F, 0xFC, 0x04, 0x9B, 0x1D, 0x7D, 0x00, 0x2E, 0x70, 0xD0, 0x00, 0x2D, ++ 0xE7, 0xD1, 0x3F, 0x2C, 0x21, 0x46, 0x4B, 0x48, 0x28, 0xBF, 0x3F, 0x21, ++ 0x3F, 0x22, 0x03, 0x91, 0xE8, 0xF7, 0x00, 0xFB, 0x03, 0x99, 0x48, 0x48, ++ 0x0A, 0xF0, 0x0C, 0xFC, 0x04, 0x9B, 0xDB, 0x68, 0x00, 0x2B, 0x3F, 0xF4, ++ 0x73, 0xAF, 0x04, 0x9B, 0x18, 0x69, 0xEB, 0xF7, 0x6F, 0xF8, 0x6D, 0xE7, ++ 0x42, 0x4A, 0x38, 0x4D, 0x93, 0x69, 0xD5, 0xF8, 0x28, 0x42, 0xDF, 0xF8, ++ 0x20, 0xA1, 0x40, 0x4F, 0x43, 0xF0, 0x01, 0x03, 0x93, 0x61, 0x04, 0x9B, ++ 0x5B, 0x68, 0x08, 0x93, 0x41, 0xF2, 0x7C, 0x52, 0x00, 0x23, 0x11, 0x46, ++ 0xCD, 0xE9, 0x00, 0x33, 0x01, 0x20, 0xA0, 0x47, 0x39, 0x4A, 0x01, 0x23, ++ 0x82, 0xF8, 0x2A, 0x30, 0x0A, 0xA9, 0xD5, 0xF8, 0x70, 0x32, 0x37, 0x4D, ++ 0x08, 0xA8, 0x98, 0x47, 0x54, 0x46, 0xCD, 0xF8, 0x10, 0xA0, 0xDD, 0xF8, ++ 0x1C, 0xA0, 0xE3, 0x79, 0x00, 0x93, 0x06, 0xEB, 0x08, 0x02, 0x23, 0x68, ++ 0x03, 0x92, 0x39, 0x46, 0x4F, 0xF4, 0x00, 0x50, 0x0A, 0xF0, 0x22, 0xFC, ++ 0x16, 0xF8, 0x01, 0xCB, 0x5A, 0xF8, 0x04, 0x3F, 0x03, 0x9A, 0xCD, 0xF8, ++ 0x00, 0xC0, 0x29, 0x46, 0x23, 0x60, 0x84, 0xF8, 0x07, 0xC0, 0x4F, 0xF4, ++ 0x00, 0x50, 0x0A, 0xF0, 0x13, 0xFC, 0x4E, 0x45, 0x04, 0xF1, 0x10, 0x04, ++ 0xE1, 0xD1, 0x9B, 0xF8, 0xB4, 0x30, 0xDD, 0xF8, 0x10, 0xA0, 0x00, 0x2B, ++ 0x3F, 0xF4, 0x65, 0xAF, 0x13, 0x4B, 0x00, 0x20, 0xD3, 0xF8, 0x80, 0x34, ++ 0x98, 0x47, 0x1D, 0x4B, 0x1E, 0x49, 0x93, 0xF8, 0x2A, 0x20, 0x08, 0x20, ++ 0x00, 0x23, 0x0A, 0xF0, 0xFB, 0xFB, 0x5B, 0xE7, 0x59, 0x7D, 0x1C, 0x46, ++ 0x39, 0xB1, 0x0A, 0x48, 0x0A, 0xF0, 0xA4, 0xFB, 0x64, 0x7D, 0x00, 0x2D, ++ 0x3F, 0xF4, 0x05, 0xAF, 0x6D, 0xE7, 0x00, 0x2D, 0x3F, 0xF4, 0x03, 0xAF, ++ 0x66, 0xE7, 0x04, 0x48, 0x0A, 0xF0, 0x98, 0xFB, 0x04, 0x9B, 0x5C, 0x7D, ++ 0x63, 0xE7, 0x00, 0xBF, 0x90, 0x9D, 0x15, 0x00, 0xBC, 0x9D, 0x15, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x1C, 0x13, 0x17, 0x00, 0x1C, 0x18, 0x17, 0x00, ++ 0x9C, 0x18, 0x17, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x04, 0x88, 0x01, 0x50, ++ 0xD0, 0x9D, 0x15, 0x00, 0xAC, 0x9D, 0x15, 0x00, 0x28, 0x91, 0x01, 0x50, ++ 0xE4, 0x9D, 0x15, 0x00, 0x00, 0x80, 0x50, 0x40, 0x44, 0x9E, 0x15, 0x00, ++ 0xBC, 0x34, 0x17, 0x00, 0x64, 0x9E, 0x15, 0x00, 0x9C, 0x77, 0x15, 0x00, ++ 0xFC, 0x9D, 0x15, 0x00, 0x20, 0x9E, 0x15, 0x00, 0x2C, 0x19, 0x17, 0x00, ++ 0x1C, 0x16, 0x17, 0x00, 0x38, 0xB5, 0x00, 0x22, 0x0D, 0x46, 0x01, 0x23, ++ 0x0C, 0x21, 0x54, 0x20, 0x08, 0xF0, 0xFA, 0xFC, 0x01, 0x23, 0x03, 0x70, ++ 0x04, 0x46, 0x28, 0x78, 0x04, 0x28, 0x0D, 0xD8, 0x0C, 0x4B, 0x4F, 0xF4, ++ 0xA4, 0x62, 0x02, 0xFB, 0x00, 0x30, 0x90, 0xF8, 0xC0, 0x34, 0x2B, 0xB1, ++ 0x00, 0x23, 0x23, 0x70, 0x69, 0x78, 0x31, 0xB1, 0x06, 0xF0, 0xA2, 0xFB, ++ 0x20, 0x46, 0x08, 0xF0, 0x13, 0xFD, 0x00, 0x20, 0x38, 0xBD, 0x06, 0xF0, ++ 0xBD, 0xFB, 0x20, 0x46, 0x08, 0xF0, 0x0C, 0xFD, 0x00, 0x20, 0x38, 0xBD, ++ 0x18, 0x88, 0x17, 0x00, 0x70, 0xB5, 0x10, 0x46, 0x14, 0x46, 0x0D, 0x46, ++ 0x1E, 0x46, 0x08, 0xF0, 0x73, 0xFF, 0x03, 0x28, 0x25, 0xD0, 0x20, 0x46, ++ 0x08, 0xF0, 0x6E, 0xFF, 0x04, 0x28, 0x20, 0xD0, 0x2A, 0x78, 0x1B, 0x4D, ++ 0x20, 0x46, 0xEA, 0x77, 0x72, 0xB9, 0x08, 0xF0, 0x65, 0xFF, 0x02, 0x28, ++ 0x17, 0xD0, 0x18, 0x4B, 0xD3, 0xF8, 0x60, 0x31, 0x98, 0x47, 0x23, 0x20, ++ 0x22, 0x46, 0x31, 0x46, 0x08, 0xF0, 0x20, 0xFD, 0x00, 0x20, 0x70, 0xBD, ++ 0x08, 0xF0, 0x56, 0xFF, 0x58, 0xB1, 0x02, 0x28, 0xF9, 0xD0, 0x10, 0x4B, ++ 0xD3, 0xF8, 0xE0, 0x30, 0x98, 0x47, 0x20, 0x46, 0x02, 0x21, 0x08, 0xF0, ++ 0xA3, 0xFE, 0x02, 0x20, 0x70, 0xBD, 0x0C, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0x02, 0xDB, 0x00, 0x23, 0x6B, 0x82, 0xE0, 0xE7, ++ 0x08, 0x4B, 0x1B, 0x68, 0x1B, 0x07, 0xF8, 0xD0, 0x07, 0x49, 0x08, 0x48, ++ 0x40, 0xF2, 0x31, 0x62, 0x0A, 0xF0, 0x76, 0xFD, 0xF1, 0xE7, 0x00, 0xBF, ++ 0x98, 0x9C, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x38, 0x00, 0x32, 0x40, 0x70, 0x79, 0x15, 0x00, 0x84, 0x9E, 0x15, 0x00, ++ 0x70, 0xB5, 0x1E, 0x4D, 0x2B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0x0E, 0x46, 0x14, 0x46, 0x1C, 0xDB, 0x20, 0x46, 0x08, 0xF0, 0x1C, 0xFF, ++ 0x58, 0xB1, 0x02, 0x28, 0x08, 0xD0, 0x18, 0x4B, 0xD3, 0xF8, 0xE0, 0x30, ++ 0x98, 0x47, 0x20, 0x46, 0x02, 0x21, 0x08, 0xF0, 0x69, 0xFE, 0x02, 0x20, ++ 0x70, 0xBD, 0x2B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x13, 0xDB, ++ 0x20, 0x46, 0x03, 0x21, 0x08, 0xF0, 0x5E, 0xFE, 0x33, 0x68, 0x98, 0x47, ++ 0x00, 0x20, 0x70, 0xBD, 0x10, 0x46, 0x08, 0xF0, 0xFF, 0xFE, 0x04, 0x28, ++ 0xDD, 0xD1, 0x0B, 0x49, 0x0B, 0x48, 0x40, 0xF2, 0x71, 0x62, 0x0A, 0xF0, ++ 0x37, 0xFD, 0xD6, 0xE7, 0x09, 0x4B, 0x1B, 0x68, 0x1B, 0x07, 0xE7, 0xD0, ++ 0x05, 0x49, 0x08, 0x48, 0x4F, 0xF4, 0xCF, 0x62, 0x0A, 0xF0, 0x2C, 0xFD, ++ 0xE0, 0xE7, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xAC, 0x9E, 0x15, 0x00, 0x38, 0x00, 0x32, 0x40, ++ 0x84, 0x9E, 0x15, 0x00, 0x70, 0xB5, 0x12, 0x4C, 0x88, 0x78, 0x4F, 0xF4, ++ 0xA4, 0x65, 0x05, 0xFB, 0x00, 0x40, 0x82, 0xB0, 0x90, 0xF8, 0x62, 0x40, ++ 0x1E, 0x46, 0x84, 0xB9, 0x90, 0xF8, 0x6C, 0x00, 0x0C, 0x4D, 0x0C, 0x88, ++ 0x4F, 0xF4, 0x1E, 0x71, 0x01, 0xFB, 0x00, 0x51, 0xA4, 0x02, 0x8C, 0x60, ++ 0x31, 0x46, 0x15, 0x20, 0x08, 0xF0, 0x8A, 0xFC, 0x00, 0x20, 0x02, 0xB0, ++ 0x70, 0xBD, 0x06, 0x4C, 0x09, 0x88, 0xD4, 0xF8, 0x60, 0x44, 0x01, 0x92, ++ 0xA0, 0x47, 0x01, 0x9A, 0xF0, 0xE7, 0x00, 0xBF, 0x18, 0x88, 0x17, 0x00, ++ 0x68, 0x65, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x41, ++ 0x88, 0x79, 0x19, 0x4D, 0x4F, 0xF4, 0xA4, 0x66, 0x06, 0xFB, 0x00, 0xF6, ++ 0x06, 0xF1, 0x38, 0x00, 0x28, 0x44, 0x35, 0x44, 0x82, 0xB0, 0x90, 0x46, ++ 0x06, 0x22, 0x1F, 0x46, 0x0C, 0x46, 0x1C, 0xF0, 0x85, 0xFF, 0x95, 0xF8, ++ 0xC0, 0x34, 0x73, 0xB9, 0x10, 0x49, 0x11, 0x4B, 0x20, 0x68, 0xA2, 0x88, ++ 0x08, 0x60, 0x1A, 0x60, 0x42, 0x46, 0x39, 0x46, 0x19, 0x20, 0x08, 0xF0, ++ 0x57, 0xFC, 0x00, 0x20, 0x02, 0xB0, 0xBD, 0xE8, 0xF0, 0x81, 0x0D, 0xF1, ++ 0x07, 0x00, 0xFC, 0xF7, 0x9F, 0xFF, 0x00, 0x28, 0xF0, 0xD1, 0x08, 0x49, ++ 0x08, 0x48, 0xD1, 0xE9, 0x00, 0x23, 0x43, 0xF0, 0x10, 0x03, 0x1A, 0x43, ++ 0x4B, 0x60, 0x02, 0x60, 0xE6, 0xE7, 0x00, 0xBF, 0x18, 0x88, 0x17, 0x00, ++ 0x20, 0x00, 0x32, 0x40, 0x24, 0x00, 0x32, 0x40, 0x98, 0x9C, 0x17, 0x00, ++ 0x60, 0x00, 0x32, 0x40, 0x2D, 0xE9, 0xF0, 0x4F, 0x0D, 0x46, 0x9E, 0x4F, ++ 0x95, 0xF8, 0x03, 0xA0, 0x4F, 0xF4, 0xA4, 0x61, 0x89, 0xB0, 0x01, 0xFB, ++ 0x0A, 0xFB, 0x07, 0xEB, 0x0B, 0x06, 0x00, 0x24, 0x0D, 0xF1, 0x1F, 0x00, ++ 0x90, 0x46, 0x99, 0x46, 0x8D, 0xF8, 0x1F, 0x40, 0xFC, 0xF7, 0x72, 0xFF, ++ 0x96, 0xF8, 0x62, 0x30, 0xAA, 0x78, 0x86, 0xF8, 0x64, 0x20, 0x04, 0x46, ++ 0x00, 0x2B, 0x40, 0xF0, 0xED, 0x80, 0x96, 0xF8, 0x6C, 0x10, 0x02, 0x91, ++ 0x00, 0x2A, 0x00, 0xF0, 0x45, 0x81, 0x8E, 0x4A, 0x8E, 0x4B, 0x03, 0x92, ++ 0x8C, 0x46, 0x8E, 0x49, 0x18, 0x69, 0xD2, 0xF8, 0xE0, 0x31, 0x4F, 0xF4, ++ 0x1E, 0x72, 0x02, 0xFB, 0x0C, 0x12, 0x0B, 0xF1, 0x18, 0x01, 0x79, 0x18, ++ 0x04, 0x91, 0x91, 0x68, 0x05, 0x92, 0x41, 0x18, 0x04, 0x98, 0x98, 0x47, ++ 0x05, 0x9A, 0x2B, 0x88, 0x13, 0x84, 0xFC, 0xF7, 0x39, 0xFF, 0x05, 0x9A, ++ 0x96, 0xF8, 0xC0, 0x14, 0x01, 0x94, 0x13, 0x8C, 0x92, 0xF8, 0x23, 0x20, ++ 0x00, 0x91, 0x4F, 0xF4, 0x80, 0x70, 0x7F, 0x49, 0x0A, 0xF0, 0x3C, 0xFA, ++ 0x96, 0xF8, 0xC0, 0x34, 0x33, 0xB9, 0x7D, 0x4A, 0x29, 0x88, 0x13, 0x68, ++ 0x9B, 0xB2, 0x43, 0xEA, 0x01, 0x43, 0x13, 0x60, 0x7A, 0x4B, 0x1B, 0x68, ++ 0x18, 0x04, 0x00, 0xF1, 0xD2, 0x81, 0x79, 0x49, 0x79, 0x4B, 0xB1, 0xF8, ++ 0x1C, 0xC0, 0x02, 0x99, 0x08, 0x46, 0x72, 0x49, 0x4F, 0xF4, 0x1E, 0x72, ++ 0x02, 0xFB, 0x00, 0x12, 0x4F, 0xF4, 0xA4, 0x6B, 0x90, 0x68, 0x02, 0x92, ++ 0x0B, 0xFB, 0x0A, 0x7B, 0x0C, 0xF1, 0x14, 0x0C, 0x00, 0xFB, 0x0C, 0xFC, ++ 0xA3, 0xFB, 0x0C, 0x3C, 0xDB, 0xF8, 0x04, 0x00, 0x4F, 0xEA, 0x9C, 0x4C, ++ 0x00, 0x23, 0xA2, 0xF8, 0x1E, 0xC0, 0x40, 0xF0, 0x01, 0x00, 0xDF, 0xF8, ++ 0x90, 0xC1, 0xAB, 0xF8, 0x68, 0x30, 0x8B, 0xF8, 0x6A, 0x30, 0x8B, 0xF8, ++ 0x8C, 0x30, 0x8B, 0xF8, 0x78, 0x30, 0xCB, 0xF8, 0x74, 0x30, 0xCB, 0xF8, ++ 0x04, 0x00, 0xDC, 0xF8, 0x10, 0x00, 0xCB, 0xF8, 0x70, 0x00, 0x30, 0x46, ++ 0x04, 0xF0, 0xF4, 0xFA, 0x9B, 0xF8, 0xC0, 0x04, 0x5D, 0x49, 0x00, 0x23, ++ 0x00, 0x28, 0x40, 0xF0, 0x76, 0x81, 0x5D, 0x4B, 0x02, 0x9A, 0x9B, 0x7C, ++ 0x00, 0x2B, 0x40, 0xF0, 0x8B, 0x81, 0x00, 0x2C, 0x40, 0xF0, 0xD5, 0x81, ++ 0xDF, 0xF8, 0x7C, 0xB1, 0xDB, 0xF8, 0x20, 0x30, 0x00, 0x2B, 0x40, 0xF0, ++ 0x81, 0x81, 0x9D, 0xF8, 0x1F, 0x30, 0x00, 0x2B, 0x40, 0xF0, 0x87, 0x82, ++ 0x53, 0x49, 0x93, 0x68, 0x0A, 0x68, 0xCB, 0xF8, 0x20, 0x60, 0x12, 0x0C, ++ 0x12, 0x04, 0xC3, 0xF3, 0x8F, 0x23, 0x13, 0x43, 0x0B, 0x60, 0xDD, 0xE9, ++ 0x03, 0x30, 0xD3, 0xF8, 0xD8, 0x31, 0x98, 0x47, 0x03, 0x9B, 0x8B, 0xF8, ++ 0x24, 0x40, 0xD3, 0xF8, 0x60, 0x32, 0x98, 0x47, 0xAA, 0x78, 0x11, 0x46, ++ 0x30, 0x46, 0x05, 0xF0, 0x5B, 0xFF, 0xAB, 0x78, 0x00, 0x2B, 0x38, 0xD0, ++ 0x45, 0x4B, 0x1B, 0x68, 0x1A, 0x68, 0x00, 0x2A, 0x00, 0xF0, 0xE0, 0x80, ++ 0x43, 0x49, 0x0A, 0x60, 0x5A, 0x68, 0x00, 0x2A, 0x00, 0xF0, 0xE5, 0x80, ++ 0xC2, 0xF3, 0x0B, 0x01, 0x00, 0x29, 0x40, 0xF0, 0x4F, 0x81, 0x4F, 0xF4, ++ 0xA4, 0x61, 0x01, 0xFB, 0x0A, 0x71, 0x22, 0xF4, 0x7F, 0x62, 0xC9, 0x68, ++ 0x3B, 0x48, 0x22, 0xF0, 0x0F, 0x02, 0xC1, 0xF3, 0x0B, 0x01, 0x0A, 0x43, ++ 0x02, 0x60, 0x9A, 0x68, 0x00, 0x2A, 0x40, 0xF0, 0xD9, 0x80, 0x4F, 0xF4, ++ 0xA4, 0x62, 0x02, 0xFB, 0x0A, 0x72, 0x35, 0x49, 0x12, 0x69, 0x0A, 0x60, ++ 0xDB, 0x68, 0x00, 0x2B, 0x40, 0xF0, 0xD4, 0x80, 0x4F, 0xF4, 0xA4, 0x63, ++ 0x03, 0xFB, 0x0A, 0x77, 0x30, 0x4B, 0x7A, 0x69, 0x1A, 0x60, 0x21, 0x4B, ++ 0xD3, 0xF8, 0xA0, 0x31, 0x98, 0x47, 0x42, 0x46, 0x49, 0x46, 0x1F, 0x20, ++ 0x08, 0xF0, 0x30, 0xFB, 0x00, 0x20, 0x09, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, ++ 0x80, 0xB1, 0x22, 0x4B, 0x9C, 0x68, 0x6C, 0xB1, 0x94, 0xF8, 0x62, 0x30, ++ 0x3B, 0xB9, 0x94, 0xF8, 0x64, 0x30, 0x23, 0xB1, 0xA6, 0x42, 0x02, 0xD0, ++ 0x94, 0xF8, 0xC0, 0x34, 0x13, 0xB1, 0x24, 0x68, 0x00, 0x2C, 0xF1, 0xD1, ++ 0x00, 0x2A, 0x00, 0xF0, 0xB2, 0x80, 0x1F, 0x4B, 0x19, 0x6A, 0xA1, 0x42, ++ 0x9D, 0xD1, 0x0E, 0x49, 0x1D, 0x4C, 0xD1, 0xF8, 0x64, 0x12, 0x00, 0x22, ++ 0x1A, 0x62, 0x83, 0xF8, 0x24, 0x20, 0x88, 0x47, 0x0F, 0x4A, 0x1A, 0x48, ++ 0xD2, 0xE9, 0x00, 0x13, 0x43, 0xF0, 0x10, 0x03, 0x19, 0x43, 0x01, 0x60, ++ 0x17, 0x48, 0x18, 0x49, 0x20, 0x60, 0x53, 0x60, 0x0B, 0x68, 0x03, 0x43, ++ 0x0B, 0x60, 0xAA, 0x78, 0x83, 0xE7, 0x00, 0xBF, 0x18, 0x88, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x00, 0x10, 0x50, 0x40, 0x68, 0x65, 0x17, 0x00, ++ 0xD0, 0x9E, 0x15, 0x00, 0x68, 0x00, 0x32, 0x40, 0x04, 0x00, 0x32, 0x40, ++ 0x98, 0x9C, 0x17, 0x00, 0x83, 0xDE, 0x1B, 0x43, 0x00, 0x88, 0x17, 0x00, ++ 0x64, 0x00, 0x32, 0x40, 0xAC, 0x35, 0x17, 0x00, 0x00, 0x02, 0x32, 0x40, ++ 0x04, 0x02, 0x32, 0x40, 0x08, 0x02, 0x32, 0x40, 0x0C, 0x02, 0x32, 0x40, ++ 0x1C, 0x9E, 0x17, 0x00, 0x70, 0x80, 0x32, 0x40, 0x60, 0x00, 0x32, 0x40, ++ 0x01, 0x00, 0x04, 0x00, 0x74, 0x80, 0x32, 0x40, 0xAC, 0x4B, 0x03, 0x93, ++ 0x0B, 0xF1, 0x18, 0x00, 0x38, 0x44, 0xD3, 0xF8, 0xD8, 0x31, 0x98, 0x47, ++ 0x03, 0x9B, 0xD3, 0xF8, 0xDC, 0x33, 0x98, 0x47, 0xA7, 0x49, 0x96, 0xF8, ++ 0xC0, 0x24, 0x23, 0x46, 0x4F, 0xF4, 0x80, 0x70, 0x0A, 0xF0, 0x0A, 0xF9, ++ 0xA4, 0x4B, 0x1B, 0x68, 0x19, 0x04, 0x00, 0xF1, 0xD8, 0x80, 0xA3, 0x4B, ++ 0x9B, 0x7F, 0x3B, 0xB9, 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, 0x0A, 0x72, ++ 0x82, 0xF8, 0xC3, 0x34, 0xC2, 0xF8, 0xC4, 0x34, 0x4F, 0xF4, 0xA4, 0x63, ++ 0x03, 0xFB, 0x0A, 0x73, 0x93, 0xF8, 0xC0, 0x34, 0x00, 0x2B, 0x00, 0xF0, ++ 0x8C, 0x80, 0x00, 0x2C, 0x00, 0xF0, 0x8E, 0x80, 0x98, 0x4B, 0x9C, 0x68, ++ 0x00, 0x2C, 0x00, 0xF0, 0x89, 0x80, 0x94, 0xF8, 0x62, 0x30, 0x4B, 0xB9, ++ 0x94, 0xF8, 0x64, 0x30, 0x33, 0xB1, 0xA6, 0x42, 0x04, 0xD0, 0x94, 0xF8, ++ 0xC0, 0x34, 0x00, 0x2B, 0x00, 0xF0, 0x4A, 0x81, 0x24, 0x68, 0x00, 0x2C, ++ 0xEF, 0xD1, 0x77, 0xE0, 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, 0x0A, 0x72, ++ 0x8C, 0x49, 0x92, 0x68, 0x0A, 0x60, 0x5A, 0x68, 0x00, 0x2A, 0x7F, 0xF4, ++ 0x1B, 0xAF, 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, 0x0A, 0x72, 0x88, 0x49, ++ 0xD2, 0x68, 0x0A, 0x60, 0x9A, 0x68, 0x00, 0x2A, 0x3F, 0xF4, 0x27, 0xAF, ++ 0x85, 0x49, 0x0A, 0x60, 0xDB, 0x68, 0x00, 0x2B, 0x3F, 0xF4, 0x2C, 0xAF, ++ 0x83, 0x4A, 0x13, 0x60, 0x7A, 0x4B, 0xD3, 0xF8, 0xA0, 0x31, 0x98, 0x47, ++ 0x2F, 0xE7, 0x81, 0x48, 0x81, 0x49, 0x03, 0x68, 0x1B, 0x0C, 0x1B, 0x04, ++ 0x03, 0x60, 0x0B, 0x6A, 0x00, 0x2B, 0x7F, 0xF4, 0xE6, 0xAE, 0x00, 0x2C, ++ 0x3F, 0xF4, 0xE3, 0xAE, 0xDF, 0xF8, 0xC4, 0xB1, 0x0C, 0x62, 0x81, 0xF8, ++ 0x24, 0x20, 0x04, 0xF1, 0x18, 0x00, 0xDB, 0xF8, 0xD8, 0x31, 0x98, 0x47, ++ 0xDB, 0xF8, 0x60, 0x32, 0x98, 0x47, 0x76, 0x49, 0xDF, 0xF8, 0xE4, 0xC1, ++ 0x75, 0x48, 0xD4, 0xF8, 0x38, 0xE0, 0xA4, 0x8F, 0xD1, 0xE9, 0x00, 0x32, ++ 0x22, 0xF0, 0x10, 0x02, 0x13, 0x43, 0xCC, 0xF8, 0x00, 0x30, 0xC0, 0xF8, ++ 0x00, 0xE0, 0x70, 0x4B, 0x4C, 0xF8, 0x3C, 0x4C, 0x00, 0xF5, 0x00, 0x40, ++ 0x54, 0x30, 0x6E, 0x4C, 0x1C, 0x60, 0x03, 0x68, 0x4A, 0x60, 0x23, 0xF4, ++ 0x80, 0x23, 0x23, 0xF0, 0x01, 0x03, 0x03, 0x60, 0x1A, 0xE0, 0xCC, 0xB1, ++ 0x64, 0x4A, 0x10, 0x6A, 0xB0, 0xB1, 0x13, 0x62, 0x82, 0xF8, 0x24, 0x30, ++ 0x03, 0x9B, 0xD3, 0xF8, 0x64, 0x32, 0x98, 0x47, 0x60, 0x49, 0x64, 0x48, ++ 0xD1, 0xE9, 0x00, 0x23, 0x43, 0xF0, 0x10, 0x03, 0x1A, 0x43, 0x4B, 0x60, ++ 0x02, 0x60, 0xAA, 0x78, 0x9F, 0xE6, 0x02, 0x2C, 0x65, 0xD0, 0x01, 0x2C, ++ 0x00, 0xF0, 0xC0, 0x80, 0xAA, 0x78, 0x98, 0xE6, 0x52, 0x49, 0x0A, 0x60, ++ 0x94, 0xE7, 0xE6, 0xF7, 0x1F, 0xFE, 0x00, 0x28, 0x3F, 0xF4, 0x29, 0xAE, ++ 0x02, 0x9A, 0x11, 0x46, 0x57, 0x4A, 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, ++ 0x01, 0x23, 0x5B, 0x68, 0x9A, 0x06, 0x7F, 0xF5, 0x1E, 0xAE, 0x28, 0x88, ++ 0xE6, 0xF7, 0x54, 0xFE, 0xF9, 0xF7, 0x9C, 0xF9, 0x51, 0x49, 0x4F, 0xF4, ++ 0x80, 0x70, 0x0A, 0xF0, 0x41, 0xF8, 0x03, 0x9B, 0xD3, 0xF8, 0xE0, 0x33, ++ 0x98, 0x47, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x0A, 0x73, 0x93, 0xF8, ++ 0x62, 0x20, 0x04, 0x2A, 0x3F, 0xF4, 0x07, 0xAE, 0x93, 0xF8, 0x63, 0x00, ++ 0x03, 0x9B, 0xD3, 0xF8, 0x30, 0x33, 0x98, 0x47, 0xFF, 0xE5, 0xE6, 0xF7, ++ 0xF1, 0xFD, 0x00, 0x28, 0x3F, 0xF4, 0x23, 0xAF, 0x41, 0x4B, 0x02, 0x99, ++ 0x4F, 0xF4, 0x1E, 0x72, 0x02, 0xFB, 0x01, 0x3B, 0xDB, 0xF8, 0x04, 0x30, ++ 0x9B, 0x06, 0x7F, 0xF5, 0x18, 0xAF, 0x96, 0xF8, 0x62, 0x30, 0x04, 0x2B, ++ 0x3F, 0xF4, 0x13, 0xAF, 0x96, 0xF8, 0x63, 0x00, 0x06, 0xF0, 0x2A, 0xFB, ++ 0x0D, 0xE7, 0x01, 0x2C, 0xB0, 0xD1, 0x30, 0x4C, 0x22, 0x6A, 0xB2, 0x42, ++ 0xAC, 0xD0, 0x23, 0x62, 0x02, 0x93, 0xDD, 0xE9, 0x03, 0x30, 0xD3, 0xF8, ++ 0xD8, 0x21, 0x90, 0x47, 0x02, 0x9B, 0x84, 0xF8, 0x24, 0x30, 0x03, 0x9B, ++ 0xD3, 0xF8, 0x64, 0x32, 0x98, 0x47, 0xAA, 0x78, 0x37, 0xE6, 0x26, 0x4C, ++ 0x23, 0x6A, 0x00, 0x2B, 0x98, 0xD1, 0x1E, 0x4B, 0x98, 0x68, 0x20, 0xB9, ++ 0xA3, 0xE0, 0x00, 0x68, 0x00, 0x28, 0x00, 0xF0, 0xA0, 0x80, 0x90, 0xF8, ++ 0x62, 0x30, 0x00, 0x2B, 0xF7, 0xD1, 0x90, 0xF8, 0x64, 0x30, 0x00, 0x2B, ++ 0xF3, 0xD0, 0x86, 0x42, 0xF1, 0xD0, 0x90, 0xF8, 0xC0, 0x34, 0x00, 0x2B, ++ 0xED, 0xD1, 0x1F, 0x49, 0x17, 0x4A, 0x20, 0x62, 0x9B, 0x46, 0x90, 0xF8, ++ 0x6C, 0x30, 0x4F, 0xF4, 0x1E, 0x7C, 0x0C, 0xFB, 0x03, 0x13, 0x11, 0x68, ++ 0x9B, 0x68, 0x09, 0x0C, 0x09, 0x04, 0xC3, 0xF3, 0x8F, 0x23, 0x0B, 0x43, ++ 0x13, 0x60, 0x03, 0x9B, 0x18, 0x30, 0xD3, 0xF8, 0xD8, 0x31, 0x98, 0x47, ++ 0x03, 0x9B, 0x84, 0xF8, 0x24, 0xB0, 0xD3, 0xF8, 0x60, 0x32, 0x98, 0x47, ++ 0xAA, 0x78, 0xFE, 0xE5, 0x88, 0x1A, 0x17, 0x00, 0x00, 0x9F, 0x15, 0x00, ++ 0x04, 0x00, 0x32, 0x40, 0x64, 0xBA, 0x17, 0x00, 0x00, 0x88, 0x17, 0x00, ++ 0x00, 0x02, 0x32, 0x40, 0x04, 0x02, 0x32, 0x40, 0x08, 0x02, 0x32, 0x40, ++ 0x0C, 0x02, 0x32, 0x40, 0x64, 0x00, 0x32, 0x40, 0x1C, 0x9E, 0x17, 0x00, ++ 0x98, 0x9C, 0x17, 0x00, 0x20, 0x00, 0x32, 0x40, 0x70, 0x80, 0x32, 0x40, ++ 0x01, 0x00, 0x04, 0x00, 0x60, 0x00, 0x32, 0x40, 0x68, 0x65, 0x17, 0x00, ++ 0xF0, 0x9E, 0x15, 0x00, 0x29, 0x4A, 0x11, 0x6A, 0xB1, 0x42, 0x7F, 0xF4, ++ 0x3B, 0xAF, 0x13, 0x62, 0x82, 0xF8, 0x24, 0x30, 0x03, 0x9B, 0xD3, 0xF8, ++ 0x64, 0x32, 0x98, 0x47, 0xAA, 0x78, 0xCC, 0xE5, 0xDF, 0xF8, 0x88, 0xB0, ++ 0xDB, 0xF8, 0x20, 0x20, 0x00, 0x2A, 0x7F, 0xF4, 0x2B, 0xAF, 0x94, 0xF8, ++ 0x6C, 0x30, 0x1F, 0x48, 0x1F, 0x49, 0xCB, 0xF8, 0x20, 0x40, 0x4F, 0xF4, ++ 0x1E, 0x7C, 0x0C, 0xFB, 0x03, 0x03, 0x08, 0x68, 0x9B, 0x68, 0x02, 0x92, ++ 0x00, 0x0C, 0x00, 0x04, 0xC3, 0xF3, 0x8F, 0x23, 0x03, 0x43, 0x0B, 0x60, ++ 0x03, 0x9B, 0x04, 0xF1, 0x18, 0x00, 0xD3, 0xF8, 0xD8, 0x31, 0x98, 0x47, ++ 0x03, 0x9B, 0x02, 0x9A, 0x8B, 0xF8, 0x24, 0x20, 0xD3, 0xF8, 0x60, 0x32, ++ 0xDF, 0xF8, 0x50, 0xB0, 0x98, 0x47, 0x11, 0x49, 0xDF, 0xF8, 0x4C, 0xC0, ++ 0x10, 0x48, 0xD4, 0xF8, 0x38, 0xE0, 0xA4, 0x8F, 0xD1, 0xE9, 0x00, 0x23, ++ 0x23, 0xF0, 0x10, 0x03, 0x1A, 0x43, 0x4B, 0x60, 0xCB, 0xF8, 0x00, 0x20, ++ 0xCC, 0xF8, 0x00, 0xE0, 0x04, 0x60, 0xAA, 0x78, 0x8F, 0xE5, 0x01, 0x2B, ++ 0x7F, 0xF4, 0xF2, 0xAE, 0xE1, 0xE6, 0x00, 0x23, 0x93, 0xF8, 0x6C, 0x30, ++ 0xFF, 0xDE, 0x00, 0xBF, 0x1C, 0x9E, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, ++ 0x64, 0x00, 0x32, 0x40, 0x98, 0x9C, 0x17, 0x00, 0x24, 0x00, 0x32, 0x40, ++ 0x60, 0x00, 0x32, 0x40, 0x20, 0x00, 0x32, 0x40, 0x38, 0xB5, 0x07, 0x20, ++ 0x0C, 0x46, 0x19, 0x46, 0x02, 0x23, 0x08, 0xF0, 0x7F, 0xF8, 0x23, 0x46, ++ 0x07, 0x4D, 0x13, 0xF8, 0x02, 0x1B, 0x22, 0x7A, 0xD5, 0xF8, 0x58, 0x54, ++ 0x04, 0x46, 0x18, 0x46, 0x63, 0x1C, 0xA8, 0x47, 0x20, 0x70, 0x20, 0x46, ++ 0x08, 0xF0, 0xA0, 0xF8, 0x00, 0x20, 0x38, 0xBD, 0x88, 0x1A, 0x17, 0x00, ++ 0x00, 0xB5, 0x08, 0x78, 0x03, 0x28, 0x83, 0xB0, 0x19, 0x46, 0x07, 0xD8, ++ 0xCD, 0xE9, 0x00, 0x23, 0x0C, 0x4B, 0xD3, 0xF8, 0x64, 0x34, 0x98, 0x47, ++ 0xDD, 0xE9, 0x00, 0x21, 0x0A, 0x4B, 0x9B, 0x68, 0x33, 0xB1, 0x09, 0x20, ++ 0x08, 0xF0, 0xC0, 0xF8, 0x00, 0x20, 0x03, 0xB0, 0x5D, 0xF8, 0x04, 0xFB, ++ 0x04, 0x4B, 0xD3, 0xF8, 0xE8, 0x30, 0xCD, 0xE9, 0x00, 0x21, 0x98, 0x47, ++ 0xDD, 0xE9, 0x00, 0x21, 0xEF, 0xE7, 0x00, 0xBF, 0x88, 0x1A, 0x17, 0x00, ++ 0x00, 0x88, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x41, 0x0D, 0x78, 0x0C, 0x46, ++ 0x16, 0x46, 0x98, 0x46, 0x00, 0x2D, 0x3B, 0xD1, 0x91, 0xF8, 0x02, 0xC0, ++ 0x26, 0x49, 0x27, 0x4A, 0x11, 0xF8, 0x0C, 0x00, 0xE1, 0x78, 0x52, 0xF8, ++ 0x20, 0x20, 0x60, 0x78, 0x24, 0x4F, 0x25, 0x4B, 0x91, 0x42, 0xB8, 0xBF, ++ 0x4A, 0x08, 0x00, 0xEB, 0x80, 0x01, 0xC0, 0xEB, 0x01, 0x11, 0x61, 0x44, ++ 0x07, 0xEB, 0xC1, 0x01, 0x4F, 0xF0, 0x9E, 0x0E, 0x91, 0xF8, 0xA5, 0x11, ++ 0x0E, 0xFB, 0x00, 0xC0, 0xA8, 0xBF, 0x02, 0xEB, 0xD2, 0x72, 0x07, 0xEB, ++ 0x80, 0x00, 0xA8, 0xBF, 0xC2, 0xF3, 0x47, 0x02, 0x01, 0xEB, 0x41, 0x01, ++ 0x80, 0xF8, 0x5A, 0x21, 0x03, 0xEB, 0xC1, 0x01, 0xA2, 0x88, 0x0A, 0x81, ++ 0x32, 0x46, 0x41, 0x46, 0x03, 0x23, 0x29, 0x20, 0x08, 0xF0, 0x0C, 0xF8, ++ 0x62, 0x78, 0x02, 0x70, 0xA2, 0x78, 0x42, 0x70, 0x85, 0x70, 0x08, 0xF0, ++ 0x35, 0xF8, 0x00, 0x20, 0xBD, 0xE8, 0xF0, 0x81, 0x48, 0x78, 0x0B, 0x49, ++ 0xA2, 0x88, 0x4F, 0xF4, 0x1E, 0x75, 0x05, 0xFB, 0x00, 0x10, 0xA1, 0x78, ++ 0x14, 0xF0, 0xA0, 0xFB, 0x08, 0xB9, 0x04, 0x25, 0xE2, 0xE7, 0x07, 0x49, ++ 0x0A, 0x68, 0x42, 0xF0, 0x80, 0x02, 0x0A, 0x60, 0x00, 0x25, 0xDB, 0xE7, ++ 0xC0, 0xB2, 0x15, 0x00, 0x7C, 0x28, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, ++ 0xF4, 0xE4, 0x17, 0x00, 0x54, 0x00, 0x32, 0x40, 0x2D, 0xE9, 0xF0, 0x43, ++ 0x04, 0x46, 0x87, 0xB0, 0x10, 0x46, 0x15, 0x46, 0x0E, 0x46, 0x1F, 0x46, ++ 0x08, 0xF0, 0x7C, 0xFA, 0x40, 0xB1, 0x02, 0x38, 0x80, 0xB2, 0x02, 0x28, ++ 0x4D, 0xD8, 0x02, 0x24, 0x20, 0x46, 0x07, 0xB0, 0xBD, 0xE8, 0xF0, 0x83, ++ 0xDF, 0xF8, 0x88, 0x83, 0xD8, 0xF8, 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0x65, 0xDB, 0x3B, 0x2C, 0x00, 0xF2, 0xA7, 0x80, 0x05, 0x2C, ++ 0x40, 0xF2, 0xE3, 0x80, 0x06, 0x3C, 0x35, 0x2C, 0x4A, 0xD8, 0xDF, 0xE8, ++ 0x14, 0xF0, 0xBF, 0x01, 0x49, 0x00, 0xB5, 0x01, 0x49, 0x00, 0x49, 0x00, ++ 0x49, 0x00, 0x49, 0x00, 0x49, 0x00, 0x88, 0x01, 0x49, 0x00, 0x6E, 0x01, ++ 0x49, 0x00, 0x5A, 0x01, 0x49, 0x00, 0x50, 0x01, 0x49, 0x00, 0x3A, 0x01, ++ 0x49, 0x00, 0x30, 0x01, 0x49, 0x00, 0x49, 0x00, 0x49, 0x00, 0x1D, 0x01, ++ 0x49, 0x00, 0x13, 0x01, 0x49, 0x00, 0x00, 0x01, 0x49, 0x00, 0x49, 0x00, ++ 0x49, 0x00, 0x49, 0x00, 0x49, 0x00, 0x49, 0x00, 0x49, 0x00, 0xF6, 0x00, ++ 0x49, 0x00, 0x49, 0x00, 0x49, 0x00, 0x49, 0x00, 0x49, 0x00, 0x49, 0x00, ++ 0x49, 0x00, 0xEF, 0x00, 0x49, 0x00, 0x49, 0x00, 0x49, 0x00, 0x49, 0x00, ++ 0x49, 0x00, 0x49, 0x00, 0x49, 0x00, 0x49, 0x00, 0x49, 0x00, 0x49, 0x00, ++ 0xE2, 0x00, 0xB1, 0x4B, 0xB1, 0x4C, 0x1B, 0x68, 0x28, 0x46, 0x03, 0xF0, ++ 0x0F, 0x03, 0xE3, 0x74, 0x08, 0xF0, 0x20, 0xFA, 0xAE, 0x4B, 0xA0, 0x74, ++ 0xD3, 0xF8, 0xE0, 0x30, 0x98, 0x47, 0x28, 0x46, 0x02, 0x21, 0x08, 0xF0, ++ 0x6F, 0xF9, 0x9E, 0xE7, 0xDF, 0xF8, 0xA0, 0x82, 0x02, 0x24, 0x98, 0xF8, ++ 0x13, 0x30, 0xA5, 0x4A, 0x1B, 0x01, 0xDB, 0xB2, 0x13, 0x60, 0x28, 0x46, ++ 0x98, 0xF8, 0x12, 0x10, 0x08, 0xF0, 0x60, 0xF9, 0x20, 0x46, 0x07, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x83, 0x9E, 0x4B, 0x1B, 0x68, 0x1B, 0x07, 0x40, 0xF0, ++ 0x6F, 0x81, 0x3B, 0x2C, 0x67, 0xD8, 0x05, 0x2C, 0x67, 0xD9, 0x06, 0x3C, ++ 0x35, 0x2C, 0x64, 0xD8, 0xDF, 0xE8, 0x14, 0xF0, 0x56, 0x01, 0x63, 0x00, ++ 0x4C, 0x01, 0x63, 0x00, 0x63, 0x00, 0x63, 0x00, 0x63, 0x00, 0x63, 0x00, ++ 0x1F, 0x01, 0x63, 0x00, 0x05, 0x01, 0x63, 0x00, 0xF1, 0x00, 0x63, 0x00, ++ 0xE7, 0x00, 0x63, 0x00, 0xD1, 0x00, 0x63, 0x00, 0xC7, 0x00, 0x63, 0x00, ++ 0x63, 0x00, 0x63, 0x00, 0xB4, 0x00, 0x63, 0x00, 0xAA, 0x00, 0x63, 0x00, ++ 0x97, 0x00, 0x63, 0x00, 0x63, 0x00, 0x63, 0x00, 0x63, 0x00, 0x63, 0x00, ++ 0x63, 0x00, 0x63, 0x00, 0x8D, 0x00, 0x63, 0x00, 0x63, 0x00, 0x63, 0x00, ++ 0x63, 0x00, 0x63, 0x00, 0x63, 0x00, 0x63, 0x00, 0x86, 0x00, 0x63, 0x00, ++ 0x63, 0x00, 0x63, 0x00, 0x63, 0x00, 0x63, 0x00, 0x63, 0x00, 0x63, 0x00, ++ 0x63, 0x00, 0x63, 0x00, 0x63, 0x00, 0x79, 0x00, 0x87, 0x2C, 0x3C, 0xD1, ++ 0xDF, 0xF8, 0xF0, 0x81, 0xDF, 0xF8, 0xF0, 0x91, 0x00, 0x27, 0x88, 0xF8, ++ 0x30, 0x70, 0x30, 0x68, 0xD9, 0xF8, 0xF8, 0x30, 0x98, 0x47, 0x04, 0x46, ++ 0x00, 0x28, 0x40, 0xF0, 0x19, 0x81, 0x98, 0xF8, 0x31, 0x30, 0x00, 0x2B, ++ 0x97, 0xD0, 0x05, 0xA8, 0x88, 0xF8, 0x31, 0x40, 0x01, 0xF0, 0x74, 0xFD, ++ 0x00, 0x28, 0x90, 0xD0, 0x05, 0x9A, 0x71, 0x49, 0x92, 0xF8, 0x63, 0x30, ++ 0x92, 0xF8, 0xC1, 0x04, 0x03, 0xEB, 0xC3, 0x02, 0x03, 0xEB, 0x42, 0x03, ++ 0x01, 0xEB, 0x43, 0x01, 0x05, 0xF0, 0x9C, 0xFF, 0x81, 0xE7, 0x87, 0x2C, ++ 0xD4, 0xD0, 0x6A, 0x49, 0x6A, 0x48, 0xDF, 0xF8, 0x98, 0x81, 0x40, 0xF6, ++ 0x06, 0x22, 0x09, 0xF0, 0xCB, 0xFF, 0x02, 0x24, 0x75, 0xE7, 0x87, 0x2C, ++ 0xC8, 0xD0, 0xD8, 0xF8, 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0xED, 0xDB, 0xDF, 0xF8, 0x78, 0x81, 0x02, 0x24, 0x69, 0xE7, 0x5D, 0x4B, ++ 0xDF, 0xF8, 0x6C, 0x81, 0x9B, 0x6D, 0x30, 0x46, 0x98, 0x47, 0x2A, 0x46, ++ 0x39, 0x46, 0x3C, 0x20, 0x07, 0xF0, 0x38, 0xFF, 0x00, 0x24, 0x5C, 0xE7, ++ 0x30, 0x46, 0x09, 0xF0, 0xD3, 0xFF, 0xDF, 0xF8, 0x50, 0x81, 0x00, 0x24, ++ 0x55, 0xE7, 0x3B, 0x46, 0x31, 0x46, 0x2A, 0x46, 0x28, 0x20, 0xFF, 0xF7, ++ 0x7B, 0xFE, 0xDF, 0xF8, 0x3C, 0x81, 0x04, 0x46, 0x4B, 0xE7, 0x52, 0x4B, ++ 0x32, 0x78, 0x1B, 0x68, 0x51, 0x48, 0xDF, 0xF8, 0x2C, 0x81, 0xDB, 0xB2, ++ 0x03, 0xFB, 0x02, 0xF3, 0x42, 0xEA, 0x03, 0x23, 0x03, 0x60, 0x39, 0x46, ++ 0x2A, 0x46, 0x21, 0x20, 0x07, 0xF0, 0x14, 0xFF, 0x00, 0x24, 0x38, 0xE7, ++ 0x3B, 0x46, 0x31, 0x46, 0x2A, 0x46, 0x1E, 0x20, 0xFF, 0xF7, 0xD4, 0xFA, ++ 0xDF, 0xF8, 0x00, 0x81, 0x04, 0x46, 0x2E, 0xE7, 0x45, 0x48, 0x33, 0x78, ++ 0x02, 0x68, 0xDF, 0xF8, 0xF4, 0x80, 0x9B, 0x03, 0x22, 0xF4, 0xE0, 0x32, ++ 0x03, 0xF4, 0xE0, 0x33, 0x13, 0x43, 0x03, 0x60, 0x39, 0x46, 0x2A, 0x46, ++ 0x1D, 0x20, 0x07, 0xF0, 0xF7, 0xFE, 0x00, 0x24, 0x1B, 0xE7, 0x3B, 0x46, ++ 0x31, 0x46, 0x2A, 0x46, 0x18, 0x20, 0xFF, 0xF7, 0x77, 0xFA, 0xDF, 0xF8, ++ 0xC8, 0x80, 0x04, 0x46, 0x11, 0xE7, 0x73, 0x79, 0xDF, 0xF8, 0xBC, 0x80, ++ 0x36, 0x4A, 0x31, 0x68, 0x92, 0x6A, 0x08, 0xEB, 0x83, 0x00, 0x41, 0x61, ++ 0x22, 0xB1, 0x12, 0x79, 0x9A, 0x42, 0x04, 0xBF, 0x32, 0x4B, 0x19, 0x60, ++ 0x39, 0x46, 0x2A, 0x46, 0x17, 0x20, 0x07, 0xF0, 0xD7, 0xFE, 0x00, 0x24, ++ 0xFB, 0xE6, 0x3B, 0x46, 0x31, 0x46, 0x2A, 0x46, 0x14, 0x20, 0xFF, 0xF7, ++ 0x2B, 0xFA, 0xDF, 0xF8, 0x88, 0x80, 0x04, 0x46, 0xF1, 0xE6, 0x2A, 0x4A, ++ 0x31, 0x78, 0x13, 0x68, 0xDF, 0xF8, 0x78, 0x80, 0x23, 0xF0, 0xFF, 0x03, ++ 0x0B, 0x43, 0x13, 0x60, 0x13, 0x68, 0x43, 0xF0, 0x00, 0x43, 0x13, 0x60, ++ 0x39, 0x46, 0x2A, 0x46, 0x13, 0x20, 0x07, 0xF0, 0xB9, 0xFE, 0x00, 0x24, ++ 0xDD, 0xE6, 0x39, 0x46, 0x02, 0x23, 0x2A, 0x46, 0x11, 0x20, 0x07, 0xF0, ++ 0x49, 0xFE, 0x72, 0x7A, 0xF3, 0x88, 0xB1, 0x7A, 0x02, 0x91, 0xCD, 0xE9, ++ 0x00, 0x32, 0x04, 0x46, 0xB3, 0x88, 0x72, 0x88, 0x71, 0x78, 0x30, 0x78, ++ 0xDF, 0xF8, 0x34, 0x80, 0xE6, 0xF7, 0x1E, 0xFA, 0x20, 0x46, 0x07, 0xF0, ++ 0x67, 0xFE, 0x00, 0x24, 0xC3, 0xE6, 0xDF, 0xF8, 0x24, 0x80, 0x33, 0x68, ++ 0xD8, 0xF8, 0x04, 0x10, 0x11, 0x4A, 0xC8, 0xF8, 0x00, 0x30, 0x0B, 0x43, ++ 0x13, 0x60, 0x39, 0x46, 0x2A, 0x46, 0x0F, 0x20, 0x07, 0xF0, 0x8E, 0xFE, ++ 0x00, 0x24, 0xB2, 0xE6, 0x38, 0x00, 0x32, 0x40, 0x98, 0x9C, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x64, 0x3E, 0x18, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x64, 0x7D, 0x15, 0x00, 0xE4, 0x00, 0x32, 0x40, 0xE8, 0x00, 0x32, 0x40, ++ 0x4C, 0x00, 0x32, 0x40, 0x30, 0x9D, 0x17, 0x00, 0xDC, 0x00, 0x32, 0x40, ++ 0x90, 0x00, 0x32, 0x40, 0x60, 0x00, 0x32, 0x40, 0x38, 0x36, 0x17, 0x00, ++ 0x3B, 0x46, 0x31, 0x46, 0x2A, 0x46, 0x08, 0x20, 0xFF, 0xF7, 0x96, 0xFD, ++ 0xDF, 0xF8, 0x2C, 0x81, 0x04, 0x46, 0x8C, 0xE6, 0x3B, 0x46, 0x31, 0x46, ++ 0x2A, 0x46, 0x06, 0x20, 0xFF, 0xF7, 0x72, 0xFD, 0xDF, 0xF8, 0x18, 0x81, ++ 0x04, 0x46, 0x82, 0xE6, 0xD9, 0xF8, 0x6C, 0x31, 0x30, 0x68, 0x98, 0x47, ++ 0x3C, 0x46, 0x7C, 0xE6, 0x3F, 0x49, 0x40, 0x48, 0x40, 0xF6, 0xC9, 0x12, ++ 0x09, 0xF0, 0xCA, 0xFE, 0x3B, 0x2C, 0x3F, 0xF6, 0xFE, 0xAE, 0x05, 0x2C, ++ 0x7F, 0xF6, 0xFD, 0xAE, 0x06, 0x3C, 0x35, 0x2C, 0x3F, 0xF6, 0xF9, 0xAE, ++ 0x01, 0xA3, 0x53, 0xF8, 0x24, 0xF0, 0x00, 0xBF, 0xBD, 0xAD, 0x13, 0x00, ++ 0xEF, 0xAB, 0x13, 0x00, 0xA9, 0xAD, 0x13, 0x00, 0xEF, 0xAB, 0x13, 0x00, ++ 0xEF, 0xAB, 0x13, 0x00, 0xEF, 0xAB, 0x13, 0x00, 0xEF, 0xAB, 0x13, 0x00, ++ 0xEF, 0xAB, 0x13, 0x00, 0x4F, 0xAD, 0x13, 0x00, 0xEF, 0xAB, 0x13, 0x00, ++ 0x1B, 0xAD, 0x13, 0x00, 0xEF, 0xAB, 0x13, 0x00, 0xF3, 0xAC, 0x13, 0x00, ++ 0xEF, 0xAB, 0x13, 0x00, 0xDF, 0xAC, 0x13, 0x00, 0xEF, 0xAB, 0x13, 0x00, ++ 0xB3, 0xAC, 0x13, 0x00, 0xEF, 0xAB, 0x13, 0x00, 0x9F, 0xAC, 0x13, 0x00, ++ 0xEF, 0xAB, 0x13, 0x00, 0xEF, 0xAB, 0x13, 0x00, 0xEF, 0xAB, 0x13, 0x00, ++ 0x79, 0xAC, 0x13, 0x00, 0xEF, 0xAB, 0x13, 0x00, 0x65, 0xAC, 0x13, 0x00, ++ 0xEF, 0xAB, 0x13, 0x00, 0x3F, 0xAC, 0x13, 0x00, 0xEF, 0xAB, 0x13, 0x00, ++ 0xEF, 0xAB, 0x13, 0x00, 0xEF, 0xAB, 0x13, 0x00, 0xEF, 0xAB, 0x13, 0x00, ++ 0xEF, 0xAB, 0x13, 0x00, 0xEF, 0xAB, 0x13, 0x00, 0xEF, 0xAB, 0x13, 0x00, ++ 0x2B, 0xAC, 0x13, 0x00, 0xEF, 0xAB, 0x13, 0x00, 0xEF, 0xAB, 0x13, 0x00, ++ 0xEF, 0xAB, 0x13, 0x00, 0xEF, 0xAB, 0x13, 0x00, 0xEF, 0xAB, 0x13, 0x00, ++ 0xEF, 0xAB, 0x13, 0x00, 0xEF, 0xAB, 0x13, 0x00, 0x1D, 0xAC, 0x13, 0x00, ++ 0xEF, 0xAB, 0x13, 0x00, 0xEF, 0xAB, 0x13, 0x00, 0xEF, 0xAB, 0x13, 0x00, ++ 0xEF, 0xAB, 0x13, 0x00, 0xEF, 0xAB, 0x13, 0x00, 0xEF, 0xAB, 0x13, 0x00, ++ 0xEF, 0xAB, 0x13, 0x00, 0xEF, 0xAB, 0x13, 0x00, 0xEF, 0xAB, 0x13, 0x00, ++ 0xEF, 0xAB, 0x13, 0x00, 0x03, 0xAC, 0x13, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x84, 0x9E, 0x15, 0x00, 0x98, 0x9C, 0x17, 0x00, 0xC0, 0x68, 0xCB, 0x68, ++ 0xC0, 0x1A, 0xC0, 0x0F, 0x70, 0x47, 0x00, 0xBF, 0x01, 0x48, 0x08, 0xF0, ++ 0xE9, 0xB9, 0x00, 0xBF, 0xD0, 0x9C, 0x17, 0x00, 0x06, 0x4B, 0x38, 0xB1, ++ 0xC1, 0x68, 0x04, 0x22, 0x4F, 0xF4, 0x80, 0x20, 0x98, 0x60, 0x19, 0x63, ++ 0x9A, 0x60, 0x70, 0x47, 0x4F, 0xF4, 0x80, 0x62, 0x9A, 0x60, 0x70, 0x47, ++ 0x00, 0x10, 0x50, 0x40, 0x33, 0x4A, 0xF8, 0xB5, 0x13, 0x69, 0xCB, 0x1A, ++ 0x00, 0x2B, 0x0C, 0x46, 0x05, 0x46, 0x57, 0xDB, 0x30, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x46, 0xDB, 0xEF, 0xF3, 0x10, 0x83, ++ 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x2C, 0x4B, 0x01, 0x22, 0x1A, 0x60, ++ 0x2B, 0x4F, 0x2C, 0x4E, 0x3B, 0x68, 0x32, 0x68, 0x01, 0x33, 0x95, 0x42, ++ 0x3B, 0x60, 0x19, 0xD0, 0x29, 0x46, 0x30, 0x46, 0x08, 0xF0, 0x08, 0xFA, ++ 0x30, 0x46, 0x27, 0x4A, 0xEC, 0x60, 0x29, 0x46, 0x08, 0xF0, 0x40, 0xFA, ++ 0x30, 0x68, 0x85, 0x42, 0x16, 0xD0, 0x3B, 0x68, 0x23, 0xB1, 0x1F, 0x4A, ++ 0x01, 0x3B, 0x12, 0x68, 0x3B, 0x60, 0xA3, 0xB1, 0x1A, 0x4B, 0x19, 0x69, ++ 0x64, 0x1A, 0x00, 0x2C, 0x17, 0xDB, 0xF8, 0xBD, 0x30, 0x46, 0x08, 0xF0, ++ 0xE3, 0xF9, 0x30, 0x46, 0x1A, 0x4A, 0xEC, 0x60, 0x29, 0x46, 0x08, 0xF0, ++ 0x27, 0xFA, 0x30, 0x68, 0x18, 0x4B, 0xD3, 0xF8, 0xDC, 0x31, 0x98, 0x47, ++ 0xE3, 0xE7, 0x00, 0x2A, 0xE8, 0xD0, 0x62, 0xB6, 0x0E, 0x4B, 0x19, 0x69, ++ 0x64, 0x1A, 0x00, 0x2C, 0xE7, 0xDA, 0xBD, 0xE8, 0xF8, 0x40, 0x4F, 0xF0, ++ 0x80, 0x40, 0x08, 0xF0, 0xE3, 0xB8, 0x09, 0x4B, 0x1B, 0x69, 0xE3, 0x1A, ++ 0x00, 0x2B, 0xB3, 0xDA, 0x0D, 0x49, 0x0E, 0x48, 0x7D, 0x22, 0x09, 0xF0, ++ 0xCF, 0xFD, 0xAD, 0xE7, 0x13, 0x69, 0x41, 0x68, 0x0B, 0x48, 0x22, 0x46, ++ 0x09, 0xF0, 0x4E, 0xFB, 0xA0, 0xE7, 0x00, 0xBF, 0x00, 0x10, 0x50, 0x40, ++ 0x38, 0x36, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0xD0, 0x9C, 0x17, 0x00, 0xE9, 0xAE, 0x13, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x74, 0x9F, 0x15, 0x00, 0x4C, 0x9F, 0x15, 0x00, ++ 0x38, 0xB5, 0x01, 0x46, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, ++ 0x72, 0xB6, 0x10, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x0F, 0x4C, 0x10, 0x4D, ++ 0x23, 0x68, 0x2A, 0x68, 0x01, 0x33, 0x8A, 0x42, 0x23, 0x60, 0x28, 0x46, ++ 0x0B, 0xD0, 0x08, 0xF0, 0x99, 0xF9, 0x23, 0x68, 0x33, 0xB1, 0x08, 0x4A, ++ 0x01, 0x3B, 0x12, 0x68, 0x23, 0x60, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, ++ 0x38, 0xBD, 0x08, 0xF0, 0x81, 0xF9, 0x06, 0x4B, 0x28, 0x68, 0xD3, 0xF8, ++ 0xDC, 0x31, 0x98, 0x47, 0xED, 0xE7, 0x00, 0xBF, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0xD0, 0x9C, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x47, 0x2C, 0x4F, 0x2D, 0x4D, 0xDF, 0xF8, 0xC8, 0xA0, ++ 0xDF, 0xF8, 0xC0, 0x80, 0x2B, 0x4E, 0xB9, 0x46, 0x01, 0xE0, 0xA0, 0x68, ++ 0x98, 0x47, 0x4F, 0xF0, 0x80, 0x40, 0x08, 0xF0, 0x9F, 0xF8, 0xEF, 0xF3, ++ 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x01, 0x23, 0xC8, 0xF8, ++ 0x00, 0x30, 0x2B, 0x68, 0x3C, 0x68, 0x01, 0x33, 0x2B, 0x60, 0x4C, 0xB3, ++ 0x32, 0x69, 0xE3, 0x68, 0x9B, 0x1A, 0x32, 0x2B, 0x08, 0xD4, 0xDA, 0xF8, ++ 0xDC, 0x31, 0x20, 0x46, 0x98, 0x47, 0x32, 0x69, 0xE3, 0x68, 0x9B, 0x1A, ++ 0x00, 0x2B, 0x2A, 0xDA, 0x48, 0x46, 0x08, 0xF0, 0x43, 0xF9, 0x2B, 0x68, ++ 0x33, 0xB1, 0x01, 0x3B, 0xD8, 0xF8, 0x00, 0x20, 0x2B, 0x60, 0x0B, 0xB9, ++ 0x02, 0xB1, 0x62, 0xB6, 0x14, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0x63, 0x68, 0xCB, 0xDA, 0x00, 0x2B, 0xC9, 0xD1, 0x11, 0x49, ++ 0x11, 0x48, 0xEB, 0x22, 0x09, 0xF0, 0x3C, 0xFD, 0x63, 0x68, 0xC2, 0xE7, ++ 0xDA, 0xF8, 0xDC, 0x31, 0x20, 0x46, 0x98, 0x47, 0x2B, 0x68, 0x33, 0xB1, ++ 0x0C, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x2B, 0x60, 0x0B, 0xB9, 0x02, 0xB1, ++ 0x62, 0xB6, 0xBD, 0xE8, 0xF0, 0x87, 0x2B, 0x68, 0x00, 0x2B, 0xFA, 0xD0, ++ 0xF2, 0xE7, 0x00, 0xBF, 0xD0, 0x9C, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x00, 0x10, 0x50, 0x40, 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x90, 0x9F, 0x15, 0x00, 0x38, 0x61, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x70, 0xB5, 0x11, 0xF4, 0x00, 0x05, 0x04, 0x46, 0x0E, 0xD1, 0x90, 0xF8, ++ 0x5C, 0x22, 0x1E, 0x49, 0x1E, 0x48, 0x01, 0x32, 0xD2, 0xB2, 0x84, 0xF8, ++ 0x5C, 0x22, 0x09, 0xF0, 0x8D, 0xFA, 0x94, 0xF8, 0x5C, 0x32, 0x09, 0x2B, ++ 0x15, 0xD8, 0x70, 0xBD, 0x17, 0x49, 0x19, 0x48, 0x09, 0xF0, 0x84, 0xFA, ++ 0x94, 0xF8, 0x23, 0x30, 0x00, 0x22, 0x0D, 0x2B, 0x84, 0xF8, 0x5C, 0x22, ++ 0xF3, 0xD8, 0x15, 0x49, 0x15, 0x4A, 0x4F, 0xF4, 0x1E, 0x70, 0x00, 0xFB, ++ 0x03, 0x13, 0x12, 0x69, 0xC3, 0xF8, 0x58, 0x22, 0x70, 0xBD, 0x2A, 0x46, ++ 0x08, 0x23, 0x0C, 0x21, 0x7D, 0x20, 0x07, 0xF0, 0x05, 0xFC, 0x94, 0xF8, ++ 0x23, 0x30, 0x03, 0x70, 0x94, 0xF8, 0x22, 0x30, 0x43, 0x70, 0x06, 0x46, ++ 0x04, 0xF1, 0x26, 0x01, 0x84, 0xF8, 0x5C, 0x52, 0x02, 0x30, 0x06, 0x22, ++ 0x1B, 0xF0, 0x7E, 0xFF, 0x30, 0x46, 0xBD, 0xE8, 0x70, 0x40, 0x07, 0xF0, ++ 0x21, 0xBC, 0x00, 0xBF, 0x34, 0xA0, 0x15, 0x00, 0x9C, 0x9F, 0x15, 0x00, ++ 0xB4, 0x9F, 0x15, 0x00, 0x68, 0x65, 0x17, 0x00, 0x00, 0x10, 0x50, 0x40, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0x90, 0xF8, 0x63, 0x30, 0x63, 0x4A, 0x4F, 0xF4, ++ 0x1E, 0x74, 0x0A, 0x33, 0x04, 0xFB, 0x03, 0xF3, 0x11, 0x46, 0x02, 0xF1, ++ 0x28, 0x04, 0x1C, 0x44, 0x1A, 0x44, 0x83, 0xB0, 0x0B, 0x46, 0xD2, 0xF8, ++ 0x08, 0x12, 0x00, 0x29, 0x40, 0xF0, 0xA2, 0x80, 0xD2, 0xF8, 0x30, 0x12, ++ 0x08, 0x32, 0x00, 0x29, 0x40, 0xF0, 0x9C, 0x80, 0xA2, 0x42, 0xF2, 0xD1, ++ 0x57, 0x4A, 0x58, 0x4C, 0xDF, 0xF8, 0x70, 0xB1, 0x4F, 0xF4, 0xA4, 0x61, ++ 0x93, 0xF8, 0x25, 0x60, 0x2E, 0xB1, 0x93, 0xF8, 0x22, 0x60, 0x01, 0xFB, ++ 0x06, 0x46, 0xB0, 0x42, 0x06, 0xD0, 0x03, 0xF5, 0x1E, 0x73, 0x9A, 0x42, ++ 0xF2, 0xD1, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x93, 0xF8, 0x23, 0x60, ++ 0x0D, 0x2E, 0x77, 0xD9, 0x4F, 0xF0, 0x00, 0x08, 0xDB, 0xF8, 0x10, 0xE0, ++ 0x1E, 0x46, 0x03, 0xF1, 0x28, 0x0C, 0xD6, 0xF8, 0x08, 0x72, 0x77, 0xB9, ++ 0xD6, 0xF8, 0x30, 0x72, 0x08, 0x36, 0x57, 0xB9, 0xB4, 0x45, 0xF6, 0xD1, ++ 0xCE, 0xF5, 0x64, 0x0E, 0x0E, 0xF5, 0x61, 0x4E, 0x0E, 0xF1, 0xC0, 0x0E, ++ 0x1E, 0xEB, 0x08, 0x0F, 0xDB, 0xD5, 0x90, 0xF8, 0x63, 0x60, 0x93, 0xF8, ++ 0x20, 0xE0, 0x00, 0x96, 0x35, 0x46, 0xC6, 0xEB, 0x86, 0x17, 0x3C, 0x4E, ++ 0x4F, 0xEA, 0xDE, 0x08, 0x06, 0xEB, 0x87, 0x07, 0x0E, 0xF0, 0x07, 0x0C, ++ 0x01, 0x26, 0x18, 0xF8, 0x07, 0x90, 0x06, 0xFA, 0x0C, 0xFC, 0x1C, 0xEA, ++ 0x09, 0x0F, 0x07, 0xEB, 0xDE, 0x06, 0x01, 0x96, 0x5F, 0xFA, 0x8C, 0xFA, ++ 0x0F, 0xFA, 0x85, 0xFE, 0xBD, 0xD1, 0x4A, 0xEA, 0x09, 0x09, 0x08, 0xF8, ++ 0x07, 0x90, 0xB0, 0xF8, 0xD0, 0x90, 0x90, 0xF8, 0xD8, 0xC0, 0x09, 0xF1, ++ 0x01, 0x09, 0xC4, 0x45, 0xA0, 0xF8, 0xD0, 0x90, 0x3E, 0xD8, 0xAF, 0x00, ++ 0x90, 0xF8, 0xD9, 0x90, 0xC1, 0x45, 0x0B, 0xD2, 0x00, 0x9D, 0x28, 0x4E, ++ 0x80, 0xF8, 0xD9, 0x80, 0x07, 0xEB, 0x05, 0x0A, 0x06, 0xEB, 0xCA, 0x0A, ++ 0x01, 0x9E, 0xCA, 0xF8, 0x20, 0x60, 0xC1, 0x46, 0x23, 0x4E, 0x00, 0x9D, ++ 0xCC, 0xF1, 0x06, 0x0C, 0xCC, 0x44, 0x06, 0xEB, 0xCE, 0x0E, 0x1F, 0xFA, ++ 0x8C, 0xFC, 0x1E, 0x4E, 0xA0, 0xF8, 0xCE, 0xC0, 0xAC, 0xF1, 0x02, 0x08, ++ 0x8E, 0xF8, 0x01, 0x80, 0x4F, 0xF0, 0x28, 0x0C, 0x2F, 0x44, 0x06, 0xEB, ++ 0xC7, 0x07, 0x0C, 0xFB, 0x05, 0x66, 0x90, 0xF8, 0xD8, 0xC0, 0x8E, 0xF8, ++ 0x04, 0xC0, 0x14, 0x36, 0x0E, 0xF1, 0x04, 0x0E, 0xC7, 0xF8, 0x0C, 0xE0, ++ 0x7E, 0x60, 0x7C, 0xE7, 0x0D, 0x4D, 0x4F, 0xF4, 0x1E, 0x77, 0x07, 0xFB, ++ 0x06, 0x56, 0xD6, 0xF8, 0x58, 0x82, 0x81, 0xE7, 0x0F, 0x4A, 0x01, 0x21, ++ 0x11, 0x70, 0x61, 0xE7, 0x00, 0x9D, 0x0B, 0x4E, 0x05, 0xEB, 0x85, 0x09, ++ 0x08, 0xF0, 0x1E, 0x0C, 0x06, 0xEB, 0xC9, 0x09, 0x67, 0x44, 0x80, 0xF8, ++ 0xD8, 0xC0, 0xC9, 0xF8, 0x1C, 0x70, 0xAF, 0x00, 0xB2, 0xE7, 0x00, 0xBF, ++ 0x68, 0x65, 0x17, 0x00, 0x18, 0x7E, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0x3C, 0x4C, 0x18, 0x00, 0x9C, 0x4B, 0x18, 0x00, 0x2C, 0x50, 0x18, 0x00, ++ 0x16, 0x2C, 0x17, 0x00, 0x00, 0x10, 0x50, 0x40, 0x2D, 0xE9, 0xF8, 0x43, ++ 0x02, 0x88, 0xC3, 0x78, 0x04, 0x46, 0xB2, 0xB9, 0x82, 0x78, 0x00, 0x2A, ++ 0x40, 0xF0, 0xAD, 0x80, 0x88, 0x48, 0x4F, 0xF4, 0xA4, 0x61, 0x01, 0xFB, ++ 0x03, 0x03, 0x83, 0xF8, 0xDA, 0x20, 0x34, 0xF8, 0x04, 0x1C, 0x42, 0x20, ++ 0x00, 0x22, 0x07, 0xF0, 0x5B, 0xFB, 0xA4, 0xF1, 0x0C, 0x00, 0xBD, 0xE8, ++ 0xF8, 0x43, 0x07, 0xF0, 0x69, 0xBB, 0x80, 0x48, 0x80, 0x4D, 0x94, 0xF8, ++ 0x02, 0xE0, 0xC3, 0xEB, 0x83, 0x11, 0x00, 0xEB, 0x81, 0x00, 0x01, 0x26, ++ 0xC2, 0xF3, 0xC7, 0x01, 0x02, 0xF0, 0x07, 0x02, 0x06, 0xFA, 0x02, 0xF2, ++ 0x0F, 0x5C, 0x0E, 0x18, 0x5F, 0xFA, 0x82, 0xFC, 0x05, 0xEB, 0xC3, 0x05, ++ 0xBE, 0xF1, 0x00, 0x0F, 0x4D, 0xD0, 0x1C, 0xEA, 0x07, 0x0F, 0xD8, 0xD1, ++ 0xDF, 0xF8, 0xC4, 0xE1, 0x4F, 0xF4, 0xA4, 0x62, 0x4C, 0xEA, 0x07, 0x07, ++ 0x02, 0xFB, 0x03, 0xE2, 0x37, 0x70, 0xB2, 0xF8, 0xD0, 0x70, 0x92, 0xF8, ++ 0xD8, 0xC0, 0x01, 0x37, 0x8C, 0x45, 0xA2, 0xF8, 0xD0, 0x70, 0x6C, 0x4F, ++ 0x0A, 0xD9, 0x03, 0xEB, 0x83, 0x0C, 0x01, 0xF0, 0xFE, 0x08, 0x07, 0xEB, ++ 0xCC, 0x0C, 0x40, 0x44, 0xCC, 0xF8, 0x1C, 0x00, 0x82, 0xF8, 0xD8, 0x80, ++ 0x4F, 0xF4, 0xA4, 0x60, 0x00, 0xFB, 0x03, 0xE0, 0x4F, 0xEA, 0x83, 0x0C, ++ 0x90, 0xF8, 0xD9, 0x80, 0x88, 0x45, 0x07, 0xD2, 0x0C, 0xEB, 0x03, 0x02, ++ 0x07, 0xEB, 0xC2, 0x02, 0x80, 0xF8, 0xD9, 0x10, 0x88, 0x46, 0x16, 0x62, ++ 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, 0x03, 0xEE, 0x0C, 0xEB, 0x03, 0x01, ++ 0x9E, 0xF8, 0xD8, 0x20, 0x2A, 0x71, 0xC2, 0xF1, 0x06, 0x02, 0x28, 0x20, ++ 0x42, 0x44, 0x07, 0xEB, 0xC1, 0x01, 0x00, 0xFB, 0x03, 0x73, 0x92, 0xB2, ++ 0x2E, 0x1D, 0x14, 0x33, 0x90, 0x1E, 0xCE, 0x60, 0x4B, 0x60, 0xAE, 0xF8, ++ 0xCE, 0x20, 0x68, 0x70, 0x8D, 0xE7, 0x1C, 0xEA, 0x07, 0x0F, 0x8A, 0xD0, ++ 0xDF, 0xF8, 0x28, 0xE1, 0x4F, 0xF4, 0xA4, 0x68, 0x08, 0xFB, 0x03, 0xF8, ++ 0x27, 0xEA, 0x02, 0x02, 0x0E, 0xEB, 0x08, 0x0C, 0x32, 0x70, 0xBC, 0xF8, ++ 0xD0, 0x70, 0x01, 0x3F, 0xBF, 0xB2, 0xAC, 0xF8, 0xD0, 0x70, 0x00, 0x2F, ++ 0x4D, 0xD0, 0x9C, 0xF8, 0xD8, 0x70, 0x01, 0xF0, 0xFE, 0x02, 0x97, 0x42, ++ 0x29, 0xD0, 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, 0x03, 0xE2, 0x92, 0xF8, ++ 0xD9, 0x70, 0x8F, 0x42, 0x35, 0xD0, 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, ++ 0x03, 0xE3, 0x93, 0xF8, 0xD8, 0x10, 0x29, 0x71, 0xC1, 0xF1, 0x06, 0x01, ++ 0x39, 0x44, 0x89, 0xB2, 0x8A, 0x1E, 0xA3, 0xF8, 0xCE, 0x10, 0x6A, 0x70, ++ 0x59, 0xE7, 0x32, 0x49, 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, 0x03, 0x13, ++ 0x01, 0x22, 0x83, 0xF8, 0xDA, 0x20, 0x50, 0xE7, 0x3A, 0x5C, 0x07, 0xF1, ++ 0x01, 0x08, 0x00, 0x2A, 0x51, 0xD1, 0x5F, 0xFA, 0x88, 0xF7, 0x8C, 0xF8, ++ 0xD8, 0x70, 0xFB, 0x2F, 0xF4, 0xD1, 0xFA, 0x22, 0x17, 0x46, 0xDF, 0xF8, ++ 0xA8, 0x90, 0x03, 0xEB, 0x83, 0x08, 0x4F, 0xF4, 0xA4, 0x6C, 0x09, 0xEB, ++ 0xC8, 0x08, 0x0C, 0xFB, 0x03, 0xEC, 0x02, 0x44, 0xC8, 0xF8, 0x1C, 0x20, ++ 0x8C, 0xF8, 0xD8, 0x70, 0xC1, 0xE7, 0x41, 0xB3, 0x37, 0x78, 0x01, 0x39, ++ 0xB4, 0x46, 0xC9, 0xB2, 0x01, 0x3E, 0x57, 0xBB, 0x82, 0xF8, 0xD9, 0x10, ++ 0xF5, 0xE7, 0x0E, 0xF1, 0xD8, 0x02, 0x06, 0x21, 0xAC, 0xF8, 0xCE, 0x10, ++ 0xFF, 0x21, 0x28, 0xF8, 0x02, 0x10, 0x19, 0x4A, 0x9C, 0xF8, 0xCE, 0x10, ++ 0x2F, 0x71, 0x03, 0xEB, 0x83, 0x03, 0x02, 0xEB, 0xC3, 0x03, 0x6E, 0x1D, ++ 0x8A, 0x1E, 0xDE, 0x60, 0x6A, 0x70, 0xE2, 0x78, 0x9C, 0xF8, 0xD9, 0x50, ++ 0x12, 0x49, 0x02, 0xEB, 0x82, 0x02, 0x28, 0x44, 0x01, 0xEB, 0x82, 0x02, ++ 0x18, 0x62, 0x5A, 0x60, 0x09, 0xE7, 0x0F, 0x46, 0x0C, 0x4A, 0x03, 0xEB, ++ 0x83, 0x01, 0x02, 0xEB, 0xC1, 0x02, 0x10, 0x62, 0x97, 0xE7, 0x4F, 0xF4, ++ 0xA4, 0x62, 0x02, 0xFB, 0x03, 0xE2, 0x60, 0x46, 0x92, 0xF8, 0xD9, 0x70, ++ 0xF0, 0xE7, 0x07, 0xF0, 0xFE, 0x07, 0x3A, 0x46, 0xB1, 0xE7, 0x00, 0xBF, ++ 0x18, 0x88, 0x17, 0x00, 0x3C, 0x4C, 0x18, 0x00, 0x2C, 0x50, 0x18, 0x00, ++ 0x9C, 0x4B, 0x18, 0x00, 0x4C, 0x40, 0x18, 0x00, 0x2D, 0xE9, 0xF8, 0x4F, ++ 0x89, 0x46, 0xD0, 0xF8, 0xB8, 0x50, 0x89, 0x88, 0x99, 0xF8, 0x08, 0xA0, ++ 0x90, 0xF8, 0x63, 0xB0, 0xD5, 0xF8, 0x24, 0x80, 0x2A, 0x4B, 0xB9, 0xF8, ++ 0x06, 0x70, 0xD3, 0xF8, 0x54, 0x31, 0x29, 0x4E, 0xA1, 0xEB, 0x0A, 0x0A, ++ 0x04, 0x46, 0x42, 0x46, 0xA0, 0xF8, 0xCC, 0xA0, 0x58, 0x46, 0x98, 0x47, ++ 0xB9, 0xF8, 0x06, 0x30, 0x6A, 0x6A, 0x21, 0x6C, 0x23, 0x48, 0x03, 0xF1, ++ 0xFF, 0x3C, 0x62, 0x44, 0xAA, 0x62, 0x99, 0xF8, 0x08, 0xC0, 0x06, 0xEB, ++ 0xCB, 0x06, 0xDB, 0x43, 0x0B, 0xEB, 0x8B, 0x0B, 0x0C, 0xF1, 0x01, 0x0C, ++ 0x00, 0xEB, 0x8B, 0x0B, 0x62, 0x44, 0x53, 0x44, 0x13, 0x44, 0x00, 0x20, ++ 0xCB, 0xE9, 0x02, 0x23, 0x03, 0x37, 0xCB, 0xF8, 0x10, 0x00, 0x31, 0xB3, ++ 0x94, 0xF8, 0xC0, 0x34, 0x0A, 0x79, 0x16, 0x49, 0xE3, 0xB1, 0x16, 0x4A, ++ 0x16, 0x48, 0x13, 0x68, 0x12, 0x68, 0x1B, 0x02, 0xD2, 0xB2, 0x9B, 0xB2, ++ 0x13, 0x43, 0x00, 0x22, 0x4B, 0x62, 0xC5, 0xE9, 0x0D, 0x21, 0xE8, 0x64, ++ 0x94, 0xF8, 0x63, 0x30, 0x10, 0x4A, 0x03, 0xEB, 0x83, 0x03, 0x02, 0xEB, ++ 0xC3, 0x03, 0x01, 0x22, 0x2B, 0x62, 0x84, 0xF8, 0xD6, 0x20, 0x18, 0xF8, ++ 0x07, 0x30, 0xF3, 0x70, 0xBD, 0xE8, 0xF8, 0x8F, 0x0A, 0x4B, 0x82, 0x42, ++ 0x08, 0xBF, 0x19, 0x46, 0xDD, 0xE7, 0x04, 0x49, 0xDB, 0xE7, 0x00, 0xBF, ++ 0x88, 0x1A, 0x17, 0x00, 0x2C, 0x50, 0x18, 0x00, 0x4C, 0x40, 0x18, 0x00, ++ 0x84, 0x3C, 0x18, 0x00, 0xA0, 0x00, 0x32, 0x40, 0x41, 0x00, 0x00, 0x01, ++ 0x9C, 0x4B, 0x18, 0x00, 0xC4, 0x3C, 0x18, 0x00, 0x2D, 0xE9, 0xF8, 0x43, ++ 0x4D, 0x4D, 0x90, 0xF8, 0x63, 0x30, 0xD0, 0xF8, 0xB8, 0x80, 0x05, 0xEB, ++ 0xC3, 0x05, 0x04, 0x46, 0x2F, 0x79, 0x00, 0xF1, 0x6C, 0x06, 0xFF, 0xF7, ++ 0x7D, 0xFD, 0xB0, 0xF8, 0xCC, 0x30, 0xB0, 0xF8, 0xCE, 0x20, 0x13, 0x44, ++ 0x04, 0x33, 0xC8, 0xF8, 0x2C, 0x30, 0x90, 0xF8, 0xC0, 0x34, 0x00, 0x2B, ++ 0x54, 0xD1, 0x42, 0x4A, 0xD8, 0xF8, 0x24, 0x10, 0xB2, 0xF8, 0xFC, 0x31, ++ 0x01, 0x33, 0x9B, 0xB2, 0x18, 0x01, 0xA2, 0xF8, 0xFC, 0x31, 0xC8, 0x82, ++ 0x94, 0xF8, 0xD7, 0x30, 0xAB, 0x70, 0x94, 0xF8, 0xDA, 0x90, 0xCB, 0xBB, ++ 0xB9, 0xF1, 0x00, 0x0F, 0x31, 0xD1, 0x07, 0xF0, 0xFE, 0x07, 0x38, 0x4B, ++ 0x1B, 0x78, 0x0B, 0xB1, 0x47, 0xF0, 0x01, 0x07, 0xEB, 0x78, 0x84, 0xF8, ++ 0xD7, 0x30, 0x2F, 0x71, 0x94, 0xF8, 0xD7, 0x30, 0x94, 0xF8, 0xDB, 0x50, ++ 0x01, 0x3B, 0x84, 0xF8, 0xD7, 0x30, 0xBD, 0xB1, 0x01, 0x3D, 0x94, 0xF8, ++ 0xDC, 0x30, 0xED, 0xB2, 0x84, 0xF8, 0xDB, 0x50, 0x63, 0xB1, 0xD8, 0xF8, ++ 0x24, 0x20, 0xD5, 0x54, 0x94, 0xF8, 0xDD, 0x30, 0x23, 0xB1, 0xD8, 0xF8, ++ 0x24, 0x20, 0x94, 0xF8, 0xDB, 0x10, 0xD1, 0x54, 0x94, 0xF8, 0xDB, 0x50, ++ 0x7D, 0xBB, 0x01, 0x23, 0x84, 0xF8, 0xDB, 0x30, 0x20, 0x46, 0x31, 0x46, ++ 0x06, 0xF0, 0xE0, 0xFC, 0x48, 0x46, 0xBD, 0xE8, 0xF8, 0x83, 0x47, 0xF0, ++ 0x01, 0x07, 0x4F, 0xF0, 0x01, 0x09, 0xCA, 0xE7, 0x19, 0xF0, 0x02, 0x09, ++ 0x1A, 0xBF, 0x47, 0xF0, 0x01, 0x07, 0x4F, 0xF0, 0x01, 0x09, 0x07, 0xF0, ++ 0xFE, 0x07, 0xC8, 0xE7, 0x90, 0xF8, 0xC1, 0x04, 0x05, 0xF0, 0x7E, 0xF9, ++ 0x00, 0x28, 0xA4, 0xD0, 0x94, 0xF8, 0x63, 0x10, 0x15, 0x4A, 0xD8, 0xF8, ++ 0x2C, 0x30, 0x01, 0xEB, 0x81, 0x01, 0x02, 0xEB, 0x81, 0x02, 0x19, 0x18, ++ 0x93, 0x68, 0xC8, 0xF8, 0x2C, 0x10, 0x01, 0x3B, 0x18, 0x44, 0xD0, 0x60, ++ 0x93, 0xE7, 0x02, 0x23, 0x00, 0x22, 0x0C, 0x21, 0x4E, 0x20, 0x94, 0xF8, ++ 0x63, 0x70, 0x07, 0xF0, 0xE3, 0xF8, 0x07, 0x70, 0x45, 0x70, 0x07, 0xF0, ++ 0x0F, 0xF9, 0x94, 0xF8, 0xDB, 0x30, 0x00, 0x2B, 0xBF, 0xD0, 0x20, 0x46, ++ 0x31, 0x46, 0x06, 0xF0, 0xA3, 0xFC, 0x48, 0x46, 0xBD, 0xE8, 0xF8, 0x83, ++ 0x2C, 0x50, 0x18, 0x00, 0x20, 0x62, 0x17, 0x00, 0x16, 0x2C, 0x17, 0x00, ++ 0xFC, 0x3E, 0x18, 0x00, 0xF8, 0xB5, 0x18, 0x4D, 0x18, 0x4F, 0x2E, 0x68, ++ 0x04, 0x46, 0x36, 0xF8, 0x04, 0x1C, 0x00, 0x22, 0x40, 0x20, 0x07, 0xF0, ++ 0x29, 0xF9, 0xD7, 0xF8, 0x78, 0x31, 0x29, 0x68, 0x20, 0x46, 0x98, 0x47, ++ 0x2A, 0x68, 0x00, 0x23, 0x84, 0xF8, 0xDB, 0x30, 0x93, 0x7A, 0x84, 0xF8, ++ 0xDC, 0x30, 0xD2, 0x7A, 0x84, 0xF8, 0xDD, 0x20, 0x0C, 0x3E, 0xD4, 0xF8, ++ 0xB8, 0x20, 0x23, 0xB1, 0x52, 0x6A, 0xD3, 0x5C, 0x01, 0x33, 0x84, 0xF8, ++ 0xDB, 0x30, 0x2B, 0x7A, 0x00, 0x22, 0x6A, 0x72, 0x13, 0xB1, 0xD7, 0xF8, ++ 0x84, 0x31, 0x98, 0x47, 0x00, 0x23, 0x30, 0x46, 0x2B, 0x60, 0xBD, 0xE8, ++ 0xF8, 0x40, 0x07, 0xF0, 0x17, 0xB9, 0x00, 0xBF, 0xD8, 0x9C, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x70, 0xB5, 0x0E, 0x4D, 0x44, 0x7A, 0x0E, 0x4A, ++ 0x0E, 0x49, 0x03, 0x46, 0x4F, 0xF4, 0x1A, 0x70, 0x00, 0xFB, 0x04, 0x50, ++ 0x01, 0x25, 0x55, 0x72, 0x00, 0x25, 0x95, 0x72, 0x9A, 0x88, 0x68, 0x30, ++ 0x1B, 0xF0, 0x0C, 0xFC, 0x08, 0x4A, 0x09, 0x4B, 0x4F, 0xF4, 0xA4, 0x60, ++ 0x29, 0x46, 0x00, 0xFB, 0x04, 0x20, 0xD3, 0xF8, 0x94, 0x31, 0xBD, 0xE8, ++ 0x70, 0x40, 0x18, 0x47, 0xFC, 0x41, 0x18, 0x00, 0xD8, 0x9C, 0x17, 0x00, ++ 0x14, 0x2A, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x7E, 0x4B, 0x2D, 0xE9, 0xF0, 0x4F, 0x1B, 0x68, 0x7D, 0x4D, 0xB3, 0xF9, ++ 0x00, 0x30, 0x6E, 0x68, 0x00, 0x2B, 0x83, 0xB0, 0x04, 0x46, 0x44, 0xDB, ++ 0x01, 0x3E, 0x6E, 0x60, 0x00, 0x2E, 0x4D, 0xD0, 0xDF, 0xF8, 0xE0, 0x91, ++ 0x77, 0x4D, 0x78, 0x4E, 0x78, 0x4F, 0xDF, 0xF8, 0x00, 0xA2, 0xDF, 0xF8, ++ 0x00, 0x82, 0x03, 0xE0, 0x05, 0xF5, 0x1E, 0x75, 0xB5, 0x42, 0x2F, 0xD0, ++ 0x95, 0xF8, 0x25, 0x20, 0x4F, 0xF4, 0xA4, 0x61, 0x00, 0x2A, 0xF5, 0xD0, ++ 0x95, 0xF8, 0x22, 0x30, 0x01, 0xFB, 0x03, 0x73, 0x9C, 0x42, 0xEF, 0xD1, ++ 0x95, 0xF8, 0x23, 0x30, 0x0D, 0x2B, 0x9B, 0xBF, 0x4F, 0xF4, 0x1E, 0x72, ++ 0x02, 0xFB, 0x03, 0x93, 0x00, 0x22, 0xD3, 0xF8, 0x58, 0x22, 0xDA, 0xF8, ++ 0x10, 0x30, 0xA8, 0xEB, 0x03, 0x03, 0xD3, 0x42, 0xDE, 0xD5, 0x20, 0x46, ++ 0xF2, 0xF7, 0x96, 0xFF, 0x00, 0x28, 0xD9, 0xD0, 0x63, 0x49, 0x95, 0xF8, ++ 0x23, 0x00, 0x2A, 0x46, 0xF4, 0xF7, 0xAE, 0xFB, 0x00, 0x28, 0xD1, 0xD1, ++ 0x95, 0xF8, 0x23, 0x10, 0x5F, 0x48, 0x08, 0xF0, 0x89, 0xFE, 0xCB, 0xE7, ++ 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x00, 0x2E, 0xB8, 0xD1, 0x5C, 0x49, ++ 0x5C, 0x48, 0x4F, 0xF4, 0x3F, 0x72, 0x09, 0xF0, 0xF7, 0xF8, 0x6E, 0x68, ++ 0x01, 0x3E, 0x6E, 0x60, 0x00, 0x2E, 0xB1, 0xD1, 0xDF, 0xF8, 0x74, 0xB1, ++ 0xFC, 0xF7, 0xCC, 0xFF, 0x94, 0xF8, 0x63, 0x30, 0x9B, 0xF8, 0x00, 0x20, ++ 0x03, 0xF1, 0x0A, 0x08, 0x00, 0x2A, 0x58, 0xD1, 0xDF, 0xF8, 0x2C, 0x91, ++ 0x51, 0x4B, 0x1B, 0x78, 0x53, 0xB3, 0x08, 0xEB, 0x88, 0x02, 0x4F, 0xF4, ++ 0x1E, 0x73, 0xC8, 0xEB, 0x02, 0x12, 0x4E, 0x4F, 0x01, 0x92, 0x03, 0xFB, ++ 0x08, 0x9B, 0x4F, 0xF0, 0x00, 0x0A, 0xDB, 0xF8, 0x08, 0x32, 0x5F, 0xFA, ++ 0x8A, 0xF6, 0x0B, 0xF5, 0x02, 0x78, 0x53, 0xB1, 0x40, 0x46, 0x07, 0xF0, ++ 0xBB, 0xFC, 0xD7, 0xF8, 0x24, 0x34, 0x31, 0x46, 0x98, 0x47, 0xDB, 0xF8, ++ 0x08, 0x32, 0x00, 0x2B, 0xF4, 0xD1, 0xDB, 0xF8, 0x30, 0x22, 0x00, 0x2A, ++ 0x5B, 0xD1, 0x0A, 0xF1, 0x01, 0x0A, 0xBA, 0xF1, 0x04, 0x0F, 0x0B, 0xF1, ++ 0x08, 0x0B, 0xE2, 0xD1, 0x3B, 0x4B, 0x1A, 0x70, 0xAB, 0x7A, 0x03, 0xBB, ++ 0xEB, 0x68, 0x63, 0xB1, 0x39, 0x4F, 0xDF, 0xF8, 0xF8, 0x80, 0xD7, 0xF8, ++ 0xD4, 0x61, 0x40, 0x46, 0x07, 0xF0, 0x9A, 0xFC, 0x0C, 0x30, 0xB0, 0x47, ++ 0xEB, 0x68, 0x00, 0x2B, 0xF5, 0xD1, 0x94, 0xF8, 0x63, 0x00, 0x05, 0x44, ++ 0x29, 0x7D, 0x19, 0xB1, 0x30, 0x4B, 0xD3, 0xF8, 0x90, 0x31, 0x98, 0x47, ++ 0x94, 0xF8, 0xDB, 0x30, 0x01, 0x2B, 0x7F, 0xF4, 0x59, 0xAF, 0x20, 0x46, ++ 0xFB, 0xF7, 0xBE, 0xFA, 0x54, 0xE7, 0x2A, 0x4F, 0x28, 0x68, 0xD7, 0xF8, ++ 0x8C, 0x31, 0x98, 0x47, 0xD8, 0xE7, 0x04, 0x23, 0x32, 0x46, 0x0C, 0x21, ++ 0x4A, 0x20, 0x06, 0xF0, 0xA5, 0xFF, 0x80, 0xF8, 0x00, 0x80, 0x46, 0x70, ++ 0x86, 0x70, 0x06, 0xF0, 0xCF, 0xFF, 0x9B, 0xF8, 0x00, 0x30, 0xDF, 0xF8, ++ 0x60, 0x90, 0x00, 0x2B, 0x96, 0xD0, 0x4F, 0xF4, 0x1E, 0x7A, 0x0A, 0xFB, ++ 0x08, 0x9A, 0x9A, 0xF8, 0x31, 0x30, 0x9B, 0x07, 0x0B, 0xD5, 0x1A, 0x4F, ++ 0x09, 0x22, 0x8A, 0xF8, 0x32, 0x20, 0xD7, 0xF8, 0x20, 0x33, 0x32, 0x46, ++ 0x51, 0x46, 0x20, 0x46, 0x98, 0x47, 0x8A, 0xF8, 0x32, 0x60, 0x00, 0x23, ++ 0x8B, 0xF8, 0x00, 0x30, 0x7E, 0xE7, 0x01, 0x98, 0x46, 0x30, 0x50, 0x44, ++ 0x09, 0xEB, 0xC0, 0x00, 0x07, 0xF0, 0x4C, 0xFC, 0x0E, 0x4B, 0x31, 0x46, ++ 0xD3, 0xF8, 0x24, 0x34, 0x98, 0x47, 0x0D, 0x48, 0x08, 0xF0, 0xDA, 0xFD, ++ 0xFE, 0xE7, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, 0xD8, 0x9C, 0x17, 0x00, ++ 0x68, 0x65, 0x17, 0x00, 0x18, 0x7E, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0x51, 0xB1, 0x13, 0x00, 0xF8, 0x9F, 0x15, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0xC8, 0x9F, 0x15, 0x00, 0x16, 0x2C, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0xDC, 0x9F, 0x15, 0x00, 0x00, 0x10, 0x50, 0x40, 0xC0, 0xE1, 0xE4, 0x00, ++ 0x10, 0x2A, 0x17, 0x00, 0xE4, 0x9C, 0x17, 0x00, 0x38, 0xB5, 0x0E, 0x4D, ++ 0x0E, 0x4C, 0x18, 0x22, 0x00, 0x21, 0x28, 0x46, 0xE4, 0xF7, 0x42, 0xFB, ++ 0x05, 0xF1, 0x0C, 0x00, 0x07, 0xF0, 0xCE, 0xFB, 0x20, 0x46, 0x04, 0xF0, ++ 0xD9, 0xFF, 0x04, 0xF1, 0x26, 0x00, 0x04, 0xF0, 0xD5, 0xFF, 0x04, 0xF1, ++ 0x4C, 0x00, 0x04, 0xF0, 0xD1, 0xFF, 0x04, 0xF1, 0x72, 0x00, 0xBD, 0xE8, ++ 0x38, 0x40, 0x04, 0xF0, 0xCB, 0xBF, 0x00, 0xBF, 0xD8, 0x9C, 0x17, 0x00, ++ 0x64, 0x3E, 0x18, 0x00, 0x2D, 0xE9, 0xF8, 0x43, 0x90, 0xF8, 0x63, 0x30, ++ 0x3F, 0x4D, 0x40, 0x49, 0x40, 0x4F, 0xDF, 0xF8, 0x1C, 0x91, 0x04, 0x46, ++ 0x03, 0xEB, 0x83, 0x02, 0x3E, 0x48, 0x4F, 0xF4, 0x1A, 0x76, 0x03, 0xEB, ++ 0x42, 0x02, 0x06, 0xFB, 0x03, 0x11, 0x05, 0xEB, 0xC2, 0x02, 0x00, 0xEB, ++ 0x83, 0x13, 0x04, 0xF1, 0x6C, 0x00, 0xF4, 0xF7, 0xFD, 0xF8, 0x94, 0xF8, ++ 0x63, 0x30, 0x37, 0x49, 0xDF, 0xF8, 0xF0, 0xC0, 0x36, 0x48, 0x06, 0x22, ++ 0xA4, 0xF8, 0xCE, 0x20, 0x00, 0x25, 0x01, 0xEB, 0xC3, 0x02, 0x4F, 0xF0, ++ 0x05, 0x0E, 0xFF, 0x26, 0xA4, 0xF8, 0xD8, 0x60, 0x84, 0xF8, 0xD7, 0x50, ++ 0xA4, 0xF8, 0xD0, 0x50, 0x84, 0xF8, 0xDA, 0x50, 0x04, 0x26, 0x01, 0xF8, ++ 0x33, 0xE0, 0x56, 0x70, 0x94, 0xF8, 0xD7, 0x10, 0x91, 0x70, 0x01, 0x21, ++ 0x15, 0x71, 0x55, 0x71, 0xD1, 0x70, 0x94, 0xF8, 0xD9, 0x10, 0x03, 0xEB, ++ 0x83, 0x08, 0xC3, 0xEB, 0x83, 0x16, 0x00, 0xEB, 0x86, 0x00, 0x0C, 0xEB, ++ 0xC8, 0x06, 0x01, 0x44, 0x07, 0xEB, 0x88, 0x03, 0x31, 0x62, 0x02, 0xEB, ++ 0x0E, 0x01, 0xC6, 0xE9, 0x03, 0x15, 0x4C, 0xF8, 0x38, 0x90, 0xB2, 0x60, ++ 0x73, 0x60, 0xB3, 0x61, 0x29, 0x46, 0xFC, 0x22, 0xC6, 0xF8, 0x14, 0x90, ++ 0xE4, 0xF7, 0xCE, 0xFA, 0x07, 0xEB, 0x88, 0x03, 0x47, 0xF8, 0x28, 0x90, ++ 0x5D, 0x60, 0x1D, 0x61, 0x94, 0xF8, 0xC0, 0x34, 0x93, 0xB1, 0x94, 0xF8, ++ 0x63, 0x30, 0x15, 0x48, 0x15, 0x49, 0x03, 0xEB, 0xC3, 0x02, 0x03, 0xEB, ++ 0x42, 0x02, 0x03, 0xEB, 0x83, 0x03, 0x01, 0xEB, 0x42, 0x01, 0x00, 0xEB, ++ 0x83, 0x02, 0xC2, 0xE9, 0x01, 0x51, 0x40, 0xF8, 0x23, 0x90, 0x15, 0x61, ++ 0xD4, 0xF8, 0xB8, 0x30, 0x0D, 0x49, 0x00, 0x22, 0x5A, 0x63, 0xDA, 0x64, ++ 0x1A, 0x62, 0xD1, 0xF8, 0x88, 0x31, 0xC4, 0xE9, 0x30, 0x34, 0xBD, 0xE8, ++ 0xF8, 0x83, 0x00, 0xBF, 0x9C, 0x40, 0x18, 0x00, 0xFC, 0x41, 0x18, 0x00, ++ 0x4C, 0x40, 0x18, 0x00, 0x4C, 0x3F, 0x18, 0x00, 0x2C, 0x50, 0x18, 0x00, ++ 0x3C, 0x4C, 0x18, 0x00, 0xFC, 0x3E, 0x18, 0x00, 0x64, 0x3E, 0x18, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0xDE, 0xFA, 0xFE, 0xCA, 0x9C, 0x4B, 0x18, 0x00, ++ 0x05, 0x4B, 0x5A, 0x68, 0x18, 0x60, 0x12, 0xB1, 0x01, 0x22, 0x9A, 0x72, ++ 0x70, 0x47, 0x03, 0x4B, 0xD3, 0xF8, 0x8C, 0x31, 0x18, 0x47, 0x00, 0xBF, ++ 0xD8, 0x9C, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x06, 0x4B, 0x5A, 0x68, ++ 0x1A, 0xB9, 0x06, 0x4B, 0xD3, 0xF8, 0xD4, 0x31, 0x18, 0x47, 0xA0, 0xF1, ++ 0x0C, 0x01, 0x03, 0xF1, 0x0C, 0x00, 0x07, 0xF0, 0x05, 0xBB, 0x00, 0xBF, ++ 0xD8, 0x9C, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x2D, 0xE9, 0xF8, 0x4F, ++ 0x40, 0x4B, 0x41, 0x4A, 0x1B, 0x68, 0x94, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x3F, 0x4E, 0x00, 0x2B, 0x41, 0xDB, 0x75, 0x7A, 0x00, 0x2D, 0x4A, 0xD1, ++ 0x3D, 0x4A, 0x35, 0x72, 0x17, 0x68, 0x7F, 0x01, 0x6C, 0xB1, 0xDF, 0xF8, ++ 0xF8, 0x90, 0xDF, 0xF8, 0xF8, 0x80, 0xAA, 0x46, 0x4F, 0xF0, 0x01, 0x0B, ++ 0x94, 0xF8, 0x62, 0x30, 0x02, 0x2B, 0x04, 0xD0, 0x24, 0x68, 0x00, 0x2C, ++ 0xF8, 0xD1, 0xBD, 0xE8, 0xF8, 0x8F, 0x94, 0xF8, 0xD6, 0x30, 0x00, 0x2B, ++ 0xF6, 0xD0, 0x94, 0xF8, 0x64, 0x30, 0x00, 0x2B, 0xF2, 0xD0, 0x94, 0xF8, ++ 0xD5, 0x20, 0x94, 0xF8, 0xD4, 0x30, 0x9A, 0x42, 0xEC, 0xD1, 0xD9, 0xF8, ++ 0x70, 0x31, 0x20, 0x46, 0x98, 0x47, 0x20, 0xB1, 0x98, 0xF8, 0x00, 0x30, ++ 0x01, 0x33, 0x88, 0xF8, 0x00, 0x30, 0xBB, 0xF1, 0x00, 0x0F, 0x05, 0xD0, ++ 0xA7, 0xF1, 0x32, 0x02, 0x40, 0xF6, 0xB6, 0x33, 0x9A, 0x42, 0x18, 0xD8, ++ 0xD5, 0xB9, 0x20, 0x46, 0x02, 0xF0, 0x7A, 0xFE, 0x83, 0x46, 0xF0, 0xB9, ++ 0x88, 0xF8, 0x00, 0x50, 0xD0, 0xE7, 0x73, 0x68, 0x00, 0x2B, 0xBA, 0xD0, ++ 0x1D, 0x49, 0x1E, 0x48, 0x40, 0xF2, 0x2F, 0x42, 0x08, 0xF0, 0xFE, 0xFE, ++ 0x75, 0x7A, 0x00, 0x2D, 0xB4, 0xD0, 0x01, 0x23, 0x33, 0x72, 0xBD, 0xE8, ++ 0xF8, 0x8F, 0x20, 0x46, 0x02, 0xF0, 0x62, 0xFE, 0x88, 0xF8, 0x00, 0xA0, ++ 0x24, 0x68, 0x4F, 0xF0, 0x00, 0x0B, 0x01, 0x25, 0x00, 0x2C, 0xB1, 0xD1, ++ 0xB7, 0xE7, 0x94, 0xF8, 0x63, 0x30, 0x84, 0xF8, 0x88, 0x30, 0xFF, 0x23, ++ 0x84, 0xF8, 0x89, 0x30, 0x04, 0x21, 0x04, 0xF1, 0x6C, 0x00, 0xF4, 0xF7, ++ 0xDB, 0xF8, 0x73, 0x68, 0x08, 0xB1, 0x01, 0x33, 0x73, 0x60, 0x01, 0x2B, ++ 0x02, 0xD0, 0x4F, 0xF0, 0x00, 0x0B, 0x9F, 0xE7, 0xFC, 0xF7, 0x58, 0xFD, ++ 0x4F, 0xF0, 0x00, 0x0B, 0x9A, 0xE7, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, ++ 0x00, 0x88, 0x17, 0x00, 0xD8, 0x9C, 0x17, 0x00, 0x40, 0x80, 0x32, 0x40, ++ 0x70, 0x79, 0x15, 0x00, 0x20, 0xA0, 0x15, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x10, 0x2A, 0x17, 0x00, 0xF8, 0xB5, 0x27, 0x4F, 0x7B, 0x68, 0x04, 0x46, ++ 0x0E, 0x46, 0x13, 0xB1, 0x3C, 0x44, 0x21, 0x75, 0xF8, 0xBD, 0x02, 0x29, ++ 0x34, 0xD0, 0x03, 0x29, 0x21, 0xD0, 0x01, 0x29, 0x14, 0xD0, 0x21, 0x4B, ++ 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x32, 0xDB, 0x1F, 0x4D, ++ 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x04, 0x53, 0x3C, 0x44, 0x00, 0x22, ++ 0x22, 0x75, 0x93, 0xF8, 0xC1, 0x04, 0x31, 0x46, 0xBD, 0xE8, 0xF8, 0x40, ++ 0x04, 0xF0, 0xC6, 0xBE, 0x18, 0x4B, 0x19, 0x4A, 0x16, 0x4D, 0x00, 0xEB, ++ 0x80, 0x01, 0x03, 0xEB, 0x81, 0x03, 0x02, 0xEB, 0x81, 0x02, 0x5A, 0x60, ++ 0xE6, 0xE7, 0x12, 0x4D, 0x14, 0x49, 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, ++ 0x00, 0x52, 0x00, 0xEB, 0xC0, 0x03, 0x00, 0xEB, 0x43, 0x03, 0x01, 0xEB, ++ 0x43, 0x01, 0x92, 0xF8, 0xC1, 0x04, 0x04, 0xF0, 0x47, 0xFE, 0xD5, 0xE7, ++ 0x0A, 0x4A, 0x09, 0x4D, 0x00, 0xEB, 0x80, 0x01, 0x02, 0xEB, 0x81, 0x02, ++ 0x53, 0x60, 0xCD, 0xE7, 0x09, 0x49, 0x0A, 0x48, 0x04, 0x4D, 0x40, 0xF2, ++ 0xC6, 0x42, 0x08, 0xF0, 0x71, 0xFE, 0xC5, 0xE7, 0xD8, 0x9C, 0x17, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, 0x4C, 0x40, 0x18, 0x00, ++ 0xFC, 0x3E, 0x18, 0x00, 0x64, 0x3E, 0x18, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x64, 0x7D, 0x15, 0x00, 0x10, 0xB5, 0x04, 0x46, 0x04, 0x23, 0x00, 0x22, ++ 0x0C, 0x21, 0x44, 0x20, 0x06, 0xF0, 0x76, 0xFD, 0x23, 0x7E, 0x03, 0x70, ++ 0x04, 0x2B, 0x09, 0xD0, 0x00, 0x23, 0x00, 0x22, 0x43, 0x70, 0xC2, 0x70, ++ 0xA3, 0x7E, 0x83, 0x70, 0xBD, 0xE8, 0x10, 0x40, 0x06, 0xF0, 0x98, 0xBD, ++ 0xE3, 0x89, 0x00, 0x3B, 0x18, 0xBF, 0x01, 0x23, 0xF1, 0xE7, 0x00, 0xBF, ++ 0x38, 0xB5, 0x05, 0xF0, 0xE1, 0xFA, 0x0C, 0x23, 0x05, 0x46, 0x19, 0x46, ++ 0x00, 0x22, 0x4F, 0x20, 0x06, 0xF0, 0x58, 0xFD, 0x2B, 0x88, 0x03, 0x80, ++ 0x04, 0x46, 0x28, 0x46, 0x05, 0xF0, 0xDE, 0xFA, 0x10, 0x4A, 0x11, 0x4D, ++ 0x11, 0x49, 0xA2, 0xFB, 0x00, 0x03, 0x9B, 0x09, 0x63, 0x60, 0x2B, 0x68, ++ 0xA2, 0xFB, 0x03, 0x23, 0x9B, 0x09, 0x00, 0x22, 0xA3, 0x60, 0xA2, 0x70, ++ 0x0A, 0x23, 0x0A, 0x68, 0x52, 0xB2, 0x01, 0x3B, 0x3A, 0xB9, 0x13, 0xF0, ++ 0xFF, 0x03, 0xF8, 0xD1, 0x20, 0x46, 0xBD, 0xE8, 0x38, 0x40, 0x06, 0xF0, ++ 0x67, 0xBD, 0xA2, 0x70, 0x20, 0x46, 0xBD, 0xE8, 0x38, 0x40, 0x06, 0xF0, ++ 0x61, 0xBD, 0x00, 0xBF, 0xD3, 0x4D, 0x62, 0x10, 0x20, 0x02, 0x32, 0x40, ++ 0x0C, 0xB2, 0x33, 0x40, 0x10, 0xB5, 0xC1, 0x89, 0x04, 0x46, 0x02, 0x23, ++ 0x00, 0x22, 0x48, 0x20, 0x06, 0xF0, 0x22, 0xFD, 0x22, 0x7E, 0x42, 0x70, ++ 0xA1, 0x7E, 0x05, 0x4A, 0x01, 0x70, 0x13, 0x68, 0x23, 0xF0, 0x04, 0x03, ++ 0xBD, 0xE8, 0x10, 0x40, 0x13, 0x60, 0x06, 0xF0, 0x45, 0xBD, 0x00, 0xBF, ++ 0x94, 0x40, 0x04, 0x40, 0xF0, 0xB5, 0x04, 0x68, 0x0E, 0x68, 0xA5, 0x1B, ++ 0x32, 0xD4, 0x8E, 0x46, 0xAB, 0x42, 0x0C, 0xD2, 0xDE, 0xE9, 0x00, 0x76, ++ 0xDC, 0x19, 0xF6, 0x1B, 0xED, 0x1A, 0xAB, 0x42, 0x06, 0xEB, 0x04, 0x07, ++ 0xA4, 0x46, 0x1C, 0x44, 0xF8, 0xD3, 0xCE, 0xE9, 0x00, 0xC7, 0xB5, 0xEB, ++ 0x53, 0x0F, 0x05, 0xD9, 0xDE, 0xE9, 0x00, 0x54, 0x1D, 0x44, 0x23, 0x44, ++ 0xCE, 0xE9, 0x00, 0x53, 0x43, 0x68, 0x4C, 0x68, 0x1D, 0x1B, 0x00, 0x2D, ++ 0x09, 0xDB, 0xB2, 0xB1, 0x05, 0x68, 0x09, 0x68, 0x53, 0x60, 0x68, 0x1A, ++ 0x00, 0x28, 0x17, 0xDA, 0x58, 0x1B, 0x15, 0x60, 0xF0, 0xBD, 0xAA, 0xB1, ++ 0x05, 0x68, 0x09, 0x68, 0x54, 0x60, 0x6B, 0x1A, 0x00, 0x2B, 0xA8, 0xBF, ++ 0x60, 0x1A, 0x18, 0xDB, 0x11, 0x60, 0xF0, 0xBD, 0x35, 0x1B, 0x86, 0x46, ++ 0xCA, 0xE7, 0x00, 0x68, 0x0A, 0x68, 0x81, 0x1A, 0x00, 0x29, 0x0C, 0xDA, ++ 0x18, 0x1A, 0xF0, 0xBD, 0x58, 0x1A, 0xF1, 0xE7, 0x00, 0x68, 0x0B, 0x68, ++ 0xC1, 0x1A, 0x00, 0x29, 0xA8, 0xBF, 0xE0, 0x1A, 0xE0, 0xDA, 0x20, 0x1A, ++ 0xF0, 0xBD, 0x98, 0x1A, 0xF0, 0xBD, 0x60, 0x1B, 0xD9, 0xE7, 0x00, 0xBF, ++ 0x70, 0xB5, 0x19, 0x4E, 0x90, 0xF8, 0xC1, 0x44, 0x8C, 0x23, 0x03, 0xFB, ++ 0x04, 0x63, 0x05, 0x46, 0x93, 0xF8, 0x20, 0x20, 0x0A, 0xB9, 0x1B, 0x7C, ++ 0xFB, 0xB9, 0x8C, 0x23, 0x03, 0xFB, 0x04, 0x64, 0x94, 0xF8, 0x50, 0x20, ++ 0x12, 0xB9, 0x94, 0xF8, 0x40, 0x30, 0x7B, 0xB9, 0x0F, 0x4B, 0x9B, 0x68, ++ 0x5B, 0xB1, 0x95, 0xF8, 0x63, 0x10, 0xFF, 0x20, 0x93, 0xF8, 0x4E, 0x20, ++ 0x8A, 0x42, 0x08, 0xBF, 0x83, 0xF8, 0x4E, 0x00, 0x1B, 0x68, 0x00, 0x2B, ++ 0xF6, 0xD1, 0x70, 0xBD, 0x08, 0x4B, 0x01, 0x21, 0xD3, 0xF8, 0x08, 0x32, ++ 0x28, 0x46, 0x98, 0x47, 0xE8, 0xE7, 0x05, 0x4B, 0x11, 0x46, 0xD3, 0xF8, ++ 0x08, 0x32, 0x98, 0x47, 0xD9, 0xE7, 0x00, 0xBF, 0x48, 0x9E, 0x17, 0x00, ++ 0x00, 0x88, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0x48, 0x4B, 0x93, 0xF8, 0x5A, 0x30, 0x9B, 0xB0, 0x01, 0x2B, 0x08, 0x90, ++ 0x40, 0xF2, 0x93, 0x81, 0xDF, 0xF8, 0x20, 0x91, 0xD9, 0xF8, 0x00, 0x30, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xC0, 0xF2, 0xB7, 0x81, 0x08, 0x9C, ++ 0x40, 0x4B, 0x20, 0x46, 0xD3, 0xF8, 0x94, 0x30, 0x98, 0x47, 0x23, 0x6C, ++ 0x94, 0xF8, 0x63, 0x20, 0xDA, 0x76, 0x94, 0xF8, 0x62, 0x20, 0x00, 0x2A, ++ 0x00, 0xF0, 0xB9, 0x81, 0x02, 0x2A, 0x08, 0xBF, 0x08, 0x9A, 0x39, 0x48, ++ 0x0A, 0xBF, 0xB2, 0xF8, 0xD2, 0x20, 0x4F, 0xF4, 0xC8, 0x32, 0x92, 0x02, ++ 0x0A, 0x92, 0x1A, 0x7E, 0x02, 0x2A, 0x02, 0xF1, 0x01, 0x03, 0x00, 0xF0, ++ 0xB9, 0x81, 0xC3, 0xEB, 0xC3, 0x04, 0x00, 0xEB, 0x84, 0x04, 0xD9, 0x00, ++ 0x24, 0x7E, 0xFF, 0x2C, 0x0D, 0xD1, 0x01, 0x2A, 0x02, 0xF1, 0x02, 0x03, ++ 0x08, 0xBF, 0x00, 0x23, 0xC3, 0xEB, 0xC3, 0x02, 0x00, 0xEB, 0x82, 0x02, ++ 0xD9, 0x00, 0x12, 0x7E, 0xFF, 0x2A, 0x00, 0xF0, 0x98, 0x82, 0x28, 0x4A, ++ 0xCB, 0x1A, 0x00, 0xEB, 0x83, 0x03, 0x96, 0x68, 0x5B, 0x7E, 0x06, 0x93, ++ 0x00, 0x2E, 0x00, 0xF0, 0x4A, 0x81, 0x0A, 0x9B, 0x4F, 0xF0, 0x00, 0x0B, ++ 0x5B, 0x00, 0x0B, 0x93, 0x5F, 0x46, 0x03, 0xE0, 0x36, 0x68, 0x00, 0x2E, ++ 0x00, 0xF0, 0x9A, 0x80, 0x33, 0x6C, 0x00, 0x2B, 0xF8, 0xD0, 0x08, 0x9A, ++ 0x12, 0x6C, 0x93, 0x42, 0xF4, 0xD0, 0x96, 0xF8, 0x62, 0x30, 0x00, 0x2B, ++ 0x00, 0xF0, 0x93, 0x81, 0x02, 0x2B, 0x0A, 0xBF, 0xB6, 0xF8, 0xD2, 0x30, ++ 0x4F, 0xF4, 0xC8, 0x3B, 0x4F, 0xEA, 0x83, 0x2B, 0x0B, 0x9B, 0x5B, 0x45, ++ 0x04, 0xD8, 0x0A, 0x9B, 0xBB, 0xFB, 0xF3, 0xF2, 0xBB, 0xFB, 0xF2, 0xFB, ++ 0x06, 0x9B, 0x4F, 0xEA, 0x5B, 0x00, 0xB0, 0xFB, 0xF3, 0xF5, 0x09, 0x95, ++ 0xE5, 0xF7, 0x7C, 0xF8, 0x43, 0xF2, 0xB0, 0x64, 0x20, 0x44, 0xA8, 0x42, ++ 0x00, 0xF2, 0x18, 0x81, 0x00, 0x2F, 0x00, 0xF0, 0x1C, 0x81, 0x06, 0x9B, ++ 0x09, 0x9A, 0x03, 0xFB, 0x02, 0xF3, 0x07, 0x93, 0x10, 0xAC, 0x00, 0x25, ++ 0x10, 0xE0, 0x00, 0xBF, 0x30, 0x9D, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x90, 0x9D, 0x17, 0x00, 0x00, 0x88, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x01, 0x35, 0xAF, 0x42, 0x04, 0xF1, 0x14, 0x04, 0x00, 0xF0, 0x03, 0x81, ++ 0x22, 0x68, 0x5A, 0x45, 0xF6, 0xD1, 0x72, 0x6A, 0x0C, 0x92, 0xD4, 0xE9, ++ 0x02, 0x01, 0x0D, 0xF1, 0x38, 0x0C, 0x0D, 0xF1, 0x30, 0x0A, 0x02, 0xF5, ++ 0x1C, 0x5E, 0x8C, 0xE8, 0x03, 0x00, 0x0E, 0xF1, 0x10, 0x0E, 0x52, 0x46, ++ 0x61, 0x46, 0x50, 0x46, 0x5B, 0x46, 0xCD, 0xF8, 0x34, 0xE0, 0xFF, 0xF7, ++ 0xB7, 0xFE, 0xD9, 0xF8, 0x00, 0x20, 0xB2, 0xF9, 0x00, 0x20, 0x00, 0x2A, ++ 0x80, 0x46, 0xC0, 0xF2, 0x2D, 0x81, 0x06, 0x9B, 0x5A, 0x1E, 0x07, 0x9B, ++ 0xB3, 0xFB, 0xF2, 0xF2, 0x05, 0x92, 0xE5, 0xF7, 0x31, 0xF8, 0x05, 0x9A, ++ 0x61, 0x68, 0xA2, 0xF5, 0x7A, 0x62, 0x12, 0x1A, 0x8A, 0x42, 0x38, 0xBF, ++ 0x0A, 0x46, 0x42, 0x45, 0xC6, 0xD9, 0x05, 0x92, 0x05, 0xEB, 0x85, 0x05, ++ 0xE5, 0xF7, 0x22, 0xF8, 0x1A, 0xAB, 0x03, 0xEB, 0x85, 0x05, 0x96, 0xF8, ++ 0x63, 0x10, 0x05, 0x9A, 0x55, 0xF8, 0x18, 0x3C, 0x36, 0x68, 0x01, 0x24, ++ 0x8C, 0x40, 0x02, 0x44, 0x9A, 0xE8, 0x03, 0x00, 0x23, 0x43, 0x02, 0xF5, ++ 0x7A, 0x62, 0xA5, 0xF1, 0x20, 0x04, 0x84, 0xE8, 0x03, 0x00, 0x45, 0xF8, ++ 0x24, 0x2C, 0x45, 0xF8, 0x18, 0x3C, 0x00, 0x2E, 0x7F, 0xF4, 0x66, 0xAF, ++ 0x00, 0x2F, 0x00, 0xF0, 0xA2, 0x80, 0xDF, 0xF8, 0x88, 0xA3, 0xDD, 0xF8, ++ 0x20, 0xB0, 0x05, 0x96, 0x09, 0x96, 0x0B, 0x96, 0x07, 0x96, 0x12, 0xAC, ++ 0x06, 0x97, 0x54, 0xF8, 0x08, 0x7C, 0x0A, 0x9B, 0xB7, 0xFB, 0xF3, 0xF2, ++ 0x03, 0xFB, 0x12, 0x72, 0x00, 0x2A, 0x00, 0xF0, 0x3A, 0x81, 0xE4, 0xF7, ++ 0xED, 0xFF, 0x54, 0xE9, 0x01, 0x63, 0xA3, 0xF5, 0xBB, 0x53, 0x10, 0x3B, ++ 0x1D, 0x1A, 0xE4, 0xF7, 0xE5, 0xFF, 0xDA, 0xF8, 0x10, 0x30, 0x54, 0xF8, ++ 0x08, 0x1C, 0xEB, 0x1A, 0x06, 0xF5, 0x7A, 0x66, 0x00, 0x2B, 0x06, 0xEB, ++ 0x00, 0x07, 0xC0, 0xF2, 0xEA, 0x80, 0xDA, 0xF8, 0x10, 0x20, 0x6B, 0x1A, ++ 0x9A, 0x1A, 0x00, 0x2A, 0x80, 0xF2, 0xDB, 0x80, 0xCD, 0xE9, 0x01, 0x75, ++ 0xBE, 0x4B, 0x00, 0x91, 0xD3, 0xF8, 0x04, 0x32, 0xDF, 0xF8, 0x1C, 0x83, ++ 0x1E, 0x46, 0x00, 0x22, 0xFF, 0x23, 0x01, 0x21, 0x58, 0x46, 0xB0, 0x47, ++ 0xEB, 0x19, 0xB9, 0x4E, 0x25, 0x60, 0x63, 0x60, 0x07, 0x46, 0x00, 0x25, ++ 0xA3, 0x68, 0xEB, 0x40, 0xDB, 0x07, 0x22, 0xD5, 0x72, 0x6A, 0x54, 0xF8, ++ 0x08, 0x3C, 0x0E, 0x92, 0x02, 0xF5, 0x1C, 0x5C, 0x0C, 0xF1, 0x10, 0x0C, ++ 0x00, 0x22, 0x0E, 0xA9, 0x20, 0x46, 0xCD, 0xF8, 0x3C, 0xC0, 0xFF, 0xF7, ++ 0x21, 0xFE, 0xD9, 0xF8, 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0xC0, 0xF2, 0xC3, 0x80, 0x0E, 0x9A, 0x63, 0x68, 0x9B, 0xF8, 0x63, 0x10, ++ 0x86, 0xF8, 0x4E, 0x10, 0x9B, 0x1A, 0x00, 0x22, 0x73, 0x65, 0x86, 0xF8, ++ 0x4F, 0x70, 0xA6, 0xF8, 0x58, 0x20, 0x01, 0x35, 0x04, 0x2D, 0x06, 0xF5, ++ 0xA4, 0x66, 0xD3, 0xD1, 0x05, 0x9B, 0x06, 0x9A, 0x01, 0x33, 0x9A, 0x42, ++ 0x05, 0x93, 0x04, 0xF1, 0x14, 0x04, 0x90, 0xD1, 0x07, 0x9B, 0x33, 0xB3, ++ 0x0B, 0x9B, 0x0A, 0x99, 0x03, 0xF5, 0x9C, 0x50, 0x09, 0x9B, 0x08, 0x30, ++ 0x83, 0x42, 0xA8, 0xBF, 0x03, 0x46, 0x18, 0x46, 0x01, 0xEB, 0xD1, 0x73, ++ 0xB0, 0xEB, 0x63, 0x0F, 0x4F, 0xEA, 0x63, 0x02, 0x00, 0xF3, 0x18, 0x81, ++ 0x52, 0x42, 0x82, 0x42, 0xC4, 0xBF, 0x0A, 0x9B, 0xC0, 0x18, 0x8F, 0x4B, ++ 0xD3, 0xF8, 0x6C, 0x31, 0x98, 0x47, 0x08, 0x9C, 0x8E, 0x4A, 0x94, 0xF8, ++ 0x4D, 0x30, 0x20, 0x65, 0x43, 0xF0, 0x20, 0x03, 0x01, 0x21, 0x84, 0xF8, ++ 0x4D, 0x30, 0x82, 0xF8, 0x31, 0x10, 0x1B, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, ++ 0xE4, 0xF7, 0x5C, 0xFF, 0x03, 0x19, 0x09, 0x93, 0x00, 0x2F, 0x7F, 0xF4, ++ 0xE4, 0xAE, 0xD9, 0xF8, 0x00, 0x20, 0xB2, 0xF9, 0x00, 0x20, 0x00, 0x2A, ++ 0x7B, 0xDB, 0x1A, 0xAB, 0x07, 0xEB, 0x87, 0x02, 0x70, 0x6A, 0x03, 0xEB, ++ 0x82, 0x02, 0x09, 0x9B, 0x42, 0xF8, 0x28, 0xBC, 0x00, 0xF5, 0x1C, 0x51, ++ 0x42, 0xE9, 0x09, 0x30, 0x10, 0x31, 0x42, 0xF8, 0x1C, 0x1C, 0xBC, 0x00, ++ 0x96, 0xF8, 0x63, 0x20, 0x3C, 0x44, 0x1A, 0xAB, 0x03, 0xEB, 0x84, 0x04, ++ 0x01, 0x23, 0x93, 0x40, 0x01, 0x37, 0x44, 0xF8, 0x18, 0x3C, 0x8F, 0xE6, ++ 0x03, 0x6C, 0xDB, 0x7E, 0xFF, 0x2B, 0x3F, 0xF4, 0x44, 0xAE, 0x90, 0xF8, ++ 0x63, 0x20, 0x9A, 0x42, 0x3F, 0xF4, 0x3F, 0xAE, 0x6E, 0x49, 0x6F, 0x48, ++ 0x40, 0xF2, 0xA7, 0x22, 0x08, 0xF0, 0x8E, 0xFB, 0x37, 0xE6, 0x08, 0x9A, ++ 0x6C, 0x49, 0x92, 0xF8, 0x6C, 0x20, 0x4F, 0xF4, 0x1E, 0x70, 0x00, 0xFB, ++ 0x02, 0x12, 0x6A, 0x48, 0x92, 0x68, 0x0A, 0x92, 0x1A, 0x7E, 0x02, 0x2A, ++ 0x02, 0xF1, 0x01, 0x03, 0x7F, 0xF4, 0x47, 0xAE, 0x03, 0x7E, 0xFF, 0x2B, ++ 0x40, 0xF0, 0xEE, 0x80, 0x01, 0x23, 0x4D, 0xE6, 0x06, 0x9B, 0x01, 0x2B, ++ 0x3F, 0xF6, 0xCF, 0xAE, 0x5D, 0x49, 0x61, 0x48, 0x40, 0xF2, 0xD3, 0x22, ++ 0x08, 0xF0, 0x6C, 0xFB, 0xC7, 0xE6, 0x5C, 0x4A, 0x96, 0xF8, 0x6C, 0x30, ++ 0x4F, 0xF4, 0x1E, 0x71, 0x01, 0xFB, 0x03, 0x23, 0xD3, 0xF8, 0x08, 0xB0, ++ 0x6A, 0xE6, 0xDA, 0xF8, 0x10, 0x20, 0x1D, 0x46, 0x5B, 0x1A, 0x9A, 0x1A, ++ 0x00, 0x2A, 0xF8, 0xDA, 0x1C, 0xE7, 0xDA, 0xF8, 0x10, 0x30, 0x0D, 0x44, ++ 0xEB, 0x1A, 0x00, 0x2B, 0xBF, 0xF6, 0x16, 0xAF, 0xDA, 0xF8, 0x10, 0x30, ++ 0x0D, 0x44, 0xEB, 0x1A, 0x00, 0x2B, 0xF2, 0xDB, 0x0E, 0xE7, 0x96, 0xF8, ++ 0x4E, 0x30, 0xFF, 0x2B, 0x3F, 0xF4, 0x38, 0xAF, 0x47, 0x49, 0x4F, 0xF4, ++ 0x58, 0x72, 0x40, 0x46, 0x08, 0xF0, 0x40, 0xFB, 0x30, 0xE7, 0x02, 0x2F, ++ 0x00, 0xF0, 0x98, 0x80, 0x1A, 0xAB, 0x07, 0xEB, 0x87, 0x02, 0x70, 0x6A, ++ 0x03, 0xEB, 0x82, 0x02, 0x09, 0x9B, 0x42, 0xF8, 0x28, 0xBC, 0x00, 0xF5, ++ 0x1C, 0x51, 0x42, 0xE9, 0x09, 0x30, 0x10, 0x31, 0x42, 0xF8, 0x1C, 0x1C, ++ 0xBC, 0x00, 0x96, 0xF8, 0x63, 0x20, 0x1F, 0x2A, 0x7F, 0xF6, 0x7E, 0xAF, ++ 0x37, 0x49, 0x3C, 0x48, 0x40, 0xF2, 0xED, 0x22, 0x08, 0xF0, 0x20, 0xFB, ++ 0x74, 0xE7, 0x3A, 0x4B, 0xDA, 0xF8, 0x10, 0x00, 0x19, 0x68, 0x0A, 0x9B, ++ 0x00, 0xEB, 0x41, 0x10, 0x9F, 0x42, 0x28, 0xBF, 0x1F, 0x46, 0x00, 0xF5, ++ 0x1C, 0x55, 0x10, 0x35, 0x3B, 0x46, 0x0E, 0xA9, 0x0E, 0x90, 0x20, 0x46, ++ 0x0F, 0x95, 0xFF, 0xF7, 0x17, 0xFD, 0x0E, 0x9E, 0x23, 0x68, 0x54, 0xF8, ++ 0x04, 0x5C, 0x9A, 0x1B, 0x00, 0x2A, 0x1D, 0x44, 0x62, 0x68, 0xA5, 0xF5, ++ 0xFA, 0x65, 0xB4, 0xBF, 0xB6, 0x1A, 0x3E, 0x1A, 0xAD, 0x1A, 0xE4, 0xF7, ++ 0x91, 0xFE, 0x00, 0xF5, 0x7A, 0x60, 0xA8, 0x42, 0x34, 0xDC, 0x54, 0xE9, ++ 0x02, 0x78, 0xE4, 0xF7, 0x89, 0xFE, 0xA7, 0xF5, 0x5A, 0x53, 0x30, 0x3B, ++ 0xA3, 0xEB, 0x08, 0x03, 0x07, 0x9A, 0xAD, 0x1B, 0x1B, 0x1A, 0x2B, 0x44, ++ 0xDA, 0xB1, 0x09, 0x9A, 0xAA, 0x42, 0x1F, 0xDB, 0x0B, 0x9A, 0x9A, 0x42, ++ 0x0A, 0xDD, 0x0A, 0x9A, 0x13, 0x44, 0x15, 0x44, 0x09, 0x9A, 0xAA, 0x42, ++ 0xFF, 0xF6, 0x83, 0xAE, 0x0B, 0x9A, 0x9A, 0x42, 0x3F, 0xF7, 0x7F, 0xAE, ++ 0x0B, 0x9A, 0xAA, 0x42, 0xB8, 0xBF, 0x2A, 0x46, 0x0B, 0x92, 0x09, 0x9A, ++ 0x9A, 0x42, 0xA8, 0xBF, 0x1A, 0x46, 0x09, 0x92, 0x73, 0xE6, 0x09, 0x93, ++ 0x01, 0x23, 0x0B, 0x95, 0x07, 0x93, 0x6E, 0xE6, 0x40, 0x1A, 0xEA, 0xE6, ++ 0x0A, 0x9A, 0xAD, 0x1A, 0x9B, 0x1A, 0xE1, 0xE7, 0xE4, 0xF7, 0x56, 0xFE, ++ 0x00, 0xF5, 0x7A, 0x65, 0xC5, 0xE7, 0x00, 0xBF, 0x88, 0x1A, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0x98, 0x9C, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x48, 0xA0, 0x15, 0x00, 0x68, 0x65, 0x17, 0x00, 0x90, 0x9D, 0x17, 0x00, ++ 0xD0, 0xA0, 0x15, 0x00, 0x00, 0xA1, 0x15, 0x00, 0x40, 0x80, 0x32, 0x40, ++ 0x00, 0x10, 0x50, 0x40, 0x10, 0xA1, 0x15, 0x00, 0x40, 0xF2, 0xE7, 0x22, ++ 0x14, 0x49, 0x15, 0x48, 0x08, 0xF0, 0x9E, 0xFA, 0xD9, 0xF8, 0x00, 0x20, ++ 0x09, 0x9B, 0xB2, 0xF9, 0x00, 0x20, 0xCD, 0xF8, 0x68, 0xB0, 0x1B, 0x93, ++ 0x73, 0x6A, 0x1C, 0x93, 0x03, 0xF5, 0x1C, 0x53, 0x10, 0x33, 0x00, 0x2A, ++ 0x1D, 0x93, 0x4F, 0xF0, 0x08, 0x04, 0xFF, 0xF6, 0x60, 0xAF, 0xDF, 0xE6, ++ 0x00, 0x23, 0x19, 0x46, 0x67, 0xE5, 0xD9, 0xF8, 0x00, 0x30, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0x05, 0xDA, 0x04, 0x49, 0x05, 0x48, 0x40, 0xF2, ++ 0xAE, 0x22, 0x08, 0xF0, 0x7B, 0xFA, 0x00, 0x23, 0x5B, 0x7E, 0xFF, 0xDE, ++ 0x70, 0x79, 0x15, 0x00, 0xE4, 0xA0, 0x15, 0x00, 0xC4, 0xA0, 0x15, 0x00, ++ 0x0A, 0x4B, 0x03, 0xF1, 0x54, 0x01, 0x1A, 0x7E, 0xFF, 0x2A, 0x02, 0xD0, ++ 0xDA, 0x7E, 0xFF, 0x2A, 0x04, 0xD1, 0x1C, 0x33, 0x8B, 0x42, 0xF6, 0xD1, ++ 0x00, 0x20, 0x70, 0x47, 0x04, 0x4B, 0x4F, 0xF4, 0xA4, 0x61, 0x01, 0xFB, ++ 0x02, 0x32, 0x02, 0x60, 0x01, 0x20, 0x70, 0x47, 0x90, 0x9D, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, 0x0E, 0x46, 0x85, 0xB0, ++ 0x14, 0x46, 0x05, 0x46, 0x00, 0x28, 0x54, 0xD0, 0x07, 0x46, 0x00, 0x2C, ++ 0x3A, 0xD0, 0xA3, 0x7A, 0xFF, 0x2B, 0x37, 0xD0, 0x3D, 0x4A, 0x23, 0x7A, ++ 0x4F, 0xF4, 0xA4, 0x61, 0x01, 0xFB, 0x03, 0x23, 0x93, 0xF8, 0x62, 0x20, ++ 0x00, 0x2A, 0x5E, 0xD0, 0x02, 0x2A, 0x52, 0xD0, 0x4F, 0xF4, 0x48, 0x4A, ++ 0x4F, 0xF4, 0xC8, 0x39, 0x60, 0x68, 0xDF, 0xF8, 0xE0, 0x80, 0x00, 0xF5, ++ 0x1C, 0x5B, 0xE4, 0xF7, 0xC9, 0xFD, 0x0B, 0xF1, 0x10, 0x0B, 0x03, 0x46, ++ 0xE1, 0x7A, 0xD8, 0xF8, 0xFC, 0x21, 0x28, 0x46, 0x9B, 0x44, 0x90, 0x47, ++ 0x83, 0x1B, 0x13, 0xEB, 0x0A, 0x0F, 0x05, 0xD5, 0xAA, 0xEB, 0x06, 0x03, ++ 0x48, 0x44, 0xC3, 0x42, 0xFC, 0xD4, 0x83, 0x1B, 0x00, 0x2B, 0x0B, 0xF5, ++ 0x0C, 0x53, 0xB8, 0xBF, 0x00, 0xF1, 0xFF, 0x36, 0x28, 0x33, 0x9B, 0x1B, ++ 0x00, 0x2B, 0x31, 0xDB, 0x0B, 0xF5, 0x7A, 0x60, 0x80, 0x1B, 0x06, 0xE0, ++ 0xE4, 0xF7, 0xA6, 0xFD, 0xDF, 0xF8, 0x8C, 0x80, 0x00, 0xF5, 0x5A, 0x50, ++ 0x30, 0x30, 0x00, 0x22, 0x01, 0x23, 0xCD, 0xE9, 0x01, 0x06, 0xD8, 0xF8, ++ 0x04, 0x42, 0x00, 0x92, 0x38, 0x46, 0x19, 0x46, 0xA0, 0x47, 0xFF, 0x38, ++ 0x18, 0xBF, 0x01, 0x20, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x17, 0x4B, ++ 0x03, 0xF1, 0x54, 0x01, 0x1A, 0x7E, 0xFF, 0x2A, 0x02, 0xD0, 0xDF, 0x7E, ++ 0xFF, 0x2F, 0x1C, 0xD1, 0x1C, 0x33, 0x99, 0x42, 0xF6, 0xD1, 0x00, 0x20, ++ 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xB3, 0xF8, 0xD2, 0x30, 0x4F, 0xEA, ++ 0x83, 0x29, 0x4F, 0xEA, 0x43, 0x2A, 0xA9, 0xE7, 0x41, 0xF2, 0x88, 0x30, ++ 0xD5, 0xE7, 0x93, 0xF8, 0x6C, 0x30, 0x0A, 0x4A, 0x4F, 0xF4, 0x1E, 0x71, ++ 0x01, 0xFB, 0x03, 0x23, 0xD3, 0xF8, 0x08, 0x90, 0x4F, 0xEA, 0x59, 0x0A, ++ 0x9A, 0xE7, 0x03, 0x4B, 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, 0x07, 0x37, ++ 0x7F, 0xE7, 0x00, 0xBF, 0x18, 0x88, 0x17, 0x00, 0x90, 0x9D, 0x17, 0x00, ++ 0x68, 0x65, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x70, 0xB5, 0x0C, 0x46, ++ 0x02, 0x7A, 0x17, 0x49, 0x23, 0x7A, 0x4F, 0xF4, 0xA4, 0x65, 0x05, 0xFB, ++ 0x02, 0x12, 0x05, 0xFB, 0x03, 0x13, 0x12, 0x6C, 0x1B, 0x6C, 0x9A, 0x42, ++ 0x0D, 0xD0, 0x45, 0x68, 0xE4, 0xF7, 0x4A, 0xFD, 0x64, 0x68, 0x06, 0x46, ++ 0xE4, 0xF7, 0x46, 0xFD, 0x2A, 0x1B, 0x06, 0xD4, 0x63, 0x1B, 0x00, 0x2B, ++ 0x0C, 0xDB, 0xA5, 0x42, 0x08, 0xD0, 0x00, 0x20, 0x70, 0xBD, 0xA4, 0xF5, ++ 0x5A, 0x53, 0x30, 0x3B, 0x5B, 0x1B, 0x9E, 0x1B, 0x00, 0x2E, 0xF1, 0xDA, ++ 0x01, 0x20, 0x70, 0xBD, 0xA2, 0xF5, 0x5A, 0x53, 0x30, 0x3B, 0x1B, 0x1A, ++ 0x00, 0x2B, 0xF7, 0xDB, 0xA5, 0x42, 0xEC, 0xD1, 0xF4, 0xE7, 0x00, 0xBF, ++ 0x18, 0x88, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, 0x07, 0x46, 0x83, 0xB0, ++ 0x0D, 0x46, 0x00, 0xF1, 0x44, 0x08, 0x91, 0x46, 0x22, 0xB9, 0x90, 0xF8, ++ 0x4D, 0x30, 0xDB, 0x07, 0x00, 0xF1, 0xA3, 0x80, 0xDF, 0xF8, 0x64, 0xA1, ++ 0xD7, 0xF8, 0x40, 0xB0, 0xDA, 0xF8, 0x20, 0x30, 0x00, 0x2B, 0x79, 0xD1, ++ 0xDA, 0xF8, 0x50, 0x30, 0x0B, 0xB1, 0x9B, 0x45, 0x2E, 0xD1, 0xBD, 0x64, ++ 0xE4, 0xF7, 0x0A, 0xFD, 0x05, 0xF5, 0x5A, 0x53, 0xDA, 0xF8, 0x10, 0x40, ++ 0x2F, 0x33, 0x1E, 0x18, 0x00, 0x2C, 0x00, 0xF0, 0x88, 0x80, 0xDF, 0xF8, ++ 0x38, 0xA1, 0x0B, 0xE0, 0xDA, 0xF8, 0xA0, 0x30, 0x98, 0x47, 0xD3, 0x46, ++ 0x40, 0xBB, 0x63, 0x68, 0xEB, 0x1A, 0x00, 0x2B, 0x08, 0xDB, 0x24, 0x68, ++ 0x00, 0x2C, 0x78, 0xD0, 0x63, 0x68, 0xF3, 0x1A, 0x00, 0x2B, 0x21, 0x46, ++ 0x40, 0x46, 0xED, 0xDA, 0x3F, 0x48, 0x42, 0x46, 0x21, 0x46, 0x06, 0xF0, ++ 0xD9, 0xFD, 0x97, 0xF8, 0x4D, 0x30, 0x43, 0xF0, 0x01, 0x03, 0x87, 0xF8, ++ 0x4D, 0x30, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xDA, 0xF8, 0x54, 0x60, ++ 0xE4, 0xF7, 0xDA, 0xFC, 0xAE, 0x1B, 0xA6, 0xF5, 0x7A, 0x66, 0x30, 0x1A, ++ 0xC4, 0x0F, 0x00, 0x2C, 0xC5, 0xD0, 0xDF, 0xF8, 0xDC, 0xB0, 0x00, 0x24, ++ 0x97, 0xF8, 0xC0, 0x34, 0x4B, 0xB1, 0x31, 0x4A, 0x97, 0xF8, 0xC1, 0x34, ++ 0x8C, 0x21, 0x01, 0xFB, 0x03, 0x23, 0x93, 0xF8, 0x70, 0x30, 0x01, 0x2B, ++ 0x1D, 0xD0, 0x97, 0xF8, 0x62, 0x30, 0xDB, 0xF8, 0x2C, 0x40, 0x7B, 0xB1, ++ 0x02, 0x2B, 0x0A, 0xBF, 0xB7, 0xF8, 0xD2, 0x10, 0x4F, 0xF4, 0xC8, 0x31, ++ 0x89, 0x02, 0x09, 0xF1, 0x01, 0x02, 0x29, 0x44, 0x38, 0x46, 0x23, 0x46, ++ 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x4F, 0x18, 0x47, 0x22, 0x4A, 0x97, 0xF8, ++ 0x6C, 0x30, 0x4F, 0xF4, 0x1E, 0x71, 0x01, 0xFB, 0x03, 0x23, 0x99, 0x68, ++ 0xED, 0xE7, 0xDB, 0xF8, 0x90, 0x30, 0x22, 0x46, 0x29, 0x46, 0x38, 0x46, ++ 0x98, 0x47, 0x97, 0xF8, 0x62, 0x30, 0xDB, 0xF8, 0x2C, 0x40, 0x00, 0x2B, ++ 0xDA, 0xD1, 0xE9, 0xE7, 0xDA, 0xF8, 0x24, 0x20, 0x01, 0x92, 0x56, 0x68, ++ 0xE4, 0xF7, 0x92, 0xFC, 0x01, 0x9A, 0x93, 0x68, 0x06, 0xF5, 0x7A, 0x66, ++ 0x9B, 0x45, 0x06, 0xEB, 0x00, 0x04, 0x0A, 0xD0, 0xE4, 0xF7, 0x88, 0xFC, ++ 0x01, 0x9A, 0xD3, 0x68, 0x04, 0xF5, 0x7A, 0x64, 0x04, 0x44, 0x13, 0xB1, ++ 0x04, 0xF5, 0x1C, 0x54, 0x10, 0x34, 0x2C, 0x1B, 0xE4, 0x0F, 0x00, 0x2C, ++ 0x3F, 0xF4, 0x6D, 0xAF, 0xA5, 0xE7, 0x00, 0x24, 0x8A, 0xE7, 0x05, 0x48, ++ 0x41, 0x46, 0x06, 0xF0, 0xD9, 0xFC, 0x97, 0xF8, 0x4D, 0x30, 0x23, 0xF0, ++ 0x01, 0x03, 0x87, 0xF8, 0x4D, 0x30, 0x51, 0xE7, 0x40, 0x9D, 0x17, 0x00, ++ 0x48, 0x9E, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, 0x30, 0x9D, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x47, 0x81, 0x46, 0x1A, 0x48, ++ 0x88, 0x46, 0x17, 0x46, 0x06, 0xF0, 0xB4, 0xFC, 0x18, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x04, 0x46, 0x0C, 0xDB, 0x16, 0x4D, ++ 0x28, 0x46, 0x21, 0x46, 0x50, 0xF8, 0x20, 0x6F, 0xE7, 0x60, 0xC4, 0xE9, ++ 0x01, 0x98, 0x06, 0xF0, 0x5F, 0xFC, 0x4E, 0xB1, 0xBD, 0xE8, 0xF0, 0x87, ++ 0x00, 0x28, 0xF0, 0xD1, 0x0F, 0x49, 0x10, 0x48, 0xD6, 0x22, 0x08, 0xF0, ++ 0xA9, 0xF8, 0xEA, 0xE7, 0x0E, 0x4B, 0x61, 0x68, 0x1B, 0x69, 0xAC, 0x64, ++ 0xCB, 0x1A, 0x14, 0x2B, 0x07, 0xD4, 0x0C, 0x4B, 0x05, 0xF1, 0x40, 0x00, ++ 0xD3, 0xF8, 0xE0, 0x31, 0xBD, 0xE8, 0xF0, 0x47, 0x18, 0x47, 0x6B, 0x6C, ++ 0x20, 0x46, 0xBD, 0xE8, 0xF0, 0x47, 0x18, 0x47, 0x48, 0x9D, 0x17, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x30, 0x9D, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x48, 0xA1, 0x15, 0x00, 0x00, 0x10, 0x50, 0x40, 0x88, 0x1A, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0xC1, 0x4B, 0xDF, 0xF8, 0x0C, 0x83, 0x1D, 0x69, ++ 0xD0, 0xF8, 0x40, 0x90, 0x2F, 0x7A, 0x6B, 0x68, 0x89, 0xB0, 0x4F, 0xF4, ++ 0xA4, 0x6A, 0xA3, 0xF5, 0x7A, 0x63, 0x0A, 0xFB, 0x07, 0x8B, 0x0C, 0x46, ++ 0x03, 0x92, 0x01, 0x93, 0x06, 0x46, 0xE4, 0xF7, 0x05, 0xFC, 0x01, 0x9B, ++ 0xDB, 0xF8, 0x40, 0x20, 0x1B, 0x1B, 0x1B, 0x1A, 0x4A, 0x45, 0x01, 0x93, ++ 0x66, 0xD0, 0x6B, 0x68, 0x02, 0x93, 0xE4, 0xF7, 0xF9, 0xFB, 0x02, 0x9B, ++ 0x99, 0xF8, 0x1B, 0x20, 0x04, 0x90, 0xA3, 0xF5, 0x7A, 0x63, 0x19, 0x1A, ++ 0xFF, 0x2A, 0x02, 0x91, 0x20, 0xD1, 0x96, 0xF8, 0x4E, 0x60, 0x05, 0x93, ++ 0xFF, 0x2E, 0x40, 0xF0, 0x8F, 0x80, 0x01, 0x9B, 0x03, 0x9A, 0x18, 0x46, ++ 0x10, 0x44, 0xB2, 0xEB, 0x50, 0x0F, 0x4F, 0xEA, 0x50, 0x03, 0x00, 0xF2, ++ 0xA9, 0x80, 0x03, 0x9A, 0xA4, 0x4E, 0xA4, 0x1A, 0x1C, 0x44, 0x4F, 0xF4, ++ 0xA4, 0x63, 0x03, 0xFB, 0x07, 0x87, 0x2A, 0x46, 0xD6, 0xF8, 0x88, 0x30, ++ 0x39, 0x6C, 0x20, 0x46, 0x98, 0x47, 0x09, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, ++ 0x0A, 0xFB, 0x02, 0x8A, 0x50, 0x46, 0x07, 0xAA, 0x06, 0xA9, 0xDB, 0xF8, ++ 0x40, 0x90, 0x01, 0x93, 0x03, 0xF0, 0xE8, 0xFB, 0x83, 0x46, 0x00, 0x28, ++ 0x00, 0xF0, 0x8C, 0x80, 0x07, 0x9C, 0x02, 0x99, 0x01, 0x9B, 0x0A, 0x1B, ++ 0x00, 0x2A, 0xC0, 0xF2, 0x41, 0x81, 0x06, 0x9A, 0xD1, 0x1A, 0x04, 0x9B, ++ 0xD9, 0x42, 0x7D, 0xD5, 0x14, 0x1B, 0xE4, 0xF7, 0xB1, 0xFB, 0x00, 0xF5, ++ 0x0C, 0x50, 0x28, 0x30, 0x84, 0x42, 0x40, 0xF2, 0x3B, 0x81, 0x8B, 0x4E, ++ 0x07, 0x98, 0xD6, 0xF8, 0x88, 0x30, 0x49, 0x46, 0x00, 0x22, 0x98, 0x47, ++ 0x06, 0x9C, 0xD6, 0xF8, 0x88, 0x90, 0xE4, 0xF7, 0x9F, 0xFB, 0xA4, 0xF5, ++ 0x7A, 0x64, 0x20, 0x1A, 0xDA, 0xF8, 0x40, 0x10, 0x02, 0x9C, 0x00, 0x22, ++ 0xC8, 0x47, 0xBA, 0xE7, 0xE4, 0xF7, 0x94, 0xFB, 0x01, 0x9B, 0xA3, 0xF5, ++ 0x7A, 0x62, 0x12, 0x1A, 0x41, 0xF2, 0x87, 0x33, 0x9A, 0x42, 0x01, 0x92, ++ 0xB9, 0xDD, 0x6F, 0x68, 0xE4, 0xF7, 0x88, 0xFB, 0x99, 0xF8, 0x1B, 0xB0, ++ 0x02, 0x97, 0x3B, 0x1A, 0xBB, 0xF1, 0xFF, 0x0F, 0x01, 0x9A, 0x04, 0x90, ++ 0xA3, 0xF5, 0x7A, 0x67, 0x70, 0xD0, 0x0A, 0xFB, 0x0B, 0x80, 0x07, 0xAA, ++ 0x06, 0xA9, 0x03, 0xF0, 0x9B, 0xFB, 0x00, 0x28, 0x40, 0xF0, 0xE6, 0x80, ++ 0xE4, 0xF7, 0x72, 0xFB, 0x06, 0x9E, 0xC6, 0xF5, 0x9C, 0x52, 0x08, 0x32, ++ 0x00, 0xF5, 0x7A, 0x60, 0x22, 0x44, 0x12, 0xEB, 0x40, 0x03, 0x00, 0xF1, ++ 0xF9, 0x80, 0xE4, 0xF7, 0x65, 0xFB, 0x07, 0x9C, 0x04, 0xF5, 0x0C, 0x53, ++ 0x28, 0x33, 0xDB, 0x1B, 0xC3, 0x42, 0x8C, 0xD5, 0x64, 0x4E, 0xDF, 0xF8, ++ 0x98, 0xA1, 0x5F, 0xE0, 0x07, 0xAA, 0x0A, 0xFB, 0x06, 0x80, 0x06, 0xA9, ++ 0x03, 0xF0, 0x78, 0xFB, 0x83, 0x46, 0xE4, 0xF7, 0x51, 0xFB, 0x06, 0x9A, ++ 0xA2, 0xF5, 0x7A, 0x62, 0x10, 0x1A, 0xDD, 0xE9, 0x04, 0x23, 0x06, 0x90, ++ 0xA2, 0xEB, 0x03, 0x0A, 0xBB, 0xF1, 0x00, 0x0F, 0x05, 0xD1, 0x02, 0x9B, ++ 0x10, 0xEB, 0x0A, 0x0F, 0x54, 0xBF, 0x1C, 0x46, 0x04, 0x46, 0xE4, 0xF7, ++ 0x3D, 0xFB, 0x07, 0x9B, 0x03, 0xF5, 0x0C, 0x53, 0x28, 0x33, 0x53, 0x44, ++ 0xC3, 0x42, 0x65, 0xD4, 0x50, 0x4E, 0x58, 0xE7, 0x06, 0x9E, 0x02, 0x9B, ++ 0x9A, 0x1B, 0x00, 0x2A, 0xF8, 0xDB, 0xE4, 0xF7, 0x2D, 0xFB, 0x00, 0xF5, ++ 0x0C, 0x50, 0x36, 0x1B, 0x28, 0x30, 0x86, 0x42, 0x49, 0x4E, 0x11, 0xD9, ++ 0x49, 0x46, 0x20, 0x46, 0x5A, 0x46, 0xD6, 0xF8, 0x88, 0x30, 0x98, 0x47, ++ 0x06, 0x9C, 0xD6, 0xF8, 0x88, 0x90, 0xE4, 0xF7, 0x1B, 0xFB, 0xA4, 0xF5, ++ 0x7A, 0x64, 0xDA, 0xF8, 0x40, 0x10, 0x20, 0x1A, 0x5A, 0x46, 0xC8, 0x47, ++ 0x07, 0x9C, 0x02, 0x9B, 0x1B, 0x1B, 0x00, 0x2B, 0xBF, 0xF6, 0x33, 0xAF, ++ 0x02, 0x9C, 0x30, 0xE7, 0x96, 0xF8, 0x4E, 0x00, 0x01, 0x93, 0xFF, 0x28, ++ 0x51, 0xD1, 0x03, 0x99, 0x0A, 0x44, 0xB1, 0xEB, 0x52, 0x0F, 0x4F, 0xEA, ++ 0x52, 0x03, 0xA1, 0xD8, 0x03, 0x9A, 0x35, 0x4E, 0xDF, 0xF8, 0xD8, 0xA0, ++ 0xA4, 0x1A, 0x1C, 0x44, 0x99, 0xF8, 0x18, 0x30, 0xD6, 0xF8, 0x88, 0x80, ++ 0x02, 0x2B, 0x03, 0xF1, 0x01, 0x01, 0x7B, 0xD0, 0xC1, 0xEB, 0xC1, 0x01, ++ 0x0A, 0xEB, 0x81, 0x01, 0x0A, 0x7E, 0xFF, 0x2A, 0x0E, 0xD1, 0x01, 0x2B, ++ 0x03, 0xF1, 0x02, 0x03, 0x08, 0xBF, 0x00, 0x23, 0xC3, 0xEB, 0xC3, 0x03, ++ 0x0A, 0xEB, 0x83, 0x0A, 0x9A, 0xF8, 0x18, 0x30, 0xFF, 0x2B, 0x14, 0xBF, ++ 0x51, 0x46, 0x00, 0x21, 0x20, 0x46, 0x00, 0x22, 0xC0, 0x47, 0xD6, 0xF8, ++ 0x88, 0x30, 0x2A, 0x46, 0x49, 0x46, 0x38, 0x46, 0x98, 0x47, 0x09, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x8F, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x06, 0x83, ++ 0x1B, 0x4E, 0x19, 0x6C, 0xD6, 0xF8, 0x88, 0x30, 0x20, 0x46, 0x00, 0x22, ++ 0x98, 0x47, 0xD6, 0xF8, 0x88, 0x30, 0x07, 0x98, 0x49, 0x46, 0x00, 0x22, ++ 0x98, 0x47, 0xBB, 0xF1, 0x00, 0x0F, 0xAD, 0xD0, 0x06, 0x9C, 0x02, 0x9B, ++ 0x1A, 0xEB, 0x04, 0x0F, 0x58, 0xBF, 0x1C, 0x46, 0xD9, 0xE6, 0x07, 0xAA, ++ 0x06, 0xA9, 0x0A, 0xFB, 0x00, 0x80, 0x03, 0xF0, 0xD3, 0xFA, 0x06, 0x9C, ++ 0xE4, 0xF7, 0xAC, 0xFA, 0x01, 0x9B, 0x1B, 0x1B, 0xC3, 0x42, 0x3F, 0xF5, ++ 0xD6, 0xAE, 0x06, 0x9C, 0x08, 0x4E, 0xDF, 0xF8, 0x28, 0xA0, 0xE4, 0xF7, ++ 0xA1, 0xFA, 0x07, 0x9B, 0xA4, 0xF5, 0x7A, 0x64, 0xFA, 0x1A, 0x24, 0x1A, ++ 0x17, 0xEA, 0x22, 0x07, 0x38, 0xBF, 0x1F, 0x46, 0x9C, 0xE7, 0x00, 0xBF, ++ 0x30, 0x9D, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0x90, 0x9D, 0x17, 0x00, 0xDD, 0xE9, 0x06, 0x64, 0xE4, 0xF7, 0x8A, 0xFA, ++ 0x02, 0x9B, 0x04, 0x9A, 0xF6, 0x1A, 0x32, 0x44, 0x13, 0x1A, 0x00, 0x2B, ++ 0x5B, 0xDB, 0xE4, 0xF7, 0x81, 0xFA, 0x3B, 0x1B, 0xA3, 0xF5, 0x0C, 0x53, ++ 0x28, 0x3B, 0x18, 0x1A, 0x00, 0x28, 0xBF, 0xF6, 0x1B, 0xAF, 0xA6, 0xE6, ++ 0x37, 0x4E, 0x67, 0xE7, 0x9A, 0xF8, 0x18, 0x30, 0xFF, 0x2B, 0x5F, 0xD1, ++ 0x01, 0x23, 0x89, 0xE7, 0x02, 0x9C, 0x37, 0xE7, 0xE4, 0xF7, 0x6C, 0xFA, ++ 0x02, 0x9B, 0xF6, 0x1A, 0x04, 0x9B, 0x33, 0x44, 0x1B, 0x1A, 0x00, 0x2B, ++ 0x4A, 0xDB, 0x01, 0x97, 0xE4, 0xF7, 0x62, 0xFA, 0x07, 0x9B, 0x03, 0xF5, ++ 0x0C, 0x53, 0x28, 0x33, 0xDB, 0x1B, 0xC3, 0x42, 0x4A, 0xD5, 0x4F, 0xF4, ++ 0xA4, 0x63, 0x03, 0xFB, 0x0B, 0x83, 0x27, 0x4E, 0x1A, 0x6C, 0xDF, 0xF8, ++ 0x9C, 0xA0, 0x11, 0x7E, 0xD6, 0xF8, 0x88, 0x30, 0x02, 0x29, 0x01, 0xF1, ++ 0x01, 0x02, 0x2B, 0xD0, 0xC2, 0xEB, 0xC2, 0x00, 0x0A, 0xEB, 0x80, 0x00, ++ 0x00, 0x7E, 0xFF, 0x28, 0x37, 0xD1, 0x01, 0x29, 0x01, 0xF1, 0x02, 0x02, ++ 0x08, 0xBF, 0x00, 0x22, 0xC2, 0xEB, 0xC2, 0x01, 0x0A, 0xEB, 0x81, 0x01, ++ 0x09, 0x7E, 0xFF, 0x29, 0x08, 0xBF, 0x00, 0x21, 0x29, 0xD1, 0x20, 0x46, ++ 0x00, 0x22, 0x98, 0x47, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x0B, 0x88, ++ 0x01, 0x98, 0xD8, 0xF8, 0x40, 0x10, 0xD6, 0xF8, 0x88, 0x30, 0x00, 0x22, ++ 0x98, 0x47, 0x07, 0x9C, 0x2C, 0xE7, 0x06, 0x9E, 0xE4, 0xF7, 0x24, 0xFA, ++ 0xA6, 0xF5, 0x7A, 0x66, 0x37, 0x1A, 0x9C, 0xE7, 0x9A, 0xF8, 0x18, 0x20, ++ 0xFF, 0x2A, 0x0D, 0xD1, 0x01, 0x22, 0xD9, 0xE7, 0x06, 0x9E, 0xE4, 0xF7, ++ 0x17, 0xFA, 0xA6, 0xF5, 0x7A, 0x66, 0x33, 0x1A, 0x01, 0x93, 0xAD, 0xE7, ++ 0x05, 0x49, 0x33, 0xE7, 0x01, 0x9F, 0xAF, 0xE6, 0x00, 0x22, 0x1C, 0x21, ++ 0x01, 0xFB, 0x02, 0xA1, 0xD1, 0xE7, 0x00, 0xBF, 0x88, 0x1A, 0x17, 0x00, ++ 0x90, 0x9D, 0x17, 0x00, 0x30, 0xB5, 0x0E, 0x48, 0x83, 0xB0, 0x06, 0xF0, ++ 0x59, 0xFA, 0x01, 0x90, 0xA0, 0xB1, 0x0C, 0x4B, 0x0C, 0x4C, 0xD3, 0xF8, ++ 0xD8, 0x31, 0x0C, 0x48, 0x98, 0x47, 0x00, 0x23, 0x01, 0x99, 0xA3, 0x64, ++ 0x04, 0xF1, 0x18, 0x05, 0x20, 0x34, 0x28, 0x46, 0x06, 0xF0, 0x04, 0xFA, ++ 0x20, 0x46, 0x06, 0xF0, 0x45, 0xFA, 0x01, 0x46, 0x00, 0x28, 0xF6, 0xD1, ++ 0x03, 0xB0, 0x30, 0xBD, 0x50, 0x9D, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x30, 0x9D, 0x17, 0x00, 0x70, 0x9D, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0x4C, 0x4B, 0x42, 0x69, 0x1F, 0x69, 0x4C, 0x4B, 0x4C, 0x4C, 0x98, 0x42, ++ 0x83, 0xB0, 0x05, 0x46, 0x17, 0x44, 0x6F, 0xD0, 0xA3, 0x6A, 0xAB, 0x42, ++ 0x04, 0xD0, 0xE4, 0xF7, 0xCD, 0xF9, 0x07, 0xF5, 0x7A, 0x67, 0x07, 0x44, ++ 0x94, 0xF8, 0x5B, 0x80, 0x94, 0xF8, 0x58, 0x30, 0xC4, 0xE9, 0x14, 0x57, ++ 0xB8, 0xF1, 0x00, 0x0F, 0x57, 0xD1, 0x42, 0x4E, 0x23, 0xF0, 0x40, 0x03, ++ 0x84, 0xF8, 0x58, 0x30, 0x73, 0x6B, 0x98, 0x47, 0xD6, 0xF8, 0x88, 0x30, ++ 0x42, 0x46, 0x41, 0x46, 0x38, 0x46, 0x98, 0x47, 0xD4, 0xF8, 0x10, 0xB0, ++ 0xBB, 0xF1, 0x00, 0x0F, 0x3A, 0xD0, 0x3A, 0x4B, 0xDF, 0xF8, 0xF8, 0x90, ++ 0xDB, 0x1B, 0x01, 0x93, 0x4F, 0xF4, 0xA4, 0x68, 0x0C, 0xE0, 0x02, 0x2A, ++ 0x04, 0xBF, 0xB0, 0xF8, 0xD2, 0x20, 0x91, 0x02, 0x61, 0x44, 0x00, 0x22, ++ 0x98, 0x47, 0xD4, 0xF8, 0x10, 0xB0, 0xBB, 0xF1, 0x00, 0x0F, 0x25, 0xD0, ++ 0xDB, 0xF8, 0x04, 0xA0, 0xE4, 0xF7, 0x96, 0xF9, 0x01, 0x9B, 0xAA, 0xEB, ++ 0x00, 0x00, 0xD8, 0x42, 0x1C, 0xD5, 0x9B, 0xF8, 0x08, 0x00, 0xDB, 0xF8, ++ 0x04, 0xC0, 0xF3, 0x6A, 0x08, 0xFB, 0x00, 0x90, 0x4F, 0xF4, 0xC8, 0x31, ++ 0x90, 0xF8, 0x62, 0x20, 0x00, 0x2A, 0xDC, 0xD1, 0x90, 0xF8, 0x6C, 0x20, ++ 0x24, 0x4F, 0x4F, 0xF4, 0x1E, 0x71, 0x01, 0xFB, 0x02, 0x72, 0x91, 0x68, ++ 0x00, 0x22, 0x61, 0x44, 0x98, 0x47, 0xD4, 0xF8, 0x10, 0xB0, 0xBB, 0xF1, ++ 0x00, 0x0F, 0xD9, 0xD1, 0xE3, 0x6A, 0xD3, 0xB1, 0x1D, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x1B, 0xDB, 0x03, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x8F, 0x43, 0xF0, 0x40, 0x03, 0x84, 0xF8, 0x58, 0x30, 0x03, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x8F, 0x94, 0xF8, 0x58, 0x30, 0x5A, 0x07, 0x8B, 0xD4, ++ 0x23, 0xF0, 0x40, 0x03, 0x84, 0xF8, 0x58, 0x30, 0x03, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x8F, 0xD6, 0xF8, 0x9C, 0x30, 0x28, 0x46, 0x03, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x4F, 0x18, 0x47, 0x94, 0xF8, 0x58, 0x30, 0x13, 0xF0, 0x0C, 0x0F, ++ 0xDE, 0xD1, 0x0B, 0x49, 0x0B, 0x48, 0x40, 0xF2, 0x86, 0x62, 0x03, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x4F, 0x07, 0xF0, 0xAC, 0xBD, 0x00, 0x10, 0x50, 0x40, ++ 0x00, 0x9E, 0x17, 0x00, 0x30, 0x9D, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x60, 0xF0, 0xFF, 0xFF, 0x68, 0x65, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x5C, 0xA1, 0x15, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0x10, 0xB5, 0x22, 0x4C, 0x94, 0xF8, 0x58, 0x30, 0xD8, 0x07, 0x11, 0xD5, ++ 0x20, 0x4A, 0x12, 0x68, 0xB2, 0xF9, 0x00, 0x20, 0x00, 0x2A, 0x22, 0xDB, ++ 0x23, 0xF0, 0x01, 0x03, 0x43, 0xF0, 0x04, 0x03, 0x84, 0xF8, 0x58, 0x30, ++ 0x1B, 0x4B, 0x1C, 0x48, 0xDB, 0x6D, 0xBD, 0xE8, 0x10, 0x40, 0x18, 0x47, ++ 0x03, 0xF0, 0x06, 0x02, 0x02, 0x2A, 0x11, 0xD1, 0x15, 0x4A, 0x12, 0x68, ++ 0xB2, 0xF9, 0x00, 0x20, 0x00, 0x2A, 0x17, 0xDB, 0x23, 0xF0, 0x02, 0x03, ++ 0x43, 0xF0, 0x08, 0x03, 0x84, 0xF8, 0x58, 0x30, 0x10, 0x4B, 0x12, 0x48, ++ 0xDB, 0x6D, 0xBD, 0xE8, 0x10, 0x40, 0x18, 0x47, 0x10, 0xBD, 0x59, 0x07, ++ 0xDA, 0xD5, 0x0F, 0x49, 0x0F, 0x48, 0x40, 0xF2, 0x9B, 0x62, 0x07, 0xF0, ++ 0x61, 0xFD, 0x94, 0xF8, 0x58, 0x30, 0xD1, 0xE7, 0x1A, 0x07, 0xE5, 0xD5, ++ 0x09, 0x49, 0x0B, 0x48, 0x40, 0xF2, 0xA6, 0x62, 0x07, 0xF0, 0x56, 0xFD, ++ 0x94, 0xF8, 0x58, 0x30, 0xDC, 0xE7, 0x00, 0xBF, 0x30, 0x9D, 0x17, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x00, 0x9E, 0x17, 0x00, ++ 0xE4, 0x9D, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x8C, 0xA1, 0x15, 0x00, ++ 0xC0, 0xA1, 0x15, 0x00, 0x0D, 0x4A, 0x92, 0xF8, 0x58, 0x30, 0xD9, 0x06, ++ 0x14, 0xD4, 0x92, 0xF8, 0x5A, 0x00, 0x43, 0xF0, 0x10, 0x03, 0x82, 0xF8, ++ 0x58, 0x30, 0x50, 0xB1, 0x08, 0x49, 0x09, 0x4B, 0x09, 0x69, 0xD3, 0xF8, ++ 0xE0, 0x31, 0x01, 0xF5, 0xEA, 0x41, 0x02, 0xF1, 0x30, 0x00, 0x30, 0x31, ++ 0x18, 0x47, 0x04, 0x4B, 0xDB, 0x6B, 0x18, 0x47, 0x70, 0x47, 0x00, 0xBF, ++ 0x30, 0x9D, 0x17, 0x00, 0x00, 0x10, 0x50, 0x40, 0x88, 0x1A, 0x17, 0x00, ++ 0x70, 0xB5, 0x32, 0x4C, 0x00, 0x23, 0x05, 0x46, 0xA3, 0x62, 0xEF, 0xF3, ++ 0x10, 0x83, 0xDA, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x2E, 0x4B, 0x01, 0x22, ++ 0x1A, 0x60, 0x2E, 0x4A, 0x2E, 0x4E, 0x11, 0x68, 0x73, 0x68, 0x48, 0x1C, ++ 0x23, 0xF0, 0x02, 0x03, 0x10, 0x60, 0x73, 0x60, 0x18, 0xB1, 0x28, 0x4B, ++ 0x11, 0x60, 0x1B, 0x68, 0xF9, 0xB1, 0x29, 0x49, 0x94, 0xF8, 0x5C, 0x30, ++ 0x0A, 0x68, 0x9B, 0x00, 0x22, 0xF0, 0x04, 0x02, 0x03, 0xF0, 0x04, 0x03, ++ 0x13, 0x43, 0x0B, 0x60, 0x2B, 0x7E, 0x03, 0x2B, 0x26, 0xD0, 0x04, 0x2B, ++ 0x94, 0xF8, 0x58, 0x30, 0x19, 0xD0, 0x23, 0xF0, 0x10, 0x02, 0xFF, 0x21, ++ 0x9B, 0x07, 0x29, 0x76, 0x84, 0xF8, 0x58, 0x20, 0x02, 0xD0, 0x1D, 0x4B, ++ 0x1B, 0x6C, 0x98, 0x47, 0xE3, 0x6A, 0x23, 0xB1, 0x70, 0xBD, 0x00, 0x2B, ++ 0xDD, 0xD0, 0x62, 0xB6, 0xDB, 0xE7, 0x18, 0x4B, 0xD3, 0xF8, 0xA4, 0x31, ++ 0x98, 0x47, 0xBD, 0xE8, 0x70, 0x40, 0xFB, 0xF7, 0x93, 0xBA, 0x23, 0xF0, ++ 0x04, 0x02, 0x84, 0xF8, 0x58, 0x20, 0xEA, 0x89, 0x92, 0xB9, 0x03, 0xF0, ++ 0xDB, 0x03, 0xDC, 0xE7, 0x94, 0xF8, 0x58, 0x30, 0x23, 0xF0, 0x08, 0x03, ++ 0x84, 0xF8, 0x58, 0x30, 0xFE, 0xF7, 0x84, 0xFE, 0xFF, 0x22, 0x02, 0x21, ++ 0x86, 0x20, 0x05, 0xF0, 0x49, 0xFC, 0x94, 0xF8, 0x58, 0x30, 0xCC, 0xE7, ++ 0x28, 0x46, 0xFE, 0xF7, 0xB1, 0xFE, 0x94, 0xF8, 0x58, 0x30, 0xC6, 0xE7, ++ 0x30, 0x9D, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x1C, 0x9E, 0x17, 0x00, 0x4C, 0x00, 0x32, 0x40, 0x88, 0x1A, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x41, 0x6B, 0x4F, 0x6C, 0x4E, 0x04, 0x46, 0x6C, 0x48, ++ 0x06, 0xF0, 0x96, 0xF8, 0x3B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0x05, 0x46, 0xC0, 0xF2, 0x85, 0x80, 0x33, 0x78, 0x00, 0x2B, 0x44, 0xD0, ++ 0x66, 0x4C, 0x01, 0x2B, 0x42, 0xD1, 0x94, 0xF8, 0x58, 0x30, 0x19, 0x07, ++ 0x00, 0xF1, 0x9D, 0x80, 0x5A, 0x07, 0x40, 0xF1, 0xB0, 0x80, 0x62, 0x4F, ++ 0xE3, 0x6A, 0xBB, 0x42, 0x02, 0xD0, 0x0B, 0xB1, 0x01, 0x22, 0x1A, 0x74, ++ 0xA3, 0x6A, 0x0B, 0xB1, 0x01, 0x22, 0x1A, 0x74, 0x00, 0x23, 0xC4, 0xE9, ++ 0x0A, 0x73, 0x39, 0x7E, 0x04, 0x23, 0x03, 0x29, 0x3B, 0x74, 0x00, 0xF0, ++ 0xA0, 0x80, 0x02, 0x29, 0x24, 0xD9, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, ++ 0x03, 0xD4, 0x72, 0xB6, 0x55, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x55, 0x4A, ++ 0x55, 0x48, 0x17, 0x68, 0x43, 0x68, 0x79, 0x1C, 0x43, 0xF0, 0x02, 0x03, ++ 0x11, 0x60, 0x43, 0x60, 0x29, 0xB1, 0x4F, 0x4B, 0x17, 0x60, 0x1B, 0x68, ++ 0x0F, 0xB9, 0x03, 0xB1, 0x62, 0xB6, 0x4F, 0x4A, 0xA3, 0x6A, 0x11, 0x68, ++ 0xC1, 0xF3, 0x80, 0x01, 0x84, 0xF8, 0x5C, 0x10, 0x11, 0x68, 0x21, 0xF0, ++ 0x04, 0x01, 0x11, 0x60, 0x01, 0xE0, 0x44, 0x4C, 0xA3, 0x6A, 0x01, 0x22, ++ 0x1A, 0x74, 0x22, 0x6D, 0x00, 0x23, 0x33, 0x70, 0x00, 0x2A, 0x31, 0xD0, ++ 0x94, 0xF8, 0x5A, 0x20, 0x23, 0x65, 0x00, 0x2A, 0x53, 0xD0, 0x01, 0x2A, ++ 0x53, 0xD0, 0x23, 0x69, 0x00, 0x2B, 0x50, 0xD0, 0x1B, 0x7A, 0x40, 0x4A, ++ 0x4F, 0xF4, 0xA4, 0x61, 0x01, 0xFB, 0x03, 0x23, 0x18, 0x6C, 0xA8, 0x60, ++ 0x18, 0xB1, 0x3D, 0x4B, 0xD3, 0xF8, 0x9C, 0x30, 0x98, 0x47, 0x3C, 0x48, ++ 0x29, 0x46, 0x05, 0xF0, 0xDF, 0xFF, 0xA0, 0x6A, 0x03, 0x7E, 0x02, 0x2B, ++ 0x02, 0xD9, 0x37, 0x4B, 0x9B, 0x6B, 0x98, 0x47, 0x20, 0x6A, 0xA0, 0x64, ++ 0x58, 0xB3, 0x36, 0x4B, 0x41, 0x68, 0x1B, 0x69, 0xCB, 0x1A, 0x14, 0x2B, ++ 0x27, 0xD4, 0x31, 0x4B, 0x33, 0x48, 0xD3, 0xF8, 0xE0, 0x31, 0xBD, 0xE8, ++ 0xF0, 0x41, 0x18, 0x47, 0xA8, 0x68, 0xDD, 0xE7, 0x84, 0x42, 0x32, 0xD0, ++ 0x2F, 0x49, 0x30, 0x48, 0x40, 0xF2, 0x4F, 0x72, 0x07, 0xF0, 0x12, 0xFC, ++ 0x33, 0x78, 0x00, 0x2B, 0x7F, 0xF4, 0x72, 0xAF, 0x3B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0xB1, 0xDA, 0x1D, 0x4C, 0xA3, 0x6A, 0x00, 0x2B, ++ 0xAF, 0xD1, 0x26, 0x49, 0x27, 0x48, 0x40, 0xF2, 0x51, 0x72, 0x07, 0xF0, ++ 0xFF, 0xFB, 0x33, 0x78, 0x61, 0xE7, 0xBD, 0xE8, 0xF0, 0x81, 0x63, 0x6C, ++ 0xBD, 0xE8, 0xF0, 0x41, 0x18, 0x47, 0x22, 0x4F, 0x64, 0xE7, 0xAA, 0x60, ++ 0xBB, 0xE7, 0x21, 0x48, 0x02, 0x7E, 0xFF, 0x2A, 0xB1, 0xD1, 0x90, 0xF8, ++ 0x34, 0x20, 0xFF, 0x2A, 0x12, 0xD1, 0x90, 0xF8, 0x50, 0x20, 0xFF, 0x2A, ++ 0x10, 0xD1, 0xAB, 0x60, 0xAD, 0xE7, 0x33, 0x78, 0x00, 0x2B, 0xD8, 0xD0, ++ 0x44, 0xE7, 0xE7, 0x6A, 0x00, 0x2F, 0x87, 0xD0, 0x52, 0xE7, 0x02, 0x20, ++ 0x05, 0xF0, 0xF2, 0xFC, 0x39, 0x7E, 0x5A, 0xE7, 0x1C, 0x30, 0x98, 0xE7, ++ 0x38, 0x30, 0x96, 0xE7, 0x38, 0x36, 0x17, 0x00, 0x17, 0x2C, 0x17, 0x00, ++ 0x50, 0x9D, 0x17, 0x00, 0x30, 0x9D, 0x17, 0x00, 0x00, 0x9E, 0x17, 0x00, ++ 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0x1C, 0x9E, 0x17, 0x00, ++ 0x4C, 0x00, 0x32, 0x40, 0x18, 0x88, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x48, 0x9D, 0x17, 0x00, 0x00, 0x10, 0x50, 0x40, 0x70, 0x9D, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xF4, 0xA1, 0x15, 0x00, 0x10, 0xA2, 0x15, 0x00, ++ 0xE4, 0x9D, 0x17, 0x00, 0x90, 0x9D, 0x17, 0x00, 0x0D, 0x4B, 0x93, 0xF8, ++ 0x58, 0x20, 0x11, 0x07, 0x03, 0xD4, 0x52, 0x07, 0x0D, 0xD5, 0x0B, 0x49, ++ 0x00, 0xE0, 0x0B, 0x49, 0xDA, 0x6A, 0x8A, 0x42, 0x03, 0xD0, 0x0A, 0xB1, ++ 0x01, 0x20, 0x10, 0x74, 0xD9, 0x62, 0x08, 0x4B, 0xD3, 0xF8, 0x98, 0x30, ++ 0x18, 0x47, 0xDB, 0x6A, 0x00, 0x2B, 0xF8, 0xD1, 0x05, 0x49, 0x08, 0x20, ++ 0x07, 0xF0, 0x68, 0xB9, 0x30, 0x9D, 0x17, 0x00, 0x00, 0x9E, 0x17, 0x00, ++ 0xE4, 0x9D, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x28, 0xA2, 0x15, 0x00, ++ 0x0B, 0x4A, 0x92, 0xF8, 0x59, 0x30, 0x43, 0xB1, 0x01, 0x3B, 0xDB, 0xB2, ++ 0x82, 0xF8, 0x59, 0x30, 0x1B, 0xB9, 0x08, 0x4A, 0x11, 0x78, 0x01, 0x29, ++ 0x00, 0xD0, 0x70, 0x47, 0x10, 0xB5, 0x06, 0x4C, 0x13, 0x70, 0xD4, 0xF8, ++ 0xA4, 0x31, 0x98, 0x47, 0xE3, 0x6F, 0xBD, 0xE8, 0x10, 0x40, 0x18, 0x47, ++ 0x30, 0x9D, 0x17, 0x00, 0x17, 0x2C, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0xF8, 0xB5, 0x1D, 0x4B, 0x1D, 0x49, 0x1E, 0x4A, 0xD3, 0xF8, 0xE0, 0x33, ++ 0x8C, 0x68, 0x95, 0x6A, 0x98, 0x47, 0x1C, 0x4B, 0x5B, 0x78, 0x23, 0xB1, ++ 0x1B, 0x4A, 0x13, 0x68, 0x23, 0xF0, 0x00, 0x43, 0x13, 0x60, 0x1A, 0x4A, ++ 0x13, 0x68, 0x23, 0xF0, 0x04, 0x03, 0x13, 0x60, 0x1C, 0xB3, 0x18, 0x4F, ++ 0x8C, 0x26, 0x01, 0xE0, 0x24, 0x68, 0xF4, 0xB1, 0x23, 0x6C, 0xAB, 0x42, ++ 0xFA, 0xD1, 0x94, 0xF8, 0x62, 0x30, 0x00, 0x2B, 0xF6, 0xD1, 0x94, 0xF8, ++ 0x64, 0x30, 0x00, 0x2B, 0xF2, 0xD0, 0x94, 0xF8, 0xC0, 0x34, 0x00, 0x22, ++ 0x11, 0x46, 0x3B, 0xB1, 0x94, 0xF8, 0xC1, 0x34, 0x06, 0xFB, 0x03, 0x73, ++ 0x93, 0xF8, 0x85, 0x30, 0x00, 0x2B, 0xE5, 0xD0, 0x94, 0xF8, 0x6C, 0x00, ++ 0xF2, 0xF7, 0xD6, 0xFD, 0x24, 0x68, 0x00, 0x2C, 0xE0, 0xD1, 0xF8, 0xBD, ++ 0x88, 0x1A, 0x17, 0x00, 0x00, 0x88, 0x17, 0x00, 0x30, 0x9D, 0x17, 0x00, ++ 0x4C, 0x36, 0x17, 0x00, 0x34, 0x04, 0x32, 0x40, 0x4C, 0x00, 0x32, 0x40, ++ 0x48, 0x9E, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, 0xDF, 0xF8, 0x08, 0x81, ++ 0x3D, 0x4A, 0x3E, 0x4E, 0xD8, 0xF8, 0xDC, 0x33, 0x94, 0x68, 0x96, 0xF8, ++ 0x59, 0x90, 0x83, 0xB0, 0x98, 0x47, 0xB5, 0x6A, 0x00, 0x2D, 0x5E, 0xD0, ++ 0x39, 0x4A, 0x3A, 0x49, 0x13, 0x68, 0x43, 0xF0, 0x04, 0x03, 0x13, 0x60, ++ 0x4B, 0x78, 0x4F, 0x46, 0x00, 0x2B, 0x4D, 0xD1, 0x00, 0x2C, 0x3A, 0xD0, ++ 0xDF, 0xF8, 0xD8, 0xB0, 0xDF, 0xF8, 0xD8, 0xA0, 0x4F, 0xF0, 0x06, 0x09, ++ 0x01, 0xE0, 0x24, 0x68, 0x7C, 0xB3, 0x23, 0x6C, 0x9D, 0x42, 0xFA, 0xD1, ++ 0x94, 0xF8, 0x62, 0x30, 0x00, 0x2B, 0xF6, 0xD1, 0x94, 0xF8, 0x64, 0x30, ++ 0x00, 0x2B, 0xF2, 0xD0, 0x94, 0xF8, 0x6C, 0x00, 0xFF, 0x28, 0x4F, 0xF0, ++ 0x8C, 0x01, 0x4F, 0xF0, 0x00, 0x02, 0xEA, 0xD0, 0x94, 0xF8, 0xC0, 0x34, ++ 0x3B, 0xB1, 0x94, 0xF8, 0xC1, 0x34, 0x01, 0xFB, 0x03, 0xA3, 0x93, 0xF8, ++ 0x85, 0x30, 0x00, 0x2B, 0xDF, 0xD0, 0x2B, 0x7C, 0x85, 0xF8, 0x10, 0x90, ++ 0xD8, 0xF8, 0xB0, 0x10, 0x01, 0x93, 0xF2, 0xF7, 0x79, 0xFD, 0x01, 0x9B, ++ 0x00, 0xB9, 0x01, 0x37, 0x01, 0x22, 0x2B, 0x74, 0x8B, 0xF8, 0x00, 0x20, ++ 0x24, 0x68, 0x00, 0x2C, 0xCF, 0xD1, 0x5F, 0xFA, 0x87, 0xF9, 0x96, 0xF8, ++ 0x59, 0x40, 0xF5, 0x6A, 0x86, 0xF8, 0x59, 0x90, 0x3C, 0x1B, 0xAD, 0xB1, ++ 0x27, 0xB1, 0x03, 0x23, 0x2B, 0x74, 0xD8, 0xF8, 0x60, 0x31, 0x98, 0x47, ++ 0x20, 0x46, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xD2, 0xF8, 0xE8, 0x33, ++ 0x43, 0xF0, 0x00, 0x43, 0xC2, 0xF8, 0xE8, 0x33, 0xAA, 0xE7, 0x00, 0x24, ++ 0x20, 0x46, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xD8, 0xF8, 0x60, 0x31, ++ 0x98, 0x47, 0x00, 0x2F, 0xF5, 0xD0, 0x96, 0xF8, 0x59, 0x30, 0x01, 0x3B, ++ 0x2C, 0x46, 0x86, 0xF8, 0x59, 0x30, 0xE3, 0xE7, 0x00, 0x88, 0x17, 0x00, ++ 0x30, 0x9D, 0x17, 0x00, 0x4C, 0x00, 0x32, 0x40, 0x4C, 0x36, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x17, 0x2C, 0x17, 0x00, 0x48, 0x9E, 0x17, 0x00, ++ 0x10, 0xB5, 0x06, 0x4C, 0xD4, 0xF8, 0xA4, 0x31, 0x98, 0x47, 0xA3, 0x6E, ++ 0x98, 0x47, 0x18, 0xB9, 0xE3, 0x6F, 0xBD, 0xE8, 0x10, 0x40, 0x18, 0x47, ++ 0x10, 0xBD, 0x00, 0xBF, 0x88, 0x1A, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x43, ++ 0x4D, 0x4E, 0x4E, 0x4F, 0xF4, 0x6A, 0x85, 0xB0, 0x00, 0x25, 0xE2, 0x88, ++ 0x61, 0x79, 0x23, 0x89, 0x20, 0x79, 0x02, 0x95, 0x65, 0x7B, 0x01, 0x95, ++ 0x65, 0x89, 0x00, 0x95, 0xE3, 0xF7, 0x72, 0xFD, 0xD7, 0xF8, 0x3C, 0x33, ++ 0x94, 0xF9, 0x0C, 0x00, 0x98, 0x47, 0x21, 0x79, 0x44, 0x4B, 0x45, 0x4A, ++ 0x03, 0xEB, 0x81, 0x03, 0x5B, 0x69, 0x13, 0x60, 0x23, 0x7E, 0x03, 0x2B, ++ 0x02, 0xD0, 0x20, 0x46, 0xFE, 0xF7, 0xFE, 0xFB, 0xB3, 0x6A, 0x0B, 0xB1, ++ 0x01, 0x22, 0x1A, 0x74, 0x00, 0x23, 0xC6, 0xE9, 0x0A, 0x43, 0x23, 0x7E, ++ 0x04, 0x22, 0x02, 0x2B, 0x22, 0x74, 0x4E, 0xD9, 0x96, 0xF8, 0x5A, 0x20, ++ 0x00, 0x2A, 0x4A, 0xD0, 0x03, 0x2B, 0x52, 0xD0, 0x04, 0x2B, 0x24, 0xD0, ++ 0xFB, 0x6E, 0x98, 0x47, 0x23, 0x7E, 0x02, 0x2B, 0x1F, 0xD8, 0x34, 0x4B, ++ 0x9D, 0x68, 0x00, 0x2D, 0x37, 0xD0, 0xDF, 0xF8, 0xE4, 0x90, 0x4F, 0xF0, ++ 0x01, 0x08, 0x01, 0xE0, 0x2D, 0x68, 0x8D, 0xB1, 0x2B, 0x6C, 0xA3, 0x42, ++ 0xFA, 0xD1, 0x95, 0xF8, 0x63, 0x30, 0xD7, 0xF8, 0x5C, 0x24, 0xC3, 0xEB, ++ 0xC3, 0x03, 0x09, 0xEB, 0x83, 0x03, 0x28, 0x46, 0x83, 0xF8, 0x1B, 0x80, ++ 0x90, 0x47, 0x2D, 0x68, 0x00, 0x2D, 0xED, 0xD1, 0x23, 0x7E, 0x02, 0x2B, ++ 0x1B, 0xD9, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, ++ 0x22, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x22, 0x4A, 0x22, 0x4C, 0x11, 0x68, ++ 0x63, 0x68, 0x48, 0x1C, 0x43, 0xF0, 0x02, 0x03, 0x10, 0x60, 0x63, 0x60, ++ 0x28, 0xBB, 0x1F, 0x4B, 0x19, 0x68, 0x1A, 0x68, 0xC1, 0xF3, 0x80, 0x01, ++ 0x22, 0xF0, 0x04, 0x02, 0x86, 0xF8, 0x5C, 0x10, 0x1A, 0x60, 0xD7, 0xF8, ++ 0x60, 0x31, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x43, 0x18, 0x47, 0x18, 0x4A, ++ 0x92, 0xF8, 0xFF, 0x21, 0x00, 0x2A, 0xAF, 0xD0, 0xF1, 0xF7, 0xA2, 0xFB, ++ 0x23, 0x7E, 0x03, 0x2B, 0xAC, 0xD1, 0x14, 0x4B, 0x00, 0x22, 0x1A, 0x60, ++ 0x02, 0x21, 0xFF, 0x22, 0x85, 0x20, 0x05, 0xF0, 0x77, 0xF9, 0x23, 0x7E, ++ 0x02, 0x2B, 0xE4, 0xD9, 0xC7, 0xE7, 0x09, 0x4B, 0x11, 0x60, 0x1B, 0x68, ++ 0x00, 0x29, 0xD4, 0xD1, 0x00, 0x2B, 0xD2, 0xD0, 0x62, 0xB6, 0xD0, 0xE7, ++ 0x30, 0x9D, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x98, 0x9C, 0x17, 0x00, ++ 0xDC, 0x00, 0x32, 0x40, 0x00, 0x88, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x1C, 0x9E, 0x17, 0x00, 0x4C, 0x00, 0x32, 0x40, ++ 0x20, 0x62, 0x17, 0x00, 0x20, 0x02, 0x32, 0x40, 0x80, 0x9F, 0x17, 0x00, ++ 0x70, 0xB5, 0x25, 0x4D, 0xEA, 0x6A, 0x04, 0x46, 0x0A, 0xB1, 0xE8, 0x62, ++ 0x70, 0xBD, 0xAE, 0x6A, 0x86, 0x42, 0x3D, 0xD0, 0x5E, 0xB1, 0x33, 0x7E, ++ 0x03, 0x2B, 0x08, 0xD0, 0x01, 0x23, 0x0C, 0x21, 0x45, 0x20, 0x05, 0xF0, ++ 0xD7, 0xF8, 0x33, 0x7E, 0x03, 0x70, 0x05, 0xF0, 0x03, 0xF9, 0x1B, 0x4B, ++ 0x5B, 0x68, 0x00, 0x2B, 0x1C, 0xDD, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, ++ 0x03, 0xD4, 0x72, 0xB6, 0x17, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x17, 0x4E, ++ 0x33, 0x68, 0x04, 0x20, 0x01, 0x33, 0x33, 0x60, 0xF1, 0xF7, 0x42, 0xF8, ++ 0x4F, 0xF0, 0x80, 0x41, 0x04, 0x20, 0xF1, 0xF7, 0xDD, 0xF8, 0x33, 0x68, ++ 0x33, 0xB1, 0x0F, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x33, 0x60, 0x0B, 0xB9, ++ 0x02, 0xB1, 0x62, 0xB6, 0x02, 0x22, 0xEC, 0x62, 0x04, 0x23, 0x22, 0x74, ++ 0x00, 0x21, 0xFF, 0x22, 0x84, 0x20, 0x05, 0xF0, 0xA9, 0xF8, 0x09, 0x4B, ++ 0x1B, 0x6E, 0x03, 0x60, 0xBD, 0xE8, 0x70, 0x40, 0x05, 0xF0, 0xD2, 0xB8, ++ 0x04, 0x23, 0x33, 0x74, 0x70, 0xBD, 0x00, 0xBF, 0x30, 0x9D, 0x17, 0x00, ++ 0xD8, 0x9C, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x38, 0xB5, 0x0A, 0x4D, 0x04, 0x46, 0xD5, 0xF8, ++ 0x6C, 0x31, 0x00, 0x6D, 0x98, 0x47, 0xD5, 0xF8, 0x00, 0x32, 0x20, 0x65, ++ 0x01, 0x46, 0x20, 0x46, 0x98, 0x47, 0x94, 0xF8, 0x4D, 0x30, 0x23, 0xF0, ++ 0x40, 0x03, 0x43, 0xF0, 0x20, 0x03, 0x84, 0xF8, 0x4D, 0x30, 0x38, 0xBD, ++ 0x88, 0x1A, 0x17, 0x00, 0x02, 0x6D, 0x41, 0x6A, 0x70, 0xB5, 0x17, 0x4D, ++ 0x04, 0x46, 0xD5, 0xF8, 0xE0, 0x31, 0x11, 0x44, 0x18, 0x30, 0x98, 0x47, ++ 0x94, 0xF8, 0x4D, 0x30, 0x23, 0xF0, 0x20, 0x02, 0xDB, 0x07, 0x84, 0xF8, ++ 0x4D, 0x20, 0x0E, 0xD5, 0x10, 0x4B, 0x5B, 0x6A, 0x23, 0xB1, 0xDA, 0x68, ++ 0x04, 0xF1, 0x44, 0x03, 0x9A, 0x42, 0x07, 0xD0, 0xEB, 0x6A, 0x61, 0x6A, ++ 0x20, 0x46, 0x00, 0x22, 0xBD, 0xE8, 0x70, 0x40, 0x18, 0x47, 0x70, 0xBD, ++ 0x6B, 0x6B, 0x98, 0x47, 0xEB, 0x6A, 0x61, 0x6A, 0x20, 0x46, 0x00, 0x22, ++ 0x98, 0x47, 0x06, 0x4A, 0xD5, 0xF8, 0x84, 0x30, 0x11, 0x69, 0x20, 0x46, ++ 0x00, 0x22, 0xBD, 0xE8, 0x70, 0x40, 0x18, 0x47, 0x88, 0x1A, 0x17, 0x00, ++ 0x30, 0x9D, 0x17, 0x00, 0x00, 0x10, 0x50, 0x40, 0x2D, 0xE9, 0xF8, 0x43, ++ 0xDF, 0xF8, 0xB8, 0x80, 0x90, 0xF8, 0x4E, 0x70, 0x4F, 0xF4, 0xA4, 0x65, ++ 0x05, 0xFB, 0x07, 0x85, 0x95, 0xF8, 0x4D, 0x60, 0x16, 0xF0, 0x60, 0x06, ++ 0x1F, 0xD1, 0x26, 0x4B, 0x04, 0x46, 0xD3, 0xF8, 0xFC, 0x31, 0x89, 0x46, ++ 0x90, 0xF8, 0x4F, 0x10, 0x28, 0x46, 0x98, 0x47, 0x63, 0x6D, 0xA0, 0xEB, ++ 0x09, 0x01, 0x58, 0x1A, 0x00, 0xB2, 0x80, 0xEA, 0xE0, 0x73, 0xA3, 0xEB, ++ 0xE0, 0x73, 0x9B, 0xB2, 0xB3, 0xF5, 0xFA, 0x6F, 0xA4, 0xF8, 0x58, 0x00, ++ 0x09, 0xD9, 0x95, 0xF8, 0x4D, 0x30, 0x23, 0xF0, 0x40, 0x03, 0x43, 0xF0, ++ 0x10, 0x03, 0x85, 0xF8, 0x4D, 0x30, 0xBD, 0xE8, 0xF8, 0x83, 0xC8, 0x2B, ++ 0xFB, 0xD9, 0x15, 0x4B, 0x9B, 0x68, 0x9B, 0xB1, 0x95, 0xF8, 0x63, 0x10, ++ 0x30, 0x46, 0x93, 0xF8, 0x4E, 0x20, 0x8A, 0x42, 0x07, 0xD1, 0xB3, 0xF9, ++ 0x58, 0x20, 0x90, 0x42, 0xA8, 0xBF, 0x10, 0x46, 0x96, 0x42, 0xB8, 0xBF, ++ 0x16, 0x46, 0x1B, 0x68, 0x00, 0x2B, 0xF0, 0xD1, 0x60, 0xB9, 0x73, 0x10, ++ 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, 0x07, 0x87, 0x97, 0xF8, 0x4D, 0x20, ++ 0x3B, 0x65, 0x42, 0xF0, 0x40, 0x03, 0x87, 0xF8, 0x4D, 0x30, 0xD8, 0xE7, ++ 0x00, 0x2E, 0xD6, 0xD1, 0x00, 0xEB, 0xD0, 0x73, 0x5B, 0x10, 0xED, 0xE7, ++ 0x88, 0x1A, 0x17, 0x00, 0x00, 0x88, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0x23, 0x48, 0x2D, 0xE9, 0xF0, 0x41, 0x60, 0x22, 0x00, 0x21, 0x22, 0x4F, ++ 0x06, 0x46, 0xE2, 0xF7, 0xD3, 0xFB, 0x00, 0x25, 0x3C, 0x46, 0xA8, 0x46, ++ 0x00, 0x21, 0x1C, 0x22, 0x20, 0x46, 0xE2, 0xF7, 0xCB, 0xFB, 0xFF, 0x23, ++ 0x02, 0x2D, 0xE3, 0x81, 0x23, 0x76, 0xE3, 0x76, 0x21, 0x46, 0x30, 0x46, ++ 0x04, 0xD8, 0x05, 0xF0, 0x55, 0xFC, 0x01, 0x35, 0x1C, 0x34, 0xED, 0xE7, ++ 0x03, 0x2D, 0x22, 0xD0, 0x04, 0x2D, 0xF8, 0xD1, 0x14, 0x48, 0x05, 0xF0, ++ 0x47, 0xFC, 0x14, 0x48, 0x05, 0xF0, 0x44, 0xFC, 0x13, 0x49, 0x11, 0x48, ++ 0x05, 0xF0, 0x44, 0xFC, 0x12, 0x49, 0x0F, 0x48, 0x05, 0xF0, 0x40, 0xFC, ++ 0x11, 0x49, 0x0D, 0x48, 0x05, 0xF0, 0x3C, 0xFC, 0x10, 0x49, 0x0B, 0x48, ++ 0x05, 0xF0, 0x38, 0xFC, 0x0F, 0x4A, 0x07, 0x4B, 0xD2, 0xF8, 0xAC, 0x10, ++ 0xD0, 0x6B, 0x58, 0x63, 0x00, 0x22, 0xC3, 0xE9, 0x11, 0x12, 0xBD, 0xE8, ++ 0xF0, 0x81, 0xA7, 0xF8, 0x5E, 0x80, 0x87, 0xF8, 0x59, 0x80, 0xD2, 0xE7, ++ 0x30, 0x9D, 0x17, 0x00, 0x90, 0x9D, 0x17, 0x00, 0x48, 0x9D, 0x17, 0x00, ++ 0x50, 0x9D, 0x17, 0x00, 0xF0, 0x9C, 0x17, 0x00, 0x00, 0x9D, 0x17, 0x00, ++ 0x10, 0x9D, 0x17, 0x00, 0x20, 0x9D, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x43, 0x21, 0x4C, 0x24, 0x68, 0xB4, 0xF9, 0x00, 0x40, ++ 0x83, 0xB0, 0x00, 0x2C, 0x9D, 0xF8, 0x28, 0x90, 0x9D, 0xF8, 0x2C, 0x80, ++ 0x1D, 0x4C, 0x07, 0x46, 0x0D, 0x46, 0x16, 0x46, 0x27, 0xDB, 0x1C, 0x49, ++ 0x84, 0xF8, 0x58, 0x70, 0x91, 0xF8, 0x58, 0x20, 0xA4, 0xF8, 0x5C, 0x50, ++ 0xA4, 0xF8, 0x5A, 0x50, 0x42, 0xF0, 0x02, 0x07, 0x84, 0xF8, 0x60, 0x60, ++ 0xFF, 0x25, 0x03, 0x26, 0x01, 0x20, 0xA3, 0x66, 0xD3, 0x06, 0x84, 0xF8, ++ 0x61, 0x90, 0x84, 0xF8, 0x6E, 0x80, 0x81, 0xF8, 0x58, 0x70, 0x84, 0xF8, ++ 0x6C, 0x60, 0xA4, 0xF8, 0x62, 0x50, 0x84, 0xF8, 0x64, 0x00, 0x05, 0xD4, ++ 0x0D, 0x4B, 0x1B, 0x6C, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x43, 0x18, 0x47, ++ 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x83, 0x94, 0xF8, 0x6C, 0x20, 0xFF, 0x2A, ++ 0xD3, 0xD0, 0x08, 0x49, 0x08, 0x48, 0x01, 0x93, 0x40, 0xF6, 0x8C, 0x22, ++ 0x07, 0xF0, 0x26, 0xF8, 0x01, 0x9B, 0xCA, 0xE7, 0x38, 0x36, 0x17, 0x00, ++ 0x90, 0x9D, 0x17, 0x00, 0x30, 0x9D, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x48, 0xA2, 0x15, 0x00, 0xF0, 0xB5, 0x65, 0x4F, ++ 0x04, 0x46, 0x83, 0xB0, 0x97, 0xF8, 0x80, 0x00, 0xE3, 0x68, 0x22, 0x78, ++ 0x00, 0x90, 0x0E, 0x46, 0x08, 0x20, 0x61, 0x49, 0x06, 0xF0, 0xE0, 0xFD, ++ 0x25, 0x78, 0x25, 0xB3, 0x01, 0x2D, 0x2F, 0xD1, 0x97, 0xF8, 0x88, 0x30, ++ 0xFF, 0x2B, 0x1A, 0xD0, 0x97, 0xF8, 0x80, 0x30, 0x03, 0x2B, 0x2B, 0xD8, ++ 0x01, 0x2B, 0x5A, 0x4C, 0x44, 0xD8, 0x09, 0xD1, 0x94, 0xF8, 0x58, 0x30, ++ 0x07, 0xF1, 0x70, 0x00, 0x23, 0xF0, 0x05, 0x03, 0x84, 0xF8, 0x58, 0x30, ++ 0xFE, 0xF7, 0xE4, 0xF9, 0x94, 0xF8, 0x58, 0x30, 0x03, 0xF0, 0x12, 0x02, ++ 0xFF, 0x21, 0x10, 0x2A, 0x87, 0xF8, 0x88, 0x10, 0x24, 0xD0, 0x00, 0x25, ++ 0x28, 0x46, 0x03, 0xB0, 0xF0, 0xBD, 0x97, 0xF8, 0x88, 0x30, 0xFF, 0x2B, ++ 0x3A, 0xD0, 0x4B, 0x4A, 0x92, 0xF8, 0x58, 0x30, 0x99, 0x06, 0x03, 0xD5, ++ 0x23, 0xF0, 0x20, 0x03, 0x82, 0xF8, 0x58, 0x30, 0x01, 0x25, 0x28, 0x46, ++ 0x03, 0xB0, 0xF0, 0xBD, 0x04, 0x2B, 0x17, 0xD1, 0x44, 0x48, 0x45, 0x4D, ++ 0xA0, 0xF1, 0x40, 0x04, 0xD5, 0xF8, 0xD8, 0x31, 0x98, 0x47, 0x00, 0x22, ++ 0xD5, 0xF8, 0xAC, 0x30, 0x20, 0x6A, 0xA2, 0x64, 0x98, 0x47, 0xD1, 0xE7, ++ 0x3E, 0x4A, 0x3F, 0x48, 0xD2, 0xF8, 0xD8, 0x21, 0x23, 0xF0, 0x10, 0x03, ++ 0x84, 0xF8, 0x58, 0x30, 0x90, 0x47, 0xD0, 0xE7, 0x37, 0x4C, 0xC5, 0xE7, ++ 0x94, 0xF8, 0x58, 0x30, 0xE2, 0x6A, 0x23, 0xF0, 0x04, 0x03, 0x84, 0xF8, ++ 0x58, 0x30, 0x2A, 0xB1, 0x07, 0xF1, 0x70, 0x03, 0x9A, 0x42, 0x50, 0xD0, ++ 0x00, 0x23, 0xE3, 0x62, 0x33, 0x48, 0xFE, 0xF7, 0x99, 0xF9, 0xB3, 0xE7, ++ 0x97, 0xF8, 0x80, 0x30, 0x04, 0x2B, 0xC0, 0xD0, 0x04, 0x20, 0x05, 0xF0, ++ 0x5D, 0xF9, 0x01, 0x28, 0xBB, 0xD0, 0x04, 0x23, 0x87, 0xF8, 0x88, 0x30, ++ 0xA3, 0x78, 0x87, 0xF8, 0x74, 0x30, 0xE3, 0x78, 0x87, 0xF8, 0x75, 0x30, ++ 0xA3, 0x88, 0xE2, 0x88, 0xA7, 0xF8, 0x76, 0x30, 0x01, 0x21, 0x23, 0x89, ++ 0x87, 0xF8, 0x80, 0x10, 0xA7, 0xF8, 0x78, 0x20, 0xE2, 0x68, 0xA7, 0xF8, ++ 0x7A, 0x30, 0x4F, 0xF4, 0x7A, 0x73, 0x03, 0xFB, 0x02, 0xF3, 0x23, 0x2A, ++ 0x84, 0xBF, 0xA3, 0xF5, 0x08, 0x43, 0xB8, 0x3B, 0xA7, 0xF8, 0x7E, 0x60, ++ 0xC7, 0xF8, 0x84, 0x30, 0x63, 0x78, 0x17, 0x4A, 0x87, 0xF8, 0x8A, 0x30, ++ 0x23, 0x7C, 0x87, 0xF8, 0x7C, 0x30, 0x16, 0x49, 0x92, 0xF8, 0x58, 0x30, ++ 0x66, 0xB9, 0x43, 0xF0, 0x04, 0x03, 0xC9, 0x6D, 0x14, 0x48, 0x82, 0xF8, ++ 0x58, 0x30, 0x88, 0x47, 0x13, 0x4A, 0x13, 0x68, 0x43, 0xF0, 0x04, 0x03, ++ 0x13, 0x60, 0x8A, 0xE7, 0x43, 0xF0, 0x01, 0x03, 0x09, 0x6C, 0x82, 0xF8, ++ 0x58, 0x30, 0x88, 0x47, 0xF2, 0xE7, 0x23, 0x6D, 0x93, 0x42, 0xAB, 0xD1, ++ 0x08, 0x4B, 0x04, 0xF1, 0x40, 0x00, 0xD3, 0xF8, 0xD8, 0x31, 0x98, 0x47, ++ 0x00, 0x23, 0xA3, 0x64, 0xA2, 0xE7, 0x00, 0xBF, 0x90, 0x9D, 0x17, 0x00, ++ 0x68, 0xA2, 0x15, 0x00, 0x30, 0x9D, 0x17, 0x00, 0x70, 0x9D, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x60, 0x9D, 0x17, 0x00, 0x00, 0x9E, 0x17, 0x00, ++ 0x94, 0x40, 0x04, 0x40, 0x2D, 0xE9, 0xF0, 0x41, 0x36, 0x4E, 0x84, 0xB0, ++ 0x04, 0x46, 0x0F, 0x46, 0x33, 0x46, 0x00, 0x25, 0x1A, 0x7E, 0xFF, 0x2A, ++ 0x03, 0xD0, 0x1A, 0x79, 0x20, 0x78, 0x90, 0x42, 0x1B, 0xD0, 0x01, 0x35, ++ 0x03, 0x2D, 0x03, 0xF1, 0x1C, 0x03, 0xF3, 0xD1, 0x2E, 0x48, 0x05, 0xF0, ++ 0x15, 0xFB, 0x03, 0x46, 0x70, 0xB3, 0x2D, 0x4A, 0x86, 0x1B, 0xB6, 0x10, ++ 0x02, 0xFB, 0x06, 0xF6, 0xF6, 0xB2, 0x06, 0x76, 0x3E, 0x70, 0x20, 0x68, ++ 0x61, 0x68, 0x04, 0x33, 0x03, 0xC3, 0x22, 0x89, 0x1A, 0x80, 0x00, 0x20, ++ 0x04, 0xB0, 0xBD, 0xE8, 0xF0, 0x81, 0xD9, 0x88, 0x62, 0x88, 0x8A, 0x42, ++ 0xDF, 0xD1, 0x93, 0xF8, 0x05, 0xC0, 0x61, 0x78, 0x8C, 0x45, 0x08, 0xD0, ++ 0x02, 0xD2, 0xBC, 0xF1, 0x03, 0x0F, 0x13, 0xD1, 0x8C, 0x45, 0xD4, 0xD9, ++ 0x03, 0x29, 0xD2, 0xD0, 0x07, 0xE0, 0x19, 0x89, 0xA2, 0x88, 0x91, 0x42, ++ 0xCD, 0xD1, 0x59, 0x89, 0xE2, 0x88, 0x91, 0x42, 0xC9, 0xD1, 0x3D, 0x70, ++ 0x00, 0x20, 0xDF, 0xE7, 0x01, 0x20, 0x04, 0xB0, 0xBD, 0xE8, 0xF0, 0x81, ++ 0xDF, 0xF8, 0x48, 0xE0, 0xB4, 0xF8, 0x04, 0x80, 0xB4, 0xF8, 0x06, 0xC0, ++ 0xDE, 0xF8, 0x28, 0x30, 0xC5, 0xEB, 0xC5, 0x04, 0x06, 0xEB, 0x84, 0x04, ++ 0xA3, 0x42, 0x61, 0x71, 0xA4, 0xF8, 0x08, 0x80, 0xA4, 0xF8, 0x0A, 0xC0, ++ 0xE5, 0xD1, 0x9E, 0xF8, 0x5A, 0x40, 0x01, 0x2C, 0xE1, 0xD1, 0x1C, 0x24, ++ 0x04, 0xFB, 0x05, 0x66, 0x00, 0x24, 0x76, 0x7B, 0xCD, 0xF8, 0x00, 0xC0, ++ 0xCD, 0xE9, 0x01, 0x64, 0x43, 0x46, 0xE3, 0xF7, 0xCF, 0xF9, 0xD4, 0xE7, ++ 0x90, 0x9D, 0x17, 0x00, 0x30, 0x9D, 0x17, 0x00, 0xB7, 0x6D, 0xDB, 0xB6, ++ 0x2D, 0xE9, 0xF0, 0x41, 0xDF, 0xF8, 0x98, 0x80, 0x20, 0x4D, 0xD8, 0xF8, ++ 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, 0xC0, 0xEB, 0xC0, 0x06, 0x00, 0x2B, ++ 0x04, 0x46, 0x05, 0xEB, 0x86, 0x06, 0x12, 0xDB, 0xC7, 0x00, 0x1B, 0x48, ++ 0x31, 0x46, 0x3C, 0x1B, 0x05, 0xF0, 0x5C, 0xFA, 0x05, 0xEB, 0x84, 0x04, ++ 0x30, 0x46, 0x1C, 0x22, 0x00, 0x21, 0xE2, 0xF7, 0xC1, 0xF9, 0xFF, 0x23, ++ 0xE3, 0x81, 0x23, 0x76, 0xE3, 0x76, 0xBD, 0xE8, 0xF0, 0x81, 0xC0, 0xEB, ++ 0xC0, 0x03, 0x05, 0xEB, 0x83, 0x03, 0xC7, 0x00, 0x1B, 0x7E, 0xFF, 0x2B, ++ 0x0C, 0xD0, 0x3B, 0x1B, 0x05, 0xEB, 0x83, 0x03, 0x5B, 0x7E, 0x00, 0x2B, ++ 0xDF, 0xD0, 0x0C, 0x49, 0x0C, 0x48, 0x40, 0xF6, 0x5C, 0x32, 0x06, 0xF0, ++ 0x8F, 0xFE, 0xD8, 0xE7, 0x08, 0x49, 0x0A, 0x48, 0x40, 0xF6, 0x5A, 0x32, ++ 0x06, 0xF0, 0x88, 0xFE, 0xD8, 0xF8, 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0xE6, 0xDB, 0xCB, 0xE7, 0x00, 0xBF, 0x90, 0x9D, 0x17, 0x00, ++ 0x30, 0x9D, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x84, 0xA2, 0x15, 0x00, ++ 0xA4, 0x88, 0x15, 0x00, 0x38, 0x36, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0xDF, 0xF8, 0x4C, 0x82, 0xDF, 0xF8, 0x24, 0xA2, 0xD8, 0xF8, 0x00, 0x20, ++ 0x84, 0x4F, 0xB2, 0xF9, 0x00, 0x30, 0xC1, 0xEB, 0xC1, 0x06, 0x00, 0x2B, ++ 0x85, 0xB0, 0x0C, 0x46, 0x05, 0x46, 0x0A, 0xEB, 0x86, 0x06, 0x5F, 0xDB, ++ 0x4F, 0xEA, 0xC4, 0x0B, 0xAB, 0xEB, 0x04, 0x01, 0x0A, 0xEB, 0x81, 0x01, ++ 0x4F, 0xF4, 0xA4, 0x63, 0x4A, 0x7E, 0xDF, 0xF8, 0x1C, 0x92, 0x01, 0x32, ++ 0x03, 0xFB, 0x05, 0x73, 0xD2, 0xB2, 0x00, 0x20, 0x01, 0x2A, 0x4A, 0x76, ++ 0x1E, 0x64, 0x83, 0xF8, 0x4D, 0x00, 0x6B, 0xD0, 0xDF, 0xF8, 0x04, 0x82, ++ 0x99, 0xF8, 0x5B, 0x10, 0x99, 0xF8, 0x5A, 0x30, 0x4F, 0xF4, 0x80, 0x70, ++ 0xCD, 0xE9, 0x00, 0x31, 0x6F, 0x49, 0x23, 0x46, 0x06, 0xF0, 0x12, 0xFC, ++ 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x05, 0x73, 0xFF, 0x21, 0x93, 0xF8, ++ 0xC0, 0x24, 0x83, 0xF8, 0x4E, 0x10, 0x4A, 0xB1, 0x69, 0x49, 0x93, 0xF8, ++ 0xC1, 0x24, 0x8C, 0x20, 0x00, 0xFB, 0x02, 0x12, 0x92, 0xF8, 0x70, 0x20, ++ 0x01, 0x2A, 0x20, 0xD0, 0x65, 0x4B, 0x03, 0xF1, 0x54, 0x01, 0x1A, 0x7E, ++ 0xFF, 0x2A, 0x03, 0xD0, 0xDA, 0x7E, 0xFF, 0x2A, 0x40, 0xF0, 0xAA, 0x80, ++ 0x1C, 0x33, 0x99, 0x42, 0xF5, 0xD1, 0xD8, 0xF8, 0xB4, 0x30, 0x30, 0x46, ++ 0x98, 0x47, 0x5E, 0x4B, 0x1B, 0x7C, 0xAB, 0x42, 0x08, 0xD0, 0xFF, 0x2B, ++ 0x06, 0xD0, 0xD8, 0xF8, 0x50, 0x30, 0x20, 0x46, 0x05, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x4F, 0x18, 0x47, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x93, 0xF8, ++ 0x4D, 0x20, 0x42, 0xF0, 0x10, 0x02, 0x83, 0xF8, 0x4D, 0x20, 0xE4, 0xE7, ++ 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x00, 0x73, 0x1B, 0x6C, 0x5B, 0xB1, ++ 0x50, 0x49, 0x51, 0x48, 0x40, 0xF6, 0x6B, 0x32, 0x06, 0xF0, 0xF4, 0xFD, ++ 0xD8, 0xF8, 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x8D, 0xDA, ++ 0xC4, 0xEB, 0xC4, 0x03, 0x0A, 0xEB, 0x83, 0x03, 0x4F, 0xEA, 0xC4, 0x0B, ++ 0x1B, 0x7E, 0xFF, 0x2B, 0x86, 0xD1, 0x46, 0x49, 0x47, 0x48, 0x40, 0xF6, ++ 0x6C, 0x32, 0x06, 0xF0, 0xDF, 0xFD, 0x7F, 0xE7, 0x99, 0xF8, 0x5A, 0x00, ++ 0x0A, 0x74, 0x42, 0x1C, 0xD8, 0xF8, 0x00, 0x30, 0xD2, 0xB2, 0x89, 0xF8, ++ 0x5A, 0x20, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x28, 0xDB, 0x02, 0x2A, ++ 0x3C, 0xD0, 0x3E, 0x48, 0x31, 0x46, 0x05, 0xF0, 0x77, 0xF9, 0x99, 0xF8, ++ 0x58, 0x30, 0x13, 0xF0, 0x0C, 0x0F, 0x0F, 0xD0, 0xD8, 0xF8, 0x00, 0x20, ++ 0xD9, 0xF8, 0x20, 0x30, 0xB2, 0xF9, 0x00, 0x20, 0x00, 0x2A, 0x20, 0xDB, ++ 0xAB, 0xEB, 0x04, 0x0B, 0x0A, 0xEB, 0x8B, 0x0A, 0x9E, 0x60, 0x9A, 0xF8, ++ 0x19, 0x20, 0x6B, 0xE7, 0xD9, 0xF8, 0x2C, 0x30, 0x8B, 0xB3, 0xAB, 0xEB, ++ 0x04, 0x0B, 0x0A, 0xEB, 0x8B, 0x0A, 0xDF, 0xF8, 0xD0, 0x80, 0x9A, 0xF8, ++ 0x19, 0x20, 0xC9, 0xF8, 0x2C, 0x60, 0x5F, 0xE7, 0x02, 0x2A, 0xD4, 0xD9, ++ 0x40, 0xF6, 0x81, 0x32, 0x25, 0x49, 0x29, 0x48, 0x06, 0xF0, 0xA0, 0xFD, ++ 0x99, 0xF8, 0x5A, 0x20, 0xCB, 0xE7, 0x00, 0x2B, 0xDC, 0xD1, 0x21, 0x49, ++ 0x25, 0x48, 0x03, 0x93, 0x4F, 0xF4, 0x39, 0x62, 0x06, 0xF0, 0x94, 0xFD, ++ 0x03, 0x9B, 0xD3, 0xE7, 0x22, 0x48, 0x05, 0xF0, 0x37, 0xF9, 0x16, 0x4B, ++ 0x03, 0xF5, 0xA4, 0x51, 0x93, 0xF8, 0x4D, 0x20, 0x22, 0xF0, 0x01, 0x02, ++ 0x83, 0xF8, 0x4D, 0x20, 0x03, 0xF5, 0xA4, 0x63, 0x99, 0x42, 0xF5, 0xD1, ++ 0xB1, 0xE7, 0xDF, 0xF8, 0x74, 0x80, 0xAB, 0xEB, 0x04, 0x0B, 0x0A, 0xEB, ++ 0x8B, 0x0A, 0xD8, 0xF8, 0x9C, 0x30, 0x30, 0x46, 0x98, 0x47, 0x9A, 0xF8, ++ 0x19, 0x20, 0x2B, 0xE7, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x02, 0x72, ++ 0x12, 0x6C, 0xB2, 0x42, 0x3F, 0xF4, 0x51, 0xAF, 0x03, 0xFB, 0x05, 0x77, ++ 0x97, 0xF8, 0x4D, 0x30, 0x43, 0xF0, 0x10, 0x03, 0x87, 0xF8, 0x4D, 0x30, ++ 0x47, 0xE7, 0x00, 0xBF, 0x18, 0x88, 0x17, 0x00, 0xE0, 0xA2, 0x15, 0x00, ++ 0x48, 0x9E, 0x17, 0x00, 0x90, 0x9D, 0x17, 0x00, 0x00, 0x88, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xA0, 0xA2, 0x15, 0x00, 0xA4, 0x88, 0x15, 0x00, ++ 0x38, 0x9D, 0x17, 0x00, 0xB8, 0xA2, 0x15, 0x00, 0xD4, 0xA2, 0x15, 0x00, ++ 0x40, 0x9D, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, 0x30, 0x9D, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, 0xDF, 0xF8, 0xBC, 0xA2, ++ 0xDF, 0xF8, 0xB4, 0x82, 0xDA, 0xF8, 0x00, 0x30, 0x4F, 0xF4, 0xA4, 0x69, ++ 0xB3, 0xF9, 0x00, 0x30, 0x09, 0xFB, 0x00, 0xF9, 0x08, 0xEB, 0x09, 0x02, ++ 0x00, 0x2B, 0x14, 0x6C, 0x85, 0xB0, 0x05, 0x46, 0xC0, 0xF2, 0x99, 0x80, ++ 0x4F, 0xF4, 0xA4, 0x66, 0x06, 0xFB, 0x05, 0x86, 0x9A, 0x4F, 0x96, 0xF8, ++ 0x4D, 0x00, 0x21, 0x7C, 0x97, 0xF8, 0x5A, 0x30, 0x62, 0x7E, 0x00, 0x93, ++ 0xCD, 0xE9, 0x01, 0x01, 0x97, 0xF8, 0x5B, 0x30, 0x95, 0x49, 0x4F, 0xF4, ++ 0x80, 0x70, 0x06, 0xF0, 0xEF, 0xFA, 0x09, 0xF1, 0x44, 0x01, 0x07, 0xF1, ++ 0x10, 0x00, 0x41, 0x44, 0x05, 0xF0, 0x0E, 0xF9, 0x96, 0xF8, 0x4D, 0x30, ++ 0x23, 0xF0, 0x01, 0x02, 0x86, 0xF8, 0x4D, 0x20, 0x9A, 0x07, 0x09, 0xD5, ++ 0x97, 0xF8, 0x5B, 0x30, 0x97, 0xF8, 0x5A, 0x20, 0x01, 0x3B, 0xDB, 0xB2, ++ 0x01, 0x2A, 0x87, 0xF8, 0x5B, 0x30, 0x5D, 0xD9, 0xDF, 0xF8, 0x3C, 0xB2, ++ 0x4F, 0xF4, 0xA4, 0x60, 0x00, 0xFB, 0x05, 0x85, 0x00, 0x23, 0x85, 0xF8, ++ 0x4D, 0x30, 0x2B, 0x64, 0x66, 0x7E, 0x23, 0x7C, 0x01, 0x3E, 0xF6, 0xB2, ++ 0x66, 0x76, 0x00, 0x2B, 0x45, 0xD0, 0x95, 0xF8, 0x63, 0x30, 0xE2, 0x7E, ++ 0x9A, 0x42, 0x00, 0xF0, 0x85, 0x80, 0x7C, 0x4B, 0x03, 0xF1, 0x54, 0x01, ++ 0x1A, 0x7E, 0xFF, 0x2A, 0x03, 0xD0, 0xD8, 0x7E, 0xFF, 0x28, 0x40, 0xF0, ++ 0xBD, 0x80, 0x1C, 0x33, 0x99, 0x42, 0xF5, 0xD1, 0x00, 0x2E, 0x4E, 0xD0, ++ 0xDB, 0xF8, 0xB4, 0x30, 0x20, 0x46, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x4F, ++ 0x18, 0x47, 0x97, 0xF8, 0x5A, 0x30, 0x00, 0x20, 0xB8, 0x62, 0x00, 0x2B, ++ 0x59, 0xD0, 0x21, 0x7E, 0xDB, 0xF8, 0x9C, 0x50, 0x6C, 0x4A, 0x02, 0x29, ++ 0x01, 0xF1, 0x01, 0x03, 0x00, 0xF0, 0xC0, 0x80, 0xC3, 0xEB, 0xC3, 0x06, ++ 0x02, 0xEB, 0x86, 0x06, 0xD8, 0x00, 0x36, 0x7E, 0xFF, 0x2E, 0x40, 0xF0, ++ 0xC3, 0x80, 0x01, 0x29, 0x01, 0xF1, 0x02, 0x03, 0x08, 0xBF, 0x00, 0x23, ++ 0xC3, 0xEB, 0xC3, 0x01, 0x02, 0xEB, 0x81, 0x01, 0xD8, 0x00, 0x09, 0x7E, ++ 0xFF, 0x29, 0x08, 0xBF, 0x00, 0x20, 0x40, 0xF0, 0xB3, 0x80, 0xA8, 0x47, ++ 0x66, 0x7E, 0x00, 0x2E, 0xCC, 0xD1, 0xDB, 0xF8, 0x48, 0x30, 0x20, 0x7E, ++ 0x98, 0x47, 0xC7, 0xE7, 0x00, 0x2B, 0x9F, 0xD1, 0x97, 0xF8, 0x58, 0x30, ++ 0xDF, 0xF8, 0x78, 0xB1, 0x5B, 0x06, 0x9B, 0xD5, 0x38, 0x6D, 0xDB, 0xF8, ++ 0x5C, 0x30, 0x98, 0x47, 0x96, 0xE7, 0x00, 0x2C, 0x7F, 0xF4, 0x64, 0xAF, ++ 0x51, 0x49, 0x52, 0x48, 0x40, 0xF6, 0xC4, 0x32, 0x06, 0xF0, 0x8C, 0xFC, ++ 0x5C, 0xE7, 0x50, 0x48, 0x21, 0x46, 0x05, 0xF0, 0x83, 0xF8, 0x26, 0x74, ++ 0x97, 0xF8, 0x5A, 0x30, 0xDA, 0xF8, 0x00, 0x20, 0x01, 0x3B, 0xDB, 0xB2, ++ 0x87, 0xF8, 0x5A, 0x30, 0xB2, 0xF9, 0x00, 0x20, 0x00, 0x2A, 0x0A, 0xDB, ++ 0x03, 0xBB, 0xBB, 0x6A, 0xA3, 0x42, 0xA2, 0xD0, 0xFB, 0x6A, 0xA3, 0x42, ++ 0x31, 0xD0, 0x66, 0x7E, 0x00, 0x2E, 0xC8, 0xD0, 0x94, 0xE7, 0x01, 0x2B, ++ 0xF2, 0xD9, 0x3F, 0x49, 0x41, 0x48, 0x4F, 0xF4, 0x40, 0x62, 0x06, 0xF0, ++ 0x67, 0xFC, 0x97, 0xF8, 0x5A, 0x30, 0xE9, 0xE7, 0xDB, 0xF8, 0x94, 0x30, ++ 0x08, 0xEB, 0x09, 0x00, 0x98, 0x47, 0x66, 0x7E, 0xFF, 0x23, 0xE3, 0x76, ++ 0x00, 0x2E, 0x7F, 0xF4, 0x7F, 0xAF, 0xCC, 0xE7, 0x38, 0x48, 0x04, 0xF0, ++ 0xFD, 0xFF, 0x38, 0x4B, 0x03, 0xF5, 0xA4, 0x51, 0x93, 0xF8, 0x4D, 0x20, ++ 0x22, 0xF0, 0x01, 0x02, 0x83, 0xF8, 0x4D, 0x20, 0x03, 0xF5, 0xA4, 0x63, ++ 0x99, 0x42, 0xF5, 0xD1, 0x3B, 0x6D, 0x00, 0x2B, 0xCB, 0xD1, 0xDB, 0xF8, ++ 0x34, 0x30, 0x98, 0x47, 0xC7, 0xE7, 0x21, 0x7E, 0x27, 0x4A, 0x02, 0x29, ++ 0x01, 0xF1, 0x01, 0x03, 0x29, 0xD0, 0xC3, 0xEB, 0xC3, 0x05, 0x02, 0xEB, ++ 0x85, 0x05, 0xD8, 0x00, 0x2D, 0x7E, 0xFF, 0x2D, 0x35, 0xD1, 0x01, 0x29, ++ 0x01, 0xF1, 0x02, 0x03, 0x08, 0xBF, 0x00, 0x23, 0xC3, 0xEB, 0xC3, 0x01, ++ 0x02, 0xEB, 0x81, 0x01, 0xD8, 0x00, 0x09, 0x7E, 0xFF, 0x29, 0x08, 0xBF, ++ 0x00, 0x22, 0x26, 0xD1, 0xFA, 0x62, 0xAE, 0xE7, 0x4F, 0xF4, 0xA4, 0x63, ++ 0x03, 0xFB, 0x00, 0x80, 0x03, 0x6C, 0xA3, 0x42, 0x3F, 0xF4, 0x3E, 0xAF, ++ 0x66, 0xB1, 0xDB, 0xF8, 0x8C, 0x30, 0x98, 0x47, 0x66, 0x7E, 0x00, 0x2E, ++ 0x7F, 0xF4, 0x38, 0xAF, 0x85, 0xE7, 0x13, 0x7E, 0xFF, 0x2B, 0x0E, 0xD1, ++ 0x01, 0x23, 0xDD, 0xE7, 0xDB, 0xF8, 0x94, 0x30, 0x98, 0x47, 0x66, 0x7E, ++ 0x00, 0x2E, 0x7F, 0xF4, 0x2B, 0xAF, 0x78, 0xE7, 0x13, 0x7E, 0xFF, 0x2B, ++ 0x07, 0xD1, 0x01, 0x23, 0x48, 0xE7, 0x00, 0x23, 0x18, 0x46, 0xC3, 0x1A, ++ 0x02, 0xEB, 0x83, 0x02, 0xD4, 0xE7, 0x03, 0x46, 0xC0, 0x1A, 0x02, 0xEB, ++ 0x80, 0x00, 0x48, 0xE7, 0x30, 0x9D, 0x17, 0x00, 0x08, 0xA3, 0x15, 0x00, ++ 0x90, 0x9D, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0xF8, 0xA2, 0x15, 0x00, ++ 0x38, 0x9D, 0x17, 0x00, 0x28, 0xA3, 0x15, 0x00, 0x40, 0x9D, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x43, 0x03, 0x46, 0x05, 0x78, 0x29, 0x4E, 0x2A, 0x4A, ++ 0x04, 0x46, 0x53, 0xF8, 0x02, 0x0F, 0x97, 0x6A, 0x59, 0x68, 0xB3, 0xF8, ++ 0x08, 0xC0, 0xC5, 0xEB, 0xC5, 0x03, 0x06, 0xEB, 0x83, 0x03, 0x04, 0x33, ++ 0x03, 0xC3, 0xC5, 0xEB, 0xC5, 0x02, 0x06, 0xEB, 0x82, 0x02, 0x97, 0x42, ++ 0x85, 0xB0, 0xA3, 0xF8, 0x00, 0xC0, 0x02, 0xD0, 0x05, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x83, 0x4F, 0xEA, 0xC5, 0x08, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, ++ 0x03, 0xD4, 0x72, 0xB6, 0x1A, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x1A, 0x4F, ++ 0xDF, 0xF8, 0x68, 0x90, 0x3B, 0x68, 0xD9, 0xF8, 0xA0, 0x22, 0x01, 0x33, ++ 0x3B, 0x60, 0x90, 0x47, 0xD9, 0xF8, 0x88, 0x32, 0x00, 0x20, 0x98, 0x47, ++ 0x3B, 0x68, 0x33, 0xB1, 0x11, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x3B, 0x60, ++ 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0xE2, 0x7A, 0x23, 0x89, 0x00, 0x93, ++ 0x00, 0x21, 0xCD, 0xE9, 0x01, 0x21, 0xA8, 0xEB, 0x05, 0x05, 0xE3, 0x88, ++ 0xA0, 0x78, 0xA2, 0x88, 0xE1, 0x78, 0x06, 0xEB, 0x85, 0x06, 0xE2, 0xF7, ++ 0x91, 0xFE, 0xD9, 0xF8, 0x3C, 0x33, 0x96, 0xF9, 0x0C, 0x00, 0x05, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x43, 0x18, 0x47, 0x00, 0xBF, 0x90, 0x9D, 0x17, 0x00, ++ 0x30, 0x9D, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x70, 0xB5, 0x12, 0x4D, 0x12, 0x4A, 0x2B, 0x7C, ++ 0x4F, 0xF4, 0xA4, 0x64, 0x04, 0xFB, 0x03, 0x24, 0x06, 0x46, 0x22, 0x6C, ++ 0x4A, 0xB1, 0x0F, 0x4C, 0x18, 0x46, 0x63, 0x6D, 0x98, 0x47, 0xE3, 0x6C, ++ 0x28, 0x7C, 0x31, 0x46, 0xBD, 0xE8, 0x70, 0x40, 0x18, 0x47, 0x05, 0x22, ++ 0x11, 0x46, 0x02, 0x23, 0x41, 0xF2, 0x17, 0x40, 0x04, 0xF0, 0x7E, 0xFA, ++ 0x01, 0x22, 0x02, 0x70, 0x94, 0xF8, 0x63, 0x20, 0x42, 0x70, 0x04, 0xF0, ++ 0xA7, 0xFA, 0x03, 0x4C, 0xE9, 0xE7, 0x00, 0xBF, 0x00, 0x88, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x2D, 0xE9, 0xF8, 0x4F, ++ 0x6B, 0x4D, 0x2C, 0x69, 0x07, 0x46, 0x8B, 0x46, 0x91, 0x46, 0x8C, 0xB3, ++ 0x63, 0x68, 0xD0, 0xF8, 0x40, 0xA0, 0xD5, 0xF8, 0x28, 0x80, 0x8B, 0x42, ++ 0x12, 0xD0, 0x05, 0xF1, 0x10, 0x06, 0xA3, 0xEB, 0x0B, 0x03, 0x00, 0x2B, ++ 0x21, 0x46, 0x30, 0x46, 0x26, 0xDA, 0x04, 0xF0, 0x33, 0xFF, 0x63, 0x7A, ++ 0x23, 0xF0, 0x01, 0x03, 0x63, 0x72, 0x2C, 0x69, 0xF4, 0xB1, 0x63, 0x68, ++ 0x5B, 0x45, 0xEE, 0xD1, 0x95, 0xF8, 0x5A, 0x30, 0x01, 0x2B, 0x4F, 0xF0, ++ 0x00, 0x04, 0x1B, 0xD8, 0x97, 0xF8, 0x4D, 0x30, 0x43, 0xF0, 0x02, 0x03, ++ 0x87, 0xF8, 0x4D, 0x30, 0x95, 0xF8, 0x5B, 0x30, 0xB8, 0xEB, 0x0A, 0x00, ++ 0x03, 0xF1, 0x01, 0x03, 0x18, 0xBF, 0x01, 0x20, 0x85, 0xF8, 0x5B, 0x30, ++ 0xBD, 0xE8, 0xF8, 0x8F, 0xD0, 0xF8, 0x40, 0xA0, 0xD5, 0xF8, 0x28, 0x80, ++ 0x95, 0xF8, 0x5A, 0x30, 0x01, 0x2B, 0x4F, 0xF0, 0x01, 0x04, 0xE3, 0xD9, ++ 0x97, 0xF8, 0x4E, 0x30, 0xFF, 0x2B, 0x26, 0xD0, 0x49, 0x4E, 0x59, 0x46, ++ 0x73, 0x6F, 0x38, 0x46, 0x98, 0x47, 0x00, 0x2C, 0x41, 0xD0, 0x97, 0xF8, ++ 0x4D, 0x30, 0x97, 0xF8, 0xC0, 0x24, 0x43, 0xF0, 0x04, 0x03, 0x87, 0xF8, ++ 0x4D, 0x30, 0x82, 0xB1, 0x42, 0x4A, 0x97, 0xF8, 0xC1, 0x34, 0x8C, 0x21, ++ 0x01, 0xFB, 0x03, 0x23, 0x93, 0xF8, 0x70, 0x30, 0x01, 0x2B, 0x06, 0xD1, ++ 0xBB, 0x6C, 0x4B, 0x45, 0x03, 0xD0, 0xA3, 0xEB, 0x09, 0x02, 0x32, 0x2A, ++ 0x5D, 0xD4, 0xB8, 0xEB, 0x0A, 0x00, 0x18, 0xBF, 0x01, 0x20, 0xBD, 0xE8, ++ 0xF8, 0x8F, 0x97, 0xF8, 0xC0, 0x34, 0xB3, 0xB3, 0x35, 0x4A, 0x97, 0xF8, ++ 0xC1, 0x34, 0x8C, 0x21, 0x01, 0xFB, 0x03, 0x21, 0x91, 0xF8, 0x70, 0x10, ++ 0x01, 0x29, 0x35, 0xD0, 0x00, 0x2C, 0x4F, 0xD1, 0x30, 0x48, 0x07, 0xF1, ++ 0x44, 0x01, 0x04, 0xF0, 0xC9, 0xFE, 0x97, 0xF8, 0x4D, 0x30, 0x03, 0xF0, ++ 0xFE, 0x03, 0x43, 0xF0, 0x02, 0x03, 0x87, 0xF8, 0x4D, 0x30, 0x95, 0xF8, ++ 0x5B, 0x30, 0x01, 0x33, 0x85, 0xF8, 0x5B, 0x30, 0xD7, 0xE7, 0x97, 0xF8, ++ 0xC0, 0x34, 0x00, 0x2B, 0xE8, 0xD0, 0x24, 0x4A, 0x97, 0xF8, 0xC1, 0x34, ++ 0x8C, 0x21, 0x01, 0xFB, 0x03, 0x23, 0x93, 0xF8, 0x70, 0x30, 0x01, 0x2B, ++ 0xDE, 0xD1, 0xF3, 0x6A, 0x49, 0x46, 0x00, 0x22, 0x38, 0x46, 0x98, 0x47, ++ 0x97, 0xF8, 0x4D, 0x30, 0x43, 0xF0, 0x08, 0x03, 0xDD, 0xE7, 0x00, 0x2C, ++ 0xD2, 0xD0, 0x97, 0xF8, 0x4D, 0x30, 0x43, 0xF0, 0x04, 0x03, 0x87, 0xF8, ++ 0x4D, 0x30, 0xB6, 0xE7, 0x97, 0xF8, 0x4D, 0x10, 0xC8, 0x06, 0x0B, 0xD5, ++ 0x12, 0x4E, 0x38, 0x46, 0xD6, 0xF8, 0x8C, 0x30, 0x98, 0x47, 0x97, 0xF8, ++ 0x4D, 0x30, 0x23, 0xF0, 0x10, 0x03, 0x87, 0xF8, 0x4D, 0x30, 0x8A, 0xE7, ++ 0x4E, 0x06, 0x10, 0xD4, 0x54, 0xB9, 0x0B, 0x4E, 0xD7, 0xE7, 0xA9, 0xEB, ++ 0x03, 0x03, 0x32, 0x2B, 0x9D, 0xD5, 0xC7, 0xF8, 0x48, 0x90, 0x9A, 0xE7, ++ 0x97, 0xF8, 0x4D, 0x10, 0x41, 0xF0, 0x04, 0x01, 0x87, 0xF8, 0x4D, 0x10, ++ 0x85, 0xE7, 0x03, 0x4E, 0x38, 0x46, 0x33, 0x6F, 0x98, 0x47, 0x72, 0xE7, ++ 0x30, 0x9D, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x48, 0x9E, 0x17, 0x00, ++ 0x40, 0x9D, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x41, 0x4D, 0x4D, 0x95, 0xF8, ++ 0x5A, 0x30, 0x01, 0x2B, 0x2B, 0xD9, 0x90, 0xF8, 0x4D, 0x20, 0x04, 0x46, ++ 0xD0, 0x06, 0x0F, 0xD5, 0x49, 0x4B, 0x03, 0xF1, 0x54, 0x00, 0x19, 0x7E, ++ 0xFF, 0x29, 0x02, 0xD0, 0xD9, 0x7E, 0xFF, 0x29, 0x3B, 0xD1, 0x1C, 0x33, ++ 0x98, 0x42, 0xF6, 0xD1, 0x02, 0xF0, 0xEF, 0x02, 0x84, 0xF8, 0x4D, 0x20, ++ 0x91, 0x07, 0x14, 0xD4, 0x53, 0x07, 0x6E, 0x6A, 0x44, 0xBF, 0x22, 0xF0, ++ 0x04, 0x02, 0x84, 0xF8, 0x4D, 0x20, 0x26, 0xB1, 0xF2, 0x68, 0x04, 0xF1, ++ 0x44, 0x03, 0x9A, 0x42, 0x09, 0xD0, 0x3B, 0x4B, 0x61, 0x6A, 0xDB, 0x6A, ++ 0x20, 0x46, 0x00, 0x22, 0xBD, 0xE8, 0xF0, 0x41, 0x18, 0x47, 0xBD, 0xE8, ++ 0xF0, 0x81, 0xD4, 0xF8, 0x48, 0x80, 0x67, 0x6A, 0xA8, 0xEB, 0x07, 0x03, ++ 0x00, 0x2B, 0x20, 0xDB, 0xA7, 0xEB, 0x08, 0x03, 0x00, 0x2B, 0x29, 0xDB, ++ 0x30, 0x4D, 0x6B, 0x6B, 0x98, 0x47, 0xEB, 0x6A, 0x61, 0x6A, 0x20, 0x46, ++ 0x00, 0x22, 0x98, 0x47, 0x2D, 0x4A, 0xD5, 0xF8, 0x84, 0x30, 0x11, 0x69, ++ 0x20, 0x46, 0x00, 0x22, 0xBD, 0xE8, 0xF0, 0x41, 0x18, 0x47, 0x2A, 0x4A, ++ 0x27, 0x4B, 0x4F, 0xF4, 0xA4, 0x60, 0x00, 0xFB, 0x01, 0x20, 0xD3, 0xF8, ++ 0x8C, 0x30, 0x98, 0x47, 0x94, 0xF8, 0x4D, 0x20, 0xBA, 0xE7, 0xE2, 0xF7, ++ 0xA5, 0xFD, 0xA7, 0xF5, 0x7A, 0x67, 0xA7, 0xEB, 0x08, 0x07, 0x38, 0x1A, ++ 0x00, 0x28, 0x0C, 0xDB, 0x67, 0x6A, 0xD4, 0xF8, 0x48, 0x80, 0xD1, 0xE7, ++ 0xE2, 0xF7, 0x98, 0xFD, 0xA8, 0xF5, 0x7A, 0x68, 0xA8, 0xEB, 0x07, 0x07, ++ 0x3F, 0x1A, 0x00, 0x2F, 0xCC, 0xDA, 0x67, 0x6A, 0xA7, 0x64, 0xE2, 0xF7, ++ 0x8D, 0xFD, 0x73, 0x68, 0xFF, 0x1A, 0x3F, 0x1A, 0xB7, 0xF5, 0x7A, 0x6F, ++ 0xB5, 0xD5, 0xA4, 0x6C, 0xE2, 0xF7, 0x84, 0xFD, 0xAB, 0x6C, 0xA4, 0xF5, ++ 0x7A, 0x64, 0x24, 0x1A, 0xB3, 0x42, 0x74, 0x60, 0xAB, 0xD1, 0x0D, 0x4C, ++ 0x0F, 0x48, 0xD4, 0xF8, 0xD8, 0x31, 0x98, 0x47, 0x0B, 0x4B, 0x71, 0x68, ++ 0x1B, 0x69, 0xAE, 0x64, 0xCB, 0x1A, 0x14, 0x2B, 0x05, 0xD4, 0xD4, 0xF8, ++ 0xE0, 0x31, 0x09, 0x48, 0xBD, 0xE8, 0xF0, 0x41, 0x18, 0x47, 0x6B, 0x6C, ++ 0x30, 0x46, 0xBD, 0xE8, 0xF0, 0x41, 0x18, 0x47, 0x30, 0x9D, 0x17, 0x00, ++ 0x90, 0x9D, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x00, 0x10, 0x50, 0x40, ++ 0x18, 0x88, 0x17, 0x00, 0x70, 0x9D, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x41, ++ 0x45, 0x4D, 0x95, 0xF8, 0x5A, 0x30, 0x01, 0x2B, 0x04, 0x46, 0x90, 0xF8, ++ 0x4D, 0x30, 0x51, 0xD9, 0x9E, 0x06, 0x04, 0xD5, 0x41, 0x4B, 0x9B, 0x6F, ++ 0x98, 0x47, 0x94, 0xF8, 0x4D, 0x30, 0x67, 0x6A, 0x13, 0xF0, 0x04, 0x06, ++ 0x3D, 0xD1, 0x99, 0x07, 0x42, 0xD5, 0x03, 0xF0, 0xFD, 0x03, 0x84, 0xF8, ++ 0x4D, 0x30, 0x95, 0xF8, 0x5B, 0x20, 0x01, 0x3A, 0xD2, 0xB2, 0x85, 0xF8, ++ 0x5B, 0x20, 0x4A, 0xB9, 0x95, 0xF8, 0x58, 0x20, 0x52, 0x06, 0x5B, 0xD5, ++ 0x34, 0x4B, 0x28, 0x6D, 0xDB, 0x6D, 0x98, 0x47, 0x94, 0xF8, 0x4D, 0x30, ++ 0xD4, 0xF8, 0x48, 0x80, 0x13, 0xF0, 0x08, 0x02, 0x42, 0xD0, 0x94, 0xF8, ++ 0x62, 0x20, 0x23, 0xF0, 0x08, 0x03, 0x84, 0xF8, 0x4D, 0x30, 0x00, 0x2A, ++ 0x4A, 0xD0, 0x02, 0x2A, 0x0A, 0xBF, 0xB4, 0xF8, 0xD2, 0x30, 0x4F, 0xF4, ++ 0xC8, 0x33, 0x9B, 0x02, 0xA8, 0xEB, 0x03, 0x08, 0xB6, 0xB1, 0xEB, 0x6A, ++ 0x26, 0x4A, 0x15, 0x69, 0x93, 0xB9, 0x24, 0x4E, 0x73, 0x6B, 0x98, 0x47, ++ 0xD6, 0xF8, 0x84, 0x30, 0xA5, 0xEB, 0x08, 0x02, 0x29, 0x46, 0x20, 0x46, ++ 0xBD, 0xE8, 0xF0, 0x41, 0x18, 0x47, 0x13, 0xF0, 0x01, 0x02, 0x23, 0xD0, ++ 0x23, 0xF0, 0x04, 0x03, 0x84, 0xF8, 0x4D, 0x30, 0xBD, 0xE8, 0xF0, 0x81, ++ 0x9A, 0x07, 0xFB, 0xD5, 0x23, 0xF0, 0x02, 0x03, 0x80, 0xF8, 0x4D, 0x30, ++ 0x95, 0xF8, 0x5B, 0x30, 0x01, 0x3B, 0xDB, 0xB2, 0x85, 0xF8, 0x5B, 0x30, ++ 0x00, 0x2B, 0xEF, 0xD1, 0x95, 0xF8, 0x58, 0x30, 0x5F, 0x06, 0xEB, 0xD5, ++ 0x10, 0x4B, 0x28, 0x6D, 0xDB, 0x6D, 0xBD, 0xE8, 0xF0, 0x41, 0x18, 0x47, ++ 0x0D, 0x4B, 0x39, 0x46, 0xDB, 0x6A, 0x20, 0x46, 0x98, 0x47, 0xC7, 0xE7, ++ 0x0A, 0x4B, 0x39, 0x46, 0xDB, 0x6A, 0x20, 0x46, 0x98, 0x47, 0x94, 0xF8, ++ 0x4D, 0x30, 0xD3, 0xE7, 0x01, 0x26, 0xA7, 0xE7, 0x07, 0x4A, 0x94, 0xF8, ++ 0x6C, 0x30, 0x4F, 0xF4, 0x1E, 0x71, 0x01, 0xFB, 0x03, 0x23, 0x9B, 0x68, ++ 0xB2, 0xE7, 0x00, 0xBF, 0x30, 0x9D, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x00, 0x10, 0x50, 0x40, 0x68, 0x65, 0x17, 0x00, 0x28, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x2D, 0xE9, 0xF0, 0x41, 0x07, 0x6C, ++ 0x05, 0x46, 0x3E, 0xDB, 0x24, 0x4E, 0x96, 0xF8, 0x58, 0x20, 0x12, 0xF0, ++ 0x20, 0x04, 0x03, 0xD1, 0x96, 0xF8, 0x5A, 0x30, 0x01, 0x2B, 0x01, 0xD8, ++ 0xBD, 0xE8, 0xF0, 0x81, 0x14, 0x23, 0x22, 0x46, 0x21, 0x46, 0x46, 0x20, ++ 0x95, 0xF8, 0x6C, 0x80, 0x04, 0xF0, 0x2E, 0xF8, 0x04, 0x70, 0x95, 0xF8, ++ 0x63, 0x10, 0x41, 0x70, 0x39, 0x79, 0x19, 0x4A, 0x81, 0x70, 0x4F, 0xF4, ++ 0x1E, 0x71, 0x01, 0xFB, 0x08, 0x28, 0x7A, 0x79, 0xC2, 0x70, 0xD8, 0xF8, ++ 0x08, 0x20, 0x15, 0x4D, 0xB7, 0xF8, 0x06, 0xC0, 0x3C, 0x89, 0x79, 0x89, ++ 0x01, 0x81, 0xA2, 0xF5, 0x9C, 0x52, 0x08, 0x3A, 0xA5, 0xFB, 0x02, 0x52, ++ 0x92, 0x09, 0xA0, 0xF8, 0x04, 0xC0, 0xC4, 0x80, 0xC2, 0x60, 0x3A, 0x7B, ++ 0x02, 0x74, 0x04, 0xF0, 0x3B, 0xF8, 0x96, 0xF8, 0x58, 0x30, 0x43, 0xF0, ++ 0x20, 0x03, 0x86, 0xF8, 0x58, 0x30, 0xBD, 0xE8, 0xF0, 0x81, 0x00, 0x2F, ++ 0xBE, 0xD1, 0x07, 0x49, 0x07, 0x48, 0x40, 0xF6, 0x71, 0x52, 0x06, 0xF0, ++ 0xDD, 0xF8, 0xB7, 0xE7, 0x38, 0x36, 0x17, 0x00, 0x30, 0x9D, 0x17, 0x00, ++ 0x68, 0x65, 0x17, 0x00, 0xD3, 0x4D, 0x62, 0x10, 0x70, 0x79, 0x15, 0x00, ++ 0xC8, 0xA0, 0x15, 0x00, 0x70, 0x47, 0x00, 0xBF, 0x0A, 0x4B, 0x9B, 0x6A, ++ 0x83, 0xB1, 0x1A, 0x7E, 0x02, 0x2A, 0x05, 0xD8, 0x00, 0x6C, 0xC0, 0x1A, ++ 0xB0, 0xFA, 0x80, 0xF0, 0x40, 0x09, 0x70, 0x47, 0x9B, 0x7E, 0x90, 0xF8, ++ 0x63, 0x00, 0x18, 0x1A, 0xB0, 0xFA, 0x80, 0xF0, 0x40, 0x09, 0x70, 0x47, ++ 0x18, 0x46, 0x70, 0x47, 0x30, 0x9D, 0x17, 0x00, 0x10, 0x4A, 0x93, 0x6A, ++ 0xDB, 0xB1, 0x19, 0x7E, 0x02, 0x29, 0x0E, 0xD8, 0x00, 0x6C, 0xC0, 0x1A, ++ 0xB0, 0xFA, 0x80, 0xF0, 0x40, 0x09, 0x88, 0xB1, 0xD2, 0x6A, 0x7A, 0xB1, ++ 0x18, 0x7C, 0xA0, 0xF1, 0x06, 0x00, 0xB0, 0xFA, 0x80, 0xF0, 0x40, 0x09, ++ 0x70, 0x47, 0x90, 0xF8, 0x63, 0x10, 0x98, 0x7E, 0x40, 0x1A, 0xB0, 0xFA, ++ 0x80, 0xF0, 0x40, 0x09, 0x00, 0x28, 0xED, 0xD1, 0x70, 0x47, 0x18, 0x46, ++ 0x70, 0x47, 0x00, 0xBF, 0x30, 0x9D, 0x17, 0x00, 0x0E, 0x4B, 0x9B, 0x6A, ++ 0x23, 0xB1, 0x02, 0x6C, 0x98, 0x88, 0x91, 0x88, 0x88, 0x42, 0x01, 0xD0, ++ 0x00, 0x20, 0x70, 0x47, 0x58, 0x7B, 0x51, 0x7B, 0x88, 0x42, 0xF9, 0xD1, ++ 0xD8, 0x88, 0xD1, 0x88, 0x88, 0x42, 0xF5, 0xD1, 0x18, 0x89, 0x11, 0x89, ++ 0x88, 0x42, 0xF1, 0xD1, 0x5B, 0x89, 0x50, 0x89, 0x18, 0x1A, 0xB0, 0xFA, ++ 0x80, 0xF0, 0x40, 0x09, 0x70, 0x47, 0x00, 0xBF, 0x30, 0x9D, 0x17, 0x00, ++ 0x43, 0x7E, 0xDB, 0xB1, 0x0E, 0x4B, 0x30, 0xB4, 0x7F, 0x21, 0x03, 0xF5, ++ 0xA4, 0x54, 0x1A, 0x6C, 0x82, 0x42, 0x08, 0xD0, 0x03, 0xF5, 0xA4, 0x63, ++ 0xA3, 0x42, 0xF8, 0xD1, 0x7F, 0x29, 0x30, 0xBC, 0x18, 0xBF, 0x01, 0x73, ++ 0x70, 0x47, 0x93, 0xF9, 0x66, 0x20, 0x93, 0xF9, 0x65, 0x50, 0xAA, 0x42, ++ 0xA8, 0xBF, 0x2A, 0x46, 0x91, 0x42, 0xA8, 0xBF, 0x11, 0x46, 0xEB, 0xE7, ++ 0x70, 0x47, 0x00, 0xBF, 0x18, 0x88, 0x17, 0x00, 0x70, 0xB5, 0x11, 0x4E, ++ 0x11, 0x4A, 0xD6, 0xF8, 0x4C, 0x32, 0x04, 0x46, 0x98, 0x47, 0xD0, 0xB1, ++ 0x0F, 0x4B, 0x10, 0x4D, 0x5B, 0x78, 0x00, 0x22, 0x2A, 0x77, 0x23, 0xB1, ++ 0x0E, 0x4A, 0x13, 0x68, 0x43, 0xF0, 0x00, 0x43, 0x13, 0x60, 0x2B, 0x7A, ++ 0x0B, 0xB1, 0x01, 0x3B, 0x2B, 0x72, 0xD6, 0xF8, 0xD8, 0x31, 0x0A, 0x48, ++ 0x98, 0x47, 0x00, 0x23, 0x6B, 0x77, 0x63, 0x68, 0x23, 0xF4, 0x01, 0x73, ++ 0x23, 0xF0, 0x02, 0x03, 0x63, 0x60, 0x70, 0xBD, 0x88, 0x1A, 0x17, 0x00, ++ 0xDD, 0xEA, 0x13, 0x00, 0x4C, 0x36, 0x17, 0x00, 0x1C, 0x9E, 0x17, 0x00, ++ 0x34, 0x04, 0x32, 0x40, 0x28, 0x9E, 0x17, 0x00, 0x70, 0xB5, 0x14, 0x4D, ++ 0x14, 0x4A, 0xD5, 0xF8, 0x4C, 0x32, 0x04, 0x46, 0x98, 0x47, 0xF8, 0xB1, ++ 0x12, 0x4A, 0x13, 0x4B, 0x52, 0x78, 0x01, 0x21, 0x19, 0x77, 0x22, 0xB1, ++ 0x11, 0x49, 0x0A, 0x68, 0x22, 0xF0, 0x00, 0x42, 0x0A, 0x60, 0x1A, 0x7A, ++ 0x0A, 0xB1, 0x01, 0x3A, 0x1A, 0x72, 0x0E, 0x4A, 0x0E, 0x49, 0x12, 0x68, ++ 0x09, 0x69, 0xD0, 0x8E, 0x5C, 0x61, 0x04, 0x26, 0x5E, 0x77, 0x01, 0x44, ++ 0xD5, 0xF8, 0xE0, 0x21, 0x0A, 0x48, 0x90, 0x47, 0x63, 0x68, 0x43, 0xF4, ++ 0x00, 0x73, 0x63, 0x60, 0x70, 0xBD, 0x00, 0xBF, 0x88, 0x1A, 0x17, 0x00, ++ 0x3D, 0xEB, 0x13, 0x00, 0x4C, 0x36, 0x17, 0x00, 0x1C, 0x9E, 0x17, 0x00, ++ 0x34, 0x04, 0x32, 0x40, 0xC8, 0x35, 0x17, 0x00, 0x00, 0x10, 0x50, 0x40, ++ 0x28, 0x9E, 0x17, 0x00, 0x38, 0xB5, 0x10, 0x4A, 0x0B, 0x46, 0x0C, 0x46, ++ 0x05, 0x46, 0x0F, 0x49, 0x02, 0x20, 0x05, 0xF0, 0xB3, 0xFD, 0x0E, 0x4B, ++ 0x0E, 0x4A, 0xD3, 0xF8, 0x4C, 0x32, 0x21, 0x46, 0x28, 0x46, 0x98, 0x47, ++ 0x30, 0xB1, 0x0C, 0x4A, 0x13, 0x7A, 0x23, 0xB1, 0x01, 0x3B, 0xDB, 0xB2, ++ 0x13, 0x72, 0x03, 0xB1, 0x38, 0xBD, 0x01, 0x23, 0x13, 0x70, 0x51, 0x88, ++ 0xBD, 0xE8, 0x38, 0x40, 0x00, 0x22, 0x32, 0x20, 0x03, 0xF0, 0x4A, 0xBF, ++ 0x68, 0xA3, 0x15, 0x00, 0x44, 0xA3, 0x15, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0xB1, 0xEB, 0x13, 0x00, 0x1C, 0x9E, 0x17, 0x00, 0x38, 0xB5, 0x18, 0x4A, ++ 0x0B, 0x46, 0x0C, 0x46, 0x05, 0x46, 0x17, 0x49, 0x02, 0x20, 0x05, 0xF0, ++ 0x87, 0xFD, 0x16, 0x4B, 0x16, 0x4A, 0xD3, 0xF8, 0x4C, 0x32, 0x21, 0x46, ++ 0x28, 0x46, 0x98, 0x47, 0xF8, 0xB1, 0x14, 0x48, 0x03, 0x7A, 0xBB, 0xB9, ++ 0x13, 0x4B, 0x9B, 0x68, 0x63, 0xB1, 0x93, 0xF8, 0x62, 0x20, 0x32, 0xB9, ++ 0x93, 0xF8, 0x64, 0x20, 0x1A, 0xB1, 0x5A, 0x68, 0x22, 0xF0, 0x0E, 0x02, ++ 0x5A, 0x60, 0x1B, 0x68, 0x00, 0x2B, 0xF2, 0xD1, 0x00, 0x22, 0x02, 0x70, ++ 0x41, 0x88, 0xBD, 0xE8, 0x38, 0x40, 0x32, 0x20, 0x03, 0xF0, 0x14, 0xBF, ++ 0x01, 0x3B, 0xDB, 0xB2, 0x03, 0x72, 0x00, 0x2B, 0xE2, 0xD0, 0x38, 0xBD, ++ 0x78, 0xA3, 0x15, 0x00, 0x44, 0xA3, 0x15, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x09, 0xEC, 0x13, 0x00, 0x1C, 0x9E, 0x17, 0x00, 0x00, 0x88, 0x17, 0x00, ++ 0x38, 0xB5, 0x11, 0xF4, 0x00, 0x03, 0x04, 0x46, 0x2A, 0xD1, 0x90, 0xF8, ++ 0x6B, 0x00, 0x25, 0x49, 0x01, 0x30, 0xC0, 0xB2, 0x09, 0x68, 0x84, 0xF8, ++ 0x6B, 0x00, 0x49, 0x78, 0x81, 0x42, 0x29, 0xD0, 0x94, 0xF8, 0x64, 0x50, ++ 0x00, 0x2D, 0x34, 0xD1, 0x1F, 0x4A, 0x20, 0x4B, 0x52, 0x78, 0x01, 0x21, ++ 0x19, 0x77, 0x22, 0xB1, 0x1E, 0x49, 0x0A, 0x68, 0x22, 0xF0, 0x00, 0x42, ++ 0x0A, 0x60, 0x1A, 0x7A, 0x0A, 0xB1, 0x01, 0x3A, 0x1A, 0x72, 0x1B, 0x4A, ++ 0x1B, 0x48, 0xD2, 0xF8, 0xD8, 0x21, 0x00, 0x21, 0x59, 0x77, 0x90, 0x47, ++ 0x63, 0x68, 0x23, 0xF4, 0x00, 0x73, 0x63, 0x60, 0x28, 0x46, 0x38, 0xBD, ++ 0x28, 0xB1, 0x00, 0x23, 0x01, 0x25, 0x80, 0xF8, 0x6B, 0x30, 0x28, 0x46, ++ 0x38, 0xBD, 0x01, 0x25, 0x28, 0x46, 0x38, 0xBD, 0x11, 0x49, 0x84, 0xF8, ++ 0x6B, 0x30, 0x4F, 0xF4, 0x80, 0x60, 0x05, 0xF0, 0x11, 0xFD, 0x0C, 0x4B, ++ 0x20, 0x46, 0xD3, 0xF8, 0xBC, 0x31, 0x01, 0x25, 0x98, 0x47, 0x28, 0x46, ++ 0x38, 0xBD, 0x11, 0x46, 0x1D, 0x46, 0x94, 0xF8, 0x6C, 0x00, 0x22, 0x46, ++ 0xF1, 0xF7, 0xD0, 0xF9, 0x28, 0x46, 0x38, 0xBD, 0xC8, 0x35, 0x17, 0x00, ++ 0x4C, 0x36, 0x17, 0x00, 0x1C, 0x9E, 0x17, 0x00, 0x34, 0x04, 0x32, 0x40, ++ 0x88, 0x1A, 0x17, 0x00, 0x28, 0x9E, 0x17, 0x00, 0x4C, 0xA3, 0x15, 0x00, ++ 0x70, 0xB5, 0x13, 0x4D, 0x2B, 0x78, 0x13, 0xB3, 0x2B, 0x7F, 0x03, 0xB3, ++ 0x11, 0x4A, 0x12, 0x49, 0x13, 0x68, 0x8C, 0x68, 0x43, 0xF0, 0x04, 0x03, ++ 0x00, 0x21, 0x13, 0x60, 0x29, 0x72, 0xB4, 0xB1, 0x0E, 0x4E, 0x94, 0xF8, ++ 0x62, 0x30, 0x7B, 0xB9, 0x94, 0xF8, 0x64, 0x30, 0x63, 0xB1, 0x94, 0xF8, ++ 0x6C, 0x00, 0xFF, 0x28, 0x22, 0x46, 0x07, 0xD0, 0xD6, 0xF8, 0x34, 0x12, ++ 0xF1, 0xF7, 0xA0, 0xF9, 0x10, 0xB9, 0x2B, 0x7A, 0x01, 0x33, 0x2B, 0x72, ++ 0x24, 0x68, 0x00, 0x2C, 0xE9, 0xD1, 0x70, 0xBD, 0x1C, 0x9E, 0x17, 0x00, ++ 0x4C, 0x00, 0x32, 0x40, 0x00, 0x88, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x70, 0xB5, 0x12, 0x4D, 0x2B, 0x7F, 0xFB, 0xB9, 0x11, 0x49, 0x12, 0x48, ++ 0x0A, 0x68, 0x84, 0x68, 0x2B, 0x72, 0x22, 0xF0, 0x04, 0x02, 0x0A, 0x60, ++ 0xB4, 0xB1, 0x0F, 0x4E, 0x94, 0xF8, 0x62, 0x30, 0x7B, 0xB9, 0x94, 0xF8, ++ 0x64, 0x30, 0x63, 0xB1, 0x94, 0xF8, 0x6C, 0x00, 0xFF, 0x28, 0x22, 0x46, ++ 0x07, 0xD0, 0xD6, 0xF8, 0x58, 0x12, 0xF1, 0xF7, 0x73, 0xF9, 0x10, 0xB9, ++ 0x2B, 0x7A, 0x01, 0x33, 0x2B, 0x72, 0x24, 0x68, 0x00, 0x2C, 0xE9, 0xD1, ++ 0x70, 0xBD, 0x00, 0xBF, 0x1C, 0x9E, 0x17, 0x00, 0x4C, 0x00, 0x32, 0x40, ++ 0x00, 0x88, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x70, 0xB5, 0x2E, 0x4B, ++ 0x2E, 0x4D, 0x1B, 0x68, 0x2E, 0x4A, 0x1B, 0x78, 0xD2, 0xF8, 0xF8, 0x21, ++ 0x01, 0x2B, 0x6B, 0x68, 0x04, 0x46, 0x03, 0xF0, 0x20, 0x03, 0x44, 0xD0, ++ 0x13, 0x43, 0x0C, 0xBF, 0x01, 0x20, 0x00, 0x20, 0x94, 0xF8, 0xAC, 0x30, ++ 0x53, 0xB1, 0x27, 0x4B, 0x1B, 0x68, 0x1B, 0x78, 0x13, 0xB1, 0x94, 0xF8, ++ 0x64, 0x30, 0x33, 0xBB, 0x00, 0x23, 0x6B, 0x77, 0x63, 0x60, 0x70, 0xBD, ++ 0x21, 0x4B, 0x1B, 0x68, 0x1B, 0x78, 0x00, 0x2B, 0xF6, 0xD0, 0x94, 0xF8, ++ 0x64, 0x30, 0x00, 0x2B, 0xF2, 0xD0, 0xC0, 0xB1, 0x1D, 0x4B, 0x1A, 0x68, ++ 0x92, 0x01, 0x05, 0xD4, 0x1B, 0x68, 0x9B, 0x01, 0x11, 0xD4, 0x95, 0xF8, ++ 0x24, 0x30, 0x73, 0xB1, 0x6B, 0x7F, 0x05, 0x2B, 0x05, 0xD1, 0x63, 0x68, ++ 0x00, 0x22, 0x23, 0xF0, 0x02, 0x03, 0x63, 0x60, 0x6A, 0x77, 0x15, 0x4B, ++ 0xBD, 0xE8, 0x70, 0x40, 0xD3, 0xF8, 0x50, 0x32, 0x18, 0x47, 0x13, 0x4B, ++ 0x13, 0x4A, 0x19, 0x68, 0x10, 0x4B, 0xC9, 0x8E, 0x6C, 0x61, 0x01, 0x20, ++ 0x68, 0x77, 0x12, 0x69, 0xD3, 0xF8, 0xE0, 0x31, 0x0F, 0x48, 0xBD, 0xE8, ++ 0x70, 0x40, 0x11, 0x44, 0x18, 0x47, 0x13, 0x43, 0x01, 0xD0, 0x00, 0x20, ++ 0xBA, 0xE7, 0xE9, 0xF7, 0x37, 0xFD, 0x00, 0x38, 0x18, 0xBF, 0x01, 0x20, ++ 0xB4, 0xE7, 0x00, 0xBF, 0x78, 0x36, 0x17, 0x00, 0x1C, 0x9E, 0x17, 0x00, ++ 0x20, 0x62, 0x17, 0x00, 0x74, 0x36, 0x17, 0x00, 0x4C, 0x00, 0x32, 0x40, ++ 0x88, 0x1A, 0x17, 0x00, 0xC8, 0x35, 0x17, 0x00, 0x00, 0x10, 0x50, 0x40, ++ 0x28, 0x9E, 0x17, 0x00, 0x10, 0xB5, 0x06, 0x4C, 0x28, 0x22, 0x20, 0x46, ++ 0x00, 0x21, 0xE1, 0xF7, 0x5F, 0xF9, 0x04, 0x4A, 0x01, 0x23, 0xD2, 0xF8, ++ 0x38, 0x22, 0x22, 0x61, 0x23, 0x77, 0x10, 0xBD, 0x1C, 0x9E, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x10, 0xB5, 0x0C, 0x4C, 0x23, 0x78, 0x33, 0xB9, ++ 0x0B, 0x4B, 0xD3, 0xF8, 0xF8, 0x31, 0x98, 0x47, 0x08, 0xB9, 0x00, 0x20, ++ 0x10, 0xBD, 0x63, 0x68, 0x00, 0x2B, 0xFA, 0xD1, 0x07, 0x4B, 0x9B, 0x68, ++ 0x13, 0xB9, 0x05, 0xE0, 0x1B, 0x68, 0x1B, 0xB1, 0x5A, 0x68, 0x00, 0x2A, ++ 0xFA, 0xD0, 0xF0, 0xE7, 0x01, 0x20, 0x10, 0xBD, 0x1C, 0x9E, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x00, 0x88, 0x17, 0x00, 0x08, 0x4B, 0x09, 0x4A, ++ 0x1B, 0x68, 0x51, 0x80, 0x1B, 0x78, 0x02, 0x2B, 0x07, 0x4B, 0x03, 0xD0, ++ 0x07, 0x49, 0x00, 0x28, 0x18, 0xBF, 0x0B, 0x46, 0x00, 0x20, 0x10, 0x72, ++ 0x4F, 0xF4, 0x00, 0x01, 0x18, 0x47, 0x00, 0xBF, 0x78, 0x36, 0x17, 0x00, ++ 0x1C, 0x9E, 0x17, 0x00, 0x09, 0xEC, 0x13, 0x00, 0xB1, 0xEB, 0x13, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x47, 0x92, 0xF8, 0x6C, 0x30, 0x42, 0x4C, 0x43, 0x4E, ++ 0x51, 0x68, 0x4F, 0xF4, 0x1E, 0x75, 0x91, 0x46, 0x05, 0xFB, 0x03, 0x43, ++ 0x32, 0x78, 0x1D, 0x8C, 0x21, 0xF0, 0x01, 0x07, 0xC9, 0xF8, 0x04, 0x70, ++ 0x00, 0x2A, 0x49, 0xD0, 0x04, 0x46, 0x00, 0x28, 0x46, 0xD0, 0x99, 0xF8, ++ 0x6A, 0x30, 0x00, 0x2B, 0x44, 0xD0, 0x00, 0xF1, 0x04, 0x08, 0x98, 0xF8, ++ 0x00, 0x30, 0x03, 0xF0, 0xFE, 0x03, 0xB3, 0xEB, 0xD5, 0x0F, 0x4F, 0xEA, ++ 0xD5, 0x00, 0x31, 0xD8, 0x61, 0x78, 0x04, 0x39, 0x19, 0x44, 0x88, 0x42, ++ 0x2C, 0xD8, 0x20, 0x44, 0xC3, 0x1A, 0x05, 0xF0, 0x07, 0x05, 0x59, 0x79, ++ 0x01, 0x23, 0x03, 0xFA, 0x05, 0xF5, 0x29, 0x42, 0x22, 0xD0, 0x2C, 0x4B, ++ 0x19, 0x68, 0x8A, 0x05, 0x03, 0xD5, 0x19, 0x68, 0x21, 0xF4, 0x00, 0x71, ++ 0x19, 0x60, 0x29, 0x4C, 0xD4, 0xF8, 0x54, 0x32, 0x98, 0x47, 0x28, 0x48, ++ 0xD9, 0xF8, 0x04, 0x30, 0x00, 0x68, 0x27, 0x49, 0xD4, 0xF8, 0xE0, 0x41, ++ 0x40, 0x8F, 0x43, 0xF0, 0x04, 0x03, 0xC9, 0xF8, 0x04, 0x30, 0x09, 0x69, ++ 0xC6, 0xF8, 0x14, 0x90, 0x06, 0x23, 0x73, 0x77, 0x01, 0x44, 0x23, 0x46, ++ 0x20, 0x48, 0xBD, 0xE8, 0xF0, 0x47, 0x18, 0x47, 0xD9, 0xF8, 0x04, 0x30, ++ 0x23, 0xF0, 0x04, 0x03, 0xC9, 0xF8, 0x04, 0x30, 0xBD, 0xE8, 0xF0, 0x87, ++ 0x03, 0x79, 0x00, 0xF1, 0x04, 0x08, 0xD8, 0x07, 0x1E, 0xD5, 0x14, 0x4B, ++ 0x47, 0xF0, 0x02, 0x07, 0xC9, 0xF8, 0x04, 0x70, 0x19, 0x68, 0x89, 0x05, ++ 0x03, 0xD5, 0x19, 0x68, 0x21, 0xF4, 0x00, 0x71, 0x19, 0x60, 0x73, 0x7F, ++ 0x00, 0x2B, 0xA8, 0xD1, 0x0E, 0x4B, 0x0F, 0x49, 0x1B, 0x68, 0x09, 0x69, ++ 0x1F, 0x8F, 0x0B, 0x4B, 0xC6, 0xF8, 0x14, 0x90, 0x05, 0x20, 0x70, 0x77, ++ 0xD3, 0xF8, 0xE0, 0x31, 0x0A, 0x48, 0x39, 0x44, 0x98, 0x47, 0x98, 0xE7, ++ 0x21, 0xF0, 0x03, 0x01, 0xC9, 0xF8, 0x04, 0x10, 0x93, 0xE7, 0x00, 0xBF, ++ 0x68, 0x65, 0x17, 0x00, 0x1C, 0x9E, 0x17, 0x00, 0x90, 0xB3, 0x33, 0x40, ++ 0x88, 0x1A, 0x17, 0x00, 0xC8, 0x35, 0x17, 0x00, 0x00, 0x10, 0x50, 0x40, ++ 0x28, 0x9E, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x41, 0x21, 0x4E, 0x14, 0x46, ++ 0x52, 0x68, 0x35, 0x78, 0x22, 0xF0, 0x01, 0x03, 0x63, 0x60, 0x00, 0x2D, ++ 0x32, 0xD0, 0x0F, 0x46, 0x94, 0xF8, 0x6A, 0x10, 0xA1, 0xB9, 0x00, 0x28, ++ 0x2E, 0xD0, 0x1B, 0x4A, 0x1B, 0x49, 0x10, 0x68, 0x1B, 0x4A, 0x00, 0x8F, ++ 0xD2, 0xF8, 0xE0, 0x21, 0x43, 0xF0, 0x02, 0x03, 0x63, 0x60, 0x09, 0x69, ++ 0x74, 0x61, 0x05, 0x23, 0x01, 0x44, 0x73, 0x77, 0x06, 0xF1, 0x0C, 0x00, ++ 0x90, 0x47, 0x63, 0x68, 0xAF, 0xB1, 0x13, 0x4D, 0x43, 0xF0, 0x04, 0x03, ++ 0x63, 0x60, 0xD5, 0xF8, 0x54, 0x32, 0x98, 0x47, 0x0D, 0x4B, 0x0E, 0x4A, ++ 0x1B, 0x68, 0x11, 0x69, 0x58, 0x8F, 0x74, 0x61, 0x06, 0x22, 0xD5, 0xF8, ++ 0xE0, 0x31, 0x72, 0x77, 0x01, 0x44, 0xBD, 0xE8, 0xF0, 0x41, 0x0A, 0x48, ++ 0x18, 0x47, 0x23, 0xF0, 0x04, 0x03, 0x63, 0x60, 0xBD, 0xE8, 0xF0, 0x81, ++ 0x22, 0xF0, 0x03, 0x03, 0x00, 0x2F, 0xF6, 0xD0, 0xDF, 0xE7, 0x00, 0xBF, ++ 0x1C, 0x9E, 0x17, 0x00, 0xC8, 0x35, 0x17, 0x00, 0x00, 0x10, 0x50, 0x40, ++ 0x88, 0x1A, 0x17, 0x00, 0x28, 0x9E, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x41, ++ 0x21, 0x4D, 0x2B, 0x78, 0xAB, 0xB1, 0x03, 0x79, 0x06, 0x88, 0xDF, 0x07, ++ 0x14, 0x46, 0x12, 0xD5, 0x6B, 0x7F, 0x05, 0x2B, 0x07, 0xD1, 0x1D, 0x4B, ++ 0x05, 0xF1, 0x0C, 0x00, 0xD3, 0xF8, 0xD8, 0x31, 0x98, 0x47, 0x00, 0x23, ++ 0x6B, 0x77, 0xB5, 0x04, 0x23, 0xD4, 0x63, 0x68, 0x23, 0xF0, 0x02, 0x03, ++ 0x63, 0x60, 0xBD, 0xE8, 0xF0, 0x81, 0x88, 0x05, 0xFB, 0xD4, 0x15, 0x4A, ++ 0x15, 0x4B, 0x12, 0x68, 0x1B, 0x69, 0xD1, 0x8E, 0x11, 0x4F, 0x6C, 0x61, ++ 0x02, 0x22, 0x19, 0x44, 0x6A, 0x77, 0xD7, 0xF8, 0xE0, 0x31, 0x05, 0xF1, ++ 0x0C, 0x00, 0x98, 0x47, 0xB1, 0x04, 0x63, 0x68, 0x0E, 0xD5, 0x5A, 0x07, ++ 0x5C, 0xBF, 0x43, 0xF0, 0x04, 0x03, 0x63, 0x60, 0xD7, 0xF8, 0x54, 0x32, ++ 0xBD, 0xE8, 0xF0, 0x41, 0x18, 0x47, 0x94, 0xF8, 0x6A, 0x30, 0x00, 0x2B, ++ 0xDB, 0xD0, 0xD6, 0xE7, 0x23, 0xF0, 0x04, 0x03, 0x63, 0x60, 0xBD, 0xE8, ++ 0xF0, 0x81, 0x00, 0xBF, 0x1C, 0x9E, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0xC8, 0x35, 0x17, 0x00, 0x00, 0x10, 0x50, 0x40, 0x38, 0xB5, 0x23, 0x4B, ++ 0x1A, 0x78, 0x00, 0x2A, 0x3F, 0xD0, 0xFF, 0x28, 0x3D, 0xD0, 0xFF, 0x29, ++ 0x3B, 0xD0, 0x20, 0x4A, 0x20, 0x49, 0x4F, 0xF4, 0x1E, 0x74, 0x04, 0xFB, ++ 0x00, 0x20, 0x4F, 0xF4, 0xA4, 0x64, 0x90, 0xF8, 0x22, 0x20, 0x04, 0xFB, ++ 0x02, 0x12, 0x92, 0xF8, 0x62, 0x10, 0x00, 0x29, 0x2B, 0xD1, 0x92, 0xF8, ++ 0x64, 0x10, 0x41, 0xB3, 0x18, 0x48, 0x19, 0x49, 0x00, 0x68, 0x09, 0x69, ++ 0xC5, 0x8E, 0x18, 0x4C, 0x5A, 0x61, 0x03, 0x20, 0x58, 0x77, 0xD4, 0xF8, ++ 0xE0, 0x21, 0x03, 0xF1, 0x0C, 0x00, 0x29, 0x44, 0x90, 0x47, 0x14, 0x4B, ++ 0x1B, 0x68, 0x5B, 0x07, 0x15, 0xD5, 0x13, 0x4B, 0x93, 0xF8, 0xB6, 0x30, ++ 0x73, 0xB1, 0x12, 0x4B, 0x1B, 0x68, 0x1B, 0x78, 0x02, 0x2B, 0x09, 0xD1, ++ 0x10, 0x49, 0x11, 0x4A, 0x0B, 0x68, 0x23, 0xF4, 0x00, 0x73, 0x0B, 0x60, ++ 0x13, 0x68, 0x23, 0xF0, 0x01, 0x03, 0x13, 0x60, 0xD4, 0xF8, 0x54, 0x32, ++ 0x98, 0x47, 0x00, 0x20, 0x38, 0xBD, 0x00, 0xBF, 0x1C, 0x9E, 0x17, 0x00, ++ 0x68, 0x65, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, 0xC8, 0x35, 0x17, 0x00, ++ 0x00, 0x10, 0x50, 0x40, 0x88, 0x1A, 0x17, 0x00, 0x4C, 0x00, 0x32, 0x40, ++ 0x2C, 0x19, 0x17, 0x00, 0x74, 0x36, 0x17, 0x00, 0x90, 0xB3, 0x33, 0x40, ++ 0x8C, 0x00, 0x32, 0x40, 0x3B, 0x4A, 0xDF, 0xF8, 0x1C, 0xC1, 0x13, 0x68, ++ 0x3A, 0x49, 0xF0, 0xB5, 0x3A, 0x4F, 0x3B, 0x4C, 0xB7, 0xF8, 0xB2, 0x00, ++ 0x3A, 0x4D, 0x3B, 0x4E, 0x43, 0xF0, 0x80, 0x43, 0x13, 0x60, 0x23, 0x68, ++ 0x39, 0x4A, 0x43, 0xF0, 0x80, 0x53, 0x23, 0x60, 0xDC, 0xF8, 0x00, 0x30, ++ 0x23, 0xF4, 0x70, 0x23, 0xCC, 0xF8, 0x00, 0x30, 0xDC, 0xF8, 0x00, 0x30, ++ 0x23, 0xF0, 0xFF, 0x03, 0x43, 0xF0, 0x10, 0x03, 0xCC, 0xF8, 0x00, 0x30, ++ 0x2B, 0x68, 0x23, 0xF0, 0xFC, 0x03, 0x43, 0xF0, 0x10, 0x03, 0x2B, 0x60, ++ 0x0B, 0x68, 0x40, 0x09, 0x00, 0xF1, 0x20, 0x0C, 0xC3, 0xF3, 0x15, 0x03, ++ 0x43, 0xEA, 0x8C, 0x53, 0x0B, 0x60, 0x83, 0xB0, 0x33, 0x68, 0x29, 0x49, ++ 0x1B, 0x78, 0xCD, 0xF8, 0x00, 0xC0, 0x02, 0x20, 0x05, 0xF0, 0x0A, 0xFA, ++ 0x32, 0x68, 0x13, 0x78, 0x01, 0x2B, 0x15, 0xD0, 0x02, 0x2B, 0x11, 0xD1, ++ 0x23, 0x48, 0x24, 0x49, 0x03, 0x68, 0x24, 0x4C, 0x1D, 0x4A, 0x43, 0xF4, ++ 0x80, 0x33, 0x03, 0x60, 0x0B, 0x68, 0x3F, 0x20, 0x23, 0xF0, 0x00, 0x73, ++ 0x0B, 0x60, 0x20, 0x60, 0x13, 0x68, 0x23, 0xF0, 0x01, 0x03, 0x13, 0x60, ++ 0x03, 0xB0, 0xF0, 0xBD, 0x97, 0xF8, 0xB5, 0x10, 0x69, 0xB1, 0x19, 0x49, ++ 0x19, 0x48, 0x0B, 0x68, 0x23, 0xF0, 0x00, 0x73, 0x0B, 0x60, 0x2B, 0x68, ++ 0x24, 0x21, 0x43, 0xF4, 0x00, 0x13, 0x2B, 0x60, 0x01, 0x60, 0x13, 0x78, ++ 0xD8, 0xE7, 0x12, 0x48, 0x12, 0x4E, 0x01, 0x68, 0x12, 0x4D, 0x41, 0xF0, ++ 0x00, 0x71, 0x01, 0x60, 0x04, 0x21, 0x31, 0x60, 0x2B, 0x60, 0x23, 0x68, ++ 0x23, 0xF4, 0x80, 0x23, 0x23, 0xF0, 0x01, 0x03, 0x23, 0x60, 0x13, 0x78, ++ 0xC6, 0xE7, 0x00, 0xBF, 0x90, 0x00, 0x32, 0x40, 0xF0, 0x00, 0x32, 0x40, ++ 0x2C, 0x19, 0x17, 0x00, 0x74, 0x80, 0x32, 0x40, 0x6C, 0x00, 0x32, 0x40, ++ 0x74, 0x36, 0x17, 0x00, 0x88, 0xA3, 0x15, 0x00, 0x5C, 0xA3, 0x15, 0x00, ++ 0x44, 0x00, 0x32, 0x40, 0x4C, 0x00, 0x32, 0x40, 0x98, 0x80, 0x32, 0x40, ++ 0x70, 0x80, 0x32, 0x40, 0x78, 0x00, 0x32, 0x40, 0x15, 0x48, 0x16, 0x4A, ++ 0x16, 0x49, 0x38, 0xB5, 0x03, 0x68, 0x43, 0xF0, 0x00, 0x73, 0x03, 0x60, ++ 0x02, 0x20, 0x05, 0xF0, 0xA7, 0xF9, 0x13, 0x4B, 0x9B, 0x7C, 0x23, 0xB9, ++ 0x12, 0x4A, 0x13, 0x68, 0x23, 0xF0, 0x01, 0x03, 0x13, 0x60, 0x11, 0x4C, ++ 0x11, 0x48, 0x23, 0x68, 0x0E, 0x49, 0x11, 0x4D, 0x11, 0x4A, 0x23, 0xF4, ++ 0x80, 0x33, 0x23, 0x60, 0x03, 0x68, 0x23, 0xF0, 0x80, 0x43, 0x03, 0x60, ++ 0x0B, 0x68, 0x00, 0x20, 0x23, 0xF0, 0x80, 0x53, 0x0B, 0x60, 0x28, 0x60, ++ 0x13, 0x68, 0x23, 0xF0, 0x01, 0x03, 0x13, 0x60, 0x38, 0xBD, 0x00, 0xBF, ++ 0x4C, 0x00, 0x32, 0x40, 0x98, 0xA3, 0x15, 0x00, 0xCC, 0xB5, 0x15, 0x00, ++ 0x00, 0x88, 0x17, 0x00, 0x74, 0x80, 0x32, 0x40, 0x44, 0x00, 0x32, 0x40, ++ 0x90, 0x00, 0x32, 0x40, 0x98, 0x80, 0x32, 0x40, 0x6C, 0x00, 0x32, 0x40, ++ 0x70, 0xB5, 0x90, 0xF8, 0x72, 0x30, 0x01, 0x2B, 0x04, 0x46, 0x11, 0xD0, ++ 0x02, 0x2B, 0x00, 0xD0, 0x70, 0xBD, 0x0C, 0x4D, 0x41, 0x6F, 0x01, 0x23, ++ 0x80, 0xF8, 0x72, 0x30, 0xD5, 0xF8, 0xE0, 0x31, 0x60, 0x30, 0x98, 0x47, ++ 0xD5, 0xF8, 0x18, 0x32, 0x20, 0x46, 0xBD, 0xE8, 0x70, 0x40, 0x18, 0x47, ++ 0x04, 0x4B, 0x00, 0x22, 0x80, 0xF8, 0x72, 0x20, 0xBD, 0xE8, 0x70, 0x40, ++ 0xD3, 0xF8, 0x18, 0x32, 0x18, 0x47, 0x00, 0xBF, 0x88, 0x1A, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0x4F, 0xF0, 0x00, 0x0C, 0x4F, 0xF0, 0x01, 0x0E, ++ 0x83, 0xB0, 0x06, 0x46, 0x04, 0x46, 0x00, 0xF1, 0x60, 0x05, 0x03, 0x46, ++ 0x67, 0x46, 0x71, 0x46, 0x1A, 0x7C, 0x02, 0x2A, 0x13, 0xD1, 0xDA, 0x7C, ++ 0x01, 0x2A, 0x10, 0xD8, 0x96, 0xF8, 0x87, 0x20, 0x32, 0xB1, 0x93, 0xF8, ++ 0x21, 0x20, 0x1A, 0xB1, 0x93, 0xF8, 0x20, 0x20, 0x01, 0x2A, 0x06, 0xD0, ++ 0xDA, 0x68, 0x00, 0x29, 0x00, 0xF0, 0xC0, 0x80, 0x01, 0x37, 0x94, 0x46, ++ 0x00, 0x21, 0x30, 0x33, 0x9D, 0x42, 0xE5, 0xD1, 0x01, 0x22, 0x8E, 0x46, ++ 0x33, 0x46, 0x4F, 0xF0, 0x00, 0x09, 0x00, 0x92, 0xA0, 0x46, 0x1A, 0x7C, ++ 0x02, 0x2A, 0x1D, 0xD1, 0xD9, 0x7C, 0x01, 0x29, 0x1A, 0xD9, 0x96, 0xF8, ++ 0x87, 0x20, 0x32, 0xB1, 0x93, 0xF8, 0x21, 0x20, 0x1A, 0xB1, 0x93, 0xF8, ++ 0x20, 0x20, 0x01, 0x2A, 0x10, 0xD0, 0xD3, 0xE9, 0x06, 0x04, 0xDA, 0x68, ++ 0x04, 0xEB, 0x02, 0x0A, 0xAA, 0xEB, 0x00, 0x00, 0xBE, 0xF1, 0x00, 0x0F, ++ 0x42, 0xD0, 0x00, 0x21, 0x00, 0x91, 0x01, 0x37, 0x81, 0x46, 0x94, 0x46, ++ 0x4F, 0xF0, 0x00, 0x0E, 0x30, 0x33, 0x9D, 0x42, 0xDB, 0xD1, 0x01, 0x96, ++ 0x44, 0x46, 0x00, 0x9E, 0x18, 0xE0, 0x00, 0x2F, 0x5F, 0xD1, 0xA1, 0xEB, ++ 0x09, 0x02, 0x00, 0x2A, 0x58, 0xDB, 0xAC, 0xEB, 0x03, 0x02, 0x00, 0x2A, ++ 0x0B, 0xDB, 0xA3, 0xEB, 0x09, 0x00, 0xAC, 0xEB, 0x01, 0x02, 0x39, 0xEA, ++ 0x20, 0x09, 0x28, 0xBF, 0x99, 0x46, 0x3C, 0xEA, 0x22, 0x0C, 0x28, 0xBF, ++ 0x8C, 0x46, 0x30, 0x34, 0xA5, 0x42, 0x0F, 0xD0, 0x23, 0x7C, 0x01, 0x2B, ++ 0xF9, 0xD1, 0xE3, 0x68, 0xA1, 0x69, 0x19, 0x44, 0xBE, 0xF1, 0x00, 0x0F, ++ 0xDD, 0xD0, 0x30, 0x34, 0x00, 0x26, 0xA5, 0x42, 0x99, 0x46, 0x8C, 0x46, ++ 0xB6, 0x46, 0xEF, 0xD1, 0x33, 0x46, 0x01, 0x9E, 0xC6, 0xF8, 0x80, 0xC0, ++ 0x0B, 0xB1, 0x0C, 0xF1, 0x0A, 0x09, 0xC6, 0xF8, 0x7C, 0x90, 0x03, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x8F, 0xA0, 0xEB, 0x0C, 0x0A, 0xBA, 0xF1, 0x00, 0x0F, ++ 0x80, 0xF2, 0x88, 0x80, 0xA4, 0xEB, 0x02, 0x0B, 0x02, 0xEB, 0x0C, 0x0A, ++ 0x01, 0x39, 0x83, 0x44, 0xA0, 0xEB, 0x0A, 0x0A, 0x01, 0xE0, 0x01, 0x39, ++ 0xB2, 0xD0, 0x0B, 0xEB, 0x02, 0x00, 0x22, 0x44, 0x1A, 0xEB, 0x02, 0x0F, ++ 0xF7, 0xD4, 0xAC, 0xEB, 0x02, 0x04, 0x3C, 0xEA, 0x24, 0x0C, 0x28, 0xBF, ++ 0x94, 0x46, 0x01, 0x29, 0x3D, 0xD0, 0x62, 0x46, 0x00, 0x99, 0x00, 0x29, ++ 0x99, 0xD1, 0xA0, 0xEB, 0x09, 0x01, 0x10, 0xEA, 0x21, 0x00, 0x38, 0xBF, ++ 0x48, 0x46, 0x94, 0xE7, 0x99, 0x46, 0x8C, 0x46, 0xB3, 0xE7, 0xA1, 0xEB, ++ 0x0C, 0x02, 0x00, 0x2A, 0x94, 0xF8, 0x13, 0x80, 0x61, 0xDA, 0x08, 0xF1, ++ 0xFF, 0x30, 0xB8, 0xF1, 0x00, 0x0F, 0xA8, 0xD0, 0xD4, 0xF8, 0x1C, 0xB0, ++ 0x9A, 0x46, 0x03, 0xE0, 0x42, 0x1E, 0x00, 0x28, 0xA1, 0xD0, 0x10, 0x46, ++ 0xDA, 0x44, 0x01, 0xEB, 0x0A, 0x08, 0xA8, 0xEB, 0x0C, 0x02, 0xD2, 0x1A, ++ 0x00, 0x2A, 0xA8, 0xEB, 0x03, 0x08, 0xF1, 0xDB, 0xA6, 0xB1, 0xAC, 0xEB, ++ 0x0A, 0x03, 0x00, 0x2B, 0x29, 0xDB, 0x58, 0xB3, 0xE3, 0x69, 0xC4, 0x46, ++ 0x0A, 0xEB, 0x03, 0x09, 0x00, 0x26, 0x8A, 0xE7, 0xAC, 0xEB, 0x02, 0x01, ++ 0x12, 0xEA, 0x21, 0x02, 0x38, 0xBF, 0x62, 0x46, 0x38, 0xE7, 0x48, 0x46, ++ 0x62, 0x46, 0x5E, 0xE7, 0xA9, 0xEB, 0x0A, 0x03, 0x00, 0x2B, 0x11, 0xDB, ++ 0xAC, 0xEB, 0x0A, 0x03, 0x00, 0x2B, 0x15, 0xDB, 0xA8, 0xEB, 0x09, 0x03, ++ 0x00, 0x2B, 0x14, 0xDB, 0x1B, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0x29, 0xDB, 0xE3, 0x69, 0xC4, 0x46, 0x0A, 0xEB, 0x03, 0x09, ++ 0x4F, 0xF0, 0x00, 0x0E, 0x67, 0xE7, 0xD1, 0x46, 0x00, 0x26, 0x64, 0xE7, ++ 0xC4, 0x46, 0x62, 0xE7, 0xD1, 0x46, 0xB6, 0x46, 0x5F, 0xE7, 0x01, 0x28, ++ 0x15, 0xDD, 0xE3, 0x69, 0x9A, 0x44, 0xAA, 0xEB, 0x09, 0x03, 0xC4, 0x46, ++ 0x39, 0xEA, 0x23, 0x09, 0x28, 0xBF, 0xD1, 0x46, 0xB6, 0x46, 0x52, 0xE7, ++ 0xAC, 0xEB, 0x02, 0x01, 0x12, 0xEA, 0x21, 0x02, 0x38, 0xBF, 0x62, 0x46, ++ 0x8A, 0xE7, 0x40, 0x46, 0x9A, 0x46, 0x88, 0x46, 0xB0, 0xE7, 0xC4, 0x46, ++ 0xB6, 0x46, 0x44, 0xE7, 0x04, 0x49, 0x05, 0x48, 0x40, 0xF2, 0x4D, 0x12, ++ 0x05, 0xF0, 0x64, 0xFA, 0xCE, 0xE7, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x64, 0x7D, 0x15, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0x03, 0x7C, 0x02, 0x2B, 0x83, 0xB0, 0x04, 0x46, 0x69, 0xD0, 0x90, 0xF8, ++ 0x40, 0x30, 0x02, 0x2B, 0x54, 0xD0, 0x94, 0xF8, 0x73, 0xA0, 0xBA, 0xF1, ++ 0x00, 0x0F, 0x18, 0xD1, 0x94, 0xF8, 0x85, 0x30, 0x01, 0x2B, 0x40, 0xF0, ++ 0xD2, 0x80, 0x94, 0xF8, 0x70, 0x30, 0x00, 0x2B, 0x40, 0xF0, 0xB8, 0x80, ++ 0xDF, 0xF8, 0x24, 0x93, 0xC3, 0x4B, 0x94, 0xF8, 0x71, 0x20, 0xD3, 0xF8, ++ 0x5C, 0x34, 0x4F, 0xF4, 0xA4, 0x60, 0x00, 0xFB, 0x02, 0x90, 0x03, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x4F, 0x18, 0x47, 0x94, 0xF8, 0x72, 0x30, 0x01, 0x2B, ++ 0x00, 0xF0, 0x54, 0x81, 0x94, 0xF8, 0x70, 0x30, 0x01, 0x2B, 0x00, 0xF0, ++ 0xB9, 0x81, 0xB9, 0x4A, 0x92, 0xF8, 0x00, 0xA0, 0xBA, 0xF1, 0x00, 0x0F, ++ 0x00, 0xF0, 0xA8, 0x80, 0x52, 0x68, 0x11, 0x07, 0x00, 0xF1, 0xD4, 0x81, ++ 0x94, 0xF8, 0x85, 0x30, 0x00, 0x2B, 0x00, 0xF0, 0x8F, 0x80, 0x94, 0xF8, ++ 0x71, 0x80, 0xDF, 0xF8, 0xD0, 0x92, 0x02, 0x23, 0x0C, 0x21, 0x00, 0x22, ++ 0x4D, 0x20, 0x03, 0xF0, 0x15, 0xF9, 0x01, 0x25, 0x94, 0xF8, 0x71, 0x20, ++ 0x02, 0x70, 0x45, 0x70, 0x03, 0xF0, 0x3E, 0xF9, 0x4F, 0xF4, 0xA4, 0x63, ++ 0x03, 0xFB, 0x08, 0x93, 0x00, 0x22, 0x84, 0xF8, 0x85, 0x20, 0x18, 0x6C, ++ 0x29, 0x46, 0xFF, 0xF7, 0x15, 0xF9, 0x55, 0xE0, 0x90, 0xF8, 0x87, 0x30, ++ 0x00, 0x2B, 0x7B, 0xD0, 0xFF, 0x23, 0x00, 0x21, 0x94, 0xF8, 0x51, 0x20, ++ 0x00, 0x2A, 0x6F, 0xD0, 0x94, 0xF8, 0x50, 0x20, 0x01, 0x2A, 0x6B, 0xD1, ++ 0x00, 0x29, 0x9A, 0xD0, 0x11, 0xE0, 0x90, 0xF8, 0x87, 0x30, 0x00, 0x2B, ++ 0x5F, 0xD0, 0x90, 0xF8, 0x21, 0x30, 0x23, 0xB1, 0x90, 0xF8, 0x20, 0x30, ++ 0x01, 0x2B, 0x00, 0xF0, 0xA6, 0x81, 0x94, 0xF8, 0x40, 0x20, 0x23, 0x7D, ++ 0x02, 0x2A, 0x00, 0xF0, 0x9E, 0x81, 0x01, 0x2B, 0xB8, 0xD0, 0x94, 0xF8, ++ 0x86, 0xA0, 0xBA, 0xF1, 0x00, 0x0F, 0x40, 0xF0, 0x0D, 0x81, 0x94, 0xF8, ++ 0x72, 0x50, 0x94, 0xF8, 0x85, 0x30, 0xA5, 0xF1, 0x01, 0x06, 0xB6, 0xFA, ++ 0x86, 0xF6, 0x76, 0x09, 0xB3, 0x42, 0x00, 0xF0, 0x4C, 0x81, 0x02, 0x23, ++ 0x0C, 0x21, 0x52, 0x46, 0x4D, 0x20, 0x94, 0xF8, 0x71, 0x80, 0xDF, 0xF8, ++ 0x20, 0x92, 0x03, 0xF0, 0xC1, 0xF8, 0x6F, 0x1E, 0x18, 0xBF, 0x01, 0x27, ++ 0x94, 0xF8, 0x71, 0x20, 0x02, 0x70, 0x47, 0x70, 0x03, 0xF0, 0xE8, 0xF8, ++ 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x08, 0x93, 0x84, 0xF8, 0x85, 0x60, ++ 0x18, 0x6C, 0x39, 0x46, 0xFF, 0xF7, 0xC0, 0xF8, 0x01, 0x2D, 0x4C, 0xD0, ++ 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x08, 0x93, 0x93, 0xF8, 0x62, 0x20, ++ 0x02, 0x2A, 0x00, 0xF0, 0xF1, 0x80, 0x94, 0xF8, 0x70, 0x30, 0x7B, 0xB9, ++ 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x08, 0x98, 0x98, 0xF8, 0x6C, 0x30, ++ 0xFF, 0x2B, 0x07, 0xD0, 0x6E, 0x4A, 0x4F, 0xF4, 0x1E, 0x71, 0x01, 0xFB, ++ 0x03, 0x23, 0x01, 0x22, 0x83, 0xF8, 0x24, 0x20, 0x03, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x8F, 0x90, 0xF8, 0x40, 0x20, 0x03, 0x7D, 0x02, 0x2A, 0xA8, 0xD1, ++ 0x94, 0xF8, 0x44, 0x20, 0x93, 0x42, 0x28, 0xBF, 0x13, 0x46, 0xA2, 0xE7, ++ 0xFF, 0x23, 0xF7, 0xE7, 0x94, 0xF8, 0x85, 0x20, 0x01, 0x2A, 0x3F, 0xF4, ++ 0x30, 0xAF, 0x94, 0xF8, 0x71, 0x80, 0xDF, 0xF8, 0x88, 0x91, 0x02, 0x23, ++ 0x0C, 0x21, 0x00, 0x22, 0x4D, 0x20, 0x03, 0xF0, 0x71, 0xF8, 0x00, 0x25, ++ 0x94, 0xF8, 0x71, 0x20, 0x02, 0x70, 0x45, 0x70, 0x03, 0xF0, 0x9A, 0xF8, ++ 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x08, 0x93, 0x01, 0x22, 0x84, 0xF8, ++ 0x85, 0x20, 0x18, 0x6C, 0x29, 0x46, 0xFF, 0xF7, 0x71, 0xF8, 0x94, 0xF8, ++ 0x70, 0xE0, 0xBE, 0xF1, 0x00, 0x0F, 0x40, 0xF0, 0xD4, 0x80, 0x4F, 0xF4, ++ 0xA4, 0x67, 0x07, 0xFB, 0x08, 0x97, 0x97, 0xF8, 0x6C, 0x10, 0xFF, 0x29, ++ 0x00, 0xF0, 0xF0, 0x80, 0x4A, 0x4D, 0x01, 0x94, 0x4F, 0xF4, 0x1E, 0x7B, ++ 0xA4, 0x23, 0x0B, 0xFB, 0x01, 0xF0, 0x03, 0xFB, 0x08, 0xF3, 0x05, 0xF5, ++ 0x16, 0x7B, 0x2E, 0x18, 0x9E, 0x33, 0x58, 0x44, 0x00, 0x90, 0x09, 0xEB, ++ 0xC3, 0x0B, 0x4F, 0xF0, 0x4F, 0x0C, 0x46, 0x20, 0x1C, 0xFB, 0x01, 0x01, ++ 0x5C, 0x46, 0x40, 0x4A, 0xDD, 0xF8, 0x00, 0xB0, 0x86, 0xF8, 0x24, 0xE0, ++ 0x05, 0xEB, 0xC1, 0x05, 0xD6, 0xF8, 0x08, 0x12, 0x39, 0xB3, 0xEF, 0xF3, ++ 0x10, 0x81, 0xCB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x39, 0x4B, 0x01, 0x21, ++ 0x19, 0x60, 0x11, 0x68, 0xA5, 0xF1, 0x28, 0x00, 0x4B, 0x1C, 0xA4, 0xF1, ++ 0x28, 0x01, 0x13, 0x60, 0x00, 0x90, 0x03, 0xF0, 0x9D, 0xFD, 0xD6, 0xF8, ++ 0x08, 0x12, 0xD6, 0xF8, 0x0C, 0x32, 0x00, 0x98, 0xC7, 0xF8, 0xC8, 0x14, ++ 0xC7, 0xF8, 0xCC, 0x34, 0x03, 0xF0, 0x9C, 0xFC, 0x2C, 0x4A, 0x11, 0x68, ++ 0x48, 0x1E, 0x31, 0xB1, 0x2B, 0x4B, 0x10, 0x60, 0x19, 0x68, 0x10, 0xB9, ++ 0x00, 0x29, 0x40, 0xF0, 0xB5, 0x80, 0xD6, 0xF8, 0x30, 0x32, 0x20, 0x46, ++ 0x29, 0x46, 0x08, 0x36, 0x08, 0x34, 0x08, 0x37, 0x2B, 0xB1, 0x03, 0xF0, ++ 0x7D, 0xFD, 0x28, 0x46, 0x03, 0xF0, 0x84, 0xFC, 0x20, 0x4A, 0x08, 0x35, ++ 0x5D, 0x45, 0xC3, 0xD1, 0x01, 0x9C, 0x40, 0x20, 0x03, 0xF0, 0xDE, 0xFB, ++ 0x94, 0xF8, 0x70, 0x20, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x08, 0x98, ++ 0x98, 0xF8, 0x62, 0x30, 0x02, 0x2B, 0x13, 0xD0, 0x00, 0x2A, 0x7F, 0xF4, ++ 0x55, 0xAF, 0xBA, 0xF1, 0x00, 0x0F, 0x7F, 0xF4, 0x51, 0xAF, 0x99, 0xE6, ++ 0x94, 0xF8, 0x85, 0x30, 0x01, 0x2B, 0x3F, 0xF4, 0x8E, 0xAE, 0x94, 0xF8, ++ 0x71, 0x80, 0xDF, 0xF8, 0x48, 0x90, 0x4F, 0xF0, 0x00, 0x0A, 0x5C, 0xE7, ++ 0xD8, 0xF8, 0x04, 0x30, 0x43, 0xF0, 0x20, 0x03, 0xC8, 0xF8, 0x04, 0x30, ++ 0x00, 0x2A, 0x7F, 0xF4, 0x3B, 0xAF, 0xE4, 0xE7, 0x94, 0xF8, 0x85, 0x30, ++ 0x01, 0x2B, 0x3F, 0xF4, 0x35, 0xAF, 0x94, 0xF8, 0x71, 0x80, 0xDF, 0xF8, ++ 0x1C, 0x90, 0x4F, 0xF0, 0x01, 0x0A, 0x46, 0xE7, 0x88, 0x1A, 0x17, 0x00, ++ 0x1C, 0x9E, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x38, 0x61, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, 0x3C, 0x49, 0x5A, 0x68, ++ 0x49, 0x68, 0x22, 0xF0, 0x20, 0x02, 0x00, 0x29, 0x5A, 0x60, 0x7F, 0xF7, ++ 0x06, 0xAF, 0xEF, 0xF3, 0x10, 0x83, 0xDA, 0x07, 0x03, 0xD4, 0x72, 0xB6, ++ 0x36, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x36, 0x4D, 0x2B, 0x68, 0x04, 0x20, ++ 0x01, 0x33, 0x2B, 0x60, 0xEE, 0xF7, 0x1C, 0xFF, 0x4F, 0xF0, 0x80, 0x41, ++ 0x04, 0x20, 0xEE, 0xF7, 0xB7, 0xFF, 0x2B, 0x68, 0x00, 0x2B, 0x3F, 0xF4, ++ 0xEE, 0xAE, 0x2D, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x2B, 0x60, 0x00, 0x2B, ++ 0x7F, 0xF4, 0xE7, 0xAE, 0x00, 0x2A, 0x3F, 0xF4, 0xE4, 0xAE, 0x62, 0xB6, ++ 0xE1, 0xE6, 0x40, 0x20, 0x03, 0xF0, 0x6E, 0xFB, 0x94, 0xF8, 0x70, 0x20, ++ 0x8E, 0xE7, 0x94, 0xF8, 0x70, 0x30, 0x00, 0x2B, 0x7F, 0xF4, 0xEA, 0xAE, ++ 0x01, 0x2D, 0x7F, 0xF4, 0xE7, 0xAE, 0x2D, 0xE6, 0x94, 0xF8, 0x71, 0x80, ++ 0xDF, 0xF8, 0x80, 0x90, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x08, 0x93, ++ 0x93, 0xF8, 0xDE, 0x20, 0x93, 0xF8, 0xC2, 0x34, 0x9A, 0x42, 0x20, 0xD0, ++ 0x94, 0xF8, 0x85, 0x30, 0x01, 0x2B, 0x3F, 0xF4, 0xD3, 0xAE, 0x4F, 0xF0, ++ 0x00, 0x0A, 0xE8, 0xE6, 0x97, 0xF8, 0x62, 0x30, 0x02, 0x2B, 0x7F, 0xF4, ++ 0x76, 0xAF, 0x7B, 0x68, 0x43, 0xF0, 0x20, 0x03, 0x7B, 0x60, 0xBA, 0xF1, ++ 0x00, 0x0F, 0x7F, 0xF4, 0xC3, 0xAE, 0x0B, 0xE6, 0x62, 0xB6, 0x48, 0xE7, ++ 0x94, 0xF8, 0x85, 0x20, 0x01, 0x2A, 0x7F, 0xF4, 0x70, 0xAF, 0x00, 0x2B, ++ 0x3F, 0xF4, 0x00, 0xAE, 0xB6, 0xE6, 0x94, 0xF8, 0x85, 0x30, 0x00, 0x2B, ++ 0x7F, 0xF4, 0x27, 0xAE, 0xB0, 0xE6, 0x01, 0x21, 0x42, 0xE6, 0x90, 0xF8, ++ 0x40, 0x30, 0x02, 0x2B, 0x7F, 0xF4, 0xE3, 0xAD, 0x3A, 0xE6, 0x00, 0xBF, ++ 0xD8, 0x9C, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, 0xDF, 0xF8, 0xF4, 0x92, ++ 0x47, 0x7C, 0xB6, 0x49, 0x90, 0xF8, 0x10, 0xB0, 0x8C, 0x23, 0x03, 0xFB, ++ 0x07, 0x93, 0x83, 0xB0, 0x93, 0xF8, 0x71, 0x20, 0x93, 0xF8, 0x70, 0x30, ++ 0x00, 0x92, 0x07, 0xEB, 0x87, 0x06, 0x4F, 0xF4, 0xA4, 0x6A, 0xC6, 0xEB, ++ 0xC6, 0x06, 0x01, 0x2B, 0x05, 0x46, 0x0A, 0xFB, 0x02, 0x1A, 0x09, 0xEB, ++ 0x86, 0x06, 0x00, 0xF0, 0x0B, 0x81, 0xAA, 0x4B, 0xC4, 0x6A, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xC0, 0xF2, 0xD3, 0x80, 0xDA, 0xF8, ++ 0x7C, 0x30, 0xE4, 0x1A, 0xA4, 0x4B, 0xA5, 0x49, 0xDF, 0xF8, 0x94, 0x82, ++ 0xBB, 0xF1, 0x01, 0x0F, 0x17, 0xD0, 0xBB, 0xF1, 0x02, 0x0F, 0x00, 0xF0, ++ 0x82, 0x80, 0x1A, 0x68, 0xB2, 0xF9, 0x00, 0x20, 0x00, 0x2A, 0x7F, 0xDB, ++ 0xD8, 0xF8, 0x10, 0x20, 0xA2, 0x1A, 0xA2, 0xF5, 0x9C, 0x52, 0x08, 0x3A, ++ 0x00, 0x2A, 0x80, 0xF2, 0xE9, 0x80, 0xBB, 0xF1, 0x00, 0x0F, 0xE7, 0xD1, ++ 0xDF, 0xF8, 0x70, 0x82, 0x20, 0xE0, 0xA8, 0x69, 0xDF, 0xF8, 0x68, 0x82, ++ 0x95, 0x4B, 0x1B, 0x69, 0x04, 0x44, 0xE3, 0x1A, 0xA3, 0xF5, 0x9C, 0x53, ++ 0x08, 0x3B, 0x00, 0x2B, 0x80, 0xF2, 0xFA, 0x80, 0xEA, 0x7C, 0xFF, 0x2A, ++ 0x1B, 0xD0, 0x01, 0x3A, 0xD2, 0xB2, 0xEA, 0x74, 0xBA, 0xB9, 0x8C, 0x23, ++ 0x03, 0xFB, 0x07, 0x97, 0x97, 0xF8, 0x70, 0x30, 0x01, 0x2B, 0x5D, 0xD0, ++ 0xD8, 0xF8, 0xE8, 0x31, 0x28, 0x46, 0x98, 0x47, 0x87, 0x4B, 0x1B, 0x69, ++ 0xD8, 0xF8, 0x1C, 0x32, 0x30, 0x46, 0x98, 0x47, 0xD8, 0xF8, 0x18, 0x32, ++ 0x30, 0x46, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x4F, 0x18, 0x47, 0x4F, 0xF0, ++ 0x8C, 0x0E, 0x0E, 0xFB, 0x07, 0x9E, 0xD5, 0xE9, 0x06, 0x0B, 0x9E, 0xF8, ++ 0x70, 0x30, 0xAB, 0xEB, 0x00, 0x01, 0x01, 0x2B, 0x0C, 0x44, 0x47, 0xD0, ++ 0x7A, 0x4A, 0x12, 0x69, 0xA2, 0x1A, 0xA2, 0xF5, 0x9C, 0x52, 0x08, 0x3A, ++ 0x00, 0x2A, 0xA8, 0xBF, 0x4F, 0xF0, 0x01, 0x0B, 0xBE, 0xDB, 0x53, 0xB9, ++ 0x72, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xC0, 0xF2, ++ 0xB0, 0x80, 0xDA, 0xF8, 0x7C, 0x30, 0x23, 0x44, 0xEB, 0x62, 0x21, 0x46, ++ 0xD8, 0xF8, 0xE0, 0x31, 0x28, 0x46, 0x98, 0x47, 0x85, 0xF8, 0x10, 0xB0, ++ 0xD8, 0xF8, 0x1C, 0x32, 0x30, 0x46, 0x98, 0x47, 0xD8, 0xF8, 0x18, 0x32, ++ 0x30, 0x46, 0x98, 0x47, 0x00, 0x9A, 0x11, 0x46, 0x63, 0x4A, 0x4F, 0xF4, ++ 0xA4, 0x63, 0x03, 0xFB, 0x01, 0x23, 0x93, 0xF8, 0x62, 0x30, 0x02, 0x2B, ++ 0x00, 0xF0, 0xA4, 0x80, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xDF, 0xF8, ++ 0x90, 0x81, 0x9B, 0xE7, 0x5F, 0x48, 0x4F, 0xF4, 0x31, 0x72, 0x04, 0xF0, ++ 0x53, 0xFF, 0x5A, 0x4B, 0x5A, 0x49, 0x77, 0xE7, 0xD8, 0xF8, 0x08, 0x32, ++ 0xA9, 0x7C, 0x50, 0x46, 0x98, 0x47, 0x58, 0x4B, 0x1B, 0x69, 0x9F, 0xE7, ++ 0x9E, 0xF8, 0x84, 0x10, 0x00, 0x29, 0x36, 0xD0, 0xA9, 0x6A, 0x01, 0x91, ++ 0x69, 0x6A, 0x01, 0xEB, 0x0B, 0x0C, 0x01, 0x99, 0x01, 0x39, 0xC5, 0xE9, ++ 0x09, 0xC1, 0x00, 0x29, 0x5E, 0xD1, 0x2A, 0x75, 0xBB, 0xF1, 0x00, 0x0F, ++ 0x05, 0xD0, 0x4F, 0xF0, 0x00, 0x43, 0xB3, 0xFB, 0xFB, 0xF3, 0x01, 0x3B, ++ 0xAB, 0x62, 0x00, 0x9B, 0x19, 0x46, 0x46, 0x4B, 0x4F, 0xF4, 0xA4, 0x62, ++ 0x02, 0xFB, 0x01, 0x32, 0xD8, 0xF8, 0x90, 0x31, 0x92, 0xF8, 0x63, 0x00, ++ 0x03, 0x21, 0x98, 0x47, 0x43, 0x4B, 0x1B, 0x69, 0xE3, 0x1A, 0xA3, 0xF5, ++ 0x9C, 0x53, 0x08, 0x3B, 0x00, 0x2B, 0x71, 0xDA, 0xA8, 0x69, 0x51, 0xE7, ++ 0x9A, 0xF8, 0x62, 0x30, 0x00, 0x2B, 0x3F, 0xF4, 0x28, 0xAF, 0x3B, 0x49, ++ 0x3D, 0x48, 0x58, 0x22, 0x04, 0xF0, 0x0E, 0xFF, 0x21, 0xE7, 0x39, 0x4A, ++ 0x12, 0x69, 0xA2, 0x1A, 0xA2, 0xF5, 0x9C, 0x52, 0x08, 0x3A, 0x00, 0x2A, ++ 0xFF, 0xF6, 0x3E, 0xAF, 0xD8, 0xF8, 0xE0, 0x21, 0x01, 0x93, 0x21, 0x46, ++ 0x28, 0x46, 0x90, 0x47, 0x01, 0x9B, 0x2B, 0x74, 0xD8, 0xF8, 0x1C, 0x32, ++ 0x30, 0x46, 0x98, 0x47, 0xD8, 0xF8, 0x18, 0x32, 0x30, 0x46, 0x98, 0x47, ++ 0x00, 0x9A, 0x11, 0x46, 0x28, 0x4A, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, ++ 0x01, 0x23, 0x93, 0xF8, 0x62, 0x30, 0x02, 0x2B, 0x8A, 0xD1, 0x31, 0xE0, ++ 0xC4, 0x68, 0xFD, 0xE6, 0xBB, 0xF1, 0x00, 0x0F, 0x3F, 0xF4, 0x16, 0xAF, ++ 0x8C, 0x23, 0x03, 0xFB, 0x07, 0x97, 0xDF, 0xF8, 0x98, 0x80, 0x97, 0xF8, ++ 0x70, 0x30, 0x54, 0xE7, 0x1F, 0x4A, 0x12, 0x69, 0xA2, 0x1A, 0xA2, 0xF5, ++ 0x9C, 0x52, 0x08, 0x3A, 0x00, 0x2A, 0xFF, 0xF6, 0x0B, 0xAF, 0x9B, 0x46, ++ 0x9E, 0xF8, 0x70, 0x30, 0x47, 0xE7, 0x9A, 0xF8, 0x62, 0x30, 0x00, 0x2B, ++ 0x3F, 0xF4, 0x4B, 0xAF, 0x15, 0x49, 0x18, 0x48, 0x49, 0x22, 0x04, 0xF0, ++ 0xC3, 0xFE, 0x44, 0xE7, 0x8C, 0x23, 0x03, 0xFB, 0x07, 0x97, 0x4F, 0xF0, ++ 0x02, 0x0B, 0x97, 0xF8, 0x70, 0x30, 0x34, 0xE7, 0xBB, 0xF1, 0x01, 0x0F, ++ 0x7F, 0xF4, 0x58, 0xAF, 0x00, 0x9A, 0x11, 0x46, 0x09, 0x4A, 0x4F, 0xF4, ++ 0xA4, 0x63, 0x03, 0xFB, 0x01, 0x23, 0x5A, 0x68, 0x42, 0xF0, 0x20, 0x02, ++ 0x5A, 0x60, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x8C, 0x23, 0x03, 0xFB, ++ 0x07, 0x97, 0x4F, 0xF0, 0x01, 0x0B, 0x97, 0xF8, 0x70, 0x30, 0x1A, 0xE7, ++ 0x18, 0x88, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x00, 0x10, 0x50, 0x40, 0x64, 0x7D, 0x15, 0x00, 0x40, 0x9C, 0x15, 0x00, ++ 0x48, 0x9E, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x38, 0xB5, 0x00, 0x22, ++ 0x04, 0x46, 0x0D, 0x46, 0x10, 0x23, 0x0C, 0x21, 0x55, 0x20, 0x02, 0xF0, ++ 0xA5, 0xFD, 0x05, 0xEB, 0x45, 0x03, 0x94, 0xF8, 0x71, 0x20, 0x02, 0x70, ++ 0x04, 0xEB, 0x03, 0x13, 0x45, 0x70, 0x1A, 0x7C, 0x22, 0xB9, 0xC2, 0x70, ++ 0xBD, 0xE8, 0x38, 0x40, 0x02, 0xF0, 0xC6, 0xBD, 0x1A, 0x7D, 0xC2, 0x70, ++ 0x00, 0x2A, 0xF7, 0xD0, 0x93, 0xF8, 0x20, 0x20, 0x82, 0x70, 0xD3, 0xE9, ++ 0x06, 0x12, 0x5B, 0x6A, 0xC3, 0x60, 0xC0, 0xE9, 0x01, 0x12, 0xBD, 0xE8, ++ 0x38, 0x40, 0x02, 0xF0, 0xB5, 0xBD, 0x00, 0xBF, 0x2D, 0xE9, 0xF0, 0x41, ++ 0x16, 0x46, 0x2D, 0x4D, 0x4F, 0xF4, 0xA4, 0x62, 0xB3, 0x42, 0x04, 0x46, ++ 0x02, 0xFB, 0x01, 0x58, 0x0B, 0xD3, 0xC2, 0x7C, 0x01, 0x2A, 0x30, 0xD0, ++ 0xC5, 0x69, 0x9B, 0x1B, 0xB3, 0xFB, 0xF5, 0xF3, 0x03, 0xFB, 0x05, 0x55, ++ 0x2E, 0x44, 0x5F, 0x1C, 0x00, 0xE0, 0x00, 0x27, 0x23, 0x4B, 0xE6, 0x62, ++ 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x28, 0xDB, 0xE3, 0x7C, ++ 0xD8, 0xF8, 0x7C, 0x00, 0xFF, 0x2B, 0xA6, 0xEB, 0x00, 0x00, 0x31, 0xD0, ++ 0xBB, 0x42, 0x94, 0xBF, 0xDB, 0x1A, 0xDB, 0x1B, 0x1B, 0x4A, 0xDB, 0xB2, ++ 0xE3, 0x74, 0x12, 0x69, 0x82, 0x1A, 0x00, 0x2A, 0x0C, 0xDA, 0x18, 0x49, ++ 0x5B, 0xB1, 0xE5, 0x69, 0xFF, 0x2B, 0x28, 0x44, 0x0A, 0xD0, 0x01, 0x3B, ++ 0xDB, 0xB2, 0xE3, 0x74, 0x0A, 0x69, 0x82, 0x1A, 0x00, 0x2A, 0xF3, 0xDB, ++ 0x03, 0xB9, 0x00, 0x20, 0xBD, 0xE8, 0xF0, 0x81, 0x0A, 0x69, 0x82, 0x1A, ++ 0x00, 0x2A, 0xED, 0xDB, 0xBD, 0xE8, 0xF0, 0x81, 0x98, 0xF8, 0x62, 0x30, ++ 0x00, 0x2B, 0xD2, 0xD0, 0x0B, 0x48, 0x0C, 0x49, 0x58, 0x22, 0x04, 0xF0, ++ 0x15, 0xFE, 0xE3, 0x7C, 0xD8, 0xF8, 0x7C, 0x00, 0xFF, 0x2B, 0xA6, 0xEB, ++ 0x00, 0x00, 0xCD, 0xD1, 0x04, 0x4A, 0x12, 0x69, 0x82, 0x1A, 0x00, 0x2A, ++ 0xD3, 0xDB, 0xE1, 0xE7, 0x18, 0x88, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x00, 0x10, 0x50, 0x40, 0x40, 0x9C, 0x15, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x70, 0xB5, 0x08, 0x4E, 0xD6, 0xF8, 0xEC, 0x41, 0x05, 0x46, 0xA0, 0x47, ++ 0x04, 0x46, 0x30, 0xB1, 0xD6, 0xF8, 0xE0, 0x31, 0x01, 0x46, 0x28, 0x46, ++ 0x98, 0x47, 0x01, 0x23, 0x2B, 0x74, 0xE0, 0xB2, 0x70, 0xBD, 0x00, 0xBF, ++ 0x88, 0x1A, 0x17, 0x00, 0x03, 0x7C, 0x43, 0xB1, 0x10, 0xB5, 0x04, 0x4B, ++ 0x04, 0x46, 0xD3, 0xF8, 0xD8, 0x31, 0x98, 0x47, 0x00, 0x23, 0x23, 0x74, ++ 0x10, 0xBD, 0x70, 0x47, 0x88, 0x1A, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0x5C, 0x4F, 0x00, 0xEB, 0x80, 0x04, 0xC4, 0xEB, 0xC4, 0x04, 0x4F, 0xEA, ++ 0x84, 0x0A, 0x83, 0xB0, 0x05, 0x46, 0x07, 0xEB, 0x84, 0x04, 0x0E, 0x46, ++ 0x00, 0x29, 0x74, 0xD0, 0x8C, 0x23, 0x03, 0xFB, 0x00, 0x73, 0x91, 0x46, ++ 0xCA, 0x78, 0x93, 0xF8, 0x84, 0x10, 0x00, 0x29, 0x40, 0xF0, 0x8A, 0x80, ++ 0x4F, 0xF0, 0x8C, 0x08, 0x08, 0xFB, 0x05, 0x78, 0x01, 0x21, 0x98, 0xF8, ++ 0x79, 0x30, 0x88, 0xF8, 0x78, 0x20, 0x88, 0xF8, 0x84, 0x10, 0xAB, 0xB1, ++ 0xDF, 0xF8, 0x30, 0xB1, 0x20, 0x46, 0xDB, 0xF8, 0xE8, 0x31, 0x98, 0x47, ++ 0x00, 0x22, 0x0A, 0xF1, 0x30, 0x00, 0xDB, 0xF8, 0xE8, 0x31, 0x88, 0xF8, ++ 0x79, 0x20, 0x38, 0x44, 0x98, 0x47, 0x00, 0x22, 0xDB, 0xF8, 0x18, 0x32, ++ 0x88, 0xF8, 0x79, 0x20, 0x20, 0x46, 0x98, 0x47, 0xB6, 0xF8, 0x01, 0x20, ++ 0x3F, 0x49, 0x02, 0x3A, 0x81, 0xFB, 0x02, 0x31, 0xD3, 0x17, 0xC3, 0xEB, ++ 0xA1, 0x03, 0x13, 0xF0, 0xFF, 0x0B, 0x2E, 0xD0, 0x8C, 0x23, 0x03, 0xFB, ++ 0x05, 0x73, 0x00, 0x93, 0x06, 0xF1, 0x05, 0x08, 0x4F, 0xF0, 0x00, 0x0A, ++ 0x01, 0x95, 0x98, 0xF8, 0x00, 0x20, 0x36, 0x49, 0x22, 0x75, 0x0A, 0xF1, ++ 0x01, 0x0A, 0x20, 0x46, 0x4B, 0x46, 0x9A, 0xB1, 0x01, 0x2A, 0xD8, 0xF8, ++ 0x05, 0x50, 0x00, 0xD9, 0x75, 0xB1, 0xD8, 0xF8, 0x01, 0xC0, 0xE2, 0x74, ++ 0xC4, 0xE9, 0x06, 0xC5, 0x00, 0x9A, 0xD1, 0xF8, 0xF4, 0x51, 0x92, 0xF8, ++ 0x71, 0x10, 0xD8, 0xF8, 0x09, 0x20, 0xA8, 0x47, 0x00, 0x28, 0x45, 0xD1, ++ 0x5F, 0xFA, 0x8A, 0xF3, 0x5B, 0x45, 0x08, 0xF1, 0x0D, 0x08, 0x04, 0xF1, ++ 0x30, 0x04, 0xDA, 0xD3, 0x01, 0x9D, 0x96, 0xF9, 0x04, 0x20, 0x33, 0x79, ++ 0x00, 0x2A, 0x2D, 0xDB, 0x8C, 0x20, 0x00, 0xFB, 0x05, 0x75, 0x00, 0x23, ++ 0x85, 0xF8, 0x73, 0x30, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x4F, 0xF0, ++ 0x8C, 0x08, 0x08, 0xFB, 0x00, 0x78, 0x98, 0xF8, 0x79, 0x30, 0x88, 0xF8, ++ 0x84, 0x10, 0x00, 0x2B, 0xEC, 0xD0, 0xDF, 0xF8, 0x60, 0x90, 0x20, 0x46, ++ 0xD9, 0xF8, 0xE8, 0x31, 0x98, 0x47, 0x0A, 0xF1, 0x30, 0x00, 0xD9, 0xF8, ++ 0xE8, 0x31, 0x88, 0xF8, 0x79, 0x60, 0x38, 0x44, 0x98, 0x47, 0xD9, 0xF8, ++ 0x18, 0x32, 0x88, 0xF8, 0x79, 0x60, 0x20, 0x46, 0x98, 0x47, 0xD7, 0xE7, ++ 0x93, 0xF8, 0x78, 0x30, 0x93, 0x42, 0x7F, 0xF4, 0x71, 0xAF, 0xD7, 0xE7, ++ 0x8C, 0x20, 0x00, 0xFB, 0x05, 0x75, 0x03, 0xF0, 0x7F, 0x03, 0x85, 0xF8, ++ 0x73, 0x30, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x00, 0x9A, 0x92, 0xF8, ++ 0x79, 0x30, 0x01, 0x33, 0x82, 0xF8, 0x79, 0x30, 0xB2, 0xE7, 0x00, 0xBF, ++ 0x48, 0x9E, 0x17, 0x00, 0x4F, 0xEC, 0xC4, 0x4E, 0x88, 0x1A, 0x17, 0x00, ++ 0x08, 0xB5, 0x01, 0x22, 0x05, 0x48, 0x00, 0x21, 0xE0, 0xF7, 0x2C, 0xF8, ++ 0x04, 0x4B, 0xFF, 0x22, 0x83, 0xF8, 0x71, 0x20, 0x83, 0xF8, 0xFD, 0x20, ++ 0x08, 0xBD, 0x00, 0xBF, 0x44, 0x9E, 0x17, 0x00, 0x48, 0x9E, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x47, 0x25, 0x4C, 0x94, 0xF8, 0x71, 0x30, 0xFF, 0x2B, ++ 0x07, 0x46, 0x0E, 0x46, 0x08, 0xD0, 0x94, 0xF8, 0xFD, 0x30, 0xFF, 0x2B, ++ 0x18, 0xBF, 0xFF, 0x25, 0x36, 0xD0, 0x28, 0x46, 0xBD, 0xE8, 0xF0, 0x87, ++ 0x00, 0x25, 0xA8, 0x46, 0x4F, 0xF0, 0x30, 0x0A, 0xA1, 0x46, 0x8C, 0x22, ++ 0x00, 0x21, 0x48, 0x46, 0xE0, 0xF7, 0x04, 0xF8, 0x8C, 0x23, 0x03, 0xFB, ++ 0x08, 0x43, 0x01, 0x2E, 0x83, 0xF8, 0x71, 0x70, 0x83, 0xF8, 0x70, 0x60, ++ 0x03, 0xD1, 0x15, 0x4A, 0x13, 0x78, 0x01, 0x33, 0x13, 0x70, 0x8C, 0x23, ++ 0x03, 0xFB, 0x08, 0x43, 0x12, 0x4A, 0xC3, 0xF8, 0x08, 0x90, 0x54, 0x44, ++ 0x00, 0x21, 0x01, 0x26, 0x9C, 0x63, 0x99, 0x74, 0x0F, 0x4C, 0xD2, 0xF8, ++ 0x10, 0x12, 0x5D, 0x74, 0x83, 0xF8, 0x41, 0x50, 0xC3, 0xF8, 0x68, 0x90, ++ 0x83, 0xF8, 0x42, 0x60, 0x5C, 0x66, 0x59, 0x60, 0x59, 0x63, 0x48, 0x46, ++ 0xD2, 0xF8, 0x18, 0x32, 0x98, 0x47, 0xC8, 0xE7, 0x01, 0x25, 0xA8, 0x46, ++ 0x4F, 0xF0, 0xBC, 0x0A, 0x04, 0xF1, 0x8C, 0x09, 0xC9, 0xE7, 0x00, 0xBF, ++ 0x48, 0x9E, 0x17, 0x00, 0x44, 0x9E, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x41, 0xF4, 0x13, 0x00, 0x0E, 0x4A, 0x8C, 0x23, 0x03, 0xFB, 0x00, 0x23, ++ 0x10, 0xB4, 0x93, 0xF8, 0x71, 0x40, 0xFF, 0x2C, 0x0A, 0xD0, 0x93, 0xF8, ++ 0x70, 0x30, 0x01, 0x2B, 0x09, 0xD0, 0x29, 0xB1, 0x8C, 0x23, 0x03, 0xFB, ++ 0x00, 0x20, 0xFF, 0x23, 0x80, 0xF8, 0x71, 0x30, 0x5D, 0xF8, 0x04, 0x4B, ++ 0x70, 0x47, 0x04, 0x4C, 0x23, 0x78, 0x01, 0x3B, 0x23, 0x70, 0x00, 0x29, ++ 0xF6, 0xD0, 0xEF, 0xE7, 0x48, 0x9E, 0x17, 0x00, 0x44, 0x9E, 0x17, 0x00, ++ 0x90, 0xF8, 0xC0, 0x34, 0xBB, 0xB3, 0x2D, 0xE9, 0xF0, 0x47, 0x90, 0xF8, ++ 0x62, 0x40, 0x0C, 0x43, 0x2F, 0xD1, 0x90, 0xF8, 0xC1, 0x54, 0xDF, 0xF8, ++ 0x64, 0x80, 0x17, 0x4F, 0x05, 0xEB, 0x85, 0x00, 0xC0, 0xEB, 0xC0, 0x00, ++ 0x08, 0xEB, 0x80, 0x09, 0xD7, 0xF8, 0xE8, 0x31, 0x86, 0x00, 0x48, 0x46, ++ 0x98, 0x47, 0x06, 0xF1, 0x30, 0x00, 0xD7, 0xF8, 0xE8, 0x31, 0x40, 0x44, ++ 0x98, 0x47, 0x8C, 0x23, 0x03, 0xFB, 0x05, 0x85, 0x95, 0xF8, 0x72, 0x30, ++ 0x85, 0xF8, 0x73, 0x40, 0x85, 0xF8, 0x78, 0x40, 0x85, 0xF8, 0x84, 0x40, ++ 0x3B, 0xB1, 0x06, 0xF1, 0x60, 0x00, 0xD7, 0xF8, 0xD8, 0x31, 0x40, 0x44, ++ 0x98, 0x47, 0x85, 0xF8, 0x72, 0x40, 0xD7, 0xF8, 0x18, 0x32, 0x48, 0x46, ++ 0xBD, 0xE8, 0xF0, 0x47, 0x18, 0x47, 0xBD, 0xE8, 0xF0, 0x87, 0x70, 0x47, ++ 0x88, 0x1A, 0x17, 0x00, 0x48, 0x9E, 0x17, 0x00, 0x03, 0x4B, 0x8C, 0x22, ++ 0x02, 0xFB, 0x00, 0x30, 0x90, 0xF8, 0x85, 0x00, 0x70, 0x47, 0x00, 0xBF, ++ 0x48, 0x9E, 0x17, 0x00, 0x11, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0x70, 0xB5, 0x05, 0x46, 0x0C, 0x46, 0x16, 0x46, 0x0E, 0xDB, ++ 0x95, 0xF8, 0xC1, 0x34, 0x0C, 0x4A, 0x8C, 0x21, 0x01, 0xFB, 0x03, 0x23, ++ 0xD3, 0xF8, 0x80, 0x20, 0x22, 0x60, 0xD8, 0x6F, 0x30, 0x60, 0x23, 0x68, ++ 0xC0, 0x1A, 0xC0, 0x0F, 0x70, 0xBD, 0x90, 0xF8, 0xC0, 0x34, 0x00, 0x2B, ++ 0xEC, 0xD1, 0x05, 0x49, 0x05, 0x48, 0x40, 0xF2, 0x06, 0x52, 0x04, 0xF0, ++ 0x23, 0xFC, 0xE5, 0xE7, 0x38, 0x36, 0x17, 0x00, 0x48, 0x9E, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xA4, 0xA3, 0x15, 0x00, 0x70, 0xB5, 0x35, 0x4E, ++ 0x33, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x05, 0x46, 0x0C, 0x46, ++ 0x12, 0xDB, 0x90, 0xF8, 0xC1, 0x24, 0x31, 0x48, 0x8C, 0x23, 0x01, 0xEB, ++ 0x41, 0x01, 0x03, 0xFB, 0x02, 0xF3, 0x03, 0xEB, 0x01, 0x13, 0x03, 0x44, ++ 0x61, 0x00, 0x1B, 0x7C, 0x01, 0x2B, 0x28, 0xD0, 0x02, 0x2B, 0x1D, 0xD0, ++ 0x00, 0x20, 0x70, 0xBD, 0x90, 0xF8, 0xC0, 0x34, 0x0B, 0xB1, 0x01, 0x29, ++ 0x30, 0xD9, 0x27, 0x49, 0x27, 0x48, 0x40, 0xF2, 0x14, 0x52, 0x04, 0xF0, ++ 0xF3, 0xFB, 0x95, 0xF8, 0xC1, 0x24, 0x22, 0x48, 0x8C, 0x23, 0x04, 0xEB, ++ 0x44, 0x01, 0x03, 0xFB, 0x02, 0xF3, 0x03, 0xEB, 0x01, 0x13, 0x03, 0x44, ++ 0x61, 0x00, 0x1B, 0x7C, 0x01, 0x2B, 0x0A, 0xD0, 0x02, 0x2B, 0x13, 0xD1, ++ 0x8C, 0x23, 0x0C, 0x44, 0x03, 0xFB, 0x02, 0xF1, 0x01, 0xEB, 0x04, 0x11, ++ 0x01, 0x44, 0xC8, 0x68, 0x70, 0xBD, 0x8C, 0x23, 0x0C, 0x44, 0x03, 0xFB, ++ 0x02, 0xF1, 0x01, 0xEB, 0x04, 0x14, 0x01, 0x19, 0xC8, 0x68, 0x8B, 0x69, ++ 0x18, 0x44, 0x70, 0xBD, 0x33, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0xC8, 0xDA, 0x10, 0xE0, 0x90, 0xF8, 0xC1, 0x24, 0x0C, 0x48, 0x8C, 0x23, ++ 0x01, 0xEB, 0x41, 0x01, 0x03, 0xFB, 0x02, 0xF3, 0x03, 0xEB, 0x01, 0x13, ++ 0x03, 0x44, 0x61, 0x00, 0x1B, 0x7C, 0x01, 0x2B, 0xDF, 0xD0, 0x02, 0x2B, ++ 0xD4, 0xD0, 0x06, 0x49, 0x07, 0x48, 0x4F, 0xF4, 0xA4, 0x62, 0x04, 0xF0, ++ 0xC9, 0xFB, 0x00, 0x20, 0x70, 0xBD, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, ++ 0x48, 0x9E, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0xB0, 0xA3, 0x15, 0x00, ++ 0x64, 0x7D, 0x15, 0x00, 0x90, 0xF8, 0xC0, 0x34, 0x00, 0x2B, 0x43, 0xD0, ++ 0x2D, 0xE9, 0xF0, 0x41, 0x28, 0x4F, 0x90, 0xF8, 0xC1, 0x24, 0x44, 0x68, ++ 0x8C, 0x26, 0x06, 0xFB, 0x02, 0x76, 0x02, 0xEB, 0x82, 0x03, 0x96, 0xF8, ++ 0x73, 0xC0, 0x01, 0x25, 0xC3, 0xEB, 0xC3, 0x03, 0x24, 0xF0, 0x40, 0x04, ++ 0x86, 0xF8, 0x86, 0x50, 0x4F, 0xEA, 0x83, 0x0E, 0x07, 0xEB, 0x83, 0x05, ++ 0x44, 0x60, 0xBC, 0xF1, 0x00, 0x0F, 0x06, 0xD1, 0x1C, 0x4E, 0x28, 0x46, ++ 0xD6, 0xF8, 0x18, 0x32, 0xBD, 0xE8, 0xF0, 0x41, 0x18, 0x47, 0x96, 0xF8, ++ 0x70, 0x30, 0x01, 0xEB, 0x8C, 0x24, 0x3B, 0xB9, 0x17, 0x4B, 0x18, 0x69, ++ 0x01, 0xF5, 0x96, 0x73, 0xC1, 0x1A, 0x11, 0xF1, 0x32, 0x0F, 0x14, 0xD4, ++ 0x8C, 0x23, 0x03, 0xFB, 0x02, 0x72, 0x11, 0x4E, 0x0E, 0xF1, 0x60, 0x00, ++ 0x01, 0x23, 0x38, 0x44, 0x21, 0x46, 0x82, 0xF8, 0x72, 0x30, 0xD6, 0xF8, ++ 0xE0, 0x31, 0x98, 0x47, 0xD6, 0xF8, 0x18, 0x32, 0x28, 0x46, 0xBD, 0xE8, ++ 0xF0, 0x41, 0x18, 0x47, 0x70, 0x47, 0x08, 0x4D, 0x74, 0x67, 0x0E, 0xF1, ++ 0x60, 0x00, 0x02, 0x22, 0x38, 0x44, 0x19, 0x46, 0x86, 0xF8, 0x72, 0x20, ++ 0xD5, 0xF8, 0xE0, 0x31, 0xBD, 0xE8, 0xF0, 0x41, 0x18, 0x47, 0x00, 0xBF, ++ 0x48, 0x9E, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x00, 0x10, 0x50, 0x40, ++ 0x30, 0xB4, 0x0A, 0x49, 0x90, 0xF8, 0xC1, 0x34, 0x09, 0x4C, 0x8C, 0x20, ++ 0x03, 0xEB, 0x83, 0x02, 0x00, 0xFB, 0x03, 0x13, 0x00, 0x25, 0xC2, 0xEB, ++ 0xC2, 0x02, 0x83, 0xF8, 0x86, 0x50, 0x01, 0xEB, 0x82, 0x00, 0xD4, 0xF8, ++ 0x18, 0x32, 0x30, 0xBC, 0x18, 0x47, 0x00, 0xBF, 0x48, 0x9E, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x41, 0x90, 0xF8, 0xC0, 0x44, ++ 0x00, 0x2C, 0x3E, 0xD0, 0x90, 0xF8, 0x62, 0x30, 0x05, 0x46, 0x00, 0x2B, ++ 0x3C, 0xD1, 0x27, 0x4B, 0x90, 0xF8, 0xC1, 0x74, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0x88, 0x46, 0x16, 0x46, 0x36, 0xDB, 0xD8, 0xF8, ++ 0x08, 0x00, 0xB2, 0x8B, 0x00, 0xF1, 0x24, 0x03, 0x10, 0x44, 0x83, 0x42, ++ 0x02, 0xD3, 0x38, 0xE0, 0x98, 0x42, 0x36, 0xD9, 0x5D, 0x78, 0x1A, 0x78, ++ 0xA9, 0x1C, 0xDD, 0x2A, 0x1C, 0x46, 0x0B, 0x44, 0xF6, 0xD1, 0x62, 0x79, ++ 0x09, 0x2A, 0xF3, 0xD1, 0x06, 0x34, 0x04, 0x3D, 0x14, 0xFA, 0x85, 0xF5, ++ 0xAC, 0x42, 0x06, 0xD3, 0xEC, 0xE7, 0xB4, 0xF8, 0x01, 0x10, 0x03, 0x31, ++ 0x0C, 0x44, 0xA5, 0x42, 0xE6, 0xD9, 0x22, 0x78, 0x0C, 0x2A, 0xF6, 0xD1, ++ 0x00, 0x2C, 0xE1, 0xD0, 0xB2, 0x68, 0x0F, 0x4B, 0x92, 0x68, 0xD3, 0xF8, ++ 0xF0, 0x31, 0x92, 0x69, 0x38, 0x46, 0x21, 0x46, 0x98, 0x47, 0x20, 0x46, ++ 0xBD, 0xE8, 0xF0, 0x81, 0x00, 0x24, 0x20, 0x46, 0xBD, 0xE8, 0xF0, 0x81, ++ 0x01, 0x2F, 0xC6, 0xD9, 0x07, 0x49, 0x08, 0x48, 0x40, 0xF2, 0x73, 0x52, ++ 0x04, 0xF0, 0xD8, 0xFA, 0x95, 0xF8, 0xC1, 0x74, 0xBD, 0xE7, 0x00, 0x24, ++ 0xE2, 0xE7, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xD8, 0xA3, 0x15, 0x00, 0xF0, 0xB5, 0x0C, 0x7E, ++ 0x7F, 0x2C, 0x83, 0xB0, 0x23, 0xD1, 0x4A, 0x7F, 0x0A, 0xBB, 0xCA, 0x7F, ++ 0xDD, 0x2A, 0x1E, 0xD1, 0x91, 0xF8, 0x24, 0x20, 0x09, 0x2A, 0x1A, 0xD1, ++ 0x91, 0xF8, 0x25, 0x20, 0x0C, 0x2A, 0x01, 0xF1, 0x25, 0x04, 0x14, 0xD1, ++ 0x11, 0x4A, 0x12, 0x49, 0x12, 0x68, 0xD1, 0xF8, 0xF0, 0x61, 0xB2, 0xF9, ++ 0x00, 0x20, 0x90, 0xF8, 0xC1, 0x74, 0x00, 0x2A, 0x05, 0x46, 0x0A, 0xDB, ++ 0xEA, 0x6F, 0x21, 0x46, 0x1A, 0x44, 0x38, 0x46, 0x33, 0x46, 0x03, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x40, 0x18, 0x47, 0x03, 0xB0, 0xF0, 0xBD, 0x90, 0xF8, ++ 0x62, 0x20, 0x00, 0x2A, 0xF0, 0xD0, 0x06, 0x49, 0x06, 0x48, 0x01, 0x93, ++ 0x49, 0x22, 0x04, 0xF0, 0x95, 0xFA, 0x01, 0x9B, 0xE8, 0xE7, 0x00, 0xBF, ++ 0x38, 0x36, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x40, 0x9C, 0x15, 0x00, 0x12, 0x4B, 0x18, 0x78, 0xF8, 0xB1, 0x12, 0x4B, ++ 0x58, 0x7C, 0xD8, 0xB9, 0x9A, 0x7C, 0x01, 0x2A, 0x19, 0xD8, 0x9B, 0x68, ++ 0x13, 0xB9, 0x16, 0xE0, 0x1B, 0x68, 0xAB, 0xB1, 0x93, 0xF8, 0x62, 0x20, ++ 0x02, 0x2A, 0xF9, 0xD1, 0x93, 0xF8, 0xC0, 0x24, 0x00, 0x2A, 0xF5, 0xD0, ++ 0x93, 0xF8, 0xC1, 0x34, 0x08, 0x4A, 0x8C, 0x21, 0x01, 0xFB, 0x03, 0x23, ++ 0x93, 0xF8, 0x85, 0x00, 0xB0, 0xFA, 0x80, 0xF0, 0x40, 0x09, 0x70, 0x47, ++ 0x00, 0x20, 0x70, 0x47, 0x70, 0x47, 0x00, 0xBF, 0x44, 0x9E, 0x17, 0x00, ++ 0x00, 0x88, 0x17, 0x00, 0x48, 0x9E, 0x17, 0x00, 0x18, 0x4B, 0x4F, 0xF4, ++ 0xA4, 0x62, 0x02, 0xFB, 0x00, 0x30, 0x90, 0xF8, 0xC0, 0x34, 0x1B, 0xB1, ++ 0x90, 0xF8, 0x62, 0x30, 0x02, 0x2B, 0x00, 0xD0, 0x70, 0x47, 0x70, 0xB5, ++ 0x90, 0xF8, 0xC1, 0x34, 0x11, 0x4C, 0x8C, 0x22, 0x02, 0xFB, 0x03, 0x42, ++ 0x00, 0x39, 0x03, 0xEB, 0x83, 0x03, 0x92, 0xF8, 0x84, 0x50, 0x18, 0xBF, ++ 0x01, 0x21, 0xC3, 0xEB, 0xC3, 0x03, 0x82, 0xF8, 0x87, 0x10, 0x04, 0xEB, ++ 0x83, 0x04, 0x35, 0xB9, 0x09, 0x4D, 0xD5, 0xF8, 0x18, 0x32, 0x20, 0x46, ++ 0xBD, 0xE8, 0x70, 0x40, 0x18, 0x47, 0x06, 0x4D, 0x92, 0xF8, 0x71, 0x00, ++ 0xD5, 0xF8, 0x90, 0x31, 0x03, 0x21, 0x98, 0x47, 0xF1, 0xE7, 0x00, 0xBF, ++ 0x18, 0x88, 0x17, 0x00, 0x48, 0x9E, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x70, 0xB5, 0x0E, 0x4E, 0x90, 0xF8, 0xC1, 0x44, 0x0D, 0x4D, 0x8C, 0x23, ++ 0x03, 0xFB, 0x04, 0x63, 0x01, 0x22, 0x04, 0xEB, 0x84, 0x04, 0x93, 0xF8, ++ 0x71, 0x00, 0x83, 0xF8, 0x73, 0x10, 0x83, 0xF8, 0x72, 0x20, 0xC4, 0xEB, ++ 0xC4, 0x04, 0xD5, 0xF8, 0x90, 0x31, 0x03, 0x21, 0x98, 0x47, 0xD5, 0xF8, ++ 0x18, 0x32, 0x06, 0xEB, 0x84, 0x00, 0xBD, 0xE8, 0x70, 0x40, 0x18, 0x47, ++ 0x48, 0x9E, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x47, ++ 0x1D, 0x4F, 0x90, 0xF8, 0xC1, 0x44, 0x8C, 0x26, 0x06, 0xFB, 0x04, 0x76, ++ 0x04, 0xEB, 0x84, 0x00, 0x96, 0xF8, 0x72, 0x20, 0xC0, 0xEB, 0xC0, 0x00, ++ 0x4F, 0xF0, 0x00, 0x09, 0x07, 0xEB, 0x80, 0x05, 0x86, 0xF8, 0x73, 0x90, ++ 0x9A, 0xB9, 0xDF, 0xF8, 0x54, 0x80, 0xD8, 0xF8, 0x18, 0x32, 0x28, 0x46, ++ 0x98, 0x47, 0x8C, 0x23, 0x03, 0xFB, 0x04, 0x74, 0x94, 0xF8, 0x79, 0x30, ++ 0x9B, 0xB9, 0xD8, 0xF8, 0x90, 0x31, 0x94, 0xF8, 0x71, 0x00, 0x02, 0x21, ++ 0xBD, 0xE8, 0xF0, 0x47, 0x18, 0x47, 0x83, 0x00, 0xDF, 0xF8, 0x28, 0x80, ++ 0x03, 0xF1, 0x60, 0x00, 0x38, 0x44, 0xD8, 0xF8, 0xD8, 0x31, 0x98, 0x47, ++ 0x86, 0xF8, 0x72, 0x90, 0xE1, 0xE7, 0xD8, 0xF8, 0x90, 0x31, 0x94, 0xF8, ++ 0x71, 0x00, 0x03, 0x21, 0xBD, 0xE8, 0xF0, 0x47, 0x18, 0x47, 0x00, 0xBF, ++ 0x48, 0x9E, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x90, 0xF8, 0xC0, 0x34, ++ 0x63, 0xB1, 0x90, 0xF8, 0xC1, 0x34, 0x06, 0x4A, 0x06, 0x48, 0x03, 0xEB, ++ 0x83, 0x03, 0xC3, 0xEB, 0xC3, 0x03, 0x00, 0xEB, 0x83, 0x00, 0xD2, 0xF8, ++ 0x18, 0x32, 0x18, 0x47, 0x70, 0x47, 0x00, 0xBF, 0x88, 0x1A, 0x17, 0x00, ++ 0x48, 0x9E, 0x17, 0x00, 0x2D, 0xE9, 0xF8, 0x4F, 0x42, 0x4E, 0x90, 0xF8, ++ 0xC1, 0x84, 0xDD, 0xF8, 0x30, 0xC0, 0x8C, 0x24, 0x04, 0xFB, 0x08, 0x64, ++ 0x94, 0xF8, 0x70, 0x70, 0x01, 0x2F, 0x0F, 0xD1, 0x08, 0xEB, 0x88, 0x05, ++ 0x94, 0xF8, 0x10, 0x90, 0xC5, 0xEB, 0xC5, 0x05, 0xA8, 0x00, 0x06, 0xEB, ++ 0x85, 0x05, 0xB9, 0xF1, 0x00, 0x0F, 0x08, 0xD0, 0x94, 0xF8, 0x40, 0x40, ++ 0x00, 0x2C, 0x64, 0xD0, 0x4F, 0xF0, 0xFF, 0x09, 0x48, 0x46, 0xBD, 0xE8, ++ 0xF8, 0x8F, 0x28, 0x46, 0xCA, 0x46, 0x8C, 0x24, 0x4F, 0xEA, 0x4A, 0x07, ++ 0x04, 0xFB, 0x08, 0xF4, 0x07, 0xEB, 0x0A, 0x0B, 0x06, 0xEB, 0x04, 0x0E, ++ 0x04, 0xEB, 0x0B, 0x14, 0x00, 0x29, 0x06, 0xEB, 0x04, 0x01, 0x9E, 0xF8, ++ 0x79, 0xB0, 0xCB, 0x74, 0x0B, 0x75, 0x0A, 0x9B, 0xCB, 0x61, 0x0B, 0xF1, ++ 0x01, 0x0B, 0x0B, 0x9B, 0x8B, 0x61, 0x0C, 0xBF, 0x01, 0x24, 0x00, 0x24, ++ 0xC1, 0xF8, 0x24, 0xC0, 0x81, 0xF8, 0x21, 0x20, 0x81, 0xF8, 0x20, 0x40, ++ 0x8E, 0xF8, 0x79, 0xB0, 0x04, 0xD0, 0x9E, 0xF8, 0x7A, 0x30, 0x01, 0x33, ++ 0x8E, 0xF8, 0x7A, 0x30, 0x0A, 0x9B, 0x73, 0xB1, 0x8C, 0x23, 0x07, 0xEB, ++ 0x0A, 0x02, 0x03, 0xFB, 0x08, 0xF3, 0x03, 0xEB, 0x02, 0x13, 0x33, 0x44, ++ 0x0A, 0x99, 0x4F, 0xF0, 0x00, 0x42, 0xB2, 0xFB, 0xF1, 0xF2, 0x01, 0x3A, ++ 0x9A, 0x62, 0x15, 0x4C, 0x61, 0x46, 0xD4, 0xF8, 0xE0, 0x31, 0x98, 0x47, ++ 0x8C, 0x23, 0x03, 0xFB, 0x08, 0xF8, 0x57, 0x44, 0x08, 0xEB, 0x07, 0x17, ++ 0x37, 0x44, 0x46, 0x44, 0x01, 0x23, 0x96, 0xF8, 0x71, 0x00, 0x3B, 0x74, ++ 0x03, 0x21, 0xD4, 0xF8, 0x90, 0x31, 0x98, 0x47, 0x49, 0x46, 0x28, 0x46, ++ 0xFF, 0xF7, 0xA4, 0xFA, 0xD4, 0xF8, 0x1C, 0x32, 0x28, 0x46, 0x98, 0x47, ++ 0x28, 0x46, 0xD4, 0xF8, 0x18, 0x32, 0x98, 0x47, 0x48, 0x46, 0xBD, 0xE8, ++ 0xF8, 0x8F, 0x30, 0x30, 0xB9, 0x46, 0x30, 0x44, 0xBA, 0x46, 0x9C, 0xE7, ++ 0x48, 0x9E, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x47, ++ 0x90, 0xF8, 0xC1, 0x64, 0x37, 0x4D, 0x8C, 0x23, 0x03, 0xFB, 0x06, 0xF3, ++ 0xE8, 0x18, 0x90, 0xF8, 0x70, 0x00, 0x01, 0x28, 0x5C, 0xD1, 0x01, 0x29, ++ 0x0C, 0x46, 0x57, 0xD8, 0x01, 0xEB, 0x41, 0x01, 0x03, 0xEB, 0x01, 0x13, ++ 0x2B, 0x44, 0x4F, 0xEA, 0x44, 0x08, 0x19, 0x7C, 0x00, 0x29, 0x4D, 0xD0, ++ 0x1A, 0xB1, 0x93, 0xF8, 0x20, 0x30, 0x00, 0x2B, 0x48, 0xD0, 0x06, 0xEB, ++ 0x86, 0x07, 0x04, 0xEB, 0x44, 0x00, 0xDF, 0xF8, 0xA4, 0x90, 0xC7, 0xEB, ++ 0xC7, 0x07, 0x00, 0x01, 0x00, 0xEB, 0x87, 0x00, 0xD9, 0xF8, 0xD8, 0x31, ++ 0x28, 0x44, 0x98, 0x47, 0x8C, 0x23, 0x03, 0xFB, 0x06, 0xFA, 0xA0, 0x44, ++ 0x0A, 0xEB, 0x08, 0x18, 0xA8, 0x44, 0x00, 0x23, 0x05, 0xEB, 0x87, 0x07, ++ 0x88, 0xF8, 0x10, 0x30, 0xD9, 0xF8, 0x1C, 0x22, 0x38, 0x46, 0x90, 0x47, ++ 0xD9, 0xF8, 0x18, 0x22, 0x38, 0x46, 0x90, 0x47, 0x05, 0xEB, 0x0A, 0x03, ++ 0x98, 0xF8, 0x20, 0x10, 0x93, 0xF8, 0x79, 0x20, 0x01, 0x3A, 0xD2, 0xB2, ++ 0x01, 0x29, 0x83, 0xF8, 0x79, 0x20, 0x04, 0xD1, 0x93, 0xF8, 0x7A, 0x10, ++ 0x01, 0x39, 0x83, 0xF8, 0x7A, 0x10, 0x8C, 0x23, 0x03, 0xFB, 0x06, 0x53, ++ 0x93, 0xF8, 0x73, 0x10, 0x01, 0xB9, 0x92, 0xB1, 0x8C, 0x23, 0x03, 0xFB, ++ 0x06, 0x55, 0x03, 0x21, 0xD9, 0xF8, 0x90, 0x31, 0x95, 0xF8, 0x71, 0x00, ++ 0x98, 0x47, 0x38, 0x46, 0x21, 0x46, 0xFF, 0xF7, 0x29, 0xFA, 0x00, 0x20, ++ 0xBD, 0xE8, 0xF0, 0x87, 0x01, 0x20, 0xBD, 0xE8, 0xF0, 0x87, 0xD9, 0xF8, ++ 0x90, 0x21, 0x93, 0xF8, 0x71, 0x00, 0x02, 0x21, 0x90, 0x47, 0xEE, 0xE7, ++ 0x48, 0x9E, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x47, ++ 0x1F, 0x4F, 0x90, 0xF8, 0xC1, 0x84, 0x8C, 0x25, 0x05, 0xFB, 0x08, 0x75, ++ 0x08, 0xEB, 0x88, 0x03, 0x95, 0xF8, 0x20, 0x20, 0xC3, 0xEB, 0xC3, 0x03, ++ 0x0E, 0x46, 0x9C, 0x00, 0xAA, 0xB9, 0x2B, 0x7C, 0x9B, 0xB1, 0xE9, 0x68, ++ 0xDF, 0xF8, 0x5C, 0x90, 0x31, 0x44, 0xD9, 0xF8, 0xE0, 0x31, 0x38, 0x19, ++ 0x98, 0x47, 0x95, 0xF8, 0x50, 0x30, 0x13, 0xB9, 0x95, 0xF8, 0x40, 0x30, ++ 0x6B, 0xB9, 0xD9, 0xF8, 0x1C, 0x32, 0x38, 0x19, 0xBD, 0xE8, 0xF0, 0x47, ++ 0x18, 0x47, 0x95, 0xF8, 0x50, 0x30, 0xAB, 0xB9, 0x95, 0xF8, 0x40, 0x30, ++ 0x93, 0xB1, 0xDF, 0xF8, 0x2C, 0x90, 0x8C, 0x23, 0x03, 0xFB, 0x08, 0x73, ++ 0x04, 0xF1, 0x30, 0x00, 0xD9, 0x6B, 0xD9, 0xF8, 0xE0, 0x31, 0x38, 0x44, ++ 0x31, 0x44, 0x98, 0x47, 0xD9, 0xF8, 0x1C, 0x32, 0x38, 0x19, 0xBD, 0xE8, ++ 0xF0, 0x47, 0x18, 0x47, 0xBD, 0xE8, 0xF0, 0x87, 0x48, 0x9E, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x0A, 0x4B, 0x8C, 0x22, 0x02, 0xFB, 0x00, 0x33, ++ 0x93, 0xF8, 0x71, 0x20, 0xFF, 0x2A, 0x0B, 0xD0, 0x93, 0xF8, 0x84, 0x00, ++ 0x48, 0xB1, 0x93, 0xF8, 0x88, 0x00, 0x00, 0xEB, 0x40, 0x03, 0x00, 0xEB, ++ 0x83, 0x00, 0x0B, 0x30, 0xC0, 0xB2, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, ++ 0x48, 0x9E, 0x17, 0x00, 0x30, 0xB4, 0xDD, 0x23, 0x50, 0x25, 0x6F, 0x24, ++ 0x9A, 0x21, 0x09, 0x22, 0x03, 0x70, 0x0C, 0x23, 0x85, 0x70, 0xC4, 0x70, ++ 0x01, 0x71, 0x42, 0x71, 0x83, 0x71, 0x30, 0xBC, 0x70, 0x47, 0x00, 0xBF, ++ 0x2D, 0xE9, 0xF0, 0x43, 0x2D, 0x4E, 0x8C, 0x23, 0x03, 0xFB, 0x00, 0x63, ++ 0x93, 0xF8, 0x78, 0x20, 0x4A, 0x72, 0x93, 0xF8, 0x73, 0x40, 0x01, 0x32, ++ 0x83, 0xF8, 0x78, 0x20, 0x00, 0x2C, 0x46, 0xD0, 0x64, 0xF0, 0x7F, 0x04, ++ 0x8C, 0x72, 0x00, 0xEB, 0x80, 0x03, 0xC3, 0xEB, 0xC3, 0x03, 0x4F, 0xF0, ++ 0x8C, 0x0C, 0xDF, 0xF8, 0x8C, 0x90, 0xDF, 0xF8, 0x8C, 0x80, 0x06, 0xEB, ++ 0x83, 0x03, 0x0C, 0xFB, 0x00, 0x6C, 0x01, 0xF1, 0x0B, 0x02, 0x01, 0xF1, ++ 0x25, 0x0E, 0x00, 0x24, 0x1D, 0x7C, 0xC5, 0xB1, 0x9C, 0xF8, 0x87, 0x50, ++ 0x15, 0xB1, 0x93, 0xF8, 0x21, 0x50, 0x55, 0xBB, 0x1D, 0x7D, 0x15, 0x70, ++ 0xD3, 0xE9, 0x06, 0x57, 0xC2, 0xF8, 0x01, 0x50, 0xC2, 0xF8, 0x05, 0x70, ++ 0xD9, 0xF8, 0x00, 0x50, 0xD8, 0xF8, 0x10, 0x70, 0xED, 0x1B, 0x5F, 0x6A, ++ 0x01, 0x34, 0x3D, 0x44, 0xE4, 0xB2, 0xC2, 0xF8, 0x09, 0x50, 0x0D, 0x32, ++ 0x72, 0x45, 0x03, 0xF1, 0x30, 0x03, 0xDF, 0xD1, 0x8C, 0x22, 0x04, 0xEB, ++ 0x44, 0x03, 0x04, 0xEB, 0x83, 0x03, 0x02, 0xFB, 0x00, 0x60, 0x03, 0xF1, ++ 0x09, 0x02, 0x80, 0xF8, 0x88, 0x40, 0x02, 0x33, 0x4A, 0x70, 0xA1, 0xF8, ++ 0x07, 0x30, 0xBD, 0xE8, 0xF0, 0x83, 0x8C, 0x72, 0xB9, 0xE7, 0x93, 0xF8, ++ 0x20, 0x50, 0x01, 0x2D, 0xD0, 0xD1, 0xE2, 0xE7, 0x48, 0x9E, 0x17, 0x00, ++ 0xA4, 0x80, 0x32, 0x40, 0x00, 0x10, 0x50, 0x40, 0x02, 0x29, 0x20, 0xD0, ++ 0x03, 0x29, 0x0F, 0xD0, 0x01, 0x29, 0x06, 0xD0, 0x15, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x1E, 0xDB, 0x70, 0x47, 0x13, 0x4B, ++ 0x8C, 0x22, 0x02, 0xFB, 0x00, 0x30, 0x80, 0xF8, 0x84, 0x10, 0x70, 0x47, ++ 0x0F, 0x4B, 0x8C, 0x22, 0x02, 0xFB, 0x00, 0x30, 0x90, 0xF8, 0x84, 0x30, ++ 0x00, 0x2B, 0xEF, 0xD1, 0x0C, 0x4B, 0x90, 0xF8, 0x71, 0x00, 0xD3, 0xF8, ++ 0x90, 0x31, 0x01, 0x21, 0x18, 0x47, 0x08, 0x4B, 0x8C, 0x22, 0x02, 0xFB, ++ 0x00, 0x30, 0x00, 0x23, 0x80, 0xF8, 0x84, 0x30, 0x70, 0x47, 0x06, 0x49, ++ 0x06, 0x48, 0x4F, 0xF4, 0xEA, 0x62, 0x03, 0xF0, 0xA5, 0xBF, 0x00, 0xBF, ++ 0x38, 0x36, 0x17, 0x00, 0x48, 0x9E, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x64, 0x7D, 0x15, 0x00, 0x90, 0xF8, 0xC0, 0x34, ++ 0x33, 0xB1, 0x90, 0xF8, 0x64, 0x30, 0x1B, 0xB1, 0x43, 0x68, 0x43, 0xF0, ++ 0x40, 0x03, 0x43, 0x60, 0x70, 0x47, 0x00, 0xBF, 0x2D, 0xE9, 0xF0, 0x47, ++ 0x36, 0x4F, 0x02, 0x7E, 0xDF, 0xF8, 0xE0, 0x80, 0x35, 0x49, 0xD8, 0xF8, ++ 0xB0, 0x33, 0x0E, 0x69, 0x05, 0x46, 0x4F, 0xF4, 0xA4, 0x60, 0x00, 0xFB, ++ 0x02, 0x70, 0x98, 0x47, 0xEB, 0x7E, 0x00, 0x2B, 0x3A, 0xD0, 0xD5, 0xE9, ++ 0x04, 0x43, 0x02, 0x2C, 0x8C, 0xBF, 0x01, 0x24, 0x00, 0x24, 0x02, 0x2B, ++ 0x6B, 0x7E, 0x95, 0xF8, 0x18, 0xA0, 0x88, 0xBF, 0x44, 0xF0, 0x02, 0x04, ++ 0x63, 0x40, 0x9B, 0x07, 0x44, 0xD1, 0xD1, 0x46, 0x4F, 0xF4, 0xA4, 0x60, ++ 0x00, 0xFB, 0x0A, 0x7A, 0x6C, 0x76, 0xDA, 0xF8, 0xE4, 0x00, 0x18, 0xB3, ++ 0xDF, 0xF8, 0x94, 0xC0, 0x4F, 0xF0, 0x00, 0x0E, 0x90, 0xF8, 0x23, 0x10, ++ 0x00, 0x68, 0x01, 0xEB, 0x41, 0x04, 0x64, 0x44, 0x4B, 0x00, 0x62, 0x78, ++ 0xA4, 0x78, 0x02, 0x2A, 0x0B, 0x44, 0x88, 0xBF, 0x01, 0x22, 0x0C, 0xEB, ++ 0x03, 0x01, 0x98, 0xBF, 0x00, 0x22, 0x02, 0x2C, 0x88, 0xBF, 0x42, 0xF0, ++ 0x02, 0x02, 0x0C, 0xF8, 0x03, 0x20, 0x81, 0xF8, 0x01, 0xE0, 0x81, 0xF8, ++ 0x02, 0xE0, 0x00, 0x28, 0xE2, 0xD1, 0x01, 0xE0, 0x95, 0xF8, 0x18, 0x90, ++ 0x11, 0x4B, 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, 0x09, 0x77, 0x9B, 0x6A, ++ 0x39, 0x6C, 0x00, 0x22, 0x5B, 0x1A, 0xC5, 0xE9, 0x04, 0x22, 0xB3, 0xFA, ++ 0x83, 0xF3, 0x5B, 0x09, 0x06, 0xF5, 0xC3, 0x31, 0xEB, 0x76, 0xD8, 0xF8, ++ 0xE0, 0x31, 0x28, 0x46, 0xA0, 0x31, 0xBD, 0xE8, 0xF0, 0x47, 0x18, 0x47, ++ 0x21, 0x46, 0x50, 0x46, 0xFF, 0xF7, 0xC4, 0xFC, 0x95, 0xF8, 0x18, 0x90, ++ 0xB4, 0xE7, 0x00, 0xBF, 0x18, 0x88, 0x17, 0x00, 0x00, 0x10, 0x50, 0x40, ++ 0x30, 0x9D, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x60, 0x9F, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x41, 0x10, 0x4D, 0xDF, 0xF8, 0x44, 0x80, 0xC0, 0xEB, ++ 0xC0, 0x03, 0x05, 0xEB, 0x83, 0x03, 0xC0, 0xEB, 0xC0, 0x06, 0x9B, 0x7E, ++ 0x04, 0x46, 0x05, 0xEB, 0x86, 0x06, 0xC7, 0x00, 0x1B, 0xB1, 0xD8, 0xF8, ++ 0xD8, 0x31, 0x30, 0x46, 0x98, 0x47, 0x3F, 0x1B, 0x05, 0xEB, 0x87, 0x05, ++ 0x1C, 0x22, 0x00, 0x21, 0x30, 0x46, 0xDF, 0xF7, 0x0F, 0xFA, 0xD8, 0xF8, ++ 0x34, 0x33, 0xAE, 0x60, 0x2C, 0x76, 0x6B, 0x60, 0xBD, 0xE8, 0xF0, 0x81, ++ 0x80, 0x9F, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x08, 0xB5, 0x00, 0x20, ++ 0xFF, 0xF7, 0xD4, 0xFF, 0x01, 0x20, 0xFF, 0xF7, 0xD1, 0xFF, 0x02, 0x20, ++ 0xFF, 0xF7, 0xCE, 0xFF, 0x03, 0x20, 0xFF, 0xF7, 0xCB, 0xFF, 0x05, 0x4B, ++ 0x00, 0x22, 0x03, 0xF1, 0x1E, 0x01, 0x5A, 0x70, 0x9A, 0x70, 0x03, 0xF8, ++ 0x03, 0x2B, 0x8B, 0x42, 0xF9, 0xD1, 0x08, 0xBD, 0x60, 0x9F, 0x17, 0x00, ++ 0x0B, 0x4A, 0xC0, 0xEB, 0xC0, 0x03, 0x02, 0xEB, 0x83, 0x03, 0x99, 0x7E, ++ 0x71, 0xB9, 0x30, 0xB4, 0x08, 0x49, 0x09, 0x4C, 0x09, 0x69, 0xD4, 0xF8, ++ 0xE0, 0x41, 0x01, 0x25, 0x01, 0xF5, 0xC3, 0x31, 0x9D, 0x76, 0x18, 0x46, ++ 0xA0, 0x31, 0x23, 0x46, 0x30, 0xBC, 0x18, 0x47, 0x70, 0x47, 0x00, 0xBF, ++ 0x80, 0x9F, 0x17, 0x00, 0x00, 0x10, 0x50, 0x40, 0x88, 0x1A, 0x17, 0x00, ++ 0x09, 0x29, 0x08, 0xB5, 0x09, 0xD9, 0x6A, 0xBB, 0x21, 0x4B, 0xC0, 0xEB, ++ 0xC0, 0x00, 0x03, 0xEB, 0x80, 0x00, 0x03, 0x69, 0x01, 0x33, 0x03, 0x61, ++ 0x08, 0xBD, 0x8A, 0xB1, 0x1C, 0x4B, 0x1D, 0x4A, 0xC0, 0xEB, 0xC0, 0x00, ++ 0x01, 0xEB, 0x41, 0x01, 0x03, 0xEB, 0x80, 0x00, 0x11, 0x44, 0x42, 0x69, ++ 0x8B, 0x78, 0x01, 0x32, 0x02, 0x2B, 0x42, 0x61, 0xEE, 0xD8, 0x01, 0x33, ++ 0x8B, 0x70, 0x08, 0xBD, 0x13, 0x4B, 0x14, 0x4A, 0xC0, 0xEB, 0xC0, 0x00, ++ 0x01, 0xEB, 0x41, 0x01, 0x03, 0xEB, 0x80, 0x00, 0x11, 0x44, 0x03, 0x69, ++ 0x4A, 0x78, 0x01, 0x33, 0x02, 0x2A, 0x03, 0x61, 0xDC, 0xD8, 0x01, 0x32, ++ 0x4A, 0x70, 0x08, 0xBD, 0x0A, 0x4A, 0x0C, 0x4B, 0x1C, 0x21, 0x01, 0xFB, ++ 0x00, 0x20, 0x1A, 0x68, 0x43, 0x69, 0xB2, 0xF9, 0x00, 0x20, 0x01, 0x33, ++ 0x00, 0x2A, 0x43, 0x61, 0x05, 0xDA, 0x07, 0x49, 0x07, 0x48, 0x40, 0xF2, ++ 0x69, 0x12, 0x03, 0xF0, 0x6F, 0xFE, 0x00, 0x23, 0x9B, 0x78, 0xFF, 0xDE, ++ 0x80, 0x9F, 0x17, 0x00, 0x60, 0x9F, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xF8, 0xA3, 0x15, 0x00, 0x70, 0xB5, 0x1E, 0x46, ++ 0x0D, 0x46, 0x01, 0x23, 0x31, 0x46, 0x40, 0xF6, 0x01, 0x00, 0x01, 0xF0, ++ 0x77, 0xFD, 0x04, 0x46, 0x02, 0x20, 0x02, 0xF0, 0x15, 0xF8, 0x18, 0x4A, ++ 0x18, 0x49, 0x03, 0x46, 0x04, 0x20, 0x03, 0xF0, 0x25, 0xFC, 0x02, 0x20, ++ 0x02, 0xF0, 0x0C, 0xF8, 0xA0, 0xB9, 0x15, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0x16, 0xDB, 0x13, 0x4A, 0x00, 0x23, 0x23, 0x70, ++ 0x28, 0x46, 0x15, 0x60, 0x93, 0x72, 0x16, 0x81, 0x01, 0x25, 0x00, 0xF0, ++ 0x7D, 0xF9, 0x20, 0x46, 0x01, 0xF0, 0x86, 0xFD, 0x28, 0x46, 0x70, 0xBD, ++ 0x08, 0x23, 0x20, 0x46, 0x23, 0x70, 0x00, 0x25, 0x01, 0xF0, 0x7E, 0xFD, ++ 0x28, 0x46, 0x70, 0xBD, 0x95, 0xF8, 0x6F, 0x31, 0x00, 0x2B, 0xE4, 0xD1, ++ 0x06, 0x49, 0x07, 0x48, 0x46, 0x22, 0x03, 0xF0, 0x25, 0xFE, 0xDE, 0xE7, ++ 0x84, 0xA4, 0x15, 0x00, 0x00, 0xA4, 0x15, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0xF4, 0x9F, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x08, 0xA4, 0x15, 0x00, ++ 0x17, 0x4A, 0x18, 0x4B, 0x12, 0x68, 0x70, 0xB5, 0xB2, 0xF9, 0x00, 0x20, ++ 0x1D, 0x68, 0x9C, 0x7A, 0x00, 0x2A, 0x19, 0xDB, 0x14, 0x4A, 0x15, 0x48, ++ 0xD2, 0xE9, 0x00, 0x63, 0x04, 0xEB, 0x44, 0x04, 0x05, 0xEB, 0x44, 0x04, ++ 0x43, 0xF4, 0x08, 0x53, 0xE1, 0x78, 0x53, 0x60, 0x33, 0x43, 0x03, 0x60, ++ 0xCB, 0x07, 0x03, 0xD4, 0x0E, 0x4B, 0xD3, 0xF8, 0xEC, 0x32, 0x98, 0x47, ++ 0x03, 0x21, 0x02, 0x20, 0x01, 0xF0, 0x0E, 0xFF, 0x00, 0x20, 0x70, 0xBD, ++ 0x02, 0x20, 0x01, 0xF0, 0xB1, 0xFF, 0x02, 0x28, 0xE0, 0xD0, 0x08, 0x49, ++ 0x08, 0x48, 0x9C, 0x22, 0x03, 0xF0, 0xEA, 0xFD, 0xDA, 0xE7, 0x00, 0xBF, ++ 0x38, 0x36, 0x17, 0x00, 0xF4, 0x9F, 0x17, 0x00, 0x98, 0x9C, 0x17, 0x00, ++ 0x60, 0x00, 0x32, 0x40, 0x88, 0x1A, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x1C, 0xA4, 0x15, 0x00, 0x38, 0xB5, 0x22, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0x32, 0xDB, 0x20, 0x49, 0x20, 0x48, 0x21, 0x4C, ++ 0xD1, 0xE9, 0x00, 0x32, 0x22, 0xF4, 0x08, 0x52, 0x13, 0x43, 0x03, 0x60, ++ 0xA3, 0x7A, 0x20, 0x68, 0x4A, 0x60, 0x90, 0xF8, 0x6F, 0x51, 0x01, 0x33, ++ 0xDB, 0xB2, 0x9D, 0x42, 0xA3, 0x72, 0x01, 0xD9, 0xE3, 0x7A, 0x93, 0xB1, ++ 0x0C, 0x38, 0x01, 0xF0, 0x55, 0xFD, 0xE3, 0x7A, 0x8B, 0xB1, 0x16, 0x4B, ++ 0x21, 0x89, 0xD3, 0xF8, 0xF0, 0x32, 0x00, 0x20, 0x98, 0x47, 0x00, 0x23, ++ 0xE3, 0x72, 0x00, 0x21, 0x02, 0x20, 0x01, 0xF0, 0xC5, 0xFE, 0x00, 0x20, ++ 0x38, 0xBD, 0x00, 0xF0, 0x8D, 0xF8, 0x00, 0x20, 0x38, 0xBD, 0x21, 0x89, ++ 0x02, 0x22, 0x40, 0xF6, 0x02, 0x00, 0x01, 0xF0, 0x27, 0xFD, 0xEE, 0xE7, ++ 0x02, 0x20, 0x01, 0xF0, 0x5D, 0xFF, 0x03, 0x28, 0xC7, 0xD0, 0x08, 0x49, ++ 0x08, 0x48, 0xC2, 0x22, 0x03, 0xF0, 0x96, 0xFD, 0xC1, 0xE7, 0x00, 0xBF, ++ 0x38, 0x36, 0x17, 0x00, 0x98, 0x9C, 0x17, 0x00, 0x60, 0x00, 0x32, 0x40, ++ 0xF4, 0x9F, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x4C, 0xA4, 0x15, 0x00, 0x38, 0xB5, 0x02, 0x20, 0x1D, 0x46, 0x01, 0xF0, ++ 0x41, 0xFF, 0x0A, 0x4A, 0x0A, 0x49, 0x04, 0x46, 0x03, 0x46, 0x04, 0x20, ++ 0x03, 0xF0, 0x50, 0xFB, 0x24, 0xB1, 0x08, 0x4B, 0x01, 0x22, 0xDA, 0x72, ++ 0x00, 0x20, 0x38, 0xBD, 0x06, 0x4B, 0x29, 0x46, 0xD3, 0xF8, 0xF0, 0x32, ++ 0x01, 0x20, 0x98, 0x47, 0x00, 0x20, 0x38, 0xBD, 0x9C, 0xA4, 0x15, 0x00, ++ 0x00, 0xA4, 0x15, 0x00, 0xF4, 0x9F, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x15, 0x4A, 0x03, 0x88, 0x11, 0x68, 0x40, 0xF6, 0x6C, 0x12, 0x93, 0x42, ++ 0x08, 0x69, 0x1F, 0xD0, 0x40, 0xF6, 0x85, 0x12, 0x93, 0x42, 0x1B, 0xD0, ++ 0x40, 0xF6, 0x9E, 0x12, 0x93, 0x42, 0x17, 0xD0, 0x40, 0xF6, 0xA8, 0x12, ++ 0x93, 0x42, 0x13, 0xD0, 0x41, 0xF2, 0x3C, 0x42, 0x93, 0x42, 0x0F, 0xD0, ++ 0x41, 0xF2, 0x64, 0x42, 0x93, 0x42, 0x0B, 0xD0, 0x41, 0xF2, 0x85, 0x62, ++ 0x93, 0x42, 0x07, 0xD0, 0x41, 0xF2, 0x99, 0x62, 0x93, 0x42, 0x03, 0xD0, ++ 0x41, 0xF2, 0xAD, 0x62, 0x93, 0x42, 0x02, 0xD1, 0x00, 0xF5, 0x9C, 0x40, ++ 0x20, 0x30, 0x70, 0x47, 0xC8, 0x35, 0x17, 0x00, 0x08, 0xB5, 0x0C, 0x22, ++ 0x00, 0x21, 0x08, 0x48, 0xDF, 0xF7, 0x48, 0xF8, 0x00, 0x21, 0x02, 0x20, ++ 0x01, 0xF0, 0x44, 0xFE, 0x05, 0x4B, 0x06, 0x4A, 0x1A, 0x60, 0x03, 0xF1, ++ 0x14, 0x01, 0x00, 0x22, 0x99, 0x60, 0x1A, 0x61, 0x5A, 0x60, 0x08, 0xBD, ++ 0xF4, 0x9F, 0x17, 0x00, 0xD4, 0x61, 0x18, 0x00, 0xDE, 0xFA, 0xFE, 0xCA, ++ 0x2D, 0xE9, 0xF0, 0x41, 0x2A, 0x4F, 0xBB, 0x7A, 0x3E, 0x68, 0x03, 0xEB, ++ 0x43, 0x03, 0x06, 0xEB, 0x43, 0x05, 0x82, 0xB0, 0x95, 0xF8, 0x03, 0x80, ++ 0x18, 0xF0, 0x05, 0x0F, 0x4F, 0xEA, 0x43, 0x04, 0x28, 0xD0, 0x24, 0x4B, ++ 0x1B, 0x68, 0x5B, 0x69, 0x96, 0xF8, 0x6E, 0xC1, 0x95, 0xF9, 0x04, 0x20, ++ 0x31, 0x5B, 0xA8, 0x78, 0xCD, 0xE9, 0x00, 0x8C, 0xFC, 0xF7, 0x94, 0xFC, ++ 0x7B, 0x68, 0x93, 0xB1, 0xAA, 0x78, 0x31, 0x5B, 0xDA, 0xB9, 0xA1, 0xF6, ++ 0x6C, 0x10, 0x48, 0x28, 0x0A, 0xD8, 0x40, 0xF6, 0xB4, 0x12, 0x91, 0x42, ++ 0x28, 0xD0, 0x18, 0x48, 0xA1, 0xF6, 0x67, 0x12, 0xA0, 0xFB, 0x02, 0x12, ++ 0xC2, 0xF3, 0x87, 0x02, 0x9A, 0x70, 0x02, 0x21, 0x08, 0x46, 0x02, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x41, 0x01, 0xF0, 0xFA, 0xBD, 0x28, 0x46, 0xFF, 0xF7, ++ 0x7B, 0xFF, 0x03, 0x46, 0xD4, 0xE7, 0x01, 0x2A, 0x02, 0xD0, 0x00, 0x22, ++ 0x9A, 0x70, 0xEE, 0xE7, 0xA1, 0xF5, 0x9C, 0x51, 0xA1, 0xF1, 0x0D, 0x02, ++ 0x92, 0xB2, 0xB2, 0xF5, 0x4D, 0x7F, 0xF4, 0xD8, 0x07, 0x4A, 0x08, 0x39, ++ 0xA2, 0xFB, 0x01, 0x12, 0xC2, 0xF3, 0x87, 0x02, 0x9A, 0x70, 0xDE, 0xE7, ++ 0x0E, 0x22, 0x9A, 0x70, 0xDB, 0xE7, 0x00, 0xBF, 0xF4, 0x9F, 0x17, 0x00, ++ 0xC8, 0x35, 0x17, 0x00, 0xCD, 0xCC, 0xCC, 0xCC, 0x70, 0xB5, 0x0B, 0x4E, ++ 0x0B, 0x4C, 0x33, 0x68, 0x05, 0x46, 0xB3, 0xF8, 0x6C, 0x11, 0x20, 0x46, ++ 0x02, 0xF0, 0x7A, 0xFB, 0x70, 0x60, 0xFF, 0xF7, 0x95, 0xFF, 0x54, 0xF8, ++ 0x0C, 0x2C, 0xB5, 0xF8, 0x6C, 0x11, 0x01, 0x3A, 0x0A, 0x44, 0x00, 0x21, ++ 0x44, 0xE9, 0x02, 0x21, 0x70, 0xBD, 0x00, 0xBF, 0xF4, 0x9F, 0x17, 0x00, ++ 0xE8, 0x61, 0x18, 0x00, 0x2D, 0xE9, 0xF8, 0x43, 0xDF, 0xF8, 0xD8, 0x90, ++ 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x00, 0x93, 0x06, 0x46, 0x93, 0xF8, ++ 0xC0, 0x04, 0x93, 0xF8, 0x6C, 0x50, 0x88, 0x46, 0x17, 0x46, 0x00, 0x28, ++ 0x52, 0xD1, 0x1B, 0x6C, 0x18, 0x79, 0x00, 0x38, 0x18, 0xBF, 0x01, 0x20, ++ 0x1A, 0x21, 0xEE, 0xF7, 0x75, 0xFE, 0x04, 0x46, 0x00, 0x28, 0x4E, 0xD0, ++ 0x28, 0x4A, 0xDF, 0xF8, 0xA8, 0xE0, 0x4F, 0xF4, 0x1E, 0x71, 0x01, 0xFB, ++ 0x05, 0x21, 0xD0, 0xE9, 0x12, 0x3C, 0x0A, 0x46, 0xBE, 0xF8, 0xFC, 0x51, ++ 0x52, 0xF8, 0x26, 0x0F, 0xD8, 0x66, 0x4F, 0xF4, 0xA4, 0x60, 0x00, 0xFB, ++ 0x06, 0x99, 0x40, 0x20, 0x83, 0xF8, 0x68, 0x00, 0x90, 0x88, 0xA3, 0xF8, ++ 0x70, 0x00, 0xD9, 0xF8, 0x5C, 0x00, 0xB9, 0xF8, 0x60, 0x90, 0xC3, 0xF8, ++ 0x72, 0x00, 0x01, 0x35, 0x90, 0x88, 0xA3, 0xF8, 0x76, 0x90, 0xAD, 0xB2, ++ 0xD2, 0xF8, 0x00, 0x90, 0xA3, 0xF8, 0x7C, 0x00, 0x00, 0x20, 0x83, 0xF8, ++ 0x69, 0x00, 0x83, 0xF8, 0x6A, 0x00, 0x83, 0xF8, 0x6B, 0x00, 0xC3, 0xF8, ++ 0x78, 0x90, 0xAE, 0xF8, 0xFC, 0x51, 0x2D, 0x01, 0x83, 0xF8, 0x80, 0x00, ++ 0x83, 0xF8, 0x81, 0x00, 0xA3, 0xF8, 0x7E, 0x50, 0xCC, 0xF8, 0x20, 0x00, ++ 0x26, 0x77, 0x91, 0xF8, 0x23, 0x30, 0x63, 0x77, 0xC4, 0xE9, 0x15, 0x87, ++ 0x20, 0x46, 0x05, 0x21, 0xBD, 0xE8, 0xF8, 0x43, 0xEE, 0xF7, 0x3A, 0xBE, ++ 0x01, 0x20, 0x1A, 0x21, 0xEE, 0xF7, 0x26, 0xFE, 0x04, 0x46, 0x00, 0x28, ++ 0xB0, 0xD1, 0xBD, 0xE8, 0xF8, 0x83, 0x00, 0xBF, 0x68, 0x65, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0x20, 0x62, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0x52, 0x4B, 0x83, 0xB0, 0x1D, 0x68, 0x9B, 0x7A, 0x01, 0x93, 0x95, 0xF8, ++ 0x70, 0x31, 0x95, 0xF8, 0x6E, 0x81, 0x00, 0x2B, 0x00, 0xF0, 0x8B, 0x80, ++ 0x4D, 0x4B, 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, 0x08, 0x38, 0x08, 0xF1, ++ 0x5C, 0x07, 0x05, 0xF1, 0xFD, 0x09, 0x00, 0x26, 0x98, 0xF8, 0xC0, 0x34, ++ 0x00, 0x2B, 0x7F, 0xD1, 0x01, 0x9B, 0x03, 0xEB, 0x43, 0x03, 0x05, 0xEB, ++ 0x43, 0x03, 0x9B, 0x78, 0x00, 0x2B, 0x77, 0xD1, 0x95, 0xF8, 0x71, 0x01, ++ 0x00, 0x38, 0x18, 0xBF, 0x01, 0x20, 0x19, 0xF8, 0x01, 0x3C, 0xB5, 0xF8, ++ 0x6C, 0x11, 0x1A, 0x33, 0x19, 0x44, 0xEE, 0xF7, 0xE9, 0xFD, 0x4A, 0x46, ++ 0x01, 0x46, 0x00, 0x28, 0x63, 0xD0, 0xD0, 0xE9, 0x12, 0x3C, 0x40, 0x24, ++ 0x00, 0x20, 0x83, 0xF8, 0x68, 0x40, 0x83, 0xF8, 0x69, 0x00, 0x83, 0xF8, ++ 0x6A, 0x00, 0x83, 0xF8, 0x6B, 0x00, 0x95, 0xF8, 0x60, 0x01, 0xC0, 0x07, ++ 0x58, 0xD4, 0xD5, 0xF8, 0x60, 0x01, 0xB5, 0xF8, 0x64, 0x41, 0xA3, 0xF8, ++ 0x70, 0x40, 0xD8, 0x66, 0x05, 0xF5, 0xB0, 0x7A, 0xDF, 0xF8, 0xC0, 0xE0, ++ 0x38, 0x68, 0xBE, 0xF8, 0xFC, 0x41, 0xB7, 0xF8, 0x04, 0xB0, 0xC3, 0xF8, ++ 0x72, 0x00, 0x01, 0x34, 0xDA, 0xF8, 0x00, 0x00, 0xBA, 0xF8, 0x04, 0xA0, ++ 0xA3, 0xF8, 0x76, 0xB0, 0xA4, 0xB2, 0x4F, 0xF0, 0x00, 0x0B, 0x98, 0x67, ++ 0xA3, 0xF8, 0x7C, 0xA0, 0xAE, 0xF8, 0xFC, 0x41, 0x83, 0xF8, 0x80, 0xB0, ++ 0x19, 0xF8, 0x01, 0x0C, 0x83, 0xF8, 0x81, 0x00, 0x19, 0xF8, 0x01, 0x0C, ++ 0x24, 0x01, 0xA3, 0xF8, 0x7E, 0x40, 0x40, 0xB1, 0x81, 0x33, 0x09, 0xEB, ++ 0x00, 0x04, 0x12, 0xF8, 0x01, 0x0B, 0x03, 0xF8, 0x01, 0x0F, 0xA2, 0x42, ++ 0xF9, 0xD1, 0xB5, 0xF8, 0x6C, 0x21, 0xDC, 0xF8, 0x28, 0x30, 0x16, 0x48, ++ 0xCC, 0xF8, 0x20, 0x00, 0x9B, 0x1A, 0x00, 0x22, 0xCC, 0xF8, 0x28, 0x30, ++ 0xC1, 0xE9, 0x15, 0x22, 0x95, 0xF8, 0x6E, 0x31, 0x0B, 0x77, 0xFF, 0x23, ++ 0x4B, 0x77, 0x08, 0x46, 0x05, 0x21, 0xEE, 0xF7, 0x99, 0xFD, 0x95, 0xF8, ++ 0x70, 0x31, 0x01, 0x36, 0xB3, 0x42, 0x09, 0xF1, 0x21, 0x09, 0x3F, 0xF7, ++ 0x7F, 0xAF, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x01, 0x20, 0x8A, 0xE7, ++ 0x07, 0x48, 0x04, 0x68, 0x80, 0x88, 0xDC, 0x66, 0xA3, 0xF8, 0x70, 0x00, ++ 0x05, 0xF5, 0xB0, 0x7A, 0xA6, 0xE7, 0x00, 0xBF, 0xF4, 0x9F, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0xD4, 0x61, 0x18, 0x00, 0xAC, 0xB2, 0x15, 0x00, ++ 0x20, 0x62, 0x17, 0x00, 0x38, 0xB5, 0x02, 0x22, 0x05, 0x46, 0x01, 0x23, ++ 0x40, 0xF6, 0x04, 0x00, 0x01, 0xF0, 0x92, 0xFA, 0x04, 0x46, 0x02, 0x20, ++ 0x01, 0xF0, 0x30, 0xFD, 0x05, 0x4A, 0x06, 0x49, 0x03, 0x46, 0x04, 0x20, ++ 0x03, 0xF0, 0x40, 0xF9, 0x25, 0x70, 0x20, 0x46, 0xBD, 0xE8, 0x38, 0x40, ++ 0x01, 0xF0, 0xB2, 0xBA, 0xBC, 0xA4, 0x15, 0x00, 0x00, 0xA4, 0x15, 0x00, ++ 0x03, 0x4A, 0x93, 0x7A, 0x10, 0x68, 0x03, 0xEB, 0x43, 0x03, 0x00, 0xEB, ++ 0x43, 0x00, 0x70, 0x47, 0xF4, 0x9F, 0x17, 0x00, 0xC3, 0x78, 0x13, 0xF0, ++ 0x05, 0x0F, 0x03, 0xD0, 0x02, 0x4B, 0x1B, 0x68, 0x58, 0x69, 0x70, 0x47, ++ 0xFF, 0xF7, 0xE8, 0xBD, 0xC8, 0x35, 0x17, 0x00, 0x0E, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x03, 0xDA, 0x0C, 0x4B, 0x1B, 0x68, ++ 0x1B, 0x07, 0x0D, 0xD1, 0x0B, 0x48, 0x0C, 0x49, 0x02, 0x68, 0x4B, 0x68, ++ 0x22, 0xF0, 0x80, 0x02, 0x02, 0x60, 0x23, 0xF0, 0x04, 0x03, 0x4F, 0xF0, ++ 0x80, 0x60, 0x4B, 0x60, 0x01, 0xF0, 0x3C, 0xBE, 0x06, 0x49, 0x07, 0x48, ++ 0x84, 0x22, 0x03, 0xF0, 0xFB, 0xBA, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, ++ 0x38, 0x00, 0x32, 0x40, 0x8C, 0x80, 0x32, 0x40, 0x1C, 0x9E, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x84, 0x9E, 0x15, 0x00, 0x5A, 0x4A, 0x5B, 0x49, ++ 0x13, 0x68, 0xF0, 0xB4, 0x14, 0x68, 0x5A, 0x4E, 0x5A, 0x4D, 0x24, 0xF0, ++ 0xFF, 0x04, 0x04, 0x43, 0x14, 0x60, 0x14, 0x68, 0x17, 0x68, 0xC4, 0xF3, ++ 0x09, 0x24, 0x27, 0xF4, 0x7F, 0x37, 0xDB, 0xB2, 0x00, 0xFB, 0x04, 0xF4, ++ 0x27, 0xF4, 0x40, 0x77, 0xB4, 0xFB, 0xF3, 0xF4, 0x01, 0xEA, 0x04, 0x24, ++ 0x3C, 0x43, 0x14, 0x60, 0x11, 0x68, 0x14, 0x68, 0xC1, 0xF3, 0x89, 0x41, ++ 0x2C, 0x40, 0x00, 0xFB, 0x01, 0xF1, 0xB1, 0xFB, 0xF3, 0xF1, 0x06, 0xEA, ++ 0x81, 0x41, 0x21, 0x43, 0x11, 0x60, 0x11, 0x68, 0x49, 0x4E, 0x4A, 0x4C, ++ 0x0D, 0x40, 0x45, 0xF0, 0x89, 0x65, 0x15, 0x60, 0x32, 0x68, 0x35, 0x68, ++ 0x47, 0x49, 0xC2, 0xF3, 0x0F, 0x22, 0x25, 0xF4, 0x7F, 0x05, 0x25, 0xF4, ++ 0x7F, 0x45, 0x00, 0xFB, 0x02, 0xF2, 0xB2, 0xFB, 0xF3, 0xF2, 0x04, 0xEA, ++ 0x02, 0x22, 0x2A, 0x43, 0x32, 0x60, 0x0A, 0x68, 0x0D, 0x68, 0x40, 0x4C, ++ 0xC2, 0xF3, 0x09, 0x52, 0x25, 0xF0, 0x7F, 0x55, 0x00, 0xFB, 0x02, 0xF2, ++ 0x25, 0xF4, 0x40, 0x15, 0xB2, 0xFB, 0xF3, 0xF2, 0x04, 0xEA, 0x02, 0x52, ++ 0x2A, 0x43, 0x0A, 0x60, 0x0A, 0x68, 0x0C, 0x68, 0xC2, 0xF3, 0x09, 0x02, ++ 0x24, 0xF4, 0x7F, 0x74, 0x00, 0xFB, 0x02, 0xF2, 0x24, 0xF0, 0x03, 0x04, ++ 0xB2, 0xFB, 0xF3, 0xF2, 0xC2, 0xF3, 0x09, 0x02, 0x22, 0x43, 0x1D, 0x28, ++ 0x0A, 0x60, 0x44, 0xD8, 0x4A, 0x68, 0x42, 0xF0, 0x03, 0x02, 0x4A, 0x60, ++ 0x2E, 0x49, 0x2B, 0x4C, 0x0A, 0x68, 0x2E, 0x4E, 0x0F, 0x68, 0x2E, 0x4D, ++ 0xC2, 0xF3, 0x0F, 0x22, 0x37, 0x40, 0x00, 0xFB, 0x02, 0xF2, 0xB2, 0xFB, ++ 0xF3, 0xF2, 0x04, 0xEA, 0x02, 0x22, 0x3A, 0x43, 0x0A, 0x60, 0x2A, 0x68, ++ 0x2F, 0x68, 0xC2, 0xF3, 0x0F, 0x22, 0x00, 0xFB, 0x02, 0xF2, 0x3E, 0x40, ++ 0xB2, 0xFB, 0xF3, 0xF2, 0x04, 0xEA, 0x02, 0x22, 0x32, 0x43, 0x2A, 0x60, ++ 0x0A, 0x69, 0x0D, 0x69, 0x1D, 0x4C, 0xC2, 0xF3, 0x09, 0x52, 0x25, 0xF0, ++ 0x7F, 0x55, 0x00, 0xFB, 0x02, 0xF2, 0x25, 0xF4, 0x40, 0x15, 0xB2, 0xFB, ++ 0xF3, 0xF2, 0x04, 0xEA, 0x02, 0x52, 0x2A, 0x43, 0x0A, 0x61, 0x0C, 0x69, ++ 0x0A, 0x69, 0xC4, 0xF3, 0x09, 0x04, 0x22, 0xF4, 0x7F, 0x72, 0x00, 0xFB, ++ 0x04, 0xF0, 0x22, 0xF0, 0x03, 0x02, 0xB0, 0xFB, 0xF3, 0xF0, 0xC0, 0xF3, ++ 0x09, 0x00, 0x10, 0x43, 0xF0, 0xBC, 0x08, 0x61, 0x70, 0x47, 0x11, 0x49, ++ 0x0A, 0x68, 0x3B, 0x28, 0x22, 0xF0, 0x03, 0x02, 0x94, 0xBF, 0x42, 0xF0, ++ 0x02, 0x02, 0x42, 0xF0, 0x01, 0x02, 0x0A, 0x60, 0xB2, 0xE7, 0x00, 0xBF, ++ 0xE4, 0x00, 0x32, 0x40, 0x00, 0xFF, 0x03, 0x00, 0x00, 0x00, 0xFC, 0x0F, ++ 0xFF, 0xFF, 0x03, 0xF0, 0xE8, 0x00, 0x32, 0x40, 0x00, 0xFF, 0xFF, 0x00, ++ 0xEC, 0x00, 0x32, 0x40, 0x00, 0x00, 0xF0, 0x3F, 0xF4, 0x00, 0x32, 0x40, ++ 0xFF, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x32, 0x40, 0xF0, 0x00, 0x32, 0x40, ++ 0x1D, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x2C, 0xDB, ++ 0xF0, 0xB4, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, ++ 0x18, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x18, 0x4B, 0x18, 0x49, 0x1B, 0x68, ++ 0x0E, 0x68, 0x18, 0x4C, 0x18, 0x4A, 0x19, 0x4D, 0x19, 0x4F, 0x03, 0xF5, ++ 0xC3, 0x43, 0x28, 0x33, 0x70, 0x1C, 0x08, 0x60, 0x23, 0x60, 0x17, 0x4C, ++ 0x80, 0x23, 0x13, 0x60, 0x2A, 0x68, 0x63, 0x68, 0x42, 0xF0, 0x80, 0x02, ++ 0x43, 0xF0, 0x04, 0x03, 0x2A, 0x60, 0x63, 0x60, 0x00, 0x23, 0x3B, 0x60, ++ 0x28, 0xB1, 0x09, 0x4B, 0x0E, 0x60, 0x1B, 0x68, 0x0E, 0xB9, 0x03, 0xB1, ++ 0x62, 0xB6, 0xF0, 0xBC, 0x70, 0x47, 0x0B, 0x4B, 0x1B, 0x68, 0x1A, 0x07, ++ 0xCE, 0xD1, 0x0B, 0x49, 0x0B, 0x48, 0xD9, 0x22, 0x03, 0xF0, 0xE4, 0xB9, ++ 0x38, 0x36, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, 0x20, 0x01, 0x32, 0x40, ++ 0x6C, 0x28, 0x17, 0x00, 0x44, 0x01, 0x32, 0x40, 0x88, 0x80, 0x32, 0x40, ++ 0x8C, 0x80, 0x32, 0x40, 0x38, 0x00, 0x32, 0x40, 0x1C, 0x9E, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xD4, 0xA4, 0x15, 0x00, 0x03, 0x4A, 0x01, 0x23, ++ 0x13, 0x60, 0x13, 0x68, 0x13, 0xF0, 0xFF, 0x0F, 0xFB, 0xD1, 0x70, 0x47, ++ 0x50, 0x80, 0x32, 0x40, 0x70, 0xB5, 0x76, 0x4A, 0x01, 0x23, 0x82, 0xB0, ++ 0x13, 0x60, 0x13, 0x68, 0x13, 0xF0, 0xFF, 0x0F, 0xFB, 0xD1, 0x73, 0x4B, ++ 0xD3, 0xF8, 0xF0, 0x40, 0xDE, 0xF7, 0x66, 0xFF, 0xA0, 0x47, 0x71, 0x4B, ++ 0x71, 0x49, 0x72, 0x4A, 0x19, 0x60, 0x13, 0x68, 0x71, 0x49, 0x23, 0xF4, ++ 0x00, 0x63, 0x13, 0x60, 0x0B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0xC0, 0xF2, 0x86, 0x80, 0x6D, 0x48, 0x6E, 0x4B, 0x6A, 0x49, 0x6E, 0x4C, ++ 0x6E, 0x4A, 0x04, 0x60, 0x1A, 0x60, 0x0A, 0x68, 0x6D, 0x4C, 0x6E, 0x4D, ++ 0x42, 0xF0, 0x80, 0x62, 0x42, 0xF4, 0xF8, 0x62, 0x0A, 0x60, 0x0A, 0x68, ++ 0x22, 0xF0, 0x80, 0x62, 0x0A, 0x60, 0x50, 0xF8, 0x84, 0x2C, 0x69, 0x49, ++ 0xA3, 0xF5, 0x00, 0x43, 0x1C, 0x3B, 0x42, 0xF4, 0x80, 0x32, 0x40, 0xF8, ++ 0x84, 0x2C, 0x25, 0x60, 0x1A, 0x68, 0x42, 0xF0, 0x7F, 0x42, 0x1A, 0x60, ++ 0x1A, 0x68, 0x42, 0xF4, 0x00, 0x02, 0x1A, 0x60, 0x1A, 0x68, 0x22, 0xF4, ++ 0xFE, 0x02, 0x42, 0xF4, 0x80, 0x12, 0x1A, 0x60, 0x8A, 0x78, 0x2A, 0xB9, ++ 0x1A, 0x68, 0x12, 0x0C, 0x12, 0x04, 0x42, 0xF0, 0x64, 0x02, 0x1A, 0x60, ++ 0x5A, 0x4B, 0x5B, 0x49, 0x50, 0x4C, 0x5B, 0x4E, 0x5B, 0x4D, 0x00, 0x22, ++ 0x4F, 0xF4, 0x40, 0x50, 0x08, 0x60, 0x1A, 0x60, 0x0D, 0xF1, 0x06, 0x01, ++ 0x0D, 0xF1, 0x07, 0x00, 0xE0, 0xF7, 0x1C, 0xF9, 0x9D, 0xF8, 0x07, 0x20, ++ 0x9D, 0xF8, 0x06, 0x00, 0x54, 0x49, 0x13, 0x02, 0x43, 0xEA, 0x00, 0x43, ++ 0x13, 0x43, 0x0B, 0x60, 0x23, 0x68, 0x52, 0x4A, 0x43, 0xF4, 0x80, 0x53, ++ 0x23, 0x60, 0x23, 0x68, 0x41, 0xF6, 0x25, 0x40, 0x43, 0xF4, 0x00, 0x53, ++ 0x23, 0x60, 0xC1, 0xF8, 0x70, 0x04, 0x13, 0x68, 0x23, 0xF0, 0x80, 0x03, ++ 0x13, 0x60, 0xDF, 0xF7, 0x77, 0xFD, 0x32, 0x68, 0x49, 0x49, 0x43, 0x1C, ++ 0x9B, 0x06, 0x22, 0xF0, 0xE0, 0x52, 0x03, 0xF0, 0xE0, 0x53, 0x13, 0x43, ++ 0x33, 0x60, 0x23, 0x68, 0x45, 0x4A, 0x43, 0xF0, 0x20, 0x03, 0x23, 0x60, ++ 0x0B, 0x68, 0x23, 0xF0, 0x01, 0x03, 0x0B, 0x60, 0x13, 0x68, 0x43, 0xF0, ++ 0x02, 0x03, 0x13, 0x60, 0x23, 0x68, 0x43, 0xF0, 0x00, 0x73, 0x23, 0x60, ++ 0x2B, 0x68, 0x99, 0x03, 0x13, 0xD4, 0x3D, 0x4A, 0x13, 0x68, 0x43, 0xF0, ++ 0x01, 0x03, 0x13, 0x60, 0x02, 0xB0, 0x70, 0xBD, 0x2A, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF1, 0xC8, 0x5F, 0xBF, 0xF4, 0x74, 0xAF, 0x37, 0x49, 0x38, 0x48, ++ 0x40, 0xF2, 0x21, 0x12, 0x03, 0xF0, 0x46, 0xF9, 0x6C, 0xE7, 0xDF, 0xF7, ++ 0x05, 0xFD, 0x00, 0x28, 0xE7, 0xD0, 0xDF, 0xF7, 0x35, 0xFD, 0x33, 0x4E, ++ 0x32, 0x68, 0x00, 0x02, 0x00, 0xF4, 0xE0, 0x63, 0x22, 0xF4, 0xE0, 0x62, ++ 0x13, 0x43, 0x33, 0x60, 0x33, 0x68, 0x23, 0xF0, 0xE0, 0x03, 0x43, 0xF0, ++ 0x60, 0x03, 0x33, 0x60, 0x33, 0x68, 0x43, 0xF0, 0x04, 0x03, 0x33, 0x60, ++ 0x33, 0x68, 0x43, 0xF0, 0x01, 0x03, 0x33, 0x60, 0x2B, 0x68, 0x1B, 0x04, ++ 0x0D, 0xD4, 0x1E, 0x4B, 0x1B, 0x68, 0x9A, 0x03, 0xC7, 0xD5, 0xDF, 0xF7, ++ 0xE9, 0xFC, 0x00, 0x28, 0xC3, 0xD0, 0x22, 0x4A, 0x13, 0x68, 0x43, 0xF0, ++ 0x02, 0x03, 0x13, 0x60, 0xBD, 0xE7, 0xDF, 0xF7, 0xB1, 0xFC, 0x00, 0x28, ++ 0xED, 0xD0, 0x23, 0x68, 0x43, 0xF4, 0x00, 0x23, 0x23, 0x60, 0x33, 0x68, ++ 0x23, 0xF0, 0x60, 0x63, 0x43, 0xF0, 0x80, 0x63, 0x33, 0x60, 0xE2, 0xE7, ++ 0x50, 0x80, 0x32, 0x40, 0x88, 0x1A, 0x17, 0x00, 0x74, 0x80, 0x32, 0x40, ++ 0x4C, 0xF1, 0x73, 0x8B, 0x4C, 0x00, 0x32, 0x40, 0x38, 0x36, 0x17, 0x00, ++ 0xD8, 0x00, 0x32, 0x40, 0x80, 0x80, 0x32, 0x40, 0x10, 0x19, 0x04, 0x00, ++ 0xC0, 0x07, 0xF9, 0x80, 0x60, 0x00, 0x32, 0x40, 0xDE, 0xFF, 0xFF, 0x7F, ++ 0x3C, 0x36, 0x17, 0x00, 0x24, 0x02, 0x32, 0x40, 0x58, 0x01, 0x32, 0x40, ++ 0x9C, 0x00, 0x32, 0x40, 0x04, 0x00, 0x32, 0x40, 0xA0, 0x00, 0x32, 0x40, ++ 0x10, 0x03, 0x32, 0x40, 0x48, 0x80, 0x32, 0x40, 0x6C, 0x00, 0x32, 0x40, ++ 0x00, 0x04, 0x32, 0x40, 0x70, 0x79, 0x15, 0x00, 0x40, 0x88, 0x15, 0x00, ++ 0x50, 0x03, 0x32, 0x40, 0x05, 0x49, 0x06, 0x4A, 0x0B, 0x68, 0x23, 0xF0, ++ 0x00, 0x43, 0x0B, 0x60, 0x13, 0x68, 0x23, 0xF0, 0x00, 0x43, 0x13, 0x60, ++ 0x70, 0x47, 0x00, 0xBF, 0x74, 0x80, 0x32, 0x40, 0x80, 0x80, 0x32, 0x40, ++ 0x1D, 0x4A, 0x1E, 0x49, 0x13, 0x68, 0x1E, 0x48, 0x30, 0xB4, 0x23, 0xF0, ++ 0x80, 0x03, 0x00, 0x25, 0x3C, 0x24, 0x13, 0x60, 0x0D, 0x60, 0x0A, 0x46, ++ 0x04, 0x60, 0x13, 0x68, 0x1B, 0x07, 0xFC, 0xD1, 0x17, 0x4A, 0x18, 0x49, ++ 0x13, 0x68, 0x18, 0x4D, 0x18, 0x48, 0x19, 0x4C, 0x43, 0xF4, 0x80, 0x33, ++ 0x13, 0x60, 0x0B, 0x68, 0x02, 0xF5, 0x00, 0x42, 0x23, 0xF0, 0xFF, 0x03, ++ 0x0B, 0x60, 0x20, 0x32, 0x4F, 0xF0, 0xFF, 0x33, 0x2B, 0x60, 0x04, 0x60, ++ 0x13, 0x68, 0x12, 0x4C, 0x12, 0x49, 0x43, 0xF0, 0x00, 0x43, 0x13, 0x60, ++ 0x22, 0x68, 0x4B, 0x68, 0xA0, 0xF5, 0x00, 0x40, 0x24, 0x38, 0x42, 0xF0, ++ 0x00, 0x42, 0x22, 0x60, 0x02, 0x68, 0x23, 0xF0, 0x04, 0x03, 0x42, 0xF0, ++ 0x80, 0x02, 0x02, 0x60, 0x30, 0xBC, 0x4B, 0x60, 0x70, 0x47, 0x00, 0xBF, ++ 0x4C, 0x00, 0x32, 0x40, 0x38, 0x00, 0x32, 0x40, 0x54, 0x00, 0x32, 0x40, ++ 0x8C, 0x80, 0x32, 0x40, 0x7C, 0x80, 0x32, 0x40, 0x70, 0x80, 0x32, 0x40, ++ 0x44, 0xF1, 0x73, 0x0B, 0x80, 0x80, 0x32, 0x40, 0x1C, 0x9E, 0x17, 0x00, ++ 0x0B, 0x49, 0x0C, 0x4A, 0x0C, 0x4B, 0x10, 0xB4, 0x04, 0x68, 0x80, 0x88, ++ 0x0C, 0x60, 0x4F, 0xF0, 0x00, 0x51, 0x10, 0x60, 0x1A, 0x46, 0x19, 0x60, ++ 0x10, 0x68, 0x81, 0x00, 0xFC, 0xD4, 0xC3, 0x00, 0x5D, 0xBF, 0x00, 0x0C, ++ 0x10, 0x38, 0xC0, 0xB2, 0xFF, 0x20, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, ++ 0xBC, 0x00, 0x32, 0x40, 0xC0, 0x00, 0x32, 0x40, 0xC4, 0x00, 0x32, 0x40, ++ 0x38, 0xB5, 0x11, 0x4B, 0x11, 0x48, 0x19, 0x68, 0x42, 0x68, 0x11, 0x4C, ++ 0x11, 0x4D, 0x21, 0xF0, 0x01, 0x01, 0x19, 0x60, 0x19, 0x68, 0x21, 0xF0, ++ 0x02, 0x01, 0x19, 0x60, 0x23, 0x68, 0x0E, 0x49, 0x43, 0xF4, 0xE0, 0x63, ++ 0x2A, 0x43, 0x23, 0x60, 0x05, 0x60, 0x01, 0x20, 0x0A, 0x60, 0xF3, 0xF7, ++ 0x51, 0xFB, 0x23, 0x68, 0x23, 0xF4, 0xE0, 0x33, 0x43, 0xF4, 0x80, 0x33, ++ 0x23, 0x60, 0x23, 0x68, 0x43, 0xF4, 0x00, 0x53, 0x23, 0x60, 0x38, 0xBD, ++ 0x74, 0x80, 0x32, 0x40, 0x98, 0x9C, 0x17, 0x00, 0x4C, 0x00, 0x32, 0x40, ++ 0xDE, 0xFF, 0xFF, 0x7F, 0x60, 0x00, 0x32, 0x40, 0x80, 0xEA, 0xE0, 0x72, ++ 0xF0, 0xB4, 0xA2, 0xEB, 0xE0, 0x72, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, ++ 0x03, 0xD4, 0x72, 0xB6, 0x16, 0x4B, 0x01, 0x21, 0x19, 0x60, 0x16, 0x4D, ++ 0x16, 0x4B, 0x2E, 0x68, 0x1B, 0x68, 0x16, 0x49, 0x77, 0x1C, 0x00, 0x28, ++ 0x09, 0x68, 0x2F, 0x60, 0x43, 0xF0, 0x80, 0x73, 0x15, 0xDD, 0x8A, 0x42, ++ 0x18, 0xD8, 0x11, 0x49, 0x0F, 0x4C, 0x0A, 0x68, 0x10, 0x1A, 0x08, 0x60, ++ 0x23, 0x60, 0x08, 0x60, 0x23, 0x60, 0x08, 0x60, 0x00, 0x20, 0x23, 0x60, ++ 0x2F, 0xB1, 0x08, 0x4B, 0x2E, 0x60, 0x1B, 0x68, 0x0E, 0xB9, 0x03, 0xB1, ++ 0x62, 0xB6, 0xF0, 0xBC, 0x70, 0x47, 0xEA, 0xD0, 0xC9, 0x43, 0x20, 0x32, ++ 0x91, 0x42, 0xE6, 0xD2, 0x4F, 0xF0, 0xFF, 0x30, 0xEE, 0xE7, 0x00, 0xBF, ++ 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0x4C, 0x00, 0x32, 0x40, ++ 0xA4, 0x80, 0x32, 0x40, 0x35, 0x4B, 0x1B, 0x68, 0x70, 0xB5, 0xC3, 0xF3, ++ 0x40, 0x64, 0x9B, 0x01, 0x12, 0xD4, 0x33, 0x49, 0x33, 0x48, 0x0B, 0x69, ++ 0x33, 0x4A, 0x05, 0x68, 0x08, 0x69, 0xB2, 0xF8, 0xB0, 0x10, 0xB2, 0xF8, ++ 0xB2, 0x20, 0xA3, 0xF5, 0xFA, 0x63, 0x03, 0xEB, 0x45, 0x13, 0x1B, 0x1A, ++ 0x5B, 0x1A, 0x9B, 0x1A, 0x00, 0x2B, 0x17, 0xDB, 0x2C, 0x4B, 0x1D, 0x68, ++ 0x9D, 0xB1, 0x28, 0x48, 0x29, 0x4E, 0xEA, 0x68, 0x03, 0x69, 0xB6, 0xF8, ++ 0xB0, 0x40, 0xB6, 0xF8, 0xB2, 0x10, 0xD3, 0x1A, 0xA3, 0xF5, 0xFA, 0x63, ++ 0x1B, 0x1B, 0x5B, 0x1A, 0x00, 0x2B, 0x07, 0xDB, 0x24, 0x4B, 0x1B, 0x68, ++ 0x1C, 0x78, 0x01, 0x2C, 0x0B, 0xD0, 0x01, 0x24, 0x20, 0x46, 0x70, 0xBD, ++ 0x21, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x12, 0xDB, ++ 0x00, 0x24, 0x20, 0x46, 0x70, 0xBD, 0x1D, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0x18, 0xDB, 0x15, 0x4B, 0x52, 0x1A, 0x4F, 0xF4, ++ 0x80, 0x20, 0x04, 0x21, 0x98, 0x60, 0x1A, 0x63, 0x20, 0x46, 0x99, 0x60, ++ 0x70, 0xBD, 0x03, 0x69, 0xD2, 0x1A, 0x02, 0xF5, 0x9C, 0x52, 0x08, 0x32, ++ 0x00, 0x2A, 0xE5, 0xDA, 0x12, 0x49, 0x13, 0x48, 0x40, 0xF2, 0x3E, 0x22, ++ 0x02, 0xF0, 0x92, 0xFF, 0x00, 0x24, 0xD5, 0xE7, 0x03, 0x69, 0xD3, 0x1A, ++ 0x5B, 0x1A, 0x00, 0x2B, 0xE1, 0xDA, 0x0C, 0x49, 0x0D, 0x48, 0x40, 0xF2, ++ 0x43, 0x22, 0x02, 0xF0, 0x85, 0xFF, 0xEA, 0x68, 0xB6, 0xF8, 0xB2, 0x10, ++ 0xD7, 0xE7, 0x00, 0xBF, 0x4C, 0x00, 0x32, 0x40, 0x00, 0x10, 0x50, 0x40, ++ 0x40, 0x80, 0x32, 0x40, 0x2C, 0x19, 0x17, 0x00, 0xD0, 0x9C, 0x17, 0x00, ++ 0x74, 0x36, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0xFC, 0xA4, 0x15, 0x00, 0x80, 0x8D, 0x15, 0x00, 0x70, 0xB4, 0xEF, 0xF3, ++ 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x0B, 0x4B, 0x01, 0x22, ++ 0x1A, 0x60, 0x0B, 0x4B, 0x0B, 0x49, 0x0C, 0x4D, 0x0E, 0x68, 0x1A, 0x68, ++ 0x28, 0x68, 0x09, 0x68, 0x54, 0x1C, 0xB1, 0x42, 0x18, 0xBF, 0x28, 0x68, ++ 0x1C, 0x60, 0x2C, 0xB1, 0x03, 0x4C, 0x1A, 0x60, 0x23, 0x68, 0x0A, 0xB9, ++ 0x03, 0xB1, 0x62, 0xB6, 0x70, 0xBC, 0x70, 0x47, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0xA8, 0x80, 0x32, 0x40, 0xA4, 0x80, 0x32, 0x40, ++ 0x3B, 0x4A, 0x3C, 0x4B, 0x10, 0xB5, 0x14, 0x68, 0x1C, 0x60, 0x61, 0x05, ++ 0x1D, 0xD4, 0xE2, 0x05, 0x16, 0xD4, 0xA3, 0x05, 0x10, 0xD4, 0xE0, 0x06, ++ 0x31, 0xD4, 0x37, 0x4B, 0x1A, 0x78, 0x22, 0xB1, 0x14, 0xF0, 0x2F, 0x0F, ++ 0x1C, 0xBF, 0x01, 0x22, 0x9A, 0x71, 0x34, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0x0D, 0xDB, 0x10, 0xBD, 0x31, 0x48, 0x02, 0xF0, ++ 0xAD, 0xFC, 0xFE, 0xE7, 0xF2, 0xF7, 0x96, 0xFD, 0xA3, 0x05, 0xE6, 0xD5, ++ 0xF6, 0xE7, 0x2E, 0x48, 0x02, 0xF0, 0xA4, 0xFC, 0xFE, 0xE7, 0xE1, 0x07, ++ 0x1C, 0xD4, 0xA2, 0x07, 0x42, 0xD4, 0x63, 0x07, 0x38, 0xD4, 0x20, 0x07, ++ 0x2E, 0xD4, 0x21, 0x06, 0x24, 0xD4, 0x62, 0x06, 0x1A, 0xD4, 0xA3, 0x06, ++ 0xE3, 0xD5, 0xBD, 0xE8, 0x10, 0x40, 0x25, 0x49, 0x25, 0x48, 0x40, 0xF2, ++ 0xB5, 0x22, 0x02, 0xF0, 0xD5, 0xBE, 0x04, 0x20, 0xEC, 0xF7, 0xA4, 0xFD, ++ 0x4F, 0xF0, 0x80, 0x41, 0x04, 0x20, 0xEC, 0xF7, 0x3F, 0xFE, 0xC4, 0xE7, ++ 0xBD, 0xE8, 0x10, 0x40, 0x1C, 0x49, 0x1E, 0x48, 0x4F, 0xF4, 0x2B, 0x72, ++ 0x02, 0xF0, 0xC4, 0xBE, 0xBD, 0xE8, 0x10, 0x40, 0x18, 0x49, 0x1B, 0x48, ++ 0x40, 0xF2, 0xB3, 0x22, 0x02, 0xF0, 0xBC, 0xBE, 0xBD, 0xE8, 0x10, 0x40, ++ 0x14, 0x49, 0x18, 0x48, 0x40, 0xF2, 0xB1, 0x22, 0x02, 0xF0, 0xB4, 0xBE, ++ 0xBD, 0xE8, 0x10, 0x40, 0x10, 0x49, 0x15, 0x48, 0x40, 0xF2, 0xAF, 0x22, ++ 0x02, 0xF0, 0xAC, 0xBE, 0xBD, 0xE8, 0x10, 0x40, 0x0C, 0x49, 0x12, 0x48, ++ 0x40, 0xF2, 0xAE, 0x22, 0x02, 0xF0, 0xA4, 0xBE, 0xBD, 0xE8, 0x10, 0x40, ++ 0x08, 0x49, 0x0F, 0x48, 0x40, 0xF2, 0xAD, 0x22, 0x02, 0xF0, 0x9C, 0xBE, ++ 0x84, 0x80, 0x32, 0x40, 0x88, 0x80, 0x32, 0x40, 0x80, 0x35, 0x17, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x5C, 0xA5, 0x15, 0x00, 0x28, 0xA5, 0x15, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x80, 0xA6, 0x15, 0x00, 0x90, 0xA5, 0x15, 0x00, ++ 0x58, 0xA6, 0x15, 0x00, 0x30, 0xA6, 0x15, 0x00, 0x08, 0xA6, 0x15, 0x00, ++ 0xE0, 0xA5, 0x15, 0x00, 0xB8, 0xA5, 0x15, 0x00, 0x38, 0xB5, 0x62, 0x4A, ++ 0x62, 0x4B, 0x11, 0x68, 0x1C, 0x68, 0x62, 0x4B, 0x0C, 0x40, 0x23, 0x40, ++ 0x54, 0x60, 0x00, 0x2B, 0x54, 0xD1, 0x60, 0x4B, 0x23, 0x40, 0x00, 0x2B, ++ 0x4B, 0xD1, 0x62, 0x07, 0x03, 0xD5, 0x5E, 0x4B, 0xD3, 0xF8, 0xDC, 0x30, ++ 0x98, 0x47, 0x23, 0x07, 0x03, 0xD5, 0x5B, 0x4B, 0xD3, 0xF8, 0xD4, 0x30, ++ 0x98, 0x47, 0xE5, 0x00, 0x2E, 0xD4, 0xE0, 0x05, 0x28, 0xD4, 0x58, 0x4B, ++ 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x00, 0xDB, 0x38, 0xBD, ++ 0x61, 0x02, 0x3C, 0xD4, 0xA2, 0x02, 0x42, 0xD4, 0x63, 0x06, 0x48, 0xD4, ++ 0xE5, 0x04, 0x4E, 0xD4, 0xA0, 0x04, 0x54, 0xD4, 0x61, 0x04, 0x5A, 0xD4, ++ 0x22, 0x04, 0x60, 0xD4, 0xE3, 0x03, 0x66, 0xD4, 0xA5, 0x03, 0x6C, 0xD4, ++ 0xE0, 0x01, 0x72, 0xD4, 0xA1, 0x01, 0x78, 0xD4, 0xE2, 0x02, 0x7E, 0xD4, ++ 0x23, 0x01, 0xE4, 0xD5, 0xBD, 0xE8, 0x38, 0x40, 0x47, 0x49, 0x48, 0x48, ++ 0x40, 0xF2, 0x19, 0x32, 0x02, 0xF0, 0x38, 0xBE, 0x46, 0x48, 0x02, 0xF0, ++ 0xED, 0xFB, 0xD2, 0xE7, 0x45, 0x4B, 0x46, 0x4A, 0x1D, 0x68, 0x93, 0x7F, ++ 0x05, 0xF0, 0x3F, 0x01, 0x0B, 0x43, 0x4F, 0xF4, 0x00, 0x20, 0x93, 0x77, ++ 0x01, 0xF0, 0x64, 0xF9, 0x41, 0x4B, 0x1D, 0x60, 0xC1, 0xE7, 0x4F, 0xF0, ++ 0x80, 0x70, 0x01, 0xF0, 0x5D, 0xF9, 0xAE, 0xE7, 0x4F, 0xF0, 0x00, 0x70, ++ 0x01, 0xF0, 0x58, 0xF9, 0xA5, 0xE7, 0xBD, 0xE8, 0x38, 0x40, 0x35, 0x49, ++ 0x3A, 0x48, 0x40, 0xF2, 0x0B, 0x32, 0x02, 0xF0, 0x13, 0xBE, 0xBD, 0xE8, ++ 0x38, 0x40, 0x31, 0x49, 0x37, 0x48, 0x4F, 0xF4, 0x43, 0x72, 0x02, 0xF0, ++ 0x0B, 0xBE, 0xBD, 0xE8, 0x38, 0x40, 0x2D, 0x49, 0x34, 0x48, 0x40, 0xF2, ++ 0x0D, 0x32, 0x02, 0xF0, 0x03, 0xBE, 0xBD, 0xE8, 0x38, 0x40, 0x29, 0x49, ++ 0x31, 0x48, 0x4F, 0xF4, 0x44, 0x72, 0x02, 0xF0, 0xFB, 0xBD, 0xBD, 0xE8, ++ 0x38, 0x40, 0x25, 0x49, 0x2E, 0x48, 0x40, 0xF2, 0x11, 0x32, 0x02, 0xF0, ++ 0xF3, 0xBD, 0xBD, 0xE8, 0x38, 0x40, 0x21, 0x49, 0x2B, 0x48, 0x40, 0xF2, ++ 0x12, 0x32, 0x02, 0xF0, 0xEB, 0xBD, 0xBD, 0xE8, 0x38, 0x40, 0x1D, 0x49, ++ 0x28, 0x48, 0x40, 0xF2, 0x13, 0x32, 0x02, 0xF0, 0xE3, 0xBD, 0xBD, 0xE8, ++ 0x38, 0x40, 0x19, 0x49, 0x25, 0x48, 0x4F, 0xF4, 0x45, 0x72, 0x02, 0xF0, ++ 0xDB, 0xBD, 0xBD, 0xE8, 0x38, 0x40, 0x15, 0x49, 0x22, 0x48, 0x40, 0xF2, ++ 0x15, 0x32, 0x02, 0xF0, 0xD3, 0xBD, 0xBD, 0xE8, 0x38, 0x40, 0x11, 0x49, ++ 0x1F, 0x48, 0x40, 0xF2, 0x16, 0x32, 0x02, 0xF0, 0xCB, 0xBD, 0xBD, 0xE8, ++ 0x38, 0x40, 0x0D, 0x49, 0x1C, 0x48, 0x40, 0xF2, 0x17, 0x32, 0x02, 0xF0, ++ 0xC3, 0xBD, 0xBD, 0xE8, 0x38, 0x40, 0x09, 0x49, 0x19, 0x48, 0x4F, 0xF4, ++ 0x46, 0x72, 0x02, 0xF0, 0xBB, 0xBD, 0x00, 0xBF, 0x6C, 0x80, 0x32, 0x40, ++ 0x74, 0x80, 0x32, 0x40, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x08, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x10, 0xA9, 0x15, 0x00, 0xA8, 0xA6, 0x15, 0x00, 0x90, 0x80, 0x32, 0x40, ++ 0x98, 0x9C, 0x17, 0x00, 0x94, 0x80, 0x32, 0x40, 0xD8, 0xA6, 0x15, 0x00, ++ 0x00, 0xA7, 0x15, 0x00, 0x34, 0xA7, 0x15, 0x00, 0x68, 0xA7, 0x15, 0x00, ++ 0x90, 0xA7, 0x15, 0x00, 0xC0, 0xA7, 0x15, 0x00, 0xF0, 0xA7, 0x15, 0x00, ++ 0x20, 0xA8, 0x15, 0x00, 0x50, 0xA8, 0x15, 0x00, 0x80, 0xA8, 0x15, 0x00, ++ 0xB4, 0xA8, 0x15, 0x00, 0xE8, 0xA8, 0x15, 0x00, 0x10, 0xB5, 0x18, 0x4B, ++ 0x84, 0xB0, 0xD3, 0xF8, 0x20, 0x32, 0x8D, 0xF8, 0x07, 0x00, 0x0D, 0xF1, ++ 0x0F, 0x02, 0x0D, 0xF1, 0x0E, 0x01, 0x0D, 0xF1, 0x07, 0x00, 0x98, 0x47, ++ 0x12, 0x4A, 0x13, 0x49, 0x13, 0x68, 0x9D, 0xF8, 0x0E, 0x40, 0x91, 0xF8, ++ 0xBA, 0x00, 0x23, 0xF4, 0x7F, 0x43, 0x43, 0xEA, 0x04, 0x23, 0x13, 0x60, ++ 0x18, 0xB1, 0x0E, 0x4B, 0x93, 0xF8, 0x2A, 0x30, 0x4B, 0xB1, 0x0A, 0x4A, ++ 0x9D, 0xF8, 0x0F, 0x10, 0x13, 0x68, 0x23, 0xF0, 0xFF, 0x03, 0x0B, 0x43, ++ 0x13, 0x60, 0x04, 0xB0, 0x10, 0xBD, 0x13, 0x68, 0x91, 0xF8, 0xBB, 0x10, ++ 0x23, 0xF0, 0xFF, 0x03, 0x0B, 0x43, 0x13, 0x60, 0x04, 0xB0, 0x10, 0xBD, ++ 0x88, 0x1A, 0x17, 0x00, 0xA0, 0x00, 0x32, 0x40, 0x2C, 0x19, 0x17, 0x00, ++ 0xBC, 0x34, 0x17, 0x00, 0x30, 0xB5, 0x90, 0xF9, 0x65, 0x50, 0x7F, 0x2D, ++ 0x83, 0xB0, 0x0E, 0xD0, 0x90, 0xF9, 0x66, 0x30, 0x0B, 0x48, 0x9D, 0x42, ++ 0xA8, 0xBF, 0x1D, 0x46, 0x8D, 0xF8, 0x07, 0x50, 0xD0, 0xF8, 0x20, 0x32, ++ 0x0D, 0xF1, 0x07, 0x00, 0x98, 0x47, 0x03, 0xB0, 0x30, 0xBD, 0x0C, 0x46, ++ 0x05, 0x49, 0x13, 0x46, 0x0A, 0x68, 0x12, 0x0A, 0x22, 0x70, 0x0A, 0x68, ++ 0x1A, 0x70, 0x03, 0xB0, 0x30, 0xBD, 0x00, 0xBF, 0x88, 0x1A, 0x17, 0x00, ++ 0xA0, 0x00, 0x32, 0x40, 0x91, 0xF9, 0x00, 0x30, 0x7F, 0x2B, 0x40, 0xD0, ++ 0xF0, 0xB5, 0x20, 0x4E, 0x90, 0xF9, 0x65, 0x70, 0xD6, 0xF8, 0x20, 0x32, ++ 0x85, 0xB0, 0x0C, 0x46, 0x05, 0x46, 0x11, 0x46, 0x20, 0x46, 0x0D, 0xF1, ++ 0x0F, 0x02, 0x01, 0x91, 0x98, 0x47, 0x94, 0xF9, 0x00, 0x30, 0x95, 0xF9, ++ 0x66, 0x20, 0x85, 0xF8, 0x65, 0x30, 0x93, 0x42, 0x20, 0xDC, 0x94, 0xF9, ++ 0x00, 0x30, 0xBB, 0x42, 0x1A, 0xD0, 0xD5, 0xF8, 0xE4, 0x30, 0x43, 0xB1, ++ 0x93, 0xF8, 0x56, 0x21, 0x42, 0xF0, 0x10, 0x02, 0x83, 0xF8, 0x56, 0x21, ++ 0x1B, 0x68, 0x00, 0x2B, 0xF6, 0xD1, 0x28, 0x6C, 0x60, 0xB1, 0xD6, 0xF8, ++ 0xB4, 0x30, 0x98, 0x47, 0x28, 0x46, 0xFC, 0xF7, 0x5D, 0xFC, 0x28, 0xB1, ++ 0x2A, 0x6C, 0xD6, 0xF8, 0x3C, 0x33, 0x92, 0xF9, 0x0C, 0x00, 0x98, 0x47, ++ 0x05, 0xB0, 0xF0, 0xBD, 0x22, 0x70, 0x01, 0x99, 0xD6, 0xF8, 0x20, 0x32, ++ 0x0D, 0xF1, 0x0F, 0x02, 0x20, 0x46, 0x98, 0x47, 0xD5, 0xE7, 0x70, 0x47, ++ 0x88, 0x1A, 0x17, 0x00, 0x10, 0xB5, 0x15, 0x4B, 0x82, 0xB0, 0x0C, 0x46, ++ 0xD3, 0xF8, 0x38, 0x33, 0x0D, 0xF1, 0x07, 0x02, 0x0D, 0xF1, 0x06, 0x01, ++ 0x98, 0x47, 0xE2, 0x6C, 0x10, 0x4B, 0x94, 0x6B, 0x93, 0xF8, 0xBD, 0x30, ++ 0x61, 0x69, 0xC1, 0xF3, 0xC2, 0x20, 0xC9, 0xB2, 0x6B, 0xB9, 0x01, 0xF0, ++ 0x7C, 0x01, 0x50, 0xEA, 0x01, 0x03, 0x0C, 0xBF, 0x9D, 0xF8, 0x06, 0x30, ++ 0x9D, 0xF8, 0x07, 0x30, 0x43, 0xEA, 0x03, 0x23, 0x63, 0x62, 0x02, 0xB0, ++ 0x10, 0xBD, 0x01, 0xF0, 0x7F, 0x01, 0xDF, 0xF7, 0xB1, 0xFA, 0x40, 0xEA, ++ 0x00, 0x20, 0x60, 0x62, 0x02, 0xB0, 0x10, 0xBD, 0x88, 0x1A, 0x17, 0x00, ++ 0x2C, 0x19, 0x17, 0x00, 0x00, 0x29, 0x11, 0xDD, 0x10, 0xB4, 0x01, 0x39, ++ 0x00, 0x23, 0x01, 0x24, 0x10, 0xF0, 0x01, 0x0F, 0x1C, 0xBF, 0x04, 0xFA, ++ 0x01, 0xF2, 0x13, 0x43, 0x01, 0x39, 0x4F, 0xEA, 0x50, 0x00, 0xF5, 0xD2, ++ 0x18, 0x46, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, 0x00, 0x23, 0x18, 0x46, ++ 0x70, 0x47, 0x00, 0xBF, 0x0B, 0x1F, 0x03, 0x44, 0x01, 0x44, 0x03, 0xF8, ++ 0x01, 0x2B, 0x8B, 0x42, 0x4F, 0xEA, 0x12, 0x22, 0xF9, 0xD1, 0x70, 0x47, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0x89, 0xB0, 0x8D, 0x88, 0x0C, 0x7D, 0x00, 0x95, ++ 0x0D, 0x68, 0x01, 0x95, 0x03, 0x93, 0x1C, 0xB1, 0x0B, 0x69, 0xAB, 0x42, ++ 0x00, 0xF0, 0xAC, 0x81, 0x01, 0x9B, 0xD9, 0x4F, 0x9C, 0xB2, 0x4F, 0xEA, ++ 0x13, 0x4C, 0xCC, 0x80, 0xA1, 0xF8, 0x08, 0xC0, 0x53, 0x78, 0x16, 0x78, ++ 0x46, 0xEA, 0x03, 0x26, 0x4E, 0x81, 0xD3, 0x78, 0x95, 0x78, 0x45, 0xEA, ++ 0x03, 0x25, 0x8D, 0x81, 0x92, 0xF8, 0x05, 0xE0, 0x13, 0x79, 0x43, 0xEA, ++ 0x0E, 0x23, 0xCB, 0x81, 0x4F, 0xF0, 0x00, 0x09, 0x09, 0xF0, 0x01, 0x0A, ++ 0x00, 0xEB, 0x4A, 0x02, 0x10, 0xF8, 0x1A, 0x80, 0x92, 0xF8, 0x01, 0xE0, ++ 0x02, 0x92, 0x48, 0xEA, 0x0E, 0x22, 0x5A, 0x40, 0x4F, 0xEA, 0x12, 0x2E, ++ 0xD2, 0xB2, 0x37, 0xF8, 0x1E, 0xE0, 0x37, 0xF8, 0x12, 0x80, 0x4F, 0xEA, ++ 0x1E, 0x22, 0x42, 0xEA, 0x0E, 0x22, 0x82, 0xEA, 0x08, 0x02, 0x4F, 0xEA, ++ 0x4A, 0x08, 0x14, 0x44, 0x08, 0xF1, 0x04, 0x02, 0xA4, 0xB2, 0x00, 0xEB, ++ 0x02, 0x0E, 0xCC, 0x80, 0x82, 0x5C, 0x9E, 0xF8, 0x01, 0xE0, 0x42, 0xEA, ++ 0x0E, 0x2E, 0x84, 0xEA, 0x0E, 0x0E, 0xCE, 0xF3, 0x0F, 0x22, 0x5F, 0xFA, ++ 0x8E, 0xFE, 0x37, 0xF8, 0x12, 0x20, 0x37, 0xF8, 0x1E, 0xB0, 0x4F, 0xEA, ++ 0x12, 0x2E, 0x4E, 0xEA, 0x02, 0x2E, 0x8E, 0xEA, 0x0B, 0x0B, 0xDC, 0x44, ++ 0x08, 0xF1, 0x08, 0x0E, 0x1F, 0xFA, 0x8C, 0xFC, 0x00, 0xEB, 0x0E, 0x02, ++ 0xA1, 0xF8, 0x08, 0xC0, 0x10, 0xF8, 0x0E, 0xE0, 0x52, 0x78, 0x4E, 0xEA, ++ 0x02, 0x22, 0x8C, 0xEA, 0x02, 0x02, 0xC2, 0xF3, 0x0F, 0x2E, 0xD2, 0xB2, ++ 0x37, 0xF8, 0x1E, 0xE0, 0x37, 0xF8, 0x12, 0xB0, 0x4F, 0xEA, 0x1E, 0x22, ++ 0x42, 0xEA, 0x0E, 0x22, 0x82, 0xEA, 0x0B, 0x0B, 0x08, 0xF1, 0x0C, 0x08, ++ 0x5E, 0x44, 0x00, 0xEB, 0x08, 0x02, 0xB6, 0xB2, 0x4E, 0x81, 0x92, 0xF8, ++ 0x01, 0xE0, 0x10, 0xF8, 0x08, 0x20, 0x42, 0xEA, 0x0E, 0x22, 0x72, 0x40, ++ 0xC2, 0xF3, 0x0F, 0x2E, 0xD2, 0xB2, 0x37, 0xF8, 0x1E, 0xE0, 0x37, 0xF8, ++ 0x12, 0x80, 0x4F, 0xEA, 0x1E, 0x22, 0x42, 0xEA, 0x0E, 0x22, 0x82, 0xEA, ++ 0x08, 0x02, 0x15, 0x44, 0xAD, 0xB2, 0x02, 0x9A, 0x8D, 0x81, 0x92, 0xF8, ++ 0x01, 0xE0, 0x10, 0xF8, 0x1A, 0x20, 0x42, 0xEA, 0x0E, 0x22, 0x6A, 0x40, ++ 0xC2, 0xF3, 0x0F, 0x2E, 0xD2, 0xB2, 0x37, 0xF8, 0x1E, 0xE0, 0x37, 0xF8, ++ 0x12, 0x80, 0x4F, 0xEA, 0x1E, 0x22, 0x42, 0xEA, 0x0E, 0x22, 0x82, 0xEA, ++ 0x08, 0x02, 0x19, 0xFA, 0x82, 0xF2, 0x13, 0x44, 0x09, 0xF1, 0x01, 0x09, ++ 0x9B, 0xB2, 0xB9, 0xF1, 0x08, 0x0F, 0xCB, 0x81, 0x7F, 0xF4, 0x6E, 0xAF, ++ 0x01, 0x9A, 0x0A, 0x61, 0x4F, 0xF0, 0x01, 0x0E, 0x81, 0xF8, 0x14, 0xE0, ++ 0x00, 0x9A, 0x90, 0xF8, 0x01, 0x80, 0x90, 0xF8, 0x00, 0xE0, 0x90, 0xF8, ++ 0x03, 0x90, 0x1A, 0x44, 0x4E, 0xEA, 0x08, 0x2E, 0x92, 0xB2, 0x82, 0xEA, ++ 0x0E, 0x0E, 0x4F, 0xEA, 0x1E, 0x28, 0x5F, 0xFA, 0x8E, 0xFE, 0x37, 0xF8, ++ 0x18, 0xA0, 0x37, 0xF8, 0x1E, 0x80, 0x4F, 0xEA, 0x1A, 0x2E, 0x4E, 0xEA, ++ 0x0A, 0x2A, 0x8A, 0xEA, 0x08, 0x0A, 0x90, 0xF8, 0x02, 0x80, 0x90, 0xF8, ++ 0x05, 0xE0, 0x54, 0x44, 0xA4, 0xB2, 0x48, 0xEA, 0x09, 0x28, 0x84, 0xEA, ++ 0x08, 0x08, 0x4F, 0xEA, 0x18, 0x2A, 0x5F, 0xFA, 0x88, 0xF8, 0x37, 0xF8, ++ 0x1A, 0xA0, 0x37, 0xF8, 0x18, 0x90, 0x4F, 0xEA, 0x1A, 0x28, 0x48, 0xEA, ++ 0x0A, 0x2A, 0x8A, 0xEA, 0x09, 0x0A, 0x90, 0xF8, 0x04, 0x90, 0x90, 0xF8, ++ 0x07, 0x80, 0xD4, 0x44, 0x1F, 0xFA, 0x8C, 0xFC, 0x49, 0xEA, 0x0E, 0x2E, ++ 0x8C, 0xEA, 0x0E, 0x0E, 0x4F, 0xEA, 0x1E, 0x2A, 0x5F, 0xFA, 0x8E, 0xFE, ++ 0x37, 0xF8, 0x1A, 0xA0, 0x37, 0xF8, 0x1E, 0x90, 0x4F, 0xEA, 0x1A, 0x2E, ++ 0x4E, 0xEA, 0x0A, 0x2A, 0x8A, 0xEA, 0x09, 0x0A, 0x90, 0xF8, 0x06, 0x90, ++ 0x90, 0xF8, 0x09, 0xE0, 0x56, 0x44, 0xB6, 0xB2, 0x49, 0xEA, 0x08, 0x28, ++ 0x86, 0xEA, 0x08, 0x08, 0x4F, 0xEA, 0x18, 0x2A, 0x5F, 0xFA, 0x88, 0xF8, ++ 0x37, 0xF8, 0x1A, 0xA0, 0x37, 0xF8, 0x18, 0x90, 0x4F, 0xEA, 0x1A, 0x28, ++ 0x48, 0xEA, 0x0A, 0x2A, 0x8A, 0xEA, 0x09, 0x0A, 0x90, 0xF8, 0x08, 0x90, ++ 0x90, 0xF8, 0x0B, 0x80, 0x55, 0x44, 0xAD, 0xB2, 0x49, 0xEA, 0x0E, 0x2E, ++ 0x85, 0xEA, 0x0E, 0x0E, 0x4F, 0xEA, 0x1E, 0x2A, 0x5F, 0xFA, 0x8E, 0xFE, ++ 0x37, 0xF8, 0x1A, 0xA0, 0x37, 0xF8, 0x1E, 0x90, 0x4F, 0xEA, 0x1A, 0x2E, ++ 0x4E, 0xEA, 0x0A, 0x2A, 0x8A, 0xEA, 0x09, 0x0A, 0x90, 0xF8, 0x0A, 0xE0, ++ 0x90, 0xF8, 0x0D, 0x90, 0x53, 0x44, 0x9B, 0xB2, 0x4E, 0xEA, 0x08, 0x2E, ++ 0x83, 0xEA, 0x0E, 0x0E, 0x4F, 0xEA, 0x1E, 0x2A, 0x5F, 0xFA, 0x8E, 0xFE, ++ 0x37, 0xF8, 0x1A, 0xA0, 0x37, 0xF8, 0x1E, 0x80, 0x07, 0x7B, 0x4F, 0xEA, ++ 0x1A, 0x2E, 0x4E, 0xEA, 0x0A, 0x2E, 0x8E, 0xEA, 0x08, 0x08, 0x42, 0x44, ++ 0x92, 0xB2, 0x47, 0xEA, 0x09, 0x29, 0x82, 0xEA, 0x09, 0x07, 0xFF, 0x03, ++ 0x82, 0xEA, 0x09, 0x09, 0x90, 0xF8, 0x0F, 0xE0, 0x47, 0xEA, 0x59, 0x09, ++ 0x87, 0x7B, 0x4C, 0x44, 0xA4, 0xB2, 0x47, 0xEA, 0x0E, 0x27, 0x84, 0xEA, ++ 0x07, 0x0E, 0x4F, 0xEA, 0xCE, 0x3E, 0x67, 0x40, 0x4E, 0xEA, 0x57, 0x07, ++ 0x67, 0x44, 0xBF, 0xB2, 0x4F, 0xEA, 0xC7, 0x3C, 0x4C, 0xEA, 0x57, 0x0C, ++ 0x66, 0x44, 0xB6, 0xB2, 0x4F, 0xEA, 0xC6, 0x3C, 0x4C, 0xEA, 0x56, 0x0C, ++ 0x65, 0x44, 0xAD, 0xB2, 0x4F, 0xEA, 0xC5, 0x3C, 0x4C, 0xEA, 0x55, 0x0C, ++ 0x63, 0x44, 0x1F, 0xFA, 0x83, 0xF9, 0x00, 0x9B, 0xAD, 0xF8, 0x18, 0x60, ++ 0x4F, 0xEA, 0x13, 0x2E, 0x0E, 0xF0, 0x7F, 0x0C, 0xAD, 0xF8, 0x16, 0x70, ++ 0xAD, 0xF8, 0x1A, 0x50, 0x03, 0x9E, 0x00, 0x9D, 0xB5, 0x70, 0x4C, 0xF0, ++ 0x20, 0x0C, 0x86, 0xF8, 0x00, 0xE0, 0x86, 0xF8, 0x01, 0xC0, 0x4F, 0xEA, ++ 0xC9, 0x38, 0x45, 0x78, 0x03, 0x78, 0xAD, 0xF8, 0x1C, 0x90, 0x48, 0xEA, ++ 0x59, 0x08, 0x42, 0x44, 0x92, 0xB2, 0x43, 0xEA, 0x05, 0x23, 0xAD, 0xF8, ++ 0x1E, 0x20, 0x5A, 0x40, 0x52, 0x08, 0xF2, 0x70, 0x33, 0x46, 0x06, 0xF1, ++ 0x0C, 0x00, 0x05, 0xAA, 0x01, 0xE0, 0x32, 0xF8, 0x02, 0x4F, 0x1C, 0x71, ++ 0x25, 0x0A, 0x5D, 0x71, 0x02, 0x33, 0x98, 0x42, 0xF7, 0xD1, 0x00, 0x23, ++ 0x0B, 0x75, 0x09, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xCC, 0x88, 0xB1, 0xF8, ++ 0x08, 0xC0, 0x4E, 0x89, 0x8D, 0x89, 0xCB, 0x89, 0x00, 0x4F, 0xFD, 0xE6, ++ 0x50, 0xA9, 0x15, 0x00, 0xF0, 0xB4, 0x13, 0x4F, 0x01, 0x22, 0x3C, 0x1F, ++ 0x00, 0x23, 0xC7, 0xF8, 0x00, 0x24, 0xC7, 0xF8, 0x04, 0x34, 0x22, 0x46, ++ 0x42, 0xF8, 0x04, 0x3F, 0x01, 0x33, 0xB3, 0xF5, 0x80, 0x7F, 0xF9, 0xD1, ++ 0x00, 0x23, 0xDF, 0xF8, 0x30, 0xC0, 0x1D, 0x46, 0xC2, 0x5C, 0x54, 0xF8, ++ 0x04, 0x6F, 0x2A, 0x44, 0x32, 0x44, 0xD5, 0xB2, 0x01, 0x33, 0x57, 0xF8, ++ 0x25, 0x20, 0x22, 0x60, 0x8B, 0x42, 0xA8, 0xBF, 0x00, 0x23, 0xA4, 0x45, ++ 0x47, 0xF8, 0x25, 0x60, 0xEE, 0xD1, 0x00, 0x20, 0xF0, 0xBC, 0x70, 0x47, ++ 0x18, 0x2C, 0x17, 0x00, 0x14, 0x30, 0x17, 0x00, 0x71, 0xB3, 0x18, 0x4B, ++ 0xF0, 0xB5, 0xD3, 0xF8, 0x00, 0x54, 0xD3, 0xF8, 0x04, 0x24, 0x53, 0xF8, ++ 0x25, 0x60, 0x32, 0x44, 0x01, 0x39, 0xD2, 0xB2, 0x89, 0xB2, 0x01, 0x31, ++ 0x53, 0xF8, 0x22, 0x40, 0x01, 0x44, 0x6F, 0x1C, 0x43, 0xF8, 0x22, 0x60, ++ 0x43, 0xF8, 0x25, 0x40, 0xFD, 0xB2, 0x34, 0x44, 0xE4, 0xB2, 0x53, 0xF8, ++ 0x25, 0x60, 0x53, 0xF8, 0x24, 0x70, 0x10, 0xF8, 0x01, 0x4B, 0x02, 0xEB, ++ 0x06, 0x0C, 0x96, 0x46, 0x5F, 0xFA, 0x8C, 0xF2, 0x67, 0x40, 0x88, 0x42, ++ 0x53, 0xF8, 0x22, 0x40, 0x00, 0xF8, 0x01, 0x7C, 0xE5, 0xD1, 0xC3, 0xF8, ++ 0x00, 0x54, 0xC3, 0xF8, 0x04, 0xE4, 0xF0, 0xBD, 0x70, 0x47, 0x00, 0xBF, ++ 0x18, 0x2C, 0x17, 0x00, 0xFF, 0xF7, 0xCA, 0xBF, 0x83, 0x68, 0x8A, 0x68, ++ 0x03, 0x48, 0x9B, 0x1A, 0x83, 0x42, 0x94, 0xBF, 0x00, 0x20, 0x01, 0x20, ++ 0x70, 0x47, 0x00, 0xBF, 0x00, 0xA3, 0xE1, 0x11, 0x83, 0x88, 0xB3, 0xEB, ++ 0x11, 0x4F, 0x01, 0xD0, 0x00, 0x20, 0x70, 0x47, 0xC0, 0x88, 0x89, 0xB2, ++ 0x40, 0x1A, 0xB0, 0xFA, 0x80, 0xF0, 0x40, 0x09, 0x70, 0x47, 0x00, 0xBF, ++ 0x2D, 0xE9, 0xF8, 0x4F, 0xDF, 0xF8, 0x4C, 0xB1, 0xDB, 0xF8, 0x00, 0x30, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x07, 0x46, 0x89, 0x46, 0x15, 0x46, ++ 0x5E, 0xDB, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, ++ 0x3F, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0xDF, 0xF8, 0x2C, 0x81, 0xDF, 0xF8, ++ 0x2C, 0xA1, 0xD8, 0xF8, 0x00, 0x30, 0xDA, 0xF8, 0x14, 0x60, 0x01, 0x33, ++ 0xC8, 0xF8, 0x00, 0x30, 0x1E, 0xB1, 0xB3, 0x88, 0xBB, 0x42, 0x40, 0xD0, ++ 0x00, 0x26, 0x37, 0x49, 0x37, 0x48, 0x49, 0xEA, 0x07, 0x42, 0x00, 0xF0, ++ 0xF5, 0xF9, 0x04, 0x46, 0x00, 0x28, 0x47, 0xD0, 0x34, 0x4B, 0x35, 0x4A, ++ 0x1B, 0x69, 0x32, 0x48, 0x1D, 0x44, 0xA5, 0x60, 0x21, 0x46, 0x00, 0xF0, ++ 0x87, 0xFE, 0x9E, 0xB9, 0xDA, 0xF8, 0x14, 0x30, 0xA3, 0x42, 0x13, 0xD0, ++ 0xD8, 0xF8, 0x00, 0x30, 0x2B, 0xB1, 0x29, 0x4A, 0x01, 0x3B, 0x12, 0x68, ++ 0xC8, 0xF8, 0x00, 0x30, 0x8B, 0xB1, 0x29, 0x4B, 0x1A, 0x69, 0xAD, 0x1A, ++ 0x00, 0x2D, 0x14, 0xDB, 0xBD, 0xE8, 0xF8, 0x8F, 0xDA, 0xF8, 0x14, 0x40, ++ 0x00, 0x2C, 0xEB, 0xD0, 0x25, 0x4B, 0xA1, 0x68, 0xD3, 0xF8, 0xE0, 0x31, ++ 0x24, 0x48, 0x98, 0x47, 0xE4, 0xE7, 0x00, 0x2A, 0xEB, 0xD0, 0x62, 0xB6, ++ 0x1E, 0x4B, 0x1A, 0x69, 0xAD, 0x1A, 0x00, 0x2D, 0xEA, 0xDA, 0xBD, 0xE8, ++ 0xF8, 0x4F, 0x4F, 0xF0, 0x00, 0x50, 0x00, 0xF0, 0x29, 0xBD, 0xF6, 0x88, ++ 0xA6, 0xEB, 0x09, 0x06, 0xB6, 0xFA, 0x86, 0xF6, 0x76, 0x09, 0xB8, 0xE7, ++ 0xB2, 0xB1, 0x19, 0x4B, 0x9A, 0x42, 0x9C, 0xD9, 0x18, 0x49, 0x19, 0x48, ++ 0x94, 0x22, 0x02, 0xF0, 0x0F, 0xFA, 0x96, 0xE7, 0x0C, 0x20, 0x00, 0xF0, ++ 0xFB, 0xF9, 0xDB, 0xF8, 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0x04, 0x46, 0x09, 0xDB, 0xA7, 0x80, 0xA4, 0xF8, 0x06, 0x90, 0xA9, 0xE7, ++ 0x0E, 0x49, 0x10, 0x48, 0x93, 0x22, 0x02, 0xF0, 0xFB, 0xF9, 0x82, 0xE7, ++ 0x00, 0x28, 0xF3, 0xD1, 0x0A, 0x49, 0x0D, 0x48, 0xA5, 0x22, 0x02, 0xF0, ++ 0xF3, 0xF9, 0xED, 0xE7, 0x38, 0x61, 0x17, 0x00, 0x59, 0x26, 0x14, 0x00, ++ 0x94, 0xB6, 0x17, 0x00, 0x00, 0x10, 0x50, 0x40, 0x41, 0x26, 0x14, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0xA0, 0xB6, 0x17, 0x00, 0xFF, 0xA2, 0xE1, 0x11, ++ 0x70, 0x79, 0x15, 0x00, 0x5C, 0xAB, 0x15, 0x00, 0x50, 0xAB, 0x15, 0x00, ++ 0x78, 0xAB, 0x15, 0x00, 0x38, 0x36, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x80, 0xB6, 0x17, 0x00, 0xF8, 0xB5, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, ++ 0x03, 0xD4, 0x72, 0xB6, 0x25, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x25, 0x4D, ++ 0x25, 0x4E, 0x2B, 0x68, 0x74, 0x69, 0x01, 0x33, 0x2B, 0x60, 0x74, 0xB1, ++ 0xA3, 0x88, 0x83, 0x42, 0x02, 0xD1, 0xE3, 0x88, 0x8B, 0x42, 0x11, 0xD0, ++ 0x41, 0xEA, 0x00, 0x42, 0x1F, 0x49, 0x20, 0x48, 0x00, 0xF0, 0x54, 0xF9, ++ 0x04, 0x46, 0x38, 0xBB, 0x2B, 0x68, 0x33, 0xB1, 0x18, 0x4A, 0x01, 0x3B, ++ 0x12, 0x68, 0x2B, 0x60, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0xF8, 0xBD, ++ 0x06, 0xF1, 0x14, 0x00, 0x00, 0xF0, 0x98, 0xFD, 0x77, 0x69, 0x17, 0x4B, ++ 0xDF, 0xB1, 0xD3, 0xF8, 0xE0, 0x31, 0xB9, 0x68, 0x06, 0xF1, 0x20, 0x00, ++ 0x98, 0x47, 0x14, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0x0A, 0xDA, 0x12, 0x4A, 0xBB, 0x68, 0x12, 0x69, 0x9B, 0x1A, 0x00, 0x2B, ++ 0x04, 0xDA, 0x10, 0x49, 0x10, 0x48, 0xE7, 0x22, 0x02, 0xF0, 0x8E, 0xF9, ++ 0x20, 0x46, 0x00, 0xF0, 0xED, 0xF9, 0x2B, 0x68, 0xD3, 0xE7, 0xD3, 0xF8, ++ 0xD8, 0x31, 0x06, 0xF1, 0x20, 0x00, 0x98, 0x47, 0xF4, 0xE7, 0x00, 0xBF, ++ 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0x80, 0xB6, 0x17, 0x00, ++ 0x59, 0x26, 0x14, 0x00, 0x94, 0xB6, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x00, 0x10, 0x50, 0x40, 0x70, 0x79, 0x15, 0x00, ++ 0x80, 0xAB, 0x15, 0x00, 0x2D, 0xE9, 0xF8, 0x43, 0x28, 0x4D, 0x29, 0x4F, ++ 0xDF, 0xF8, 0xB0, 0x80, 0x28, 0x4E, 0xDF, 0xF8, 0xB0, 0x90, 0x21, 0xE0, ++ 0xA1, 0x68, 0x33, 0x69, 0xCB, 0x1A, 0x32, 0x2B, 0x07, 0xD4, 0xD9, 0xF8, ++ 0xE0, 0x31, 0x98, 0x47, 0xA3, 0x68, 0x32, 0x69, 0x9B, 0x1A, 0x00, 0x2B, ++ 0x30, 0xDA, 0x21, 0x48, 0x00, 0xF0, 0x44, 0xFD, 0x2B, 0x68, 0x04, 0x46, ++ 0x5A, 0x1E, 0x2B, 0xB1, 0xD8, 0xF8, 0x00, 0x30, 0x2A, 0x60, 0x0A, 0xB9, ++ 0x03, 0xB1, 0x62, 0xB6, 0xA0, 0x88, 0xE1, 0x88, 0xFF, 0x22, 0x00, 0xF0, ++ 0xCB, 0xF8, 0x20, 0x46, 0x00, 0xF0, 0xA4, 0xF9, 0x4F, 0xF0, 0x00, 0x50, ++ 0x00, 0xF0, 0x6C, 0xFC, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, ++ 0x72, 0xB6, 0x01, 0x23, 0xC8, 0xF8, 0x00, 0x30, 0x2A, 0x68, 0x7C, 0x69, ++ 0x10, 0x48, 0x53, 0x1C, 0x2B, 0x60, 0x00, 0x2C, 0xCA, 0xD1, 0x2B, 0xB1, ++ 0x0E, 0x4B, 0x2A, 0x60, 0x1B, 0x68, 0x0A, 0xB9, 0x03, 0xB1, 0x62, 0xB6, ++ 0xBD, 0xE8, 0xF8, 0x83, 0x2B, 0x68, 0x00, 0x2B, 0xFA, 0xD0, 0x09, 0x4A, ++ 0x01, 0x3B, 0x12, 0x68, 0x2B, 0x60, 0x00, 0x2B, 0xF4, 0xD1, 0x00, 0x2A, ++ 0xF2, 0xD0, 0xF0, 0xE7, 0x6C, 0x28, 0x17, 0x00, 0x80, 0xB6, 0x17, 0x00, ++ 0x00, 0x10, 0x50, 0x40, 0x94, 0xB6, 0x17, 0x00, 0xA0, 0xB6, 0x17, 0x00, ++ 0x38, 0x61, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x38, 0xB5, 0xEF, 0xF3, ++ 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x0E, 0x4B, 0x01, 0x22, ++ 0x1A, 0x60, 0x0E, 0x4D, 0x0E, 0x4C, 0x2B, 0x68, 0x4F, 0xF0, 0x00, 0x50, ++ 0x01, 0x33, 0x2B, 0x60, 0x00, 0xF0, 0x28, 0xFC, 0x01, 0xE0, 0x00, 0xF0, ++ 0x59, 0xF9, 0x20, 0x46, 0x00, 0xF0, 0xE4, 0xFC, 0x00, 0x28, 0xF8, 0xD1, ++ 0x2B, 0x68, 0x33, 0xB1, 0x03, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x2B, 0x60, ++ 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0x38, 0xBD, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x94, 0xB6, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x41, ++ 0x80, 0x46, 0x03, 0xF1, 0x0C, 0x00, 0x1D, 0x46, 0x0F, 0x46, 0x16, 0x46, ++ 0x00, 0xF0, 0xC8, 0xF8, 0x0F, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0x04, 0x46, 0x0F, 0xDB, 0x00, 0x21, 0xA4, 0xF8, 0x04, 0x80, ++ 0x04, 0xF1, 0x0C, 0x08, 0xE7, 0x80, 0x26, 0x81, 0x65, 0x81, 0x2A, 0x46, ++ 0x21, 0x60, 0x40, 0x46, 0xDD, 0xF7, 0xDC, 0xFB, 0x40, 0x46, 0xBD, 0xE8, ++ 0xF0, 0x81, 0x00, 0x28, 0xED, 0xD1, 0x04, 0x49, 0x04, 0x48, 0x52, 0x22, ++ 0x02, 0xF0, 0xBA, 0xF8, 0xE7, 0xE7, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xA8, 0xAB, 0x15, 0x00, 0x16, 0x4B, 0x1A, 0x68, ++ 0x30, 0xF8, 0x06, 0x3C, 0xB2, 0xF9, 0x00, 0x10, 0x00, 0x29, 0x10, 0xB5, ++ 0xDA, 0xB2, 0x04, 0x46, 0x0C, 0xDB, 0x0B, 0x2A, 0x13, 0xD8, 0x11, 0x48, ++ 0xA4, 0xF1, 0x0C, 0x01, 0x00, 0xF0, 0x4C, 0xFC, 0xBD, 0xE8, 0x10, 0x40, ++ 0x4F, 0xF0, 0x00, 0x60, 0x00, 0xF0, 0xA4, 0xBB, 0x0D, 0x2A, 0xF0, 0xD9, ++ 0x0B, 0x49, 0x0C, 0x48, 0xBB, 0x22, 0x02, 0xF0, 0x93, 0xF8, 0x34, 0xF8, ++ 0x06, 0x3C, 0x34, 0xF8, 0x04, 0x2C, 0x34, 0xF8, 0x08, 0x1C, 0x08, 0x48, ++ 0x01, 0xF0, 0x10, 0xFE, 0xA4, 0xF1, 0x0C, 0x00, 0xBD, 0xE8, 0x10, 0x40, ++ 0x02, 0xF0, 0xDE, 0xB8, 0x38, 0x36, 0x17, 0x00, 0x84, 0xB6, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x10, 0x7D, 0x15, 0x00, 0xB4, 0xAB, 0x15, 0x00, ++ 0x08, 0xB5, 0x00, 0x23, 0xFF, 0xF7, 0x94, 0xFF, 0xBD, 0xE8, 0x08, 0x40, ++ 0xFF, 0xF7, 0xC0, 0xBF, 0x10, 0xB4, 0x5D, 0xF8, 0x04, 0x4B, 0x20, 0xF8, ++ 0x08, 0x1C, 0x20, 0xF8, 0x06, 0x2C, 0x20, 0xF8, 0x04, 0x3C, 0xFF, 0xF7, ++ 0xB5, 0xBF, 0x00, 0xBF, 0x00, 0xF0, 0xC6, 0xB8, 0x2D, 0xE9, 0xF0, 0x41, ++ 0x04, 0x68, 0xD4, 0xB1, 0x07, 0x46, 0x0D, 0x46, 0x16, 0x46, 0x4F, 0xF0, ++ 0x00, 0x08, 0x02, 0xE0, 0xA0, 0x46, 0x93, 0xB1, 0x1C, 0x46, 0x31, 0x46, ++ 0x20, 0x46, 0xA8, 0x47, 0x23, 0x68, 0x00, 0x28, 0xF6, 0xD0, 0xB8, 0xF1, ++ 0x00, 0x0F, 0x0C, 0xD0, 0xC8, 0xF8, 0x00, 0x30, 0x23, 0x68, 0x5B, 0xB1, ++ 0x00, 0x23, 0x23, 0x60, 0x20, 0x46, 0xBD, 0xE8, 0xF0, 0x81, 0x00, 0x24, ++ 0x20, 0x46, 0xBD, 0xE8, 0xF0, 0x81, 0x3B, 0x60, 0x00, 0x2B, 0xF3, 0xD1, ++ 0xC7, 0xF8, 0x04, 0x80, 0x20, 0x46, 0xBD, 0xE8, 0xF0, 0x81, 0x00, 0xBF, ++ 0x0F, 0x48, 0x30, 0xB4, 0x20, 0xF0, 0x03, 0x00, 0xEF, 0xF3, 0x10, 0x83, ++ 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x0C, 0x4B, 0x01, 0x22, 0x1A, 0x60, ++ 0x0B, 0x4A, 0x0C, 0x4B, 0x11, 0x68, 0x23, 0xF0, 0x03, 0x03, 0x4C, 0x1C, ++ 0x1B, 0x1A, 0x00, 0x25, 0x14, 0x60, 0xC0, 0xE9, 0x00, 0x53, 0x2C, 0xB1, ++ 0x04, 0x4B, 0x11, 0x60, 0x1B, 0x68, 0x09, 0xB9, 0x03, 0xB1, 0x62, 0xB6, ++ 0x30, 0xBC, 0x70, 0x47, 0x03, 0xA0, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x80, 0xB6, 0x17, 0x00, 0xF8, 0xB5, 0x31, 0x4F, ++ 0x3B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x03, 0x30, 0x20, 0xF0, 0x03, 0x04, ++ 0x00, 0x2B, 0x04, 0xF1, 0x04, 0x06, 0x48, 0xDB, 0x2C, 0x4B, 0xDB, 0x69, ++ 0xEF, 0xF3, 0x10, 0x82, 0xD2, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x2A, 0x4A, ++ 0x01, 0x21, 0x11, 0x60, 0x29, 0x4D, 0x2A, 0x68, 0x02, 0xF1, 0x01, 0x0C, ++ 0xC5, 0xF8, 0x00, 0xC0, 0x00, 0x2B, 0x3E, 0xD0, 0x04, 0xF1, 0x0C, 0x00, ++ 0x00, 0x21, 0x05, 0xE0, 0x4C, 0x68, 0xA2, 0x42, 0x38, 0xBF, 0x19, 0x46, ++ 0x1B, 0x68, 0x43, 0xB1, 0x5A, 0x68, 0x82, 0x42, 0xFA, 0xD3, 0x00, 0x29, ++ 0xF4, 0xD1, 0x19, 0x46, 0x1B, 0x68, 0x00, 0x2B, 0xF6, 0xD1, 0x3B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x12, 0xDB, 0x0A, 0x46, 0x4B, 0x68, ++ 0x9B, 0x1B, 0x98, 0x18, 0x4B, 0x60, 0x04, 0x30, 0x9E, 0x50, 0xBC, 0xF1, ++ 0x00, 0x0F, 0x07, 0xD0, 0x13, 0x4A, 0x0C, 0xF1, 0xFF, 0x33, 0x12, 0x68, ++ 0x2B, 0x60, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0xF8, 0xBD, 0x00, 0x29, ++ 0xEA, 0xD1, 0x10, 0x49, 0x10, 0x48, 0x97, 0x22, 0x01, 0xF0, 0xC0, 0xFF, ++ 0x00, 0x22, 0xD5, 0xF8, 0x00, 0xC0, 0x11, 0x46, 0xE1, 0xE7, 0x07, 0x2E, ++ 0xB4, 0xD8, 0x0A, 0x49, 0x0B, 0x48, 0x7B, 0x22, 0x01, 0xF0, 0xB4, 0xFF, ++ 0xAE, 0xE7, 0x3A, 0x68, 0xB2, 0xF9, 0x00, 0x20, 0x00, 0x2A, 0xE8, 0xDB, ++ 0x5B, 0x68, 0xFF, 0xDE, 0x38, 0x36, 0x17, 0x00, 0x80, 0xB6, 0x17, 0x00, ++ 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x08, 0xAC, 0x15, 0x00, 0xE0, 0xAB, 0x15, 0x00, 0x2D, 0xE9, 0xF8, 0x43, ++ 0xDF, 0xF8, 0xF4, 0x90, 0x36, 0x4A, 0xD9, 0xF8, 0x00, 0x30, 0xD4, 0x69, ++ 0xB3, 0xF9, 0x00, 0x30, 0x50, 0xF8, 0x04, 0x8C, 0x00, 0x2B, 0x06, 0x46, ++ 0xA0, 0xF1, 0x04, 0x05, 0x2F, 0xDB, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, ++ 0x03, 0xD4, 0x72, 0xB6, 0x2E, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x2E, 0x48, ++ 0xD0, 0xF8, 0x00, 0xC0, 0x0C, 0xF1, 0x01, 0x07, 0x07, 0x60, 0x00, 0x2C, ++ 0x47, 0xD0, 0x63, 0x68, 0x1A, 0x19, 0xAA, 0x42, 0x23, 0xD0, 0xAC, 0x42, ++ 0x06, 0xD9, 0x37, 0xE0, 0x63, 0x68, 0x1A, 0x19, 0xAA, 0x42, 0x1C, 0xD0, ++ 0xAC, 0x42, 0x26, 0xD8, 0x21, 0x46, 0x24, 0x68, 0x00, 0x2C, 0xF5, 0xD1, ++ 0x0D, 0x60, 0x46, 0xE9, 0x01, 0x48, 0x47, 0xB1, 0x1E, 0x4B, 0xC0, 0xF8, ++ 0x00, 0xC0, 0x1B, 0x68, 0xBC, 0xF1, 0x00, 0x0F, 0x01, 0xD1, 0x03, 0xB1, ++ 0x62, 0xB6, 0xBD, 0xE8, 0xF8, 0x83, 0xA0, 0x42, 0xCD, 0xD8, 0x1A, 0x49, ++ 0x1A, 0x48, 0xC7, 0x22, 0x01, 0xF0, 0x56, 0xFF, 0xC7, 0xE7, 0x43, 0x44, ++ 0x22, 0x68, 0x63, 0x60, 0xE1, 0x18, 0x8A, 0x42, 0xE5, 0xD1, 0xD2, 0xE9, ++ 0x00, 0x21, 0x0B, 0x44, 0x22, 0x60, 0x63, 0x60, 0xDF, 0xE7, 0x05, 0xEB, ++ 0x08, 0x03, 0x9C, 0x42, 0x0D, 0x60, 0xD8, 0xD1, 0x23, 0x68, 0x46, 0xF8, ++ 0x04, 0x3C, 0x52, 0x1B, 0x32, 0x60, 0xD4, 0xE7, 0xD9, 0xF8, 0x00, 0x30, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x04, 0xDB, 0x00, 0x23, 0x1D, 0x60, ++ 0xFF, 0xDE, 0x25, 0x60, 0xFF, 0xDE, 0x06, 0x49, 0x07, 0x48, 0xE2, 0x22, ++ 0x01, 0xF0, 0x2E, 0xFF, 0xF4, 0xE7, 0x00, 0xBF, 0x80, 0xB6, 0x17, 0x00, ++ 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x18, 0xAC, 0x15, 0x00, 0x3C, 0xAC, 0x15, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0xC0, 0x88, 0x40, 0x1A, 0xB0, 0xFA, 0x80, 0xF0, 0x40, 0x09, 0x70, 0x47, ++ 0x2A, 0xB3, 0xF8, 0xB5, 0x53, 0x1E, 0x0F, 0x46, 0x0A, 0x68, 0x01, 0xE0, ++ 0x59, 0x1C, 0x11, 0xD0, 0x32, 0xF8, 0x33, 0x40, 0x84, 0x42, 0x4F, 0xEA, ++ 0xC3, 0x06, 0x02, 0xEB, 0xC3, 0x05, 0x03, 0xF1, 0xFF, 0x33, 0xF3, 0xD1, ++ 0x0B, 0x4B, 0x68, 0x68, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0x02, 0xDB, 0xF8, 0xBD, 0x00, 0x20, 0xF8, 0xBD, 0x00, 0x28, 0xFA, 0xD1, ++ 0x06, 0x49, 0x07, 0x48, 0xF4, 0x22, 0x01, 0xF0, 0xF5, 0xFE, 0x3B, 0x68, ++ 0x1E, 0x44, 0x70, 0x68, 0xF8, 0xBD, 0x00, 0x20, 0x70, 0x47, 0x00, 0xBF, ++ 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x50, 0xAC, 0x15, 0x00, ++ 0x2D, 0xE9, 0xF8, 0x43, 0x44, 0x4F, 0x3B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0x04, 0x46, 0x0D, 0x46, 0x4F, 0xEA, 0x10, 0x29, 0xC6, 0xB2, ++ 0x3B, 0xDB, 0x40, 0x4B, 0x03, 0xEB, 0x06, 0x16, 0xB3, 0x68, 0x03, 0xEB, ++ 0x49, 0x09, 0x3E, 0x48, 0x2A, 0x46, 0x21, 0x46, 0x01, 0xF0, 0x56, 0xFC, ++ 0xB9, 0xF8, 0x00, 0x30, 0xAB, 0x42, 0x01, 0xD1, 0xBD, 0xE8, 0xF8, 0x83, ++ 0xDF, 0xF8, 0x0C, 0x81, 0x38, 0x4F, 0x39, 0x4E, 0xA9, 0xF8, 0x00, 0x50, ++ 0x19, 0xE0, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x02, 0xD4, 0x72, 0xB6, ++ 0x01, 0x23, 0x33, 0x60, 0x34, 0x4D, 0x35, 0x48, 0x2B, 0x68, 0x01, 0x33, ++ 0x2B, 0x60, 0x00, 0xF0, 0x61, 0xFA, 0x2A, 0x68, 0x53, 0x1E, 0x22, 0xB1, ++ 0x32, 0x68, 0x2B, 0x60, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0x4F, 0xF0, ++ 0x00, 0x60, 0x00, 0xF0, 0xB3, 0xF9, 0x41, 0x46, 0x22, 0x46, 0x38, 0x46, ++ 0xFF, 0xF7, 0x40, 0xFE, 0x01, 0x46, 0x00, 0x28, 0xDD, 0xD1, 0xBD, 0xE8, ++ 0xF8, 0x83, 0x0C, 0x2E, 0x23, 0xD8, 0x33, 0xD0, 0x20, 0x4B, 0x03, 0xEB, ++ 0x06, 0x16, 0xF3, 0x89, 0x4B, 0x45, 0x0B, 0xD9, 0xB3, 0x68, 0x03, 0xEB, ++ 0x49, 0x09, 0xB9, 0xF1, 0x00, 0x0F, 0xBA, 0xD1, 0x20, 0x49, 0x21, 0x48, ++ 0xB9, 0x22, 0x01, 0xF0, 0x8B, 0xFE, 0xB4, 0xE7, 0xB4, 0x22, 0x1D, 0x49, ++ 0x1E, 0x48, 0x01, 0xF0, 0x85, 0xFE, 0x3A, 0x68, 0xB3, 0x68, 0xB2, 0xF9, ++ 0x00, 0x20, 0x00, 0x2A, 0x03, 0xEB, 0x49, 0x09, 0xA7, 0xDA, 0xB9, 0xF1, ++ 0x00, 0x0F, 0xA4, 0xD1, 0xE8, 0xE7, 0x15, 0x49, 0x17, 0x48, 0xB2, 0x22, ++ 0x01, 0xF0, 0x74, 0xFE, 0x3B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0x93, 0xDA, 0x0D, 0x2E, 0x04, 0xD0, 0x0F, 0x49, 0x12, 0x48, 0xBB, 0x22, ++ 0x01, 0xF0, 0x68, 0xFE, 0x0C, 0x49, 0x11, 0x48, 0xB3, 0x22, 0x01, 0xF0, ++ 0x63, 0xFE, 0x3B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xC1, 0xDB, ++ 0x81, 0xE7, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, 0x14, 0xAD, 0x15, 0x00, ++ 0xC8, 0xAC, 0x15, 0x00, 0x8C, 0xB6, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x84, 0xB6, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0xB8, 0xAC, 0x15, 0x00, 0x98, 0xAC, 0x15, 0x00, 0x74, 0xAC, 0x15, 0x00, ++ 0x10, 0x7D, 0x15, 0x00, 0x84, 0xAC, 0x15, 0x00, 0x41, 0x2D, 0x14, 0x00, ++ 0x70, 0xB5, 0x20, 0x4D, 0x2B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0x4F, 0xEA, 0x10, 0x26, 0xC4, 0xB2, 0x06, 0xDB, 0x1C, 0x4D, 0x24, 0x01, ++ 0x25, 0x44, 0xAB, 0x68, 0x33, 0xF8, 0x16, 0x00, 0x70, 0xBD, 0x0C, 0x2C, ++ 0x11, 0xD8, 0x21, 0xD0, 0x17, 0x4D, 0x05, 0xEB, 0x04, 0x13, 0x24, 0x01, ++ 0xDB, 0x89, 0xB3, 0x42, 0xF0, 0xD8, 0x25, 0x44, 0x14, 0x49, 0x15, 0x48, ++ 0xD9, 0x22, 0x01, 0xF0, 0x1F, 0xFE, 0xAB, 0x68, 0x33, 0xF8, 0x16, 0x00, ++ 0x70, 0xBD, 0x10, 0x49, 0x11, 0x48, 0xD7, 0x22, 0x01, 0xF0, 0x16, 0xFE, ++ 0x2B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xDA, 0xDA, 0x0D, 0x2C, ++ 0x04, 0xD0, 0x0A, 0x49, 0x0C, 0x48, 0xBB, 0x22, 0x01, 0xF0, 0x0A, 0xFE, ++ 0x07, 0x49, 0x0B, 0x48, 0xD8, 0x22, 0x01, 0xF0, 0x05, 0xFE, 0x2B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xD3, 0xDB, 0xC8, 0xE7, 0x00, 0xBF, ++ 0x38, 0x36, 0x17, 0x00, 0x14, 0xAD, 0x15, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x98, 0xAC, 0x15, 0x00, 0x74, 0xAC, 0x15, 0x00, 0x10, 0x7D, 0x15, 0x00, ++ 0x84, 0xAC, 0x15, 0x00, 0x2D, 0xE9, 0xF0, 0x47, 0xEF, 0xF3, 0x10, 0x83, ++ 0xDA, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x68, 0x4B, 0x01, 0x22, 0x1A, 0x60, ++ 0x67, 0x4D, 0x68, 0x48, 0x2B, 0x68, 0x01, 0x33, 0x2B, 0x60, 0x00, 0xF0, ++ 0xCF, 0xF9, 0x2B, 0x68, 0x04, 0x46, 0x2B, 0xB1, 0x61, 0x4A, 0x01, 0x3B, ++ 0x12, 0x68, 0x2B, 0x60, 0x00, 0x2B, 0x54, 0xD0, 0x00, 0x2C, 0x39, 0xD0, ++ 0x60, 0x4F, 0xB4, 0xF8, 0x06, 0xA0, 0x3B, 0x68, 0xB4, 0xF8, 0x04, 0x80, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x5F, 0xFA, 0x8A, 0xF6, 0x4F, 0xEA, ++ 0x1A, 0x2A, 0x48, 0xDB, 0xDF, 0xF8, 0x90, 0x91, 0x36, 0x01, 0x59, 0xF8, ++ 0x06, 0x10, 0xB1, 0x44, 0x00, 0x29, 0x52, 0xD0, 0xD9, 0xF8, 0x08, 0x30, ++ 0x33, 0xF8, 0x1A, 0x30, 0x01, 0xEB, 0xC3, 0x01, 0x40, 0x46, 0x8A, 0x88, ++ 0xFF, 0xF7, 0x9C, 0xFE, 0x06, 0x46, 0x00, 0x28, 0x45, 0xD0, 0xE3, 0x88, ++ 0x22, 0x89, 0xA1, 0x88, 0x4E, 0x48, 0x01, 0xF0, 0x31, 0xFB, 0x23, 0x89, ++ 0xE2, 0x88, 0xA0, 0x88, 0x04, 0xF1, 0x0C, 0x01, 0xB0, 0x47, 0x01, 0x28, ++ 0x08, 0xD0, 0x02, 0x28, 0x7B, 0xD0, 0x00, 0x28, 0x50, 0xD0, 0x3B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x79, 0xDB, 0xEF, 0xF3, 0x10, 0x83, ++ 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x3E, 0x4B, 0x01, 0x22, 0x1A, 0x60, ++ 0x41, 0x4A, 0x2B, 0x68, 0x52, 0x68, 0x01, 0x33, 0x2B, 0x60, 0x00, 0x2A, ++ 0x40, 0xD0, 0x33, 0xB1, 0x38, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x2B, 0x60, ++ 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0xBD, 0xE8, 0xF0, 0x87, 0x00, 0x2A, ++ 0xA8, 0xD0, 0x62, 0xB6, 0xA6, 0xE7, 0x0C, 0x2E, 0x36, 0xD8, 0x48, 0xD0, ++ 0xDF, 0xF8, 0xF8, 0x90, 0x09, 0xEB, 0x06, 0x13, 0x36, 0x01, 0xDB, 0x89, ++ 0x53, 0x45, 0xAE, 0xD8, 0x32, 0x49, 0x33, 0x48, 0x4F, 0xF4, 0x89, 0x72, ++ 0x01, 0xF0, 0x6C, 0xFD, 0xA7, 0xE7, 0xD9, 0xF8, 0x04, 0x10, 0x69, 0xB1, ++ 0x8A, 0x88, 0x40, 0x46, 0xFF, 0xF7, 0x4C, 0xFE, 0xE3, 0x88, 0x22, 0x89, ++ 0xA1, 0x88, 0x06, 0x46, 0x27, 0x48, 0x01, 0xF0, 0xE3, 0xFA, 0x00, 0x2E, ++ 0xAF, 0xD1, 0x05, 0xE0, 0xE3, 0x88, 0x22, 0x89, 0xA1, 0x88, 0x23, 0x48, ++ 0x01, 0xF0, 0xDA, 0xFA, 0xE3, 0x88, 0x22, 0x89, 0xA1, 0x88, 0x24, 0x48, ++ 0x01, 0xF0, 0xD4, 0xFA, 0x20, 0x46, 0xFF, 0xF7, 0xE5, 0xFC, 0xAF, 0xE7, ++ 0x4F, 0xF0, 0x00, 0x60, 0x00, 0xF0, 0x74, 0xF8, 0x2B, 0x68, 0xB8, 0xE7, ++ 0x1B, 0x49, 0x1E, 0x48, 0x4F, 0xF4, 0x88, 0x72, 0x01, 0xF0, 0x3E, 0xFD, ++ 0x3B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xBF, 0xF6, 0x72, 0xAF, ++ 0x0D, 0x2E, 0x04, 0xD0, 0x14, 0x49, 0x18, 0x48, 0xBB, 0x22, 0x01, 0xF0, ++ 0x31, 0xFD, 0x12, 0x49, 0x16, 0x48, 0x40, 0xF2, 0x11, 0x12, 0x01, 0xF0, ++ 0x2B, 0xFD, 0x3B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xAB, 0xDB, ++ 0x5E, 0xE7, 0x12, 0x48, 0x21, 0x46, 0x00, 0xF0, 0xCD, 0xF8, 0x85, 0xE7, ++ 0x09, 0x49, 0x10, 0x48, 0x40, 0xF2, 0x6D, 0x12, 0x01, 0xF0, 0x1A, 0xFD, ++ 0x7E, 0xE7, 0x00, 0xBF, 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x84, 0xB6, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, 0xB4, 0xAB, 0x15, 0x00, ++ 0x80, 0xB6, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x98, 0xAC, 0x15, 0x00, ++ 0xDC, 0xAC, 0x15, 0x00, 0x74, 0xAC, 0x15, 0x00, 0x10, 0x7D, 0x15, 0x00, ++ 0x84, 0xAC, 0x15, 0x00, 0x8C, 0xB6, 0x17, 0x00, 0x64, 0x7D, 0x15, 0x00, ++ 0x14, 0xAD, 0x15, 0x00, 0x00, 0x20, 0x70, 0x47, 0x02, 0x20, 0x70, 0x47, ++ 0x30, 0xB4, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, ++ 0x09, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x09, 0x4A, 0x09, 0x4D, 0x11, 0x68, ++ 0x2B, 0x68, 0x4C, 0x1C, 0x18, 0x43, 0x14, 0x60, 0x28, 0x60, 0x2C, 0xB1, ++ 0x03, 0x4B, 0x11, 0x60, 0x1B, 0x68, 0x09, 0xB9, 0x03, 0xB1, 0x62, 0xB6, ++ 0x30, 0xBC, 0x70, 0x47, 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x80, 0xB6, 0x17, 0x00, 0x4F, 0xF0, 0x00, 0x50, 0xFF, 0xF7, 0xDC, 0xBF, ++ 0x30, 0xB4, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, ++ 0x0A, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x0A, 0x4A, 0x0A, 0x4D, 0x11, 0x68, ++ 0x2B, 0x68, 0x4C, 0x1C, 0x23, 0xEA, 0x00, 0x00, 0x14, 0x60, 0x28, 0x60, ++ 0x2C, 0xB1, 0x04, 0x4B, 0x11, 0x60, 0x1B, 0x68, 0x09, 0xB9, 0x03, 0xB1, ++ 0x62, 0xB6, 0x30, 0xBC, 0x70, 0x47, 0x00, 0xBF, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x80, 0xB6, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x47, ++ 0x18, 0x4E, 0x34, 0x68, 0xDC, 0xB1, 0xDF, 0xF8, 0x68, 0x80, 0x17, 0x4D, ++ 0x17, 0x4F, 0xDF, 0xF8, 0x64, 0xA0, 0xDF, 0xF8, 0x64, 0x90, 0xD8, 0xF8, ++ 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xB4, 0xFA, 0x84, 0xF4, ++ 0x12, 0xDB, 0x55, 0xF8, 0x34, 0x30, 0x05, 0xEB, 0xC4, 0x04, 0x60, 0x68, ++ 0x98, 0x47, 0x3B, 0x68, 0x34, 0x68, 0xDB, 0x78, 0x1B, 0xB9, 0x00, 0x2C, ++ 0xEB, 0xD1, 0xBD, 0xE8, 0xF0, 0x87, 0xE9, 0xF7, 0x09, 0xFA, 0x00, 0x2C, ++ 0xE5, 0xD1, 0xF8, 0xE7, 0x1D, 0x2C, 0x03, 0xDC, 0x55, 0xF8, 0x34, 0x30, ++ 0x00, 0x2B, 0xE8, 0xD1, 0xDC, 0x22, 0x51, 0x46, 0x48, 0x46, 0x01, 0xF0, ++ 0x7D, 0xFC, 0xE0, 0xE7, 0x80, 0xB6, 0x17, 0x00, 0x70, 0x21, 0x17, 0x00, ++ 0x34, 0x36, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0xE4, 0xAD, 0x15, 0x00, 0x08, 0xB5, 0xFF, 0xF7, 0x35, 0xFC, 0x08, 0x4B, ++ 0x08, 0x49, 0xD8, 0x61, 0x00, 0x22, 0xC3, 0xE9, 0x03, 0x22, 0xC3, 0xE9, ++ 0x01, 0x22, 0xC3, 0xE9, 0x05, 0x22, 0x59, 0x62, 0x4F, 0xF0, 0xFF, 0x30, ++ 0xBD, 0xE8, 0x08, 0x40, 0xFF, 0xF7, 0x8A, 0xBF, 0x80, 0xB6, 0x17, 0x00, ++ 0xD1, 0x31, 0x14, 0x00, 0x00, 0x23, 0xC0, 0xE9, 0x00, 0x33, 0x70, 0x47, ++ 0x38, 0xB5, 0x0E, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0x05, 0x46, 0x0C, 0x46, 0x07, 0xDB, 0x2B, 0x68, 0x6B, 0xB1, 0x6B, 0x68, ++ 0x1C, 0x60, 0x00, 0x23, 0x6C, 0x60, 0x23, 0x60, 0x38, 0xBD, 0x00, 0x29, ++ 0xF5, 0xD1, 0x06, 0x49, 0x06, 0x48, 0x48, 0x22, 0x01, 0xF0, 0x3C, 0xFC, ++ 0xEF, 0xE7, 0x00, 0x23, 0x2C, 0x60, 0x6C, 0x60, 0x23, 0x60, 0x38, 0xBD, ++ 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x14, 0xAE, 0x15, 0x00, ++ 0x38, 0xB5, 0x0C, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0x05, 0x46, 0x0C, 0x46, 0x04, 0xDB, 0x2B, 0x68, 0x53, 0xB1, 0x23, 0x60, ++ 0x2C, 0x60, 0x38, 0xBD, 0x00, 0x29, 0xF8, 0xD1, 0x05, 0x49, 0x06, 0x48, ++ 0x5F, 0x22, 0x01, 0xF0, 0x1B, 0xFC, 0xF2, 0xE7, 0x6C, 0x60, 0x23, 0x60, ++ 0x2C, 0x60, 0x38, 0xBD, 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x14, 0xAE, 0x15, 0x00, 0x03, 0x68, 0x33, 0xB1, 0x42, 0x68, 0x19, 0x68, ++ 0x01, 0x60, 0x9A, 0x42, 0x04, 0xBF, 0x00, 0x22, 0x42, 0x60, 0x18, 0x46, ++ 0x70, 0x47, 0x00, 0xBF, 0x38, 0xB5, 0x16, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0x05, 0x46, 0x0C, 0x46, 0x0B, 0xDB, 0x2B, 0x68, ++ 0x43, 0xB1, 0xA3, 0x42, 0x02, 0xD1, 0x14, 0xE0, 0xA3, 0x42, 0x0C, 0xD0, ++ 0x1A, 0x46, 0x1B, 0x68, 0x00, 0x2B, 0xF9, 0xD1, 0x38, 0xBD, 0x00, 0x28, ++ 0xF1, 0xD1, 0x0C, 0x49, 0x0C, 0x48, 0x84, 0x22, 0x01, 0xF0, 0xE8, 0xFB, ++ 0xEB, 0xE7, 0x6B, 0x68, 0xA3, 0x42, 0x0A, 0xD0, 0x23, 0x68, 0x13, 0x60, ++ 0x38, 0xBD, 0x6B, 0x68, 0x22, 0x68, 0x2A, 0x60, 0xA3, 0x42, 0xEB, 0xD1, ++ 0x00, 0x23, 0x6B, 0x60, 0x38, 0xBD, 0x6A, 0x60, 0xF2, 0xE7, 0x00, 0xBF, ++ 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x28, 0xAE, 0x15, 0x00, ++ 0x03, 0x68, 0x2B, 0xB1, 0x00, 0x20, 0x1B, 0x68, 0x01, 0x30, 0x00, 0x2B, ++ 0xFB, 0xD1, 0x70, 0x47, 0x18, 0x46, 0x70, 0x47, 0x2D, 0xE9, 0xF0, 0x41, ++ 0xD0, 0xE9, 0x00, 0x47, 0x80, 0x46, 0x0D, 0x46, 0x16, 0x46, 0x1F, 0xB1, ++ 0x39, 0x46, 0x28, 0x46, 0x90, 0x47, 0x88, 0xB1, 0x00, 0x27, 0x24, 0xB9, ++ 0x1A, 0xE0, 0x23, 0x68, 0x27, 0x46, 0x8B, 0xB1, 0x1C, 0x46, 0x21, 0x46, ++ 0x28, 0x46, 0xB0, 0x47, 0x00, 0x28, 0xF6, 0xD0, 0x2C, 0x60, 0x67, 0xB9, ++ 0xC8, 0xF8, 0x00, 0x50, 0xBD, 0xE8, 0xF0, 0x81, 0x3D, 0x60, 0xC8, 0xF8, ++ 0x04, 0x50, 0x28, 0x60, 0xBD, 0xE8, 0xF0, 0x81, 0xC8, 0xF8, 0x04, 0x50, ++ 0x2B, 0x60, 0x3D, 0x60, 0xBD, 0xE8, 0xF0, 0x81, 0x00, 0x23, 0xC8, 0xF8, ++ 0x04, 0x50, 0x2B, 0x60, 0xEA, 0xE7, 0x00, 0xBF, 0x03, 0x68, 0xB9, 0xB1, ++ 0xCB, 0xB1, 0x8B, 0x42, 0x10, 0xB4, 0x04, 0x46, 0x02, 0xD1, 0x07, 0xE0, ++ 0x99, 0x42, 0x05, 0xD0, 0x1B, 0x68, 0x00, 0x2B, 0xFA, 0xD1, 0x5D, 0xF8, ++ 0x04, 0x4B, 0x70, 0x47, 0x63, 0x68, 0x08, 0x68, 0x10, 0x60, 0x8B, 0x42, ++ 0x0A, 0x60, 0xF6, 0xD1, 0x62, 0x60, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, ++ 0x11, 0x46, 0xFF, 0xF7, 0x49, 0xBF, 0x70, 0x47, 0x81, 0xB1, 0x03, 0x68, ++ 0x8B, 0x42, 0x0A, 0xD0, 0x2B, 0xB1, 0x18, 0x68, 0x88, 0x42, 0x03, 0xD0, ++ 0x03, 0x46, 0x00, 0x2B, 0xF9, 0xD1, 0x70, 0x47, 0x11, 0x60, 0x1A, 0x60, ++ 0x70, 0x47, 0x11, 0x46, 0xFF, 0xF7, 0x36, 0xBF, 0x11, 0x46, 0xFF, 0xF7, ++ 0x0F, 0xBF, 0x00, 0xBF, 0x0B, 0x46, 0x09, 0x68, 0x99, 0xB1, 0x02, 0x46, ++ 0x00, 0x68, 0x48, 0xB1, 0x10, 0xB4, 0x54, 0x68, 0x58, 0x68, 0x21, 0x60, ++ 0x50, 0x60, 0x00, 0x22, 0x5D, 0xF8, 0x04, 0x4B, 0x1A, 0x60, 0x70, 0x47, ++ 0x93, 0xE8, 0x03, 0x00, 0x82, 0xE8, 0x03, 0x00, 0x00, 0x22, 0x1A, 0x60, ++ 0x70, 0x47, 0x70, 0x47, 0xF8, 0xB5, 0x1F, 0x4F, 0x3B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0x06, 0x46, 0x0D, 0x46, 0x14, 0x46, 0x0A, 0xDB, ++ 0x25, 0xB3, 0x23, 0x68, 0x2B, 0x60, 0x73, 0x68, 0xA3, 0x42, 0x4F, 0xF0, ++ 0x00, 0x03, 0x08, 0xBF, 0x75, 0x60, 0x23, 0x60, 0xF8, 0xBD, 0xE0, 0xB1, ++ 0xB5, 0xB1, 0x2B, 0x68, 0xA3, 0x42, 0x0A, 0xD0, 0x13, 0x49, 0x14, 0x48, ++ 0x40, 0xF2, 0x75, 0x12, 0x01, 0xF0, 0x2A, 0xFB, 0x3B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0xE5, 0xDA, 0x00, 0x2C, 0xE3, 0xD1, 0x0D, 0x49, ++ 0x0E, 0x48, 0x4F, 0xF4, 0xBB, 0x72, 0x01, 0xF0, 0x1D, 0xFB, 0xDB, 0xE7, ++ 0x00, 0x2C, 0xF6, 0xD0, 0x23, 0x68, 0x33, 0x60, 0xD9, 0xE7, 0x07, 0x49, ++ 0x09, 0x48, 0x4F, 0xF4, 0xBA, 0x72, 0x01, 0xF0, 0x11, 0xFB, 0x3B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xD7, 0xDB, 0xCA, 0xE7, 0x00, 0xBF, ++ 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x38, 0xAE, 0x15, 0x00, ++ 0x74, 0xAE, 0x15, 0x00, 0x28, 0xAE, 0x15, 0x00, 0x81, 0xB1, 0x10, 0xB4, ++ 0x08, 0x4C, 0x01, 0x44, 0x10, 0xF8, 0x01, 0x3B, 0x83, 0xEA, 0x12, 0x63, ++ 0x81, 0x42, 0x54, 0xF8, 0x23, 0x30, 0x83, 0xEA, 0x02, 0x22, 0xF5, 0xD1, ++ 0x10, 0x46, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, 0x10, 0x46, 0x70, 0x47, ++ 0x84, 0xAE, 0x15, 0x00, 0xF8, 0xB5, 0x0F, 0x18, 0xB8, 0x42, 0xBC, 0x46, ++ 0x06, 0xD3, 0x1D, 0xE0, 0x44, 0x78, 0x2E, 0x78, 0x02, 0x34, 0xFF, 0x2E, ++ 0x20, 0x44, 0x06, 0xD0, 0x46, 0x1C, 0xB7, 0x42, 0x05, 0x46, 0xF5, 0xD8, ++ 0x00, 0x25, 0x28, 0x46, 0xF8, 0xBD, 0x87, 0x42, 0xFA, 0xD3, 0x1C, 0x80, ++ 0x00, 0x2D, 0xF7, 0xD0, 0xEE, 0x1C, 0x66, 0x45, 0xF4, 0xD8, 0xAE, 0x78, ++ 0x96, 0x42, 0xF2, 0xD0, 0x0C, 0x1B, 0x84, 0x45, 0xA1, 0xB2, 0x01, 0xD9, ++ 0x0F, 0x18, 0xE7, 0xE7, 0x06, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0xE5, 0xDA, 0x84, 0x45, 0xE3, 0xD0, 0x03, 0x49, 0x04, 0x48, ++ 0x7F, 0x22, 0x01, 0xF0, 0xB9, 0xFA, 0xDD, 0xE7, 0x38, 0x36, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x84, 0xB2, 0x15, 0x00, 0x2D, 0xE9, 0xF8, 0x43, ++ 0x01, 0xEB, 0x00, 0x08, 0x40, 0x45, 0xC6, 0x46, 0x2D, 0xD2, 0x02, 0xF1, ++ 0x05, 0x0C, 0xC2, 0xF1, 0x02, 0x07, 0x05, 0xE0, 0x44, 0x78, 0x35, 0x78, ++ 0x02, 0x34, 0xDD, 0x2D, 0x20, 0x44, 0x07, 0xD0, 0x45, 0x1C, 0xA8, 0x45, ++ 0x06, 0x46, 0xF5, 0xD8, 0x00, 0x26, 0x30, 0x46, 0xBD, 0xE8, 0xF8, 0x83, ++ 0x80, 0x45, 0xF9, 0xD3, 0x1C, 0x80, 0x00, 0x2E, 0xF6, 0xD0, 0xF5, 0x1D, ++ 0xAE, 0x45, 0xF3, 0xD3, 0x15, 0x46, 0x01, 0xE0, 0x65, 0x45, 0xF0, 0xD0, ++ 0x05, 0xEB, 0x06, 0x08, 0x15, 0xF8, 0x01, 0x9B, 0x18, 0xF8, 0x07, 0x80, ++ 0xC1, 0x45, 0xF5, 0xD0, 0x0C, 0x1B, 0x86, 0x45, 0xA1, 0xB2, 0x02, 0xD9, ++ 0x01, 0xEB, 0x00, 0x08, 0xDC, 0xE7, 0x07, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0xDA, 0xDA, 0x86, 0x45, 0xD8, 0xD0, 0x04, 0x49, ++ 0x04, 0x48, 0xB4, 0x22, 0x01, 0xF0, 0x70, 0xFA, 0xD2, 0xE7, 0x00, 0xBF, ++ 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x84, 0xB2, 0x15, 0x00, ++ 0x01, 0x44, 0x43, 0x1C, 0x99, 0x42, 0x19, 0xD9, 0x70, 0xB4, 0x03, 0xE0, ++ 0x6B, 0x1C, 0x99, 0x42, 0x28, 0x46, 0x10, 0xD9, 0x44, 0x78, 0x06, 0x78, ++ 0xA3, 0x1C, 0x01, 0x2E, 0x03, 0xEB, 0x00, 0x05, 0xF4, 0xD1, 0xA9, 0x42, ++ 0x07, 0xD3, 0x38, 0xB1, 0x0A, 0x2B, 0x04, 0xD8, 0x02, 0x2B, 0x02, 0xD0, ++ 0x14, 0x70, 0x70, 0xBC, 0x70, 0x47, 0x00, 0x20, 0x70, 0xBC, 0x70, 0x47, ++ 0x00, 0x20, 0x70, 0x47, 0x01, 0x44, 0x43, 0x1C, 0x99, 0x42, 0x17, 0xD9, ++ 0x70, 0xB4, 0x03, 0xE0, 0x6B, 0x1C, 0x99, 0x42, 0x28, 0x46, 0x0E, 0xD9, ++ 0x44, 0x78, 0x06, 0x78, 0xA3, 0x1C, 0x32, 0x2E, 0x03, 0xEB, 0x00, 0x05, ++ 0xF4, 0xD1, 0xA9, 0x42, 0x05, 0xD3, 0x28, 0xB1, 0x02, 0x2B, 0x02, 0xD0, ++ 0x14, 0x70, 0x70, 0xBC, 0x70, 0x47, 0x00, 0x20, 0x70, 0xBC, 0x70, 0x47, ++ 0x00, 0x20, 0x70, 0x47, 0x01, 0x44, 0x43, 0x1C, 0x99, 0x42, 0x19, 0xD9, ++ 0x70, 0xB4, 0x03, 0xE0, 0x73, 0x1C, 0x99, 0x42, 0x30, 0x46, 0x10, 0xD9, ++ 0x45, 0x78, 0x04, 0x78, 0xAB, 0x1C, 0x1E, 0x18, 0x00, 0x2C, 0xF5, 0xD1, ++ 0xB1, 0x42, 0x05, 0xD3, 0x10, 0xB1, 0x22, 0x2B, 0x02, 0xD8, 0x15, 0x70, ++ 0x70, 0xBC, 0x70, 0x47, 0x20, 0x46, 0x70, 0xBC, 0x70, 0x47, 0x00, 0x20, ++ 0x70, 0xBC, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x01, 0x44, 0x43, 0x1C, ++ 0x99, 0x42, 0x17, 0xD9, 0x70, 0xB4, 0x03, 0xE0, 0x6B, 0x1C, 0x99, 0x42, ++ 0x28, 0x46, 0x0E, 0xD9, 0x44, 0x78, 0x06, 0x78, 0xA3, 0x1C, 0x07, 0x2E, ++ 0x03, 0xEB, 0x00, 0x05, 0xF4, 0xD1, 0xA9, 0x42, 0x05, 0xD3, 0x28, 0xB1, ++ 0x07, 0x2B, 0x02, 0xD9, 0x14, 0x70, 0x70, 0xBC, 0x70, 0x47, 0x00, 0x20, ++ 0x70, 0xBC, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x01, 0x44, 0x43, 0x1C, ++ 0x99, 0x42, 0x17, 0xD9, 0x70, 0xB4, 0x03, 0xE0, 0x6B, 0x1C, 0x99, 0x42, ++ 0x28, 0x46, 0x0E, 0xD9, 0x44, 0x78, 0x06, 0x78, 0xA3, 0x1C, 0x30, 0x2E, ++ 0x03, 0xEB, 0x00, 0x05, 0xF4, 0xD1, 0xA9, 0x42, 0x05, 0xD3, 0x28, 0xB1, ++ 0x13, 0x2B, 0x02, 0xD9, 0x14, 0x70, 0x70, 0xBC, 0x70, 0x47, 0x00, 0x20, ++ 0x70, 0xBC, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x01, 0x44, 0x43, 0x1C, ++ 0x99, 0x42, 0x19, 0xD9, 0x10, 0xB4, 0x03, 0xE0, 0x53, 0x1C, 0x99, 0x42, ++ 0x10, 0x46, 0x0F, 0xD9, 0x43, 0x78, 0x04, 0x78, 0x02, 0x33, 0x25, 0x2C, ++ 0x03, 0xEB, 0x00, 0x02, 0xF4, 0xD1, 0x91, 0x42, 0x06, 0xD3, 0x30, 0xB1, ++ 0x05, 0x2B, 0x18, 0xBF, 0x00, 0x20, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, ++ 0x00, 0x20, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, ++ 0x01, 0x44, 0x43, 0x1C, 0x99, 0x42, 0x19, 0xD9, 0x10, 0xB4, 0x03, 0xE0, ++ 0x53, 0x1C, 0x99, 0x42, 0x10, 0x46, 0x0F, 0xD9, 0x43, 0x78, 0x04, 0x78, ++ 0x02, 0x33, 0x3C, 0x2C, 0x03, 0xEB, 0x00, 0x02, 0xF4, 0xD1, 0x91, 0x42, ++ 0x06, 0xD3, 0x30, 0xB1, 0x06, 0x2B, 0x18, 0xBF, 0x00, 0x20, 0x5D, 0xF8, ++ 0x04, 0x4B, 0x70, 0x47, 0x00, 0x20, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, ++ 0x00, 0x20, 0x70, 0x47, 0x01, 0x44, 0x43, 0x1C, 0x99, 0x42, 0x1A, 0xD9, ++ 0x30, 0xB4, 0x03, 0xE0, 0x63, 0x1C, 0x99, 0x42, 0x20, 0x46, 0x11, 0xD9, ++ 0x43, 0x78, 0x05, 0x78, 0x02, 0x33, 0x3E, 0x2D, 0x03, 0xEB, 0x00, 0x04, ++ 0xF4, 0xD1, 0xA1, 0x42, 0x08, 0xD3, 0x40, 0xB1, 0xA3, 0xF1, 0x03, 0x03, ++ 0xB3, 0xFA, 0x83, 0xF3, 0x5B, 0x09, 0x30, 0xBC, 0x13, 0x70, 0x70, 0x47, ++ 0x00, 0x20, 0x30, 0xBC, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0xBF, ++ 0x01, 0x44, 0x43, 0x1C, 0x99, 0x42, 0x2B, 0xD9, 0x30, 0xB4, 0x03, 0xE0, ++ 0x18, 0x46, 0x01, 0x33, 0x99, 0x42, 0x16, 0xD9, 0x44, 0x78, 0x05, 0x78, ++ 0xA3, 0x1C, 0xC4, 0x2D, 0x03, 0x44, 0xF5, 0xD1, 0x99, 0x42, 0x0E, 0xD3, ++ 0x70, 0xB1, 0x02, 0x30, 0x04, 0x44, 0x07, 0xE0, 0x43, 0x78, 0x05, 0x78, ++ 0x02, 0x33, 0xC2, 0x2D, 0x03, 0xEB, 0x00, 0x01, 0x06, 0xD0, 0x08, 0x46, ++ 0x43, 0x1C, 0x9C, 0x42, 0xF4, 0xD8, 0x00, 0x20, 0x30, 0xBC, 0x70, 0x47, ++ 0x8C, 0x42, 0xFA, 0xD3, 0x00, 0x28, 0xF9, 0xD0, 0xA3, 0xF1, 0x05, 0x03, ++ 0xB3, 0xFA, 0x83, 0xF3, 0x5B, 0x09, 0x30, 0xBC, 0x13, 0x70, 0x70, 0x47, ++ 0x00, 0x20, 0x70, 0x47, 0x01, 0x44, 0x43, 0x1C, 0x99, 0x42, 0x19, 0xD9, ++ 0x10, 0xB4, 0x03, 0xE0, 0x53, 0x1C, 0x99, 0x42, 0x10, 0x46, 0x0F, 0xD9, ++ 0x43, 0x78, 0x04, 0x78, 0x02, 0x33, 0x03, 0x2C, 0x03, 0xEB, 0x00, 0x02, ++ 0xF4, 0xD1, 0x91, 0x42, 0x06, 0xD3, 0x30, 0xB1, 0x03, 0x2B, 0x18, 0xBF, ++ 0x00, 0x20, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, 0x00, 0x20, 0x5D, 0xF8, ++ 0x04, 0x4B, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x01, 0x44, 0x43, 0x1C, ++ 0x99, 0x42, 0x19, 0xD9, 0x10, 0xB4, 0x03, 0xE0, 0x53, 0x1C, 0x99, 0x42, ++ 0x10, 0x46, 0x0F, 0xD9, 0x43, 0x78, 0x04, 0x78, 0x02, 0x33, 0x4C, 0x2C, ++ 0x03, 0xEB, 0x00, 0x02, 0xF4, 0xD1, 0x91, 0x42, 0x06, 0xD3, 0x30, 0xB1, ++ 0x12, 0x2B, 0x18, 0xBF, 0x00, 0x20, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, ++ 0x00, 0x20, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, ++ 0x01, 0x44, 0x43, 0x1C, 0x99, 0x42, 0x19, 0xD9, 0x10, 0xB4, 0x03, 0xE0, ++ 0x53, 0x1C, 0x99, 0x42, 0x10, 0x46, 0x0F, 0xD9, 0x43, 0x78, 0x04, 0x78, ++ 0x02, 0x33, 0x2A, 0x2C, 0x03, 0xEB, 0x00, 0x02, 0xF4, 0xD1, 0x91, 0x42, ++ 0x06, 0xD3, 0x30, 0xB1, 0x03, 0x2B, 0x18, 0xBF, 0x00, 0x20, 0x5D, 0xF8, ++ 0x04, 0x4B, 0x70, 0x47, 0x00, 0x20, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, ++ 0x00, 0x20, 0x70, 0x47, 0x01, 0x44, 0x43, 0x1C, 0x99, 0x42, 0x19, 0xD9, ++ 0x10, 0xB4, 0x03, 0xE0, 0x53, 0x1C, 0x99, 0x42, 0x10, 0x46, 0x0F, 0xD9, ++ 0x43, 0x78, 0x04, 0x78, 0x02, 0x33, 0xC7, 0x2C, 0x03, 0xEB, 0x00, 0x02, ++ 0xF4, 0xD1, 0x91, 0x42, 0x06, 0xD3, 0x30, 0xB1, 0x03, 0x2B, 0x18, 0xBF, ++ 0x00, 0x20, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, 0x00, 0x20, 0x5D, 0xF8, ++ 0x04, 0x4B, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x01, 0x44, 0x43, 0x1C, ++ 0x99, 0x42, 0x19, 0xD9, 0x10, 0xB4, 0x03, 0xE0, 0x53, 0x1C, 0x99, 0x42, ++ 0x10, 0x46, 0x0F, 0xD9, 0x43, 0x78, 0x04, 0x78, 0x02, 0x33, 0x20, 0x2C, ++ 0x03, 0xEB, 0x00, 0x02, 0xF4, 0xD1, 0x91, 0x42, 0x06, 0xD3, 0x30, 0xB1, ++ 0x03, 0x2B, 0x18, 0xBF, 0x00, 0x20, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, ++ 0x00, 0x20, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, ++ 0x01, 0x44, 0x43, 0x1C, 0x99, 0x42, 0x19, 0xD9, 0x10, 0xB4, 0x03, 0xE0, ++ 0x53, 0x1C, 0x99, 0x42, 0x10, 0x46, 0x0F, 0xD9, 0x43, 0x78, 0x04, 0x78, ++ 0x02, 0x33, 0x36, 0x2C, 0x03, 0xEB, 0x00, 0x02, 0xF4, 0xD1, 0x91, 0x42, ++ 0x06, 0xD3, 0x30, 0xB1, 0x05, 0x2B, 0x18, 0xBF, 0x00, 0x20, 0x5D, 0xF8, ++ 0x04, 0x4B, 0x70, 0x47, 0x00, 0x20, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, ++ 0x00, 0x20, 0x70, 0x47, 0x00, 0xB5, 0x83, 0xB0, 0x06, 0x4A, 0x0D, 0xF1, ++ 0x06, 0x03, 0xFF, 0xF7, 0xC1, 0xFD, 0x20, 0xB1, 0xBD, 0xF8, 0x06, 0x30, ++ 0x1A, 0x2B, 0x18, 0xBF, 0x00, 0x20, 0x03, 0xB0, 0x5D, 0xF8, 0x04, 0xFB, ++ 0x98, 0xB2, 0x15, 0x00, 0x01, 0x44, 0x43, 0x1C, 0x99, 0x42, 0x19, 0xD9, ++ 0x10, 0xB4, 0x03, 0xE0, 0x53, 0x1C, 0x99, 0x42, 0x10, 0x46, 0x0F, 0xD9, ++ 0x43, 0x78, 0x04, 0x78, 0x02, 0x33, 0x2D, 0x2C, 0x03, 0xEB, 0x00, 0x02, ++ 0xF4, 0xD1, 0x91, 0x42, 0x06, 0xD3, 0x30, 0xB1, 0x1C, 0x2B, 0x18, 0xBF, ++ 0x00, 0x20, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, 0x00, 0x20, 0x5D, 0xF8, ++ 0x04, 0x4B, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x01, 0x44, 0x43, 0x1C, ++ 0x99, 0x42, 0x19, 0xD9, 0x10, 0xB4, 0x03, 0xE0, 0x53, 0x1C, 0x99, 0x42, ++ 0x10, 0x46, 0x0F, 0xD9, 0x43, 0x78, 0x04, 0x78, 0x02, 0x33, 0x47, 0x2C, ++ 0x03, 0xEB, 0x00, 0x02, 0xF4, 0xD1, 0x91, 0x42, 0x06, 0xD3, 0x30, 0xB1, ++ 0x06, 0x2B, 0x38, 0xBF, 0x00, 0x20, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, ++ 0x00, 0x20, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, ++ 0x01, 0x44, 0x43, 0x1C, 0x99, 0x42, 0x1D, 0xD9, 0x10, 0xB4, 0x03, 0xE0, ++ 0x63, 0x1C, 0x99, 0x42, 0x20, 0x46, 0x13, 0xD9, 0x43, 0x78, 0x02, 0x78, ++ 0x02, 0x33, 0x1C, 0x18, 0x00, 0x2A, 0xF5, 0xD1, 0xA1, 0x42, 0x03, 0xD2, ++ 0x10, 0x46, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, 0x00, 0x28, 0xFA, 0xD0, ++ 0x06, 0x2B, 0x38, 0xBF, 0x00, 0x20, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, ++ 0x00, 0x20, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, ++ 0x01, 0x44, 0x43, 0x1C, 0x99, 0x42, 0x19, 0xD9, 0x10, 0xB4, 0x03, 0xE0, ++ 0x53, 0x1C, 0x99, 0x42, 0x10, 0x46, 0x0F, 0xD9, 0x43, 0x78, 0x04, 0x78, ++ 0x02, 0x33, 0x53, 0x2C, 0x03, 0xEB, 0x00, 0x02, 0xF4, 0xD1, 0x91, 0x42, ++ 0x06, 0xD3, 0x30, 0xB1, 0x04, 0x2B, 0x18, 0xBF, 0x00, 0x20, 0x5D, 0xF8, ++ 0x04, 0x4B, 0x70, 0x47, 0x00, 0x20, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, ++ 0x00, 0x20, 0x70, 0x47, 0x01, 0x44, 0x43, 0x1C, 0x99, 0x42, 0x19, 0xD9, ++ 0x10, 0xB4, 0x03, 0xE0, 0x53, 0x1C, 0x99, 0x42, 0x10, 0x46, 0x0F, 0xD9, ++ 0x43, 0x78, 0x04, 0x78, 0x02, 0x33, 0x55, 0x2C, 0x03, 0xEB, 0x00, 0x02, ++ 0xF4, 0xD1, 0x91, 0x42, 0x06, 0xD3, 0x30, 0xB1, 0x02, 0x2B, 0x08, 0xBF, ++ 0x00, 0x20, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, 0x00, 0x20, 0x5D, 0xF8, ++ 0x04, 0x4B, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x01, 0x44, 0x43, 0x1C, ++ 0x99, 0x42, 0x19, 0xD9, 0x10, 0xB4, 0x03, 0xE0, 0x53, 0x1C, 0x99, 0x42, ++ 0x10, 0x46, 0x0F, 0xD9, 0x43, 0x78, 0x04, 0x78, 0x02, 0x33, 0xBF, 0x2C, ++ 0x03, 0xEB, 0x00, 0x02, 0xF4, 0xD1, 0x91, 0x42, 0x06, 0xD3, 0x30, 0xB1, ++ 0x0E, 0x2B, 0x18, 0xBF, 0x00, 0x20, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, ++ 0x00, 0x20, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, ++ 0x10, 0xB5, 0x82, 0xB0, 0x14, 0x46, 0x0D, 0xF1, 0x06, 0x03, 0x23, 0x22, ++ 0xFF, 0xF7, 0xB2, 0xFC, 0x40, 0xB1, 0xBD, 0xF8, 0x06, 0x30, 0xA3, 0xF1, ++ 0x18, 0x02, 0x21, 0x2A, 0x9A, 0xBF, 0x03, 0x3B, 0x23, 0x70, 0x00, 0x20, ++ 0x02, 0xB0, 0x10, 0xBD, 0x01, 0x44, 0x43, 0x1C, 0x99, 0x42, 0x19, 0xD9, ++ 0x10, 0xB4, 0x03, 0xE0, 0x53, 0x1C, 0x99, 0x42, 0x10, 0x46, 0x0F, 0xD9, ++ 0x43, 0x78, 0x04, 0x78, 0x02, 0x33, 0x3D, 0x2C, 0x03, 0xEB, 0x00, 0x02, ++ 0xF4, 0xD1, 0x91, 0x42, 0x06, 0xD3, 0x30, 0xB1, 0x18, 0x2B, 0x18, 0xBF, ++ 0x00, 0x20, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, 0x00, 0x20, 0x5D, 0xF8, ++ 0x04, 0x4B, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x01, 0x44, 0x43, 0x1C, ++ 0x99, 0x42, 0x19, 0xD9, 0x10, 0xB4, 0x03, 0xE0, 0x53, 0x1C, 0x99, 0x42, ++ 0x10, 0x46, 0x0F, 0xD9, 0x43, 0x78, 0x04, 0x78, 0x02, 0x33, 0xC0, 0x2C, ++ 0x03, 0xEB, 0x00, 0x02, 0xF4, 0xD1, 0x91, 0x42, 0x06, 0xD3, 0x30, 0xB1, ++ 0x07, 0x2B, 0x18, 0xBF, 0x00, 0x20, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, ++ 0x00, 0x20, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, ++ 0x10, 0xB5, 0x82, 0xB0, 0x14, 0x46, 0x0D, 0xF1, 0x06, 0x03, 0x24, 0x22, ++ 0xFF, 0xF7, 0x5E, 0xFC, 0x40, 0xB1, 0xBD, 0xF8, 0x06, 0x30, 0xA3, 0xF1, ++ 0x09, 0x02, 0x09, 0x2A, 0x9A, 0xBF, 0x03, 0x3B, 0x23, 0x70, 0x00, 0x20, ++ 0x02, 0xB0, 0x10, 0xBD, 0x00, 0xB5, 0x83, 0xB0, 0x0D, 0xF1, 0x06, 0x03, ++ 0x26, 0x22, 0xFF, 0xF7, 0x4B, 0xFC, 0x20, 0xB1, 0xBD, 0xF8, 0x06, 0x30, ++ 0x10, 0x2B, 0x18, 0xBF, 0x00, 0x20, 0x03, 0xB0, 0x5D, 0xF8, 0x04, 0xFB, ++ 0x00, 0xB5, 0x83, 0xB0, 0x0D, 0xF1, 0x06, 0x03, 0x25, 0x22, 0xFF, 0xF7, ++ 0x3B, 0xFC, 0x20, 0xB1, 0xBD, 0xF8, 0x06, 0x30, 0x04, 0x2B, 0x18, 0xBF, ++ 0x00, 0x20, 0x03, 0xB0, 0x5D, 0xF8, 0x04, 0xFB, 0x43, 0x79, 0x02, 0x79, ++ 0x58, 0x00, 0x40, 0xEA, 0xD2, 0x10, 0x80, 0x05, 0x70, 0x47, 0x00, 0xBF, ++ 0x43, 0x79, 0x07, 0x48, 0x83, 0xEA, 0x13, 0x13, 0x5B, 0x01, 0xC1, 0xF3, ++ 0x08, 0x01, 0x03, 0xF4, 0xF0, 0x73, 0x0B, 0x44, 0x00, 0xEA, 0x83, 0x50, ++ 0x40, 0xF4, 0x7C, 0x10, 0x70, 0x47, 0x00, 0xBF, 0x00, 0x00, 0xC0, 0x7F, ++ 0x00, 0x28, 0x08, 0xDA, 0x10, 0xF1, 0x6D, 0x0F, 0x01, 0xDA, 0x00, 0x20, ++ 0x70, 0x47, 0x6E, 0x30, 0x40, 0x00, 0xC0, 0xB2, 0x70, 0x47, 0xDC, 0x20, ++ 0x70, 0x47, 0x00, 0xBF, 0x2D, 0xE9, 0xF0, 0x4F, 0x1D, 0x46, 0x95, 0xB0, ++ 0x90, 0x46, 0xDD, 0xF8, 0x78, 0xB0, 0x15, 0xF8, 0x01, 0x2B, 0x03, 0x91, ++ 0x07, 0x46, 0x00, 0x28, 0x00, 0xF0, 0x7F, 0x81, 0x00, 0x2A, 0x00, 0xF0, ++ 0x91, 0x83, 0x00, 0x24, 0xCD, 0xE9, 0x00, 0x44, 0x03, 0x9E, 0x02, 0x94, ++ 0xA1, 0x46, 0xA2, 0x46, 0xA2, 0xF1, 0x20, 0x03, 0x58, 0x2B, 0x5A, 0xD8, ++ 0xDF, 0xE8, 0x13, 0xF0, 0x35, 0x01, 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, ++ 0x59, 0x00, 0x34, 0x03, 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, ++ 0x17, 0x03, 0x35, 0x01, 0x59, 0x00, 0x35, 0x01, 0x36, 0x03, 0x59, 0x00, ++ 0x12, 0x01, 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, ++ 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, ++ 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, 0x6E, 0x00, ++ 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, ++ 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, 0x6E, 0x00, ++ 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, ++ 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, 0x6E, 0x00, 0x59, 0x00, ++ 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, 0x59, 0x00, ++ 0x59, 0x00, 0x6E, 0x00, 0x6E, 0x00, 0x6E, 0x00, 0x6E, 0x00, 0x59, 0x00, ++ 0x59, 0x00, 0x59, 0x00, 0x10, 0x01, 0x6E, 0x00, 0x59, 0x00, 0x59, 0x00, ++ 0x10, 0x01, 0x6E, 0x00, 0x59, 0x00, 0x59, 0x00, 0x6E, 0x00, 0x59, 0x00, ++ 0x59, 0x00, 0x6E, 0x00, 0x59, 0x00, 0x6E, 0x00, 0x59, 0x00, 0x59, 0x00, ++ 0x6E, 0x00, 0xA2, 0xF1, 0x31, 0x01, 0x08, 0x29, 0x40, 0xF2, 0xE2, 0x80, ++ 0x00, 0x21, 0x9E, 0x48, 0x00, 0xEB, 0xCA, 0x0A, 0x1A, 0xF8, 0x01, 0xA0, ++ 0xBA, 0xF1, 0x07, 0x0F, 0x00, 0xF2, 0xD8, 0x83, 0xDF, 0xE8, 0x0A, 0xF0, ++ 0x75, 0x5B, 0x45, 0x9A, 0x70, 0x8E, 0x80, 0x06, 0x07, 0x21, 0xEE, 0xE7, ++ 0xA2, 0xF1, 0x41, 0x03, 0x37, 0x2B, 0x00, 0xF2, 0x05, 0x82, 0xDF, 0xE8, ++ 0x13, 0xF0, 0x05, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, ++ 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, ++ 0x03, 0x02, 0x54, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, ++ 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, ++ 0x29, 0x01, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, ++ 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x05, 0x02, 0x29, 0x01, 0x5E, 0x01, ++ 0x29, 0x01, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0xA3, 0x01, ++ 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x54, 0x02, 0x03, 0x02, 0x03, 0x02, ++ 0x29, 0x01, 0x03, 0x02, 0x03, 0x02, 0xF8, 0x01, 0x03, 0x02, 0x29, 0x01, ++ 0x03, 0x02, 0x03, 0x02, 0x29, 0x01, 0x10, 0x2B, 0x00, 0xF2, 0xCA, 0x80, ++ 0xDF, 0xE8, 0x13, 0xF0, 0xD2, 0x00, 0xC8, 0x00, 0xC8, 0x00, 0xC8, 0x00, ++ 0xC8, 0x00, 0xC8, 0x00, 0xC8, 0x00, 0xC8, 0x00, 0xC8, 0x00, 0xC8, 0x00, ++ 0xC8, 0x00, 0xD9, 0x00, 0xC8, 0x00, 0xE0, 0x00, 0xC8, 0x00, 0xC8, 0x00, ++ 0xC1, 0x00, 0x00, 0x23, 0x00, 0x93, 0x02, 0x93, 0x4F, 0xF0, 0xFF, 0x33, ++ 0x01, 0x93, 0x4F, 0xF0, 0x01, 0x0A, 0x15, 0xF8, 0x01, 0x2B, 0x00, 0x2A, ++ 0x7F, 0xF4, 0x28, 0xAF, 0x00, 0x2E, 0x62, 0xD0, 0x00, 0x23, 0x3B, 0x70, ++ 0x20, 0x46, 0x15, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x00, 0x23, 0x01, 0x93, ++ 0x4F, 0xF0, 0x04, 0x0A, 0xED, 0xE7, 0x2E, 0xB1, 0xA0, 0x45, 0x9C, 0xBF, ++ 0x07, 0xF8, 0x01, 0x2B, 0x06, 0xF1, 0xFF, 0x36, 0x01, 0x34, 0x4F, 0xF0, ++ 0x00, 0x0A, 0xE2, 0xE7, 0x68, 0x2A, 0x7B, 0xD0, 0x6C, 0x2A, 0x3F, 0xD0, ++ 0x57, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xC0, 0xF2, ++ 0x92, 0x82, 0x4F, 0xF0, 0x06, 0x0A, 0xD4, 0xE7, 0x2A, 0x2A, 0x61, 0xD0, ++ 0x01, 0x9B, 0x30, 0x3A, 0x03, 0xEB, 0x83, 0x03, 0x02, 0xEB, 0x43, 0x03, ++ 0x01, 0x93, 0x4F, 0xF0, 0x05, 0x0A, 0xC8, 0xE7, 0x2A, 0x2A, 0x5B, 0xD0, ++ 0x02, 0x9B, 0x30, 0x3A, 0x03, 0xEB, 0x83, 0x03, 0x02, 0xEB, 0x43, 0x03, ++ 0x02, 0x93, 0x4F, 0xF0, 0x03, 0x0A, 0xBC, 0xE7, 0x06, 0x21, 0x4C, 0xE7, ++ 0x44, 0x4B, 0x03, 0xEB, 0xCA, 0x0A, 0x9A, 0xF8, 0x03, 0xA0, 0xBA, 0xF1, ++ 0x07, 0x0F, 0x00, 0xF2, 0x25, 0x83, 0x01, 0xA3, 0x53, 0xF8, 0x2A, 0xF0, ++ 0x8F, 0x3F, 0x14, 0x00, 0x5B, 0x3F, 0x14, 0x00, 0xBB, 0x40, 0x14, 0x00, ++ 0xD9, 0x3F, 0x14, 0x00, 0x85, 0x3F, 0x14, 0x00, 0xC1, 0x3F, 0x14, 0x00, ++ 0xA5, 0x3F, 0x14, 0x00, 0xB1, 0x3E, 0x14, 0x00, 0x00, 0x9B, 0x43, 0xF0, ++ 0x02, 0x03, 0x00, 0x93, 0x4F, 0xF0, 0x06, 0x0A, 0x97, 0xE7, 0x05, 0x21, ++ 0x27, 0xE7, 0x03, 0x9B, 0x00, 0x2B, 0x9B, 0xD0, 0x20, 0x46, 0x07, 0xF8, ++ 0x01, 0x6C, 0x15, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x2D, 0x49, 0x01, 0xEB, ++ 0xCA, 0x0A, 0x9A, 0xF8, 0x04, 0xA0, 0xBA, 0xF1, 0x07, 0x0F, 0x00, 0xF2, ++ 0xF7, 0x82, 0x01, 0xA1, 0x51, 0xF8, 0x2A, 0xF0, 0x8F, 0x3F, 0x14, 0x00, ++ 0x5B, 0x3F, 0x14, 0x00, 0x2F, 0x3F, 0x14, 0x00, 0xDD, 0x3F, 0x14, 0x00, ++ 0x85, 0x3F, 0x14, 0x00, 0xC1, 0x3F, 0x14, 0x00, 0xA5, 0x3F, 0x14, 0x00, ++ 0xB1, 0x3E, 0x14, 0x00, 0x5B, 0xF8, 0x04, 0x3B, 0x01, 0x93, 0x4F, 0xF0, ++ 0x05, 0x0A, 0x6A, 0xE7, 0x5B, 0xF8, 0x04, 0x3B, 0x02, 0x93, 0x4F, 0xF0, ++ 0x03, 0x0A, 0x64, 0xE7, 0x00, 0x9B, 0x43, 0xF0, 0x01, 0x03, 0x00, 0x93, ++ 0x4F, 0xF0, 0x06, 0x0A, 0x5D, 0xE7, 0x14, 0x46, 0x00, 0x2A, 0x3F, 0xF4, ++ 0x63, 0xAF, 0x03, 0x90, 0x7D, 0xE6, 0x00, 0x9B, 0x43, 0xF0, 0x40, 0x03, ++ 0x00, 0x93, 0x4F, 0xF0, 0x02, 0x0A, 0x50, 0xE7, 0x10, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xC0, 0xF2, 0x9E, 0x82, 0x4F, 0xF0, ++ 0x02, 0x0A, 0x46, 0xE7, 0x00, 0x9B, 0x43, 0xF0, 0x10, 0x03, 0x00, 0x93, ++ 0x4F, 0xF0, 0x02, 0x0A, 0x3F, 0xE7, 0x00, 0x9B, 0x43, 0xF0, 0x08, 0x03, ++ 0x00, 0x93, 0x4F, 0xF0, 0x02, 0x0A, 0x38, 0xE7, 0x00, 0x9B, 0x43, 0xF0, ++ 0x20, 0x03, 0x00, 0x93, 0x4F, 0xF0, 0x02, 0x0A, 0x31, 0xE7, 0x00, 0xBF, ++ 0x24, 0xB3, 0x15, 0x00, 0x38, 0x36, 0x17, 0x00, 0x00, 0x9B, 0x9B, 0x07, ++ 0x00, 0xF1, 0x94, 0x81, 0x00, 0x9B, 0xD8, 0x07, 0x40, 0xF1, 0x90, 0x81, ++ 0x64, 0x2A, 0x00, 0xF0, 0x32, 0x82, 0x5B, 0xF8, 0x04, 0x1B, 0x58, 0x3A, ++ 0x89, 0xB2, 0x20, 0x2A, 0x00, 0xF2, 0x24, 0x82, 0xDF, 0xE8, 0x12, 0xF0, ++ 0x5A, 0x02, 0x22, 0x02, 0x22, 0x02, 0x22, 0x02, 0x22, 0x02, 0x22, 0x02, ++ 0x22, 0x02, 0x22, 0x02, 0x22, 0x02, 0x22, 0x02, 0x4E, 0x02, 0x22, 0x02, ++ 0x72, 0x00, 0x22, 0x02, 0x22, 0x02, 0x22, 0x02, 0x22, 0x02, 0x22, 0x02, ++ 0x22, 0x02, 0x22, 0x02, 0x22, 0x02, 0x22, 0x02, 0x22, 0x02, 0x22, 0x02, ++ 0x36, 0x02, 0x22, 0x02, 0x22, 0x02, 0x22, 0x02, 0x22, 0x02, 0x72, 0x00, ++ 0x22, 0x02, 0x22, 0x02, 0x69, 0x02, 0x02, 0x9B, 0x59, 0x1E, 0x5B, 0xF8, ++ 0x04, 0x3B, 0x8D, 0xF8, 0x10, 0x30, 0x00, 0x9B, 0x04, 0xAA, 0x03, 0xF0, ++ 0x40, 0x00, 0x01, 0x23, 0x00, 0x28, 0x70, 0xD1, 0x00, 0x98, 0x80, 0x06, ++ 0x40, 0xF1, 0x15, 0x81, 0x00, 0x2B, 0x00, 0xF0, 0xEA, 0x81, 0x10, 0x46, ++ 0x02, 0xEB, 0x03, 0x09, 0xA4, 0xEB, 0x02, 0x0E, 0x09, 0xE0, 0xE0, 0x45, ++ 0x04, 0xD8, 0x07, 0x78, 0x02, 0xF8, 0x01, 0x7B, 0x01, 0x3E, 0x17, 0x46, ++ 0x01, 0x30, 0x48, 0x45, 0x07, 0xD0, 0x00, 0xEB, 0x0E, 0x0C, 0x3A, 0x46, ++ 0x00, 0x2E, 0xF0, 0xD1, 0x01, 0x30, 0x48, 0x45, 0xF4, 0xD1, 0x23, 0x44, ++ 0x00, 0x29, 0x40, 0xF3, 0xCA, 0x81, 0xCC, 0x18, 0x20, 0x21, 0x08, 0xE0, ++ 0x98, 0x45, 0x03, 0xD8, 0x02, 0xF8, 0x01, 0x1B, 0x01, 0x3E, 0x17, 0x46, ++ 0x01, 0x33, 0xA3, 0x42, 0x05, 0xD0, 0x3A, 0x46, 0x00, 0x2E, 0xF3, 0xD1, ++ 0x01, 0x33, 0xA3, 0x42, 0xF6, 0xD1, 0x4F, 0xF0, 0x07, 0x0A, 0xB2, 0xE6, ++ 0x00, 0x9B, 0x99, 0x07, 0x03, 0xD4, 0x00, 0x9B, 0xDA, 0x07, 0x00, 0xF1, ++ 0xBC, 0x81, 0x5B, 0xF8, 0x04, 0x1B, 0x00, 0x29, 0xC0, 0xF2, 0xBE, 0x81, ++ 0xDF, 0xF8, 0x5C, 0xA4, 0x00, 0x23, 0x0D, 0xF1, 0x50, 0x0E, 0xAA, 0xFB, ++ 0x01, 0x2C, 0x4F, 0xEA, 0xDC, 0x0C, 0x0C, 0xEB, 0x8C, 0x00, 0xA1, 0xEB, ++ 0x40, 0x00, 0x89, 0x46, 0x30, 0x30, 0xB9, 0xF1, 0x09, 0x0F, 0x72, 0x46, ++ 0x61, 0x46, 0x0E, 0xF8, 0x01, 0x0D, 0x18, 0x46, 0x03, 0xF1, 0x01, 0x03, ++ 0xEB, 0xD8, 0x00, 0x99, 0x09, 0x06, 0x00, 0xF1, 0x9E, 0x81, 0x00, 0x99, ++ 0x09, 0x07, 0x40, 0xF1, 0xE7, 0x81, 0x83, 0x1C, 0x2B, 0x20, 0x0E, 0xF8, ++ 0x01, 0x0C, 0x00, 0x98, 0x02, 0x99, 0x00, 0xF0, 0x40, 0x00, 0x02, 0x3A, ++ 0xC9, 0x1A, 0x00, 0x28, 0x8E, 0xD0, 0x00, 0x29, 0x14, 0xDD, 0x0C, 0x44, ++ 0x4F, 0xF0, 0x30, 0x0E, 0x08, 0xE0, 0xE0, 0x45, 0x03, 0xD8, 0x00, 0xF8, ++ 0x01, 0xEB, 0x01, 0x3E, 0x07, 0x46, 0x01, 0x39, 0x00, 0xF0, 0xB0, 0x80, ++ 0xA4, 0xEB, 0x01, 0x0C, 0x38, 0x46, 0x00, 0x2E, 0xF1, 0xD1, 0x01, 0x39, ++ 0xF5, 0xD1, 0x00, 0x21, 0x00, 0x2B, 0x7F, 0xF4, 0x7C, 0xAF, 0x91, 0x46, ++ 0xA7, 0xE7, 0x5B, 0xF8, 0x04, 0x2B, 0x00, 0x2A, 0x40, 0xF0, 0x2C, 0x81, ++ 0x00, 0x9B, 0x02, 0x99, 0x03, 0xF0, 0x40, 0x00, 0x00, 0x23, 0x65, 0xE7, ++ 0x4A, 0x46, 0xF7, 0xE7, 0x5B, 0xF8, 0x04, 0x3B, 0x02, 0x9A, 0xDF, 0xF8, ++ 0xB0, 0xE3, 0x9C, 0x46, 0x1C, 0xF8, 0x01, 0x3B, 0x00, 0x2A, 0x00, 0xF0, ++ 0x09, 0x81, 0x19, 0x11, 0x15, 0x2A, 0x03, 0xF0, 0x0F, 0x03, 0x1E, 0xF8, ++ 0x01, 0x10, 0x1E, 0xF8, 0x03, 0x30, 0x8D, 0xF8, 0x10, 0x10, 0x28, 0xBF, ++ 0x15, 0x22, 0x02, 0xEB, 0x42, 0x01, 0x01, 0x3A, 0x8D, 0xF8, 0x11, 0x30, ++ 0x01, 0xF1, 0xFF, 0x33, 0xC1, 0xF1, 0x01, 0x01, 0x1D, 0xD0, 0x0C, 0xEB, ++ 0x02, 0x0A, 0x0D, 0xF1, 0x13, 0x02, 0x1C, 0xF0, 0x03, 0x0F, 0x1C, 0xF8, ++ 0x01, 0x0B, 0x4F, 0xEA, 0x20, 0x19, 0x00, 0xF0, 0x0F, 0x00, 0x1E, 0xF8, ++ 0x09, 0x90, 0x82, 0xF8, 0x00, 0x90, 0x1E, 0xF8, 0x00, 0x00, 0x50, 0x70, ++ 0x0C, 0xBF, 0x4F, 0xF0, 0x3A, 0x09, 0x4F, 0xF0, 0x2E, 0x09, 0xE2, 0x45, ++ 0x02, 0xF8, 0x01, 0x9C, 0x02, 0xF1, 0x03, 0x02, 0xE5, 0xD1, 0x00, 0x9A, ++ 0x02, 0xF0, 0x40, 0x02, 0x00, 0x2A, 0x40, 0xF0, 0x69, 0x81, 0x00, 0x98, ++ 0x02, 0x92, 0x80, 0x06, 0x04, 0xAA, 0x3F, 0xF5, 0x1F, 0xAF, 0x00, 0x2B, ++ 0x7F, 0xF4, 0x1F, 0xAF, 0xA1, 0xE7, 0x5B, 0xF8, 0x04, 0x1B, 0xDF, 0xF8, ++ 0x14, 0xE3, 0x8C, 0x46, 0x4F, 0xF0, 0x3A, 0x09, 0x1C, 0xF8, 0x06, 0x3B, ++ 0x1A, 0x11, 0x03, 0xF0, 0x0F, 0x03, 0x1E, 0xF8, 0x02, 0x20, 0x1E, 0xF8, ++ 0x03, 0x30, 0x8D, 0xF8, 0x11, 0x30, 0x8D, 0xF8, 0x10, 0x20, 0x01, 0x31, ++ 0x04, 0xAB, 0x11, 0xF8, 0x01, 0x2B, 0x83, 0xF8, 0x02, 0x90, 0x10, 0x11, ++ 0x02, 0xF0, 0x0F, 0x02, 0x1E, 0xF8, 0x00, 0x00, 0x1E, 0xF8, 0x02, 0x20, ++ 0xD8, 0x70, 0x8C, 0x45, 0x1A, 0x71, 0x03, 0xF1, 0x03, 0x03, 0xEE, 0xD1, ++ 0x02, 0x9B, 0xA3, 0xF1, 0x11, 0x01, 0x00, 0x9B, 0x04, 0xAA, 0x03, 0xF0, ++ 0x40, 0x00, 0x11, 0x23, 0xE4, 0xE6, 0x00, 0x29, 0x7F, 0xF7, 0x6C, 0xAF, ++ 0x21, 0x44, 0x4F, 0xF0, 0x20, 0x0C, 0x08, 0xE0, 0xA0, 0x45, 0x03, 0xD8, ++ 0x00, 0xF8, 0x01, 0xCB, 0x01, 0x3E, 0x07, 0x46, 0x01, 0x34, 0xA1, 0x42, ++ 0x05, 0xD0, 0x38, 0x46, 0x00, 0x2E, 0xF3, 0xD1, 0x01, 0x34, 0xA1, 0x42, ++ 0xF6, 0xD1, 0x0C, 0x46, 0x00, 0x21, 0x00, 0x2B, 0x7F, 0xF4, 0xD3, 0xAE, ++ 0x55, 0xE7, 0x04, 0x23, 0x9A, 0x49, 0x01, 0xEB, 0xCA, 0x0A, 0x1A, 0xF8, ++ 0x03, 0xA0, 0xBA, 0xF1, 0x07, 0x0F, 0x00, 0xF2, 0x1F, 0x81, 0x01, 0xA3, ++ 0x53, 0xF8, 0x2A, 0xF0, 0x8F, 0x3F, 0x14, 0x00, 0x5B, 0x3F, 0x14, 0x00, ++ 0xC9, 0x40, 0x14, 0x00, 0xD9, 0x3F, 0x14, 0x00, 0x85, 0x3F, 0x14, 0x00, ++ 0xC1, 0x3F, 0x14, 0x00, 0xA5, 0x3F, 0x14, 0x00, 0xB1, 0x3E, 0x14, 0x00, ++ 0x01, 0x23, 0xE1, 0xE7, 0x02, 0x21, 0x26, 0xE5, 0x58, 0x3A, 0x5B, 0xF8, ++ 0x04, 0x1B, 0x20, 0x2A, 0x00, 0xF2, 0x98, 0x80, 0x01, 0xA3, 0x53, 0xF8, ++ 0x22, 0xF0, 0x00, 0xBF, 0xED, 0x45, 0x14, 0x00, 0x7D, 0x45, 0x14, 0x00, ++ 0x7D, 0x45, 0x14, 0x00, 0x7D, 0x45, 0x14, 0x00, 0x7D, 0x45, 0x14, 0x00, ++ 0x7D, 0x45, 0x14, 0x00, 0x7D, 0x45, 0x14, 0x00, 0x7D, 0x45, 0x14, 0x00, ++ 0x7D, 0x45, 0x14, 0x00, 0x7D, 0x45, 0x14, 0x00, 0xD5, 0x45, 0x14, 0x00, ++ 0x7D, 0x45, 0x14, 0x00, 0x17, 0x42, 0x14, 0x00, 0x7D, 0x45, 0x14, 0x00, ++ 0x7D, 0x45, 0x14, 0x00, 0x7D, 0x45, 0x14, 0x00, 0x7D, 0x45, 0x14, 0x00, ++ 0x7D, 0x45, 0x14, 0x00, 0x7D, 0x45, 0x14, 0x00, 0x7D, 0x45, 0x14, 0x00, ++ 0x7D, 0x45, 0x14, 0x00, 0x7D, 0x45, 0x14, 0x00, 0x7D, 0x45, 0x14, 0x00, ++ 0x7D, 0x45, 0x14, 0x00, 0xA5, 0x45, 0x14, 0x00, 0x7D, 0x45, 0x14, 0x00, ++ 0x7D, 0x45, 0x14, 0x00, 0x7D, 0x45, 0x14, 0x00, 0x7D, 0x45, 0x14, 0x00, ++ 0x1D, 0x42, 0x14, 0x00, 0x7D, 0x45, 0x14, 0x00, 0x7D, 0x45, 0x14, 0x00, ++ 0x0B, 0x46, 0x14, 0x00, 0x03, 0x9E, 0x14, 0x46, 0x4A, 0xE5, 0x64, 0x49, ++ 0x64, 0x48, 0x4F, 0xF4, 0xA2, 0x72, 0x00, 0xF0, 0x49, 0xFB, 0x4F, 0xF0, ++ 0x06, 0x0A, 0x3C, 0xE5, 0x1A, 0x11, 0x03, 0xF0, 0x0F, 0x03, 0x1E, 0xF8, ++ 0x02, 0x20, 0x1E, 0xF8, 0x03, 0x30, 0x8D, 0xF8, 0x10, 0x20, 0x8D, 0xF8, ++ 0x11, 0x30, 0x6F, 0xF0, 0x2E, 0x01, 0x2F, 0x23, 0x0F, 0x22, 0xFC, 0xE6, ++ 0x13, 0x78, 0x00, 0x2B, 0x00, 0xF0, 0x97, 0x80, 0x01, 0x9B, 0x00, 0x2B, ++ 0x3F, 0xF4, 0xCC, 0xAE, 0x01, 0x9B, 0x11, 0x46, 0xC2, 0xF1, 0x01, 0x00, ++ 0x00, 0x2B, 0x00, 0xEB, 0x01, 0x0C, 0x0F, 0xDD, 0x11, 0xF8, 0x01, 0xEF, ++ 0x01, 0x3B, 0xBE, 0xF1, 0x00, 0x0F, 0x10, 0xD0, 0x00, 0x2B, 0xF3, 0xD1, ++ 0x02, 0x99, 0x00, 0x98, 0x01, 0x93, 0x63, 0x46, 0xC9, 0x1A, 0x00, 0xF0, ++ 0x40, 0x00, 0x1F, 0xE6, 0x00, 0xEB, 0x01, 0x0C, 0x11, 0xF8, 0x01, 0xEF, ++ 0xBE, 0xF1, 0x00, 0x0F, 0xE4, 0xD1, 0x01, 0x93, 0x63, 0x46, 0x02, 0x99, ++ 0x00, 0x98, 0xC9, 0x1A, 0x00, 0xF0, 0x40, 0x00, 0x10, 0xE6, 0x1C, 0x46, ++ 0x4F, 0xF0, 0x07, 0x0A, 0xF9, 0xE4, 0x23, 0x46, 0x91, 0x46, 0x2B, 0xE6, ++ 0x00, 0x9B, 0x02, 0x99, 0x03, 0xF0, 0x40, 0x00, 0x14, 0xAA, 0x00, 0x23, ++ 0x02, 0xE6, 0x5B, 0xF8, 0x04, 0x1B, 0x09, 0xB2, 0x41, 0xE6, 0x83, 0x1C, ++ 0x2D, 0x20, 0x64, 0xE6, 0x00, 0x9B, 0x43, 0xF0, 0x80, 0x03, 0x49, 0x42, ++ 0x00, 0x93, 0x3B, 0xE6, 0x00, 0x9B, 0x43, 0xF0, 0x40, 0x03, 0x00, 0x93, ++ 0x08, 0x23, 0x40, 0x20, 0x02, 0x93, 0xDF, 0xF8, 0xD0, 0xC0, 0x14, 0xAA, ++ 0x01, 0xF0, 0x0F, 0x03, 0x09, 0x09, 0x1C, 0xF8, 0x03, 0x30, 0x02, 0xF8, ++ 0x01, 0x3D, 0x14, 0xAB, 0xA3, 0xEB, 0x02, 0x03, 0xF4, 0xD1, 0x02, 0x99, ++ 0xC9, 0x1A, 0xDD, 0xE5, 0x14, 0xAA, 0x01, 0xF0, 0x01, 0x03, 0x30, 0x33, ++ 0x02, 0xF8, 0x01, 0x3D, 0x49, 0x08, 0x14, 0xAB, 0xA3, 0xEB, 0x02, 0x03, ++ 0xF5, 0xD1, 0xBA, 0xE7, 0xDF, 0xF8, 0x90, 0xE0, 0x14, 0xAA, 0x01, 0xF0, ++ 0x0F, 0x03, 0x09, 0x09, 0x1E, 0xF8, 0x03, 0x30, 0x02, 0xF8, 0x01, 0x3D, ++ 0x14, 0xAB, 0xA3, 0xEB, 0x02, 0x03, 0xF4, 0xD1, 0xAB, 0xE7, 0x00, 0x9B, ++ 0x03, 0xF0, 0x40, 0x00, 0xCF, 0xE7, 0x17, 0x49, 0x17, 0x48, 0x40, 0xF2, ++ 0x11, 0x12, 0x00, 0xF0, 0xAF, 0xFA, 0x4F, 0xF0, 0x02, 0x0A, 0xA2, 0xE4, ++ 0x00, 0x22, 0x02, 0x92, 0x04, 0xAA, 0xBA, 0xE5, 0x00, 0x99, 0xC9, 0x06, ++ 0x06, 0xD4, 0x02, 0x98, 0xC1, 0x1A, 0x00, 0x98, 0x72, 0x46, 0x00, 0xF0, ++ 0x40, 0x00, 0xA7, 0xE5, 0x83, 0x1C, 0x20, 0x20, 0x0D, 0xE6, 0x00, 0x99, ++ 0x01, 0xF0, 0x40, 0x00, 0x02, 0x99, 0x9F, 0xE5, 0x09, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xBF, 0xF6, 0x86, 0xAC, 0x04, 0x49, ++ 0x04, 0x48, 0x4F, 0xF4, 0x12, 0x72, 0x00, 0xF0, 0x89, 0xFA, 0x7E, 0xE4, ++ 0x24, 0xB3, 0x15, 0x00, 0x70, 0x79, 0x15, 0x00, 0x64, 0x7D, 0x15, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0xCD, 0xCC, 0xCC, 0xCC, 0x10, 0xB3, 0x15, 0x00, ++ 0xFC, 0xB2, 0x15, 0x00, 0x0F, 0xB4, 0x2D, 0xE9, 0xF0, 0x47, 0x21, 0x4E, ++ 0xD6, 0xF8, 0x04, 0x31, 0x82, 0xB0, 0xFB, 0xB1, 0x0A, 0x9C, 0xDF, 0xF8, ++ 0x80, 0x80, 0xDF, 0xF8, 0x80, 0xA0, 0xDF, 0xF8, 0x80, 0x90, 0xA7, 0x1C, ++ 0x20, 0x46, 0x14, 0xF8, 0x01, 0x5B, 0x29, 0x06, 0xA5, 0xF1, 0x80, 0x02, ++ 0x0A, 0xD5, 0x88, 0x2D, 0x13, 0xD8, 0xD6, 0xF8, 0x00, 0x31, 0xDB, 0x43, ++ 0xD3, 0x40, 0xDB, 0x07, 0x08, 0xD4, 0xA7, 0x42, 0x20, 0x46, 0xED, 0xD1, ++ 0x12, 0x4B, 0x0B, 0xA9, 0xD3, 0xF8, 0x30, 0x34, 0x01, 0x91, 0x98, 0x47, ++ 0x02, 0xB0, 0xBD, 0xE8, 0xF0, 0x47, 0x04, 0xB0, 0x70, 0x47, 0xD8, 0xF8, ++ 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x20, 0x05, 0xF1, 0x66, 0x03, 0x00, 0x2A, ++ 0xDB, 0xB2, 0x05, 0xDB, 0xD6, 0xF8, 0x04, 0x31, 0x9A, 0x3D, 0xAB, 0x42, ++ 0xE3, 0xD8, 0xEB, 0xE7, 0x05, 0x2B, 0xF7, 0xD9, 0x40, 0xF2, 0xA9, 0x22, ++ 0x51, 0x46, 0x48, 0x46, 0x00, 0xF0, 0x36, 0xFA, 0xF0, 0xE7, 0x00, 0xBF, ++ 0xB0, 0xB6, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xCC, 0xB2, 0x15, 0x00, 0x0E, 0xB4, 0x09, 0x4B, ++ 0x00, 0xB5, 0x1B, 0x68, 0x1B, 0x88, 0x18, 0x42, 0x82, 0xB0, 0x06, 0xD0, ++ 0x06, 0x4B, 0x03, 0x98, 0xD3, 0xF8, 0x30, 0x34, 0x04, 0xA9, 0x01, 0x91, ++ 0x98, 0x47, 0x02, 0xB0, 0x5D, 0xF8, 0x04, 0xEB, 0x03, 0xB0, 0x70, 0x47, ++ 0x38, 0x36, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x08, 0xB5, 0x05, 0x48, ++ 0xFF, 0xF7, 0x94, 0xFF, 0x01, 0x21, 0x40, 0xF2, 0x1F, 0x40, 0xFE, 0xF7, ++ 0x35, 0xF8, 0xE0, 0xF7, 0x0F, 0xFC, 0xFE, 0xE7, 0x64, 0xB3, 0x15, 0x00, ++ 0x08, 0xB5, 0x05, 0x48, 0xFF, 0xF7, 0x86, 0xFF, 0x01, 0x21, 0x40, 0xF2, ++ 0x1E, 0x40, 0xFE, 0xF7, 0x27, 0xF8, 0xE0, 0xF7, 0x01, 0xFC, 0xFE, 0xE7, ++ 0x7C, 0xB3, 0x15, 0x00, 0x30, 0xB5, 0x17, 0x48, 0x00, 0x68, 0x00, 0x78, ++ 0x02, 0x28, 0x83, 0xB0, 0x1D, 0x46, 0x06, 0xD1, 0x48, 0x78, 0x83, 0x1E, ++ 0x01, 0x2B, 0x0C, 0x46, 0x0E, 0xD9, 0x05, 0x28, 0x0C, 0xD0, 0x11, 0x48, ++ 0x01, 0x92, 0xFF, 0xF7, 0x69, 0xFF, 0x01, 0x9A, 0x29, 0x46, 0x40, 0xF2, ++ 0x1C, 0x40, 0xFE, 0xF7, 0x63, 0xF9, 0x00, 0x20, 0x03, 0xB0, 0x30, 0xBD, ++ 0x23, 0x78, 0x53, 0xB9, 0xA3, 0x78, 0x01, 0x92, 0x1B, 0xB1, 0xE1, 0xF7, ++ 0x17, 0xFE, 0x01, 0x9A, 0xEE, 0xE7, 0xE1, 0xF7, 0x1D, 0xFE, 0x01, 0x9A, ++ 0xEA, 0xE7, 0x01, 0x21, 0x01, 0x92, 0xE1, 0xF7, 0xE1, 0xFD, 0x60, 0x78, ++ 0x01, 0x9A, 0xED, 0xE7, 0x78, 0x36, 0x17, 0x00, 0x88, 0xB3, 0x15, 0x00, ++ 0x30, 0xB5, 0x83, 0xB0, 0x0C, 0x46, 0x09, 0x48, 0x09, 0x68, 0x01, 0x92, ++ 0x1D, 0x46, 0xFF, 0xF7, 0x3F, 0xFF, 0x07, 0x4B, 0x21, 0x68, 0xC3, 0xF8, ++ 0x04, 0x11, 0x01, 0x9A, 0x29, 0x46, 0x40, 0xF2, 0x07, 0x40, 0xFE, 0xF7, ++ 0x35, 0xF9, 0x00, 0x20, 0x03, 0xB0, 0x30, 0xBD, 0xA0, 0xB3, 0x15, 0x00, ++ 0xB0, 0xB6, 0x17, 0x00, 0x30, 0xB5, 0x83, 0xB0, 0x0C, 0x46, 0x09, 0x48, ++ 0x09, 0x68, 0x01, 0x92, 0x1D, 0x46, 0xFF, 0xF7, 0x25, 0xFF, 0x07, 0x4B, ++ 0x21, 0x68, 0xC3, 0xF8, 0x00, 0x11, 0x01, 0x9A, 0x29, 0x46, 0x40, 0xF2, ++ 0x05, 0x40, 0xFE, 0xF7, 0x1B, 0xF9, 0x00, 0x20, 0x03, 0xB0, 0x30, 0xBD, ++ 0xC8, 0xB3, 0x15, 0x00, 0xB0, 0xB6, 0x17, 0x00, 0x18, 0x46, 0x38, 0xB5, ++ 0x0D, 0x46, 0x04, 0x23, 0x01, 0x46, 0x4F, 0xF4, 0x82, 0x60, 0xFE, 0xF7, ++ 0xA3, 0xF8, 0x22, 0x4B, 0xA9, 0x88, 0x93, 0xF8, 0xA9, 0x30, 0x04, 0x46, ++ 0xEB, 0xB1, 0x4B, 0x1E, 0x01, 0x2B, 0x0D, 0xD9, 0x02, 0x29, 0x2A, 0xD0, ++ 0x03, 0x29, 0x2F, 0xD0, 0x04, 0x29, 0x1C, 0xD1, 0x1B, 0x4B, 0x2A, 0x68, ++ 0xDA, 0x65, 0x4F, 0xF0, 0x80, 0x72, 0xC3, 0xF8, 0x34, 0x21, 0x14, 0xE0, ++ 0x18, 0x48, 0x17, 0x4A, 0x03, 0x68, 0x43, 0xF0, 0x00, 0x73, 0x03, 0x60, ++ 0x53, 0x6F, 0x16, 0x48, 0x43, 0xF0, 0x10, 0x03, 0x53, 0x67, 0x01, 0x23, ++ 0x03, 0x70, 0x01, 0x29, 0xE2, 0xD1, 0x10, 0x4B, 0x2A, 0x68, 0xDA, 0x63, ++ 0x40, 0x22, 0xC3, 0xF8, 0x24, 0x21, 0x00, 0x25, 0x0F, 0x48, 0x25, 0x60, ++ 0xFF, 0xF7, 0xDA, 0xFE, 0x20, 0x46, 0xFE, 0xF7, 0x9F, 0xF8, 0x28, 0x46, ++ 0x38, 0xBD, 0x08, 0x4B, 0x2A, 0x68, 0x9A, 0x65, 0x20, 0x22, 0xC3, 0xF8, ++ 0x24, 0x21, 0xEE, 0xE7, 0x04, 0x4B, 0x2A, 0x68, 0x1A, 0x64, 0x80, 0x22, ++ 0xC3, 0xF8, 0x24, 0x21, 0xE7, 0xE7, 0x00, 0xBF, 0x2C, 0x19, 0x17, 0x00, ++ 0x00, 0x00, 0x50, 0x40, 0xE0, 0x50, 0x34, 0x40, 0x4C, 0x36, 0x17, 0x00, ++ 0xF0, 0xB3, 0x15, 0x00, 0x30, 0xB5, 0x18, 0x46, 0x0C, 0x46, 0x08, 0x23, ++ 0x01, 0x46, 0x85, 0xB0, 0x40, 0xF2, 0x12, 0x40, 0xFE, 0xF7, 0x4A, 0xF8, ++ 0x18, 0x4B, 0x22, 0x68, 0x1B, 0x68, 0x1B, 0x78, 0x01, 0x3B, 0x01, 0x2B, ++ 0x05, 0x46, 0x19, 0xD9, 0x11, 0x68, 0xA3, 0x68, 0x60, 0x68, 0x4B, 0x40, ++ 0x03, 0x40, 0x4B, 0x40, 0x13, 0x60, 0x22, 0x68, 0x2A, 0x60, 0x11, 0x68, ++ 0xA3, 0x68, 0x69, 0x60, 0xCD, 0xE9, 0x01, 0x11, 0x00, 0x92, 0x61, 0x68, ++ 0x0D, 0x48, 0x1A, 0x46, 0xFF, 0xF7, 0x96, 0xFE, 0x28, 0x46, 0xFE, 0xF7, ++ 0x5B, 0xF8, 0x00, 0x20, 0x05, 0xB0, 0x30, 0xBD, 0x09, 0x4B, 0x9A, 0x42, ++ 0x07, 0xD1, 0xD4, 0xE9, 0x01, 0x03, 0x11, 0x68, 0x4B, 0x40, 0x03, 0x40, ++ 0x4B, 0x40, 0x13, 0x60, 0x22, 0x68, 0xA3, 0x68, 0xC5, 0xE9, 0x00, 0x23, ++ 0x19, 0x46, 0xE1, 0xE7, 0x78, 0x36, 0x17, 0x00, 0x04, 0xB4, 0x15, 0x00, ++ 0x58, 0x40, 0x34, 0x40, 0x10, 0xB5, 0x19, 0x46, 0x40, 0xF2, 0x0A, 0x40, ++ 0x0C, 0x23, 0xFE, 0xF7, 0x0B, 0xF8, 0x00, 0x24, 0xC0, 0xE9, 0x00, 0x44, ++ 0x84, 0x60, 0xFE, 0xF7, 0x35, 0xF8, 0x20, 0x46, 0x10, 0xBD, 0x00, 0xBF, ++ 0x30, 0xB5, 0x18, 0x46, 0x83, 0xB0, 0x08, 0x23, 0x0C, 0x46, 0x01, 0x46, ++ 0x40, 0xF2, 0x03, 0x40, 0xFD, 0xF7, 0xF8, 0xFF, 0x10, 0x4B, 0x1B, 0x68, ++ 0x1B, 0x78, 0x01, 0x3B, 0x01, 0x2B, 0x05, 0x46, 0x13, 0xD9, 0xD4, 0xE9, ++ 0x00, 0x32, 0x1A, 0x60, 0x23, 0x68, 0x03, 0x60, 0x19, 0x68, 0x62, 0x68, ++ 0x41, 0x60, 0xCD, 0xE9, 0x00, 0x11, 0x09, 0x48, 0x11, 0x46, 0xFF, 0xF7, ++ 0x4B, 0xFE, 0x28, 0x46, 0xFE, 0xF7, 0x10, 0xF8, 0x00, 0x20, 0x03, 0xB0, ++ 0x30, 0xBD, 0xD4, 0xE9, 0x00, 0x32, 0xC0, 0xE9, 0x00, 0x32, 0x11, 0x46, ++ 0xED, 0xE7, 0x00, 0xBF, 0x78, 0x36, 0x17, 0x00, 0x58, 0xB4, 0x15, 0x00, ++ 0x38, 0xB5, 0x0D, 0x46, 0x40, 0xF2, 0x01, 0x40, 0x19, 0x46, 0x08, 0x23, ++ 0xFD, 0xF7, 0xCA, 0xFF, 0x29, 0x68, 0x0B, 0x68, 0x04, 0x46, 0xC4, 0xE9, ++ 0x00, 0x13, 0x1A, 0x46, 0x03, 0x48, 0xFF, 0xF7, 0x29, 0xFE, 0x20, 0x46, ++ 0xFD, 0xF7, 0xEE, 0xFF, 0x00, 0x20, 0x38, 0xBD, 0x98, 0xB4, 0x15, 0x00, ++ 0x38, 0xB5, 0x0C, 0x46, 0x40, 0xF2, 0x0E, 0x40, 0x19, 0x46, 0x04, 0x23, ++ 0xFD, 0xF7, 0xB2, 0xFF, 0x61, 0x68, 0x02, 0x29, 0x05, 0x46, 0x20, 0xD9, ++ 0x03, 0x29, 0x11, 0xD0, 0x13, 0x48, 0xFF, 0xF7, 0x11, 0xFE, 0x4F, 0xF4, ++ 0xD2, 0x73, 0x0F, 0x20, 0x1B, 0x68, 0x98, 0x47, 0xC0, 0xB2, 0x28, 0x60, ++ 0x0F, 0x48, 0xFF, 0xF7, 0x07, 0xFE, 0x28, 0x46, 0xFD, 0xF7, 0xCC, 0xFF, ++ 0x00, 0x20, 0x38, 0xBD, 0x24, 0x68, 0x0C, 0x48, 0x21, 0x46, 0xFF, 0xF7, ++ 0xFD, 0xFD, 0x5C, 0xB1, 0xA2, 0x02, 0x01, 0x21, 0x40, 0xF2, 0x1E, 0x40, ++ 0xFD, 0xF7, 0xEC, 0xFD, 0xE3, 0xE7, 0x22, 0x68, 0x06, 0x48, 0xFF, 0xF7, ++ 0xF1, 0xFD, 0xDE, 0xE7, 0xE0, 0xF7, 0x70, 0xFA, 0xFE, 0xE7, 0x00, 0xBF, ++ 0xF4, 0xB4, 0x15, 0x00, 0x08, 0xB5, 0x15, 0x00, 0xE8, 0xB4, 0x15, 0x00, ++ 0xC8, 0xB4, 0x15, 0x00, 0x30, 0xB5, 0x40, 0xF2, 0x0C, 0x40, 0x83, 0xB0, ++ 0x0C, 0x46, 0x19, 0x46, 0x04, 0x23, 0xFD, 0xF7, 0x73, 0xFF, 0x05, 0x46, ++ 0x20, 0x68, 0x00, 0x23, 0x82, 0x07, 0x62, 0x68, 0x2B, 0x60, 0x1C, 0xBF, ++ 0xFF, 0x23, 0x2B, 0x60, 0x93, 0x07, 0x1C, 0xBF, 0x01, 0x23, 0x2B, 0x60, ++ 0x04, 0xF1, 0x08, 0x01, 0x12, 0xF0, 0xEA, 0xFA, 0xD4, 0xE9, 0x00, 0x12, ++ 0x28, 0x68, 0xA3, 0x68, 0x00, 0x90, 0x0A, 0x44, 0x04, 0x48, 0xFF, 0xF7, ++ 0xC1, 0xFD, 0x28, 0x46, 0xFD, 0xF7, 0x86, 0xFF, 0x00, 0x20, 0x03, 0xB0, ++ 0x30, 0xBD, 0x00, 0xBF, 0x1C, 0xB5, 0x15, 0x00, 0x70, 0xB5, 0x06, 0x46, ++ 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x11, 0x4B, ++ 0x01, 0x20, 0x18, 0x60, 0x10, 0x4C, 0x11, 0x48, 0x25, 0x68, 0x22, 0xF0, ++ 0x7F, 0x43, 0x01, 0x35, 0x0A, 0x46, 0x31, 0x46, 0x25, 0x60, 0xFF, 0xF7, ++ 0xA3, 0xFD, 0x0D, 0x4B, 0x1B, 0x68, 0x00, 0x2B, 0x05, 0xDB, 0xFC, 0xF7, ++ 0x41, 0xFF, 0x4F, 0xF0, 0x00, 0x40, 0xFE, 0xF7, 0x1D, 0xFB, 0x23, 0x68, ++ 0x33, 0xB1, 0x04, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x23, 0x60, 0x0B, 0xB9, ++ 0x02, 0xB1, 0x62, 0xB6, 0x70, 0xBD, 0x00, 0xBF, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x78, 0xB5, 0x15, 0x00, 0x80, 0xB6, 0x17, 0x00, ++ 0x70, 0xB5, 0x04, 0x46, 0x72, 0xB6, 0x07, 0x4D, 0x07, 0x48, 0x00, 0x26, ++ 0x22, 0xF0, 0x7F, 0x43, 0x2E, 0x60, 0x0A, 0x46, 0x21, 0x46, 0xFF, 0xF7, ++ 0x79, 0xFD, 0x04, 0x4B, 0x1B, 0x68, 0x00, 0x2B, 0xFD, 0xD1, 0x70, 0xBD, ++ 0x38, 0x00, 0x32, 0x40, 0x78, 0xB5, 0x15, 0x00, 0xD0, 0x22, 0x17, 0x00, ++ 0x10, 0xB4, 0x0C, 0x46, 0x22, 0xF0, 0x7F, 0x43, 0x01, 0x46, 0x22, 0x46, ++ 0x02, 0x48, 0x5D, 0xF8, 0x04, 0x4B, 0xFF, 0xF7, 0x63, 0xBD, 0x00, 0xBF, ++ 0x90, 0xB5, 0x15, 0x00, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, ++ 0x72, 0xB6, 0x07, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x06, 0x4B, 0x1A, 0x68, ++ 0x51, 0x1C, 0x19, 0x60, 0x29, 0xB1, 0x03, 0x49, 0x1A, 0x60, 0x0B, 0x68, ++ 0x0A, 0xB9, 0x03, 0xB1, 0x62, 0xB6, 0x70, 0x47, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x10, 0xB5, 0x06, 0x4C, 0x4F, 0xF4, 0x84, 0x72, ++ 0x20, 0x46, 0x00, 0x21, 0xDB, 0xF7, 0xD2, 0xFA, 0x4F, 0xF0, 0xFF, 0x32, ++ 0x02, 0x23, 0xC4, 0xE9, 0x40, 0x23, 0x10, 0xBD, 0xB0, 0xB6, 0x17, 0x00, ++ 0x08, 0xB5, 0x08, 0x22, 0x00, 0x21, 0x02, 0x48, 0xDB, 0xF7, 0xC4, 0xFA, ++ 0x00, 0x20, 0x08, 0xBD, 0xB8, 0xB7, 0x17, 0x00, 0xE0, 0xF7, 0xB4, 0xBC, ++ 0x01, 0x4B, 0xD3, 0xF8, 0x24, 0x31, 0x18, 0x47, 0x88, 0x1A, 0x17, 0x00, ++ 0x02, 0x20, 0x70, 0x47, 0xE0, 0xF7, 0xCC, 0xBB, 0x04, 0x4B, 0x1B, 0x68, ++ 0x1B, 0x78, 0x03, 0x2B, 0x01, 0xD0, 0x01, 0x20, 0x70, 0x47, 0xE0, 0xF7, ++ 0x5F, 0xBB, 0x00, 0xBF, 0x78, 0x36, 0x17, 0x00, 0xE0, 0xF7, 0x6E, 0xBB, ++ 0x70, 0xB5, 0x04, 0x68, 0x9C, 0xB1, 0x0A, 0x4E, 0x05, 0x46, 0x03, 0xE0, ++ 0xFE, 0xF7, 0x32, 0xFB, 0x2C, 0x68, 0x64, 0xB1, 0x28, 0x46, 0xFE, 0xF7, ++ 0x71, 0xFB, 0xE3, 0x68, 0x21, 0x46, 0x30, 0x46, 0x00, 0x2B, 0xF3, 0xD1, ++ 0xA2, 0x68, 0x2C, 0x68, 0x13, 0x81, 0x00, 0x2C, 0xF2, 0xD1, 0x70, 0xBD, ++ 0x24, 0x65, 0x17, 0x00, 0x38, 0xB5, 0x14, 0x4B, 0x1B, 0x68, 0x1B, 0x78, ++ 0x03, 0x2B, 0x00, 0xD0, 0x38, 0xBD, 0x04, 0x46, 0xE0, 0xF7, 0x80, 0xFB, ++ 0x05, 0x46, 0xB8, 0xB1, 0x4C, 0xF2, 0xDE, 0x03, 0xA3, 0x61, 0x21, 0x46, ++ 0x1C, 0x22, 0x12, 0xF0, 0x07, 0xFA, 0x0C, 0x4C, 0x23, 0x68, 0x00, 0x2B, ++ 0xFC, 0xD0, 0x0B, 0x4B, 0x18, 0x68, 0x29, 0x1F, 0x00, 0xF5, 0x07, 0x70, ++ 0xFE, 0xF7, 0x02, 0xFB, 0x01, 0x23, 0x23, 0x60, 0xBD, 0xE8, 0x38, 0x40, ++ 0xE0, 0xF7, 0x90, 0xBB, 0xBD, 0xE8, 0x38, 0x40, 0x04, 0x48, 0xFF, 0xF7, ++ 0xD1, 0xBC, 0x00, 0xBF, 0x78, 0x36, 0x17, 0x00, 0x58, 0x40, 0x04, 0x40, ++ 0x00, 0x38, 0x18, 0x00, 0xA8, 0xB5, 0x15, 0x00, 0x01, 0x4B, 0xD3, 0xF8, ++ 0x28, 0x31, 0x18, 0x47, 0x88, 0x1A, 0x17, 0x00, 0x38, 0xB5, 0x04, 0x46, ++ 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x10, 0x4B, ++ 0x01, 0x22, 0x1A, 0x60, 0x0F, 0x4D, 0x10, 0x48, 0x2B, 0x68, 0x01, 0x33, ++ 0x2B, 0x60, 0xFE, 0xF7, 0xD7, 0xFA, 0x05, 0x2C, 0x03, 0xD8, 0x0D, 0x4A, ++ 0x13, 0x5D, 0x01, 0x3B, 0x13, 0x55, 0x2B, 0x68, 0x33, 0xB1, 0x07, 0x4A, ++ 0x01, 0x3B, 0x12, 0x68, 0x2B, 0x60, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, ++ 0x07, 0x4A, 0xD2, 0xF8, 0xF8, 0x31, 0x01, 0x3B, 0xC2, 0xF8, 0xF8, 0x31, ++ 0x38, 0xBD, 0x00, 0xBF, 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x20, 0x58, 0x17, 0x00, 0x74, 0x28, 0x17, 0x00, 0x20, 0x62, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x41, 0x0C, 0x4C, 0xDF, 0xF8, 0x3C, 0x80, 0x0C, 0x4F, ++ 0x0C, 0x4E, 0x04, 0xF5, 0x7C, 0x75, 0x62, 0x69, 0x30, 0x46, 0x13, 0x46, ++ 0x3A, 0xB1, 0x12, 0x78, 0x21, 0x69, 0x20, 0x2A, 0x0C, 0xBF, 0x42, 0x46, ++ 0x3A, 0x46, 0xE1, 0xF7, 0xB1, 0xFA, 0x10, 0x34, 0xAC, 0x42, 0xF0, 0xD1, ++ 0x00, 0x20, 0xBD, 0xE8, 0xF0, 0x81, 0x00, 0xBF, 0x24, 0x30, 0x17, 0x00, ++ 0xC4, 0xB5, 0x15, 0x00, 0xC8, 0xB5, 0x15, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0xF8, 0xB5, 0x10, 0xF8, 0x01, 0x3C, 0x09, 0x2B, 0x00, 0xF1, 0xFF, 0x36, ++ 0x30, 0xD1, 0x1C, 0x4C, 0x23, 0x68, 0x99, 0x42, 0x0D, 0x46, 0x08, 0xDA, ++ 0x1A, 0x4F, 0x38, 0x46, 0x00, 0xF0, 0x64, 0xFD, 0x23, 0x68, 0x01, 0x3B, ++ 0xAB, 0x42, 0x23, 0x60, 0xF7, 0xDC, 0x17, 0x4D, 0xAE, 0x42, 0x19, 0xD9, ++ 0x16, 0x4F, 0x06, 0xE0, 0x23, 0x68, 0x01, 0x33, 0x23, 0x60, 0x00, 0xF0, ++ 0x53, 0xFD, 0xAE, 0x42, 0x10, 0xD0, 0x15, 0xF8, 0x01, 0x0B, 0x09, 0x28, ++ 0xF4, 0xD1, 0x20, 0x68, 0x00, 0xF0, 0x07, 0x00, 0x38, 0x44, 0x00, 0xF0, ++ 0x49, 0xFD, 0x23, 0x68, 0x23, 0xF0, 0x07, 0x03, 0x08, 0x33, 0xAE, 0x42, ++ 0x23, 0x60, 0xEE, 0xD1, 0x0A, 0x4A, 0x13, 0x68, 0x01, 0x3B, 0x30, 0x46, ++ 0x13, 0x60, 0xF8, 0xBD, 0x04, 0x48, 0x00, 0xF0, 0x39, 0xFD, 0x02, 0x4A, ++ 0x13, 0x68, 0x01, 0x3B, 0x13, 0x60, 0xF1, 0xE7, 0x24, 0x34, 0x17, 0x00, ++ 0x1C, 0xB8, 0x15, 0x00, 0x28, 0x34, 0x17, 0x00, 0x20, 0xB8, 0x15, 0x00, ++ 0x68, 0x34, 0x17, 0x00, 0x61, 0xB3, 0x2D, 0xE9, 0xF8, 0x43, 0xDF, 0xF8, ++ 0x64, 0x90, 0x16, 0x4F, 0xDF, 0xF8, 0x58, 0x80, 0x0E, 0x46, 0x45, 0x1E, ++ 0x00, 0x24, 0x08, 0xE0, 0x15, 0xF8, 0x01, 0x1F, 0x38, 0x46, 0xFF, 0xF7, ++ 0x11, 0xFC, 0x23, 0x07, 0x10, 0xD0, 0xB4, 0x42, 0x13, 0xD0, 0x14, 0xF0, ++ 0x07, 0x0F, 0x04, 0xF1, 0x01, 0x04, 0xF1, 0xD1, 0x48, 0x46, 0xFF, 0xF7, ++ 0x05, 0xFC, 0x15, 0xF8, 0x01, 0x1F, 0x38, 0x46, 0xFF, 0xF7, 0x00, 0xFC, ++ 0x23, 0x07, 0xEE, 0xD1, 0x40, 0x46, 0xFF, 0xF7, 0xFB, 0xFB, 0xB4, 0x42, ++ 0xEB, 0xD1, 0xBD, 0xE8, 0xF8, 0x43, 0x04, 0x48, 0xFF, 0xF7, 0xF4, 0xBB, ++ 0x02, 0x48, 0xFF, 0xF7, 0xF1, 0xBB, 0x00, 0xBF, 0xD8, 0xB5, 0x15, 0x00, ++ 0xB4, 0x79, 0x15, 0x00, 0xD4, 0xB5, 0x15, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0x87, 0xB0, 0x04, 0x93, 0x00, 0x29, 0x7E, 0xD0, 0x04, 0x2A, 0x14, 0x46, ++ 0x02, 0xD0, 0x53, 0x1E, 0x01, 0x2B, 0x78, 0xD8, 0x65, 0x42, 0x04, 0xFB, ++ 0x01, 0xF3, 0xDF, 0xF8, 0x8C, 0x91, 0x03, 0x93, 0x05, 0x40, 0x5C, 0x48, ++ 0x29, 0x46, 0xE1, 0xF7, 0x09, 0xFA, 0x03, 0x9A, 0x2B, 0x0E, 0x10, 0x2A, ++ 0x17, 0x46, 0x28, 0xBF, 0x10, 0x27, 0x01, 0x2B, 0x68, 0xD0, 0x2B, 0x0D, ++ 0xB3, 0xF5, 0xA0, 0x6F, 0x64, 0xD0, 0x00, 0x2A, 0x00, 0xF0, 0x9C, 0x80, ++ 0xDF, 0xF8, 0x60, 0x81, 0xDF, 0xF8, 0x60, 0xA1, 0x2E, 0x46, 0x4F, 0xF0, ++ 0x00, 0x0B, 0x0A, 0xE0, 0x02, 0x2C, 0x0A, 0xBF, 0x31, 0x88, 0x31, 0x78, ++ 0x50, 0x46, 0xA3, 0x44, 0xE1, 0xF7, 0xEA, 0xF9, 0x5F, 0x45, 0x26, 0x44, ++ 0x0A, 0xD9, 0x04, 0x2C, 0x40, 0x46, 0xF1, 0xD1, 0x31, 0x68, 0x48, 0x48, ++ 0xA3, 0x44, 0xE1, 0xF7, 0xDF, 0xF9, 0x5F, 0x45, 0x26, 0x44, 0xF4, 0xD8, ++ 0x04, 0x9B, 0xB3, 0xB3, 0x03, 0x9B, 0x0F, 0x2B, 0x7D, 0xD8, 0x4F, 0xF0, ++ 0x00, 0x08, 0xC7, 0xF1, 0x10, 0x03, 0x04, 0xF1, 0xFF, 0x3A, 0x05, 0x94, ++ 0xDF, 0xF8, 0x14, 0xB1, 0x44, 0x46, 0x98, 0x46, 0x04, 0xE0, 0x58, 0x46, ++ 0x00, 0xF0, 0x9A, 0xFC, 0xA0, 0x45, 0x0C, 0xD0, 0x1A, 0xEA, 0x04, 0x0F, ++ 0x04, 0xF1, 0x01, 0x04, 0xF5, 0xD1, 0x20, 0x20, 0x00, 0xF0, 0x8E, 0xFC, ++ 0x58, 0x46, 0x00, 0xF0, 0x8D, 0xFC, 0xA0, 0x45, 0xF2, 0xD1, 0x34, 0x48, ++ 0x05, 0x9C, 0x00, 0xF0, 0x87, 0xFC, 0x03, 0x9B, 0x00, 0x2B, 0x4D, 0xD0, ++ 0x4F, 0xF0, 0x00, 0x08, 0x15, 0xF8, 0x08, 0x00, 0xA0, 0xF1, 0x1F, 0x03, ++ 0x5F, 0x2B, 0x88, 0xBF, 0x2E, 0x20, 0x08, 0xF1, 0x01, 0x08, 0x00, 0xF0, ++ 0x75, 0xFC, 0x47, 0x45, 0xF2, 0xD8, 0x35, 0x46, 0x29, 0x48, 0x00, 0xF0, ++ 0x71, 0xFC, 0x03, 0x9B, 0xDB, 0x1B, 0x03, 0x93, 0x8D, 0xD1, 0x07, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x8F, 0x03, 0x9B, 0x8B, 0xB3, 0xDF, 0xF8, 0x84, 0xA0, ++ 0x4F, 0xF0, 0x00, 0x08, 0x09, 0xE0, 0xCD, 0xF8, 0x00, 0xC0, 0xE1, 0xF7, ++ 0x8D, 0xF9, 0x08, 0xF1, 0x04, 0x08, 0x47, 0x45, 0x05, 0xF1, 0x04, 0x05, ++ 0x1A, 0xD9, 0x28, 0x46, 0xDD, 0xF7, 0xEE, 0xF9, 0x04, 0x2C, 0x06, 0x46, ++ 0x4F, 0xEA, 0x10, 0x6C, 0xC0, 0xF3, 0x07, 0x43, 0xC0, 0xF3, 0x07, 0x22, ++ 0xC1, 0xB2, 0x48, 0x46, 0x0F, 0xD0, 0x02, 0x2C, 0xE5, 0xD1, 0x15, 0x48, ++ 0x32, 0x0C, 0xB1, 0xB2, 0x08, 0xF1, 0x04, 0x08, 0xE1, 0xF7, 0x70, 0xF9, ++ 0x47, 0x45, 0x05, 0xF1, 0x04, 0x05, 0xE4, 0xD8, 0x00, 0x23, 0x04, 0x93, ++ 0xC6, 0xE7, 0x31, 0x46, 0x50, 0x46, 0xE1, 0xF7, 0x65, 0xF9, 0xD6, 0xE7, ++ 0x0A, 0x48, 0x07, 0xB0, 0xBD, 0xE8, 0xF0, 0x4F, 0x00, 0xF0, 0x30, 0xBC, ++ 0x04, 0x9B, 0x00, 0x2B, 0xB8, 0xD0, 0x2E, 0x46, 0x81, 0xE7, 0x04, 0x48, ++ 0x00, 0xF0, 0x28, 0xFC, 0xA2, 0xE7, 0x00, 0xBF, 0xE0, 0xB5, 0x15, 0x00, ++ 0xB8, 0x89, 0x15, 0x00, 0x1C, 0xB6, 0x15, 0x00, 0xD0, 0x79, 0x15, 0x00, ++ 0xE8, 0xB5, 0x15, 0x00, 0xF4, 0xB5, 0x15, 0x00, 0x14, 0xB6, 0x15, 0x00, ++ 0x0C, 0xB6, 0x15, 0x00, 0xD4, 0xB5, 0x15, 0x00, 0x10, 0xB5, 0xEF, 0xF3, ++ 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x22, 0x4B, 0x01, 0x22, ++ 0x1A, 0x60, 0x22, 0x4C, 0x22, 0x48, 0x23, 0x68, 0x01, 0x33, 0x23, 0x60, ++ 0xFE, 0xF7, 0x1E, 0xF9, 0x20, 0x48, 0xFE, 0xF7, 0x1B, 0xF9, 0x20, 0x49, ++ 0x1D, 0x48, 0xFE, 0xF7, 0x1B, 0xF9, 0x1F, 0x49, 0x1B, 0x48, 0xFE, 0xF7, ++ 0x17, 0xF9, 0x1E, 0x49, 0x19, 0x48, 0xFE, 0xF7, 0x13, 0xF9, 0x1D, 0x49, ++ 0x17, 0x48, 0xFE, 0xF7, 0x0F, 0xF9, 0x23, 0x68, 0x33, 0xB1, 0x13, 0x4A, ++ 0x01, 0x3B, 0x12, 0x68, 0x23, 0x60, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, ++ 0x17, 0x4B, 0x18, 0x49, 0x18, 0x48, 0x01, 0x22, 0x00, 0xF0, 0xFC, 0xFB, ++ 0x17, 0x4B, 0x18, 0x49, 0x18, 0x48, 0x04, 0x22, 0x00, 0xF0, 0xF6, 0xFB, ++ 0x17, 0x4B, 0x18, 0x49, 0x18, 0x48, 0x03, 0x22, 0x00, 0xF0, 0xF0, 0xFB, ++ 0x17, 0x4B, 0x18, 0x49, 0x18, 0x48, 0x04, 0x22, 0x00, 0xF0, 0xEA, 0xFB, ++ 0xBD, 0xE8, 0x10, 0x40, 0x16, 0x4B, 0x17, 0x49, 0x17, 0x48, 0x02, 0x22, ++ 0x00, 0xF0, 0xE2, 0xBB, 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0xD8, 0xB8, 0x17, 0x00, 0xC0, 0xB7, 0x17, 0x00, 0xC8, 0xB7, 0x17, 0x00, ++ 0x0C, 0xB8, 0x17, 0x00, 0x50, 0xB8, 0x17, 0x00, 0x94, 0xB8, 0x17, 0x00, ++ 0x69, 0x4D, 0x14, 0x00, 0x24, 0xB6, 0x15, 0x00, 0x30, 0xB6, 0x15, 0x00, ++ 0x61, 0x56, 0x14, 0x00, 0x38, 0xB6, 0x15, 0x00, 0x7C, 0xAB, 0x15, 0x00, ++ 0x2D, 0x57, 0x14, 0x00, 0x4C, 0xB6, 0x15, 0x00, 0x58, 0xB6, 0x15, 0x00, ++ 0xED, 0x55, 0x14, 0x00, 0x5C, 0xB6, 0x15, 0x00, 0x68, 0xB6, 0x15, 0x00, ++ 0x99, 0x57, 0x14, 0x00, 0x6C, 0xB6, 0x15, 0x00, 0x7C, 0xB6, 0x15, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x41, 0x54, 0x4D, 0x55, 0x4E, 0x29, 0x68, 0x31, 0x60, ++ 0x17, 0x28, 0x04, 0x46, 0x10, 0xD8, 0x17, 0x28, 0x00, 0xF2, 0x8E, 0x80, ++ 0xDF, 0xE8, 0x00, 0xF0, 0x15, 0x8C, 0x8C, 0x71, 0x8C, 0x8C, 0x8C, 0x8C, ++ 0x48, 0x8C, 0x1A, 0x8C, 0x8C, 0x1A, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, ++ 0x8C, 0x55, 0x8C, 0x60, 0x7F, 0x28, 0x39, 0xD0, 0x49, 0x4F, 0x3B, 0x68, ++ 0x3D, 0x2B, 0x65, 0xDD, 0x07, 0x20, 0x00, 0xF0, 0x75, 0xFB, 0x4F, 0xF0, ++ 0xFF, 0x34, 0x20, 0x46, 0xBD, 0xE8, 0xF0, 0x81, 0x44, 0x4E, 0x45, 0x48, ++ 0x33, 0x68, 0xDF, 0xF8, 0x20, 0x81, 0x00, 0x22, 0x1A, 0x70, 0x00, 0xF0, ++ 0x69, 0xFB, 0x34, 0x68, 0xA4, 0xEB, 0x08, 0x04, 0x00, 0x2C, 0xEE, 0xDB, ++ 0x0F, 0xD1, 0x3F, 0x48, 0x00, 0xF0, 0x60, 0xFB, 0x00, 0x24, 0x3D, 0x48, ++ 0x12, 0xF0, 0x70, 0xF9, 0x38, 0x4B, 0x28, 0x60, 0x00, 0x22, 0xC6, 0xF8, ++ 0x00, 0x80, 0x1A, 0x60, 0x20, 0x46, 0xBD, 0xE8, 0xF0, 0x81, 0x38, 0x48, ++ 0xFE, 0xF7, 0xB2, 0xF8, 0x07, 0x46, 0x00, 0x28, 0x48, 0xD0, 0x41, 0x46, ++ 0x04, 0x30, 0x12, 0xF0, 0xED, 0xF8, 0x34, 0x48, 0x39, 0x46, 0xFE, 0xF7, ++ 0x63, 0xF8, 0xE4, 0xE7, 0x2C, 0x4B, 0x2D, 0x4E, 0x1B, 0x68, 0x30, 0x68, ++ 0x0B, 0xB1, 0xFF, 0xF7, 0xC9, 0xFD, 0x4F, 0xF0, 0xFF, 0x34, 0x30, 0x60, ++ 0x20, 0x46, 0xBD, 0xE8, 0xF0, 0x81, 0x27, 0x4A, 0x25, 0x4B, 0x2B, 0x49, ++ 0x11, 0x60, 0x4F, 0xF0, 0xFF, 0x34, 0x00, 0x22, 0x1A, 0x60, 0x20, 0x46, ++ 0xBD, 0xE8, 0xF0, 0x81, 0x20, 0x4F, 0x21, 0x4E, 0x3B, 0x68, 0x30, 0x68, ++ 0x0B, 0xB9, 0xAE, 0xE7, 0x29, 0x68, 0xFF, 0xF7, 0xAF, 0xFD, 0x3B, 0x68, ++ 0x30, 0x60, 0x00, 0x2B, 0xA7, 0xDD, 0x03, 0x78, 0x20, 0x2B, 0xF5, 0xD1, ++ 0xA3, 0xE7, 0xDF, 0xF8, 0x78, 0x80, 0x18, 0x4E, 0x00, 0x23, 0x88, 0xF8, ++ 0x00, 0x30, 0xB0, 0xE7, 0x01, 0x31, 0x20, 0x46, 0x31, 0x60, 0x00, 0xF0, ++ 0x0D, 0xFB, 0x13, 0x49, 0x0B, 0x68, 0x1C, 0x70, 0x3A, 0x68, 0x01, 0x33, ++ 0x01, 0x32, 0x0B, 0x60, 0x3A, 0x60, 0x4F, 0xF0, 0xFF, 0x34, 0x8E, 0xE7, ++ 0x13, 0x48, 0x00, 0xF0, 0x01, 0xFB, 0xA0, 0xE7, 0x0A, 0x4F, 0x3B, 0x68, ++ 0x3D, 0x2B, 0x81, 0xDC, 0x09, 0x28, 0xE5, 0xD1, 0x0F, 0x48, 0x01, 0xF0, ++ 0x07, 0x01, 0x08, 0x44, 0x00, 0xF0, 0xF4, 0xFA, 0x33, 0x68, 0x23, 0xF0, ++ 0x07, 0x03, 0x08, 0x33, 0x33, 0x60, 0xDE, 0xE7, 0x6C, 0x34, 0x17, 0x00, ++ 0x24, 0x34, 0x17, 0x00, 0x68, 0x34, 0x17, 0x00, 0xD4, 0x22, 0x17, 0x00, ++ 0xD0, 0x79, 0x15, 0x00, 0xA0, 0xB6, 0x15, 0x00, 0xD8, 0xB8, 0x17, 0x00, ++ 0xC0, 0xB7, 0x17, 0x00, 0x28, 0x34, 0x17, 0x00, 0x84, 0xB6, 0x15, 0x00, ++ 0x20, 0xB8, 0x15, 0x00, 0xF8, 0xB5, 0x0C, 0x4D, 0x2C, 0x68, 0x3F, 0x2C, ++ 0x0D, 0xD8, 0x0B, 0x4F, 0x4F, 0xEA, 0x04, 0x1C, 0x07, 0xEB, 0x04, 0x16, ++ 0x01, 0x34, 0x47, 0xF8, 0x0C, 0x00, 0xC6, 0xE9, 0x01, 0x12, 0xF3, 0x60, ++ 0x2C, 0x60, 0x00, 0x20, 0xF8, 0xBD, 0x05, 0x48, 0xE0, 0xF7, 0xF0, 0xFF, ++ 0x4F, 0xF0, 0xFF, 0x30, 0xF8, 0xBD, 0x00, 0xBF, 0x20, 0x30, 0x17, 0x00, ++ 0x24, 0x30, 0x17, 0x00, 0xA8, 0xB6, 0x15, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0x95, 0xB0, 0xEF, 0xF3, 0x10, 0x83, 0xDA, 0x07, 0x03, 0xD4, 0x72, 0xB6, ++ 0x76, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0xDF, 0xF8, 0xFC, 0xB1, 0x75, 0x48, ++ 0xDB, 0xF8, 0x00, 0x30, 0x01, 0x33, 0xCB, 0xF8, 0x00, 0x30, 0xFE, 0xF7, ++ 0x05, 0xF8, 0xDB, 0xF8, 0x00, 0x30, 0x06, 0x46, 0x3B, 0xB1, 0x6E, 0x4A, ++ 0x01, 0x3B, 0x12, 0x68, 0xCB, 0xF8, 0x00, 0x30, 0x0B, 0xB9, 0x02, 0xB1, ++ 0x62, 0xB6, 0x00, 0x2E, 0x00, 0xF0, 0x94, 0x80, 0x33, 0x1D, 0x03, 0xAC, ++ 0x01, 0x22, 0x4F, 0xF0, 0x00, 0x0C, 0x57, 0x1E, 0x3D, 0x46, 0x19, 0x46, ++ 0x13, 0xF8, 0x01, 0x0B, 0x20, 0x28, 0xFA, 0xD0, 0x09, 0x28, 0xF8, 0xD0, ++ 0x00, 0x28, 0x00, 0xF0, 0xA0, 0x80, 0x22, 0x28, 0x00, 0xF0, 0x83, 0x80, ++ 0x21, 0x60, 0x08, 0x78, 0x15, 0x46, 0x00, 0x28, 0x00, 0xF0, 0xAC, 0x80, ++ 0x0B, 0x46, 0x06, 0xE0, 0x09, 0x28, 0x06, 0xD0, 0x13, 0xF8, 0x01, 0x0F, ++ 0x00, 0x28, 0x00, 0xF0, 0xA3, 0x80, 0x20, 0x28, 0xF6, 0xD1, 0x19, 0x78, ++ 0x00, 0x29, 0x00, 0xF0, 0x9D, 0x80, 0x01, 0x32, 0x11, 0x2A, 0x03, 0xF8, ++ 0x01, 0xCB, 0x04, 0xF1, 0x04, 0x04, 0xD4, 0xD1, 0x52, 0x48, 0x10, 0x21, ++ 0xE0, 0xF7, 0x8E, 0xFF, 0x10, 0x25, 0xDD, 0xF8, 0x0C, 0x90, 0x2E, 0x21, ++ 0x48, 0x46, 0x11, 0xF0, 0x95, 0xFF, 0x00, 0x28, 0x00, 0xF0, 0x83, 0x80, ++ 0xA0, 0xEB, 0x09, 0x04, 0x4B, 0x4B, 0x1B, 0x68, 0x00, 0x2B, 0x28, 0xDD, ++ 0x4A, 0x4F, 0x01, 0x95, 0x4F, 0xF0, 0x00, 0x08, 0xC2, 0x46, 0x3D, 0x46, ++ 0x05, 0xE0, 0x46, 0x4B, 0x1A, 0x68, 0x92, 0x45, 0x07, 0xF1, 0x10, 0x07, ++ 0x16, 0xDA, 0x39, 0x68, 0x22, 0x46, 0x48, 0x46, 0x0A, 0xF1, 0x01, 0x0A, ++ 0x12, 0xF0, 0xBE, 0xF8, 0x00, 0x28, 0xF0, 0xD1, 0x38, 0x68, 0x12, 0xF0, ++ 0x4B, 0xF8, 0x84, 0x42, 0x43, 0xD0, 0x3C, 0x4B, 0x1A, 0x68, 0x92, 0x45, ++ 0x3D, 0x46, 0x08, 0xF1, 0x01, 0x08, 0x07, 0xF1, 0x10, 0x07, 0xE8, 0xDB, ++ 0xB8, 0xF1, 0x01, 0x0F, 0x2B, 0x46, 0x01, 0x9D, 0x37, 0xD0, 0x03, 0x99, ++ 0x36, 0x48, 0xE0, 0xF7, 0x51, 0xFF, 0x36, 0x48, 0x00, 0xF0, 0x20, 0xFA, ++ 0x35, 0x48, 0x00, 0xF0, 0x1D, 0xFA, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, ++ 0x03, 0xD4, 0x72, 0xB6, 0x2A, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0xDB, 0xF8, ++ 0x00, 0x30, 0x30, 0x48, 0x01, 0x33, 0x31, 0x46, 0xCB, 0xF8, 0x00, 0x30, ++ 0xFD, 0xF7, 0x2A, 0xFF, 0x25, 0x48, 0xFD, 0xF7, 0x6B, 0xFF, 0xDB, 0xF8, ++ 0x00, 0x30, 0x06, 0x46, 0x00, 0x2B, 0x7F, 0xF4, 0x64, 0xAF, 0x00, 0x2E, ++ 0x7F, 0xF4, 0x6C, 0xAF, 0x15, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x4B, 0x1C, ++ 0x23, 0x60, 0x49, 0x78, 0x15, 0x46, 0x19, 0xB9, 0x28, 0xE0, 0x13, 0xF8, ++ 0x01, 0x1F, 0x29, 0xB3, 0x22, 0x29, 0xFA, 0xD1, 0x81, 0xE7, 0x01, 0x9D, ++ 0x3B, 0x46, 0x9A, 0x68, 0xAA, 0x42, 0x24, 0xDB, 0xDB, 0x68, 0x00, 0x2B, ++ 0xC8, 0xD0, 0x28, 0x46, 0x03, 0xA9, 0x98, 0x47, 0x00, 0x28, 0xC3, 0xD0, ++ 0xBF, 0xE7, 0x14, 0xAB, 0x03, 0xEB, 0x87, 0x03, 0x43, 0xF8, 0x44, 0x0C, ++ 0x00, 0x2F, 0xB8, 0xD0, 0xDD, 0xF8, 0x0C, 0x90, 0x2E, 0x21, 0x48, 0x46, ++ 0x11, 0xF0, 0x12, 0xFF, 0x00, 0x28, 0x7F, 0xF4, 0x7D, 0xAF, 0x48, 0x46, ++ 0x11, 0xF0, 0xE4, 0xFF, 0x04, 0x46, 0x79, 0xE7, 0x14, 0xAB, 0x03, 0xEB, ++ 0x82, 0x02, 0x00, 0x23, 0x42, 0xF8, 0x44, 0x3C, 0x67, 0xE7, 0x59, 0x68, ++ 0x0A, 0x48, 0xE0, 0xF7, 0xF1, 0xFE, 0x9E, 0xE7, 0x38, 0x61, 0x17, 0x00, ++ 0xC0, 0xB7, 0x17, 0x00, 0xC4, 0xB6, 0x15, 0x00, 0x20, 0x30, 0x17, 0x00, ++ 0x24, 0x30, 0x17, 0x00, 0xE4, 0xB6, 0x15, 0x00, 0x08, 0xB7, 0x15, 0x00, ++ 0xA0, 0xB6, 0x15, 0x00, 0xD8, 0xB8, 0x17, 0x00, 0xFC, 0xB6, 0x15, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0xF0, 0xB4, 0x05, 0x78, 0x30, 0x2D, 0x2B, 0xD0, ++ 0x00, 0x2A, 0x08, 0xBF, 0x0A, 0x22, 0x2D, 0x2D, 0x32, 0xD0, 0x00, 0x27, ++ 0x00, 0x26, 0xA5, 0xF1, 0x30, 0x03, 0x5F, 0xFA, 0x83, 0xFC, 0x25, 0xF0, ++ 0x20, 0x04, 0xBC, 0xF1, 0x09, 0x0F, 0xA4, 0xF1, 0x41, 0x04, 0x12, 0xD9, ++ 0x05, 0x2C, 0x06, 0xD9, 0x07, 0xB1, 0x76, 0x42, 0x01, 0xB1, 0x08, 0x60, ++ 0x30, 0x46, 0xF0, 0xBC, 0x70, 0x47, 0xA5, 0xF1, 0x61, 0x04, 0xA5, 0xF1, ++ 0x20, 0x03, 0x19, 0x2C, 0xDB, 0xB2, 0x94, 0xBF, 0x37, 0x3B, 0xA5, 0xF1, ++ 0x37, 0x03, 0x93, 0x42, 0xEC, 0xD2, 0x10, 0xF8, 0x01, 0x5F, 0x02, 0xFB, ++ 0x06, 0x36, 0xDA, 0xE7, 0x45, 0x78, 0x78, 0x2D, 0x00, 0xF1, 0x01, 0x03, ++ 0x0A, 0xD0, 0x18, 0x46, 0x00, 0x2A, 0xCE, 0xD1, 0x2D, 0x2D, 0x4F, 0xF0, ++ 0x08, 0x02, 0xCC, 0xD1, 0x01, 0x27, 0x45, 0x78, 0x38, 0x44, 0xC9, 0xE7, ++ 0x84, 0x78, 0xA4, 0xF1, 0x30, 0x06, 0x09, 0x2E, 0x09, 0xD9, 0x24, 0xF0, ++ 0x20, 0x06, 0x41, 0x3E, 0x05, 0x2E, 0x04, 0xD9, 0x3A, 0xB9, 0x17, 0x46, ++ 0x18, 0x46, 0x08, 0x22, 0xBA, 0xE7, 0x02, 0x30, 0x25, 0x46, 0x10, 0x22, ++ 0xB3, 0xE7, 0x18, 0x46, 0xB3, 0xE7, 0x00, 0xBF, 0x38, 0xB5, 0x0A, 0x22, ++ 0x0C, 0x46, 0x05, 0x46, 0x48, 0x68, 0x00, 0x21, 0xFF, 0xF7, 0xA2, 0xFF, ++ 0xC0, 0xB1, 0x01, 0x28, 0x10, 0xD1, 0x02, 0x2D, 0x1C, 0xDD, 0x10, 0x22, ++ 0xA0, 0x68, 0x00, 0x21, 0xFF, 0xF7, 0x98, 0xFF, 0x0E, 0x4B, 0x1B, 0x68, ++ 0x01, 0x46, 0x19, 0x80, 0x0D, 0x48, 0x89, 0xB2, 0xFF, 0xF7, 0x34, 0xF8, ++ 0x00, 0x20, 0x38, 0xBD, 0x01, 0x46, 0x0B, 0x48, 0xFF, 0xF7, 0x2E, 0xF8, ++ 0x00, 0x20, 0x38, 0xBD, 0x06, 0x4B, 0x09, 0x48, 0x1B, 0x68, 0x19, 0x88, ++ 0xFF, 0xF7, 0x26, 0xF8, 0x00, 0x20, 0x38, 0xBD, 0x06, 0x48, 0xFF, 0xF7, ++ 0x21, 0xF8, 0x00, 0x20, 0x38, 0xBD, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, ++ 0x2C, 0xB7, 0x15, 0x00, 0x50, 0xB7, 0x15, 0x00, 0x18, 0xB7, 0x15, 0x00, ++ 0x40, 0xB7, 0x15, 0x00, 0x01, 0x28, 0xF8, 0xB5, 0x2A, 0xDD, 0x0D, 0x46, ++ 0x04, 0x46, 0x10, 0x22, 0x68, 0x68, 0x00, 0x21, 0xFF, 0xF7, 0x66, 0xFF, ++ 0x02, 0x2C, 0x06, 0x46, 0x0D, 0xD1, 0x03, 0x0E, 0x01, 0x2B, 0x22, 0xD0, ++ 0x03, 0x0D, 0xB3, 0xF5, 0xA0, 0x6F, 0x1E, 0xD0, 0x32, 0x68, 0x24, 0x48, ++ 0x31, 0x46, 0xFE, 0xF7, 0xFB, 0xFF, 0x00, 0x20, 0xF8, 0xBD, 0x00, 0x22, ++ 0xA8, 0x68, 0x11, 0x46, 0x00, 0xF0, 0x18, 0xF9, 0x03, 0x2C, 0x07, 0x46, ++ 0x19, 0xD1, 0x04, 0x20, 0x01, 0x2F, 0x1C, 0xD0, 0xC2, 0xB2, 0x39, 0x46, ++ 0x30, 0x46, 0x00, 0x23, 0xFF, 0xF7, 0xFE, 0xFB, 0x00, 0x20, 0xF8, 0xBD, ++ 0x18, 0x48, 0xFE, 0xF7, 0xE3, 0xFF, 0x01, 0x20, 0xF8, 0xBD, 0x30, 0x46, ++ 0xDC, 0xF7, 0x7E, 0xFE, 0x31, 0x46, 0x02, 0x46, 0x12, 0x48, 0xFE, 0xF7, ++ 0xD9, 0xFF, 0x00, 0x20, 0xF8, 0xBD, 0x00, 0x22, 0xE8, 0x68, 0x11, 0x46, ++ 0xFF, 0xF7, 0x2E, 0xFF, 0xE0, 0xE7, 0x33, 0x0E, 0x01, 0x2B, 0xEC, 0xD0, ++ 0x33, 0x0D, 0xB3, 0xF5, 0xA0, 0x6F, 0xE8, 0xD0, 0x01, 0x28, 0x06, 0xD1, ++ 0x32, 0x78, 0x0A, 0x48, 0x31, 0x46, 0xFE, 0xF7, 0xC3, 0xFF, 0x00, 0x20, ++ 0xF8, 0xBD, 0x02, 0x28, 0xBE, 0xD1, 0x32, 0x88, 0x06, 0x48, 0x92, 0xB2, ++ 0x31, 0x46, 0xFE, 0xF7, 0xB9, 0xFF, 0x00, 0x20, 0xF8, 0xBD, 0x00, 0xBF, ++ 0x7C, 0xB7, 0x15, 0x00, 0x64, 0xB7, 0x15, 0x00, 0x90, 0xB7, 0x15, 0x00, ++ 0xA4, 0xB7, 0x15, 0x00, 0x02, 0x28, 0x38, 0xB5, 0x21, 0xDD, 0x0D, 0x46, ++ 0x10, 0x22, 0x68, 0x68, 0x00, 0x21, 0xFF, 0xF7, 0x01, 0xFF, 0x10, 0x22, ++ 0x04, 0x46, 0x00, 0x21, 0xA8, 0x68, 0xFF, 0xF7, 0xFB, 0xFE, 0x21, 0x46, ++ 0x02, 0x46, 0x05, 0x46, 0x0F, 0x48, 0xFE, 0xF7, 0x99, 0xFF, 0x23, 0x0E, ++ 0x01, 0x2B, 0x06, 0xD0, 0x23, 0x0D, 0xB3, 0xF5, 0xA0, 0x6F, 0x0D, 0xD0, ++ 0x25, 0x60, 0x00, 0x20, 0x38, 0xBD, 0x20, 0x46, 0x29, 0x46, 0xDC, 0xF7, ++ 0x53, 0xFE, 0x00, 0x20, 0x38, 0xBD, 0x07, 0x48, 0xFE, 0xF7, 0x86, 0xFF, ++ 0x01, 0x20, 0x38, 0xBD, 0xB4, 0xF1, 0xA0, 0x4F, 0xF1, 0xD1, 0x28, 0x46, ++ 0xDC, 0xF7, 0xF6, 0xFD, 0x00, 0x20, 0x38, 0xBD, 0x7C, 0xB7, 0x15, 0x00, ++ 0xB8, 0xB7, 0x15, 0x00, 0x02, 0x28, 0x38, 0xB5, 0x46, 0xDC, 0x01, 0x28, ++ 0x32, 0xD0, 0x00, 0x22, 0x48, 0x68, 0x11, 0x46, 0xFF, 0xF7, 0xCA, 0xFE, ++ 0x25, 0x4A, 0x26, 0x4B, 0x02, 0xFB, 0x00, 0xF2, 0x9A, 0x42, 0x04, 0x46, ++ 0x3E, 0xD8, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, ++ 0x21, 0x4B, 0x01, 0x21, 0x19, 0x60, 0x21, 0x4D, 0x21, 0x49, 0x2B, 0x68, ++ 0x0A, 0x60, 0x01, 0x33, 0x2B, 0x60, 0x82, 0xB1, 0x1F, 0x49, 0x09, 0x78, ++ 0xF9, 0xB9, 0x33, 0xB1, 0x1A, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x2B, 0x60, ++ 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0x1B, 0x48, 0x21, 0x46, 0xFE, 0xF7, ++ 0x49, 0xFF, 0x00, 0x20, 0x38, 0xBD, 0x01, 0x21, 0x40, 0xF2, 0x1F, 0x40, ++ 0xFC, 0xF7, 0xE8, 0xFF, 0x2B, 0x68, 0xEA, 0xE7, 0x12, 0x4A, 0x15, 0x4B, ++ 0x11, 0x68, 0x15, 0x48, 0xA3, 0xFB, 0x01, 0x31, 0x89, 0x0C, 0xFE, 0xF7, ++ 0x37, 0xFF, 0x00, 0x20, 0x38, 0xBD, 0x01, 0x21, 0x40, 0xF2, 0x1F, 0x40, ++ 0xFC, 0xF7, 0x26, 0xFF, 0x2B, 0x68, 0xD8, 0xE7, 0x0E, 0x48, 0xFE, 0xF7, ++ 0x2B, 0xFF, 0x4F, 0xF0, 0xFF, 0x30, 0x38, 0xBD, 0x0C, 0x48, 0xFE, 0xF7, ++ 0x25, 0xFF, 0x4F, 0xF0, 0xFF, 0x30, 0x38, 0xBD, 0x40, 0x42, 0x0F, 0x00, ++ 0xFF, 0xA2, 0xE1, 0x11, 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x6C, 0x60, 0x17, 0x00, 0x64, 0x28, 0x17, 0x00, 0xF8, 0xB7, 0x15, 0x00, ++ 0x83, 0xDE, 0x1B, 0x43, 0xE8, 0xB7, 0x15, 0x00, 0xD0, 0xB7, 0x15, 0x00, ++ 0x08, 0xB8, 0x15, 0x00, 0x10, 0xB5, 0x07, 0x4C, 0x01, 0xE0, 0x04, 0x2A, ++ 0x05, 0xD0, 0x23, 0x68, 0x03, 0xF0, 0x0F, 0x02, 0xDB, 0x07, 0xF8, 0xD5, ++ 0x10, 0xBD, 0xE0, 0xF7, 0x1D, 0xFC, 0xFF, 0xF7, 0x6B, 0xFC, 0xF4, 0xE7, ++ 0x08, 0x10, 0x04, 0x40, 0xE0, 0xF7, 0x0A, 0xBC, 0x10, 0xB5, 0x04, 0x46, ++ 0x00, 0x78, 0x28, 0xB1, 0xE0, 0xF7, 0x04, 0xFC, 0x14, 0xF8, 0x01, 0x0F, ++ 0x00, 0x28, 0xF9, 0xD1, 0x10, 0xBD, 0x00, 0xBF, 0x10, 0xB5, 0x04, 0x4C, ++ 0xD4, 0xF8, 0xB8, 0x30, 0x98, 0x47, 0xD4, 0xF8, 0x28, 0x33, 0xBD, 0xE8, ++ 0x10, 0x40, 0x18, 0x47, 0x88, 0x1A, 0x17, 0x00, 0xFF, 0xF7, 0x2E, 0xBD, ++ 0xFF, 0xF7, 0x0C, 0xBD, 0xFF, 0xF7, 0x36, 0xBE, 0x70, 0xB4, 0x02, 0x68, ++ 0x1C, 0x4C, 0x2D, 0x21, 0xA3, 0x89, 0x11, 0x70, 0x02, 0x68, 0x1A, 0x21, ++ 0x51, 0x70, 0x23, 0xF0, 0x1C, 0x03, 0x02, 0x68, 0x9B, 0xB2, 0x43, 0xF0, ++ 0x0C, 0x03, 0x53, 0x80, 0xA3, 0x7B, 0x13, 0x71, 0x06, 0x68, 0x04, 0xF1, ++ 0x0F, 0x03, 0x04, 0xF1, 0x1F, 0x05, 0x13, 0xF8, 0x01, 0x1B, 0x1A, 0x1B, ++ 0x32, 0x44, 0xAB, 0x42, 0x02, 0xF8, 0x0B, 0x1C, 0xF7, 0xD1, 0x01, 0x68, ++ 0x0E, 0x4A, 0x00, 0x23, 0xCB, 0x73, 0x01, 0x68, 0x0B, 0x74, 0x05, 0x68, ++ 0x23, 0x8C, 0xA5, 0xF8, 0x15, 0x30, 0x05, 0xF1, 0x17, 0x03, 0x1B, 0x35, ++ 0x12, 0xF8, 0x01, 0x1B, 0x03, 0xF8, 0x01, 0x1B, 0xAB, 0x42, 0xF9, 0xD1, ++ 0x03, 0x68, 0x94, 0xF8, 0x28, 0x20, 0xDA, 0x76, 0x03, 0x68, 0x1C, 0x33, ++ 0x03, 0x60, 0x70, 0xBC, 0x1C, 0x20, 0x70, 0x47, 0xE4, 0xB8, 0x17, 0x00, ++ 0x08, 0xB9, 0x17, 0x00, 0x03, 0x68, 0x28, 0x4A, 0xFF, 0x21, 0x70, 0xB4, ++ 0x19, 0x70, 0x03, 0x68, 0x23, 0x21, 0x99, 0x70, 0x05, 0x68, 0xEB, 0x1C, ++ 0x05, 0xF1, 0x09, 0x04, 0x12, 0xF8, 0x01, 0x1F, 0x03, 0xF8, 0x01, 0x1B, ++ 0xA3, 0x42, 0xF9, 0xD1, 0x20, 0x4A, 0xA2, 0xF1, 0x41, 0x01, 0x02, 0xF1, ++ 0x0B, 0x06, 0xA2, 0xF1, 0x38, 0x03, 0x12, 0xF8, 0x01, 0x4F, 0x5B, 0x1A, ++ 0xB2, 0x42, 0x5C, 0x55, 0xF7, 0xD1, 0x91, 0xF8, 0x42, 0x30, 0xB1, 0xF8, ++ 0x50, 0x40, 0xB1, 0xF8, 0x4E, 0x20, 0xEC, 0x82, 0x1C, 0x07, 0xAA, 0x82, ++ 0x05, 0xF1, 0x18, 0x06, 0x4F, 0xEA, 0x63, 0x02, 0x07, 0xD5, 0xB1, 0xF8, ++ 0x52, 0x40, 0xB1, 0xF8, 0x54, 0x30, 0x6B, 0x83, 0x2C, 0x83, 0x05, 0xF1, ++ 0x1C, 0x06, 0x13, 0x07, 0x04, 0xD5, 0xB1, 0xF8, 0x56, 0x30, 0x33, 0x80, ++ 0x73, 0x80, 0x04, 0x36, 0x0C, 0x4C, 0x32, 0x46, 0x14, 0xF8, 0x01, 0x5F, ++ 0x15, 0x70, 0x91, 0xF8, 0x75, 0x51, 0x93, 0x1B, 0x9D, 0x42, 0x02, 0xF1, ++ 0x01, 0x02, 0xF5, 0xDA, 0x03, 0x68, 0xD2, 0x1A, 0x91, 0x1E, 0x59, 0x70, ++ 0x03, 0x68, 0x13, 0x44, 0x03, 0x60, 0x70, 0xBC, 0x10, 0x46, 0x70, 0x47, ++ 0x1F, 0xB9, 0x17, 0x00, 0x25, 0xB9, 0x17, 0x00, 0x3D, 0xB9, 0x17, 0x00, ++ 0x70, 0xB4, 0x0F, 0x4C, 0x03, 0x46, 0x22, 0x6B, 0x09, 0xB1, 0x22, 0xF4, ++ 0xC0, 0x52, 0x19, 0x68, 0xBF, 0x20, 0x08, 0x70, 0x19, 0x68, 0x0C, 0x20, ++ 0x48, 0x70, 0x18, 0x68, 0xA1, 0x8E, 0xC0, 0xF8, 0x02, 0x20, 0x1A, 0x68, ++ 0x60, 0x8F, 0xE6, 0x8E, 0x25, 0x8F, 0xD1, 0x80, 0x02, 0xF1, 0x0E, 0x01, ++ 0x16, 0x81, 0x55, 0x81, 0x90, 0x81, 0x70, 0xBC, 0x0E, 0x20, 0x19, 0x60, ++ 0x70, 0x47, 0x00, 0xBF, 0xE4, 0xB8, 0x17, 0x00, 0x03, 0x68, 0x10, 0xB4, ++ 0xC7, 0x24, 0x1C, 0x70, 0x03, 0x68, 0x01, 0x24, 0x5C, 0x70, 0x03, 0x68, ++ 0x42, 0xEA, 0x01, 0x11, 0x99, 0x70, 0x03, 0x68, 0x5D, 0xF8, 0x04, 0x4B, ++ 0x03, 0x33, 0x03, 0x60, 0x03, 0x20, 0x70, 0x47, 0x03, 0x68, 0x46, 0x22, ++ 0x1A, 0x70, 0x03, 0x68, 0x05, 0x22, 0x5A, 0x70, 0x03, 0x68, 0x70, 0x22, ++ 0x9A, 0x70, 0x02, 0x68, 0x00, 0x23, 0xD3, 0x70, 0x02, 0x68, 0x13, 0x71, ++ 0x02, 0x68, 0x53, 0x71, 0x02, 0x68, 0x93, 0x71, 0x03, 0x68, 0x07, 0x33, ++ 0x03, 0x60, 0x07, 0x20, 0x70, 0x47, 0x00, 0xBF, 0x30, 0xB4, 0x02, 0x9C, ++ 0x01, 0x80, 0x42, 0x80, 0x83, 0x80, 0x84, 0xB1, 0x10, 0x22, 0x80, 0x23, ++ 0x82, 0x71, 0xC3, 0x71, 0xE5, 0x18, 0x22, 0x46, 0x13, 0x46, 0x08, 0x33, ++ 0x12, 0xF8, 0x01, 0x1B, 0x1B, 0x1B, 0xAA, 0x42, 0x19, 0x54, 0xF7, 0xD1, ++ 0x88, 0x20, 0x30, 0xBC, 0x70, 0x47, 0x06, 0x20, 0x30, 0xBC, 0x70, 0x47, ++ 0x01, 0x80, 0x02, 0x20, 0x70, 0x47, 0x00, 0xBF, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0x8F, 0xB0, 0x1F, 0x46, 0x1A, 0x9E, 0x03, 0x93, 0x34, 0x8F, 0xB6, 0xF8, ++ 0x36, 0x80, 0x0D, 0x46, 0x03, 0x46, 0x01, 0x2C, 0x38, 0x46, 0x38, 0xBF, ++ 0x01, 0x24, 0x07, 0x93, 0x17, 0x46, 0x01, 0xF0, 0xC1, 0xFE, 0xB5, 0xF8, ++ 0xAE, 0x90, 0x07, 0x9B, 0x09, 0xF0, 0x10, 0x09, 0x40, 0xEA, 0x09, 0x00, ++ 0x06, 0xF1, 0x40, 0x02, 0x5C, 0x80, 0x02, 0x92, 0x18, 0x80, 0x1F, 0xFA, ++ 0x80, 0xF9, 0x14, 0x46, 0x00, 0x2F, 0x00, 0xF0, 0xDE, 0x81, 0x3A, 0x88, ++ 0x9A, 0x80, 0x7A, 0x88, 0xDA, 0x80, 0xBA, 0x88, 0x1A, 0x81, 0x0A, 0x22, ++ 0x17, 0x46, 0x18, 0x99, 0x98, 0x18, 0x08, 0x60, 0x00, 0x21, 0x07, 0x90, ++ 0x95, 0xF8, 0x7E, 0x00, 0x99, 0x54, 0x07, 0x9B, 0x00, 0xF1, 0x02, 0x0E, ++ 0x58, 0x70, 0x00, 0x28, 0x40, 0xF0, 0xC7, 0x80, 0x07, 0x9B, 0x95, 0xF8, ++ 0xB0, 0x10, 0x0E, 0xEB, 0x03, 0x00, 0x01, 0x22, 0x07, 0x90, 0x0E, 0xF8, ++ 0x03, 0x20, 0x07, 0x9B, 0x08, 0x29, 0x8C, 0x46, 0x28, 0xBF, 0x4F, 0xF0, ++ 0x08, 0x0C, 0x83, 0xF8, 0x01, 0xC0, 0x07, 0x9B, 0x1F, 0xFA, 0x8E, 0xFE, ++ 0x0C, 0xF1, 0x02, 0x0A, 0x05, 0xF1, 0xB1, 0x02, 0x51, 0xB1, 0x0C, 0xF1, ++ 0xB1, 0x0C, 0xAC, 0x44, 0x12, 0xF8, 0x01, 0x0B, 0xD1, 0x18, 0x49, 0x1B, ++ 0x94, 0x45, 0x01, 0xF8, 0xB0, 0x0C, 0xF7, 0xD1, 0x95, 0xF8, 0xB0, 0x20, ++ 0xD6, 0x44, 0x0A, 0xEB, 0x03, 0x01, 0x08, 0x2A, 0x77, 0x44, 0x07, 0x91, ++ 0x1A, 0xD9, 0x32, 0x21, 0x0A, 0xF8, 0x03, 0x10, 0x07, 0x9B, 0xA2, 0xF1, ++ 0x08, 0x01, 0x59, 0x70, 0x02, 0xF1, 0xB1, 0x0C, 0x07, 0x9B, 0xA2, 0xF1, ++ 0x06, 0x0E, 0xAC, 0x44, 0x05, 0xF1, 0xB9, 0x02, 0x12, 0xF8, 0x01, 0x0B, ++ 0xD1, 0x18, 0x49, 0x1B, 0x94, 0x45, 0x01, 0xF8, 0xB8, 0x0C, 0xF7, 0xD1, ++ 0x73, 0x44, 0x77, 0x44, 0x07, 0x93, 0xBF, 0xB2, 0x19, 0xF4, 0x80, 0x7F, ++ 0x40, 0xF0, 0xB5, 0x80, 0x07, 0xA8, 0xFF, 0xF7, 0x3F, 0xFF, 0x47, 0x44, ++ 0x07, 0x9B, 0x80, 0xB2, 0xBF, 0xB2, 0xB8, 0xF1, 0x00, 0x0F, 0x0A, 0xD0, ++ 0x02, 0x9A, 0x42, 0x44, 0x94, 0x46, 0x14, 0xF8, 0x01, 0x1B, 0xE2, 0x18, ++ 0x92, 0x1B, 0x64, 0x45, 0x02, 0xF8, 0x41, 0x1C, 0xF7, 0xD1, 0xD5, 0xF8, ++ 0xE0, 0x40, 0x07, 0x44, 0x43, 0x44, 0xE2, 0x07, 0xBF, 0xB2, 0x07, 0x93, ++ 0x1A, 0xD5, 0xB4, 0x4A, 0x07, 0xCA, 0x0A, 0xAE, 0x03, 0xC6, 0x00, 0x20, ++ 0x0A, 0xA9, 0x32, 0x80, 0xAD, 0xF8, 0x36, 0x00, 0xCD, 0xF8, 0x32, 0x00, ++ 0x8D, 0xF8, 0x30, 0x00, 0x5B, 0x1A, 0x0C, 0xA8, 0xDD, 0x22, 0x01, 0xE0, ++ 0x11, 0xF8, 0x01, 0x2F, 0x5A, 0x54, 0x88, 0x42, 0xFA, 0xD1, 0x07, 0x9B, ++ 0x09, 0x37, 0x09, 0x33, 0xBF, 0xB2, 0x07, 0x93, 0xA6, 0x07, 0x04, 0xD5, ++ 0xA6, 0x4B, 0x93, 0xF8, 0x76, 0x31, 0xDC, 0x07, 0x53, 0xD4, 0xA5, 0x4B, ++ 0x9B, 0x7D, 0x01, 0x2B, 0x5A, 0xD0, 0xD5, 0xF8, 0xE0, 0x30, 0x18, 0x07, ++ 0x04, 0xD5, 0xA0, 0x4A, 0x92, 0xF8, 0x76, 0x21, 0x51, 0x07, 0x3C, 0xD4, ++ 0x5A, 0x07, 0x22, 0xD5, 0x9C, 0x4D, 0x95, 0xF8, 0x76, 0x31, 0x9B, 0x07, ++ 0x1D, 0xD5, 0x03, 0x99, 0x9B, 0x4B, 0x9C, 0x4C, 0x4F, 0xF4, 0xA4, 0x62, ++ 0x02, 0xFB, 0x01, 0x33, 0x07, 0xA8, 0x93, 0xF8, 0xC0, 0x14, 0xD4, 0xF8, ++ 0x50, 0x21, 0x90, 0x47, 0x07, 0x44, 0x28, 0x8F, 0xD4, 0xF8, 0x4C, 0x61, ++ 0x01, 0xF0, 0x9A, 0xFC, 0x95, 0xF8, 0x75, 0x21, 0x04, 0x2A, 0x01, 0x46, ++ 0x08, 0xBF, 0x03, 0x22, 0x07, 0xA8, 0xB0, 0x47, 0xBF, 0xB2, 0x38, 0x44, ++ 0x87, 0xB2, 0x18, 0x9B, 0x1A, 0x68, 0x07, 0x9B, 0x9B, 0x1A, 0x19, 0x9A, ++ 0x38, 0x46, 0x13, 0x80, 0x0F, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x7F, 0x30, ++ 0x07, 0x9B, 0x28, 0x44, 0x05, 0xF1, 0x7F, 0x02, 0x12, 0xF8, 0x01, 0xCB, ++ 0xD1, 0x18, 0x49, 0x1B, 0x90, 0x42, 0x01, 0xF8, 0x7E, 0xCC, 0xF7, 0xD1, ++ 0x2B, 0xE7, 0x82, 0x4B, 0x07, 0xA8, 0xD3, 0xF8, 0x44, 0x31, 0x98, 0x47, ++ 0x38, 0x44, 0xD5, 0xF8, 0xE0, 0x30, 0x87, 0xB2, 0xB8, 0xE7, 0x7D, 0x4B, ++ 0x07, 0xA8, 0xD3, 0xF8, 0x48, 0x31, 0x98, 0x47, 0x78, 0x4B, 0x9B, 0x7D, ++ 0x38, 0x44, 0x01, 0x2B, 0x87, 0xB2, 0xA4, 0xD1, 0xB5, 0xF8, 0xE4, 0x30, ++ 0x00, 0x2B, 0xA0, 0xD0, 0x07, 0x9B, 0x36, 0x22, 0x1A, 0x70, 0x07, 0x9B, ++ 0x03, 0x22, 0x5A, 0x70, 0x07, 0x9B, 0xB5, 0xF8, 0xE4, 0x20, 0x5A, 0x80, ++ 0x95, 0xF8, 0xE6, 0x20, 0x1A, 0x71, 0x07, 0x9B, 0x05, 0x37, 0x05, 0x33, ++ 0xBF, 0xB2, 0x07, 0x93, 0x8D, 0xE7, 0x07, 0x9B, 0x21, 0x22, 0x59, 0x1C, ++ 0x07, 0x91, 0x1A, 0x70, 0x07, 0x9B, 0x02, 0x22, 0x59, 0x1C, 0x07, 0x91, ++ 0x0A, 0xA8, 0x1A, 0x70, 0x0D, 0xF1, 0x27, 0x01, 0xDB, 0xF7, 0x8E, 0xFE, ++ 0xD5, 0xF8, 0xA4, 0x30, 0x9D, 0xF9, 0x28, 0x20, 0x93, 0xF9, 0x04, 0x30, ++ 0x9A, 0x42, 0xC8, 0xBF, 0x8D, 0xF8, 0x28, 0x30, 0x07, 0x9B, 0x9D, 0xF8, ++ 0x27, 0x20, 0x59, 0x1C, 0x07, 0x91, 0x1A, 0x70, 0x07, 0x9B, 0x9D, 0xF8, ++ 0x28, 0x20, 0x59, 0x1C, 0x07, 0x91, 0x1A, 0x70, 0x07, 0x9B, 0x24, 0x22, ++ 0x59, 0x1C, 0x07, 0x91, 0x1A, 0x70, 0x07, 0x9B, 0x04, 0x93, 0x1A, 0x46, ++ 0x02, 0xF1, 0x01, 0x0B, 0xD5, 0xF8, 0xA4, 0x30, 0xCD, 0xF8, 0x1C, 0xB0, ++ 0x9B, 0x78, 0x4F, 0x4A, 0x00, 0x2B, 0x52, 0xD1, 0x01, 0x23, 0x92, 0xF8, ++ 0x72, 0xA1, 0x05, 0x93, 0x76, 0x32, 0xBA, 0xF1, 0x00, 0x0F, 0x00, 0xF0, ++ 0x8C, 0x80, 0x00, 0x21, 0x06, 0x95, 0x01, 0x91, 0x08, 0x46, 0x8E, 0x46, ++ 0xA1, 0x46, 0x0D, 0x46, 0x1A, 0x96, 0xD3, 0x78, 0x13, 0xF0, 0x02, 0x03, ++ 0x1F, 0xD1, 0x94, 0x78, 0xB2, 0xF8, 0x00, 0xC0, 0x00, 0x2C, 0x43, 0xD1, ++ 0xAC, 0xF6, 0x6C, 0x14, 0x48, 0x2C, 0x3A, 0xD8, 0x40, 0xF6, 0xB4, 0x13, ++ 0x9C, 0x45, 0x6F, 0xD0, 0x40, 0x4C, 0xAC, 0xF6, 0x67, 0x13, 0xA4, 0xFB, ++ 0x03, 0x43, 0x9C, 0x08, 0xC3, 0xF3, 0x87, 0x03, 0x00, 0x28, 0x45, 0xD0, ++ 0xA4, 0xEB, 0x0E, 0x0E, 0x05, 0x9C, 0xA6, 0x45, 0x44, 0xD1, 0x01, 0x30, ++ 0xC0, 0xB2, 0x9E, 0x46, 0x06, 0x32, 0x01, 0x31, 0xCB, 0xB2, 0x9A, 0x45, ++ 0xD7, 0xD8, 0x01, 0x9B, 0x1A, 0x9E, 0x03, 0xF1, 0x02, 0x0E, 0x29, 0x46, ++ 0x5F, 0xFA, 0x8E, 0xF3, 0x06, 0x9D, 0x4C, 0x46, 0x9E, 0x46, 0x0B, 0xF1, ++ 0x01, 0x02, 0x07, 0x92, 0x8B, 0xF8, 0x00, 0x10, 0x07, 0x9A, 0x51, 0x1C, ++ 0x07, 0x91, 0x06, 0x37, 0x10, 0x70, 0x04, 0x9A, 0x1E, 0xFA, 0x87, 0xF7, ++ 0xBF, 0xB2, 0x13, 0x70, 0xC0, 0xE6, 0x04, 0x23, 0x92, 0xF8, 0x73, 0xA1, ++ 0x05, 0x93, 0xCA, 0x32, 0xAB, 0xE7, 0xD8, 0xB9, 0x86, 0x46, 0x05, 0x46, ++ 0x01, 0x20, 0xD5, 0xE7, 0x01, 0x2C, 0xF8, 0xD1, 0xAC, 0xF5, 0x9C, 0x5C, ++ 0xAC, 0xF1, 0x0D, 0x04, 0xA4, 0xB2, 0xB4, 0xF5, 0x4D, 0x7F, 0xF0, 0xD8, ++ 0x1D, 0x4B, 0xAC, 0xF1, 0x08, 0x0C, 0xA3, 0xFB, 0x0C, 0x43, 0x9C, 0x08, ++ 0xC3, 0xF3, 0x87, 0x03, 0x00, 0x28, 0xB9, 0xD1, 0x9E, 0x46, 0x1D, 0x46, ++ 0x01, 0x20, 0xBD, 0xE7, 0x0B, 0xF1, 0x01, 0x04, 0x07, 0x94, 0x8B, 0xF8, ++ 0x00, 0x50, 0x07, 0x9C, 0x01, 0x9E, 0x04, 0xF1, 0x01, 0x0C, 0x06, 0xF1, ++ 0x02, 0x0E, 0xCD, 0xF8, 0x1C, 0xC0, 0x00, 0xF1, 0x02, 0x0C, 0x20, 0x70, ++ 0x5F, 0xFA, 0x8E, 0xF0, 0x01, 0x90, 0xDD, 0xF8, 0x1C, 0xB0, 0x9E, 0x46, ++ 0x5F, 0xFA, 0x8C, 0xF0, 0xA4, 0xE7, 0x04, 0x22, 0x17, 0x46, 0x26, 0xE6, ++ 0x0E, 0x23, 0x1C, 0x46, 0x94, 0xE7, 0x02, 0x23, 0x50, 0x46, 0x51, 0x46, ++ 0x9E, 0x46, 0xA8, 0xE7, 0x2C, 0xB8, 0x15, 0x00, 0xE4, 0xB8, 0x17, 0x00, ++ 0x64, 0xBA, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0xCD, 0xCC, 0xCC, 0xCC, 0x03, 0x22, 0x00, 0x23, 0x30, 0xB4, 0x02, 0x70, ++ 0x43, 0x70, 0x4B, 0x7C, 0x83, 0x70, 0x0B, 0x7C, 0x8C, 0x7B, 0xCA, 0x7B, ++ 0x4D, 0x89, 0xA0, 0xF8, 0x05, 0x50, 0x9B, 0x00, 0x43, 0xEA, 0x44, 0x03, ++ 0x43, 0xEA, 0x82, 0x13, 0xA0, 0xF8, 0x03, 0x30, 0x0B, 0x89, 0x1B, 0x01, ++ 0xA0, 0xF8, 0x07, 0x30, 0x30, 0xBC, 0x09, 0x20, 0x70, 0x47, 0x00, 0xBF, ++ 0x30, 0xB4, 0x22, 0xF0, 0x01, 0x02, 0xBD, 0xF8, 0x08, 0x40, 0xA0, 0xF8, ++ 0x05, 0x20, 0x03, 0x25, 0x01, 0x22, 0xA0, 0xF8, 0x03, 0x40, 0x83, 0x70, ++ 0x05, 0x70, 0x42, 0x70, 0x2C, 0xB1, 0x00, 0x23, 0xC3, 0x71, 0x03, 0x72, ++ 0x30, 0xBC, 0x09, 0x20, 0x70, 0x47, 0x4B, 0x89, 0xA0, 0xF8, 0x07, 0x30, ++ 0x30, 0xBC, 0x09, 0x20, 0x70, 0x47, 0x00, 0xBF, 0x10, 0xB4, 0x02, 0x23, ++ 0x03, 0x24, 0x04, 0x70, 0x43, 0x70, 0x0B, 0x7C, 0x49, 0x7B, 0x5D, 0xF8, ++ 0x04, 0x4B, 0x82, 0x80, 0x1B, 0x03, 0x9B, 0xB2, 0x01, 0x29, 0x08, 0xBF, ++ 0x43, 0xF4, 0x00, 0x63, 0x43, 0x80, 0x06, 0x20, 0x70, 0x47, 0x00, 0xBF, ++ 0x2D, 0xE9, 0xF0, 0x41, 0x82, 0xB0, 0x16, 0x46, 0x0D, 0xF1, 0x07, 0x02, ++ 0x07, 0x46, 0x88, 0x46, 0xFD, 0xF7, 0x7A, 0xFB, 0xA8, 0xB3, 0x9D, 0xF8, ++ 0x07, 0x40, 0x83, 0x1C, 0x7C, 0xB1, 0x02, 0x34, 0x20, 0x44, 0x00, 0x24, ++ 0x1D, 0x78, 0x25, 0xF0, 0x81, 0x02, 0x7E, 0x2A, 0x03, 0xF1, 0x01, 0x03, ++ 0x03, 0xD0, 0x32, 0x19, 0x01, 0x34, 0x55, 0x70, 0xE4, 0xB2, 0x98, 0x42, ++ 0xF2, 0xD1, 0x0D, 0xF1, 0x07, 0x02, 0x41, 0x46, 0x38, 0x46, 0xFD, 0xF7, ++ 0x7F, 0xFB, 0xB0, 0xB1, 0x9D, 0xF8, 0x07, 0x30, 0x81, 0x1C, 0x93, 0xB1, ++ 0x02, 0x33, 0x1F, 0x18, 0x0A, 0x78, 0x22, 0xF0, 0x81, 0x00, 0x63, 0x1C, ++ 0x7E, 0x28, 0x06, 0xEB, 0x04, 0x05, 0x01, 0xF1, 0x01, 0x01, 0xDB, 0xB2, ++ 0x03, 0xD0, 0x0B, 0x2B, 0x6A, 0x70, 0x1C, 0x46, 0x01, 0xD8, 0x8F, 0x42, ++ 0xEE, 0xD1, 0x34, 0x70, 0x02, 0xB0, 0xBD, 0xE8, 0xF0, 0x81, 0x04, 0x46, ++ 0x34, 0x70, 0x02, 0xB0, 0xBD, 0xE8, 0xF0, 0x81, 0x10, 0xB5, 0x14, 0x46, ++ 0xFD, 0xF7, 0xE8, 0xFC, 0x00, 0xB1, 0x80, 0x78, 0x84, 0xF8, 0xDA, 0x00, ++ 0x10, 0xBD, 0x00, 0xBF, 0xF0, 0xB5, 0x83, 0xB0, 0x14, 0x46, 0x0D, 0xF1, ++ 0x07, 0x02, 0xFD, 0xF7, 0x8B, 0xFB, 0x60, 0xB3, 0xD4, 0xF8, 0xA4, 0xE0, ++ 0x9E, 0xF8, 0x02, 0x40, 0x4C, 0xB3, 0x01, 0x2C, 0xBE, 0xF8, 0x00, 0x30, ++ 0x40, 0xD0, 0x00, 0x24, 0x04, 0x25, 0x9D, 0xF8, 0x07, 0x70, 0x02, 0x37, ++ 0xFF, 0xB2, 0x08, 0x2F, 0x8D, 0xF8, 0x07, 0x70, 0x19, 0xD9, 0x05, 0x26, ++ 0x06, 0xEB, 0x00, 0x0C, 0x33, 0x5C, 0x9C, 0xF8, 0x01, 0x10, 0x69, 0xB1, ++ 0x9C, 0x42, 0x25, 0xD0, 0x01, 0x39, 0xC9, 0xB2, 0x00, 0x22, 0x01, 0xE0, ++ 0x9C, 0x42, 0x1F, 0xD0, 0x2B, 0x44, 0x8A, 0x42, 0xDB, 0xB2, 0x02, 0xF1, ++ 0x01, 0x02, 0xF7, 0xD1, 0x03, 0x36, 0xF6, 0xB2, 0xF3, 0x1C, 0x9F, 0x42, ++ 0xE6, 0xDC, 0x03, 0xB0, 0xF0, 0xBD, 0xBE, 0xF8, 0x00, 0x30, 0xA3, 0xF6, ++ 0x6C, 0x12, 0x48, 0x2A, 0x12, 0xD8, 0x40, 0xF6, 0xB4, 0x12, 0x93, 0x42, ++ 0x20, 0xD0, 0x12, 0x4A, 0xA3, 0xF6, 0x67, 0x14, 0xA2, 0xFB, 0x04, 0x34, ++ 0xC4, 0xF3, 0x87, 0x04, 0x01, 0x25, 0xC8, 0xE7, 0x9C, 0xF8, 0x02, 0x30, ++ 0x8E, 0xF8, 0x04, 0x30, 0x03, 0xB0, 0xF0, 0xBD, 0x01, 0x25, 0xC0, 0xE7, ++ 0xA3, 0xF5, 0x9C, 0x53, 0xA3, 0xF1, 0x0D, 0x02, 0x92, 0xB2, 0xB2, 0xF5, ++ 0x4D, 0x7F, 0xB6, 0xD8, 0x05, 0x4C, 0x08, 0x3B, 0xA4, 0xFB, 0x03, 0x34, ++ 0xC4, 0xF3, 0x87, 0x04, 0x04, 0x25, 0xB0, 0xE7, 0x0E, 0x24, 0x01, 0x25, ++ 0xAD, 0xE7, 0x00, 0xBF, 0xCD, 0xCC, 0xCC, 0xCC, 0x10, 0xB5, 0x14, 0x46, ++ 0xFD, 0xF7, 0x96, 0xFC, 0x48, 0xB1, 0x83, 0x78, 0xC2, 0x78, 0x43, 0xEA, ++ 0x02, 0x23, 0xA4, 0xF8, 0xE4, 0x30, 0x03, 0x79, 0x84, 0xF8, 0xE6, 0x30, ++ 0x10, 0xBD, 0x84, 0xF8, 0xE6, 0x00, 0xA4, 0xF8, 0xE4, 0x00, 0x10, 0xBD, ++ 0x2D, 0xE9, 0xF0, 0x47, 0x82, 0xB0, 0x1C, 0x46, 0x05, 0x46, 0x0E, 0x46, ++ 0x91, 0x46, 0xFD, 0xF7, 0x49, 0xFB, 0x31, 0x46, 0x07, 0x46, 0x28, 0x46, ++ 0xFD, 0xF7, 0x64, 0xFB, 0x57, 0xEA, 0x00, 0x03, 0x72, 0xD0, 0x80, 0x46, ++ 0x0D, 0xF1, 0x07, 0x02, 0x31, 0x46, 0x28, 0x46, 0xFD, 0xF7, 0x7A, 0xFB, ++ 0x82, 0x46, 0x18, 0xB1, 0x9D, 0xF8, 0x07, 0x30, 0x00, 0x2B, 0x65, 0xD0, ++ 0x31, 0x46, 0x0D, 0xF1, 0x07, 0x02, 0x28, 0x46, 0xFD, 0xF7, 0x90, 0xFB, ++ 0x01, 0x46, 0x00, 0x28, 0x58, 0xD1, 0x00, 0x2F, 0x7A, 0xD0, 0xBB, 0x78, ++ 0x38, 0x79, 0x89, 0xF8, 0x00, 0x30, 0x97, 0xF8, 0x03, 0xC0, 0x00, 0x28, ++ 0x08, 0xBF, 0x02, 0x20, 0xBC, 0xF1, 0x0E, 0x0F, 0x0C, 0xF1, 0xFF, 0x33, ++ 0x8C, 0xBF, 0x01, 0x27, 0x00, 0x27, 0x4D, 0xD8, 0x0D, 0x2B, 0x70, 0xD8, ++ 0xBC, 0xF1, 0x0E, 0x0F, 0x00, 0xF0, 0x97, 0x80, 0x0C, 0xEB, 0x8C, 0x06, ++ 0x06, 0xF6, 0x67, 0x16, 0x00, 0x29, 0x4A, 0xD0, 0x8D, 0x78, 0xCA, 0x78, ++ 0x91, 0xF8, 0x04, 0xE0, 0x05, 0xF1, 0xFF, 0x38, 0xB8, 0xF1, 0x02, 0x0F, ++ 0x9A, 0xBF, 0x01, 0x35, 0xED, 0xB2, 0x01, 0x25, 0xBC, 0xF1, 0x0E, 0x0F, ++ 0x93, 0xB2, 0x1F, 0xFA, 0x8E, 0xF1, 0x57, 0xD8, 0x02, 0xF1, 0xFF, 0x3C, ++ 0xBC, 0xF1, 0x0D, 0x0F, 0x72, 0xD8, 0x0E, 0x2A, 0x00, 0xF0, 0x90, 0x80, ++ 0x03, 0xEB, 0x83, 0x03, 0x03, 0xF6, 0x67, 0x13, 0x61, 0xB1, 0x0E, 0xF1, ++ 0xFF, 0x32, 0x0D, 0x2A, 0x60, 0xD8, 0xBE, 0xF1, 0x0E, 0x0F, 0x00, 0xF0, ++ 0x9A, 0x80, 0x01, 0xEB, 0x81, 0x01, 0x01, 0xF6, 0x67, 0x11, 0x89, 0xB2, ++ 0x4B, 0x4A, 0x92, 0xF8, 0x75, 0x21, 0xAA, 0x42, 0x24, 0xD2, 0x01, 0x2A, ++ 0x67, 0xD0, 0x02, 0x2A, 0x5E, 0xD0, 0x00, 0x2A, 0x08, 0xBF, 0x33, 0x46, ++ 0x15, 0x46, 0x1B, 0xE0, 0x9D, 0xF8, 0x07, 0x30, 0x00, 0x2B, 0xA2, 0xD1, ++ 0x00, 0x20, 0x02, 0xB0, 0xBD, 0xE8, 0xF0, 0x87, 0xA4, 0x2B, 0x22, 0xD8, ++ 0x0C, 0xEB, 0x8C, 0x06, 0x06, 0xF5, 0x9C, 0x56, 0x08, 0x36, 0x00, 0x29, ++ 0xB4, 0xD1, 0xBA, 0xF1, 0x00, 0x0F, 0x31, 0xD0, 0x9A, 0xF8, 0x02, 0x50, ++ 0x01, 0x2D, 0x3A, 0xD0, 0x03, 0x2D, 0x50, 0xD0, 0x0D, 0x46, 0x33, 0x46, ++ 0x27, 0x70, 0x65, 0x70, 0x66, 0x80, 0xA3, 0x80, 0xE1, 0x80, 0x02, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x87, 0x98, 0xF8, 0x02, 0x30, 0x98, 0xF8, 0x05, 0x00, ++ 0x89, 0xF8, 0x00, 0x30, 0x98, 0xF8, 0x04, 0xC0, 0x81, 0xE7, 0x4F, 0xF6, ++ 0xFF, 0x76, 0x93, 0xE7, 0x01, 0x3A, 0xA4, 0x2A, 0x19, 0xD8, 0x03, 0xEB, ++ 0x83, 0x03, 0x03, 0xF5, 0x9C, 0x53, 0x08, 0x33, 0x00, 0x29, 0xB7, 0xD0, ++ 0x0E, 0xF1, 0xFF, 0x3E, 0xBE, 0xF1, 0xA4, 0x0F, 0x0A, 0xD8, 0x01, 0xEB, ++ 0x81, 0x01, 0x01, 0xF5, 0x9C, 0x51, 0x08, 0x31, 0x89, 0xB2, 0xAB, 0xE7, ++ 0x51, 0x46, 0x55, 0x46, 0x33, 0x46, 0xD1, 0xE7, 0x4F, 0xF6, 0xFF, 0x71, ++ 0xA4, 0xE7, 0x4F, 0xF6, 0xFF, 0x73, 0xE7, 0xE7, 0x4F, 0xF6, 0xFF, 0x73, ++ 0x90, 0xE7, 0x06, 0xF1, 0x0A, 0x03, 0x9B, 0xB2, 0xC4, 0xE7, 0x40, 0xF6, ++ 0xB4, 0x16, 0x69, 0xE7, 0x9E, 0x42, 0x94, 0xBF, 0x28, 0x3B, 0x28, 0x33, ++ 0x9B, 0xB2, 0x15, 0x46, 0xBA, 0xE7, 0x02, 0x2D, 0x0F, 0xD0, 0x03, 0xF1, ++ 0x28, 0x05, 0xB5, 0x42, 0x15, 0xDA, 0x3C, 0x33, 0x9B, 0xB2, 0x15, 0x46, ++ 0xB0, 0xE7, 0xA6, 0xF1, 0x0A, 0x03, 0x9B, 0xB2, 0x01, 0x25, 0xAB, 0xE7, ++ 0x40, 0xF6, 0xB4, 0x13, 0x70, 0xE7, 0x9E, 0x42, 0x03, 0xD8, 0x14, 0x3B, ++ 0x9B, 0xB2, 0x15, 0x46, 0xA2, 0xE7, 0x14, 0x33, 0x9B, 0xB2, 0x15, 0x46, ++ 0x9E, 0xE7, 0x9E, 0x42, 0xF9, 0xD8, 0xA3, 0xF1, 0x27, 0x05, 0xAE, 0x42, ++ 0xF1, 0xDA, 0x3C, 0x3B, 0x9B, 0xB2, 0x15, 0x46, 0x94, 0xE7, 0x40, 0xF6, ++ 0xB4, 0x11, 0x67, 0xE7, 0xE4, 0xB8, 0x17, 0x00, 0x70, 0xB5, 0x1D, 0x46, ++ 0x14, 0x46, 0xFD, 0xF7, 0x95, 0xFB, 0x00, 0x23, 0x2B, 0x70, 0x00, 0x28, ++ 0x48, 0xD0, 0x02, 0x7A, 0xA1, 0x7C, 0x02, 0xF0, 0x0F, 0x03, 0x99, 0x42, ++ 0x40, 0xD0, 0x01, 0x21, 0x29, 0x70, 0xA3, 0x74, 0x22, 0x74, 0xD0, 0xF8, ++ 0x0A, 0x20, 0x13, 0x0A, 0xD1, 0x08, 0x02, 0xF0, 0x0F, 0x02, 0x52, 0xEA, ++ 0x03, 0x12, 0x04, 0xBF, 0x40, 0xF6, 0x43, 0x23, 0x63, 0x60, 0xD0, 0xF8, ++ 0x0E, 0x30, 0x18, 0xBF, 0x62, 0x60, 0x1D, 0x0A, 0x03, 0xF0, 0x0F, 0x02, ++ 0x52, 0xEA, 0x05, 0x12, 0x08, 0xBF, 0x40, 0xF6, 0x47, 0x22, 0x22, 0x60, ++ 0xD0, 0xF8, 0x12, 0x20, 0x95, 0x08, 0x16, 0x0A, 0x02, 0xF0, 0x0F, 0x02, ++ 0x52, 0xEA, 0x06, 0x12, 0x08, 0xBF, 0x12, 0x4A, 0xA2, 0x60, 0xD0, 0xF8, ++ 0x16, 0x20, 0xC3, 0xF3, 0x00, 0x13, 0x50, 0x08, 0x05, 0xF0, 0x04, 0x05, ++ 0x01, 0xF0, 0x02, 0x01, 0x2B, 0x43, 0x00, 0xF0, 0x08, 0x00, 0x49, 0xB2, ++ 0x03, 0x43, 0x0B, 0x43, 0x11, 0x0A, 0x02, 0xF0, 0x0F, 0x02, 0x52, 0xEA, ++ 0x01, 0x12, 0x63, 0x74, 0x0A, 0xBF, 0x07, 0x4B, 0xE2, 0x60, 0xE3, 0x60, ++ 0x01, 0x20, 0x70, 0xBD, 0x40, 0xF6, 0x43, 0x23, 0xC4, 0xE9, 0x00, 0x33, ++ 0xC4, 0xE9, 0x02, 0x33, 0x70, 0xBD, 0x00, 0xBF, 0x32, 0xE4, 0x05, 0x00, ++ 0x22, 0xF3, 0x02, 0x00, 0x38, 0xB5, 0x14, 0x46, 0xFD, 0xF7, 0x4A, 0xFB, ++ 0xE8, 0xB1, 0xC2, 0x78, 0x83, 0x78, 0x43, 0xEA, 0x02, 0x23, 0x23, 0x80, ++ 0x23, 0x46, 0x02, 0x79, 0x03, 0xF8, 0x02, 0x2F, 0x04, 0xF1, 0x12, 0x05, ++ 0xC4, 0xF1, 0x03, 0x02, 0xC1, 0x18, 0x89, 0x5C, 0x03, 0xF8, 0x01, 0x1F, ++ 0xAB, 0x42, 0xF9, 0xD1, 0x43, 0x7D, 0x82, 0x7D, 0xB0, 0xF8, 0x17, 0x10, ++ 0xA1, 0x61, 0x43, 0xEA, 0x02, 0x23, 0xA3, 0x82, 0xC3, 0x7E, 0x23, 0x77, ++ 0x01, 0x20, 0x38, 0xBD, 0xF8, 0xB5, 0x14, 0x46, 0xFD, 0xF7, 0xCA, 0xFB, ++ 0xB8, 0xB1, 0xC7, 0x79, 0x43, 0x7A, 0x85, 0x79, 0x02, 0x7A, 0x81, 0x7A, ++ 0xC6, 0x7A, 0x45, 0xEA, 0x07, 0x25, 0x42, 0xEA, 0x03, 0x22, 0xD0, 0xF8, ++ 0x02, 0x70, 0x03, 0x7B, 0x40, 0x7B, 0x27, 0x60, 0x43, 0xEA, 0x00, 0x23, ++ 0x41, 0xEA, 0x06, 0x21, 0xA5, 0x80, 0x21, 0x81, 0xE2, 0x80, 0x63, 0x81, ++ 0x01, 0x20, 0xF8, 0xBD, 0xF0, 0xB5, 0x83, 0xB0, 0x15, 0x46, 0x0D, 0xF1, ++ 0x07, 0x02, 0xFD, 0xF7, 0xC9, 0xFB, 0x00, 0x28, 0x45, 0xD0, 0x9D, 0xF8, ++ 0x07, 0x30, 0xC6, 0x1C, 0xC5, 0xF1, 0x04, 0x04, 0x1E, 0x44, 0x04, 0x44, ++ 0x6B, 0x1E, 0x69, 0x1D, 0x1A, 0x5D, 0x03, 0xF8, 0x01, 0x2F, 0x8B, 0x42, ++ 0xFA, 0xD1, 0x05, 0xF1, 0x10, 0x02, 0x19, 0x5D, 0x03, 0xF8, 0x01, 0x1F, ++ 0x93, 0x42, 0xFA, 0xD1, 0x02, 0x7D, 0x47, 0x7D, 0x83, 0x7D, 0xC4, 0x7D, ++ 0xA9, 0x79, 0x42, 0xEA, 0x07, 0x22, 0x43, 0xEA, 0x04, 0x23, 0x6A, 0x82, ++ 0x4A, 0x10, 0x09, 0x07, 0xAB, 0x82, 0x00, 0xF1, 0x18, 0x03, 0x0E, 0xD5, ++ 0x00, 0xF1, 0x1C, 0x01, 0xB1, 0x42, 0x1C, 0xD8, 0x5F, 0x78, 0x04, 0x7E, ++ 0x83, 0x7E, 0xC0, 0x7E, 0x44, 0xEA, 0x07, 0x24, 0x43, 0xEA, 0x00, 0x20, ++ 0xEC, 0x82, 0x0B, 0x46, 0x28, 0x83, 0x12, 0x07, 0x12, 0xD5, 0x1A, 0x1D, ++ 0xB2, 0x42, 0x0C, 0xD8, 0x58, 0x78, 0x19, 0x78, 0x9A, 0x78, 0xDB, 0x78, ++ 0x41, 0xEA, 0x00, 0x21, 0x42, 0xEA, 0x03, 0x23, 0x01, 0x20, 0x69, 0x83, ++ 0xAB, 0x83, 0x03, 0xB0, 0xF0, 0xBD, 0x00, 0x20, 0x03, 0xB0, 0xF0, 0xBD, ++ 0x01, 0x20, 0x03, 0xB0, 0xF0, 0xBD, 0x00, 0xBF, 0x10, 0xB5, 0x82, 0xB0, ++ 0x14, 0x46, 0x0D, 0xF1, 0x07, 0x02, 0xFD, 0xF7, 0xC7, 0xFB, 0x40, 0xB1, ++ 0xD0, 0xF8, 0x03, 0x30, 0xC4, 0xF8, 0xDC, 0x30, 0x00, 0x38, 0x18, 0xBF, ++ 0x01, 0x20, 0x02, 0xB0, 0x10, 0xBD, 0x01, 0x4B, 0xF6, 0xE7, 0x00, 0xBF, ++ 0x00, 0x00, 0x01, 0x80, 0xF8, 0xB5, 0x1D, 0x46, 0x14, 0x46, 0xFD, 0xF7, ++ 0xC7, 0xFB, 0x00, 0x23, 0x2B, 0x70, 0x00, 0xB3, 0xC2, 0x78, 0x61, 0x7C, ++ 0x02, 0xF0, 0x0F, 0x03, 0x99, 0x42, 0x1B, 0xD0, 0x01, 0x26, 0x2E, 0x70, ++ 0x22, 0x74, 0x63, 0x74, 0xB0, 0xF8, 0x05, 0x10, 0x03, 0x79, 0x02, 0x89, ++ 0xB0, 0xF8, 0x0B, 0x70, 0xC5, 0x89, 0x43, 0xEA, 0x01, 0x23, 0x63, 0x60, ++ 0xC1, 0x79, 0x41, 0xEA, 0x02, 0x21, 0x21, 0x60, 0x82, 0x7A, 0x42, 0xEA, ++ 0x07, 0x22, 0xA2, 0x60, 0x43, 0x7B, 0x43, 0xEA, 0x05, 0x23, 0x30, 0x46, ++ 0xE3, 0x60, 0xF8, 0xBD, 0x01, 0x20, 0xF8, 0xBD, 0x10, 0xB5, 0x14, 0x46, ++ 0xFD, 0xF7, 0xAC, 0xFB, 0x40, 0xB1, 0xC3, 0x78, 0x03, 0xF0, 0x07, 0x02, ++ 0xC3, 0xF3, 0xC2, 0x03, 0x22, 0x70, 0x63, 0x70, 0x01, 0x20, 0x10, 0xBD, ++ 0x03, 0x22, 0x05, 0x23, 0x22, 0x70, 0x63, 0x70, 0x10, 0xBD, 0x00, 0xBF, ++ 0x38, 0xB5, 0x07, 0x48, 0x1C, 0x46, 0x15, 0x46, 0xFE, 0x22, 0x10, 0xF0, ++ 0x67, 0xFD, 0x2A, 0x46, 0x21, 0x46, 0x41, 0xF2, 0x03, 0x40, 0xFC, 0xF7, ++ 0x41, 0xFA, 0x00, 0x20, 0x38, 0xBD, 0x00, 0xBF, 0x5A, 0xB9, 0x17, 0x00, ++ 0x70, 0xB5, 0x32, 0x4C, 0x08, 0x78, 0x24, 0x68, 0x01, 0x28, 0x19, 0x46, ++ 0x20, 0x70, 0x29, 0xD0, 0x02, 0x28, 0x05, 0xD0, 0x41, 0xF2, 0x16, 0x40, ++ 0xFC, 0xF7, 0x2E, 0xFA, 0x00, 0x20, 0x70, 0xBD, 0x2B, 0x4C, 0x2C, 0x48, ++ 0x23, 0x68, 0x2C, 0x4E, 0x2C, 0x4D, 0x43, 0xF4, 0x80, 0x33, 0x23, 0x60, ++ 0x03, 0x68, 0x2B, 0x4C, 0x23, 0xF0, 0x00, 0x73, 0x03, 0x60, 0x3F, 0x23, ++ 0x33, 0x60, 0x2B, 0x68, 0x28, 0x48, 0x23, 0xF0, 0x01, 0x03, 0x2B, 0x60, ++ 0x23, 0x6D, 0x23, 0xF4, 0x80, 0x23, 0x23, 0x65, 0x03, 0x69, 0x43, 0xF0, ++ 0x80, 0x03, 0x03, 0x61, 0x41, 0xF2, 0x16, 0x40, 0xFC, 0xF7, 0x0C, 0xFA, ++ 0x00, 0x20, 0x70, 0xBD, 0x20, 0x4B, 0x1B, 0x4C, 0x93, 0xF8, 0xB5, 0x30, ++ 0x0B, 0xBB, 0x23, 0x68, 0x19, 0x4E, 0x1E, 0x4D, 0x43, 0xF0, 0x00, 0x73, ++ 0x23, 0x60, 0x04, 0xF5, 0x00, 0x44, 0x04, 0x23, 0x28, 0x34, 0x33, 0x60, ++ 0x28, 0x60, 0x23, 0x68, 0x23, 0xF4, 0x80, 0x23, 0x23, 0xF0, 0x01, 0x03, ++ 0x23, 0x60, 0x13, 0x4C, 0x13, 0x48, 0x23, 0x6D, 0x43, 0xF4, 0x80, 0x23, ++ 0x23, 0x65, 0x03, 0x69, 0x23, 0xF0, 0x80, 0x03, 0x03, 0x61, 0x41, 0xF2, ++ 0x16, 0x40, 0xFC, 0xF7, 0xE5, 0xF9, 0x00, 0x20, 0x70, 0xBD, 0x23, 0x68, ++ 0x09, 0x48, 0x08, 0x4D, 0x23, 0xF0, 0x00, 0x73, 0x23, 0x60, 0x03, 0x68, ++ 0x24, 0x24, 0x43, 0xF4, 0x00, 0x13, 0x03, 0x60, 0x2C, 0x60, 0xE2, 0xE7, ++ 0x74, 0x36, 0x17, 0x00, 0x44, 0x00, 0x32, 0x40, 0x4C, 0x00, 0x32, 0x40, ++ 0x98, 0x80, 0x32, 0x40, 0x6C, 0x00, 0x32, 0x40, 0x00, 0x60, 0x50, 0x40, ++ 0x00, 0x00, 0x50, 0x40, 0x2C, 0x19, 0x17, 0x00, 0x70, 0x80, 0x32, 0x40, ++ 0xF8, 0xB5, 0x4C, 0x78, 0x08, 0x78, 0x16, 0x46, 0x1D, 0x46, 0x2C, 0xB3, ++ 0x17, 0x4C, 0x18, 0x4B, 0x4F, 0xF4, 0x1E, 0x72, 0x02, 0xFB, 0x00, 0x44, ++ 0x4F, 0xF4, 0xA4, 0x61, 0x94, 0xF8, 0x22, 0x20, 0x01, 0xFB, 0x02, 0x32, ++ 0x02, 0x23, 0x92, 0xF8, 0x62, 0x70, 0x84, 0xF8, 0x30, 0x30, 0x5F, 0xB9, ++ 0x06, 0x22, 0x05, 0x21, 0x41, 0xF2, 0x19, 0x40, 0xFC, 0xF7, 0x3E, 0xF9, ++ 0x07, 0x70, 0x94, 0xF8, 0x22, 0x20, 0x42, 0x70, 0xFC, 0xF7, 0x68, 0xF9, ++ 0x32, 0x46, 0x29, 0x46, 0x41, 0xF2, 0x05, 0x40, 0xFC, 0xF7, 0x9A, 0xF9, ++ 0x00, 0x20, 0xF8, 0xBD, 0x04, 0x4B, 0x4F, 0xF4, 0x1E, 0x72, 0x02, 0xFB, ++ 0x00, 0x30, 0x01, 0x23, 0x80, 0xF8, 0x30, 0x30, 0xEE, 0xE7, 0x00, 0xBF, ++ 0x68, 0x65, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, 0x2D, 0xE9, 0xF8, 0x43, ++ 0x0C, 0x20, 0x0C, 0x46, 0x17, 0x46, 0x00, 0x21, 0x05, 0x22, 0x1E, 0x46, ++ 0x01, 0x23, 0xFC, 0xF7, 0x17, 0xF9, 0xDF, 0xF8, 0x6C, 0x90, 0xDF, 0xF8, ++ 0x6C, 0x80, 0xD9, 0xF8, 0x24, 0x30, 0x05, 0x46, 0x20, 0x78, 0x98, 0x47, ++ 0x23, 0x78, 0x2B, 0x70, 0x28, 0x46, 0xFC, 0xF7, 0x39, 0xF9, 0x20, 0x78, ++ 0xD9, 0xF8, 0xD8, 0x31, 0x4F, 0xF4, 0x1E, 0x75, 0x05, 0xFB, 0x00, 0xF0, ++ 0x00, 0xF5, 0x18, 0x70, 0x40, 0x44, 0x98, 0x47, 0x63, 0x78, 0x43, 0xB9, ++ 0x3A, 0x46, 0x31, 0x46, 0x41, 0xF2, 0x0A, 0x40, 0xFC, 0xF7, 0x5E, 0xF9, ++ 0x00, 0x20, 0xBD, 0xE8, 0xF8, 0x83, 0x02, 0x23, 0x06, 0x22, 0x05, 0x21, ++ 0x41, 0xF2, 0x19, 0x40, 0xFC, 0xF7, 0xEC, 0xF8, 0x00, 0x22, 0x02, 0x70, ++ 0x22, 0x78, 0x05, 0xFB, 0x02, 0x88, 0x98, 0xF8, 0x22, 0x20, 0x42, 0x70, ++ 0xFC, 0xF7, 0x12, 0xF9, 0xE4, 0xE7, 0x00, 0xBF, 0x88, 0x1A, 0x17, 0x00, ++ 0x68, 0x65, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x41, 0x0C, 0x46, 0x89, 0x78, ++ 0x25, 0x78, 0xDF, 0xF8, 0xAC, 0x80, 0x1E, 0x46, 0x17, 0x46, 0x63, 0x78, ++ 0xA1, 0xB1, 0x00, 0x2B, 0x44, 0xD1, 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, ++ 0x05, 0x83, 0x93, 0xF8, 0x31, 0x20, 0x02, 0xF0, 0xFB, 0x02, 0x4F, 0xF4, ++ 0x1E, 0x73, 0x03, 0xFB, 0x05, 0x83, 0x93, 0xF8, 0x2E, 0x11, 0x83, 0xF8, ++ 0x31, 0x20, 0x0F, 0x29, 0x1E, 0xD1, 0x0A, 0xE0, 0x2B, 0xBB, 0x4F, 0xF4, ++ 0x1E, 0x73, 0x03, 0xFB, 0x05, 0x83, 0x93, 0xF8, 0x31, 0x20, 0x22, 0xF0, ++ 0x01, 0x02, 0x83, 0xF8, 0x31, 0x20, 0x04, 0x23, 0x05, 0x22, 0x00, 0x21, ++ 0x41, 0x20, 0xFC, 0xF7, 0xAB, 0xF8, 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, ++ 0x05, 0x85, 0x95, 0xF8, 0x22, 0x30, 0x2A, 0x8C, 0x02, 0x80, 0xC3, 0x70, ++ 0x63, 0x78, 0x83, 0x70, 0xFC, 0xF7, 0xCE, 0xF8, 0x3A, 0x46, 0x31, 0x46, ++ 0x41, 0xF2, 0x0D, 0x40, 0xFC, 0xF7, 0x00, 0xF9, 0x00, 0x20, 0xBD, 0xE8, ++ 0xF0, 0x81, 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, 0x05, 0x83, 0x93, 0xF8, ++ 0x31, 0x20, 0x42, 0xF0, 0x01, 0x02, 0x83, 0xF8, 0x31, 0x20, 0xD8, 0xE7, ++ 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, 0x05, 0x83, 0x93, 0xF8, 0x31, 0x20, ++ 0x42, 0xF0, 0x04, 0x02, 0xB9, 0xE7, 0x00, 0xBF, 0x68, 0x65, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x47, 0x31, 0x20, 0x0D, 0x46, 0x4B, 0x4C, 0x91, 0x46, ++ 0x98, 0x46, 0x05, 0x22, 0x01, 0x23, 0x00, 0x21, 0xFC, 0xF7, 0x72, 0xF8, ++ 0x00, 0x23, 0x84, 0xF8, 0x76, 0x31, 0x95, 0xF8, 0x67, 0x30, 0x82, 0x46, ++ 0x5B, 0xB1, 0x01, 0x23, 0x84, 0xF8, 0x76, 0x31, 0x2F, 0x46, 0x0F, 0xCF, ++ 0x04, 0xF1, 0x0C, 0x06, 0x0F, 0xC6, 0x97, 0xE8, 0x0F, 0x00, 0x86, 0xE8, ++ 0x0F, 0x00, 0x95, 0xF8, 0x68, 0x30, 0x5B, 0xB1, 0x94, 0xF8, 0x76, 0x21, ++ 0x3C, 0x4B, 0x42, 0xF0, 0x02, 0x02, 0x84, 0xF8, 0x76, 0x21, 0x05, 0xF1, ++ 0x20, 0x02, 0x07, 0xCA, 0x83, 0xE8, 0x07, 0x00, 0x95, 0xF8, 0x69, 0x30, ++ 0x93, 0xB1, 0x94, 0xF8, 0x76, 0x31, 0x36, 0x4E, 0x43, 0xF0, 0x04, 0x03, ++ 0x84, 0xF8, 0x76, 0x31, 0x05, 0xF1, 0x2C, 0x07, 0x0F, 0xCF, 0x0F, 0xC6, ++ 0x0F, 0xCF, 0x0F, 0xC6, 0x0F, 0xCF, 0x0F, 0xC6, 0x97, 0xE8, 0x03, 0x00, ++ 0x86, 0xE8, 0x03, 0x00, 0x95, 0xF8, 0x6A, 0x30, 0x2B, 0xB1, 0x94, 0xF8, ++ 0x76, 0x31, 0x43, 0xF0, 0x08, 0x03, 0x84, 0xF8, 0x76, 0x31, 0x95, 0xF8, ++ 0x66, 0x30, 0x84, 0xF8, 0x75, 0x31, 0x4A, 0x46, 0x41, 0x46, 0x41, 0xF2, ++ 0x01, 0x40, 0xFC, 0xF7, 0x8F, 0xF8, 0x94, 0xF8, 0x76, 0x31, 0x13, 0xF0, ++ 0x01, 0x03, 0x14, 0xD1, 0x84, 0xF8, 0x74, 0x31, 0x95, 0xF8, 0x6B, 0x30, ++ 0xB5, 0xF8, 0x64, 0x10, 0x84, 0xF8, 0x77, 0x31, 0x95, 0xF8, 0x6D, 0x20, ++ 0xA1, 0x85, 0x00, 0x2A, 0x14, 0xBF, 0x02, 0x22, 0x01, 0x22, 0x84, 0xF8, ++ 0x78, 0x21, 0xF3, 0xB9, 0x00, 0x20, 0xBD, 0xE8, 0xF0, 0x87, 0xDA, 0xF7, ++ 0xE3, 0xFC, 0x94, 0xF8, 0x76, 0x31, 0x01, 0x30, 0x40, 0x10, 0x5B, 0x07, ++ 0x84, 0xF8, 0x74, 0x01, 0xE2, 0xD5, 0x94, 0xF8, 0x75, 0x21, 0x94, 0xF8, ++ 0x44, 0x30, 0x02, 0x2A, 0x88, 0xBF, 0x94, 0xF8, 0x49, 0x20, 0x4F, 0xEA, ++ 0x93, 0x03, 0x88, 0xBF, 0x03, 0xEA, 0x92, 0x13, 0x03, 0xF0, 0x01, 0x03, ++ 0x84, 0xF8, 0x74, 0x30, 0xD0, 0xE7, 0xFF, 0x23, 0x23, 0x81, 0x50, 0x46, ++ 0x8A, 0xF8, 0x00, 0x20, 0xFC, 0xF7, 0x1A, 0xF8, 0x01, 0x21, 0x05, 0x20, ++ 0xFC, 0xF7, 0xE0, 0xF9, 0x00, 0x20, 0xBD, 0xE8, 0xF0, 0x87, 0x00, 0xBF, ++ 0xE4, 0xB8, 0x17, 0x00, 0x14, 0xB9, 0x17, 0x00, 0x20, 0xB9, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0x41, 0xF2, 0x08, 0x40, 0x97, 0xB0, 0x0C, 0x46, ++ 0x19, 0x46, 0x03, 0x23, 0xFB, 0xF7, 0xD2, 0xFF, 0x4F, 0xF0, 0x00, 0x0A, ++ 0xCD, 0xE9, 0x0C, 0xAA, 0x05, 0x46, 0xAD, 0xF8, 0x2E, 0xA0, 0x8D, 0xF8, ++ 0x2C, 0xA0, 0x08, 0xF0, 0xEB, 0xFB, 0x94, 0xF8, 0x81, 0x70, 0xA2, 0x6F, ++ 0x06, 0x90, 0x4F, 0xF4, 0xA4, 0x61, 0x01, 0xFB, 0x07, 0xF1, 0x12, 0xF0, ++ 0x02, 0x06, 0x07, 0x91, 0x1B, 0xD0, 0x12, 0xF0, 0x04, 0x06, 0x04, 0xF1, ++ 0x14, 0x08, 0x40, 0xF0, 0xDC, 0x81, 0xB1, 0x46, 0x0B, 0xAB, 0x12, 0xF0, ++ 0x20, 0x02, 0x0D, 0xF1, 0x34, 0x0C, 0x02, 0x93, 0x0C, 0xAB, 0xCD, 0xE9, ++ 0x00, 0x3C, 0x18, 0xBF, 0x04, 0xF1, 0x40, 0x02, 0x0D, 0xF1, 0x2E, 0x03, ++ 0x49, 0x46, 0x40, 0x46, 0x00, 0xF0, 0x00, 0xFE, 0x94, 0xF8, 0x81, 0x30, ++ 0x00, 0xE0, 0x3B, 0x46, 0x00, 0x22, 0xDF, 0xF8, 0xC4, 0x93, 0x20, 0x68, ++ 0x0C, 0x99, 0xB4, 0xF8, 0x04, 0xE0, 0xBD, 0xF8, 0x2E, 0xC0, 0x0E, 0x92, ++ 0x8D, 0xF8, 0x55, 0x20, 0x8D, 0xF8, 0x56, 0x20, 0x9D, 0xF8, 0x2C, 0x20, ++ 0x8D, 0xF8, 0x51, 0x30, 0xCD, 0xF8, 0x4A, 0x00, 0x10, 0x91, 0x8D, 0xF8, ++ 0x50, 0x20, 0xD9, 0xF8, 0xC4, 0x31, 0x11, 0x96, 0xAD, 0xF8, 0x4E, 0xE0, ++ 0xAD, 0xF8, 0x48, 0xC0, 0x0D, 0xF1, 0x2D, 0x02, 0x29, 0x46, 0x0E, 0xA8, ++ 0x98, 0x47, 0x83, 0x46, 0x68, 0x70, 0x00, 0x28, 0x40, 0xF0, 0x1C, 0x81, ++ 0x23, 0x46, 0x2E, 0x78, 0x53, 0xF8, 0x06, 0x0F, 0xDF, 0xF8, 0x70, 0x83, ++ 0x59, 0x68, 0x9A, 0x68, 0x93, 0xF8, 0x0C, 0xE0, 0xD4, 0xF8, 0x78, 0xC0, ++ 0x04, 0x96, 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, 0x06, 0xF3, 0x08, 0xEB, ++ 0x03, 0x0A, 0x08, 0x93, 0x0A, 0xF1, 0xB8, 0x03, 0x07, 0xC3, 0x1C, 0xF0, ++ 0x01, 0x0F, 0x83, 0xF8, 0x00, 0xE0, 0x40, 0xF0, 0x06, 0x81, 0xC7, 0x4B, ++ 0x05, 0x93, 0x1C, 0xF0, 0x08, 0x0F, 0x08, 0xD0, 0x04, 0x9A, 0x4F, 0xF4, ++ 0x1E, 0x73, 0x03, 0xFB, 0x02, 0x83, 0x5A, 0x68, 0x42, 0xF0, 0x08, 0x02, ++ 0x5A, 0x60, 0x04, 0x9A, 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, 0x02, 0x83, ++ 0x94, 0xF8, 0x7E, 0x20, 0x83, 0xF8, 0x2E, 0x21, 0x94, 0xF8, 0x7F, 0x10, ++ 0xB4, 0xF8, 0x7C, 0x20, 0x1A, 0x84, 0x83, 0xF8, 0x2F, 0x11, 0x50, 0x46, ++ 0x09, 0x93, 0x00, 0xF0, 0xBB, 0xFE, 0xA2, 0x6F, 0xD2, 0x06, 0x06, 0xD5, ++ 0x94, 0xF9, 0x80, 0x20, 0x94, 0xF8, 0x80, 0x10, 0x00, 0x2A, 0x80, 0xF2, ++ 0x77, 0x81, 0xBB, 0xF1, 0x00, 0x0F, 0x40, 0xF0, 0x7F, 0x81, 0x05, 0x9B, ++ 0xAF, 0x48, 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, 0x07, 0x34, 0x04, 0x9B, ++ 0xB4, 0xF8, 0xE0, 0x20, 0x4F, 0xF4, 0x1E, 0x7B, 0x0B, 0xFB, 0x03, 0x86, ++ 0xD4, 0xF8, 0xB0, 0x34, 0x96, 0xF8, 0x56, 0x11, 0xC6, 0xF8, 0x68, 0xA2, ++ 0x03, 0xF0, 0x01, 0x03, 0xC3, 0xF1, 0x02, 0x03, 0x86, 0xF8, 0x30, 0x30, ++ 0x41, 0xF0, 0x10, 0x01, 0xA3, 0x4B, 0x86, 0xF8, 0x56, 0x11, 0x52, 0xBA, ++ 0x4F, 0xF0, 0x01, 0x0A, 0xC6, 0xF8, 0x64, 0x02, 0xB2, 0x86, 0x08, 0x98, ++ 0x86, 0xF8, 0x70, 0xA2, 0x1A, 0x69, 0x9E, 0x49, 0xD9, 0xF8, 0xE0, 0x31, ++ 0x00, 0xF5, 0x18, 0x70, 0x40, 0x44, 0x11, 0x44, 0x98, 0x47, 0x06, 0x9B, ++ 0xAB, 0x70, 0x00, 0x2B, 0x00, 0xF0, 0x9A, 0x80, 0x94, 0xF8, 0xDE, 0x20, ++ 0x86, 0xF8, 0x24, 0x30, 0x00, 0x2A, 0x40, 0xF0, 0x85, 0x80, 0x94, 0xF8, ++ 0x63, 0x60, 0x0A, 0x36, 0xF6, 0xB2, 0x0B, 0xFB, 0x06, 0xF3, 0x08, 0xEB, ++ 0x03, 0x0B, 0x04, 0x93, 0x9B, 0xF8, 0x24, 0x30, 0x53, 0x45, 0x77, 0xD0, ++ 0x02, 0x23, 0x0C, 0x21, 0x49, 0x20, 0xFB, 0xF7, 0xDB, 0xFE, 0x8B, 0xF8, ++ 0x24, 0xA0, 0x06, 0x70, 0x80, 0xF8, 0x01, 0xA0, 0xFB, 0xF7, 0x04, 0xFF, ++ 0x9B, 0xF8, 0x24, 0x30, 0x00, 0x2B, 0x40, 0xF0, 0x48, 0x81, 0x9B, 0xF8, ++ 0x23, 0x30, 0x09, 0x2B, 0x00, 0xF2, 0x43, 0x81, 0x9B, 0xF8, 0x22, 0x00, ++ 0x05, 0x9C, 0xCD, 0xF8, 0x18, 0xA0, 0x9E, 0x23, 0xA4, 0x21, 0x4F, 0xF4, ++ 0xA4, 0x6C, 0x11, 0xFB, 0x00, 0x31, 0x0C, 0xFB, 0x00, 0x4A, 0x4F, 0x23, ++ 0x46, 0x20, 0x13, 0xFB, 0x06, 0x03, 0x7B, 0x4A, 0x05, 0x98, 0x7B, 0x4C, ++ 0x08, 0x95, 0x08, 0xEB, 0xC3, 0x08, 0x04, 0x9B, 0x00, 0xEB, 0xC1, 0x06, ++ 0x13, 0x44, 0x35, 0x46, 0x1E, 0x46, 0xDB, 0xF8, 0x08, 0x22, 0x1A, 0xB3, ++ 0xEF, 0xF3, 0x10, 0x82, 0xD3, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x73, 0x4B, ++ 0x06, 0x9A, 0x1A, 0x60, 0x22, 0x68, 0xA8, 0xF1, 0x28, 0x00, 0x01, 0x32, ++ 0xA5, 0xF1, 0x28, 0x01, 0x04, 0x90, 0x22, 0x60, 0xFC, 0xF7, 0x18, 0xFC, ++ 0xDB, 0xE9, 0x82, 0x21, 0x04, 0x98, 0xCA, 0xF8, 0xC8, 0x24, 0xCA, 0xF8, ++ 0xCC, 0x14, 0xFC, 0xF7, 0x19, 0xFB, 0x22, 0x68, 0x51, 0x1E, 0x2A, 0xB1, ++ 0x66, 0x4B, 0x21, 0x60, 0x1A, 0x68, 0x09, 0xB9, 0x02, 0xB1, 0x62, 0xB6, ++ 0xDB, 0xF8, 0x30, 0x22, 0x28, 0x46, 0x41, 0x46, 0x0B, 0xF1, 0x08, 0x0B, ++ 0x08, 0x35, 0x0A, 0xF1, 0x08, 0x0A, 0x22, 0xB1, 0xFC, 0xF7, 0xFA, 0xFB, ++ 0x40, 0x46, 0xFC, 0xF7, 0x01, 0xFB, 0x08, 0xF1, 0x08, 0x08, 0x46, 0x45, ++ 0xC5, 0xD1, 0x40, 0x20, 0x08, 0x9D, 0xFC, 0xF7, 0x5B, 0xFA, 0x05, 0x9A, ++ 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x07, 0x23, 0x93, 0xF8, 0xDE, 0x20, ++ 0x05, 0x9C, 0xD9, 0xF8, 0x0C, 0x32, 0x4F, 0xF4, 0xA4, 0x61, 0x01, 0xFB, ++ 0x07, 0x47, 0x07, 0x99, 0x01, 0x32, 0x21, 0x44, 0x08, 0x46, 0x87, 0xF8, ++ 0xDE, 0x20, 0x98, 0x47, 0x28, 0x46, 0xFB, 0xF7, 0x87, 0xFE, 0x00, 0x20, ++ 0x17, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xDA, 0xF8, 0x04, 0x30, 0x05, 0x93, ++ 0x1C, 0xF0, 0x02, 0x0F, 0x43, 0xF0, 0x01, 0x03, 0xCA, 0xF8, 0x04, 0x30, ++ 0x3F, 0xF4, 0xEF, 0xAE, 0x45, 0x4B, 0x93, 0xF8, 0x76, 0x31, 0x09, 0x93, ++ 0x13, 0xF0, 0x01, 0x0B, 0x3F, 0xF4, 0xE7, 0xAE, 0x04, 0xF1, 0x14, 0x0E, ++ 0xBE, 0xE8, 0x0F, 0x00, 0x0A, 0xF1, 0xC8, 0x0B, 0xAB, 0xE8, 0x0F, 0x00, ++ 0x9E, 0xE8, 0x0F, 0x00, 0x05, 0x9E, 0x1C, 0xF0, 0x20, 0x0F, 0x46, 0xF0, ++ 0x03, 0x0E, 0x8B, 0xE8, 0x0F, 0x00, 0xCA, 0xF8, 0x04, 0xE0, 0x22, 0xD0, ++ 0x09, 0x9B, 0x58, 0x07, 0x1F, 0xD5, 0x04, 0xF1, 0x40, 0x0E, 0xBE, 0xE8, ++ 0x0F, 0x00, 0x0A, 0xF1, 0xF4, 0x0B, 0xAB, 0xE8, 0x0F, 0x00, 0xBE, 0xE8, ++ 0x0F, 0x00, 0xAB, 0xE8, 0x0F, 0x00, 0xBE, 0xE8, 0x0F, 0x00, 0xAB, 0xE8, ++ 0x0F, 0x00, 0x9E, 0xE8, 0x03, 0x00, 0x46, 0xF0, 0x23, 0x03, 0xCA, 0xF8, ++ 0x04, 0x30, 0x09, 0x9B, 0x8B, 0xE8, 0x03, 0x00, 0x19, 0x07, 0x04, 0xD5, ++ 0x50, 0x46, 0xEC, 0xF7, 0x85, 0xFF, 0xD4, 0xF8, 0x78, 0xC0, 0x1C, 0xF0, ++ 0x04, 0x0F, 0x1F, 0xD0, 0x24, 0x4B, 0x04, 0x9A, 0x93, 0xF8, 0x76, 0x31, ++ 0x13, 0xF0, 0x02, 0x0F, 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, 0x02, 0x83, ++ 0xD3, 0xF8, 0x04, 0xC0, 0x02, 0xD1, 0x1C, 0xF0, 0x20, 0x0F, 0x0F, 0xD0, ++ 0x04, 0xF1, 0x34, 0x03, 0x93, 0xE8, 0x07, 0x00, 0x04, 0x9E, 0x4F, 0xF4, ++ 0x1E, 0x73, 0x03, 0xFB, 0x06, 0x83, 0x03, 0xF1, 0xE8, 0x0E, 0x8E, 0xE8, ++ 0x07, 0x00, 0x4C, 0xF0, 0x04, 0x02, 0x5A, 0x60, 0x07, 0x9A, 0x0D, 0x4B, ++ 0x05, 0x93, 0x02, 0xF1, 0xEC, 0x01, 0x19, 0x44, 0x50, 0x46, 0x00, 0xF0, ++ 0x53, 0xFB, 0xD4, 0xF8, 0x78, 0xC0, 0x83, 0x46, 0x81, 0xE6, 0x07, 0x4B, ++ 0x05, 0x93, 0x0B, 0x44, 0x04, 0xF1, 0x34, 0x09, 0x93, 0xF8, 0x62, 0x30, ++ 0x02, 0x2B, 0x43, 0xD0, 0x03, 0x2B, 0x2F, 0xD0, 0xA3, 0xB3, 0x56, 0x46, ++ 0x16, 0xE6, 0x00, 0xBF, 0x18, 0x88, 0x17, 0x00, 0x1D, 0x66, 0x12, 0x00, ++ 0x00, 0x10, 0x50, 0x40, 0x40, 0x4B, 0x4C, 0x00, 0xC0, 0x67, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, 0xE4, 0xB8, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, 0x09, 0x9B, 0x0A, 0x09, ++ 0x93, 0xF8, 0x23, 0x00, 0x01, 0xF0, 0x03, 0x01, 0x01, 0xF0, 0x34, 0xF8, ++ 0xBB, 0xF1, 0x00, 0x0F, 0x3F, 0xF4, 0x81, 0xAE, 0x04, 0x9A, 0x4F, 0xF4, ++ 0x1E, 0x73, 0x03, 0xFB, 0x02, 0x83, 0xFF, 0x21, 0x93, 0xF8, 0x23, 0x00, ++ 0x00, 0x22, 0x01, 0xF0, 0x25, 0xF8, 0x74, 0xE6, 0x20, 0x46, 0xFC, 0xF7, ++ 0x61, 0xFF, 0xA2, 0x6F, 0x06, 0x46, 0xE3, 0xE5, 0x09, 0x4B, 0x01, 0xF5, ++ 0xB2, 0x70, 0x03, 0x44, 0xB4, 0xF8, 0x7C, 0x10, 0x18, 0x46, 0xFC, 0xF7, ++ 0x5D, 0xFF, 0xA2, 0x6F, 0x06, 0x46, 0xD7, 0xE5, 0x07, 0x9B, 0x03, 0xF1, ++ 0x5C, 0x00, 0x05, 0x9B, 0xF1, 0xE7, 0x94, 0xF8, 0xDE, 0x20, 0x1B, 0xE7, ++ 0x18, 0x88, 0x17, 0x00, 0xF0, 0xB5, 0x0C, 0x46, 0x21, 0x4D, 0x09, 0x78, ++ 0x6F, 0x68, 0x1E, 0x46, 0x63, 0x78, 0x01, 0x20, 0x83, 0xB0, 0x98, 0x40, ++ 0xC1, 0xB1, 0x38, 0x43, 0x95, 0xF8, 0x77, 0x31, 0x68, 0x60, 0x5B, 0xB1, ++ 0x05, 0x20, 0x01, 0x92, 0xFC, 0xF7, 0x10, 0xF8, 0x01, 0x28, 0x2C, 0xD0, ++ 0x17, 0xF0, 0xFF, 0x0F, 0x23, 0x78, 0x01, 0x9A, 0x0B, 0xD0, 0x63, 0xB1, ++ 0x41, 0xF2, 0x1A, 0x40, 0x31, 0x46, 0xFB, 0xF7, 0xC9, 0xFD, 0x00, 0x20, ++ 0x03, 0xB0, 0xF0, 0xBD, 0x27, 0xEA, 0x00, 0x00, 0xE4, 0xE7, 0x00, 0x2B, ++ 0xF2, 0xD0, 0x01, 0x23, 0x00, 0x21, 0x31, 0x20, 0x01, 0x92, 0xFB, 0xF7, ++ 0x53, 0xFD, 0x6B, 0x68, 0x01, 0x9A, 0x2E, 0x81, 0x63, 0xB1, 0x00, 0x23, ++ 0x03, 0x70, 0x01, 0x92, 0xFB, 0xF7, 0x7A, 0xFD, 0x01, 0x9A, 0x01, 0x21, ++ 0x10, 0x46, 0xFB, 0xF7, 0x3F, 0xFF, 0x00, 0x20, 0x03, 0xB0, 0xF0, 0xBD, ++ 0x95, 0xF8, 0x78, 0x31, 0xF0, 0xE7, 0x02, 0x20, 0xDC, 0xE7, 0x00, 0xBF, ++ 0xE4, 0xB8, 0x17, 0x00, 0x11, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0x10, 0xB5, 0x14, 0x46, 0x0E, 0xDB, 0x0E, 0x4B, 0x19, 0x89, ++ 0xFF, 0x29, 0x04, 0xD0, 0x22, 0x46, 0x41, 0xF2, 0x18, 0x40, 0xFB, 0xF7, ++ 0x91, 0xFD, 0x20, 0x46, 0x00, 0x21, 0xFB, 0xF7, 0x1F, 0xFF, 0x00, 0x20, ++ 0x10, 0xBD, 0x10, 0x46, 0xFB, 0xF7, 0xC2, 0xFF, 0x01, 0x28, 0xEB, 0xD0, ++ 0x05, 0x49, 0x06, 0x48, 0x40, 0xF2, 0x7F, 0x22, 0xFD, 0xF7, 0xFA, 0xFD, ++ 0xE4, 0xE7, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, 0xE4, 0xB8, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x3C, 0xB8, 0x15, 0x00, 0x11, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x10, 0xB5, 0x14, 0x46, 0x0E, 0xDB, ++ 0x0E, 0x4B, 0x19, 0x89, 0xFF, 0x29, 0x04, 0xD0, 0x22, 0x46, 0x41, 0xF2, ++ 0x1A, 0x40, 0xFB, 0xF7, 0x65, 0xFD, 0x20, 0x46, 0x00, 0x21, 0xFB, 0xF7, ++ 0xF3, 0xFE, 0x00, 0x20, 0x10, 0xBD, 0x10, 0x46, 0xFB, 0xF7, 0x96, 0xFF, ++ 0x01, 0x28, 0xEB, 0xD0, 0x05, 0x49, 0x06, 0x48, 0x40, 0xF2, 0x15, 0x32, ++ 0xFD, 0xF7, 0xCE, 0xFD, 0xE4, 0xE7, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, ++ 0xE4, 0xB8, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x3C, 0xB8, 0x15, 0x00, ++ 0x70, 0xB5, 0x0C, 0x46, 0x41, 0xF2, 0x0F, 0x40, 0x19, 0x46, 0xC8, 0x23, ++ 0xFB, 0xF7, 0xDA, 0xFC, 0x22, 0x78, 0x37, 0x49, 0x4F, 0xF4, 0x1E, 0x73, ++ 0x03, 0xFB, 0x02, 0x13, 0x06, 0x46, 0xD3, 0xF8, 0x4C, 0x51, 0x02, 0x70, ++ 0x00, 0x2D, 0x5C, 0xD0, 0xB5, 0xF8, 0xB4, 0x00, 0xB5, 0xF8, 0x90, 0x10, ++ 0xB5, 0xF8, 0x92, 0x20, 0xD5, 0xF8, 0x94, 0x30, 0xB3, 0x60, 0x70, 0x80, ++ 0xB1, 0x80, 0xF2, 0x80, 0x95, 0xF8, 0xA4, 0x30, 0x33, 0x73, 0xB5, 0xF8, ++ 0x98, 0x30, 0x73, 0x73, 0x08, 0x22, 0x05, 0xF1, 0x88, 0x01, 0x06, 0xF1, ++ 0x0E, 0x00, 0x10, 0xF0, 0x3D, 0xF8, 0x78, 0x22, 0x29, 0x1D, 0x06, 0xF1, ++ 0x16, 0x00, 0x10, 0xF0, 0x37, 0xF8, 0xB5, 0xF8, 0xB4, 0x30, 0x83, 0xB1, ++ 0x00, 0x24, 0x00, 0x22, 0xE1, 0xB2, 0x28, 0x46, 0x0C, 0xF0, 0x2C, 0xFE, ++ 0xA3, 0xB2, 0x06, 0xEB, 0x83, 0x03, 0xB5, 0xF8, 0xB4, 0x20, 0xC3, 0xF8, ++ 0x9C, 0x00, 0x01, 0x34, 0xA3, 0xB2, 0x9A, 0x42, 0xEF, 0xD8, 0xEF, 0xF3, ++ 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x16, 0x4B, 0x01, 0x22, ++ 0x1A, 0x60, 0x05, 0xF1, 0x7C, 0x03, 0x07, 0xCB, 0x14, 0x4C, 0xC6, 0xF8, ++ 0x8E, 0x00, 0x23, 0x68, 0xC6, 0xF8, 0x92, 0x10, 0x01, 0x33, 0xC6, 0xF8, ++ 0x96, 0x20, 0x28, 0x46, 0x00, 0x22, 0x0A, 0x21, 0x23, 0x60, 0x0C, 0xF0, ++ 0x07, 0xFE, 0x23, 0x68, 0xC6, 0xF8, 0xC4, 0x00, 0x33, 0xB1, 0x0A, 0x4A, ++ 0x01, 0x3B, 0x12, 0x68, 0x23, 0x60, 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, ++ 0x30, 0x46, 0xFB, 0xF7, 0xA3, 0xFC, 0x00, 0x20, 0x70, 0xBD, 0x45, 0x80, ++ 0x30, 0x46, 0xFB, 0xF7, 0x9D, 0xFC, 0x00, 0x20, 0x70, 0xBD, 0x00, 0xBF, ++ 0x68, 0x65, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, ++ 0x70, 0xB5, 0x23, 0x4A, 0x0B, 0x78, 0x12, 0x68, 0x0C, 0x46, 0x22, 0x49, ++ 0xB2, 0xF9, 0x00, 0x20, 0x4F, 0xF4, 0x1E, 0x70, 0x00, 0xFB, 0x03, 0x13, ++ 0x00, 0x2A, 0xD3, 0xF8, 0x4C, 0x51, 0x22, 0xDB, 0x66, 0x88, 0x4F, 0xF6, ++ 0xFF, 0x73, 0x9E, 0x42, 0x0B, 0xD1, 0x95, 0xF8, 0xA2, 0x30, 0xA5, 0xF8, ++ 0xBA, 0x60, 0x03, 0xF0, 0xCF, 0x03, 0x85, 0xF8, 0xA2, 0x30, 0x1B, 0x06, ++ 0x1C, 0xD4, 0x00, 0x20, 0x70, 0xBD, 0x31, 0x46, 0x28, 0x46, 0x0C, 0xF0, ++ 0x65, 0xFD, 0x00, 0x28, 0xF7, 0xD0, 0x95, 0xF8, 0xA2, 0x30, 0xA5, 0xF8, ++ 0xBA, 0x60, 0x23, 0xF0, 0x30, 0x03, 0x43, 0xF0, 0x10, 0x03, 0x85, 0xF8, ++ 0xA2, 0x30, 0x00, 0x20, 0x70, 0xBD, 0x00, 0x2D, 0xDA, 0xD1, 0x0B, 0x49, ++ 0x0B, 0x48, 0x40, 0xF2, 0xAF, 0x32, 0xFD, 0xF7, 0x0B, 0xFD, 0xD3, 0xE7, ++ 0x20, 0x78, 0x0C, 0xF0, 0xC9, 0xFB, 0x95, 0xF8, 0xA2, 0x30, 0x03, 0xF0, ++ 0x7F, 0x03, 0x85, 0xF8, 0xA2, 0x30, 0x00, 0x20, 0x70, 0xBD, 0x00, 0xBF, ++ 0x38, 0x36, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x68, 0x8E, 0x15, 0x00, 0xF8, 0xB5, 0x05, 0x20, 0x0E, 0x46, 0x15, 0x46, ++ 0x1C, 0x46, 0xFB, 0xF7, 0xAF, 0xFE, 0x01, 0x28, 0x4F, 0xD0, 0x2A, 0x46, ++ 0x0C, 0x23, 0x21, 0x46, 0x41, 0xF2, 0x12, 0x40, 0xFB, 0xF7, 0x04, 0xFC, ++ 0x37, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x05, 0x46, ++ 0x2A, 0xDB, 0x35, 0x4B, 0x1C, 0x7C, 0xDA, 0xF7, 0x7F, 0xF8, 0x00, 0x28, ++ 0x30, 0xD1, 0xF3, 0x7A, 0x53, 0xB1, 0x32, 0x4B, 0x32, 0x49, 0x9A, 0x68, ++ 0xD1, 0xF8, 0x2C, 0x12, 0x11, 0x66, 0xA3, 0xF5, 0x40, 0x63, 0x4F, 0xF4, ++ 0x80, 0x72, 0x1A, 0x60, 0x2E, 0x4F, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, ++ 0x04, 0x77, 0x3C, 0x6C, 0x4C, 0xB3, 0x23, 0x7E, 0x2B, 0x70, 0xB3, 0x7A, ++ 0xE3, 0xB9, 0x23, 0x1D, 0x03, 0xCB, 0x1B, 0x88, 0x6B, 0x81, 0xC5, 0xF8, ++ 0x02, 0x00, 0xC5, 0xF8, 0x06, 0x10, 0x28, 0x46, 0xFB, 0xF7, 0x04, 0xFC, ++ 0x00, 0x20, 0xF8, 0xBD, 0x1F, 0x4F, 0x3C, 0x7C, 0xFF, 0x2C, 0xD2, 0xD1, ++ 0x21, 0x49, 0x22, 0x48, 0x40, 0xF2, 0xEB, 0x32, 0xFD, 0xF7, 0xAA, 0xFC, ++ 0x3C, 0x7C, 0xCA, 0xE7, 0xF0, 0x7A, 0xDA, 0xF7, 0x53, 0xF8, 0xCA, 0xE7, ++ 0x1D, 0x48, 0xFC, 0xF7, 0xD1, 0xF8, 0x01, 0x28, 0x0A, 0xD0, 0x3C, 0x6C, ++ 0xDB, 0xE7, 0x02, 0x20, 0xF8, 0xBD, 0xFF, 0x23, 0x28, 0x46, 0x2B, 0x70, ++ 0xFB, 0xF7, 0xE4, 0xFB, 0x20, 0x46, 0xF8, 0xBD, 0x05, 0x22, 0x0C, 0x23, ++ 0x00, 0x21, 0x3B, 0x20, 0xFB, 0xF7, 0xAC, 0xFB, 0x39, 0x6C, 0x03, 0x46, ++ 0x09, 0x7E, 0x03, 0xF8, 0x02, 0x1B, 0x31, 0x89, 0x37, 0x68, 0x74, 0x68, ++ 0xC0, 0xF8, 0x02, 0x70, 0x19, 0x81, 0x5C, 0x60, 0xFB, 0xF7, 0xCE, 0xFB, ++ 0x31, 0x68, 0x72, 0x68, 0x33, 0x89, 0x6B, 0x81, 0xC5, 0xF8, 0x02, 0x10, ++ 0xC5, 0xF8, 0x06, 0x20, 0xBD, 0xE7, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, ++ 0x00, 0x88, 0x17, 0x00, 0x00, 0xED, 0x00, 0xE0, 0x88, 0x1A, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x60, 0xB8, 0x15, 0x00, ++ 0x08, 0x88, 0x17, 0x00, 0xF8, 0xB5, 0x05, 0x20, 0x0C, 0x46, 0x15, 0x46, ++ 0x1E, 0x46, 0xFB, 0xF7, 0x1F, 0xFE, 0x01, 0x28, 0x3C, 0xD0, 0x1F, 0x4F, ++ 0x3B, 0x68, 0x73, 0xB1, 0x22, 0x78, 0xB2, 0xB1, 0x61, 0x78, 0x01, 0x22, ++ 0x8A, 0x40, 0x13, 0x43, 0x31, 0x46, 0x2A, 0x46, 0x41, 0xF2, 0x18, 0x40, ++ 0x3B, 0x60, 0xFB, 0xF7, 0xD3, 0xFB, 0x00, 0x20, 0xF8, 0xBD, 0x23, 0x78, ++ 0x3B, 0xB9, 0x2A, 0x46, 0x31, 0x46, 0x41, 0xF2, 0x18, 0x40, 0xFB, 0xF7, ++ 0xC9, 0xFB, 0x00, 0x20, 0xF8, 0xBD, 0x01, 0x23, 0x00, 0x21, 0x2A, 0x46, ++ 0x22, 0x20, 0xFB, 0xF7, 0x59, 0xFB, 0x23, 0x78, 0x61, 0x78, 0x8B, 0xB1, ++ 0x3A, 0x68, 0x01, 0x23, 0x8B, 0x40, 0x13, 0x43, 0xB3, 0xFA, 0x83, 0xF2, ++ 0x52, 0x09, 0x3B, 0x60, 0x3E, 0x81, 0x02, 0x70, 0xFB, 0xF7, 0x7A, 0xFB, ++ 0x28, 0x46, 0x01, 0x21, 0xFB, 0xF7, 0x40, 0xFD, 0x00, 0x20, 0xF8, 0xBD, ++ 0x3B, 0x68, 0x01, 0x22, 0x8A, 0x40, 0x23, 0xEA, 0x02, 0x03, 0xEB, 0xE7, ++ 0x02, 0x20, 0xF8, 0xBD, 0xE4, 0xB8, 0x17, 0x00, 0xF8, 0xB5, 0x05, 0x20, ++ 0x0D, 0x46, 0x17, 0x46, 0x1E, 0x46, 0xFB, 0xF7, 0xD5, 0xFD, 0x01, 0x28, ++ 0x24, 0xD0, 0x13, 0x4C, 0x2B, 0x78, 0x61, 0x68, 0x00, 0x3B, 0x18, 0xBF, ++ 0x01, 0x23, 0x84, 0xF8, 0x77, 0x31, 0x81, 0xB9, 0x01, 0x23, 0x05, 0x22, ++ 0x31, 0x20, 0xFB, 0xF7, 0x23, 0xFB, 0x94, 0xF8, 0x77, 0x31, 0xFF, 0x22, ++ 0x22, 0x81, 0x73, 0xB9, 0x03, 0x70, 0xFB, 0xF7, 0x4B, 0xFB, 0x01, 0x21, ++ 0x05, 0x20, 0xFB, 0xF7, 0x11, 0xFD, 0x3A, 0x46, 0x31, 0x46, 0x41, 0xF2, ++ 0x14, 0x40, 0xFB, 0xF7, 0x79, 0xFB, 0x00, 0x20, 0xF8, 0xBD, 0x94, 0xF8, ++ 0x78, 0x31, 0xED, 0xE7, 0x02, 0x20, 0xF8, 0xBD, 0xE4, 0xB8, 0x17, 0x00, ++ 0x08, 0xB5, 0x4F, 0xF4, 0xBE, 0x72, 0x00, 0x21, 0x09, 0x48, 0xD8, 0xF7, ++ 0xFB, 0xFE, 0x00, 0x21, 0x05, 0x20, 0xFB, 0xF7, 0xF7, 0xFC, 0x04, 0xF0, ++ 0xFB, 0xFF, 0x04, 0xF0, 0x7D, 0xFA, 0x02, 0xF0, 0x25, 0xF9, 0x09, 0xF0, ++ 0x41, 0xF9, 0xBD, 0xE8, 0x08, 0x40, 0x0E, 0xF0, 0xD5, 0xB8, 0x00, 0xBF, ++ 0xE4, 0xB8, 0x17, 0x00, 0xA8, 0xB9, 0x10, 0x4B, 0x93, 0xF8, 0x72, 0x01, ++ 0x76, 0x33, 0xC8, 0xB1, 0x00, 0xEB, 0x40, 0x00, 0x10, 0xB4, 0x03, 0xEB, ++ 0x40, 0x04, 0x01, 0xE0, 0xA3, 0x42, 0x0D, 0xD0, 0x1A, 0x88, 0x8A, 0x42, ++ 0x18, 0x46, 0x03, 0xF1, 0x06, 0x03, 0xF7, 0xD1, 0x5D, 0xF8, 0x04, 0x4B, ++ 0x70, 0x47, 0x05, 0x4B, 0x93, 0xF8, 0x73, 0x01, 0xCA, 0x33, 0xE8, 0xE7, ++ 0x00, 0x20, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, 0x70, 0x47, 0x00, 0xBF, ++ 0xE4, 0xB8, 0x17, 0x00, 0xF0, 0xB9, 0x4B, 0x1E, 0x0D, 0x2B, 0x31, 0xD8, ++ 0x0E, 0x29, 0x32, 0xD0, 0x01, 0xEB, 0x81, 0x01, 0x01, 0xF6, 0x67, 0x11, ++ 0x19, 0x4B, 0x93, 0xF8, 0x72, 0x01, 0x76, 0x33, 0x60, 0xB3, 0x00, 0xEB, ++ 0x40, 0x00, 0x10, 0xB4, 0x03, 0xEB, 0x40, 0x04, 0x01, 0xE0, 0xA3, 0x42, ++ 0x1A, 0xD0, 0x1A, 0x88, 0x8A, 0x42, 0x18, 0x46, 0x03, 0xF1, 0x06, 0x03, ++ 0xF7, 0xD1, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, 0x01, 0x28, 0x06, 0xD0, ++ 0x4F, 0xF6, 0xFF, 0x71, 0x0C, 0x4B, 0x93, 0xF8, 0x73, 0x01, 0xCA, 0x33, ++ 0xE4, 0xE7, 0x4B, 0x1E, 0xA4, 0x2B, 0xF5, 0xD8, 0x01, 0xEB, 0x81, 0x01, ++ 0x01, 0xF5, 0x9C, 0x51, 0x08, 0x31, 0xF1, 0xE7, 0x00, 0x20, 0x5D, 0xF8, ++ 0x04, 0x4B, 0x70, 0x47, 0x4F, 0xF6, 0xFF, 0x71, 0xD0, 0xE7, 0x40, 0xF6, ++ 0xB4, 0x11, 0xCD, 0xE7, 0x70, 0x47, 0x00, 0xBF, 0xE4, 0xB8, 0x17, 0x00, ++ 0xF0, 0xB4, 0x03, 0x46, 0x42, 0x48, 0x5C, 0x68, 0x90, 0xF8, 0x75, 0x21, ++ 0xA5, 0x06, 0x2E, 0xD5, 0x93, 0xF8, 0xFA, 0x70, 0x93, 0xF8, 0xFC, 0x50, ++ 0x93, 0xF8, 0x01, 0x61, 0x7C, 0x10, 0xFF, 0x06, 0x4F, 0xEA, 0xD5, 0x05, ++ 0x55, 0xD5, 0x04, 0x24, 0x05, 0xEA, 0xD6, 0x16, 0x90, 0xF8, 0x74, 0x50, ++ 0xB3, 0xF8, 0xC8, 0x00, 0xB5, 0x42, 0x28, 0xBF, 0x35, 0x46, 0x94, 0x42, ++ 0x28, 0xBF, 0x14, 0x46, 0x83, 0xF8, 0x2C, 0x41, 0x91, 0xF8, 0xD9, 0x20, ++ 0x04, 0x2A, 0x46, 0xD0, 0xA2, 0x42, 0x28, 0xBF, 0x22, 0x46, 0x04, 0x2A, ++ 0x43, 0xD0, 0xD2, 0xB2, 0x00, 0xF0, 0x0C, 0x00, 0x0C, 0x38, 0x83, 0xF8, ++ 0x2D, 0x21, 0x83, 0xF8, 0x30, 0x51, 0x18, 0xBF, 0x01, 0x20, 0xF0, 0xBC, ++ 0x70, 0x47, 0x90, 0xF8, 0x74, 0x51, 0x60, 0x07, 0x13, 0xD5, 0xD3, 0xF8, ++ 0xE8, 0x00, 0x00, 0xF0, 0x0C, 0x04, 0x04, 0x2C, 0x44, 0xD0, 0x08, 0x2C, ++ 0x0C, 0xBF, 0x04, 0x24, 0x02, 0x24, 0xC0, 0xF3, 0x02, 0x20, 0x04, 0x28, ++ 0x27, 0xD8, 0x85, 0x42, 0x28, 0xBF, 0x05, 0x46, 0xB3, 0xF8, 0xC8, 0x00, ++ 0xCD, 0xE7, 0xB3, 0xF8, 0xC8, 0x00, 0x10, 0xF0, 0x02, 0x04, 0xC0, 0xF3, ++ 0x01, 0x26, 0x28, 0xD0, 0x01, 0x2A, 0x28, 0xBF, 0x01, 0x22, 0x83, 0xF8, ++ 0x2C, 0x21, 0x14, 0x46, 0x91, 0xF8, 0xD9, 0x20, 0xB5, 0x42, 0x28, 0xBF, ++ 0x35, 0x46, 0x04, 0x2A, 0xC2, 0xD1, 0x02, 0x2C, 0x22, 0x46, 0x28, 0xBF, ++ 0x02, 0x22, 0xD2, 0xB2, 0xC2, 0xE7, 0x67, 0x07, 0x09, 0xD5, 0x03, 0x24, ++ 0xA6, 0xE7, 0x04, 0x2C, 0xF3, 0xD1, 0x03, 0x22, 0xBA, 0xE7, 0xB3, 0xF8, ++ 0xC8, 0x00, 0x00, 0x25, 0xA7, 0xE7, 0xA6, 0x07, 0x47, 0xBF, 0x05, 0xF0, ++ 0x01, 0x06, 0x02, 0x24, 0x04, 0xF0, 0x01, 0x04, 0x05, 0xF0, 0x01, 0x06, ++ 0x96, 0xE7, 0xB5, 0x42, 0x83, 0xF8, 0x2C, 0x41, 0x28, 0xBF, 0x35, 0x46, ++ 0x22, 0x46, 0xA5, 0xE7, 0x03, 0x24, 0xBC, 0xE7, 0xE4, 0xB8, 0x17, 0x00, ++ 0x00, 0xF0, 0x03, 0x00, 0x01, 0x28, 0x04, 0xD0, 0x02, 0x28, 0x14, 0xBF, ++ 0x07, 0x20, 0x09, 0x20, 0x70, 0x47, 0x08, 0x20, 0x70, 0x47, 0x00, 0xBF, ++ 0x00, 0xF0, 0x03, 0x00, 0x01, 0x28, 0x04, 0xD0, 0x02, 0x28, 0x14, 0xBF, ++ 0x07, 0x20, 0x0B, 0x20, 0x70, 0x47, 0x09, 0x20, 0x70, 0x47, 0x00, 0xBF, ++ 0x10, 0xB4, 0x0E, 0x22, 0x04, 0x46, 0x07, 0x20, 0x44, 0xFA, 0x02, 0xF3, ++ 0x03, 0xF0, 0x03, 0x03, 0x03, 0x2B, 0x00, 0xF1, 0xFF, 0x31, 0xA2, 0xF1, ++ 0x02, 0x02, 0x02, 0xD1, 0x11, 0xF0, 0xFF, 0x00, 0xF2, 0xD1, 0x5D, 0xF8, ++ 0x04, 0x4B, 0x70, 0x47, 0xC3, 0x78, 0x33, 0xB9, 0x83, 0x78, 0x33, 0xB9, ++ 0x40, 0x78, 0x00, 0x28, 0x18, 0xBF, 0x01, 0x20, 0x70, 0x47, 0x03, 0x20, ++ 0x70, 0x47, 0x02, 0x20, 0x70, 0x47, 0x00, 0xBF, 0x00, 0x23, 0x40, 0xFA, ++ 0x03, 0xF2, 0x12, 0xF0, 0x01, 0x0F, 0xD9, 0xB2, 0x03, 0xF1, 0x01, 0x03, ++ 0x02, 0xD1, 0x0C, 0x2B, 0xF5, 0xD1, 0x19, 0x46, 0x08, 0x46, 0x70, 0x47, ++ 0x68, 0xB1, 0x00, 0x23, 0xC3, 0xF1, 0x0B, 0x02, 0x40, 0xFA, 0x02, 0xF2, ++ 0xD2, 0x07, 0xD9, 0xB2, 0x03, 0xF1, 0x01, 0x03, 0x05, 0xD4, 0x0C, 0x2B, ++ 0xF4, 0xD1, 0xFF, 0x20, 0x70, 0x47, 0x0C, 0x20, 0x70, 0x47, 0xC1, 0xF1, ++ 0x0B, 0x01, 0xC8, 0xB2, 0x70, 0x47, 0x00, 0xBF, 0xF0, 0xB5, 0xDD, 0xE9, ++ 0x05, 0x56, 0x00, 0x24, 0x1C, 0x80, 0x2C, 0x60, 0x34, 0x60, 0x50, 0xB3, ++ 0x84, 0x78, 0xC4, 0xF3, 0x82, 0x0C, 0xBC, 0xF1, 0x02, 0x0F, 0x04, 0xF0, ++ 0x03, 0x04, 0x23, 0xDC, 0x4F, 0xF0, 0x01, 0x0C, 0x04, 0xF1, 0x0D, 0x00, ++ 0x4F, 0xF0, 0x01, 0x0E, 0x0E, 0xFA, 0x00, 0xF0, 0x07, 0x9F, 0x01, 0x38, ++ 0x80, 0xB2, 0x87, 0xF8, 0x00, 0xC0, 0x18, 0x80, 0xF9, 0xB1, 0x09, 0x68, ++ 0xC1, 0xF3, 0xC2, 0x51, 0x01, 0xF1, 0x0D, 0x03, 0x0E, 0xFA, 0x03, 0xF3, ++ 0x01, 0x3B, 0x2B, 0x60, 0x4A, 0xB1, 0x07, 0x29, 0x11, 0xD1, 0xD3, 0x78, ++ 0xC3, 0xF3, 0xC1, 0x03, 0x14, 0x33, 0x0E, 0xFA, 0x03, 0xF7, 0x01, 0x3F, ++ 0x37, 0x60, 0xF0, 0xBD, 0xAC, 0xF1, 0x03, 0x00, 0x4F, 0xF0, 0x01, 0x0C, ++ 0x0C, 0xFA, 0x00, 0xFC, 0x5F, 0xFA, 0x8C, 0xFC, 0xD4, 0xE7, 0x33, 0x60, ++ 0xF0, 0xBD, 0x00, 0x2A, 0xF1, 0xD0, 0x03, 0x2C, 0x01, 0xD0, 0x30, 0x60, ++ 0xF0, 0xBD, 0xD3, 0x78, 0xC3, 0xF3, 0xC1, 0x03, 0x10, 0x33, 0x0E, 0xFA, ++ 0x03, 0xF7, 0x01, 0x3F, 0x37, 0x60, 0xF0, 0xBD, 0x00, 0xF0, 0x7F, 0x03, ++ 0x48, 0x2B, 0x31, 0xD8, 0x10, 0xF0, 0x7E, 0x0F, 0x2C, 0xD0, 0x02, 0x3B, ++ 0x46, 0x2B, 0x29, 0xD8, 0xDF, 0xE8, 0x03, 0xF0, 0x26, 0x28, 0x24, 0x28, ++ 0x28, 0x28, 0x28, 0x28, 0x28, 0x35, 0x37, 0x28, 0x28, 0x28, 0x28, 0x28, ++ 0x39, 0x28, 0x28, 0x28, 0x3B, 0x28, 0x3D, 0x28, 0x28, 0x28, 0x28, 0x28, ++ 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x3F, 0x28, 0x28, 0x28, 0x28, 0x28, ++ 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x41, 0x28, 0x28, 0x28, 0x28, 0x28, ++ 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, ++ 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x33, 0x00, 0x01, 0x20, 0x70, 0x47, ++ 0x00, 0x20, 0x70, 0x47, 0xFF, 0x20, 0x70, 0x47, 0x60, 0x2B, 0x04, 0xD0, ++ 0x6C, 0x2B, 0x14, 0xBF, 0xFF, 0x20, 0x0B, 0x20, 0x70, 0x47, 0x0A, 0x20, ++ 0x70, 0x47, 0x09, 0x20, 0x70, 0x47, 0x02, 0x20, 0x70, 0x47, 0x04, 0x20, ++ 0x70, 0x47, 0x05, 0x20, 0x70, 0x47, 0x03, 0x20, 0x70, 0x47, 0x06, 0x20, ++ 0x70, 0x47, 0x07, 0x20, 0x70, 0x47, 0x08, 0x20, 0x70, 0x47, 0x00, 0xBF, ++ 0x2D, 0xE9, 0xF8, 0x4F, 0x90, 0xF8, 0x00, 0xB0, 0xBB, 0xF1, 0x00, 0x0F, ++ 0x34, 0xD0, 0xDF, 0xF8, 0x70, 0x80, 0xDF, 0xF8, 0x70, 0xA0, 0xDF, 0xF8, ++ 0x70, 0x90, 0x05, 0x46, 0x0E, 0x46, 0x04, 0x46, 0x00, 0x27, 0x9E, 0xB9, ++ 0x60, 0x78, 0xFF, 0xF7, 0x9B, 0xFF, 0xD8, 0xF8, 0x00, 0x30, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0x4F, 0xF0, 0x01, 0x03, 0x0E, 0xDB, 0x0B, 0x28, ++ 0x0E, 0xDD, 0x01, 0x34, 0x63, 0x1B, 0x5B, 0x45, 0xED, 0xDB, 0x38, 0x46, ++ 0xBD, 0xE8, 0xF8, 0x8F, 0x94, 0xF9, 0x01, 0x30, 0x60, 0x78, 0x00, 0x2B, ++ 0xE7, 0xDB, 0xF2, 0xE7, 0x0B, 0x28, 0x04, 0xDC, 0x03, 0xFA, 0x00, 0xF0, ++ 0x07, 0x43, 0xBF, 0xB2, 0xEB, 0xE7, 0x4F, 0xF4, 0x15, 0x72, 0x51, 0x46, ++ 0x48, 0x46, 0xFD, 0xF7, 0xC5, 0xF9, 0x95, 0xF8, 0x00, 0xB0, 0xE2, 0xE7, ++ 0x5F, 0x46, 0x38, 0x46, 0xBD, 0xE8, 0xF8, 0x8F, 0x38, 0x36, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x94, 0xB8, 0x15, 0x00, 0xF0, 0xB4, 0x00, 0x24, ++ 0x4F, 0xF6, 0xFF, 0x77, 0x03, 0x26, 0x40, 0xFA, 0x04, 0xF3, 0x03, 0xF0, ++ 0x03, 0x03, 0x06, 0xFA, 0x04, 0xF2, 0x41, 0xFA, 0x04, 0xF5, 0x03, 0x2B, ++ 0x27, 0xEA, 0x02, 0x02, 0x05, 0xF0, 0x03, 0x05, 0x0A, 0xD0, 0x03, 0x2D, ++ 0x08, 0xD0, 0xAB, 0x42, 0x28, 0xBF, 0x2B, 0x46, 0xA3, 0x40, 0x02, 0x34, ++ 0x1A, 0x43, 0x10, 0x2C, 0x97, 0xB2, 0xE6, 0xD1, 0x38, 0x46, 0xF0, 0xBC, ++ 0x70, 0x47, 0x00, 0xBF, 0x08, 0x4B, 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, ++ 0x00, 0x30, 0x41, 0xF2, 0x21, 0x42, 0xD0, 0xF8, 0x90, 0x31, 0x98, 0x78, ++ 0x41, 0xF2, 0x21, 0x53, 0x01, 0x28, 0x14, 0xBF, 0x10, 0x46, 0x18, 0x46, ++ 0x70, 0x47, 0x00, 0xBF, 0x18, 0x88, 0x17, 0x00, 0xD0, 0xF8, 0xDC, 0x30, ++ 0xC3, 0xF3, 0x05, 0x60, 0x5B, 0x00, 0x54, 0xBF, 0x40, 0xF4, 0x80, 0x70, ++ 0x40, 0xF4, 0x40, 0x70, 0x70, 0x47, 0x00, 0xBF, 0x10, 0xB5, 0x04, 0x46, ++ 0x0C, 0xF0, 0x86, 0xFB, 0x03, 0x4B, 0x20, 0x46, 0xD3, 0xF8, 0x5C, 0x31, ++ 0xBD, 0xE8, 0x10, 0x40, 0x18, 0x47, 0x00, 0xBF, 0x88, 0x1A, 0x17, 0x00, ++ 0x38, 0xB5, 0x16, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0x05, 0x46, 0x90, 0xF8, 0xB8, 0x00, 0x18, 0xDB, 0x68, 0xB1, 0x05, 0xF1, ++ 0xB8, 0x03, 0x1C, 0x18, 0x00, 0x20, 0x13, 0xF8, 0x01, 0x2F, 0x22, 0xF0, ++ 0x80, 0x01, 0x81, 0x42, 0xC8, 0xBF, 0x02, 0xF0, 0x7F, 0x00, 0xA3, 0x42, ++ 0xF5, 0xD1, 0xFF, 0xF7, 0xFF, 0xFE, 0x01, 0x46, 0x28, 0x46, 0x0C, 0xF0, ++ 0x5F, 0xF9, 0x00, 0x23, 0x85, 0xF8, 0x56, 0x31, 0x38, 0xBD, 0x00, 0x28, ++ 0xE5, 0xD1, 0x05, 0x48, 0x05, 0x49, 0x40, 0xF2, 0xC1, 0x22, 0xFD, 0xF7, ++ 0x25, 0xF9, 0x95, 0xF8, 0xB8, 0x00, 0xDB, 0xE7, 0x38, 0x36, 0x17, 0x00, ++ 0xB0, 0xB8, 0x15, 0x00, 0x70, 0x79, 0x15, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0x90, 0xF8, 0x56, 0x31, 0xD0, 0xF8, 0x48, 0x71, 0x99, 0xB0, 0x00, 0x2B, ++ 0x00, 0xF0, 0xDB, 0x80, 0xFA, 0x6B, 0x09, 0x92, 0x7A, 0x68, 0x05, 0x92, ++ 0x07, 0xF1, 0x14, 0x04, 0xBA, 0x68, 0x07, 0x92, 0x10, 0xAE, 0x0D, 0xF1, ++ 0x50, 0x08, 0x05, 0x46, 0x22, 0x46, 0xB4, 0x46, 0x40, 0x46, 0x07, 0xF1, ++ 0x24, 0x0B, 0x52, 0xF8, 0x04, 0x1B, 0x4C, 0xF8, 0x04, 0x1B, 0x5A, 0x45, ++ 0xD1, 0x68, 0x40, 0xF8, 0x04, 0x1B, 0xF6, 0xD1, 0x13, 0xF0, 0x01, 0x02, ++ 0x06, 0x92, 0x40, 0xF0, 0xC0, 0x80, 0x09, 0x9A, 0xC2, 0xF3, 0xC0, 0x02, ++ 0x06, 0x92, 0x9A, 0x06, 0x00, 0xF1, 0x16, 0x81, 0x98, 0x07, 0x1A, 0xD5, ++ 0xDF, 0xF8, 0x64, 0x93, 0x06, 0xF1, 0x10, 0x0E, 0x31, 0x46, 0x51, 0xF8, ++ 0x04, 0x2B, 0xC2, 0xF3, 0xC2, 0x2A, 0x02, 0xF0, 0x7C, 0x00, 0x5A, 0xEA, ++ 0x00, 0x00, 0xC2, 0xF3, 0xC1, 0x1C, 0x02, 0xEA, 0x09, 0x02, 0x06, 0xD0, ++ 0xD5, 0xF8, 0x50, 0x01, 0x02, 0x43, 0x42, 0xEA, 0x0C, 0x62, 0x41, 0xF8, ++ 0x04, 0x2C, 0x8E, 0x45, 0xE9, 0xD1, 0xD9, 0x06, 0x5C, 0xD5, 0x95, 0xF8, ++ 0x22, 0x10, 0xC3, 0x4A, 0xC3, 0x4B, 0x4F, 0xF4, 0xA4, 0x60, 0x00, 0xFB, ++ 0x01, 0x20, 0xD3, 0xF8, 0x38, 0x33, 0x0D, 0xF1, 0x3F, 0x02, 0x0D, 0xF1, ++ 0x3E, 0x01, 0x98, 0x47, 0x06, 0xF1, 0x10, 0x03, 0x06, 0x94, 0x08, 0x95, ++ 0x0D, 0xF1, 0x50, 0x09, 0x1C, 0x46, 0x35, 0x46, 0xBA, 0x4B, 0x59, 0xF8, ++ 0x04, 0xAB, 0x55, 0xF8, 0x04, 0x1B, 0x93, 0xF8, 0xBD, 0x30, 0x4F, 0xEA, ++ 0x1A, 0x4A, 0xC1, 0xF3, 0xC7, 0x22, 0xC1, 0xF3, 0xC2, 0x20, 0x5F, 0xFA, ++ 0x81, 0xFC, 0x4F, 0xEA, 0x0A, 0x4A, 0x01, 0xF0, 0x7F, 0x01, 0xD3, 0xB9, ++ 0x0C, 0xF0, 0x7C, 0x0C, 0x50, 0xEA, 0x0C, 0x03, 0x00, 0xF0, 0x29, 0x81, ++ 0xAD, 0x4B, 0x93, 0xF8, 0xBA, 0x30, 0x00, 0x2B, 0x00, 0xF0, 0xF3, 0x80, ++ 0xAB, 0x4B, 0x93, 0xF8, 0x2A, 0x30, 0x00, 0x2B, 0x40, 0xF0, 0xED, 0x80, ++ 0x00, 0x28, 0x40, 0xF0, 0x2F, 0x81, 0x09, 0x29, 0x00, 0xF2, 0x2C, 0x81, ++ 0x02, 0xF0, 0x06, 0x02, 0x2D, 0xE1, 0xD9, 0xF7, 0x47, 0xFE, 0xA4, 0x4B, ++ 0x1A, 0x7D, 0x00, 0x2A, 0x00, 0xF0, 0x06, 0x81, 0x5A, 0x7D, 0x00, 0x2A, ++ 0x00, 0xF0, 0x02, 0x81, 0x4A, 0xEA, 0x00, 0x20, 0x40, 0xF0, 0xA8, 0x00, ++ 0x49, 0xF8, 0x04, 0x0C, 0xAC, 0x42, 0xBD, 0xD1, 0x08, 0x9D, 0x06, 0x9C, ++ 0x95, 0xF8, 0x56, 0x31, 0x5A, 0x06, 0x13, 0xD5, 0x94, 0x4A, 0x95, 0xF8, ++ 0x22, 0x30, 0x4F, 0xF4, 0xA4, 0x61, 0x01, 0xFB, 0x03, 0x23, 0x07, 0x9A, ++ 0xD3, 0xF8, 0xC8, 0x31, 0x22, 0xF0, 0x7C, 0x72, 0x00, 0x2B, 0x07, 0x92, ++ 0x04, 0xDB, 0xC3, 0xF3, 0x05, 0x63, 0x42, 0xEA, 0x03, 0x53, 0x07, 0x93, ++ 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, 0x8D, 0x4B, ++ 0x01, 0x22, 0x1A, 0x60, 0x8C, 0x4A, 0x05, 0x9B, 0x11, 0x68, 0x7B, 0x60, ++ 0x48, 0x1C, 0x07, 0x9B, 0xBB, 0x60, 0x10, 0x60, 0x56, 0xF8, 0x04, 0x3B, ++ 0x44, 0xF8, 0x04, 0x3B, 0x58, 0xF8, 0x04, 0x3B, 0xE3, 0x60, 0xA3, 0x45, ++ 0xF6, 0xD1, 0x28, 0xB1, 0x82, 0x4B, 0x11, 0x60, 0x1B, 0x68, 0x09, 0xB9, ++ 0x03, 0xB1, 0x62, 0xB6, 0x00, 0x23, 0x85, 0xF8, 0x56, 0x31, 0x38, 0x46, ++ 0x19, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xD5, 0xF8, 0x4C, 0x01, 0x95, 0xF8, ++ 0x30, 0x21, 0x0D, 0x92, 0xCD, 0xE9, 0x0B, 0x34, 0x00, 0x22, 0x08, 0x92, ++ 0x00, 0xF1, 0x88, 0x0E, 0x0A, 0x92, 0x31, 0x46, 0x82, 0x46, 0x3E, 0xF8, ++ 0x02, 0x3B, 0x03, 0xEB, 0x43, 0x03, 0x0A, 0xEB, 0x83, 0x03, 0x58, 0x89, ++ 0xC0, 0xF3, 0x0D, 0x03, 0x43, 0xF0, 0x80, 0x43, 0x4F, 0xEA, 0xD3, 0x29, ++ 0x19, 0xF0, 0x06, 0x0C, 0x00, 0xF0, 0x8E, 0x80, 0x09, 0xF0, 0x07, 0x09, ++ 0xB9, 0xF1, 0x04, 0x0F, 0x03, 0xF0, 0x7F, 0x0C, 0x00, 0xF0, 0xE5, 0x80, ++ 0xB9, 0xF1, 0x05, 0x0F, 0x00, 0xF0, 0xE4, 0x80, 0xCC, 0xF3, 0xC1, 0x0C, ++ 0x00, 0x2A, 0x00, 0xF0, 0xD1, 0x80, 0x08, 0x98, 0x00, 0x28, 0x40, 0xF0, ++ 0x95, 0x80, 0x08, 0x68, 0x20, 0xF0, 0x60, 0x40, 0x20, 0xF4, 0x7F, 0x50, ++ 0x20, 0xF0, 0x3F, 0x00, 0x18, 0x43, 0x08, 0x60, 0x01, 0x32, 0x04, 0x2A, ++ 0x01, 0xF1, 0x04, 0x01, 0xCB, 0xD1, 0x05, 0x9A, 0x22, 0xF4, 0xC0, 0x71, ++ 0x08, 0x9A, 0x05, 0x91, 0xDD, 0xE9, 0x0B, 0x34, 0x22, 0xB1, 0x0A, 0x9A, ++ 0x01, 0x32, 0x41, 0xEA, 0xC2, 0x12, 0x05, 0x92, 0x06, 0x9A, 0x00, 0x2A, ++ 0x7E, 0xD1, 0x09, 0x9A, 0x22, 0xF0, 0x08, 0x02, 0x43, 0xF0, 0x02, 0x03, ++ 0xFA, 0x63, 0x9A, 0x06, 0x85, 0xF8, 0x56, 0x31, 0x7F, 0xF5, 0xEA, 0xAE, ++ 0xD5, 0xF8, 0x4C, 0x01, 0x7A, 0x69, 0x90, 0xF8, 0xA0, 0x30, 0xDF, 0xF8, ++ 0x38, 0xE1, 0x05, 0x99, 0x03, 0xEB, 0x43, 0x03, 0x00, 0xEB, 0x83, 0x03, ++ 0x0E, 0xEA, 0x02, 0x0E, 0xB3, 0xF8, 0x0A, 0xC0, 0xCC, 0xF3, 0x0D, 0x02, ++ 0xC1, 0xF3, 0xC1, 0x13, 0x42, 0xF0, 0x80, 0x42, 0x11, 0xF4, 0xC0, 0x7F, ++ 0xCC, 0xF3, 0x80, 0x3C, 0x4E, 0xEA, 0x02, 0x01, 0x03, 0xF1, 0xFF, 0x33, ++ 0xDB, 0xB2, 0x80, 0xF8, 0xA1, 0xC0, 0xC0, 0xF8, 0x9C, 0x10, 0x4F, 0xF0, ++ 0x00, 0x02, 0x06, 0x98, 0x00, 0x93, 0x03, 0x90, 0x14, 0xBF, 0x01, 0x23, ++ 0x13, 0x46, 0xCD, 0xE9, 0x01, 0x22, 0x38, 0x46, 0x0C, 0xF0, 0x56, 0xFF, ++ 0x95, 0xF8, 0x56, 0x31, 0xB6, 0xE6, 0x9D, 0xF8, 0x3F, 0x00, 0x40, 0xEA, ++ 0x00, 0x20, 0x40, 0xEA, 0x0A, 0x00, 0x02, 0xF0, 0x06, 0x02, 0x49, 0xF8, ++ 0x04, 0x0C, 0x00, 0x2A, 0x3F, 0xF4, 0x20, 0xAF, 0x09, 0x29, 0x7F, 0xF6, ++ 0x1D, 0xAF, 0x29, 0x4B, 0x59, 0xF8, 0x04, 0x2C, 0x93, 0xF8, 0xAF, 0x10, ++ 0x12, 0x0C, 0x41, 0xEA, 0x01, 0x21, 0x12, 0x04, 0x0A, 0x43, 0x49, 0xF8, ++ 0x04, 0x2C, 0x0F, 0xE7, 0x08, 0x68, 0xCD, 0xF8, 0x18, 0xC0, 0x20, 0xF0, ++ 0x60, 0x40, 0x20, 0xF4, 0x7F, 0x50, 0x20, 0xF0, 0x3F, 0x00, 0x18, 0x43, ++ 0x08, 0x60, 0x83, 0xE7, 0x40, 0xEA, 0x00, 0x20, 0x40, 0xEA, 0x0A, 0x00, ++ 0x49, 0xF8, 0x04, 0x0C, 0xFC, 0xE6, 0x9D, 0xF8, 0x3E, 0x20, 0x42, 0xEA, ++ 0x02, 0x22, 0x42, 0xEA, 0x0A, 0x02, 0x49, 0xF8, 0x04, 0x2C, 0xF3, 0xE6, ++ 0x0A, 0x98, 0xAC, 0xEB, 0x00, 0x00, 0xB0, 0xFA, 0x80, 0xF0, 0x40, 0x09, ++ 0x08, 0x90, 0x62, 0xE7, 0x09, 0x9A, 0x42, 0xF0, 0x08, 0x02, 0x7F, 0xE7, ++ 0x12, 0xF0, 0x06, 0x02, 0x0B, 0xD0, 0x04, 0x29, 0x09, 0xD8, 0x0C, 0x4B, ++ 0x93, 0xF8, 0xBB, 0x00, 0x40, 0xEA, 0x00, 0x20, 0x40, 0xEA, 0x0A, 0x00, ++ 0x49, 0xF8, 0x04, 0x0C, 0xB5, 0xE7, 0x07, 0x4B, 0xB3, 0xF8, 0xBB, 0x00, ++ 0x40, 0xBA, 0x80, 0xB2, 0x40, 0xEA, 0x0A, 0x00, 0x49, 0xF8, 0x04, 0x0C, ++ 0xAB, 0xE7, 0x00, 0xBF, 0x18, 0x88, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x2C, 0x19, 0x17, 0x00, 0xBC, 0x34, 0x17, 0x00, 0x4C, 0x36, 0x17, 0x00, ++ 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0xFF, 0x3F, 0x00, 0xE0, ++ 0x00, 0xC0, 0xFF, 0x1F, 0x0D, 0x98, 0x84, 0x45, 0x0A, 0x98, 0x38, 0xBF, ++ 0x60, 0x46, 0x0A, 0x90, 0x08, 0x98, 0x38, 0xBF, 0x01, 0x20, 0x08, 0x90, ++ 0x27, 0xE7, 0x4F, 0xEA, 0x1C, 0x1C, 0x1D, 0xE7, 0x14, 0xAC, 0x03, 0xF4, ++ 0xC0, 0x69, 0x54, 0xF8, 0x22, 0x40, 0xB9, 0xF5, 0x80, 0x6F, 0x0C, 0xBF, ++ 0x4F, 0xF4, 0x00, 0x39, 0x4F, 0xF4, 0x80, 0x39, 0x24, 0xF4, 0x40, 0x34, ++ 0x44, 0xEA, 0x09, 0x09, 0x40, 0x04, 0x14, 0xAC, 0x4C, 0xBF, 0x49, 0xF4, ++ 0x80, 0x20, 0x29, 0xF4, 0x80, 0x20, 0x44, 0xF8, 0x22, 0x00, 0x4F, 0xEA, ++ 0x1C, 0x1C, 0x01, 0xE7, 0xF0, 0xB4, 0xD2, 0xF8, 0xA4, 0x50, 0x2C, 0x88, ++ 0x30, 0xBB, 0x00, 0x29, 0x44, 0xD0, 0x51, 0x4E, 0x03, 0x46, 0x96, 0xF8, ++ 0x75, 0x01, 0x26, 0x46, 0x01, 0x28, 0x4F, 0xD9, 0x8F, 0x78, 0x17, 0xF0, ++ 0x03, 0x07, 0x3C, 0xD0, 0xAD, 0x78, 0xCB, 0x78, 0x09, 0x79, 0x00, 0x2D, ++ 0x41, 0xD1, 0x5E, 0x1E, 0x0D, 0x2E, 0x40, 0xD8, 0x0E, 0x2B, 0x00, 0xF0, ++ 0x86, 0x80, 0x03, 0xEB, 0x83, 0x03, 0x03, 0xF6, 0x67, 0x13, 0x00, 0x29, ++ 0x47, 0xD0, 0x03, 0x2F, 0x60, 0xD0, 0x02, 0x2F, 0x57, 0xD0, 0x02, 0x20, ++ 0x1C, 0x46, 0x00, 0x21, 0x03, 0x46, 0x05, 0xE0, 0x3E, 0x4B, 0x93, 0xF8, ++ 0x75, 0x31, 0x5B, 0xB9, 0x18, 0x46, 0x00, 0x21, 0xA2, 0xF8, 0xA8, 0x40, ++ 0x82, 0xF8, 0xD8, 0x30, 0xF0, 0xBC, 0x82, 0xF8, 0xD9, 0x00, 0xA2, 0xF8, ++ 0xAA, 0x10, 0x70, 0x47, 0xC0, 0x78, 0x10, 0xF0, 0x03, 0x00, 0x12, 0xD0, ++ 0x01, 0x28, 0x4F, 0xF6, 0xF6, 0x76, 0x08, 0xBF, 0x0A, 0x26, 0x26, 0x44, ++ 0xB6, 0xB2, 0x51, 0xBB, 0x01, 0x23, 0x34, 0x46, 0x18, 0x46, 0xE5, 0xE7, ++ 0x08, 0x46, 0x0B, 0x46, 0xE2, 0xE7, 0x34, 0x46, 0x39, 0x46, 0x18, 0x46, ++ 0xDE, 0xE7, 0x99, 0xB1, 0x1F, 0x46, 0x26, 0x46, 0x03, 0x46, 0x38, 0x46, ++ 0xB2, 0xE7, 0x01, 0x2D, 0x1A, 0xD0, 0x4F, 0xF6, 0xFF, 0x73, 0xC2, 0xE7, ++ 0x34, 0x46, 0xCF, 0xE7, 0x4F, 0xF6, 0xD8, 0x71, 0x9C, 0x42, 0x94, 0xBF, ++ 0x0C, 0x46, 0x28, 0x24, 0x23, 0x44, 0x9C, 0xB2, 0x03, 0x46, 0x00, 0x21, ++ 0xC6, 0xE7, 0x02, 0x2F, 0x11, 0xD0, 0x03, 0x2F, 0x20, 0xD0, 0x02, 0x20, ++ 0x1C, 0x46, 0x03, 0x46, 0xBE, 0xE7, 0x18, 0x46, 0x01, 0x23, 0x95, 0xE7, ++ 0x5E, 0x1E, 0xA4, 0x2E, 0xE1, 0xD8, 0x03, 0xEB, 0x83, 0x03, 0x03, 0xF5, ++ 0x9C, 0x53, 0x08, 0x33, 0xA1, 0xE7, 0x02, 0x28, 0xDE, 0xD0, 0x03, 0x20, ++ 0x1C, 0x46, 0x00, 0x21, 0x03, 0x46, 0xAB, 0xE7, 0x85, 0xB9, 0x4C, 0x1E, ++ 0x0D, 0x2C, 0x0A, 0xD8, 0x0E, 0x29, 0x19, 0xD0, 0x01, 0xEB, 0x81, 0x01, ++ 0x01, 0xF6, 0x67, 0x11, 0x04, 0x28, 0x94, 0xD1, 0x1C, 0x46, 0x03, 0x23, ++ 0x9C, 0xE7, 0x4F, 0xF6, 0xFF, 0x71, 0xF7, 0xE7, 0x01, 0x2D, 0xFA, 0xD1, ++ 0x4C, 0x1E, 0xA4, 0x2C, 0xF7, 0xD8, 0x01, 0xEB, 0x81, 0x01, 0x01, 0xF5, ++ 0x9C, 0x51, 0x08, 0x31, 0xEC, 0xE7, 0x40, 0xF6, 0xB4, 0x13, 0x7A, 0xE7, ++ 0x40, 0xF6, 0xB4, 0x11, 0xE6, 0xE7, 0x00, 0xBF, 0xE4, 0xB8, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF8, 0x4F, 0x7B, 0x4F, 0xDF, 0xF8, 0x08, 0x92, 0x4F, 0xF4, ++ 0x1E, 0x73, 0x03, 0xFB, 0x00, 0x73, 0x04, 0x46, 0x93, 0xF8, 0x22, 0x60, ++ 0x58, 0x68, 0x77, 0x4B, 0x1B, 0x68, 0x10, 0xF0, 0x20, 0x0A, 0xB3, 0xF9, ++ 0x00, 0x30, 0x0D, 0x46, 0x90, 0x46, 0x4F, 0xD0, 0x00, 0x2B, 0xC0, 0xF2, ++ 0x9F, 0x80, 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, 0x04, 0x73, 0x0E, 0x21, ++ 0xB3, 0xF8, 0x06, 0xC1, 0x07, 0x22, 0x4C, 0xFA, 0x01, 0xF3, 0x03, 0xF0, ++ 0x03, 0x03, 0x03, 0x2B, 0x02, 0xF1, 0xFF, 0x30, 0xA1, 0xF1, 0x02, 0x01, ++ 0x40, 0xF0, 0xB3, 0x80, 0x10, 0xF0, 0xFF, 0x02, 0xF1, 0xD1, 0x90, 0x46, ++ 0xB9, 0xF8, 0x50, 0xC0, 0x0E, 0x21, 0x07, 0x22, 0x4C, 0xFA, 0x01, 0xF3, ++ 0x03, 0xF0, 0x03, 0x03, 0x03, 0x2B, 0x02, 0xF1, 0xFF, 0x30, 0xA1, 0xF1, ++ 0x02, 0x01, 0x40, 0xF0, 0x9B, 0x80, 0x10, 0xF0, 0xFF, 0x02, 0xF1, 0xD1, ++ 0x5D, 0x4B, 0x4F, 0xF4, 0x1E, 0x70, 0x00, 0xFB, 0x04, 0x74, 0x4F, 0xF4, ++ 0xA4, 0x61, 0x01, 0xFB, 0x06, 0x36, 0x94, 0xF8, 0x2C, 0x31, 0x96, 0xF8, ++ 0xC4, 0x11, 0x94, 0xF8, 0x23, 0x00, 0x04, 0x2B, 0x08, 0xBF, 0x03, 0x23, ++ 0xA9, 0x42, 0x28, 0xBF, 0x29, 0x46, 0x99, 0x42, 0x28, 0xBF, 0x19, 0x46, ++ 0x84, 0xF8, 0x2D, 0x11, 0x0B, 0xF0, 0x22, 0xFD, 0x94, 0xF8, 0x56, 0x31, ++ 0x43, 0xF0, 0x08, 0x03, 0x84, 0xF8, 0x56, 0x31, 0xBD, 0xE8, 0xF8, 0x8F, ++ 0x10, 0xF0, 0x04, 0x0B, 0x28, 0xD0, 0x00, 0x2B, 0x58, 0xDB, 0x4F, 0xF4, ++ 0x1E, 0x73, 0x03, 0xFB, 0x04, 0x73, 0x0E, 0x22, 0xB3, 0xF8, 0xEC, 0xC0, ++ 0x07, 0x20, 0x4C, 0xFA, 0x02, 0xF3, 0x03, 0xF0, 0x03, 0x03, 0x03, 0x2B, ++ 0x00, 0xF1, 0xFF, 0x31, 0xA2, 0xF1, 0x02, 0x02, 0x6A, 0xD1, 0x11, 0xF0, ++ 0xFF, 0x00, 0xF2, 0xD1, 0xB9, 0xF8, 0x38, 0xC0, 0x0E, 0x21, 0x07, 0x22, ++ 0x4C, 0xFA, 0x01, 0xF3, 0x03, 0xF0, 0x03, 0x03, 0x03, 0x2B, 0x02, 0xF1, ++ 0xFF, 0x30, 0xA1, 0xF1, 0x02, 0x01, 0x54, 0xD1, 0x10, 0xF0, 0xFF, 0x02, ++ 0xF2, 0xD1, 0xAF, 0xE7, 0x00, 0x2B, 0x3A, 0xDB, 0x4F, 0xF4, 0x1E, 0x73, ++ 0x03, 0xFB, 0x04, 0x73, 0x03, 0xF1, 0xCB, 0x02, 0x93, 0xF8, 0xCE, 0x30, ++ 0x00, 0x2B, 0x54, 0xD1, 0x93, 0x78, 0x00, 0x2B, 0x4B, 0xD1, 0x53, 0x78, ++ 0x01, 0x20, 0x00, 0x2B, 0x48, 0xD1, 0x99, 0xF8, 0x12, 0x30, 0x00, 0x2B, ++ 0x4B, 0xD1, 0x99, 0xF8, 0x11, 0x30, 0x00, 0x2B, 0x49, 0xD1, 0x99, 0xF8, ++ 0x10, 0x20, 0x00, 0x3A, 0x18, 0xBF, 0x01, 0x22, 0x93, 0x45, 0x58, 0x46, ++ 0x28, 0xBF, 0x10, 0x46, 0xC2, 0xB2, 0x89, 0xE7, 0x99, 0xF8, 0x76, 0x31, ++ 0x59, 0x07, 0x3F, 0xF5, 0x5C, 0xAF, 0x21, 0x49, 0x21, 0x48, 0x40, 0xF2, ++ 0x55, 0x52, 0xFC, 0xF7, 0x99, 0xFD, 0x54, 0xE7, 0x99, 0xF8, 0x76, 0x31, ++ 0x9A, 0x07, 0xA2, 0xD4, 0x1B, 0x49, 0x1D, 0x48, 0x40, 0xF2, 0x62, 0x52, ++ 0xFC, 0xF7, 0x8E, 0xFD, 0x9B, 0xE7, 0x99, 0xF8, 0x76, 0x31, 0xDB, 0x07, ++ 0xC0, 0xD4, 0x16, 0x49, 0x18, 0x48, 0x40, 0xF2, 0x6D, 0x52, 0xFC, 0xF7, ++ 0x83, 0xFD, 0xB9, 0xE7, 0x42, 0x45, 0x28, 0xBF, 0x42, 0x46, 0xD2, 0xB2, ++ 0x62, 0xE7, 0x90, 0x45, 0x28, 0xBF, 0x90, 0x46, 0x4C, 0xE7, 0x52, 0x45, ++ 0x28, 0xBF, 0x52, 0x46, 0xD2, 0xB2, 0x59, 0xE7, 0x40, 0x45, 0x28, 0xBF, ++ 0x40, 0x46, 0x82, 0x46, 0x92, 0xE7, 0x02, 0x20, 0x80, 0x45, 0x28, 0xBF, ++ 0x80, 0x46, 0xC3, 0x46, 0xB1, 0xE7, 0x03, 0x20, 0xF8, 0xE7, 0x03, 0x22, ++ 0xBA, 0xE7, 0x02, 0x22, 0xB8, 0xE7, 0x00, 0xBF, 0x68, 0x65, 0x17, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0xC4, 0xB8, 0x15, 0x00, 0xD4, 0xB8, 0x15, 0x00, 0xE4, 0xB8, 0x15, 0x00, ++ 0xE4, 0xB8, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, 0x2D, 0xED, 0x02, 0x8B, ++ 0xDF, 0xF8, 0xE4, 0xA3, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x00, 0xF3, ++ 0x0A, 0xEB, 0x03, 0x06, 0x8B, 0xB0, 0xB6, 0xF8, 0xC2, 0x41, 0x02, 0x93, ++ 0x01, 0x90, 0xD6, 0xF8, 0x90, 0x31, 0x96, 0xF8, 0xC6, 0x51, 0x04, 0x95, ++ 0x00, 0x20, 0xA6, 0xF8, 0xC2, 0x01, 0x98, 0x78, 0x02, 0x9D, 0xD6, 0xF8, ++ 0xC8, 0x31, 0x03, 0x94, 0x03, 0xF0, 0x7F, 0x43, 0x05, 0xF1, 0xEC, 0x0C, ++ 0x24, 0x32, 0x05, 0x93, 0x0A, 0xEB, 0x0C, 0x03, 0xD6, 0xF8, 0xE4, 0x40, ++ 0x96, 0xF8, 0xC5, 0x71, 0x08, 0xEE, 0x10, 0x2A, 0x08, 0xEE, 0x90, 0x3A, ++ 0xA1, 0xF1, 0x24, 0x09, 0x00, 0x28, 0x00, 0xF0, 0xDD, 0x81, 0x1F, 0xFA, ++ 0x89, 0xF8, 0x01, 0x9B, 0x4F, 0xF4, 0xA4, 0x69, 0x09, 0xFB, 0x03, 0xA9, ++ 0xD9, 0xF8, 0xCC, 0x31, 0xDD, 0x07, 0x05, 0xD5, 0x99, 0xF8, 0x62, 0xB0, ++ 0xBB, 0xF1, 0x00, 0x0F, 0x00, 0xF0, 0x5C, 0x82, 0xD2, 0x4B, 0x93, 0xF8, ++ 0x76, 0xB1, 0x1B, 0xF0, 0x01, 0x0B, 0x40, 0xF0, 0xE9, 0x81, 0xD9, 0x46, ++ 0x48, 0x46, 0x18, 0xEE, 0x90, 0x2A, 0x59, 0x46, 0xFF, 0xF7, 0xF8, 0xFD, ++ 0x02, 0x9B, 0x03, 0xF2, 0xB4, 0x43, 0x18, 0xEE, 0x10, 0x0A, 0x53, 0x44, ++ 0x0D, 0xF1, 0x25, 0x02, 0x41, 0x46, 0xFD, 0xF7, 0xD5, 0xFF, 0x10, 0xF0, ++ 0xFF, 0x09, 0x1F, 0xD0, 0x01, 0x9B, 0x4F, 0xF4, 0xA4, 0x6B, 0x0B, 0xFB, ++ 0x03, 0xAB, 0x9B, 0xF8, 0x62, 0x30, 0x00, 0x2B, 0x40, 0xF0, 0x9D, 0x81, ++ 0x9B, 0xF8, 0x8A, 0x10, 0x00, 0x29, 0x00, 0xF0, 0x6F, 0x82, 0x89, 0x45, ++ 0x07, 0xD0, 0x01, 0x9A, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x02, 0xA3, ++ 0x01, 0x22, 0x83, 0xF8, 0x8C, 0x20, 0x01, 0x9A, 0x4F, 0xF4, 0xA4, 0x63, ++ 0x03, 0xFB, 0x02, 0xA3, 0x83, 0xF8, 0x8A, 0x90, 0x18, 0xEE, 0x90, 0x2A, ++ 0x41, 0x46, 0x18, 0xEE, 0x10, 0x0A, 0xFD, 0xF7, 0x25, 0xFF, 0x01, 0x9A, ++ 0x04, 0x99, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x02, 0xA3, 0x93, 0xF8, ++ 0xC6, 0x21, 0x8A, 0x42, 0x0E, 0xD0, 0xD3, 0xF8, 0x90, 0x11, 0xAC, 0x4B, ++ 0x09, 0x79, 0xD3, 0xF8, 0x40, 0x33, 0x8A, 0x1A, 0x8D, 0xF8, 0x26, 0x20, ++ 0x0D, 0xF1, 0x26, 0x01, 0x0D, 0xF1, 0x27, 0x02, 0x30, 0x46, 0x98, 0x47, ++ 0x01, 0x9B, 0x4F, 0xF4, 0xA4, 0x68, 0x08, 0xFB, 0x03, 0xA8, 0x98, 0xF8, ++ 0xC5, 0x31, 0xBB, 0x42, 0x00, 0xF2, 0x01, 0x81, 0x00, 0x2C, 0x00, 0xF0, ++ 0x8E, 0x80, 0x01, 0x9B, 0x9F, 0x4E, 0x03, 0x9D, 0xDD, 0xF8, 0x14, 0x90, ++ 0x4F, 0xF4, 0xA4, 0x68, 0x08, 0xFB, 0x03, 0xA8, 0xB8, 0xF8, 0xC2, 0x21, ++ 0xAA, 0x42, 0x1D, 0xD0, 0x29, 0x46, 0x30, 0x46, 0xFC, 0xF7, 0x1A, 0xFA, ++ 0x94, 0xF8, 0x56, 0x31, 0xB8, 0xF8, 0xC2, 0x21, 0x94, 0xF8, 0x23, 0x00, ++ 0x43, 0xF0, 0x02, 0x03, 0x84, 0xF8, 0x56, 0x31, 0x53, 0x07, 0x4F, 0xF0, ++ 0x00, 0x01, 0x58, 0xBF, 0x4F, 0xF4, 0x80, 0x63, 0xC4, 0xF8, 0x50, 0x11, ++ 0x4E, 0xBF, 0xA4, 0xF8, 0x54, 0x11, 0xA4, 0xF8, 0x54, 0x31, 0x01, 0x21, ++ 0x0B, 0xF0, 0x02, 0xFC, 0x98, 0xF8, 0xC5, 0x31, 0xBB, 0x42, 0x4B, 0xD0, ++ 0x04, 0x2B, 0x94, 0xF8, 0x2C, 0xA1, 0x5F, 0xD0, 0x53, 0x45, 0x28, 0xBF, ++ 0x53, 0x46, 0x04, 0x2B, 0x00, 0xF0, 0x93, 0x80, 0x5F, 0xFA, 0x83, 0xFA, ++ 0x94, 0xF8, 0x2D, 0x31, 0x53, 0x45, 0x3B, 0xD0, 0x63, 0x68, 0x13, 0xF0, ++ 0x20, 0x0B, 0x58, 0xD0, 0x7F, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0xC0, 0xF2, 0xA7, 0x80, 0xB4, 0xF8, 0x06, 0xC1, 0x0E, 0x22, ++ 0x07, 0x20, 0x4C, 0xFA, 0x02, 0xF3, 0x03, 0xF0, 0x03, 0x03, 0x03, 0x2B, ++ 0x00, 0xF1, 0xFF, 0x31, 0xA2, 0xF1, 0x02, 0x02, 0x02, 0xD1, 0x11, 0xF0, ++ 0xFF, 0x00, 0xF2, 0xD1, 0x70, 0x4B, 0x07, 0x22, 0xB3, 0xF8, 0x50, 0xE0, ++ 0x0E, 0x23, 0x4E, 0xFA, 0x03, 0xF1, 0x01, 0xF0, 0x03, 0x01, 0x03, 0x29, ++ 0x02, 0xF1, 0xFF, 0x3C, 0xA3, 0xF1, 0x02, 0x03, 0x40, 0xF0, 0xF4, 0x80, ++ 0x1C, 0xF0, 0xFF, 0x02, 0xF1, 0xD1, 0x94, 0xF8, 0x23, 0x00, 0x84, 0xF8, ++ 0x2D, 0xA1, 0x51, 0x46, 0x0B, 0xF0, 0x54, 0xFB, 0x94, 0xF8, 0x56, 0x31, ++ 0x43, 0xF0, 0x08, 0x03, 0x84, 0xF8, 0x56, 0x31, 0xD8, 0xF8, 0xC8, 0x31, ++ 0x03, 0xF0, 0x7F, 0x43, 0x4B, 0x45, 0x08, 0xD0, 0x63, 0x68, 0x9B, 0x06, ++ 0x05, 0xD5, 0x94, 0xF8, 0x56, 0x31, 0x43, 0xF0, 0x40, 0x03, 0x84, 0xF8, ++ 0x56, 0x31, 0x24, 0x68, 0x00, 0x2C, 0x7F, 0xF4, 0x7B, 0xAF, 0x0B, 0xB0, ++ 0xBD, 0xEC, 0x02, 0x8B, 0xBD, 0xE8, 0xF0, 0x8F, 0xBA, 0xF1, 0x03, 0x0F, ++ 0x35, 0xD8, 0xBA, 0xF1, 0x02, 0x0F, 0x28, 0xBF, 0x4F, 0xF0, 0x02, 0x0A, ++ 0x9E, 0xE7, 0x13, 0xF0, 0x04, 0x0F, 0x52, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x2B, 0xD0, 0x00, 0x2B, 0xC0, 0xF2, 0xA7, 0x80, 0xB4, 0xF8, ++ 0xEC, 0xC0, 0x0E, 0x22, 0x07, 0x20, 0x4C, 0xFA, 0x02, 0xF3, 0x03, 0xF0, ++ 0x03, 0x03, 0x03, 0x2B, 0x00, 0xF1, 0xFF, 0x31, 0xA2, 0xF1, 0x02, 0x02, ++ 0x40, 0xF0, 0x97, 0x81, 0x11, 0xF0, 0xFF, 0x00, 0xF1, 0xD1, 0x42, 0x4B, ++ 0xB3, 0xF8, 0x38, 0xC0, 0x0E, 0x21, 0x07, 0x22, 0x4C, 0xFA, 0x01, 0xF3, ++ 0x03, 0xF0, 0x03, 0x03, 0x03, 0x2B, 0x02, 0xF1, 0xFF, 0x30, 0xA1, 0xF1, ++ 0x02, 0x01, 0x40, 0xF0, 0x7F, 0x81, 0x10, 0xF0, 0xFF, 0x02, 0xF1, 0xD1, ++ 0xA1, 0xE7, 0x4F, 0xF0, 0x03, 0x0A, 0x6B, 0xE7, 0x00, 0x2B, 0x5E, 0xDB, ++ 0x94, 0xF8, 0xCE, 0x30, 0x00, 0x2B, 0x40, 0xF0, 0xDF, 0x81, 0x94, 0xF8, ++ 0xCD, 0x30, 0x00, 0x2B, 0x40, 0xF0, 0xE0, 0x81, 0x94, 0xF8, 0xCC, 0x20, ++ 0x11, 0x1E, 0x18, 0xBF, 0x01, 0x21, 0x2E, 0x4A, 0x93, 0x7C, 0x00, 0x2B, ++ 0x40, 0xF0, 0xD2, 0x81, 0x53, 0x7C, 0x00, 0x2B, 0x40, 0xF0, 0xD0, 0x81, ++ 0x13, 0x7C, 0x1A, 0x1E, 0x18, 0xBF, 0x01, 0x22, 0x8A, 0x42, 0x28, 0xBF, ++ 0x0A, 0x46, 0x7C, 0xE7, 0x25, 0x4B, 0x93, 0xF8, 0x76, 0x31, 0x58, 0x07, ++ 0x3F, 0xF5, 0x53, 0xAF, 0x26, 0x49, 0x27, 0x48, 0x40, 0xF2, 0xCD, 0x12, ++ 0xFC, 0xF7, 0xA8, 0xFB, 0x4B, 0xE7, 0x0C, 0x23, 0x05, 0x22, 0x00, 0x21, ++ 0x3B, 0x20, 0xFA, 0xF7, 0xBF, 0xFA, 0x1F, 0x4B, 0xD8, 0xF8, 0x40, 0x20, ++ 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x81, 0x46, 0xC0, 0xF2, ++ 0x18, 0x81, 0x13, 0x7E, 0x89, 0xF8, 0x00, 0x30, 0xD6, 0xF8, 0x90, 0x31, ++ 0x99, 0x78, 0x89, 0xF8, 0x02, 0x10, 0x96, 0xF8, 0xC5, 0x11, 0x89, 0xF8, ++ 0x03, 0x10, 0xB3, 0xF8, 0x00, 0xC0, 0xB6, 0xF8, 0x94, 0x01, 0xB6, 0xF8, ++ 0x96, 0x11, 0xA9, 0xF8, 0x08, 0x10, 0xA9, 0xF8, 0x06, 0x00, 0xA9, 0xF8, ++ 0x04, 0xC0, 0x12, 0x7B, 0x89, 0xF8, 0x0A, 0x20, 0xDB, 0x78, 0x89, 0xF8, ++ 0x0B, 0x30, 0x48, 0x46, 0xFA, 0xF7, 0xC4, 0xFA, 0xCC, 0xE6, 0x06, 0x4B, ++ 0x93, 0xF8, 0x76, 0x31, 0xDA, 0x07, 0x9B, 0xD4, 0x07, 0x49, 0x09, 0x48, ++ 0x40, 0xF2, 0xE5, 0x12, 0xFC, 0xF7, 0x6A, 0xFB, 0x94, 0xE7, 0x00, 0xBF, ++ 0xE4, 0xB8, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x0C, 0xB9, 0x15, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0xC4, 0xB8, 0x15, 0x00, ++ 0xE4, 0xB8, 0x15, 0x00, 0x18, 0x88, 0x17, 0x00, 0xB9, 0x4B, 0x93, 0xF8, ++ 0x76, 0x31, 0x99, 0x07, 0x3F, 0xF5, 0x53, 0xAF, 0xB7, 0x49, 0xB8, 0x48, ++ 0x4F, 0xF4, 0xED, 0x72, 0xFC, 0xF7, 0x4C, 0xFB, 0x4B, 0xE7, 0x02, 0x2B, ++ 0x08, 0xBF, 0x8B, 0xF8, 0xDB, 0x90, 0x73, 0xE6, 0x82, 0x42, 0x28, 0xBF, ++ 0x02, 0x46, 0x0A, 0xE7, 0x1F, 0xFA, 0x89, 0xF8, 0x41, 0x46, 0x10, 0x46, ++ 0xFB, 0xF7, 0x42, 0xFA, 0x00, 0x28, 0x3F, 0xF4, 0x1A, 0xAE, 0xB6, 0xF8, ++ 0xC2, 0x31, 0x82, 0x78, 0x23, 0xF0, 0x07, 0x03, 0x9B, 0xB2, 0xD1, 0x07, ++ 0x48, 0xBF, 0x43, 0xF0, 0x01, 0x03, 0xA6, 0xF8, 0xC2, 0x31, 0x53, 0x07, ++ 0x7F, 0xF5, 0x0B, 0xAE, 0x01, 0x9A, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, ++ 0x02, 0xA3, 0xB3, 0xF8, 0xC2, 0x21, 0x42, 0xF0, 0x04, 0x02, 0xA3, 0xF8, ++ 0xC2, 0x21, 0x00, 0xE6, 0x18, 0xEE, 0x10, 0x0A, 0x41, 0x46, 0xFB, 0xF7, ++ 0x89, 0xFB, 0x9A, 0x4B, 0x93, 0xF8, 0x76, 0xB1, 0x1B, 0xF0, 0x06, 0x0B, ++ 0x81, 0x46, 0x3F, 0xF4, 0x0B, 0xAE, 0x18, 0xEE, 0x10, 0x0A, 0x41, 0x46, ++ 0xFB, 0xF7, 0x9C, 0xFB, 0x01, 0x9A, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, ++ 0x02, 0xA3, 0x83, 0x46, 0x93, 0xF8, 0x62, 0x20, 0x00, 0x2A, 0x00, 0xF0, ++ 0xAA, 0x80, 0x8E, 0x4B, 0x93, 0xF8, 0x76, 0x31, 0x59, 0x07, 0x7F, 0xF5, ++ 0xF5, 0xAD, 0x18, 0xEE, 0x90, 0x2A, 0x18, 0xEE, 0x10, 0x0A, 0x41, 0x46, ++ 0xFD, 0xF7, 0xD6, 0xFF, 0x00, 0x28, 0x00, 0xF0, 0x09, 0x81, 0x01, 0x9A, ++ 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x02, 0xA3, 0xD3, 0xF8, 0xC8, 0x31, ++ 0xC3, 0xF3, 0x09, 0x12, 0x15, 0x46, 0xA2, 0xB1, 0x04, 0x23, 0x05, 0x22, ++ 0x00, 0x21, 0x6F, 0x20, 0xFA, 0xF7, 0xFE, 0xF9, 0x01, 0x9B, 0x4F, 0xF4, ++ 0xA4, 0x62, 0x02, 0xFB, 0x03, 0xA2, 0x06, 0x92, 0x92, 0xF8, 0x63, 0x10, ++ 0x81, 0x70, 0x05, 0x80, 0xFA, 0xF7, 0x22, 0xFA, 0x06, 0x9A, 0xD2, 0xF8, ++ 0xC8, 0x31, 0x05, 0x9A, 0x03, 0xF0, 0x7F, 0x43, 0x93, 0x42, 0x3F, 0xF4, ++ 0xC5, 0xAD, 0x04, 0x23, 0x05, 0x22, 0x00, 0x21, 0x71, 0x20, 0xFA, 0xF7, ++ 0xE3, 0xF9, 0x01, 0x9A, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x02, 0xA3, ++ 0xD3, 0xF8, 0xC8, 0x21, 0xC2, 0xF3, 0x05, 0x63, 0x52, 0x00, 0x54, 0xBF, ++ 0x43, 0xF4, 0x80, 0x73, 0x43, 0xF4, 0x40, 0x73, 0x03, 0x60, 0xFA, 0xF7, ++ 0x01, 0xFA, 0xAB, 0xE5, 0x02, 0x9B, 0x03, 0xF5, 0xD6, 0x72, 0x52, 0x44, ++ 0x0D, 0xF1, 0x27, 0x03, 0x18, 0xEE, 0x10, 0x0A, 0x41, 0x46, 0x06, 0x92, ++ 0xFD, 0xF7, 0x92, 0xFE, 0x9D, 0xF8, 0x27, 0x30, 0x00, 0x2B, 0x3F, 0xF4, ++ 0x93, 0xAD, 0x06, 0x9A, 0x06, 0x97, 0x03, 0x9F, 0x25, 0x46, 0x4C, 0x46, ++ 0x91, 0x46, 0x08, 0x23, 0x05, 0x22, 0x00, 0x21, 0x1A, 0x20, 0xFA, 0xF7, ++ 0xB3, 0xF9, 0x59, 0xF8, 0x04, 0x1B, 0x80, 0xF8, 0x05, 0xB0, 0x94, 0xF8, ++ 0x63, 0x20, 0x82, 0x71, 0x4F, 0xF0, 0x00, 0x02, 0x01, 0x60, 0x0B, 0xF1, ++ 0x01, 0x0B, 0x02, 0x71, 0xFA, 0xF7, 0xD4, 0xF9, 0xBB, 0xF1, 0x04, 0x0F, ++ 0xE7, 0xD1, 0x03, 0x97, 0x2C, 0x46, 0x06, 0x9F, 0x70, 0xE5, 0x00, 0x2A, ++ 0x7F, 0xF4, 0xE5, 0xAE, 0x45, 0x22, 0x4C, 0x49, 0x4D, 0x48, 0xFC, 0xF7, ++ 0x77, 0xFA, 0xD8, 0xF8, 0x40, 0x20, 0xDC, 0xE6, 0x9B, 0xF8, 0x8C, 0x30, ++ 0x00, 0x2B, 0x3F, 0xF4, 0x96, 0xAD, 0x9D, 0xF8, 0x25, 0x30, 0x01, 0x2B, ++ 0x7F, 0xF4, 0x91, 0xAD, 0x46, 0x4B, 0x9B, 0xF8, 0x63, 0x00, 0xD3, 0xF8, ++ 0xC0, 0x31, 0x98, 0x47, 0x9B, 0xF8, 0x8A, 0x10, 0x00, 0x29, 0x3F, 0xF4, ++ 0x86, 0xAD, 0x7A, 0xE5, 0x5A, 0x45, 0x28, 0xBF, 0x5A, 0x46, 0xD2, 0xB2, ++ 0x21, 0xE6, 0x83, 0x46, 0x69, 0xE6, 0x18, 0xEE, 0x10, 0x0A, 0x41, 0x46, ++ 0x06, 0x93, 0xFB, 0xF7, 0x77, 0xF9, 0xB0, 0xB1, 0x06, 0x9B, 0x3A, 0x49, ++ 0x93, 0xF8, 0x6C, 0x20, 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, 0x02, 0x13, ++ 0x5B, 0x68, 0x13, 0xF0, 0x24, 0x0F, 0x0A, 0xD0, 0x90, 0xF9, 0x02, 0x30, ++ 0x81, 0x78, 0x00, 0x2B, 0x05, 0xDB, 0x10, 0x46, 0x0A, 0x09, 0x01, 0xF0, ++ 0x03, 0x01, 0xFF, 0xF7, 0xDD, 0xFB, 0x01, 0x9A, 0x4F, 0xF4, 0xA4, 0x63, ++ 0x03, 0xFB, 0x02, 0xA3, 0x06, 0x93, 0xD3, 0xF8, 0xCC, 0x31, 0x18, 0x07, ++ 0x7F, 0xF5, 0x2D, 0xAF, 0x02, 0x23, 0x05, 0x22, 0x00, 0x21, 0x6D, 0x20, ++ 0xFA, 0xF7, 0x46, 0xF9, 0x41, 0x46, 0x02, 0x46, 0x07, 0x90, 0x18, 0xEE, ++ 0x10, 0x0A, 0xFD, 0xF7, 0x45, 0xFF, 0x07, 0x9A, 0x10, 0x46, 0xFA, 0xF7, ++ 0x6B, 0xF9, 0x22, 0x4B, 0x1B, 0x69, 0x00, 0x2B, 0x3F, 0xF4, 0x17, 0xAF, ++ 0x02, 0x9B, 0x03, 0xF5, 0xA8, 0x72, 0x18, 0xEE, 0x10, 0x0A, 0x0D, 0xF1, ++ 0x27, 0x03, 0x52, 0x44, 0x41, 0x46, 0xFD, 0xF7, 0x05, 0xFF, 0x9D, 0xF8, ++ 0x27, 0x30, 0x00, 0x2B, 0x3F, 0xF4, 0x07, 0xAF, 0x10, 0x23, 0x05, 0x22, ++ 0x00, 0x21, 0x6B, 0x20, 0xFA, 0xF7, 0x20, 0xF9, 0x06, 0x9A, 0x11, 0x46, ++ 0x15, 0x46, 0xD2, 0xF8, 0x50, 0xE1, 0xD2, 0xF8, 0x54, 0x21, 0xD1, 0xF8, ++ 0x58, 0x11, 0xD5, 0xF8, 0x5C, 0x51, 0xC5, 0x60, 0xC0, 0xE9, 0x00, 0xE2, ++ 0x81, 0x60, 0xFA, 0xF7, 0x3F, 0xF9, 0xEE, 0xE6, 0x03, 0x21, 0x28, 0xE6, ++ 0x03, 0x22, 0x33, 0xE6, 0x02, 0x22, 0x31, 0xE6, 0x02, 0x21, 0x22, 0xE6, ++ 0x40, 0xF2, 0xFF, 0x33, 0x1D, 0x46, 0xFD, 0xE6, 0xE4, 0xB8, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xD4, 0xB8, 0x15, 0x00, 0xF4, 0xB8, 0x15, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, 0x94, 0x64, 0x17, 0x00, ++ 0x70, 0xB5, 0x0C, 0x46, 0x84, 0xB0, 0x89, 0x78, 0x0C, 0x4D, 0x26, 0x79, ++ 0x8D, 0xF8, 0x04, 0x10, 0xAD, 0xF8, 0x08, 0x20, 0x01, 0x46, 0x9D, 0xF8, ++ 0x20, 0x20, 0x20, 0x88, 0xE4, 0x78, 0xAD, 0xF8, 0x0A, 0x30, 0xAD, 0xF8, ++ 0x06, 0x00, 0x6B, 0x6C, 0x8D, 0xF8, 0x0C, 0x60, 0x8D, 0xF8, 0x0D, 0x40, ++ 0x8D, 0xF8, 0x05, 0x20, 0x01, 0xA8, 0x98, 0x47, 0x04, 0xB0, 0x70, 0xBD, ++ 0x88, 0x1A, 0x17, 0x00, 0x03, 0x68, 0x30, 0xB4, 0x0C, 0x68, 0x5A, 0x40, ++ 0x84, 0xEA, 0xF2, 0x34, 0x22, 0x44, 0x13, 0x0A, 0x15, 0x02, 0x05, 0xF0, ++ 0xFF, 0x25, 0x03, 0xF0, 0xFF, 0x13, 0x2B, 0x43, 0x63, 0x40, 0x1A, 0x44, ++ 0x83, 0xEA, 0x72, 0x73, 0x1A, 0x44, 0x83, 0xEA, 0xB2, 0x03, 0x1A, 0x44, ++ 0x0B, 0x60, 0x30, 0xBC, 0x02, 0x60, 0x70, 0x47, 0xF8, 0xB5, 0x1F, 0x88, ++ 0xD3, 0xF8, 0x02, 0x50, 0x0B, 0x68, 0x96, 0x88, 0x12, 0x68, 0x03, 0x60, ++ 0x9D, 0xF8, 0x18, 0x40, 0x4B, 0x68, 0x43, 0x60, 0x00, 0x23, 0xFF, 0x2C, ++ 0x83, 0x60, 0x03, 0x73, 0x00, 0xF1, 0x04, 0x01, 0x46, 0xEA, 0x07, 0x46, ++ 0x14, 0xBF, 0x04, 0xF0, 0x07, 0x04, 0x00, 0x24, 0xFF, 0xF7, 0xCC, 0xFF, ++ 0x32, 0x46, 0xFF, 0xF7, 0xC9, 0xFF, 0x2A, 0x46, 0xFF, 0xF7, 0xC6, 0xFF, ++ 0x22, 0x46, 0xBD, 0xE8, 0xF8, 0x40, 0xFF, 0xF7, 0xC1, 0xBF, 0x00, 0xBF, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0x21, 0xF0, 0x03, 0x06, 0x01, 0xF0, 0x03, 0x01, ++ 0xC1, 0xF1, 0x04, 0x03, 0x37, 0x68, 0x90, 0xF8, 0x0C, 0xC0, 0x85, 0x68, ++ 0xDB, 0xB2, 0x04, 0x36, 0xC9, 0x00, 0x9A, 0x42, 0x83, 0xB0, 0x27, 0xFA, ++ 0x01, 0xF1, 0xB1, 0x46, 0x78, 0xD2, 0xC2, 0xF1, 0x04, 0x04, 0xE3, 0x00, ++ 0x4F, 0xF0, 0xFF, 0x34, 0x4F, 0xF0, 0x00, 0x0B, 0xDC, 0x40, 0x21, 0x40, ++ 0xD8, 0x46, 0x5F, 0x46, 0x0C, 0xEB, 0x02, 0x04, 0x03, 0x2C, 0x52, 0xD8, ++ 0x4F, 0xEA, 0xCC, 0x0C, 0x01, 0xFA, 0x0C, 0xF1, 0x0D, 0x43, 0xB8, 0xF1, ++ 0x00, 0x0F, 0x22, 0xD0, 0xE3, 0x00, 0xC4, 0xF1, 0x04, 0x0A, 0x00, 0x93, ++ 0x4F, 0xEA, 0x88, 0x03, 0x4F, 0xEA, 0xCA, 0x0A, 0x01, 0x1D, 0x01, 0x93, ++ 0x06, 0xEB, 0x88, 0x08, 0xB1, 0x46, 0xD9, 0xF8, 0x00, 0x30, 0x00, 0x9A, ++ 0x03, 0xFA, 0x02, 0xF2, 0xBA, 0xF1, 0x20, 0x0F, 0x42, 0xEA, 0x05, 0x02, ++ 0x09, 0xF1, 0x04, 0x09, 0x14, 0xBF, 0x23, 0xFA, 0x0A, 0xF5, 0x00, 0x25, ++ 0xFF, 0xF7, 0x76, 0xFF, 0xC1, 0x45, 0xEC, 0xD1, 0x01, 0x9B, 0x33, 0x44, ++ 0x99, 0x46, 0x5F, 0x45, 0x20, 0xD9, 0x07, 0xF0, 0x03, 0x07, 0xC7, 0xF1, ++ 0x04, 0x03, 0xDA, 0x00, 0x20, 0x2A, 0xD9, 0xF8, 0x00, 0x10, 0x40, 0xD0, ++ 0x4F, 0xF0, 0xFF, 0x33, 0xD3, 0x40, 0x0B, 0x40, 0xE2, 0x00, 0x03, 0xFA, ++ 0x02, 0xF2, 0x15, 0x43, 0x27, 0x44, 0x03, 0x2F, 0x2F, 0xD9, 0xC4, 0xF1, ++ 0x04, 0x04, 0xE4, 0x00, 0x20, 0x2C, 0x14, 0xBF, 0xE3, 0x40, 0x00, 0x23, ++ 0x2A, 0x46, 0x01, 0x1D, 0x3C, 0x1F, 0x1D, 0x46, 0xFF, 0xF7, 0x4E, 0xFF, ++ 0x85, 0x60, 0x04, 0x73, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x4F, 0xEA, ++ 0xCC, 0x02, 0xCC, 0xF1, 0x04, 0x0C, 0x4F, 0xEA, 0xCC, 0x0C, 0xBC, 0xF1, ++ 0x20, 0x0F, 0x01, 0xFA, 0x02, 0xF2, 0x42, 0xEA, 0x05, 0x02, 0x18, 0xBF, ++ 0x21, 0xFA, 0x0C, 0xF5, 0x00, 0xF1, 0x04, 0x01, 0x08, 0xBF, 0x00, 0x25, ++ 0x04, 0x3C, 0xFF, 0xF7, 0x33, 0xFF, 0x9A, 0xE7, 0xD7, 0x1A, 0x4F, 0xEA, ++ 0x97, 0x08, 0x1A, 0x46, 0x27, 0xF0, 0x03, 0x0B, 0x8A, 0xE7, 0x3C, 0x46, ++ 0x85, 0x60, 0x04, 0x73, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x00, 0x23, ++ 0xC4, 0xE7, 0x00, 0xBF, 0x38, 0xB5, 0x10, 0x4B, 0x85, 0x68, 0x1B, 0x68, ++ 0x02, 0x7B, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x04, 0x46, 0x0D, 0xDB, ++ 0x5A, 0x23, 0xD2, 0x00, 0x03, 0xFA, 0x02, 0xF2, 0x2A, 0x43, 0x21, 0x1D, ++ 0x20, 0x46, 0xFF, 0xF7, 0x0F, 0xFF, 0xBD, 0xE8, 0x38, 0x40, 0x00, 0x22, ++ 0xFF, 0xF7, 0x0A, 0xBF, 0x03, 0x2A, 0xEF, 0xD9, 0x40, 0xF2, 0x41, 0x12, ++ 0x03, 0x49, 0x04, 0x48, 0xFC, 0xF7, 0xB8, 0xF8, 0x22, 0x7B, 0xE7, 0xE7, ++ 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x20, 0xB9, 0x15, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0x06, 0x20, 0x83, 0xB0, 0x00, 0x24, 0xCD, 0xE9, ++ 0x00, 0x44, 0x91, 0xF8, 0x3D, 0x90, 0x0D, 0x46, 0x17, 0x46, 0x1E, 0x46, ++ 0xFA, 0xF7, 0x62, 0xFA, 0x09, 0x28, 0x79, 0xD0, 0x01, 0x23, 0x3A, 0x46, ++ 0x31, 0x46, 0x41, 0xF6, 0x01, 0x00, 0xF9, 0xF7, 0xB7, 0xFF, 0x80, 0x46, ++ 0x06, 0x20, 0xFA, 0xF7, 0x55, 0xFA, 0x48, 0xB1, 0x08, 0x26, 0x40, 0x46, ++ 0x88, 0xF8, 0x00, 0x60, 0xF9, 0xF7, 0xDC, 0xFF, 0x20, 0x46, 0x03, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x8F, 0xDF, 0xF8, 0xAC, 0xA1, 0x4F, 0xF4, 0xA4, 0x63, ++ 0x03, 0xFB, 0x09, 0xA3, 0x93, 0xF8, 0x62, 0x20, 0x00, 0x2A, 0x4F, 0xD1, ++ 0x93, 0xF8, 0x64, 0x30, 0x00, 0x2B, 0x4B, 0xD1, 0xDF, 0xF8, 0x94, 0xB1, ++ 0x5A, 0x4A, 0x5B, 0x49, 0x13, 0x68, 0x43, 0xF0, 0x10, 0x03, 0x13, 0x60, ++ 0x95, 0xF8, 0x3B, 0x30, 0x01, 0x22, 0x02, 0x2B, 0xCA, 0x75, 0x0E, 0xD0, ++ 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, 0x09, 0xA2, 0x92, 0xF8, 0x64, 0x10, ++ 0x29, 0xB9, 0x53, 0x4C, 0x21, 0x68, 0xB1, 0xF9, 0x00, 0x10, 0x00, 0x29, ++ 0x7F, 0xDB, 0x03, 0x2B, 0x57, 0xD0, 0x3A, 0x46, 0x4F, 0xF4, 0x55, 0x73, ++ 0x31, 0x46, 0x41, 0xF6, 0x02, 0x00, 0xCB, 0xF8, 0x00, 0x50, 0xF9, 0xF7, ++ 0x73, 0xFF, 0x95, 0xF8, 0x3B, 0x30, 0xCB, 0xF8, 0x04, 0x00, 0x00, 0x27, ++ 0x02, 0x2B, 0x8B, 0xF8, 0x16, 0x70, 0x4F, 0xD0, 0x9B, 0xF8, 0x1E, 0x60, ++ 0x3E, 0xB3, 0x95, 0xF8, 0x3D, 0x10, 0x44, 0x48, 0x4F, 0xF4, 0xA4, 0x64, ++ 0x04, 0xFB, 0x01, 0xA1, 0x06, 0x22, 0x38, 0x31, 0x0E, 0xF0, 0xE4, 0xFA, ++ 0x09, 0x21, 0x06, 0x20, 0xFA, 0xF7, 0x52, 0xF9, 0x95, 0xF8, 0x3D, 0x00, ++ 0x39, 0x46, 0x04, 0xFB, 0x00, 0xA0, 0x01, 0xF0, 0xCB, 0xF8, 0x3E, 0x46, ++ 0x01, 0x24, 0x9C, 0xE7, 0x95, 0xF8, 0x3B, 0x30, 0x02, 0x2B, 0xAF, 0xD0, ++ 0x2C, 0x6B, 0x14, 0xF0, 0x20, 0x04, 0x17, 0xD1, 0x09, 0x26, 0x92, 0xE7, ++ 0x02, 0x24, 0x20, 0x46, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x01, 0xA9, ++ 0x68, 0x46, 0x00, 0xF0, 0x75, 0xFD, 0xDD, 0xE9, 0x00, 0x01, 0x28, 0xB1, ++ 0x21, 0xB1, 0x32, 0x46, 0x00, 0xF0, 0x14, 0xFE, 0x01, 0x24, 0x80, 0xE7, ++ 0x00, 0xF0, 0x90, 0xFD, 0x01, 0x24, 0x7C, 0xE7, 0xDF, 0xF8, 0xBC, 0xB0, ++ 0x28, 0x48, 0x01, 0x23, 0x8B, 0xF8, 0x1E, 0x30, 0xFB, 0xF7, 0x8E, 0xFD, ++ 0x8C, 0xE7, 0xE9, 0x8E, 0x05, 0xF1, 0x40, 0x00, 0x02, 0xF0, 0x32, 0xF8, ++ 0x00, 0x28, 0xC4, 0xBF, 0x00, 0x23, 0x85, 0xF8, 0x3B, 0x30, 0x9C, 0xE7, ++ 0x95, 0xF8, 0x3D, 0x10, 0x1F, 0x48, 0x4F, 0xF4, 0xA4, 0x66, 0x06, 0xFB, ++ 0x01, 0xA1, 0x06, 0x22, 0x38, 0x31, 0x01, 0x24, 0x8B, 0xF8, 0x16, 0x40, ++ 0x0E, 0xF0, 0x94, 0xFA, 0x09, 0x21, 0x06, 0x20, 0xFA, 0xF7, 0x02, 0xF9, ++ 0x95, 0xF8, 0x3D, 0x00, 0x39, 0x46, 0x06, 0xFB, 0x00, 0xA0, 0x01, 0xF0, ++ 0x7B, 0xF8, 0x3E, 0x46, 0x4D, 0xE7, 0x92, 0xF8, 0x6C, 0x30, 0xFF, 0x2B, ++ 0x09, 0xD0, 0x12, 0x49, 0x12, 0x48, 0x64, 0x22, 0xFB, 0xF7, 0xD8, 0xFF, ++ 0x23, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x0B, 0xDA, 0x4F, 0xF4, ++ 0xA4, 0x63, 0x03, 0xFB, 0x09, 0xA9, 0xD9, 0xF8, 0x40, 0x30, 0x23, 0xB1, ++ 0x09, 0x49, 0x0B, 0x48, 0x65, 0x22, 0xFB, 0xF7, 0xC7, 0xFF, 0x95, 0xF8, ++ 0x3B, 0x30, 0x62, 0xE7, 0x94, 0x40, 0x04, 0x40, 0x4C, 0x36, 0x17, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x84, 0xBA, 0x17, 0x00, 0x40, 0xB9, 0x15, 0x00, ++ 0x7C, 0xBA, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x4C, 0xB9, 0x15, 0x00, ++ 0xA0, 0xA2, 0x15, 0x00, 0x18, 0x88, 0x17, 0x00, 0x64, 0xBA, 0x17, 0x00, ++ 0x38, 0xB5, 0x0B, 0x46, 0x4F, 0xF4, 0x80, 0x70, 0x0F, 0x49, 0x1C, 0x78, ++ 0xFB, 0xF7, 0x7C, 0xFD, 0x06, 0x20, 0xFA, 0xF7, 0x63, 0xF9, 0xA8, 0xB9, ++ 0x0C, 0x4B, 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, 0x04, 0x34, 0x94, 0xF8, ++ 0x62, 0x50, 0x15, 0xB9, 0x94, 0xF8, 0x64, 0x00, 0x00, 0xB9, 0x38, 0xBD, ++ 0x09, 0x21, 0x06, 0x20, 0xFA, 0xF7, 0xAA, 0xF8, 0x20, 0x46, 0x01, 0x21, ++ 0x01, 0xF0, 0x26, 0xF8, 0x28, 0x46, 0x38, 0xBD, 0x02, 0x20, 0x38, 0xBD, ++ 0x70, 0xB9, 0x15, 0x00, 0x18, 0x88, 0x17, 0x00, 0x08, 0xB5, 0x06, 0x20, ++ 0xFA, 0xF7, 0x42, 0xF9, 0x05, 0x28, 0x04, 0xD0, 0x06, 0x20, 0xFA, 0xF7, ++ 0x3D, 0xF9, 0x06, 0x28, 0x04, 0xD1, 0x01, 0x20, 0x01, 0xF0, 0x9C, 0xF9, ++ 0x00, 0x20, 0x08, 0xBD, 0x06, 0x20, 0xFA, 0xF7, 0x33, 0xF9, 0x07, 0x28, ++ 0xF5, 0xD0, 0x00, 0x20, 0x08, 0xBD, 0x00, 0xBF, 0x16, 0x4B, 0x00, 0xB5, ++ 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x20, 0x00, 0x23, 0x83, 0xB0, 0x9A, 0x42, ++ 0xCD, 0xE9, 0x00, 0x33, 0x15, 0xDB, 0x68, 0x46, 0x01, 0xA9, 0x00, 0xF0, ++ 0xB7, 0xFC, 0x00, 0x98, 0x40, 0xB1, 0x01, 0x99, 0x31, 0xB1, 0x00, 0x22, ++ 0x00, 0xF0, 0x56, 0xFD, 0x00, 0x20, 0x03, 0xB0, 0x5D, 0xF8, 0x04, 0xFB, ++ 0x01, 0x20, 0x01, 0xF0, 0x75, 0xF9, 0x00, 0x20, 0x03, 0xB0, 0x5D, 0xF8, ++ 0x04, 0xFB, 0x06, 0x20, 0xFA, 0xF7, 0x0A, 0xF9, 0x01, 0x28, 0xE4, 0xD0, ++ 0x04, 0x49, 0x05, 0x48, 0x4F, 0xF4, 0x8F, 0x72, 0xFB, 0xF7, 0x42, 0xFF, ++ 0xDD, 0xE7, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x80, 0xB9, 0x15, 0x00, 0x93, 0x4B, 0x2D, 0xE9, 0xF0, 0x4F, 0x1B, 0x68, ++ 0x92, 0x4D, 0xB3, 0xF9, 0x00, 0x30, 0x2F, 0x68, 0x00, 0x2B, 0x89, 0xB0, ++ 0xC0, 0xF2, 0x91, 0x80, 0x97, 0xF8, 0x3D, 0x80, 0x8E, 0x4E, 0x4F, 0xF4, ++ 0xA4, 0x64, 0x04, 0xFB, 0x08, 0x64, 0xD4, 0xF8, 0xCC, 0x31, 0x00, 0x2B, ++ 0x18, 0xDB, 0x6B, 0x7D, 0x33, 0xB9, 0x01, 0x20, 0x01, 0xF0, 0x42, 0xF9, ++ 0x00, 0x20, 0x09, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x00, 0x23, 0x07, 0xA9, ++ 0x06, 0xA8, 0xCD, 0xE9, 0x06, 0x33, 0x00, 0xF0, 0x6B, 0xFC, 0xDD, 0xE9, ++ 0x06, 0x01, 0x01, 0x22, 0x00, 0xF0, 0x0C, 0xFD, 0x00, 0x20, 0x09, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x8F, 0x07, 0xA8, 0x00, 0xF0, 0xE1, 0xFD, 0x00, 0x28, ++ 0x74, 0xD1, 0x01, 0x46, 0x20, 0x23, 0x06, 0x22, 0x0A, 0x20, 0xF9, 0xF7, ++ 0x1D, 0xFE, 0x94, 0xF8, 0xC0, 0x34, 0x05, 0x46, 0x2B, 0xB1, 0xD4, 0xF8, ++ 0xCC, 0x21, 0x22, 0xF0, 0x08, 0x02, 0xC4, 0xF8, 0xCC, 0x21, 0x74, 0x4A, ++ 0x92, 0xF8, 0x04, 0x21, 0x4A, 0xB1, 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, ++ 0x08, 0xF2, 0xB1, 0x18, 0xD1, 0xF8, 0x90, 0x01, 0x80, 0x78, 0x01, 0x28, ++ 0x6D, 0xD0, 0x6E, 0x4B, 0x97, 0xF8, 0x3D, 0x00, 0xDB, 0x6C, 0x9D, 0xF8, ++ 0x1C, 0x10, 0x98, 0x47, 0x4F, 0xF4, 0xA4, 0x6B, 0x00, 0x23, 0x2B, 0x60, ++ 0x0B, 0xFB, 0x08, 0xFB, 0x97, 0xF8, 0x3D, 0x20, 0x6A, 0x76, 0x06, 0xEB, ++ 0x0B, 0x0A, 0xDA, 0xF8, 0x64, 0x01, 0xBA, 0xF8, 0x68, 0x21, 0xAB, 0x76, ++ 0x9A, 0xF8, 0x8B, 0x31, 0x6B, 0x77, 0x9A, 0xF8, 0x8C, 0x31, 0xAB, 0x77, ++ 0xDA, 0xF8, 0xCC, 0x31, 0xC5, 0xF8, 0x12, 0x00, 0x13, 0xF0, 0x02, 0x04, ++ 0xEA, 0x82, 0x1B, 0xD0, 0x0B, 0xF1, 0xEC, 0x09, 0x13, 0xF0, 0x04, 0x04, ++ 0xB1, 0x44, 0x6E, 0xD1, 0x21, 0x46, 0x13, 0xF0, 0x08, 0x02, 0x05, 0xF1, ++ 0x18, 0x03, 0x18, 0xBF, 0x0B, 0xF5, 0x8C, 0x72, 0x05, 0xF1, 0x04, 0x0C, ++ 0x02, 0x93, 0x05, 0xF1, 0x08, 0x03, 0xCD, 0xE9, 0x00, 0x3C, 0x18, 0xBF, ++ 0x92, 0x19, 0x48, 0x46, 0x05, 0xF1, 0x10, 0x03, 0xFE, 0xF7, 0x22, 0xFC, ++ 0x28, 0x46, 0xEC, 0x60, 0xF9, 0xF7, 0xF0, 0xFD, 0x03, 0x21, 0x06, 0x20, ++ 0xF9, 0xF7, 0xB6, 0xFF, 0x0F, 0xE0, 0x06, 0x20, 0xFA, 0xF7, 0x5A, 0xF8, ++ 0x02, 0x28, 0x3F, 0xF4, 0x69, 0xAF, 0x47, 0x49, 0x47, 0x48, 0x4F, 0xF4, ++ 0xA3, 0x72, 0xFB, 0xF7, 0x91, 0xFE, 0x61, 0xE7, 0x01, 0x20, 0x01, 0xF0, ++ 0xB1, 0xF8, 0x3A, 0x6B, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x08, 0x66, ++ 0x53, 0x07, 0xC6, 0xF8, 0xB0, 0x24, 0x7F, 0xF5, 0x65, 0xAF, 0xD6, 0xF8, ++ 0xCC, 0x31, 0x00, 0x20, 0x23, 0xF0, 0x0E, 0x03, 0xC6, 0xF8, 0xCC, 0x31, ++ 0x09, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xD1, 0xF8, 0xCC, 0x11, 0x11, 0xF0, ++ 0x0C, 0x0F, 0x8C, 0xD0, 0x00, 0x2B, 0x8A, 0xD1, 0xDF, 0xF8, 0xD8, 0x90, ++ 0x02, 0xF5, 0xB2, 0x72, 0xB4, 0x18, 0x9A, 0x46, 0xCB, 0x46, 0x58, 0x46, ++ 0x06, 0x22, 0x21, 0x46, 0x0E, 0xF0, 0xDC, 0xF8, 0x0B, 0xF1, 0x14, 0x0B, ++ 0x18, 0xB3, 0x0A, 0xF1, 0x01, 0x0A, 0xBA, 0xF1, 0x05, 0x0F, 0xF2, 0xD1, ++ 0x2C, 0x49, 0x50, 0x22, 0x01, 0xF1, 0x14, 0x00, 0x0E, 0xF0, 0xFE, 0xF8, ++ 0x29, 0x48, 0x21, 0x46, 0x06, 0x22, 0x0E, 0xF0, 0xF9, 0xF8, 0x01, 0x23, ++ 0xA9, 0xF8, 0x06, 0x30, 0x89, 0xF8, 0x08, 0x30, 0x65, 0xE7, 0x0B, 0xF5, ++ 0xB2, 0x70, 0x0B, 0xF5, 0x86, 0x71, 0x31, 0x44, 0x30, 0x44, 0x05, 0x91, ++ 0xFA, 0xF7, 0x28, 0xFF, 0xDA, 0xF8, 0xCC, 0x31, 0x05, 0x99, 0x04, 0x46, ++ 0x83, 0xE7, 0x0A, 0xEB, 0x8A, 0x03, 0x09, 0xEB, 0x83, 0x03, 0x4F, 0xEA, ++ 0x8A, 0x0B, 0x9A, 0x79, 0x14, 0x23, 0x03, 0xFB, 0x0A, 0x93, 0x4A, 0xB1, ++ 0xDB, 0x79, 0x53, 0xB1, 0x0B, 0xEB, 0x0A, 0x03, 0x09, 0xEB, 0x83, 0x09, ++ 0x01, 0x23, 0x89, 0xF8, 0x08, 0x30, 0x42, 0xE7, 0x01, 0x22, 0x9A, 0x71, ++ 0xF4, 0xE7, 0x4F, 0xF4, 0xA4, 0x64, 0x04, 0xFB, 0x08, 0x64, 0x00, 0x92, ++ 0xB4, 0xF8, 0x68, 0x31, 0xB4, 0xF8, 0x66, 0x21, 0xB4, 0xF8, 0x64, 0x11, ++ 0x0C, 0x48, 0xFB, 0xF7, 0x9F, 0xFB, 0xD4, 0xF8, 0xCC, 0x31, 0x23, 0xF0, ++ 0x0C, 0x03, 0xC4, 0xF8, 0xCC, 0x31, 0xDF, 0xE7, 0x38, 0x36, 0x17, 0x00, ++ 0x64, 0xBA, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, 0x2C, 0x19, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0xA8, 0xB9, 0x15, 0x00, ++ 0xCC, 0x35, 0x17, 0x00, 0xCC, 0xB9, 0x15, 0x00, 0x08, 0xB5, 0x16, 0x4B, ++ 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x0F, 0xDB, 0x06, 0x20, ++ 0xF9, 0xF7, 0xB6, 0xFF, 0x04, 0x28, 0x06, 0xD0, 0x06, 0x20, 0xF9, 0xF7, ++ 0xB1, 0xFF, 0x09, 0x28, 0x01, 0xD0, 0x00, 0x20, 0x08, 0xBD, 0x00, 0xF0, ++ 0xF5, 0xFC, 0x00, 0x20, 0x08, 0xBD, 0x06, 0x20, 0xF9, 0xF7, 0xA6, 0xFF, ++ 0x04, 0x28, 0xEA, 0xD0, 0x06, 0x20, 0xF9, 0xF7, 0xA1, 0xFF, 0x00, 0x28, ++ 0xE5, 0xD0, 0x06, 0x20, 0xF9, 0xF7, 0x9C, 0xFF, 0x09, 0x28, 0xE0, 0xD0, ++ 0x04, 0x49, 0x05, 0x48, 0x4F, 0xF4, 0x16, 0x72, 0xFB, 0xF7, 0xD4, 0xFD, ++ 0xD9, 0xE7, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0xE4, 0xB9, 0x15, 0x00, 0x08, 0xB5, 0x0C, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0x03, 0xDB, 0x00, 0xF0, 0xCD, 0xFC, 0x00, 0x20, ++ 0x08, 0xBD, 0x06, 0x20, 0xF9, 0xF7, 0x7E, 0xFF, 0x04, 0x28, 0xF6, 0xD0, ++ 0x05, 0x49, 0x06, 0x48, 0x40, 0xF2, 0x79, 0x22, 0xFB, 0xF7, 0xB6, 0xFD, ++ 0x00, 0xF0, 0xBE, 0xFC, 0x00, 0x20, 0x08, 0xBD, 0x38, 0x36, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x6C, 0xBA, 0x15, 0x00, 0x08, 0xB5, 0x0C, 0x4B, ++ 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x03, 0xDB, 0x00, 0xF0, ++ 0xAD, 0xFC, 0x00, 0x20, 0x08, 0xBD, 0x06, 0x20, 0xF9, 0xF7, 0x5E, 0xFF, ++ 0x09, 0x28, 0xF6, 0xD0, 0x05, 0x49, 0x06, 0x48, 0x40, 0xF2, 0x29, 0x32, ++ 0xFB, 0xF7, 0x96, 0xFD, 0x00, 0xF0, 0x9E, 0xFC, 0x00, 0x20, 0x08, 0xBD, ++ 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x9C, 0xBA, 0x15, 0x00, ++ 0x08, 0xB5, 0x0C, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0x03, 0xDB, 0x00, 0xF0, 0x8D, 0xFC, 0x00, 0x20, 0x08, 0xBD, 0x06, 0x20, ++ 0xF9, 0xF7, 0x3E, 0xFF, 0x09, 0x28, 0xF6, 0xD0, 0x05, 0x49, 0x06, 0x48, ++ 0x40, 0xF2, 0x43, 0x32, 0xFB, 0xF7, 0x76, 0xFD, 0x00, 0xF0, 0x7E, 0xFC, ++ 0x00, 0x20, 0x08, 0xBD, 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x9C, 0xBA, 0x15, 0x00, 0x37, 0x4B, 0x30, 0xB5, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0x83, 0xB0, 0x37, 0xDB, 0x06, 0x20, 0xF9, 0xF7, ++ 0x21, 0xFF, 0x09, 0x28, 0x10, 0xD0, 0x32, 0x4B, 0x9A, 0x7D, 0x01, 0x2A, ++ 0x50, 0xD0, 0x1B, 0x68, 0x93, 0xF8, 0x3B, 0x30, 0x02, 0x2B, 0x3A, 0xD9, ++ 0x03, 0x2B, 0x3F, 0xD1, 0x2D, 0x48, 0x01, 0xF0, 0xF5, 0xFC, 0x00, 0x20, ++ 0x03, 0xB0, 0x30, 0xBD, 0x29, 0x4C, 0xA2, 0x6A, 0x23, 0x7D, 0x00, 0x25, ++ 0xC2, 0xF8, 0xCC, 0x51, 0x00, 0x2B, 0x40, 0xD1, 0xA0, 0x68, 0x0C, 0x30, ++ 0xF9, 0xF7, 0x90, 0xFC, 0xA3, 0x7D, 0x00, 0x22, 0x01, 0x2B, 0xA2, 0x60, ++ 0x01, 0xD0, 0xA1, 0x7F, 0x61, 0xB3, 0x00, 0x24, 0x01, 0xA9, 0x68, 0x46, ++ 0xCD, 0xE9, 0x00, 0x44, 0x00, 0xF0, 0x8C, 0xFA, 0xDD, 0xE9, 0x00, 0x01, ++ 0x22, 0x46, 0x00, 0xF0, 0x2D, 0xFB, 0x00, 0x20, 0x03, 0xB0, 0x30, 0xBD, ++ 0x06, 0x20, 0xF9, 0xF7, 0xE9, 0xFE, 0x04, 0x28, 0xC2, 0xD0, 0x06, 0x20, ++ 0xF9, 0xF7, 0xE4, 0xFE, 0x09, 0x28, 0xBD, 0xD0, 0x15, 0x49, 0x16, 0x48, ++ 0x40, 0xF2, 0x93, 0x22, 0xFB, 0xF7, 0x1C, 0xFD, 0xB6, 0xE7, 0x00, 0x21, ++ 0x01, 0x20, 0x01, 0xF0, 0x2B, 0xF8, 0x00, 0x20, 0x03, 0xB0, 0x30, 0xBD, ++ 0x01, 0x20, 0x00, 0xF0, 0x35, 0xFF, 0x00, 0x20, 0x03, 0xB0, 0x30, 0xBD, ++ 0x06, 0x20, 0xF9, 0xF7, 0x23, 0xFE, 0xDA, 0xE7, 0x01, 0xF0, 0x48, 0xF9, ++ 0x00, 0x20, 0x03, 0xB0, 0x30, 0xBD, 0x06, 0x22, 0x0C, 0x21, 0x41, 0xF6, ++ 0x04, 0x00, 0xF9, 0xF7, 0x85, 0xFC, 0x25, 0x75, 0xB6, 0xE7, 0x00, 0xBF, ++ 0x38, 0x36, 0x17, 0x00, 0x64, 0xBA, 0x17, 0x00, 0x08, 0xAC, 0x0F, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xC8, 0xBA, 0x15, 0x00, 0x4B, 0x88, 0x03, 0xF0, ++ 0xFC, 0x03, 0xB0, 0x2B, 0x10, 0xB5, 0x0C, 0x46, 0x13, 0xD0, 0x10, 0x2B, ++ 0x0A, 0xD0, 0x30, 0x2B, 0x08, 0xD0, 0xC0, 0x2B, 0x01, 0xD0, 0xA0, 0x2B, ++ 0x14, 0xD1, 0x20, 0x46, 0xBD, 0xE8, 0x10, 0x40, 0x01, 0xF0, 0x78, 0xBB, ++ 0x06, 0x20, 0xF9, 0xF7, 0x9B, 0xFE, 0x07, 0x28, 0x13, 0xD0, 0x00, 0x20, ++ 0x10, 0xBD, 0x06, 0x20, 0xF9, 0xF7, 0x94, 0xFE, 0x05, 0x28, 0xF8, 0xD1, ++ 0x20, 0x46, 0x01, 0xF0, 0x37, 0xFA, 0xF4, 0xE7, 0xD0, 0x2B, 0xF2, 0xD1, ++ 0x23, 0x7B, 0x08, 0x2B, 0xEF, 0xD1, 0x20, 0x46, 0x01, 0xF0, 0xD4, 0xFB, ++ 0xEB, 0xE7, 0x20, 0x46, 0x01, 0xF0, 0x70, 0xFA, 0xE7, 0xE7, 0x00, 0xBF, ++ 0x10, 0xB5, 0x06, 0x20, 0x0C, 0x46, 0xF9, 0xF7, 0x7B, 0xFE, 0x06, 0x28, ++ 0x01, 0xD0, 0x00, 0x20, 0x10, 0xBD, 0x60, 0x88, 0x01, 0xF0, 0xC8, 0xFC, ++ 0x00, 0x20, 0x10, 0xBD, 0x10, 0xB5, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, ++ 0x03, 0xD4, 0x72, 0xB6, 0x0D, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x0D, 0x4C, ++ 0x0D, 0x4A, 0x23, 0x68, 0xD2, 0x7D, 0x01, 0x33, 0x01, 0x2A, 0x23, 0x60, ++ 0x0C, 0xD0, 0x33, 0xB1, 0x07, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x23, 0x60, ++ 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0x07, 0x48, 0xFB, 0xF7, 0x1C, 0xFA, ++ 0x00, 0x20, 0x10, 0xBD, 0x00, 0xF0, 0x16, 0xFB, 0x23, 0x68, 0xEE, 0xE7, ++ 0x38, 0x61, 0x17, 0x00, 0x6C, 0x28, 0x17, 0x00, 0x4C, 0x36, 0x17, 0x00, ++ 0x28, 0xBB, 0x15, 0x00, 0x38, 0xB5, 0x06, 0x20, 0x0D, 0x46, 0xF9, 0xF7, ++ 0x43, 0xFE, 0x30, 0xB9, 0x04, 0x46, 0x29, 0x88, 0xA8, 0x78, 0x00, 0xF0, ++ 0xB7, 0xFD, 0x20, 0x46, 0x38, 0xBD, 0x02, 0x20, 0x38, 0xBD, 0x00, 0xBF, ++ 0x8B, 0x4B, 0x2D, 0xE9, 0xF0, 0x4F, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0x89, 0xB0, 0x0C, 0x46, 0xC0, 0xF2, 0xFD, 0x80, 0x25, 0x78, ++ 0x00, 0x2D, 0x40, 0xF0, 0xF2, 0x80, 0x63, 0x78, 0x00, 0x93, 0x4F, 0xF4, ++ 0x1E, 0x74, 0x04, 0xFB, 0x03, 0xF4, 0x82, 0x4B, 0xDF, 0xF8, 0x18, 0xA2, ++ 0x1F, 0x19, 0x4F, 0xF4, 0xA4, 0x6C, 0x97, 0xF8, 0x22, 0xE0, 0x0C, 0xFB, ++ 0x0E, 0xAC, 0x0C, 0xF5, 0xCE, 0x73, 0x0F, 0xCB, 0x07, 0xF1, 0xB8, 0x06, ++ 0x07, 0xC6, 0xDC, 0xF8, 0xCC, 0x81, 0x33, 0x70, 0x18, 0xF0, 0x01, 0x0F, ++ 0x03, 0xD0, 0x7B, 0x68, 0x43, 0xF0, 0x01, 0x03, 0x7B, 0x60, 0x18, 0xF0, ++ 0x02, 0x0F, 0x58, 0xD0, 0x4F, 0xF4, 0xA4, 0x66, 0x06, 0xFB, 0x0E, 0xA3, ++ 0x03, 0xF1, 0xEC, 0x0B, 0x00, 0x9E, 0x01, 0x93, 0xBB, 0xE8, 0x0F, 0x00, ++ 0xB4, 0x46, 0x6E, 0x4E, 0x4F, 0xF4, 0x1E, 0x79, 0x09, 0xFB, 0x0C, 0x69, ++ 0x09, 0xF1, 0xC8, 0x0C, 0xAC, 0xE8, 0x0F, 0x00, 0x9B, 0xE8, 0x0F, 0x00, ++ 0xD9, 0xF8, 0x04, 0xB0, 0x18, 0xF0, 0x08, 0x0F, 0x4B, 0xF0, 0x02, 0x06, ++ 0x8C, 0xE8, 0x0F, 0x00, 0xC9, 0xF8, 0x04, 0x60, 0x15, 0xD0, 0x01, 0x9B, ++ 0x03, 0xF5, 0x8C, 0x76, 0x0F, 0xCE, 0x09, 0xF1, 0xF4, 0x0C, 0xAC, 0xE8, ++ 0x0F, 0x00, 0x0F, 0xCE, 0xAC, 0xE8, 0x0F, 0x00, 0x0F, 0xCE, 0xAC, 0xE8, ++ 0x0F, 0x00, 0x96, 0xE8, 0x03, 0x00, 0x8C, 0xE8, 0x03, 0x00, 0x4B, 0xF0, ++ 0x22, 0x03, 0xC9, 0xF8, 0x04, 0x30, 0x18, 0xF0, 0x04, 0x0F, 0x16, 0xD0, ++ 0x4F, 0xF4, 0xA4, 0x63, 0x00, 0x9E, 0x03, 0xFB, 0x0E, 0xA3, 0x03, 0xF5, ++ 0x86, 0x73, 0x93, 0xE8, 0x07, 0x00, 0xB4, 0x46, 0x51, 0x4E, 0x4F, 0xF4, ++ 0x1E, 0x73, 0x03, 0xFB, 0x0C, 0x63, 0x03, 0xF1, 0xE8, 0x06, 0x86, 0xE8, ++ 0x07, 0x00, 0x5A, 0x68, 0x42, 0xF0, 0x04, 0x02, 0x5A, 0x60, 0x4F, 0xF4, ++ 0xA4, 0x61, 0x01, 0xFB, 0x0E, 0xA1, 0xEC, 0x31, 0x38, 0x46, 0xFE, 0xF7, ++ 0x81, 0xF8, 0x48, 0x4B, 0xD3, 0xF8, 0x14, 0x33, 0x98, 0x47, 0x47, 0x4B, ++ 0x1B, 0x78, 0x00, 0x2B, 0x66, 0xD0, 0x00, 0x9A, 0x42, 0x49, 0x4F, 0xF4, ++ 0x1E, 0x73, 0x03, 0xFB, 0x02, 0x13, 0x93, 0xF8, 0xB8, 0x20, 0x00, 0x23, ++ 0xCD, 0xE9, 0x02, 0x33, 0xCD, 0xE9, 0x05, 0x33, 0x04, 0x93, 0x07, 0x93, ++ 0x00, 0x2A, 0x70, 0xD0, 0x01, 0x3A, 0xD2, 0xB2, 0xB8, 0x34, 0x02, 0xAE, ++ 0x0D, 0xF1, 0x14, 0x0C, 0x9B, 0x46, 0x0D, 0xF1, 0x09, 0x03, 0x01, 0x92, ++ 0x0C, 0x44, 0x03, 0xEB, 0x02, 0x09, 0x31, 0x46, 0x62, 0x46, 0x4F, 0xF0, ++ 0x01, 0x08, 0x40, 0xF2, 0x05, 0x2A, 0x07, 0xE0, 0x01, 0xF8, 0x01, 0x0B, ++ 0x49, 0x45, 0x82, 0xF8, 0x00, 0x80, 0x02, 0xF1, 0x01, 0x02, 0x14, 0xD0, ++ 0x14, 0xF8, 0x01, 0x0F, 0x00, 0xF0, 0x7F, 0x03, 0x02, 0x3B, 0xDB, 0xB2, ++ 0x09, 0x2B, 0x08, 0xFA, 0x03, 0xFE, 0xED, 0xD8, 0x1E, 0xEA, 0x0A, 0x0F, ++ 0xEA, 0xD0, 0x01, 0xF8, 0x01, 0x0B, 0x49, 0x45, 0x82, 0xF8, 0x00, 0xB0, ++ 0x02, 0xF1, 0x01, 0x02, 0xEA, 0xD1, 0x01, 0x9A, 0x0C, 0xF1, 0x01, 0x03, ++ 0x1A, 0x44, 0x11, 0x46, 0x00, 0x9A, 0x10, 0x46, 0x1E, 0x4A, 0x4F, 0xF4, ++ 0x1E, 0x74, 0x04, 0xFB, 0x00, 0x24, 0x00, 0xE0, 0x01, 0x33, 0x9C, 0xF8, ++ 0x00, 0x20, 0x9C, 0x46, 0x2A, 0xB1, 0x62, 0x19, 0x30, 0x78, 0x82, 0xF8, ++ 0xB9, 0x00, 0x01, 0x35, 0xED, 0xB2, 0x8B, 0x42, 0x06, 0xF1, 0x01, 0x06, ++ 0xF0, 0xD1, 0x00, 0x9A, 0x11, 0x46, 0x13, 0x4A, 0x4F, 0xF4, 0x1E, 0x73, ++ 0x03, 0xFB, 0x01, 0x23, 0x83, 0xF8, 0xB8, 0x50, 0x38, 0x46, 0xFE, 0xF7, ++ 0x1D, 0xFA, 0x00, 0x20, 0x09, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x01, 0x20, ++ 0x00, 0xF0, 0x98, 0xFD, 0x00, 0x20, 0x09, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, ++ 0x06, 0x20, 0xF9, 0xF7, 0x2D, 0xFD, 0x03, 0x28, 0x3F, 0xF4, 0xFD, 0xAE, ++ 0x08, 0x49, 0x09, 0x48, 0x40, 0xF2, 0xF1, 0x12, 0xFB, 0xF7, 0x64, 0xFB, ++ 0xF5, 0xE6, 0x15, 0x46, 0xD9, 0xE7, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, ++ 0x68, 0x65, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0xB8, 0x34, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x40, 0xBB, 0x15, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0x70, 0xB5, 0x06, 0x20, 0xF9, 0xF7, 0x0E, 0xFD, 0x08, 0x28, 0x06, 0xD0, ++ 0x06, 0x20, 0xF9, 0xF7, 0x09, 0xFD, 0x09, 0x28, 0x33, 0xD0, 0x00, 0x20, ++ 0x70, 0xBD, 0x22, 0x4A, 0x22, 0x4B, 0x14, 0x68, 0x94, 0xF8, 0x3D, 0x60, ++ 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, 0x06, 0x36, 0x06, 0x23, 0x1A, 0x46, ++ 0x00, 0x21, 0x4B, 0x20, 0x96, 0xF8, 0x6C, 0x50, 0xF9, 0xF7, 0x52, 0xFA, ++ 0x94, 0xF8, 0x3A, 0x20, 0x02, 0x71, 0x22, 0x8F, 0x42, 0x80, 0x94, 0xF8, ++ 0x3D, 0x20, 0x02, 0x70, 0xF9, 0xF7, 0x78, 0xFA, 0xD6, 0xF8, 0xB0, 0x34, ++ 0x15, 0x4A, 0xA1, 0x8E, 0x4F, 0xF4, 0x1E, 0x70, 0x03, 0xF0, 0x01, 0x03, ++ 0x00, 0xFB, 0x05, 0x22, 0xC3, 0xF1, 0x02, 0x03, 0x49, 0xBA, 0x02, 0x2B, ++ 0x82, 0xF8, 0x30, 0x30, 0x91, 0x86, 0x08, 0xD0, 0x00, 0x20, 0x00, 0xF0, ++ 0x39, 0xFD, 0x00, 0x20, 0x70, 0xBD, 0x00, 0xF0, 0x1B, 0xFA, 0x00, 0x20, ++ 0x70, 0xBD, 0x06, 0x22, 0x05, 0x21, 0x41, 0xF2, 0x19, 0x40, 0xF9, 0xF7, ++ 0x27, 0xFA, 0x00, 0x22, 0x02, 0x70, 0x94, 0xF8, 0x3D, 0x20, 0x42, 0x70, ++ 0xF9, 0xF7, 0x50, 0xFA, 0xE8, 0xE7, 0x00, 0xBF, 0x64, 0xBA, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, 0x70, 0xB5, 0x06, 0x46, ++ 0x06, 0x20, 0x0D, 0x46, 0xF9, 0xF7, 0xB4, 0xFC, 0x2B, 0x46, 0x02, 0x46, ++ 0x0A, 0x49, 0x04, 0x46, 0x4F, 0xF4, 0x80, 0x70, 0xFB, 0xF7, 0xC2, 0xF8, ++ 0x08, 0x4B, 0x1D, 0x42, 0x04, 0xD0, 0x24, 0xF0, 0x02, 0x01, 0x89, 0xB2, ++ 0x05, 0x29, 0x00, 0xD0, 0x70, 0xBD, 0x30, 0x46, 0xE6, 0xF7, 0xDC, 0xFC, ++ 0x01, 0x23, 0x86, 0xF8, 0x5E, 0x30, 0x70, 0xBD, 0x70, 0xBB, 0x15, 0x00, ++ 0x00, 0x00, 0x03, 0x40, 0x08, 0xB5, 0x0C, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0x04, 0xDB, 0xBD, 0xE8, 0x08, 0x40, 0x09, 0x48, ++ 0xF9, 0xF7, 0x74, 0xBE, 0x08, 0x4B, 0xDB, 0x68, 0x00, 0x2B, 0xF6, 0xD0, ++ 0x07, 0x48, 0x08, 0x49, 0x70, 0x22, 0xFB, 0xF7, 0xC3, 0xFA, 0xBD, 0xE8, ++ 0x08, 0x40, 0x02, 0x48, 0xF9, 0xF7, 0x66, 0xBE, 0x38, 0x36, 0x17, 0x00, ++ 0x70, 0xBA, 0x17, 0x00, 0x64, 0xBA, 0x17, 0x00, 0x80, 0xBB, 0x15, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x03, 0x4A, 0x04, 0x4B, 0x00, 0x21, 0x06, 0x20, ++ 0xD1, 0x75, 0x19, 0x60, 0xF9, 0xF7, 0xC4, 0xBB, 0x4C, 0x36, 0x17, 0x00, ++ 0x64, 0xBA, 0x17, 0x00, 0x70, 0xB5, 0x11, 0x4B, 0x1E, 0x68, 0x00, 0x23, ++ 0x03, 0x60, 0x0B, 0x60, 0x96, 0xF8, 0x22, 0x30, 0xDB, 0x07, 0x05, 0x46, ++ 0x0C, 0x46, 0x08, 0xD5, 0x30, 0x46, 0x03, 0xF0, 0x57, 0xFB, 0x58, 0xB1, ++ 0x83, 0x1C, 0x2B, 0x60, 0xC3, 0x6A, 0x23, 0x60, 0x70, 0xBD, 0x06, 0xF1, ++ 0x22, 0x00, 0x28, 0x60, 0x03, 0xF0, 0x46, 0xFB, 0x00, 0x28, 0xF5, 0xD1, ++ 0x32, 0x8D, 0x4F, 0xF6, 0xFF, 0x73, 0x9A, 0x42, 0x1C, 0xBF, 0x28, 0x36, ++ 0x26, 0x60, 0x70, 0xBD, 0x64, 0xBA, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x41, ++ 0x3B, 0x4C, 0x4F, 0xF4, 0xBA, 0x73, 0x06, 0x22, 0x84, 0xB0, 0x80, 0x46, ++ 0x0F, 0x46, 0x4F, 0xF4, 0x80, 0x50, 0x04, 0x21, 0x25, 0x68, 0xF9, 0xF7, ++ 0x91, 0xF9, 0x95, 0xF8, 0x3D, 0x30, 0x80, 0xF8, 0x6E, 0x31, 0x04, 0x46, ++ 0x0F, 0xCD, 0x4F, 0xF0, 0x00, 0x0C, 0x04, 0xF1, 0xFC, 0x06, 0xC4, 0xF8, ++ 0x68, 0xC1, 0xA4, 0xF8, 0x6C, 0xC1, 0x0F, 0xC6, 0x0F, 0xCD, 0x0F, 0xC6, ++ 0x01, 0x23, 0x2A, 0x68, 0x32, 0x70, 0x84, 0xF8, 0x70, 0x31, 0xB8, 0xF1, ++ 0x00, 0x0F, 0x19, 0xD0, 0xD8, 0xF8, 0x00, 0x00, 0xC4, 0xF8, 0x60, 0x01, ++ 0xB8, 0xF8, 0x04, 0x30, 0xA4, 0xF8, 0x64, 0x31, 0xCF, 0xB1, 0x38, 0x68, ++ 0x20, 0x60, 0xBB, 0x88, 0xA3, 0x80, 0x01, 0x23, 0x84, 0xF8, 0x6F, 0x31, ++ 0x20, 0x46, 0xF9, 0xF7, 0x95, 0xF9, 0x01, 0x21, 0x06, 0x20, 0x04, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x41, 0xF9, 0xF7, 0x58, 0xBB, 0x1C, 0x4B, 0x18, 0x68, ++ 0x9B, 0x88, 0xC4, 0xF8, 0x60, 0x01, 0xA4, 0xF8, 0x64, 0x31, 0x00, 0x2F, ++ 0xE5, 0xD1, 0x19, 0x4B, 0x02, 0x93, 0x93, 0xF8, 0xFD, 0x50, 0x93, 0xF8, ++ 0xFC, 0x00, 0x8D, 0xF8, 0x05, 0x50, 0x03, 0xF1, 0x54, 0x02, 0x03, 0x92, ++ 0x84, 0xF8, 0x6F, 0x71, 0x0D, 0xF1, 0x08, 0x0C, 0x06, 0x26, 0xB8, 0xB1, ++ 0x5C, 0xF8, 0x27, 0x30, 0x16, 0xFB, 0x00, 0x30, 0xDA, 0x78, 0x92, 0x07, ++ 0x0D, 0xD4, 0x94, 0xF8, 0x6F, 0x21, 0x51, 0x1C, 0x84, 0xF8, 0x6F, 0x11, ++ 0x02, 0xEB, 0x42, 0x02, 0x19, 0x68, 0x44, 0xF8, 0x12, 0x10, 0x04, 0xEB, ++ 0x42, 0x02, 0x99, 0x88, 0x91, 0x80, 0x06, 0x33, 0x83, 0x42, 0xEB, 0xD1, ++ 0x00, 0x2F, 0xC1, 0xD1, 0x28, 0x46, 0x01, 0x27, 0xE1, 0xE7, 0x00, 0xBF, ++ 0x64, 0xBA, 0x17, 0x00, 0xAC, 0xB2, 0x15, 0x00, 0x5A, 0xB9, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF8, 0x4F, 0x8B, 0x78, 0x0D, 0x46, 0x80, 0x46, 0x17, 0x46, ++ 0x1B, 0xB9, 0x37, 0x4B, 0x1B, 0x68, 0x00, 0x2B, 0x49, 0xDB, 0x36, 0x4C, ++ 0xDF, 0xF8, 0xEC, 0xA0, 0x4F, 0xF0, 0x00, 0x09, 0x4F, 0xF4, 0xBA, 0x73, ++ 0x06, 0x22, 0x04, 0x21, 0x41, 0xF2, 0x02, 0x00, 0xDA, 0xF8, 0x00, 0xB0, ++ 0x84, 0xF8, 0x17, 0x90, 0xF9, 0xF7, 0x04, 0xF9, 0x04, 0x46, 0x28, 0x68, ++ 0x20, 0x60, 0x4F, 0xF0, 0x01, 0x0C, 0xB5, 0xF8, 0x04, 0xE0, 0x84, 0xF8, ++ 0x6F, 0xC1, 0x5E, 0x46, 0x0F, 0xCE, 0x04, 0xF1, 0xFC, 0x05, 0xA4, 0xF8, ++ 0x04, 0xE0, 0x0F, 0xC5, 0x0F, 0xCE, 0x0F, 0xC5, 0x33, 0x68, 0x2B, 0x70, ++ 0x84, 0xF8, 0x70, 0xC1, 0xA4, 0xF8, 0x6C, 0x91, 0xC4, 0xF8, 0x68, 0x91, ++ 0x9B, 0xF8, 0x3D, 0x30, 0x84, 0xF8, 0x6E, 0x31, 0xD8, 0xF8, 0x00, 0x00, ++ 0xC4, 0xF8, 0x60, 0x01, 0xB8, 0xF8, 0x04, 0x30, 0xA4, 0xF8, 0x64, 0x31, ++ 0x1F, 0xB1, 0xE3, 0x78, 0x43, 0xEA, 0x0C, 0x03, 0xE3, 0x70, 0xB7, 0xFA, ++ 0x87, 0xF2, 0x20, 0x46, 0x52, 0x09, 0x8A, 0xF8, 0x15, 0x20, 0xF9, 0xF7, ++ 0x01, 0xF9, 0xBD, 0xE8, 0xF8, 0x4F, 0x02, 0x21, 0x06, 0x20, 0xF9, 0xF7, ++ 0xC5, 0xBA, 0x12, 0x4B, 0x10, 0x4C, 0xD3, 0xF8, 0x24, 0x31, 0x5B, 0x06, ++ 0xB0, 0xD5, 0xE3, 0x7D, 0x01, 0x2B, 0xAD, 0xD1, 0x0E, 0x4A, 0x63, 0x70, ++ 0x13, 0x68, 0x0E, 0x49, 0x0E, 0x48, 0x23, 0xF0, 0x00, 0x43, 0x13, 0x60, ++ 0x08, 0x60, 0x0D, 0x4A, 0xC4, 0xF8, 0x0C, 0x80, 0x06, 0x21, 0x41, 0xF6, ++ 0x09, 0x00, 0x25, 0x61, 0xA7, 0x75, 0xF8, 0xF7, 0x0D, 0xFF, 0xBD, 0xE8, ++ 0xF8, 0x4F, 0xDC, 0xF7, 0xF9, 0xB8, 0x00, 0xBF, 0x48, 0x30, 0x34, 0x40, ++ 0x4C, 0x36, 0x17, 0x00, 0x00, 0x00, 0x50, 0x40, 0x34, 0x04, 0x32, 0x40, ++ 0x20, 0x04, 0x32, 0x40, 0x40, 0x1F, 0xDC, 0x05, 0xA0, 0x86, 0x01, 0x00, ++ 0x64, 0xBA, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x47, 0x27, 0x4D, 0xDF, 0xF8, ++ 0xA0, 0x80, 0xAF, 0x7D, 0xD8, 0xF8, 0x00, 0x90, 0x4F, 0xF4, 0xBA, 0x73, ++ 0x06, 0x22, 0x04, 0x21, 0x41, 0xF2, 0x02, 0x00, 0xF9, 0xF7, 0x8A, 0xF8, ++ 0x06, 0x21, 0x04, 0x46, 0x41, 0xF6, 0x09, 0x00, 0xF8, 0xF7, 0x92, 0xFF, ++ 0xD5, 0xE9, 0x03, 0x23, 0x4F, 0xF0, 0x00, 0x0C, 0x85, 0xF8, 0x17, 0xC0, ++ 0x10, 0x68, 0xC4, 0xF8, 0x60, 0x01, 0x18, 0x68, 0x95, 0x88, 0x20, 0x60, ++ 0x4F, 0xF0, 0x01, 0x0E, 0xB3, 0xF8, 0x04, 0xA0, 0x84, 0xF8, 0x6F, 0xE1, ++ 0x4E, 0x46, 0x0F, 0xCE, 0xA4, 0xF8, 0x64, 0x51, 0x04, 0xF1, 0xFC, 0x05, ++ 0xA4, 0xF8, 0x04, 0xA0, 0x0F, 0xC5, 0x0F, 0xCE, 0x0F, 0xC5, 0x33, 0x68, ++ 0x2B, 0x70, 0x84, 0xF8, 0x70, 0xE1, 0xA4, 0xF8, 0x6C, 0xC1, 0xC4, 0xF8, ++ 0x68, 0xC1, 0x99, 0xF8, 0x3D, 0x30, 0x84, 0xF8, 0x6E, 0x31, 0x1F, 0xB1, ++ 0xE3, 0x78, 0x43, 0xEA, 0x0E, 0x03, 0xE3, 0x70, 0xB7, 0xFA, 0x87, 0xF3, ++ 0x20, 0x46, 0x5B, 0x09, 0x88, 0xF8, 0x15, 0x30, 0xF9, 0xF7, 0x7E, 0xF8, ++ 0xBD, 0xE8, 0xF0, 0x47, 0x02, 0x21, 0x06, 0x20, 0xF9, 0xF7, 0x42, 0xBA, ++ 0x4C, 0x36, 0x17, 0x00, 0x64, 0xBA, 0x17, 0x00, 0x30, 0xB5, 0x14, 0x4A, ++ 0x14, 0x4B, 0x11, 0x68, 0x14, 0x4A, 0x91, 0xF8, 0x3D, 0x10, 0x54, 0x6C, ++ 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, 0x01, 0xF2, 0x99, 0x18, 0x85, 0xB0, ++ 0xD1, 0xF8, 0x90, 0x31, 0x91, 0xF8, 0xC5, 0x51, 0x8D, 0xF8, 0x05, 0x50, ++ 0x0A, 0x46, 0x99, 0x78, 0xD2, 0xF8, 0x94, 0x21, 0x8D, 0xF8, 0x04, 0x10, ++ 0x19, 0x88, 0x02, 0x92, 0x1A, 0x79, 0xAD, 0xF8, 0x06, 0x10, 0x8D, 0xF8, ++ 0x0C, 0x20, 0xDB, 0x78, 0x8D, 0xF8, 0x0D, 0x30, 0x01, 0x46, 0x01, 0xA8, ++ 0xA0, 0x47, 0x05, 0xB0, 0x30, 0xBD, 0x00, 0xBF, 0x64, 0xBA, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x10, 0xB5, 0x0C, 0x48, ++ 0xF9, 0xF7, 0xE2, 0xFC, 0x0B, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0x04, 0x46, 0x05, 0xDB, 0x04, 0xF1, 0x0C, 0x00, 0xBD, 0xE8, ++ 0x10, 0x40, 0xF9, 0xF7, 0x33, 0xB8, 0x00, 0x28, 0xF7, 0xD1, 0x05, 0x49, ++ 0x05, 0x48, 0x40, 0xF2, 0x0D, 0x22, 0xFB, 0xF7, 0xDD, 0xF8, 0xF0, 0xE7, ++ 0x70, 0xBA, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0xA8, 0xAB, 0x15, 0x00, 0x2D, 0xE9, 0xF0, 0x41, 0x02, 0x23, 0x04, 0x46, ++ 0x06, 0x22, 0x05, 0x21, 0x41, 0xF2, 0x19, 0x40, 0xF8, 0xF7, 0xE8, 0xFF, ++ 0x06, 0x22, 0x02, 0x23, 0x06, 0x46, 0x05, 0x21, 0x41, 0xF2, 0x17, 0x40, ++ 0xF8, 0xF7, 0xE0, 0xFF, 0x38, 0x4F, 0x39, 0x49, 0x05, 0x46, 0x4F, 0xF4, ++ 0x80, 0x70, 0xFA, 0xF7, 0x91, 0xFE, 0xFF, 0xF7, 0xE1, 0xFD, 0x20, 0x46, ++ 0xE5, 0xF7, 0x4A, 0xF8, 0x4F, 0xF0, 0x00, 0x08, 0x94, 0xF8, 0x6C, 0x00, ++ 0x7B, 0x6A, 0x98, 0x47, 0x86, 0xF8, 0x00, 0x80, 0x94, 0xF8, 0x63, 0x30, ++ 0x73, 0x70, 0x2F, 0x48, 0xA6, 0xF1, 0x0C, 0x01, 0xF9, 0xF7, 0x52, 0xFC, ++ 0x94, 0xF8, 0x64, 0x30, 0x00, 0x2B, 0x3F, 0xD1, 0x94, 0xF8, 0x6C, 0x30, ++ 0xFF, 0x2B, 0x0D, 0xD0, 0x01, 0x23, 0x00, 0x21, 0x06, 0x22, 0x0C, 0x20, ++ 0xF8, 0xF7, 0xB6, 0xFF, 0x01, 0x46, 0x94, 0xF8, 0x6C, 0x30, 0x01, 0xF8, ++ 0x0C, 0x39, 0x23, 0x48, 0xF9, 0xF7, 0x3C, 0xFC, 0x23, 0x6C, 0x6B, 0xB1, ++ 0x01, 0x23, 0x00, 0x21, 0x06, 0x22, 0x39, 0x20, 0xF8, 0xF7, 0xA6, 0xFF, ++ 0x01, 0x46, 0x94, 0xF8, 0x63, 0x30, 0x01, 0xF8, 0x0C, 0x39, 0x1B, 0x48, ++ 0xF9, 0xF7, 0x2C, 0xFC, 0x00, 0x26, 0x2E, 0x70, 0x94, 0xF8, 0x63, 0x20, ++ 0x18, 0x4B, 0x6A, 0x70, 0x93, 0xF8, 0x04, 0x31, 0x43, 0xB1, 0xD7, 0xF8, ++ 0xD8, 0x31, 0x04, 0xF1, 0x9C, 0x00, 0x98, 0x47, 0xC4, 0xE9, 0x24, 0x66, ++ 0xC4, 0xF8, 0x98, 0x60, 0x00, 0x23, 0xA5, 0xF1, 0x0C, 0x01, 0xC4, 0xF8, ++ 0xCC, 0x31, 0x0E, 0x48, 0xF9, 0xF7, 0x12, 0xFC, 0xBD, 0xE8, 0xF0, 0x41, ++ 0xFF, 0xF7, 0x6C, 0xBF, 0x41, 0x46, 0x04, 0x23, 0x06, 0x22, 0x1E, 0x20, ++ 0xF8, 0xF7, 0x7A, 0xFF, 0x80, 0xF8, 0x02, 0x80, 0x94, 0xF8, 0x63, 0x30, ++ 0xC3, 0x70, 0xA0, 0xF1, 0x0C, 0x01, 0x04, 0x48, 0xF9, 0xF7, 0xFE, 0xFB, ++ 0xAE, 0xE7, 0x00, 0xBF, 0x88, 0x1A, 0x17, 0x00, 0xA8, 0xBB, 0x15, 0x00, ++ 0x70, 0xBA, 0x17, 0x00, 0x2C, 0x19, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0x6A, 0x4B, 0xDF, 0xF8, 0xB4, 0xA1, 0x1D, 0x68, 0x83, 0xB0, 0x95, 0xF8, ++ 0x3D, 0x20, 0x00, 0x92, 0x16, 0x46, 0x02, 0x23, 0x06, 0x22, 0x05, 0x21, ++ 0x41, 0xF2, 0x19, 0x40, 0xF8, 0xF7, 0x54, 0xFF, 0x08, 0x23, 0x81, 0x46, ++ 0x06, 0x22, 0x00, 0x21, 0x18, 0x20, 0xF8, 0xF7, 0x4D, 0xFF, 0x08, 0x23, ++ 0x07, 0x46, 0x06, 0x22, 0x00, 0x21, 0x16, 0x20, 0xF8, 0xF7, 0x46, 0xFF, ++ 0x4F, 0xF4, 0xA4, 0x64, 0x04, 0xFB, 0x06, 0xF4, 0x04, 0x23, 0x06, 0x46, ++ 0x06, 0x22, 0x00, 0x21, 0x14, 0x20, 0xF8, 0xF7, 0x3B, 0xFF, 0x02, 0x23, ++ 0x06, 0x22, 0x05, 0x21, 0x83, 0x46, 0x41, 0xF2, 0x17, 0x40, 0xF8, 0xF7, ++ 0x33, 0xFF, 0x80, 0x46, 0xFF, 0xF7, 0x3A, 0xFD, 0x4F, 0xF0, 0x01, 0x02, ++ 0x89, 0xF8, 0x00, 0x20, 0x95, 0xF8, 0x3D, 0x30, 0x89, 0xF8, 0x01, 0x30, ++ 0x0A, 0xEB, 0x04, 0x03, 0x01, 0x93, 0x4B, 0x4B, 0xA9, 0xF1, 0x0C, 0x01, ++ 0x03, 0xF1, 0x0C, 0x00, 0xF9, 0xF7, 0xAC, 0xFB, 0x01, 0x9B, 0xD3, 0xF8, ++ 0x64, 0x01, 0xB3, 0xF8, 0x68, 0x21, 0xBA, 0x80, 0x44, 0x4B, 0x38, 0x60, ++ 0x95, 0xF8, 0x3D, 0x20, 0xBA, 0x71, 0x03, 0xF1, 0x0C, 0x00, 0xA7, 0xF1, ++ 0x0C, 0x01, 0xF9, 0xF7, 0x9B, 0xFB, 0x01, 0x9B, 0xD3, 0xF8, 0x90, 0x31, ++ 0x04, 0xF5, 0xCE, 0x70, 0x9B, 0x78, 0x73, 0x71, 0x01, 0x21, 0x50, 0x44, ++ 0xFD, 0xF7, 0xFE, 0xFD, 0x73, 0x79, 0x30, 0x60, 0x95, 0xF8, 0x3D, 0x20, ++ 0x32, 0x71, 0x2B, 0xB9, 0xC1, 0x07, 0x4F, 0xD5, 0x36, 0x4B, 0x4F, 0xF4, ++ 0x80, 0x62, 0x5A, 0x61, 0xA6, 0xF1, 0x0C, 0x01, 0x34, 0x48, 0xF9, 0xF7, ++ 0x7F, 0xFB, 0x00, 0x9B, 0x32, 0x48, 0x4F, 0xF4, 0xA4, 0x66, 0x06, 0xFB, ++ 0x03, 0xA6, 0xAB, 0xF1, 0x0C, 0x01, 0xB6, 0xF8, 0x98, 0x31, 0xAB, 0xF8, ++ 0x00, 0x30, 0x95, 0xF8, 0x3D, 0x30, 0x8B, 0xF8, 0x02, 0x30, 0xF9, 0xF7, ++ 0x6D, 0xFB, 0xD6, 0xF8, 0xCC, 0x31, 0x1B, 0x07, 0x36, 0xD4, 0x04, 0xF5, ++ 0xD6, 0x74, 0x00, 0x26, 0x26, 0x4F, 0xA2, 0x44, 0x34, 0x46, 0x08, 0x23, ++ 0x06, 0x22, 0x00, 0x21, 0x1A, 0x20, 0xF8, 0xF7, 0xCF, 0xFE, 0x5A, 0xF8, ++ 0x04, 0x3B, 0x03, 0x60, 0x46, 0x71, 0x95, 0xF8, 0x3D, 0x30, 0x83, 0x71, ++ 0x04, 0x71, 0xA0, 0xF1, 0x0C, 0x01, 0x01, 0x36, 0x38, 0x46, 0xF9, 0xF7, ++ 0x4F, 0xFB, 0x04, 0x2E, 0xE9, 0xD1, 0x01, 0x23, 0x88, 0xF8, 0x00, 0x30, ++ 0x95, 0xF8, 0x3D, 0x30, 0x17, 0x48, 0x88, 0xF8, 0x01, 0x30, 0xA8, 0xF1, ++ 0x0C, 0x01, 0xF9, 0xF7, 0x41, 0xFB, 0xFF, 0xF7, 0x9D, 0xFE, 0x31, 0x46, ++ 0x06, 0x20, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x4F, 0xF9, 0xF7, 0xA4, 0xB8, ++ 0xC2, 0x06, 0xB1, 0xD5, 0x0D, 0x4B, 0x04, 0x22, 0x5A, 0x61, 0xAD, 0xE7, ++ 0x06, 0x22, 0x00, 0x21, 0x04, 0x23, 0x71, 0x20, 0xF8, 0xF7, 0x9E, 0xFE, ++ 0x04, 0xF1, 0xEC, 0x03, 0x06, 0x46, 0x0A, 0xEB, 0x03, 0x00, 0xFD, 0xF7, ++ 0x0F, 0xFE, 0x31, 0x46, 0x03, 0x46, 0x41, 0xF8, 0x0C, 0x39, 0x04, 0x48, ++ 0xF9, 0xF7, 0x1E, 0xFB, 0xB3, 0xE7, 0x00, 0xBF, 0x64, 0xBA, 0x17, 0x00, ++ 0xC4, 0x3C, 0x18, 0x00, 0x70, 0xBA, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0x06, 0x23, 0x2D, 0xE9, 0xF0, 0x41, 0x1A, 0x46, 0x04, 0x46, 0x0F, 0x46, ++ 0x41, 0xF6, 0x05, 0x00, 0x0C, 0x21, 0xF8, 0xF7, 0x7B, 0xFE, 0x38, 0x4E, ++ 0x94, 0xF8, 0xC0, 0x34, 0xB4, 0x62, 0x05, 0x46, 0x00, 0x2B, 0x3F, 0xD0, ++ 0x35, 0x4B, 0x9B, 0x68, 0x00, 0x2B, 0x61, 0xD0, 0x93, 0xF8, 0x62, 0x20, ++ 0x7A, 0xB9, 0x33, 0x49, 0x33, 0x4A, 0xD8, 0x6D, 0x08, 0x60, 0xB3, 0xF8, ++ 0x60, 0x10, 0x11, 0x60, 0x93, 0xF8, 0x64, 0x20, 0x2A, 0xB1, 0x30, 0x49, ++ 0x98, 0x6B, 0x30, 0x4A, 0x08, 0x60, 0x99, 0x8F, 0x11, 0x60, 0x2F, 0x4A, ++ 0x12, 0x68, 0x00, 0x2A, 0x2C, 0xDB, 0xDF, 0xF8, 0xC4, 0x80, 0x00, 0x20, ++ 0xDB, 0xF7, 0x86, 0xFE, 0x00, 0x22, 0xD8, 0xF8, 0xD8, 0x31, 0x84, 0xF8, ++ 0xAC, 0x20, 0x04, 0xF1, 0xB0, 0x00, 0x98, 0x47, 0xD8, 0xF8, 0x10, 0x33, ++ 0x20, 0x46, 0x98, 0x47, 0x2F, 0x80, 0x94, 0xF8, 0x63, 0x30, 0xAB, 0x70, ++ 0xB3, 0x7D, 0x01, 0x2B, 0x08, 0xBF, 0xEB, 0x70, 0xB3, 0x7F, 0xA3, 0xF1, ++ 0x01, 0x03, 0xB3, 0xFA, 0x83, 0xF3, 0x5B, 0x09, 0xA5, 0xF1, 0x0C, 0x02, ++ 0x2B, 0x71, 0xB2, 0x60, 0xBD, 0xE8, 0xF0, 0x81, 0x1A, 0x4B, 0x1B, 0x68, ++ 0x00, 0x2B, 0xD6, 0xDA, 0x13, 0x4B, 0x9B, 0x68, 0x00, 0x2B, 0xD2, 0xD0, ++ 0x00, 0x21, 0x93, 0xF8, 0x62, 0x20, 0x1A, 0xB9, 0x93, 0xF8, 0x64, 0x20, ++ 0x02, 0xB1, 0x01, 0x31, 0x1B, 0x68, 0x00, 0x2B, 0xF5, 0xD1, 0x01, 0x29, ++ 0xC5, 0xD1, 0x11, 0x4A, 0x11, 0x49, 0x53, 0x70, 0x0B, 0x68, 0x11, 0x4A, ++ 0x43, 0xF0, 0x00, 0x43, 0x0B, 0x60, 0x13, 0x68, 0x1B, 0x0C, 0x1B, 0x04, ++ 0x43, 0xF4, 0xBB, 0x63, 0x43, 0xF0, 0x04, 0x03, 0x13, 0x60, 0xB4, 0xE7, ++ 0x07, 0x4B, 0x1B, 0x68, 0xB1, 0xE7, 0x00, 0xBF, 0x64, 0xBA, 0x17, 0x00, ++ 0x00, 0x88, 0x17, 0x00, 0x10, 0x00, 0x32, 0x40, 0x14, 0x00, 0x32, 0x40, ++ 0x20, 0x00, 0x32, 0x40, 0x24, 0x00, 0x32, 0x40, 0x48, 0x30, 0x34, 0x40, ++ 0x4C, 0x36, 0x17, 0x00, 0x34, 0x04, 0x32, 0x40, 0x20, 0x04, 0x32, 0x40, ++ 0x88, 0x1A, 0x17, 0x00, 0x10, 0xB5, 0x0A, 0x46, 0x04, 0x46, 0x05, 0x49, ++ 0x4F, 0xF4, 0x80, 0x70, 0xFA, 0xF7, 0xA4, 0xFC, 0x20, 0x46, 0x00, 0x21, ++ 0xBD, 0xE8, 0x10, 0x40, 0xFF, 0xF7, 0x60, 0xBF, 0xBC, 0xBB, 0x15, 0x00, ++ 0x2D, 0xE9, 0xF8, 0x43, 0xDF, 0xF8, 0xC8, 0x81, 0x4F, 0xF4, 0xA4, 0x64, ++ 0x04, 0xFB, 0x00, 0x84, 0x0B, 0x46, 0x02, 0x46, 0x06, 0x46, 0x0F, 0x46, ++ 0x4F, 0xF4, 0x80, 0x70, 0x66, 0x49, 0x94, 0xF8, 0x6C, 0x90, 0xFA, 0xF7, ++ 0x89, 0xFC, 0x94, 0xF8, 0x62, 0x50, 0x15, 0xB9, 0x94, 0xF8, 0x64, 0x30, ++ 0x3B, 0xB9, 0xBD, 0xE8, 0xF8, 0x43, 0x06, 0x22, 0x0C, 0x21, 0x41, 0xF6, ++ 0x04, 0x00, 0xF8, 0xF7, 0x2B, 0xBE, 0x5E, 0x4B, 0x01, 0x25, 0x09, 0x21, ++ 0x06, 0x20, 0x1D, 0x75, 0xF8, 0xF7, 0xB6, 0xFF, 0x94, 0xF8, 0xC0, 0x34, ++ 0x00, 0x2B, 0x79, 0xD1, 0xD4, 0xF8, 0x90, 0x31, 0x9D, 0x78, 0x2C, 0x1E, ++ 0x4F, 0xF4, 0xA4, 0x65, 0x05, 0xFB, 0x06, 0x85, 0x28, 0x46, 0x18, 0xBF, ++ 0x01, 0x24, 0xE4, 0xF7, 0x11, 0xFD, 0x00, 0x28, 0x74, 0xD0, 0x20, 0x46, ++ 0x4F, 0xF4, 0xC0, 0x71, 0xE6, 0xF7, 0x72, 0xF8, 0x04, 0x46, 0x01, 0x46, ++ 0x28, 0x46, 0x00, 0x2C, 0x6C, 0xD0, 0xF8, 0xF7, 0x69, 0xF9, 0x4C, 0x4B, ++ 0xD4, 0xF8, 0x48, 0x80, 0x4B, 0x49, 0xE8, 0x6D, 0x4F, 0xF4, 0x1E, 0x72, ++ 0x02, 0xFB, 0x09, 0x39, 0xB1, 0xF8, 0xFC, 0x31, 0x59, 0xF8, 0x26, 0x2F, ++ 0xC8, 0xF8, 0x6C, 0x20, 0x6F, 0xF0, 0x3F, 0x02, 0x88, 0xF8, 0x68, 0x20, ++ 0xB9, 0xF8, 0x04, 0x20, 0xA8, 0xF8, 0x70, 0x20, 0xB5, 0xF8, 0x60, 0x20, ++ 0xA8, 0xF8, 0x76, 0x20, 0x01, 0x33, 0xD9, 0xF8, 0x00, 0x20, 0xC8, 0xF8, ++ 0x72, 0x00, 0x9B, 0xB2, 0xB9, 0xF8, 0x04, 0x00, 0xC8, 0xF8, 0x78, 0x20, ++ 0x00, 0x22, 0xA8, 0xF8, 0x7C, 0x00, 0x88, 0xF8, 0x69, 0x20, 0x88, 0xF8, ++ 0x6A, 0x20, 0x88, 0xF8, 0x6B, 0x20, 0x18, 0x01, 0xA1, 0xF8, 0xFC, 0x31, ++ 0x35, 0x4B, 0xA8, 0xF8, 0x7E, 0x00, 0x26, 0x77, 0xA5, 0x65, 0x63, 0x65, ++ 0x95, 0xF8, 0x6C, 0x30, 0x63, 0x77, 0x84, 0xF8, 0x33, 0x20, 0x84, 0xF8, ++ 0x35, 0x20, 0xC0, 0x21, 0x20, 0x46, 0x07, 0xF0, 0x5F, 0xF9, 0x01, 0x28, ++ 0x06, 0x46, 0x08, 0xF1, 0x68, 0x09, 0x34, 0xD0, 0x39, 0x46, 0x08, 0xF1, ++ 0x80, 0x00, 0xFB, 0xF7, 0xDD, 0xFD, 0x02, 0x2E, 0x00, 0xF1, 0x18, 0x05, ++ 0x3D, 0xD0, 0xE2, 0x6C, 0x53, 0x6A, 0x01, 0x3B, 0x2B, 0x44, 0x04, 0x35, ++ 0xC2, 0xE9, 0x0A, 0x35, 0x05, 0x21, 0x20, 0x46, 0xE6, 0xF7, 0x20, 0xF8, ++ 0x05, 0x46, 0x88, 0xB1, 0xBD, 0xE8, 0xF8, 0x83, 0x2C, 0x46, 0x4F, 0xF4, ++ 0xA4, 0x65, 0x05, 0xFB, 0x06, 0x85, 0x28, 0x46, 0xE4, 0xF7, 0x9C, 0xFC, ++ 0x00, 0x28, 0x8A, 0xD1, 0x01, 0x46, 0x28, 0x46, 0xBD, 0xE8, 0xF8, 0x43, ++ 0xFF, 0xF7, 0xA8, 0xBE, 0xA4, 0x6D, 0x17, 0x49, 0x02, 0x46, 0x4F, 0xF4, ++ 0x80, 0x70, 0xFA, 0xF7, 0xDF, 0xFB, 0x29, 0x46, 0x20, 0x46, 0xBD, 0xE8, ++ 0xF8, 0x43, 0xFF, 0xF7, 0x9B, 0xBE, 0x18, 0x22, 0x49, 0x46, 0x20, 0x46, ++ 0x05, 0xF0, 0x84, 0xFF, 0x94, 0xF8, 0x33, 0x50, 0x18, 0x35, 0x09, 0xEB, ++ 0x05, 0x00, 0x39, 0x46, 0xFB, 0xF7, 0xA0, 0xFD, 0x94, 0xF8, 0x35, 0x20, ++ 0x15, 0x44, 0x05, 0x44, 0xC1, 0xE7, 0x2A, 0x46, 0x49, 0x46, 0x20, 0x46, ++ 0x07, 0xF0, 0x4A, 0xF9, 0x05, 0x44, 0xBA, 0xE7, 0xD4, 0xBB, 0x15, 0x00, ++ 0x64, 0xBA, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, 0x20, 0x62, 0x17, 0x00, ++ 0xD1, 0x9D, 0x14, 0x00, 0xBC, 0xBB, 0x15, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x43, 0x66, 0x4D, 0x67, 0x49, 0xD5, 0xE9, 0x00, 0x34, ++ 0x93, 0xF8, 0x3D, 0x70, 0x67, 0x72, 0x0A, 0x68, 0x20, 0x80, 0x22, 0xF0, ++ 0x10, 0x02, 0x4F, 0xF4, 0xA4, 0x66, 0x83, 0xB0, 0x80, 0x46, 0x06, 0xFB, ++ 0x07, 0xF6, 0x0A, 0x60, 0x00, 0x28, 0x6C, 0xD1, 0xDF, 0xF8, 0x98, 0x91, ++ 0x09, 0xEB, 0x06, 0x01, 0x91, 0xF8, 0x6C, 0x20, 0xD1, 0xF8, 0x64, 0x01, ++ 0xB1, 0xF8, 0x68, 0xC1, 0xA2, 0x72, 0x0A, 0x6C, 0xA4, 0xF8, 0x06, 0xC0, ++ 0xC4, 0xF8, 0x02, 0x00, 0x10, 0x7E, 0xE0, 0x72, 0x10, 0x79, 0x84, 0xF8, ++ 0x36, 0x03, 0xD0, 0x88, 0xB2, 0xF8, 0x08, 0xC0, 0xA4, 0xF8, 0x38, 0x03, ++ 0x50, 0x89, 0xC4, 0xE9, 0xCF, 0xC0, 0x52, 0x79, 0x84, 0xF8, 0x3A, 0x23, ++ 0xD1, 0xF8, 0xCC, 0x21, 0x02, 0xF0, 0x01, 0x02, 0x22, 0x73, 0x00, 0x2A, ++ 0x6D, 0xD1, 0x42, 0x46, 0x62, 0x73, 0x1A, 0x6B, 0x4F, 0xF4, 0xA4, 0x63, ++ 0x02, 0xF0, 0x20, 0x02, 0x03, 0xFB, 0x07, 0x93, 0x22, 0x72, 0x93, 0xF8, ++ 0xC0, 0x24, 0xA2, 0xB1, 0xB3, 0xF8, 0x5E, 0x00, 0xB3, 0xF8, 0x5C, 0x20, ++ 0x42, 0x49, 0x42, 0xEA, 0x00, 0x42, 0x0A, 0x60, 0x41, 0x4A, 0xB3, 0xF8, ++ 0x60, 0x10, 0x11, 0x60, 0x58, 0x8F, 0x1A, 0x8F, 0x3F, 0x49, 0x42, 0xEA, ++ 0x00, 0x42, 0x0A, 0x60, 0x3E, 0x4A, 0x9B, 0x8F, 0x13, 0x60, 0x20, 0x46, ++ 0xF8, 0xF7, 0xC8, 0xFC, 0x94, 0xF8, 0x3A, 0x33, 0xB4, 0xF8, 0x3C, 0x03, ++ 0x40, 0xEA, 0x03, 0x40, 0x40, 0xF0, 0x00, 0x40, 0xDB, 0xF7, 0xC0, 0xFC, ++ 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x07, 0x97, 0x01, 0x22, 0x35, 0x4B, ++ 0x87, 0xF8, 0xAC, 0x20, 0x1A, 0x69, 0x34, 0x49, 0x34, 0x4B, 0x06, 0xF1, ++ 0xB0, 0x00, 0x48, 0x44, 0x11, 0x44, 0xD3, 0xF8, 0xE0, 0x31, 0x98, 0x47, ++ 0x00, 0x21, 0x06, 0x20, 0xF8, 0xF7, 0x72, 0xFE, 0x12, 0xE0, 0x2F, 0x4B, ++ 0x1B, 0x68, 0x00, 0x2B, 0x26, 0xDB, 0x2E, 0x4B, 0x06, 0x20, 0x09, 0x21, ++ 0x1E, 0x44, 0xF8, 0xF7, 0x67, 0xFE, 0x29, 0x4A, 0xAE, 0x62, 0xA4, 0xF1, ++ 0x0C, 0x03, 0xD2, 0xF8, 0x10, 0x23, 0xAB, 0x60, 0x30, 0x46, 0x90, 0x47, ++ 0xB4, 0xF8, 0x34, 0x33, 0x62, 0x7A, 0x26, 0x49, 0x00, 0x93, 0x4F, 0xF4, ++ 0x80, 0x70, 0x43, 0x46, 0xFA, 0xF7, 0x12, 0xFB, 0x28, 0x68, 0x0C, 0x38, ++ 0xF8, 0xF7, 0xD2, 0xFC, 0x00, 0x23, 0x2B, 0x60, 0xAB, 0x75, 0xAB, 0x77, ++ 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x83, 0x91, 0xF8, 0xBD, 0x21, 0x8F, 0xE7, ++ 0x1C, 0x4B, 0x9A, 0x68, 0x62, 0xB1, 0x00, 0x21, 0x92, 0xF8, 0x62, 0x30, ++ 0x1B, 0xB9, 0x92, 0xF8, 0x64, 0x30, 0x03, 0xB1, 0x01, 0x31, 0x12, 0x68, ++ 0x00, 0x2A, 0xF5, 0xD1, 0x00, 0x29, 0xC8, 0xD1, 0x15, 0x4B, 0x16, 0x49, ++ 0x00, 0x22, 0x5A, 0x70, 0x0B, 0x68, 0x15, 0x4A, 0x43, 0xF0, 0x00, 0x43, ++ 0x0B, 0x60, 0x13, 0x68, 0x1B, 0x0C, 0x1B, 0x04, 0x43, 0xF4, 0xBB, 0x63, ++ 0x43, 0xF0, 0x04, 0x03, 0x13, 0x60, 0xB6, 0xE7, 0x64, 0xBA, 0x17, 0x00, ++ 0x94, 0x40, 0x04, 0x40, 0x10, 0x00, 0x32, 0x40, 0x14, 0x00, 0x32, 0x40, ++ 0x20, 0x00, 0x32, 0x40, 0x24, 0x00, 0x32, 0x40, 0x00, 0x10, 0x50, 0x40, ++ 0x40, 0x4B, 0x4C, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x48, 0x30, 0x34, 0x40, ++ 0x18, 0x88, 0x17, 0x00, 0xE8, 0xBB, 0x15, 0x00, 0x00, 0x88, 0x17, 0x00, ++ 0x4C, 0x36, 0x17, 0x00, 0x34, 0x04, 0x32, 0x40, 0x20, 0x04, 0x32, 0x40, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0x8B, 0x4B, 0x8C, 0x4E, 0xD3, 0xF8, 0x00, 0x90, ++ 0x8B, 0x4A, 0x99, 0xF8, 0x3D, 0x50, 0x4F, 0xF4, 0xA4, 0x64, 0x04, 0xFB, ++ 0x05, 0x64, 0x89, 0xB0, 0x07, 0x46, 0x88, 0x46, 0x4F, 0xF4, 0x80, 0x70, ++ 0x86, 0x49, 0x94, 0xF8, 0x6C, 0xA0, 0xFA, 0xF7, 0xAB, 0xFA, 0x94, 0xF8, ++ 0xC0, 0x34, 0x00, 0x2B, 0x40, 0xF0, 0x82, 0x80, 0xD4, 0xF8, 0x90, 0x31, ++ 0x98, 0x78, 0x00, 0x38, 0x18, 0xBF, 0x01, 0x20, 0x4F, 0xF4, 0xC0, 0x71, ++ 0xE5, 0xF7, 0xB2, 0xFE, 0x04, 0x46, 0x00, 0x28, 0x7C, 0xD0, 0x4F, 0xF4, ++ 0xA4, 0x63, 0x03, 0xFB, 0x05, 0x65, 0x28, 0x46, 0x21, 0x46, 0xF7, 0xF7, ++ 0xA5, 0xFF, 0x78, 0x4B, 0xA2, 0x6C, 0x78, 0x49, 0x4F, 0xF4, 0x1E, 0x70, ++ 0x00, 0xFB, 0x0A, 0x3A, 0x53, 0x46, 0xB1, 0xF8, 0xFC, 0x61, 0x53, 0xF8, ++ 0x26, 0x0F, 0xD0, 0x66, 0x6F, 0xF0, 0x4F, 0x00, 0x82, 0xF8, 0x68, 0x00, ++ 0x98, 0x88, 0xA2, 0xF8, 0x70, 0x00, 0xE8, 0x6D, 0xC2, 0xF8, 0x72, 0x00, ++ 0x01, 0x36, 0xB5, 0xF8, 0x60, 0x00, 0xA2, 0xF8, 0x76, 0x00, 0x4F, 0xF0, ++ 0x00, 0x0B, 0x18, 0x68, 0x9B, 0x88, 0xA2, 0xF8, 0x7C, 0x30, 0xB6, 0xB2, ++ 0x90, 0x67, 0x82, 0xF8, 0x69, 0xB0, 0x82, 0xF8, 0x6A, 0xB0, 0x82, 0xF8, ++ 0x6B, 0xB0, 0x65, 0x4B, 0xA1, 0xF8, 0xFC, 0x61, 0x30, 0x01, 0x95, 0xF8, ++ 0x63, 0x10, 0xA2, 0xF8, 0x7E, 0x00, 0x21, 0x77, 0x95, 0xF8, 0x6C, 0x10, ++ 0x1B, 0x68, 0x61, 0x77, 0x84, 0xF8, 0x33, 0xB0, 0x84, 0xF8, 0x35, 0xB0, ++ 0x1B, 0x78, 0x99, 0xF8, 0x3B, 0x10, 0x9B, 0x07, 0x02, 0xF1, 0x68, 0x05, ++ 0x38, 0xD4, 0x01, 0x29, 0x44, 0xD0, 0x18, 0x26, 0xCD, 0xF8, 0x00, 0x80, ++ 0x3A, 0x46, 0xA8, 0x19, 0x00, 0x23, 0xFB, 0xF7, 0xFF, 0xFB, 0x30, 0x44, ++ 0xE1, 0x6C, 0x94, 0xF8, 0x35, 0x30, 0x4A, 0x6A, 0xA4, 0x65, 0x18, 0x44, ++ 0x01, 0x3A, 0x02, 0x44, 0x03, 0x1D, 0x50, 0x48, 0x60, 0x65, 0xC1, 0xE9, ++ 0x0A, 0x23, 0x20, 0x46, 0x05, 0x21, 0xE5, 0xF7, 0x59, 0xFE, 0x4D, 0x4B, ++ 0x1B, 0x68, 0x06, 0x21, 0xDA, 0x68, 0x41, 0xF6, 0x08, 0x00, 0xF8, 0xF7, ++ 0xD1, 0xF9, 0x05, 0x21, 0x06, 0x20, 0xF8, 0xF7, 0x69, 0xFD, 0x09, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x8F, 0x01, 0x20, 0x4F, 0xF4, 0xC0, 0x71, 0xE5, 0xF7, ++ 0x35, 0xFE, 0x04, 0x46, 0x00, 0x28, 0x82, 0xD1, 0x01, 0x20, 0xFF, 0xF7, ++ 0x67, 0xFE, 0x09, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x01, 0x29, 0x01, 0xD1, ++ 0x03, 0x2F, 0x17, 0xD0, 0xCD, 0xF8, 0x00, 0x80, 0x3A, 0x46, 0x05, 0xF1, ++ 0x18, 0x00, 0x00, 0x23, 0xFB, 0xF7, 0xC4, 0xFB, 0x18, 0x30, 0xC3, 0xE7, ++ 0x03, 0x2F, 0xB8, 0xD1, 0x29, 0x46, 0x20, 0x46, 0x18, 0x22, 0x05, 0xF0, ++ 0xB1, 0xFD, 0x94, 0xF8, 0x33, 0x00, 0x99, 0xF8, 0x3B, 0x10, 0x00, 0xF1, ++ 0x18, 0x06, 0xAD, 0xE7, 0xDA, 0xF8, 0xB4, 0x30, 0x29, 0x46, 0x18, 0x22, ++ 0x20, 0x46, 0x1E, 0x68, 0x05, 0xF0, 0xA2, 0xFD, 0x94, 0xF8, 0x33, 0x00, ++ 0x99, 0xF8, 0x3B, 0x10, 0xCD, 0xF8, 0x00, 0x80, 0x00, 0xF1, 0x18, 0x08, ++ 0x05, 0xEB, 0x08, 0x09, 0x5B, 0x46, 0x3A, 0x46, 0x48, 0x46, 0xFB, 0xF7, ++ 0x9D, 0xFB, 0x05, 0x46, 0x3A, 0x46, 0x29, 0x46, 0x4F, 0xF0, 0xFF, 0x33, ++ 0x48, 0x46, 0xDB, 0xF7, 0x67, 0xFD, 0x96, 0xF8, 0x60, 0x30, 0x21, 0x8F, ++ 0x62, 0x8F, 0xAD, 0xF8, 0x10, 0x10, 0x8D, 0xF8, 0x12, 0x20, 0x06, 0xF1, ++ 0x64, 0x01, 0x93, 0xB1, 0x03, 0x2B, 0x1A, 0xD0, 0x03, 0x20, 0xDB, 0xF7, ++ 0x8F, 0xFD, 0x29, 0x1D, 0x02, 0x46, 0x89, 0xB2, 0x48, 0x46, 0x03, 0x91, ++ 0xF7, 0xF7, 0x20, 0xFF, 0x48, 0x46, 0x03, 0x99, 0xF8, 0xF7, 0x16, 0xF9, ++ 0x05, 0xEB, 0x08, 0x00, 0x78, 0xE7, 0x05, 0x22, 0x0D, 0xF1, 0x13, 0x00, ++ 0x0C, 0xF0, 0x88, 0xFE, 0x04, 0xA8, 0x08, 0x21, 0xF8, 0xF7, 0xDE, 0xF8, ++ 0xE4, 0xE7, 0x0D, 0x22, 0x0D, 0xF1, 0x13, 0x00, 0x0C, 0xF0, 0x7E, 0xFE, ++ 0x04, 0xA8, 0x10, 0x21, 0xF8, 0xF7, 0xD4, 0xF8, 0xDA, 0xE7, 0x00, 0xBF, ++ 0x64, 0xBA, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, 0x9C, 0xBC, 0x15, 0x00, ++ 0xCC, 0xB5, 0x15, 0x00, 0x68, 0x65, 0x17, 0x00, 0x20, 0x62, 0x17, 0x00, ++ 0x34, 0x36, 0x17, 0x00, 0x89, 0x95, 0x14, 0x00, 0xC8, 0x35, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0x77, 0x4F, 0x78, 0x4E, 0xD7, 0xF8, 0x00, 0x80, ++ 0x77, 0x4A, 0x98, 0xF8, 0x3D, 0x50, 0x77, 0x49, 0x4F, 0xF4, 0xA4, 0x64, ++ 0x04, 0xFB, 0x05, 0x64, 0x87, 0xB0, 0x4F, 0xF4, 0x80, 0x70, 0x94, 0xF8, ++ 0x6C, 0xA0, 0xFA, 0xF7, 0x81, 0xF9, 0x94, 0xF8, 0xC0, 0x34, 0x00, 0x2B, ++ 0x40, 0xF0, 0xAA, 0x80, 0xD4, 0xF8, 0x90, 0x31, 0x98, 0x78, 0x00, 0x38, ++ 0x18, 0xBF, 0x01, 0x20, 0x4F, 0xF4, 0xC0, 0x71, 0xE5, 0xF7, 0x88, 0xFD, ++ 0x04, 0x46, 0x00, 0x28, 0x00, 0xF0, 0xA5, 0x80, 0x4F, 0xF4, 0xA4, 0x6B, ++ 0x0B, 0xFB, 0x05, 0xFB, 0x06, 0xEB, 0x0B, 0x00, 0x21, 0x46, 0xD7, 0xF8, ++ 0x04, 0x90, 0xF7, 0xF7, 0x77, 0xFE, 0xBA, 0x7D, 0xA3, 0x6C, 0x01, 0x2A, ++ 0x03, 0xF1, 0x68, 0x0C, 0x00, 0xF0, 0x99, 0x80, 0xBA, 0x7F, 0x00, 0x2A, ++ 0x00, 0xF0, 0xA7, 0x80, 0x20, 0x22, 0x00, 0x21, 0x83, 0xF8, 0x68, 0x20, ++ 0x5B, 0x4A, 0x83, 0xF8, 0x69, 0x10, 0x5B, 0x49, 0x5B, 0x4F, 0x4F, 0xF4, ++ 0x1E, 0x70, 0x00, 0xFB, 0x0A, 0x10, 0xB7, 0xF8, 0xFC, 0xE1, 0x50, 0xF8, ++ 0x26, 0xAF, 0xC3, 0xF8, 0x6C, 0xA0, 0x4F, 0xF4, 0xA4, 0x61, 0x01, 0xFB, ++ 0x05, 0x65, 0xB0, 0xF8, 0x04, 0xA0, 0xA3, 0xF8, 0x70, 0xA0, 0x0B, 0xF1, ++ 0xEC, 0x01, 0x0E, 0xF1, 0x01, 0x0E, 0xD0, 0xF8, 0x00, 0xA0, 0xB0, 0xF8, ++ 0x04, 0xB0, 0xE8, 0x6D, 0xC3, 0xF8, 0x72, 0x00, 0x1F, 0xFA, 0x8E, 0xFE, ++ 0x31, 0x44, 0x00, 0x26, 0xB5, 0xF8, 0x60, 0x00, 0xC3, 0xF8, 0x78, 0xA0, ++ 0x83, 0xF8, 0x6A, 0x60, 0x83, 0xF8, 0x6B, 0x60, 0x4F, 0xEA, 0x0E, 0x1A, ++ 0x46, 0x4E, 0xA3, 0xF8, 0x76, 0x00, 0xA3, 0xF8, 0x7C, 0xB0, 0x0C, 0xF1, ++ 0x18, 0x00, 0xA7, 0xF8, 0xFC, 0xE1, 0x0D, 0xF1, 0x12, 0x0C, 0xA3, 0xF8, ++ 0x7E, 0xA0, 0x05, 0xAF, 0x95, 0xF8, 0x63, 0x30, 0xCD, 0xF8, 0x08, 0x80, ++ 0xD6, 0xF8, 0x58, 0x61, 0xCD, 0xE9, 0x00, 0x7C, 0xB0, 0x47, 0x95, 0xF8, ++ 0x63, 0x30, 0x23, 0x77, 0x95, 0xF8, 0x6C, 0x30, 0xE1, 0x6C, 0x63, 0x77, ++ 0x4B, 0x6A, 0xBD, 0xF8, 0x12, 0x20, 0x37, 0x4D, 0xA4, 0x65, 0x17, 0x33, ++ 0x03, 0x44, 0xB2, 0xF5, 0x48, 0x7F, 0x00, 0xF1, 0x1C, 0x00, 0x65, 0x65, ++ 0xC1, 0xE9, 0x0A, 0x30, 0x3B, 0xD8, 0x05, 0x98, 0x6A, 0xB1, 0x4A, 0x44, ++ 0x13, 0x38, 0x13, 0x32, 0xA0, 0xEB, 0x09, 0x00, 0x09, 0xF1, 0x13, 0x03, ++ 0xC1, 0x5C, 0x03, 0xF8, 0x01, 0x1F, 0x93, 0x42, 0xFA, 0xD1, 0xBD, 0xF8, ++ 0x12, 0x20, 0xA9, 0xF8, 0x0E, 0x20, 0x20, 0x46, 0x05, 0x21, 0xE5, 0xF7, ++ 0x07, 0xFD, 0x27, 0x4B, 0x1B, 0x68, 0x06, 0x21, 0x9A, 0x68, 0x41, 0xF6, ++ 0x08, 0x00, 0xF8, 0xF7, 0x7F, 0xF8, 0x07, 0x21, 0x06, 0x20, 0xF8, 0xF7, ++ 0x17, 0xFC, 0x07, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x01, 0x20, 0x4F, 0xF4, ++ 0xC0, 0x71, 0xE5, 0xF7, 0xE3, 0xFC, 0x04, 0x46, 0x00, 0x28, 0x7F, 0xF4, ++ 0x5B, 0xAF, 0x01, 0x20, 0xFF, 0xF7, 0x14, 0xFD, 0x07, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x8F, 0x20, 0x22, 0x00, 0x21, 0x83, 0xF8, 0x68, 0x20, 0x83, 0xF8, ++ 0x69, 0x10, 0x16, 0x4A, 0x69, 0xE7, 0x16, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0x08, 0xDB, 0x00, 0x23, 0xA9, 0xF8, 0x0E, 0x30, ++ 0xCB, 0xE7, 0x83, 0xF8, 0x68, 0x20, 0x83, 0xF8, 0x69, 0x20, 0x5A, 0xE7, ++ 0x0F, 0x49, 0x10, 0x48, 0x4F, 0xF4, 0x82, 0x62, 0xFA, 0xF7, 0xE8, 0xFA, ++ 0xEF, 0xE7, 0x00, 0xBF, 0x64, 0xBA, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0xAC, 0xBC, 0x15, 0x00, 0xCC, 0xB5, 0x15, 0x00, 0x84, 0xBA, 0x17, 0x00, ++ 0x68, 0x65, 0x17, 0x00, 0x20, 0x62, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x89, 0x95, 0x14, 0x00, 0xC8, 0x35, 0x17, 0x00, 0x7C, 0xBA, 0x17, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x64, 0x7D, 0x15, 0x00, ++ 0x38, 0xB5, 0x0B, 0x4D, 0x04, 0x46, 0x04, 0x23, 0x00, 0x21, 0x06, 0x22, ++ 0x1E, 0x20, 0x2D, 0x68, 0xF8, 0xF7, 0xC6, 0xF9, 0x01, 0x22, 0x04, 0x80, ++ 0x82, 0x70, 0x95, 0xF8, 0x3D, 0x20, 0xC2, 0x70, 0xF8, 0xF7, 0xEE, 0xF9, ++ 0xBD, 0xE8, 0x38, 0x40, 0x08, 0x21, 0x06, 0x20, 0xF8, 0xF7, 0xB2, 0xBB, ++ 0x64, 0xBA, 0x17, 0x00, 0x70, 0xB5, 0x00, 0xF1, 0x0C, 0x06, 0x06, 0x21, ++ 0x04, 0x46, 0x41, 0xF6, 0x08, 0x00, 0xF8, 0xF7, 0xBB, 0xF8, 0xB5, 0x88, ++ 0x19, 0x49, 0x2A, 0x46, 0x4F, 0xF4, 0x80, 0x70, 0xFA, 0xF7, 0x5E, 0xF8, ++ 0x45, 0xB9, 0xA3, 0x89, 0x13, 0xB1, 0x01, 0x2B, 0x09, 0xD0, 0x70, 0xBD, ++ 0xBD, 0xE8, 0x70, 0x40, 0xFF, 0xF7, 0xBE, 0xBE, 0x28, 0x46, 0xBD, 0xE8, ++ 0x70, 0x40, 0xFF, 0xF7, 0x9D, 0xBC, 0x73, 0x88, 0x04, 0x2B, 0xF3, 0xD0, ++ 0x02, 0x2B, 0x11, 0xD0, 0x0D, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0x04, 0xDB, 0xBD, 0xE8, 0x70, 0x40, 0x01, 0x20, 0xFF, 0xF7, ++ 0x8D, 0xBC, 0x09, 0x49, 0x09, 0x48, 0x4F, 0xF4, 0x8C, 0x62, 0xFA, 0xF7, ++ 0x7B, 0xFA, 0xF3, 0xE7, 0x04, 0xF1, 0x14, 0x01, 0x03, 0x20, 0xBD, 0xE8, ++ 0x70, 0x40, 0xFF, 0xF7, 0x6F, 0xBD, 0x00, 0xBF, 0x00, 0xBC, 0x15, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x64, 0x7D, 0x15, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0x69, 0x4B, 0xD3, 0xE9, 0x00, 0x2A, 0x05, 0x46, ++ 0x83, 0xB0, 0x06, 0x21, 0x00, 0x24, 0x41, 0xF6, 0x08, 0x00, 0x92, 0xF8, ++ 0x3D, 0x80, 0x8D, 0xF8, 0x06, 0x40, 0xF8, 0xF7, 0x6D, 0xF8, 0x29, 0x88, ++ 0xEE, 0x89, 0x4F, 0xF4, 0xA4, 0x67, 0x05, 0x29, 0x05, 0xF1, 0x0C, 0x09, ++ 0x07, 0xFB, 0x08, 0xF7, 0x34, 0xD9, 0xBA, 0xF8, 0x0E, 0x30, 0x06, 0x39, ++ 0x89, 0xB2, 0xCA, 0x18, 0x05, 0xF1, 0x12, 0x0B, 0xB2, 0xF5, 0x48, 0x7F, ++ 0x5C, 0x46, 0x09, 0xDD, 0x58, 0x4A, 0x12, 0x68, 0xB2, 0xF9, 0x00, 0x20, ++ 0x00, 0x2A, 0xC0, 0xF2, 0x81, 0x80, 0xC3, 0xF5, 0x48, 0x71, 0x89, 0xB2, ++ 0x0A, 0xF1, 0x14, 0x00, 0x18, 0x44, 0x8B, 0x44, 0x39, 0xB1, 0xA4, 0xF1, ++ 0x12, 0x03, 0x14, 0xF8, 0x01, 0x2B, 0x5B, 0x1B, 0x5C, 0x45, 0x1A, 0x54, ++ 0xF7, 0xD1, 0xAA, 0xF8, 0x10, 0x10, 0x32, 0x46, 0x4C, 0x49, 0x4F, 0xF4, ++ 0x80, 0x70, 0xF9, 0xF7, 0xE3, 0xFF, 0x9E, 0xB1, 0x4A, 0x4B, 0x93, 0xF8, ++ 0x04, 0x31, 0x2B, 0xBB, 0x30, 0x46, 0xFF, 0xF7, 0x29, 0xFC, 0x03, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x8F, 0x44, 0x49, 0xAA, 0xF8, 0x10, 0x40, 0x32, 0x46, ++ 0x4F, 0xF4, 0x80, 0x70, 0xF9, 0xF7, 0xD0, 0xFF, 0x00, 0x2E, 0xEB, 0xD1, ++ 0xB9, 0xF8, 0x04, 0x00, 0x40, 0x4C, 0xC0, 0xF3, 0x0D, 0x00, 0xFF, 0xF7, ++ 0x3F, 0xFF, 0x3D, 0x4B, 0x93, 0xF8, 0x04, 0x31, 0x63, 0xB3, 0x4F, 0xF4, ++ 0xA4, 0x65, 0x05, 0xFB, 0x08, 0x45, 0xD5, 0xF8, 0x90, 0x31, 0x9A, 0x78, ++ 0x01, 0x2A, 0x48, 0xD0, 0x38, 0x4E, 0x28, 0xE0, 0x12, 0x2E, 0xD7, 0xD1, ++ 0x35, 0x4B, 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, 0x08, 0x38, 0xD8, 0xF8, ++ 0x90, 0x21, 0x92, 0x78, 0x01, 0x2A, 0xCD, 0xD1, 0x98, 0xF8, 0xC0, 0x44, ++ 0x00, 0x2C, 0xC9, 0xD1, 0x30, 0x4D, 0x07, 0xF5, 0xB2, 0x77, 0x1F, 0x44, ++ 0xA8, 0x46, 0x40, 0x46, 0x06, 0x22, 0x39, 0x46, 0x0C, 0xF0, 0x3E, 0xFC, ++ 0x08, 0xF1, 0x14, 0x08, 0x00, 0x28, 0x3F, 0xD0, 0x01, 0x34, 0x05, 0x2C, ++ 0xF3, 0xD1, 0xB7, 0xE7, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x08, 0x43, ++ 0x24, 0x4E, 0xD3, 0xF8, 0x90, 0x31, 0x1B, 0x79, 0xD6, 0xF8, 0x40, 0x53, ++ 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, 0x08, 0x48, 0xE0, 0x19, 0x98, 0xF8, ++ 0xC6, 0x21, 0x9B, 0x1A, 0x8D, 0xF8, 0x07, 0x30, 0x0D, 0xF1, 0x06, 0x02, ++ 0x0D, 0xF1, 0x07, 0x01, 0xA8, 0x47, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, ++ 0x1A, 0x49, 0x1B, 0x48, 0x40, 0xF2, 0x8B, 0x42, 0xFA, 0xF7, 0xB6, 0xF9, ++ 0xBA, 0xF8, 0x0E, 0x30, 0x75, 0xE7, 0xD5, 0xF8, 0xCC, 0x21, 0x12, 0xF0, ++ 0x0C, 0x0F, 0xB1, 0xD0, 0x95, 0xF8, 0xC0, 0x24, 0x00, 0x2A, 0xAD, 0xD1, ++ 0x13, 0x4B, 0x14, 0x49, 0x1B, 0x69, 0x0E, 0x4E, 0x07, 0xF1, 0x9C, 0x00, ++ 0x19, 0x44, 0x20, 0x44, 0xD6, 0xF8, 0xE0, 0x31, 0x98, 0x47, 0xD5, 0xF8, ++ 0x90, 0x31, 0xCA, 0xE7, 0x04, 0xEB, 0x84, 0x04, 0x05, 0xEB, 0x84, 0x04, ++ 0x01, 0x23, 0xE3, 0x71, 0x74, 0xE7, 0x00, 0xBF, 0x64, 0xBA, 0x17, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x14, 0xBC, 0x15, 0x00, 0x2C, 0x19, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0xCC, 0x35, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x64, 0x7D, 0x15, 0x00, 0x00, 0x10, 0x50, 0x40, ++ 0x80, 0x96, 0x98, 0x00, 0x2D, 0xE9, 0xF0, 0x47, 0x04, 0x46, 0x06, 0x20, ++ 0x25, 0x7A, 0xF8, 0xF7, 0x1F, 0xFB, 0x09, 0x28, 0x0A, 0xD0, 0x06, 0x20, ++ 0xF8, 0xF7, 0x1A, 0xFB, 0x48, 0xB1, 0x2D, 0x4A, 0x23, 0x7A, 0x12, 0x68, ++ 0x92, 0xF8, 0x3D, 0x20, 0x9A, 0x42, 0x0D, 0xD0, 0x02, 0x20, 0xBD, 0xE8, ++ 0xF0, 0x87, 0x29, 0x4F, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x05, 0xF5, ++ 0x7E, 0x19, 0x96, 0xF8, 0x64, 0x00, 0x60, 0xB9, 0xBD, 0xE8, 0xF0, 0x87, ++ 0x24, 0x49, 0x4F, 0xF4, 0x80, 0x70, 0xF9, 0xF7, 0x15, 0xFF, 0x01, 0x20, ++ 0xFF, 0xF7, 0x60, 0xFB, 0x00, 0x20, 0xBD, 0xE8, 0xF0, 0x87, 0xA4, 0x89, ++ 0x1F, 0x49, 0x22, 0x46, 0x4F, 0xF4, 0x80, 0x70, 0xF9, 0xF7, 0x08, 0xFF, ++ 0x1D, 0x4B, 0x93, 0xF8, 0x04, 0x31, 0x0B, 0xB1, 0x08, 0x2C, 0x0A, 0xD0, ++ 0x09, 0x21, 0x06, 0x20, 0xF8, 0xF7, 0x40, 0xFA, 0x78, 0x19, 0x21, 0x46, ++ 0xFF, 0xF7, 0xBC, 0xF9, 0x00, 0x20, 0xBD, 0xE8, 0xF0, 0x87, 0xD6, 0xF8, ++ 0x90, 0x31, 0x9B, 0x78, 0x01, 0x2B, 0xEF, 0xD1, 0x96, 0xF8, 0xC0, 0x64, ++ 0x00, 0x2E, 0xEB, 0xD1, 0xDF, 0xF8, 0x44, 0x90, 0x05, 0xF5, 0xB2, 0x7A, ++ 0xC8, 0x46, 0xBA, 0x44, 0x40, 0x46, 0x06, 0x22, 0x51, 0x46, 0x0C, 0xF0, ++ 0x83, 0xFB, 0x08, 0xF1, 0x14, 0x08, 0x18, 0xB1, 0x01, 0x36, 0x05, 0x2E, ++ 0xF4, 0xD1, 0xD9, 0xE7, 0x06, 0xEB, 0x86, 0x06, 0x09, 0xEB, 0x86, 0x06, ++ 0x01, 0x23, 0xB3, 0x71, 0xD2, 0xE7, 0x00, 0xBF, 0x64, 0xBA, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0x2C, 0xBC, 0x15, 0x00, 0x50, 0xBC, 0x15, 0x00, ++ 0x2C, 0x19, 0x17, 0x00, 0xCC, 0x35, 0x17, 0x00, 0x2D, 0xE9, 0xF8, 0x43, ++ 0x46, 0x4B, 0x04, 0x7A, 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, 0x04, 0x34, ++ 0x94, 0xF8, 0x64, 0x30, 0xC3, 0xB1, 0x94, 0xF8, 0x62, 0x30, 0xAB, 0xB9, ++ 0xC3, 0x79, 0xFF, 0x2B, 0x05, 0x46, 0x11, 0xD0, 0x94, 0xF8, 0x6C, 0x20, ++ 0x9A, 0x42, 0x0D, 0xD1, 0x3D, 0x4E, 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, ++ 0x02, 0x66, 0x96, 0xF8, 0x30, 0x30, 0x02, 0x2B, 0x04, 0xD1, 0x90, 0xF8, ++ 0x0D, 0x90, 0xB9, 0xF1, 0x00, 0x0F, 0x01, 0xD0, 0xBD, 0xE8, 0xF8, 0x83, ++ 0x80, 0x79, 0xB5, 0xF8, 0x0E, 0x80, 0x00, 0x38, 0x18, 0xBF, 0x01, 0x20, ++ 0x4F, 0xF4, 0xC0, 0x71, 0xE5, 0xF7, 0xAE, 0xFA, 0x07, 0x46, 0x00, 0x28, ++ 0xF0, 0xD0, 0x01, 0x46, 0x20, 0x46, 0xF7, 0xF7, 0xA5, 0xFB, 0x32, 0x46, ++ 0xDF, 0xF8, 0xB4, 0xC0, 0xBB, 0x6C, 0x52, 0xF8, 0x26, 0x0F, 0xBC, 0xF8, ++ 0xFC, 0x11, 0xD8, 0x66, 0x6F, 0xF0, 0x2F, 0x00, 0x83, 0xF8, 0x68, 0x00, ++ 0x01, 0x31, 0x90, 0x88, 0xA3, 0xF8, 0x70, 0x00, 0x89, 0xB2, 0xE0, 0x6D, ++ 0xB4, 0xF8, 0x60, 0x40, 0xA3, 0xF8, 0x76, 0x40, 0xC3, 0xF8, 0x72, 0x00, ++ 0x14, 0x68, 0x90, 0x88, 0x83, 0xF8, 0x69, 0x90, 0x0A, 0x01, 0x83, 0xF8, ++ 0x6A, 0x90, 0x83, 0xF8, 0x6B, 0x90, 0x9C, 0x67, 0xA3, 0xF8, 0x7C, 0x00, ++ 0xAC, 0xF8, 0xFC, 0x11, 0xA3, 0xF8, 0x7E, 0x20, 0x2A, 0x7A, 0x3A, 0x77, ++ 0xEA, 0x79, 0x7A, 0x77, 0x03, 0xF1, 0x68, 0x04, 0x87, 0xF8, 0x33, 0x90, ++ 0x87, 0xF8, 0x35, 0x90, 0x08, 0x22, 0xD0, 0x21, 0x38, 0x46, 0x06, 0xF0, ++ 0xA5, 0xFB, 0x21, 0x46, 0x38, 0x46, 0x18, 0x22, 0x05, 0xF0, 0x04, 0xFA, ++ 0x97, 0xF8, 0x33, 0x30, 0x18, 0x33, 0x1A, 0x19, 0x08, 0x21, 0x19, 0x55, ++ 0x01, 0x21, 0x51, 0x70, 0xF9, 0x6C, 0xA2, 0xF8, 0x02, 0x80, 0x97, 0xF8, ++ 0x35, 0x00, 0x4A, 0x6A, 0x04, 0x30, 0x03, 0x44, 0x01, 0x3A, 0x1A, 0x44, ++ 0x04, 0x33, 0xC1, 0xE9, 0x0A, 0x23, 0x38, 0x46, 0x05, 0x21, 0xBD, 0xE8, ++ 0xF8, 0x43, 0xE5, 0xF7, 0x5F, 0xBA, 0x00, 0xBF, 0x18, 0x88, 0x17, 0x00, ++ 0x68, 0x65, 0x17, 0x00, 0x20, 0x62, 0x17, 0x00, 0x31, 0x4B, 0x32, 0x4A, ++ 0x1B, 0x68, 0x2D, 0xE9, 0xF0, 0x41, 0xB3, 0xF9, 0x00, 0x30, 0xD2, 0xF8, ++ 0x00, 0x80, 0x2F, 0x4F, 0x98, 0xF8, 0x3D, 0x50, 0x00, 0x2B, 0x06, 0x46, ++ 0x45, 0xDB, 0x2C, 0x23, 0x06, 0x22, 0x0C, 0x21, 0x41, 0xF6, 0x06, 0x00, ++ 0xF7, 0xF7, 0x64, 0xFF, 0x4F, 0xF4, 0xA4, 0x61, 0x03, 0x46, 0x98, 0xF8, ++ 0x3D, 0x20, 0x03, 0xF8, 0x01, 0x2B, 0x01, 0xFB, 0x05, 0x71, 0x01, 0xF5, ++ 0xB5, 0x72, 0x04, 0x46, 0x01, 0xF5, 0xC5, 0x71, 0xD2, 0xF8, 0x00, 0xE0, ++ 0xD2, 0xF8, 0x04, 0xC0, 0x90, 0x68, 0xD2, 0xF8, 0x0C, 0x80, 0xC3, 0xF8, ++ 0x0C, 0x80, 0x10, 0x32, 0x8A, 0x42, 0xC3, 0xF8, 0x00, 0xE0, 0xC3, 0xF8, ++ 0x04, 0xC0, 0x98, 0x60, 0x03, 0xF1, 0x10, 0x03, 0xEC, 0xD1, 0x4F, 0xF4, ++ 0xA4, 0x61, 0x12, 0x78, 0x1A, 0x70, 0x01, 0xFB, 0x05, 0x75, 0x36, 0xBA, ++ 0xD5, 0xF8, 0x64, 0x01, 0xB5, 0xF8, 0x68, 0x31, 0xE3, 0x84, 0x06, 0x21, ++ 0xC4, 0xF8, 0x22, 0x00, 0xA6, 0x62, 0x08, 0x46, 0xF8, 0xF7, 0x2A, 0xF9, ++ 0x41, 0xF6, 0x08, 0x00, 0x0E, 0x4A, 0x06, 0x21, 0xF7, 0xF7, 0x88, 0xFD, ++ 0x20, 0x46, 0xBD, 0xE8, 0xF0, 0x41, 0xF7, 0xF7, 0x55, 0xBF, 0x4F, 0xF4, ++ 0xA4, 0x63, 0x03, 0xFB, 0x05, 0x73, 0xD3, 0xF8, 0xCC, 0x31, 0x00, 0x2B, ++ 0xB1, 0xDB, 0x07, 0x49, 0x07, 0x48, 0x4F, 0xF4, 0xAB, 0x62, 0xF9, 0xF7, ++ 0xF9, 0xFF, 0xAA, 0xE7, 0x38, 0x36, 0x17, 0x00, 0x64, 0xBA, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0xC0, 0x27, 0x09, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x74, 0xBC, 0x15, 0x00, 0x10, 0xB5, 0x06, 0x21, 0x04, 0x46, 0x41, 0xF6, ++ 0x08, 0x00, 0xF7, 0xF7, 0x11, 0xFE, 0x1C, 0xB9, 0xBD, 0xE8, 0x10, 0x40, ++ 0xFF, 0xF7, 0x20, 0xBC, 0x20, 0x46, 0xBD, 0xE8, 0x10, 0x40, 0xFF, 0xF7, ++ 0xFF, 0xB9, 0x00, 0xBF, 0x08, 0xB5, 0x06, 0x20, 0xF8, 0xF7, 0x96, 0xF9, ++ 0xA0, 0xF1, 0x06, 0x00, 0xB0, 0xFA, 0x80, 0xF0, 0x40, 0x09, 0x08, 0xBD, ++ 0x00, 0xB5, 0x83, 0xB0, 0x0D, 0xF1, 0x07, 0x02, 0xF8, 0xF7, 0xDE, 0xFD, ++ 0xB8, 0xB1, 0x9D, 0xF8, 0x07, 0x30, 0x1D, 0x2B, 0x16, 0xD9, 0x02, 0x89, ++ 0x92, 0x00, 0x0A, 0x3B, 0x92, 0xB2, 0x9B, 0x1A, 0xDB, 0xB2, 0x15, 0x2B, ++ 0x0E, 0xD9, 0x0A, 0x30, 0x02, 0x3B, 0x81, 0x5A, 0x89, 0x00, 0x89, 0xB2, ++ 0x5B, 0x1A, 0xDB, 0xB2, 0x13, 0x2B, 0x10, 0x44, 0x04, 0xD9, 0x04, 0x30, ++ 0x40, 0x5A, 0x03, 0xB0, 0x5D, 0xF8, 0x04, 0xFB, 0x00, 0x20, 0x03, 0xB0, ++ 0x5D, 0xF8, 0x04, 0xFB, 0x2D, 0xE9, 0xF0, 0x4F, 0x4F, 0xF4, 0xA4, 0x68, ++ 0x95, 0xB0, 0xDF, 0xF8, 0x50, 0x93, 0xDF, 0xF8, 0x50, 0xB3, 0x08, 0xFB, ++ 0x00, 0xF3, 0x07, 0x93, 0x4B, 0x44, 0x05, 0x46, 0xD3, 0xF8, 0x90, 0x01, ++ 0x93, 0xF8, 0x6C, 0x40, 0x80, 0x78, 0x02, 0x93, 0x17, 0x46, 0x4F, 0xF4, ++ 0x1E, 0x78, 0x00, 0x38, 0x08, 0xFB, 0x04, 0xB6, 0x0A, 0x46, 0x3B, 0x78, ++ 0xD6, 0xF8, 0xB0, 0xA0, 0x04, 0x94, 0x18, 0xBF, 0x01, 0x20, 0x4F, 0xF4, ++ 0xC0, 0x71, 0x05, 0x92, 0x06, 0x93, 0xE5, 0xF7, 0x6F, 0xF9, 0x00, 0x28, ++ 0x00, 0xF0, 0xED, 0x80, 0x02, 0x9B, 0x04, 0x46, 0x21, 0x46, 0x18, 0x46, ++ 0xF7, 0xF7, 0x64, 0xFA, 0xB9, 0x4B, 0x96, 0xF8, 0x23, 0x00, 0xD3, 0xF8, ++ 0x34, 0x21, 0xA3, 0x6C, 0x02, 0x93, 0x00, 0x21, 0x90, 0x47, 0x02, 0x9B, ++ 0x03, 0x90, 0x03, 0xF1, 0x68, 0x02, 0x08, 0x92, 0x00, 0x28, 0x40, 0xF0, ++ 0xD9, 0x80, 0xB2, 0x49, 0xB1, 0xF8, 0xFC, 0x21, 0x01, 0x32, 0x92, 0xB2, ++ 0x08, 0x20, 0x83, 0xF8, 0x68, 0x00, 0x10, 0x01, 0x01, 0x26, 0x80, 0xB2, ++ 0x83, 0xF8, 0x69, 0x60, 0x09, 0x90, 0xA1, 0xF8, 0xFC, 0x21, 0x04, 0x99, ++ 0x02, 0x93, 0x4F, 0xF4, 0x1E, 0x72, 0x02, 0xFB, 0x01, 0xB2, 0x4F, 0xF4, ++ 0xA4, 0x66, 0x52, 0xF8, 0x26, 0x1F, 0xD9, 0x66, 0x06, 0xFB, 0x05, 0x96, ++ 0x91, 0x88, 0xF0, 0x6D, 0xB6, 0xF8, 0x60, 0x20, 0xA3, 0xF8, 0x76, 0x20, ++ 0x4F, 0xF0, 0x00, 0x08, 0xA3, 0xF8, 0x70, 0x10, 0xC3, 0xF8, 0x72, 0x00, ++ 0x05, 0x99, 0x83, 0xF8, 0x6A, 0x80, 0x83, 0xF8, 0x6B, 0x80, 0x06, 0x22, ++ 0x03, 0xF1, 0x78, 0x00, 0x0C, 0xF0, 0xDC, 0xF9, 0x09, 0x9B, 0x96, 0xF8, ++ 0x63, 0x20, 0x19, 0x01, 0x02, 0x9B, 0xA3, 0xF8, 0x7E, 0x10, 0x22, 0x77, ++ 0x96, 0xF8, 0x6C, 0x20, 0x62, 0x77, 0x03, 0x9A, 0x00, 0x2A, 0x00, 0xF0, ++ 0xE1, 0x80, 0x1A, 0x22, 0x83, 0xF8, 0x80, 0x80, 0x83, 0xF8, 0x81, 0x80, ++ 0x02, 0x92, 0x7A, 0x78, 0x00, 0x21, 0x12, 0xF0, 0x40, 0x02, 0xCD, 0xE9, ++ 0x0A, 0x11, 0x40, 0xF0, 0xB5, 0x80, 0x84, 0xF8, 0x33, 0x20, 0x84, 0xF8, ++ 0x35, 0x20, 0x89, 0x4B, 0x02, 0x9A, 0x93, 0xE8, 0x03, 0x00, 0x08, 0x9B, ++ 0x13, 0x44, 0x1E, 0x46, 0x0D, 0xF1, 0x30, 0x0C, 0x07, 0x9B, 0x8C, 0xE8, ++ 0x03, 0x00, 0x08, 0x22, 0x61, 0x46, 0x30, 0x46, 0x03, 0xF1, 0x5C, 0x08, ++ 0x0C, 0xF0, 0xA8, 0xF9, 0x7F, 0x4B, 0xD3, 0xE9, 0x02, 0x01, 0x08, 0x22, ++ 0x0E, 0xAB, 0x83, 0xE8, 0x03, 0x00, 0xC8, 0x44, 0x19, 0x46, 0xB0, 0x18, ++ 0x0C, 0xF0, 0x9C, 0xF9, 0x06, 0x22, 0x41, 0x46, 0x06, 0xF1, 0x10, 0x00, ++ 0x0C, 0xF0, 0x96, 0xF9, 0x4F, 0xF4, 0xA4, 0x60, 0x00, 0xFB, 0x05, 0x95, ++ 0x9D, 0xF9, 0x18, 0x20, 0xD5, 0xF8, 0xC4, 0x34, 0xB3, 0x75, 0xD5, 0xF8, ++ 0xC4, 0x34, 0x1B, 0x0A, 0xF3, 0x75, 0xB5, 0xF8, 0xC6, 0x34, 0x33, 0x76, ++ 0x95, 0xF8, 0xC7, 0x34, 0x73, 0x76, 0x7B, 0x78, 0x58, 0x06, 0x67, 0xD4, ++ 0x00, 0x2A, 0xB8, 0xBF, 0x07, 0xF1, 0x2A, 0x01, 0x4F, 0xF0, 0x0A, 0x02, ++ 0xA8, 0xBF, 0x07, 0xF1, 0x28, 0x01, 0x06, 0xF1, 0x1A, 0x00, 0x0C, 0xF0, ++ 0x73, 0xF9, 0xE2, 0x6C, 0x94, 0xF8, 0x35, 0x50, 0x53, 0x6A, 0x02, 0x99, ++ 0xA4, 0x65, 0x24, 0x35, 0x0D, 0x44, 0x01, 0x3B, 0x2B, 0x44, 0x00, 0x20, ++ 0x29, 0x1D, 0x60, 0x65, 0xC2, 0xE9, 0x0A, 0x31, 0x03, 0x9B, 0x6B, 0xB1, ++ 0x04, 0x9B, 0x4F, 0xF4, 0x1E, 0x72, 0x02, 0xFB, 0x03, 0xB3, 0x93, 0xF8, ++ 0x23, 0x30, 0x02, 0xFB, 0x03, 0xBB, 0x9B, 0xF8, 0xA5, 0x91, 0xB9, 0xF1, ++ 0x21, 0x0F, 0x6A, 0xD1, 0x7B, 0x78, 0x59, 0x06, 0x2F, 0xD5, 0x9A, 0xF8, ++ 0x60, 0x30, 0x01, 0x2B, 0x00, 0xF0, 0x53, 0x81, 0x52, 0x4B, 0x1B, 0x68, ++ 0x1B, 0x78, 0x9B, 0x07, 0x09, 0xD5, 0x9A, 0xF8, 0x60, 0x30, 0x01, 0x2B, ++ 0x0A, 0xF1, 0x64, 0x09, 0x40, 0xF2, 0x36, 0x81, 0x03, 0x2B, 0x00, 0xF0, ++ 0x34, 0x81, 0x20, 0x46, 0x05, 0x21, 0xE5, 0xF7, 0x8F, 0xF8, 0x15, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x8F, 0x96, 0xF8, 0x23, 0x20, 0x08, 0xFB, 0x02, 0xB8, ++ 0x6F, 0xF0, 0x77, 0x02, 0xB8, 0xF8, 0x34, 0x11, 0x83, 0xF8, 0x68, 0x20, ++ 0x4A, 0x1C, 0x01, 0x20, 0xC2, 0xF3, 0x0B, 0x02, 0x83, 0xF8, 0x69, 0x00, ++ 0x09, 0x91, 0x03, 0x90, 0xA8, 0xF8, 0x34, 0x21, 0x21, 0xE7, 0x3D, 0x4B, ++ 0x1B, 0x68, 0x1B, 0x78, 0x9A, 0x07, 0xDE, 0xD5, 0xBA, 0xF1, 0x00, 0x0F, ++ 0xDB, 0xD0, 0xD0, 0xE7, 0x00, 0x2A, 0xB8, 0xBF, 0x07, 0xF1, 0x32, 0x01, ++ 0x4F, 0xF0, 0x0A, 0x02, 0xA8, 0xBF, 0x07, 0xF1, 0x30, 0x01, 0x06, 0xF1, ++ 0x1A, 0x00, 0x0C, 0xF0, 0x0B, 0xF9, 0x96, 0xE7, 0xE2, 0x6C, 0xB3, 0xF8, ++ 0x68, 0x10, 0x90, 0x6B, 0x41, 0xF4, 0x80, 0x41, 0xC2, 0x68, 0xA3, 0xF8, ++ 0x68, 0x10, 0x22, 0xF4, 0x7F, 0x73, 0x9A, 0xF8, 0x62, 0x20, 0x08, 0x99, ++ 0x23, 0xF0, 0x03, 0x03, 0x13, 0x43, 0xC3, 0x60, 0x9A, 0xF8, 0x60, 0x30, ++ 0x02, 0x98, 0x0E, 0x18, 0x04, 0x2B, 0x00, 0xF2, 0xD3, 0x81, 0xDF, 0xE8, ++ 0x03, 0xF0, 0x1E, 0x51, 0xBA, 0x1E, 0x85, 0x00, 0x18, 0x22, 0x02, 0x92, ++ 0x21, 0xE7, 0x4F, 0xEA, 0x09, 0x20, 0x40, 0xF0, 0x08, 0x00, 0xF7, 0xF7, ++ 0xFD, 0xFF, 0x01, 0x28, 0x8C, 0xD1, 0x1E, 0x4B, 0x09, 0x99, 0x09, 0xEB, ++ 0x49, 0x09, 0x03, 0xEB, 0xC9, 0x09, 0x02, 0x22, 0xD9, 0xF8, 0x14, 0x00, ++ 0x02, 0x90, 0x05, 0xF0, 0x1D, 0xFB, 0x02, 0x98, 0x05, 0xF0, 0xF8, 0xFA, ++ 0x7C, 0xE7, 0x04, 0x23, 0x84, 0xF8, 0x33, 0x30, 0x84, 0xF8, 0x35, 0x30, ++ 0xDA, 0xE9, 0x12, 0x32, 0x01, 0x33, 0x42, 0xF1, 0x00, 0x02, 0x18, 0x46, ++ 0x11, 0x46, 0x53, 0x46, 0xE3, 0xE9, 0x12, 0x01, 0x06, 0x22, 0x19, 0x46, ++ 0x0A, 0xA8, 0x0C, 0xF0, 0xBD, 0xF8, 0x02, 0x99, 0x08, 0x9A, 0xBD, 0xF8, ++ 0x28, 0x30, 0x53, 0x52, 0xBD, 0xF8, 0x2A, 0x30, 0x9A, 0xF8, 0x61, 0x20, ++ 0x43, 0xEA, 0x82, 0x33, 0x73, 0x80, 0x94, 0xF8, 0x33, 0x30, 0xCB, 0x18, ++ 0x02, 0x93, 0xF0, 0xE6, 0x88, 0x1A, 0x17, 0x00, 0x20, 0x62, 0x17, 0x00, ++ 0x8C, 0xBC, 0x15, 0x00, 0x34, 0x36, 0x17, 0x00, 0xF4, 0xE4, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, 0x08, 0x22, 0x0C, 0x23, ++ 0x84, 0xF8, 0x33, 0x20, 0x84, 0xF8, 0x35, 0x30, 0xDA, 0xE9, 0x12, 0x32, ++ 0x01, 0x33, 0x42, 0xF1, 0x00, 0x02, 0x18, 0x46, 0x11, 0x46, 0x53, 0x46, ++ 0xE3, 0xE9, 0x12, 0x01, 0x06, 0x22, 0x19, 0x46, 0x0A, 0xA8, 0x0C, 0xF0, ++ 0x89, 0xF8, 0xBD, 0xF8, 0x28, 0x20, 0x02, 0x99, 0x42, 0xF4, 0x00, 0x53, ++ 0x03, 0xF4, 0xFE, 0x43, 0x43, 0xEA, 0x12, 0x23, 0x08, 0x9A, 0x53, 0x52, ++ 0x9D, 0xF8, 0x28, 0x30, 0x9A, 0xF8, 0x61, 0x20, 0x43, 0xEA, 0x82, 0x33, ++ 0x43, 0xF4, 0x00, 0x53, 0x73, 0x80, 0xBD, 0xF8, 0x2A, 0x30, 0xB3, 0x80, ++ 0xBD, 0xF8, 0x2C, 0x30, 0xF3, 0x80, 0x94, 0xF8, 0x33, 0x30, 0xCB, 0x18, ++ 0x02, 0x93, 0xAE, 0xE6, 0x10, 0x23, 0x12, 0x21, 0x84, 0xF8, 0x33, 0x10, ++ 0x84, 0xF8, 0x35, 0x30, 0x0F, 0x2A, 0xDA, 0xF8, 0x48, 0x30, 0xDA, 0xF8, ++ 0x4C, 0x20, 0x40, 0xF2, 0x00, 0x81, 0x02, 0x33, 0x42, 0xF1, 0x00, 0x02, ++ 0x18, 0x46, 0x11, 0x46, 0x53, 0x46, 0xE3, 0xE9, 0x12, 0x01, 0x08, 0x22, ++ 0x19, 0x46, 0x0A, 0xA8, 0x0C, 0xF0, 0x50, 0xF8, 0x9A, 0xF8, 0x61, 0x30, ++ 0x33, 0x80, 0xBD, 0xF8, 0x28, 0x30, 0x73, 0x80, 0xBD, 0xF8, 0x2A, 0x30, ++ 0xB3, 0x80, 0xBD, 0xF8, 0x2C, 0x30, 0xF3, 0x80, 0xBD, 0xF8, 0x2E, 0x30, ++ 0x33, 0x81, 0x45, 0xF6, 0x36, 0x43, 0x73, 0x81, 0xB3, 0x81, 0xF3, 0x81, ++ 0x33, 0x82, 0x02, 0x9A, 0x94, 0xF8, 0x33, 0x30, 0x1A, 0x44, 0x02, 0x92, ++ 0x79, 0xE6, 0x08, 0x23, 0x84, 0xF8, 0x33, 0x30, 0x84, 0xF8, 0x35, 0x30, ++ 0xDA, 0xE9, 0x12, 0x32, 0x01, 0x33, 0x42, 0xF1, 0x00, 0x02, 0x18, 0x46, ++ 0x11, 0x46, 0x53, 0x46, 0xE3, 0xE9, 0x12, 0x01, 0x06, 0x22, 0x19, 0x46, ++ 0x0A, 0xA8, 0x0C, 0xF0, 0x21, 0xF8, 0x08, 0x9A, 0xBD, 0xF8, 0x28, 0x30, ++ 0x10, 0x46, 0x02, 0x9A, 0x83, 0x52, 0x9A, 0xF8, 0x61, 0x30, 0x9B, 0x03, ++ 0x43, 0xF4, 0x00, 0x53, 0x73, 0x80, 0xBD, 0xF8, 0x2A, 0x30, 0xB3, 0x80, ++ 0xBD, 0xF8, 0x2C, 0x30, 0xF3, 0x80, 0x94, 0xF8, 0x33, 0x30, 0xD3, 0x18, ++ 0x02, 0x93, 0x4E, 0xE6, 0x31, 0xD0, 0x03, 0x9B, 0x0D, 0xF1, 0x40, 0x0B, ++ 0x00, 0x2B, 0x5D, 0xD1, 0x94, 0xF8, 0x33, 0x70, 0x94, 0xF8, 0x35, 0x30, ++ 0x1F, 0x44, 0xC7, 0xF5, 0x7F, 0x47, 0xEC, 0x37, 0x2F, 0x44, 0xBF, 0xB2, ++ 0x5C, 0xE0, 0x05, 0x99, 0x06, 0x22, 0x04, 0xF1, 0x0C, 0x00, 0x0B, 0xF0, ++ 0xF3, 0xFF, 0x06, 0x22, 0x41, 0x46, 0x04, 0xF1, 0x12, 0x00, 0x0B, 0xF0, ++ 0xED, 0xFF, 0x03, 0x9B, 0x00, 0x22, 0xE2, 0x76, 0x00, 0x2B, 0x78, 0xD0, ++ 0x94, 0xF8, 0x35, 0x10, 0x94, 0xF8, 0x33, 0x30, 0x69, 0x48, 0x0B, 0x44, ++ 0xEB, 0x1A, 0xD0, 0xF8, 0x7C, 0x73, 0x00, 0x92, 0x1A, 0x3B, 0x32, 0x46, ++ 0x0A, 0xF1, 0x50, 0x01, 0x20, 0x46, 0xB8, 0x47, 0x8A, 0xE6, 0x03, 0x9B, ++ 0x94, 0xF8, 0x33, 0x70, 0x00, 0x2B, 0x00, 0xF0, 0x82, 0x80, 0x94, 0xF8, ++ 0x35, 0x30, 0x1F, 0x44, 0xC7, 0xF5, 0x7F, 0x47, 0xF2, 0x37, 0x2F, 0x44, ++ 0xBF, 0xB2, 0x39, 0x1F, 0x4F, 0xF0, 0xFF, 0x33, 0x03, 0x22, 0x30, 0x46, ++ 0xDA, 0xF7, 0x7E, 0xFE, 0xDA, 0xF8, 0x48, 0xC0, 0xDA, 0xF8, 0x4C, 0x00, ++ 0x57, 0x49, 0x4F, 0xEA, 0x1C, 0x43, 0x43, 0xEA, 0x00, 0x43, 0x0D, 0xF1, ++ 0x40, 0x0B, 0x0B, 0x60, 0x42, 0x46, 0x5B, 0x46, 0x48, 0x46, 0xA1, 0xF8, ++ 0x04, 0xC0, 0xF7, 0xF7, 0x45, 0xF8, 0x58, 0x46, 0x10, 0x21, 0xF7, 0xF7, ++ 0x05, 0xFA, 0x9A, 0xF8, 0x60, 0x30, 0x00, 0x2B, 0x40, 0xF0, 0x85, 0x80, ++ 0x94, 0xF8, 0x33, 0x70, 0x94, 0xF8, 0x35, 0x30, 0x1F, 0x44, 0xC7, 0xF5, ++ 0x7F, 0x47, 0xEA, 0x37, 0x2F, 0x44, 0xBF, 0xB2, 0x4F, 0xF0, 0xFF, 0x33, ++ 0x03, 0x22, 0x39, 0x1F, 0x30, 0x46, 0xDA, 0xF7, 0x51, 0xFE, 0x9A, 0xF8, ++ 0x60, 0x30, 0xBA, 0xF8, 0x48, 0x10, 0xBA, 0xF8, 0x4A, 0x20, 0xAD, 0xF8, ++ 0x40, 0x10, 0x8D, 0xF8, 0x42, 0x20, 0x49, 0x46, 0x7B, 0xBB, 0x05, 0x22, ++ 0x0D, 0xF1, 0x43, 0x00, 0x0B, 0xF0, 0x84, 0xFF, 0x58, 0x46, 0x08, 0x21, ++ 0xF7, 0xF7, 0xDA, 0xF9, 0x03, 0x20, 0xDA, 0xF7, 0x71, 0xFE, 0x39, 0x46, ++ 0x02, 0x46, 0x30, 0x46, 0xF7, 0xF7, 0x04, 0xF8, 0x39, 0x46, 0x30, 0x46, ++ 0xF7, 0xF7, 0xFA, 0xF9, 0x20, 0x46, 0x05, 0x21, 0xE4, 0xF7, 0xC6, 0xFE, ++ 0x35, 0xE6, 0x94, 0xF8, 0x35, 0x20, 0x94, 0xF8, 0x33, 0x30, 0x2D, 0x49, ++ 0x13, 0x44, 0xD1, 0xF8, 0x7C, 0x73, 0x03, 0x99, 0x00, 0x91, 0xEB, 0x1A, ++ 0x18, 0x3B, 0x32, 0x46, 0x0A, 0xF1, 0x50, 0x01, 0x20, 0x46, 0xB8, 0x47, ++ 0x10, 0xE6, 0x01, 0x33, 0x42, 0xF1, 0x00, 0x02, 0xFE, 0xE6, 0x0D, 0x22, ++ 0x0D, 0xF1, 0x43, 0x00, 0x0B, 0xF0, 0x54, 0xFF, 0x58, 0x46, 0x10, 0x21, ++ 0xF7, 0xF7, 0xAA, 0xF9, 0xCE, 0xE7, 0x94, 0xF8, 0x35, 0x30, 0x1F, 0x44, ++ 0xC7, 0xF5, 0x7F, 0x47, 0xF4, 0x37, 0x2F, 0x44, 0xBF, 0xB2, 0x39, 0x1F, ++ 0x4F, 0xF0, 0xFF, 0x33, 0x03, 0x22, 0x30, 0x46, 0xDA, 0xF7, 0xFC, 0xFD, ++ 0xDA, 0xF8, 0x48, 0xC0, 0xDA, 0xF8, 0x4C, 0x00, 0x16, 0x49, 0x4F, 0xEA, ++ 0x1C, 0x43, 0x43, 0xEA, 0x00, 0x43, 0x0D, 0xF1, 0x40, 0x0B, 0x0B, 0x60, ++ 0x42, 0x46, 0x5B, 0x46, 0x48, 0x46, 0xA1, 0xF8, 0x04, 0xC0, 0xF6, 0xF7, ++ 0xC3, 0xFF, 0x58, 0x46, 0x10, 0x21, 0xF7, 0xF7, 0x83, 0xF9, 0x9A, 0xF8, ++ 0x60, 0x30, 0x00, 0x2B, 0x3F, 0xF4, 0x20, 0xAF, 0x03, 0x2B, 0xA1, 0xD1, ++ 0x1C, 0xE7, 0x03, 0x2B, 0x9E, 0xD1, 0x77, 0xE7, 0x08, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xBF, 0xF6, 0xDC, 0xAE, 0x06, 0x49, ++ 0x06, 0x48, 0x40, 0xF2, 0x2C, 0x62, 0xF9, 0xF7, 0x6B, 0xFC, 0xD4, 0xE6, ++ 0x88, 0x1A, 0x17, 0x00, 0x70, 0x34, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x64, 0x7D, 0x15, 0x00, 0x08, 0xB5, 0x0C, 0x4B, ++ 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x05, 0xDB, 0x0A, 0x4B, ++ 0x00, 0x20, 0x5B, 0x68, 0x98, 0x47, 0x00, 0x20, 0x08, 0xBD, 0x07, 0x20, ++ 0xF7, 0xF7, 0x10, 0xFE, 0x02, 0x28, 0xF4, 0xD0, 0x05, 0x49, 0x06, 0x48, ++ 0x40, 0xF2, 0x31, 0x12, 0xF9, 0xF7, 0x48, 0xFC, 0xED, 0xE7, 0x00, 0xBF, ++ 0x38, 0x36, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0xC0, 0xBC, 0x15, 0x00, 0x2D, 0xE9, 0xF0, 0x41, 0x0C, 0x46, 0x36, 0x49, ++ 0x60, 0x7C, 0x4F, 0xF4, 0xA4, 0x65, 0x05, 0xFB, 0x00, 0x10, 0x86, 0xB0, ++ 0x90, 0xF8, 0x62, 0x10, 0x00, 0x25, 0x02, 0x29, 0x98, 0x46, 0x8D, 0xF8, ++ 0x0B, 0x50, 0x10, 0xD0, 0x04, 0x25, 0x41, 0x46, 0x02, 0x23, 0x41, 0xF6, ++ 0x05, 0x40, 0xF7, 0xF7, 0x43, 0xFB, 0x05, 0x70, 0x9D, 0xF8, 0x0B, 0x20, ++ 0x42, 0x70, 0xF7, 0xF7, 0x6D, 0xFB, 0x00, 0x20, 0x06, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x81, 0x90, 0xF8, 0x64, 0x10, 0x09, 0xB1, 0x08, 0x25, 0xEA, 0xE7, ++ 0x07, 0x20, 0x01, 0x92, 0xF7, 0xF7, 0xD2, 0xFD, 0x01, 0x9A, 0x00, 0x28, ++ 0xF6, 0xD1, 0xA7, 0x78, 0x20, 0x7C, 0x21, 0x88, 0x1F, 0x4E, 0x8D, 0xF8, ++ 0x0C, 0x70, 0x8D, 0xF8, 0x0D, 0x00, 0xA7, 0x68, 0xE0, 0x68, 0xAD, 0xF8, ++ 0x0E, 0x10, 0x21, 0x79, 0x75, 0x6C, 0xAD, 0xF8, 0x12, 0x00, 0x8D, 0xF8, ++ 0x14, 0x10, 0xAD, 0xF8, 0x10, 0x70, 0x0D, 0xF1, 0x0B, 0x01, 0x03, 0xA8, ++ 0xA8, 0x47, 0x01, 0x9A, 0x05, 0x46, 0x10, 0xBB, 0xF6, 0x6C, 0x60, 0x7C, ++ 0x9D, 0xF8, 0x0B, 0x10, 0xB0, 0x47, 0xEF, 0xF3, 0x10, 0x81, 0x11, 0xF0, ++ 0x01, 0x0F, 0x01, 0x9A, 0x03, 0xD1, 0x72, 0xB6, 0x0E, 0x49, 0x01, 0x20, ++ 0x08, 0x60, 0x0E, 0x48, 0x0E, 0x4F, 0x04, 0x68, 0x79, 0x68, 0x66, 0x1C, ++ 0x41, 0xF0, 0x10, 0x01, 0x06, 0x60, 0x79, 0x60, 0x00, 0x2E, 0xAE, 0xD0, ++ 0x07, 0x49, 0x04, 0x60, 0x09, 0x68, 0x00, 0x2C, 0xA9, 0xD1, 0x00, 0x29, ++ 0xA7, 0xD0, 0x62, 0xB6, 0xA5, 0xE7, 0x01, 0x25, 0xA3, 0xE7, 0x00, 0xBF, ++ 0x18, 0x88, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x1C, 0x9E, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x43, ++ 0x0C, 0x46, 0x85, 0xB0, 0x90, 0x46, 0x4F, 0xF4, 0x80, 0x70, 0x4A, 0x69, ++ 0x4D, 0x49, 0x4E, 0x4F, 0x99, 0x46, 0xF9, 0xF7, 0x8D, 0xF9, 0x94, 0xF8, ++ 0x33, 0x60, 0x4F, 0xF4, 0xA4, 0x65, 0x05, 0xFB, 0x06, 0x75, 0x95, 0xF8, ++ 0x62, 0x10, 0x02, 0x29, 0x11, 0xD0, 0x04, 0x25, 0x42, 0x46, 0x49, 0x46, ++ 0x04, 0x23, 0x41, 0xF6, 0x01, 0x40, 0xF7, 0xF7, 0xC3, 0xFA, 0x05, 0x70, ++ 0x94, 0xF8, 0x33, 0x20, 0x42, 0x70, 0xF7, 0xF7, 0xED, 0xFA, 0x00, 0x20, ++ 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x83, 0x07, 0x20, 0xF7, 0xF7, 0x58, 0xFD, ++ 0xC0, 0xB9, 0x95, 0xF8, 0x64, 0x30, 0xBB, 0xB9, 0x3B, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x13, 0xDB, 0x23, 0x7F, 0x39, 0x49, ++ 0x00, 0x93, 0xD4, 0xE9, 0x05, 0x23, 0x0C, 0x60, 0x0D, 0xF1, 0x0D, 0x00, ++ 0x04, 0xF1, 0x0E, 0x01, 0xFD, 0xF7, 0xAC, 0xF9, 0x05, 0x46, 0x70, 0xB1, ++ 0x01, 0x25, 0xD1, 0xE7, 0x08, 0x25, 0xCF, 0xE7, 0x09, 0x25, 0xCD, 0xE7, ++ 0x2B, 0x6C, 0x00, 0x2B, 0xE8, 0xD0, 0x2F, 0x49, 0x2F, 0x48, 0x56, 0x22, ++ 0xF9, 0xF7, 0x72, 0xFB, 0xE2, 0xE7, 0xE1, 0x89, 0x20, 0x7C, 0xDF, 0xF8, ++ 0xB4, 0x80, 0xFB, 0xF7, 0x9B, 0xFF, 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, ++ 0x06, 0xF2, 0x07, 0xEB, 0x02, 0x09, 0xC9, 0xF8, 0x90, 0x01, 0x94, 0xF9, ++ 0x12, 0x30, 0x03, 0x71, 0xD4, 0xE9, 0x05, 0x31, 0xA9, 0xF8, 0x96, 0x11, ++ 0xA9, 0xF8, 0x94, 0x31, 0x23, 0x7F, 0x89, 0xF8, 0xC5, 0x31, 0x04, 0x2B, ++ 0x08, 0xBF, 0x03, 0x23, 0x89, 0xF8, 0xC4, 0x31, 0x89, 0xF8, 0xC6, 0x51, ++ 0xD8, 0xF8, 0x4C, 0x30, 0x94, 0xF8, 0x33, 0x00, 0x9D, 0xF8, 0x0D, 0x10, ++ 0x15, 0x46, 0x98, 0x47, 0x23, 0x7C, 0xA3, 0xB1, 0x00, 0xF0, 0x8C, 0xFA, ++ 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x06, 0x73, 0x78, 0x19, 0xD3, 0xF8, ++ 0x90, 0x31, 0xD8, 0xF8, 0x40, 0x43, 0x1B, 0x79, 0x8D, 0xF8, 0x0E, 0x30, ++ 0x0D, 0xF1, 0x0F, 0x02, 0x0D, 0xF1, 0x0E, 0x01, 0xA0, 0x47, 0x01, 0x20, ++ 0x92, 0xE7, 0x05, 0xF5, 0xCE, 0x70, 0x38, 0x44, 0x01, 0x21, 0xFC, 0xF7, ++ 0x45, 0xF9, 0x10, 0xF0, 0x0F, 0x00, 0x1A, 0xBF, 0xB0, 0xFA, 0x80, 0xF0, ++ 0xC0, 0xF1, 0x1F, 0x03, 0x01, 0x23, 0x89, 0xF8, 0xC1, 0x31, 0xD9, 0xE7, ++ 0xEC, 0xBC, 0x15, 0x00, 0x18, 0x88, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x94, 0xBA, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0xA0, 0xA2, 0x15, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0xF8, 0xB5, 0x4F, 0x88, 0x0D, 0x48, 0x0C, 0x46, ++ 0x16, 0x46, 0x04, 0x31, 0x3A, 0x46, 0x1D, 0x46, 0x0B, 0xF0, 0xAE, 0xFD, ++ 0xDF, 0xF8, 0x28, 0xC0, 0x32, 0x46, 0x29, 0x46, 0x02, 0x23, 0x41, 0xF6, ++ 0x09, 0x40, 0xAC, 0xF8, 0x00, 0x70, 0xF7, 0xF7, 0x1B, 0xFA, 0x01, 0x22, ++ 0x02, 0x70, 0x22, 0x78, 0x42, 0x70, 0xF7, 0xF7, 0x45, 0xFA, 0x00, 0x20, ++ 0xF8, 0xBD, 0x00, 0xBF, 0x14, 0x2A, 0x17, 0x00, 0x14, 0x2C, 0x17, 0x00, ++ 0x08, 0xB5, 0x15, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0x0F, 0xDB, 0x07, 0x20, 0xF7, 0xF7, 0xA6, 0xFC, 0x01, 0x28, 0x06, 0xD0, ++ 0x07, 0x20, 0xF7, 0xF7, 0xA1, 0xFC, 0x03, 0x28, 0x01, 0xD0, 0x00, 0x20, ++ 0x08, 0xBD, 0x00, 0xF0, 0x01, 0xFA, 0x00, 0x20, 0x08, 0xBD, 0x07, 0x20, ++ 0xF7, 0xF7, 0x96, 0xFC, 0x01, 0x28, 0xEA, 0xD0, 0x07, 0x20, 0xF7, 0xF7, ++ 0x91, 0xFC, 0x00, 0x28, 0xE5, 0xD0, 0x07, 0x20, 0xF7, 0xF7, 0x8C, 0xFC, ++ 0x03, 0x28, 0xE0, 0xD0, 0x03, 0x49, 0x04, 0x48, 0xC2, 0x22, 0xF9, 0xF7, ++ 0xC5, 0xFA, 0xDA, 0xE7, 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0xFC, 0xBC, 0x15, 0x00, 0x08, 0xB5, 0x0C, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0x03, 0xDB, 0x00, 0xF0, 0xDB, 0xF9, 0x00, 0x20, ++ 0x08, 0xBD, 0x07, 0x20, 0xF7, 0xF7, 0x70, 0xFC, 0x01, 0x28, 0xF6, 0xD0, ++ 0x05, 0x49, 0x06, 0x48, 0xE6, 0x22, 0xF9, 0xF7, 0xA9, 0xFA, 0x00, 0xF0, ++ 0xCD, 0xF9, 0x00, 0x20, 0x08, 0xBD, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x84, 0xBD, 0x15, 0x00, 0x08, 0xB5, 0x0C, 0x4B, ++ 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x03, 0xDB, 0x00, 0xF0, ++ 0xBB, 0xF9, 0x00, 0x20, 0x08, 0xBD, 0x07, 0x20, 0xF7, 0xF7, 0x50, 0xFC, ++ 0x03, 0x28, 0xF6, 0xD0, 0x05, 0x49, 0x06, 0x48, 0x40, 0xF2, 0x4B, 0x12, ++ 0xF9, 0xF7, 0x88, 0xFA, 0x00, 0xF0, 0xAC, 0xF9, 0x00, 0x20, 0x08, 0xBD, ++ 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0xB4, 0xBD, 0x15, 0x00, ++ 0x08, 0xB5, 0x11, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0x06, 0xDB, 0x07, 0x20, 0xF7, 0xF7, 0x34, 0xFC, 0x03, 0x28, 0x12, 0xD0, ++ 0x00, 0x20, 0x08, 0xBD, 0x07, 0x20, 0xF7, 0xF7, 0x2D, 0xFC, 0x03, 0x28, ++ 0xF3, 0xD0, 0x07, 0x20, 0xF7, 0xF7, 0x28, 0xFC, 0x00, 0x28, 0xEE, 0xD0, ++ 0x06, 0x49, 0x07, 0x48, 0x40, 0xF2, 0x65, 0x12, 0xF9, 0xF7, 0x60, 0xFA, ++ 0xE7, 0xE7, 0x00, 0xF0, 0x83, 0xF9, 0x00, 0x20, 0x08, 0xBD, 0x00, 0xBF, ++ 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0xDC, 0xBD, 0x15, 0x00, ++ 0xF8, 0xB5, 0x0C, 0x46, 0x4F, 0xF4, 0x80, 0x70, 0x13, 0x49, 0x16, 0x46, ++ 0x1D, 0x46, 0xF9, 0xF7, 0x21, 0xF8, 0x24, 0x78, 0x11, 0x4B, 0x4F, 0xF4, ++ 0xA4, 0x62, 0x02, 0xFB, 0x04, 0x34, 0x94, 0xF8, 0x62, 0x70, 0x02, 0x2F, ++ 0x02, 0xD1, 0x94, 0xF8, 0x64, 0x30, 0x3B, 0xB9, 0x32, 0x46, 0x29, 0x46, ++ 0x41, 0xF6, 0x03, 0x40, 0xF7, 0xF7, 0xBE, 0xF9, 0x00, 0x20, 0xF8, 0xBD, ++ 0x07, 0x20, 0xF7, 0xF7, 0xF3, 0xFB, 0x05, 0x46, 0x28, 0xB9, 0x06, 0x4B, ++ 0x20, 0x46, 0x9B, 0x68, 0x98, 0x47, 0x28, 0x46, 0xF8, 0xBD, 0x38, 0x46, ++ 0xF8, 0xBD, 0x00, 0xBF, 0x30, 0xBE, 0x15, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x70, 0xB5, 0x0C, 0x46, 0x21, 0x49, 0x20, 0x78, ++ 0x4F, 0xF4, 0xA4, 0x65, 0x05, 0xFB, 0x00, 0x10, 0x82, 0xB0, 0x90, 0xF8, ++ 0x62, 0x50, 0x02, 0x2D, 0x19, 0x46, 0x06, 0xD0, 0x41, 0xF6, 0x07, 0x40, ++ 0xF7, 0xF7, 0x96, 0xF9, 0x00, 0x20, 0x02, 0xB0, 0x70, 0xBD, 0x90, 0xF8, ++ 0x64, 0x30, 0x00, 0x2B, 0xF4, 0xD1, 0x07, 0x20, 0xCD, 0xE9, 0x00, 0x21, ++ 0xF7, 0xF7, 0xC4, 0xFB, 0xDD, 0xE9, 0x00, 0x21, 0x00, 0x28, 0xEB, 0xD1, ++ 0x12, 0x4B, 0x20, 0x78, 0x5B, 0x6D, 0x98, 0x47, 0xEF, 0xF3, 0x10, 0x83, ++ 0x13, 0xF0, 0x01, 0x0F, 0xDD, 0xE9, 0x00, 0x21, 0x03, 0xD1, 0x72, 0xB6, ++ 0x0D, 0x4B, 0x01, 0x20, 0x18, 0x60, 0x0D, 0x48, 0x0D, 0x4E, 0x04, 0x68, ++ 0x73, 0x68, 0x65, 0x1C, 0x23, 0xF0, 0x10, 0x03, 0x05, 0x60, 0x73, 0x60, ++ 0x00, 0x2D, 0xD1, 0xD0, 0x06, 0x4B, 0x04, 0x60, 0x1B, 0x68, 0x00, 0x2C, ++ 0xCC, 0xD1, 0x00, 0x2B, 0xCA, 0xD0, 0x62, 0xB6, 0xC8, 0xE7, 0x00, 0xBF, ++ 0x18, 0x88, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x1C, 0x9E, 0x17, 0x00, 0x10, 0xB5, 0x22, 0x4C, ++ 0x23, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x28, 0xDB, 0x07, 0x20, ++ 0xF7, 0xF7, 0x88, 0xFB, 0x01, 0x28, 0x13, 0xD1, 0x23, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0x03, 0xDB, 0x00, 0xF0, 0x9B, 0xF9, 0x00, 0x20, ++ 0x10, 0xBD, 0x19, 0x4B, 0x5B, 0x68, 0x00, 0x2B, 0xF7, 0xD0, 0x18, 0x49, ++ 0x18, 0x48, 0x40, 0xF2, 0x0B, 0x12, 0xF9, 0xF7, 0xB3, 0xF9, 0xF0, 0xE7, ++ 0x07, 0x20, 0xF7, 0xF7, 0x6F, 0xFB, 0x03, 0x28, 0xED, 0xD1, 0x07, 0x22, ++ 0x0C, 0x21, 0x41, 0xF6, 0x03, 0x40, 0xF7, 0xF7, 0x2D, 0xF9, 0x00, 0x21, ++ 0x07, 0x20, 0xF7, 0xF7, 0xBB, 0xFA, 0xE2, 0xE7, 0x07, 0x20, 0xF7, 0xF7, ++ 0x5F, 0xFB, 0x01, 0x28, 0xD1, 0xD0, 0x07, 0x20, 0xF7, 0xF7, 0x5A, 0xFB, ++ 0x00, 0x28, 0xCC, 0xD0, 0x07, 0x20, 0xF7, 0xF7, 0x55, 0xFB, 0x03, 0x28, ++ 0xC7, 0xD0, 0x05, 0x49, 0x06, 0x48, 0x40, 0xF2, 0x03, 0x12, 0xF9, 0xF7, ++ 0x8D, 0xF9, 0xC0, 0xE7, 0x38, 0x36, 0x17, 0x00, 0x94, 0xBA, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x3C, 0xBE, 0x15, 0x00, 0xFC, 0xBC, 0x15, 0x00, ++ 0x08, 0xB5, 0x0C, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0x04, 0xDB, 0xBD, 0xE8, 0x08, 0x40, 0x09, 0x48, 0xF7, 0xF7, 0x1E, 0xBD, ++ 0x08, 0x4B, 0x5B, 0x68, 0x00, 0x2B, 0xF6, 0xD0, 0x07, 0x48, 0x08, 0x49, ++ 0x2D, 0x22, 0xF9, 0xF7, 0x6D, 0xF9, 0xBD, 0xE8, 0x08, 0x40, 0x02, 0x48, ++ 0xF7, 0xF7, 0x10, 0xBD, 0x38, 0x36, 0x17, 0x00, 0x98, 0xBA, 0x17, 0x00, ++ 0x94, 0xBA, 0x17, 0x00, 0x3C, 0xBE, 0x15, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x10, 0xB5, 0x06, 0x4C, 0x00, 0x21, 0x20, 0x46, 0x10, 0x22, 0xD4, 0xF7, ++ 0x6F, 0xFC, 0x00, 0x21, 0x21, 0x73, 0x07, 0x20, 0xBD, 0xE8, 0x10, 0x40, ++ 0xF7, 0xF7, 0x68, 0xBA, 0x94, 0xBA, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x47, ++ 0xDF, 0xF8, 0xD8, 0x80, 0x05, 0x46, 0x04, 0x23, 0x07, 0x22, 0x0C, 0x21, ++ 0x41, 0xF6, 0x01, 0x40, 0xD8, 0xF8, 0x00, 0x60, 0xF7, 0xF7, 0x5E, 0xF8, ++ 0x04, 0x46, 0x95, 0xB1, 0x96, 0xF8, 0x33, 0x30, 0x63, 0x70, 0x20, 0x46, ++ 0x25, 0x70, 0xF7, 0xF7, 0x85, 0xF8, 0xA6, 0xF1, 0x0C, 0x00, 0xF7, 0xF7, ++ 0xCD, 0xF8, 0x00, 0x21, 0xC8, 0xF8, 0x00, 0x10, 0x07, 0x20, 0xBD, 0xE8, ++ 0xF0, 0x47, 0xF7, 0xF7, 0x43, 0xBA, 0x04, 0x23, 0x29, 0x46, 0x07, 0x22, ++ 0x1E, 0x20, 0x96, 0xF8, 0x33, 0x70, 0xF7, 0xF7, 0x41, 0xF8, 0x21, 0x4A, ++ 0x4F, 0xF4, 0xA4, 0x69, 0x09, 0xFB, 0x07, 0x29, 0x4F, 0xF0, 0x01, 0x0A, ++ 0x80, 0xF8, 0x02, 0xA0, 0x99, 0xF8, 0x63, 0x20, 0xC2, 0x70, 0xF7, 0xF7, ++ 0x63, 0xF8, 0xF1, 0x6A, 0x32, 0x8E, 0xD9, 0xF8, 0x40, 0x30, 0xC9, 0xF8, ++ 0xB0, 0x14, 0xA9, 0xF8, 0xE0, 0x20, 0x89, 0xF8, 0xDE, 0x50, 0x1B, 0x7E, ++ 0xA3, 0x70, 0x96, 0xF8, 0x33, 0x30, 0xDF, 0xF8, 0x54, 0xC0, 0x0A, 0x33, ++ 0xE3, 0x70, 0x96, 0xE8, 0x0F, 0x00, 0x4F, 0xF4, 0x1E, 0x7E, 0x0A, 0x37, ++ 0x0E, 0xFB, 0x07, 0xC7, 0x07, 0xF1, 0xB8, 0x0C, 0xAC, 0xE8, 0x07, 0x00, ++ 0x02, 0x22, 0x87, 0xF8, 0x30, 0x20, 0x8C, 0xF8, 0x00, 0x30, 0x38, 0x46, ++ 0xFB, 0xF7, 0xA0, 0xFF, 0x97, 0xF8, 0x56, 0x31, 0xA7, 0xF8, 0x26, 0xA0, ++ 0x43, 0xF0, 0x10, 0x03, 0x87, 0xF8, 0x56, 0x31, 0x96, 0xF8, 0x33, 0x30, ++ 0x03, 0xF1, 0x0A, 0x02, 0x87, 0xF8, 0x23, 0x20, 0xA4, 0xE7, 0x00, 0xBF, ++ 0x18, 0x88, 0x17, 0x00, 0x94, 0xBA, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, ++ 0x10, 0xB5, 0x0C, 0x48, 0xF7, 0xF7, 0xC6, 0xFC, 0x0B, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x04, 0x46, 0x05, 0xDB, 0x04, 0xF1, ++ 0x0C, 0x00, 0xBD, 0xE8, 0x10, 0x40, 0xF7, 0xF7, 0x17, 0xB8, 0x00, 0x28, ++ 0xF7, 0xD1, 0x05, 0x49, 0x05, 0x48, 0xCB, 0x22, 0xF9, 0xF7, 0xC2, 0xF8, ++ 0xF1, 0xE7, 0x00, 0xBF, 0x98, 0xBA, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xA8, 0xAB, 0x15, 0x00, 0x2D, 0xE9, 0xF8, 0x4F, ++ 0x44, 0x4B, 0xDF, 0xF8, 0x1C, 0xB1, 0x1C, 0x68, 0x07, 0x22, 0x08, 0x23, ++ 0x00, 0x21, 0x18, 0x20, 0x94, 0xF8, 0x33, 0x90, 0xF6, 0xF7, 0xC8, 0xFF, ++ 0x08, 0x23, 0x07, 0x22, 0x00, 0x21, 0x06, 0x46, 0x16, 0x20, 0xF6, 0xF7, ++ 0xC1, 0xFF, 0x04, 0x23, 0x07, 0x22, 0x00, 0x21, 0x05, 0x46, 0x14, 0x20, ++ 0xF6, 0xF7, 0xBA, 0xFF, 0x02, 0x23, 0x07, 0x22, 0x05, 0x21, 0x80, 0x46, ++ 0x41, 0xF2, 0x17, 0x40, 0xF6, 0xF7, 0xB2, 0xFF, 0x4F, 0xF4, 0xA4, 0x6A, ++ 0x0A, 0xFB, 0x09, 0xBA, 0x07, 0x46, 0xFF, 0xF7, 0x0B, 0xFF, 0x9A, 0xF8, ++ 0xC0, 0x34, 0x00, 0x2B, 0x49, 0xD0, 0x2F, 0x4A, 0x13, 0x68, 0x23, 0xF0, ++ 0x04, 0x03, 0x13, 0x60, 0xDA, 0xF8, 0x04, 0x30, 0x43, 0xF0, 0x20, 0x03, ++ 0xCA, 0xF8, 0x04, 0x30, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x09, 0xB9, ++ 0xA6, 0xF1, 0x0C, 0x01, 0xD9, 0xF8, 0x5C, 0x00, 0xB9, 0xF8, 0x60, 0x30, ++ 0xB3, 0x80, 0x30, 0x60, 0x94, 0xF8, 0x33, 0x30, 0xB3, 0x71, 0x23, 0x48, ++ 0xF7, 0xF7, 0x18, 0xFC, 0x23, 0x7C, 0x6B, 0x71, 0x01, 0x21, 0x20, 0x46, ++ 0xFB, 0xF7, 0x80, 0xFE, 0x28, 0x60, 0x94, 0xF8, 0x33, 0x30, 0x2B, 0x71, ++ 0xA5, 0xF1, 0x0C, 0x01, 0x1B, 0x48, 0xF7, 0xF7, 0x09, 0xFC, 0x23, 0x8D, ++ 0xA8, 0xF8, 0x00, 0x30, 0x94, 0xF8, 0x33, 0x30, 0x88, 0xF8, 0x02, 0x30, ++ 0xA8, 0xF1, 0x0C, 0x01, 0x01, 0x25, 0x15, 0x48, 0xF7, 0xF7, 0xFC, 0xFB, ++ 0x3D, 0x70, 0x94, 0xF8, 0x33, 0x30, 0x12, 0x48, 0x7B, 0x70, 0xA7, 0xF1, ++ 0x0C, 0x01, 0xF7, 0xF7, 0xF3, 0xFB, 0xFF, 0xF7, 0x6B, 0xFF, 0x29, 0x46, ++ 0x07, 0x20, 0xBD, 0xE8, 0xF8, 0x4F, 0xF7, 0xF7, 0x57, 0xB9, 0x02, 0x23, ++ 0x07, 0x22, 0x05, 0x21, 0x41, 0xF2, 0x19, 0x40, 0xF6, 0xF7, 0x56, 0xFF, ++ 0x01, 0x23, 0x03, 0x70, 0x9A, 0xF8, 0x63, 0x30, 0x43, 0x70, 0x03, 0x4B, ++ 0x01, 0x46, 0x0C, 0x39, 0x18, 0x1D, 0xF7, 0xF7, 0xD9, 0xFB, 0xAD, 0xE7, ++ 0x94, 0xBA, 0x17, 0x00, 0x4C, 0x00, 0x32, 0x40, 0x98, 0xBA, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0x38, 0xB5, 0x0E, 0x4C, 0x0C, 0x23, 0x07, 0x22, ++ 0x00, 0x21, 0x3F, 0x20, 0x24, 0x68, 0xF6, 0xF7, 0x39, 0xFF, 0xA1, 0x8C, ++ 0xE2, 0x8C, 0x25, 0x6A, 0x05, 0x60, 0x81, 0x80, 0xC2, 0x80, 0x94, 0xF8, ++ 0x32, 0x20, 0x02, 0x72, 0x94, 0xF8, 0x33, 0x20, 0x42, 0x72, 0xF6, 0xF7, ++ 0x5B, 0xFF, 0xBD, 0xE8, 0x38, 0x40, 0x02, 0x21, 0x07, 0x20, 0xF7, 0xF7, ++ 0x1F, 0xB9, 0x00, 0xBF, 0x94, 0xBA, 0x17, 0x00, 0xF8, 0xB5, 0x07, 0x22, ++ 0x04, 0x46, 0x02, 0x23, 0x05, 0x21, 0x41, 0xF2, 0x19, 0x40, 0xF6, 0xF7, ++ 0x19, 0xFF, 0x02, 0x23, 0x06, 0x46, 0x07, 0x22, 0x05, 0x21, 0x41, 0xF2, ++ 0x17, 0x40, 0xF6, 0xF7, 0x11, 0xFF, 0x00, 0x27, 0x05, 0x46, 0xFF, 0xF7, ++ 0x6D, 0xFE, 0x37, 0x70, 0x94, 0xF8, 0x63, 0x30, 0x73, 0x70, 0x1D, 0x48, ++ 0xA6, 0xF1, 0x0C, 0x01, 0xF7, 0xF7, 0x92, 0xFB, 0x94, 0xF8, 0x64, 0x30, ++ 0x0B, 0xBB, 0x23, 0x6C, 0x6B, 0xB1, 0x01, 0x23, 0x00, 0x21, 0x07, 0x22, ++ 0x39, 0x20, 0xF6, 0xF7, 0xF9, 0xFE, 0x01, 0x46, 0x94, 0xF8, 0x63, 0x30, ++ 0x01, 0xF8, 0x0C, 0x39, 0x12, 0x48, 0xF7, 0xF7, 0x7F, 0xFB, 0x00, 0x23, ++ 0x2B, 0x70, 0x94, 0xF8, 0x63, 0x30, 0x0F, 0x48, 0x6B, 0x70, 0xA5, 0xF1, ++ 0x0C, 0x01, 0xF7, 0xF7, 0x75, 0xFB, 0xFF, 0xF7, 0xED, 0xFE, 0xBD, 0xE8, ++ 0xF8, 0x40, 0x03, 0x21, 0x07, 0x20, 0xF7, 0xF7, 0xD9, 0xB8, 0x39, 0x46, ++ 0x04, 0x23, 0x07, 0x22, 0x1E, 0x20, 0xF6, 0xF7, 0xD9, 0xFE, 0x87, 0x70, ++ 0x94, 0xF8, 0x63, 0x30, 0xC3, 0x70, 0xA0, 0xF1, 0x0C, 0x01, 0x02, 0x48, ++ 0xF7, 0xF7, 0x5E, 0xFB, 0xCD, 0xE7, 0x00, 0xBF, 0x98, 0xBA, 0x17, 0x00, ++ 0x15, 0x4A, 0x03, 0x7F, 0x4F, 0xF4, 0xA4, 0x61, 0x01, 0xFB, 0x03, 0x23, ++ 0x93, 0xF8, 0x62, 0x30, 0x02, 0x2B, 0x13, 0xD1, 0x43, 0x7F, 0x0D, 0x2B, ++ 0x10, 0xD8, 0x82, 0x88, 0x2A, 0xB9, 0x82, 0x6C, 0xB2, 0xF8, 0x68, 0x20, ++ 0xB2, 0xF5, 0x12, 0x7F, 0x08, 0xD0, 0x0C, 0x4A, 0x4F, 0xF4, 0x1E, 0x71, ++ 0x01, 0xFB, 0x03, 0x22, 0x92, 0xF8, 0x24, 0x30, 0x01, 0x2B, 0x02, 0xD0, ++ 0x01, 0x23, 0x18, 0x46, 0x70, 0x47, 0x92, 0xF8, 0x32, 0x20, 0x12, 0xF0, ++ 0x03, 0x02, 0xF8, 0xD1, 0xC1, 0x8B, 0x41, 0xF4, 0x80, 0x51, 0x13, 0x46, ++ 0xC1, 0x83, 0xF2, 0xE7, 0x18, 0x88, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, ++ 0xC3, 0x8B, 0xDB, 0x04, 0x00, 0xD4, 0x70, 0x47, 0x10, 0xB5, 0x0C, 0x46, ++ 0xC2, 0x7E, 0x15, 0x49, 0x94, 0xF8, 0x2E, 0x31, 0x8A, 0x5C, 0x13, 0x42, ++ 0x1A, 0xD0, 0x94, 0xF8, 0x31, 0x20, 0x11, 0x07, 0x1A, 0xD4, 0x42, 0xF0, ++ 0x08, 0x02, 0x0F, 0x2B, 0x84, 0xF8, 0x31, 0x20, 0x14, 0xD1, 0x05, 0x22, ++ 0x04, 0x23, 0x00, 0x21, 0x41, 0x20, 0xF6, 0xF7, 0x7F, 0xFE, 0x22, 0x8C, ++ 0x02, 0x80, 0x94, 0xF8, 0x22, 0x20, 0xC2, 0x70, 0x01, 0x22, 0x82, 0x70, ++ 0xBD, 0xE8, 0x10, 0x40, 0xF6, 0xF7, 0xA4, 0xBE, 0x94, 0xF8, 0x31, 0x30, ++ 0x9A, 0x07, 0x00, 0xD5, 0x10, 0xBD, 0x43, 0xF0, 0x02, 0x03, 0x84, 0xF8, ++ 0x31, 0x30, 0xE4, 0xE7, 0xA4, 0xB2, 0x15, 0x00, 0x2D, 0xE9, 0xF0, 0x47, ++ 0x90, 0xF8, 0x62, 0x70, 0x02, 0x2F, 0x91, 0x46, 0x5A, 0xD1, 0x91, 0xF8, ++ 0x32, 0x20, 0x0E, 0x46, 0x00, 0x2A, 0x55, 0xD0, 0x12, 0xF0, 0x01, 0x08, ++ 0x91, 0xF8, 0x31, 0x30, 0x04, 0xBF, 0x08, 0x27, 0x4F, 0xF0, 0x04, 0x08, ++ 0x1F, 0x42, 0x78, 0xD0, 0xD1, 0xF8, 0xFC, 0x41, 0x00, 0x2C, 0x68, 0xD0, ++ 0xA2, 0xF1, 0x02, 0x02, 0xB2, 0xFA, 0x82, 0xF2, 0x91, 0xF8, 0x2E, 0x11, ++ 0x3C, 0x4D, 0x52, 0x09, 0x4F, 0xF0, 0x00, 0x0A, 0x04, 0xE0, 0x23, 0x68, ++ 0xA2, 0x46, 0x00, 0x2B, 0x59, 0xD0, 0x1C, 0x46, 0xE3, 0x7E, 0xEB, 0x5C, ++ 0x19, 0x42, 0x0C, 0xBF, 0x01, 0x23, 0x00, 0x23, 0x93, 0x42, 0xF2, 0xD0, ++ 0x51, 0x46, 0x22, 0x46, 0x06, 0xF5, 0xFE, 0x70, 0xF7, 0xF7, 0xC8, 0xFB, ++ 0x96, 0xF8, 0x32, 0x10, 0x11, 0xF0, 0x08, 0x0F, 0x0C, 0xBF, 0x03, 0x23, ++ 0x04, 0x23, 0xE3, 0x76, 0xBA, 0xF1, 0x00, 0x0F, 0x52, 0xD0, 0xDA, 0xF8, ++ 0x00, 0x30, 0x0B, 0xB3, 0xA1, 0xF1, 0x02, 0x01, 0xB1, 0xFA, 0x81, 0xF1, ++ 0x96, 0xF8, 0x2E, 0x01, 0x49, 0x09, 0x01, 0xE0, 0x1B, 0x68, 0xBB, 0xB1, ++ 0xDA, 0x7E, 0xAA, 0x5C, 0x10, 0x42, 0x0C, 0xBF, 0x01, 0x22, 0x00, 0x22, ++ 0x8A, 0x42, 0xF5, 0xD0, 0xA2, 0x6C, 0xB2, 0xF8, 0x68, 0x30, 0x43, 0xF4, ++ 0x00, 0x53, 0xA2, 0xF8, 0x68, 0x30, 0x20, 0x46, 0xBD, 0xE8, 0xF0, 0x87, ++ 0x00, 0x24, 0xC9, 0xF8, 0x00, 0x40, 0x20, 0x46, 0xBD, 0xE8, 0xF0, 0x87, ++ 0x96, 0xF8, 0x31, 0x10, 0x21, 0xEA, 0x07, 0x07, 0x17, 0xEA, 0x08, 0x01, ++ 0x86, 0xF8, 0x31, 0x70, 0x07, 0xEA, 0x08, 0x05, 0xE4, 0xD1, 0x04, 0x23, ++ 0x05, 0x22, 0x41, 0x20, 0xF6, 0xF7, 0xF0, 0xFD, 0x32, 0x8C, 0x02, 0x80, ++ 0x96, 0xF8, 0x22, 0x20, 0xC2, 0x70, 0x85, 0x70, 0xF6, 0xF7, 0x18, 0xFE, ++ 0x20, 0x46, 0xBD, 0xE8, 0xF0, 0x87, 0x0C, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0x05, 0xDA, 0x0A, 0x49, 0x0A, 0x48, 0x40, 0xF2, ++ 0x91, 0x12, 0xF8, 0xF7, 0xD3, 0xFE, 0x01, 0x23, 0x00, 0x24, 0xC9, 0xF8, ++ 0x00, 0x30, 0x20, 0x46, 0xBD, 0xE8, 0xF0, 0x87, 0xD6, 0xF8, 0xFC, 0x31, ++ 0xAB, 0xE7, 0x00, 0xBF, 0xA4, 0xB2, 0x15, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x64, 0x7D, 0x15, 0x00, 0x38, 0xB5, 0x90, 0xF8, ++ 0x62, 0x30, 0x02, 0x2B, 0x14, 0xD1, 0x13, 0x4C, 0x13, 0x4B, 0x4F, 0xF4, ++ 0x1E, 0x72, 0x02, 0xFB, 0x01, 0x44, 0x21, 0x46, 0xD3, 0xF8, 0x20, 0x33, ++ 0x00, 0x22, 0x98, 0x47, 0x94, 0xF8, 0x31, 0x10, 0x11, 0xF0, 0x0A, 0x0F, ++ 0x04, 0xD0, 0x01, 0xF0, 0xF5, 0x05, 0x84, 0xF8, 0x31, 0x50, 0x05, 0xB1, ++ 0x38, 0xBD, 0x29, 0x46, 0x04, 0x23, 0x05, 0x22, 0x41, 0x20, 0xF6, 0xF7, ++ 0xA5, 0xFD, 0x94, 0xF8, 0x22, 0x20, 0x21, 0x8C, 0xC2, 0x70, 0x85, 0x70, ++ 0xBD, 0xE8, 0x38, 0x40, 0x01, 0x80, 0xF6, 0xF7, 0xCB, 0xBD, 0x00, 0xBF, ++ 0x68, 0x65, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x03, 0x6C, 0x2D, 0xE9, ++ 0xF0, 0x41, 0x04, 0x46, 0x88, 0x46, 0x00, 0x2B, 0x6C, 0xD0, 0x3A, 0x4A, ++ 0x1B, 0x79, 0x12, 0x68, 0xB2, 0xF9, 0x00, 0x20, 0x00, 0x2A, 0x53, 0xDB, ++ 0x94, 0xF8, 0xC0, 0x24, 0x13, 0x43, 0x14, 0xBF, 0x01, 0x20, 0x00, 0x20, ++ 0x4F, 0xF4, 0xC0, 0x71, 0xE4, 0xF7, 0x4C, 0xF8, 0x05, 0x46, 0x00, 0x28, ++ 0x56, 0xD0, 0x01, 0x46, 0x20, 0x46, 0xF6, 0xF7, 0x43, 0xF9, 0xAE, 0x6C, ++ 0x00, 0x27, 0x6F, 0xF0, 0x3F, 0x03, 0x41, 0x46, 0x86, 0xF8, 0x68, 0x30, ++ 0x86, 0xF8, 0x69, 0x70, 0x86, 0xF8, 0x6A, 0x70, 0x86, 0xF8, 0x6B, 0x70, ++ 0x06, 0xF1, 0x6C, 0x00, 0x06, 0x22, 0x0B, 0xF0, 0xED, 0xF8, 0x26, 0x4A, ++ 0xE0, 0x6D, 0xB2, 0xF8, 0xFC, 0x31, 0xB4, 0xF8, 0x60, 0x10, 0xB4, 0xF8, ++ 0x60, 0xC0, 0xC6, 0xF8, 0x72, 0x00, 0x01, 0x33, 0x9B, 0xB2, 0xE0, 0x6D, ++ 0xA6, 0xF8, 0x76, 0x10, 0x19, 0x01, 0xB0, 0x67, 0xA6, 0xF8, 0x7C, 0xC0, ++ 0xA2, 0xF8, 0xFC, 0x31, 0xA6, 0xF8, 0x7E, 0x10, 0xC5, 0xE9, 0x15, 0x74, ++ 0x94, 0xF8, 0x63, 0x30, 0x2B, 0x77, 0xFF, 0x23, 0x6B, 0x77, 0x06, 0xF1, ++ 0x80, 0x00, 0x07, 0x21, 0xF9, 0xF7, 0xCE, 0xFD, 0xE9, 0x6C, 0x4B, 0x6A, ++ 0x17, 0x33, 0x1A, 0x18, 0x00, 0xF1, 0x1C, 0x03, 0xC1, 0xE9, 0x0A, 0x23, ++ 0x28, 0x46, 0x05, 0x21, 0xBD, 0xE8, 0xF0, 0x41, 0xE4, 0xF7, 0x12, 0xB8, ++ 0x02, 0x2B, 0xA9, 0xD1, 0x0D, 0x49, 0x0E, 0x48, 0x4F, 0xF4, 0x09, 0x72, ++ 0xF8, 0xF7, 0x0E, 0xFE, 0x01, 0x20, 0x4F, 0xF4, 0xC0, 0x71, 0xE3, 0xF7, ++ 0xF5, 0xFF, 0x05, 0x46, 0x00, 0x28, 0xA8, 0xD1, 0xBD, 0xE8, 0xF0, 0x81, ++ 0x03, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xEF, 0xDA, ++ 0xE8, 0xE7, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, 0x20, 0x62, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xFC, 0x90, 0x15, 0x00, 0xF8, 0xB5, 0x14, 0x4A, ++ 0x14, 0x4D, 0x41, 0xF2, 0x0A, 0x00, 0x41, 0xF2, 0x08, 0x07, 0x00, 0x26, ++ 0x16, 0x52, 0x0C, 0x46, 0xD3, 0x53, 0x41, 0xF2, 0x0C, 0x06, 0xD1, 0xF8, ++ 0x64, 0x11, 0xD4, 0xF8, 0x60, 0x01, 0x90, 0x51, 0x0B, 0x2B, 0x14, 0x60, ++ 0xA9, 0x80, 0x0D, 0xD0, 0x19, 0x46, 0x04, 0x22, 0x02, 0x23, 0x41, 0xF2, ++ 0x09, 0x00, 0xF6, 0xF7, 0xF5, 0xFC, 0x01, 0x22, 0x42, 0x70, 0x94, 0xF8, ++ 0x6E, 0x21, 0x02, 0x70, 0xF6, 0xF7, 0x1E, 0xFD, 0x04, 0x4B, 0xD3, 0xF8, ++ 0xF4, 0x32, 0x98, 0x47, 0x01, 0x20, 0xF8, 0xBD, 0xA8, 0xBA, 0x17, 0x00, ++ 0xB4, 0xCA, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x1A, 0x46, 0x70, 0xB5, ++ 0x40, 0x23, 0x14, 0x4C, 0x0D, 0x46, 0x41, 0xF2, 0x06, 0x00, 0x11, 0x46, ++ 0x04, 0x22, 0xF6, 0xF7, 0xD7, 0xFC, 0xA3, 0x88, 0x06, 0x46, 0x13, 0xB1, ++ 0x2A, 0x78, 0x93, 0x42, 0x06, 0xD8, 0x00, 0x23, 0x30, 0x46, 0x33, 0x70, ++ 0xF6, 0xF7, 0xFC, 0xFC, 0x00, 0x20, 0x70, 0xBD, 0x04, 0xEB, 0x82, 0x14, ++ 0x08, 0x34, 0x0F, 0xCC, 0x35, 0x46, 0x0F, 0xC5, 0x0F, 0xCC, 0x0F, 0xC5, ++ 0x0F, 0xCC, 0x0F, 0xC5, 0x94, 0xE8, 0x0F, 0x00, 0x85, 0xE8, 0x0F, 0x00, ++ 0x30, 0x46, 0xF6, 0xF7, 0xE9, 0xFC, 0x00, 0x20, 0x70, 0xBD, 0x00, 0xBF, ++ 0xA8, 0xBA, 0x17, 0x00, 0x08, 0xB5, 0x04, 0x22, 0x01, 0x23, 0x02, 0x21, ++ 0x40, 0xF6, 0x03, 0x00, 0xF6, 0xF7, 0xAC, 0xFC, 0xF6, 0xF7, 0xDA, 0xFC, ++ 0x04, 0x20, 0xF6, 0xF7, 0x49, 0xFF, 0x03, 0x49, 0x02, 0x46, 0x08, 0x20, ++ 0xF8, 0xF7, 0x5A, 0xFB, 0x00, 0x20, 0x08, 0xBD, 0x6C, 0xBE, 0x15, 0x00, ++ 0x08, 0xB5, 0x19, 0x46, 0x04, 0x22, 0x01, 0x23, 0x41, 0xF2, 0x0B, 0x00, ++ 0xF6, 0xF7, 0x96, 0xFC, 0xF6, 0xF7, 0xC4, 0xFC, 0x02, 0x49, 0x08, 0x20, ++ 0xF8, 0xF7, 0x48, 0xFB, 0x00, 0x20, 0x08, 0xBD, 0x80, 0xBE, 0x15, 0x00, ++ 0x1A, 0x46, 0x38, 0xB5, 0x41, 0xF2, 0x08, 0x00, 0x0D, 0x46, 0x02, 0x23, ++ 0x11, 0x46, 0x04, 0x22, 0xF6, 0xF7, 0x82, 0xFC, 0x06, 0x49, 0x04, 0x46, ++ 0x08, 0x20, 0xF8, 0xF7, 0x35, 0xFB, 0x01, 0x23, 0x23, 0x70, 0xAB, 0x78, ++ 0x63, 0x70, 0x20, 0x46, 0xF6, 0xF7, 0xA6, 0xFC, 0x00, 0x20, 0x38, 0xBD, ++ 0x98, 0xBE, 0x15, 0x00, 0x10, 0xB5, 0x41, 0xF2, 0x08, 0x00, 0x04, 0x4C, ++ 0x04, 0x49, 0x1A, 0x46, 0x23, 0x5A, 0x08, 0x20, 0xF8, 0xF7, 0x20, 0xFB, ++ 0x02, 0x20, 0x10, 0xBD, 0xA8, 0xBA, 0x17, 0x00, 0xB4, 0xBE, 0x15, 0x00, ++ 0xF8, 0xB5, 0x36, 0x4C, 0x91, 0xF8, 0x6E, 0x21, 0x35, 0x4E, 0x21, 0x60, ++ 0x0D, 0x46, 0x41, 0xF2, 0x08, 0x00, 0x4F, 0xF4, 0xA4, 0x67, 0x41, 0xF2, ++ 0x0A, 0x01, 0x07, 0xFB, 0x02, 0x62, 0x01, 0x26, 0x23, 0x52, 0x66, 0x52, ++ 0x00, 0x23, 0xC2, 0xF8, 0xCC, 0x31, 0x05, 0xF5, 0xB0, 0x77, 0x97, 0xE8, ++ 0x03, 0x00, 0xDF, 0xF8, 0xC4, 0xC0, 0x41, 0xF2, 0x0C, 0x02, 0xAC, 0xF8, ++ 0x04, 0x10, 0x41, 0xF2, 0x3B, 0x01, 0xA0, 0x50, 0x63, 0x54, 0x38, 0x46, ++ 0x1A, 0x46, 0x19, 0x46, 0x00, 0xF0, 0x4A, 0xF9, 0x18, 0xB1, 0x90, 0xF8, ++ 0x3D, 0x10, 0x03, 0x46, 0x91, 0xB9, 0x97, 0xE8, 0x03, 0x00, 0x21, 0x4B, ++ 0x41, 0xF2, 0x34, 0x02, 0x99, 0x80, 0x20, 0x4B, 0xA0, 0x50, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x28, 0xDB, 0x1D, 0x4B, 0xD3, 0xF8, ++ 0xF4, 0x32, 0x98, 0x47, 0x01, 0x20, 0xF8, 0xBD, 0x02, 0x46, 0x41, 0xF2, ++ 0x34, 0x0C, 0x52, 0xF8, 0x02, 0x0F, 0x93, 0xF8, 0x3E, 0x70, 0x44, 0xF8, ++ 0x0C, 0x00, 0x14, 0x48, 0x92, 0x88, 0x82, 0x80, 0xBE, 0x40, 0x41, 0xF2, ++ 0x38, 0x00, 0x01, 0x3E, 0x22, 0x5A, 0x36, 0x02, 0x36, 0xB2, 0x22, 0xEA, ++ 0x06, 0x02, 0x12, 0xB2, 0x22, 0x52, 0xDB, 0x88, 0xA3, 0xEB, 0x01, 0x21, ++ 0x0E, 0x40, 0x0C, 0x4B, 0x16, 0x43, 0x26, 0x52, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0xD6, 0xDA, 0x95, 0xF8, 0x60, 0x31, 0xDB, 0x07, ++ 0xD2, 0xD5, 0x08, 0x49, 0x08, 0x48, 0xA1, 0x22, 0xF8, 0xF7, 0xD8, 0xFC, ++ 0xCC, 0xE7, 0x00, 0xBF, 0xA8, 0xBA, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0xDC, 0xCA, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xD0, 0xBE, 0x15, 0x00, 0xB4, 0xCA, 0x17, 0x00, ++ 0x1A, 0x46, 0x38, 0xB5, 0x41, 0xF2, 0x08, 0x00, 0x0D, 0x46, 0x02, 0x23, ++ 0x11, 0x46, 0x04, 0x22, 0xF6, 0xF7, 0xDA, 0xFB, 0x0A, 0x49, 0x04, 0x46, ++ 0x08, 0x20, 0xF8, 0xF7, 0x8D, 0xFA, 0x29, 0x46, 0x08, 0x48, 0x31, 0xF8, ++ 0x03, 0x2B, 0x20, 0xF8, 0x03, 0x2B, 0x0A, 0xF0, 0x55, 0xFF, 0x01, 0x23, ++ 0x23, 0x70, 0xAB, 0x78, 0x63, 0x70, 0x20, 0x46, 0xF6, 0xF7, 0xF6, 0xFB, ++ 0x00, 0x20, 0x38, 0xBD, 0xF0, 0xBE, 0x15, 0x00, 0x68, 0xCB, 0x17, 0x00, ++ 0x08, 0x78, 0x08, 0xB9, 0x00, 0x20, 0x70, 0x47, 0x08, 0xB5, 0x00, 0xF0, ++ 0x31, 0xF8, 0x00, 0x20, 0x08, 0xBD, 0x00, 0xBF, 0x70, 0xB5, 0x0B, 0x4E, ++ 0x41, 0xF2, 0x08, 0x05, 0x01, 0x23, 0x0C, 0x46, 0x04, 0x22, 0x71, 0x5B, ++ 0x41, 0xF2, 0x0B, 0x00, 0xF6, 0xF7, 0xAA, 0xFB, 0xF6, 0xF7, 0xD8, 0xFB, ++ 0x72, 0x5B, 0x05, 0x49, 0x08, 0x20, 0xF8, 0xF7, 0x5B, 0xFA, 0x20, 0x78, ++ 0x00, 0xF0, 0x18, 0xF8, 0x00, 0x20, 0x70, 0xBD, 0xA8, 0xBA, 0x17, 0x00, ++ 0x00, 0xBF, 0x15, 0x00, 0x08, 0xB5, 0x05, 0x49, 0x41, 0xF2, 0x0B, 0x02, ++ 0x8B, 0x5C, 0x01, 0x33, 0x8B, 0x54, 0x00, 0xF0, 0x65, 0xFD, 0x00, 0x20, ++ 0x08, 0xBD, 0x00, 0xBF, 0xA8, 0xBA, 0x17, 0x00, 0x08, 0x46, 0x00, 0xF0, ++ 0x19, 0xB9, 0x00, 0xBF, 0xF0, 0xB5, 0x39, 0x4C, 0x41, 0xF2, 0x0A, 0x05, ++ 0x83, 0xB0, 0x63, 0x5D, 0x06, 0x46, 0x00, 0x2B, 0x43, 0xD0, 0x41, 0xF2, ++ 0x08, 0x02, 0x03, 0x23, 0xA1, 0x5A, 0x41, 0xF2, 0x03, 0x00, 0x04, 0x22, ++ 0xF6, 0xF7, 0x76, 0xFB, 0x05, 0x46, 0x23, 0x68, 0x30, 0x49, 0x93, 0xF8, ++ 0x6E, 0x21, 0x00, 0x96, 0x41, 0xF2, 0x0A, 0x07, 0x08, 0x20, 0xE3, 0x5D, ++ 0xF8, 0xF7, 0x22, 0xFA, 0xE3, 0x5D, 0x63, 0xB9, 0x2B, 0x49, 0x2C, 0x4A, ++ 0x0B, 0x68, 0x2C, 0x48, 0x23, 0xF0, 0x04, 0x03, 0x0B, 0x60, 0x13, 0x68, ++ 0x01, 0x88, 0x1B, 0x0C, 0x1B, 0x04, 0x0B, 0x43, 0x13, 0x60, 0x20, 0x68, ++ 0x27, 0x4B, 0x90, 0xF8, 0x6E, 0x21, 0x2A, 0x70, 0x6E, 0x70, 0xA2, 0x88, ++ 0xAA, 0x70, 0x1B, 0x68, 0x1B, 0x78, 0x01, 0x2B, 0x20, 0xD0, 0x0C, 0x38, ++ 0xF6, 0xF7, 0xC8, 0xFB, 0x00, 0x26, 0x28, 0x46, 0x26, 0x60, 0xF6, 0xF7, ++ 0x77, 0xFB, 0x1F, 0x4A, 0x53, 0x68, 0x31, 0x46, 0x23, 0xF0, 0x20, 0x03, ++ 0x04, 0x20, 0x53, 0x60, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x40, 0xF6, 0xF7, ++ 0x35, 0xBD, 0xA3, 0x88, 0xF3, 0xB1, 0x41, 0xF2, 0x08, 0x02, 0x03, 0x23, ++ 0xA1, 0x5A, 0x41, 0xF2, 0x01, 0x00, 0x04, 0x22, 0xF6, 0xF7, 0x30, 0xFB, ++ 0x05, 0x46, 0xB8, 0xE7, 0x13, 0x4B, 0x93, 0xF8, 0xB5, 0x30, 0x00, 0x2B, ++ 0xD9, 0xD0, 0x12, 0x49, 0x12, 0x4B, 0x0A, 0x68, 0x22, 0xF0, 0x7C, 0x72, ++ 0x0A, 0x60, 0x1A, 0x68, 0x42, 0xF4, 0x80, 0x02, 0x1A, 0x60, 0x1A, 0x68, ++ 0x42, 0xF4, 0x00, 0x12, 0x1A, 0x60, 0xCA, 0xE7, 0xD6, 0xF7, 0xCC, 0xFB, ++ 0x63, 0x5D, 0x00, 0x2B, 0xDB, 0xD0, 0x94, 0xE7, 0xA8, 0xBA, 0x17, 0x00, ++ 0x30, 0xBF, 0x15, 0x00, 0x94, 0x40, 0x04, 0x40, 0x20, 0x04, 0x32, 0x40, ++ 0x28, 0x25, 0x17, 0x00, 0x74, 0x36, 0x17, 0x00, 0x1C, 0x9E, 0x17, 0x00, ++ 0x2C, 0x19, 0x17, 0x00, 0x74, 0x00, 0x32, 0x40, 0x6C, 0x00, 0x32, 0x40, ++ 0x08, 0xB5, 0x00, 0x21, 0x04, 0x20, 0xF6, 0xF7, 0xF5, 0xFC, 0xBD, 0xE8, ++ 0x08, 0x40, 0x03, 0x48, 0x4F, 0xF4, 0x86, 0x52, 0x00, 0x21, 0xD3, 0xF7, ++ 0xED, 0xBE, 0x00, 0xBF, 0xA8, 0xBA, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0x3C, 0x4D, 0x83, 0xB0, 0xA8, 0x46, 0x2B, 0x46, 0x00, 0x22, 0x08, 0xE0, ++ 0x5F, 0x89, 0x04, 0x88, 0xA7, 0x42, 0x14, 0xD0, 0x01, 0x32, 0x40, 0x2A, ++ 0x03, 0xF1, 0x40, 0x03, 0x1C, 0xD0, 0x1C, 0x7A, 0x03, 0xF1, 0x08, 0x06, ++ 0x00, 0x2C, 0xF1, 0xD1, 0x00, 0x29, 0xF3, 0xD0, 0x08, 0xEB, 0x82, 0x12, ++ 0x80, 0x23, 0x82, 0xF8, 0x44, 0x30, 0x30, 0x46, 0x03, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x8F, 0x9F, 0x89, 0x44, 0x88, 0xA7, 0x42, 0xE6, 0xD1, 0xDF, 0x89, ++ 0x84, 0x88, 0xA7, 0x42, 0xF3, 0xD0, 0x01, 0x32, 0x40, 0x2A, 0x03, 0xF1, ++ 0x40, 0x03, 0xE2, 0xD1, 0x00, 0x29, 0x46, 0xD0, 0x26, 0x4F, 0x4F, 0xF0, ++ 0x00, 0x0B, 0x4F, 0xF0, 0x21, 0x0A, 0x06, 0xE0, 0x0B, 0xF1, 0x01, 0x0B, ++ 0xBB, 0xF1, 0x40, 0x0F, 0x05, 0xF1, 0x40, 0x05, 0x39, 0xD0, 0x2B, 0x7A, ++ 0x05, 0xF1, 0x08, 0x06, 0x00, 0x2B, 0xF3, 0xD0, 0x95, 0xF8, 0x45, 0x40, ++ 0x00, 0x2C, 0xEF, 0xD1, 0x38, 0x68, 0x30, 0xB3, 0x90, 0xF8, 0x70, 0x31, ++ 0x1B, 0xB3, 0x05, 0xF1, 0x11, 0x01, 0x4F, 0xF0, 0xFD, 0x09, 0x06, 0xE0, ++ 0x38, 0x68, 0x01, 0x34, 0x90, 0xF8, 0x70, 0x31, 0xE4, 0xB2, 0xA3, 0x42, ++ 0x15, 0xD9, 0x04, 0xEB, 0x44, 0x13, 0x03, 0x44, 0x93, 0xF8, 0xFC, 0x30, ++ 0x00, 0x2B, 0xF1, 0xD0, 0x2A, 0x7C, 0x9A, 0x42, 0xEE, 0xD1, 0x1A, 0xFB, ++ 0x04, 0x93, 0x18, 0x44, 0x01, 0x91, 0x0A, 0xF0, 0xE1, 0xFD, 0x01, 0x99, ++ 0x00, 0x28, 0xE5, 0xD1, 0x3B, 0x68, 0x93, 0xF8, 0x70, 0x31, 0x9C, 0x42, ++ 0xC6, 0xD1, 0x08, 0xEB, 0x8B, 0x11, 0x80, 0x20, 0x00, 0x23, 0x81, 0xF8, ++ 0x44, 0x00, 0x0B, 0x72, 0xA5, 0xE7, 0x00, 0x26, 0x30, 0x46, 0x03, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x8F, 0xA8, 0xBA, 0x17, 0x00, 0xF4, 0x9F, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0x2D, 0xED, 0x02, 0x8B, 0x61, 0x4B, 0x99, 0xB0, ++ 0x1C, 0x68, 0x03, 0x46, 0x04, 0x93, 0x04, 0x20, 0x94, 0xF8, 0x6E, 0x31, ++ 0x07, 0x93, 0xF6, 0xF7, 0x03, 0xFD, 0x01, 0x28, 0x05, 0xD0, 0x00, 0x20, ++ 0x19, 0xB0, 0xBD, 0xEC, 0x02, 0x8B, 0xBD, 0xE8, 0xF0, 0x8F, 0x58, 0x49, ++ 0x41, 0xF2, 0x0C, 0x03, 0xCA, 0x5C, 0xD2, 0x07, 0x19, 0xD4, 0xCA, 0x5A, ++ 0x04, 0x9B, 0x9B, 0x8B, 0x9A, 0x42, 0x00, 0xF0, 0x85, 0x80, 0x52, 0x49, ++ 0x41, 0xF2, 0x34, 0x02, 0x8A, 0x5A, 0x9A, 0x42, 0xE7, 0xD1, 0x04, 0x9A, ++ 0x41, 0xF2, 0x36, 0x03, 0xD2, 0x8B, 0xCB, 0x5A, 0x9A, 0x42, 0xE0, 0xD1, ++ 0x04, 0x9A, 0x41, 0xF2, 0x38, 0x03, 0x12, 0x8C, 0xCB, 0x5A, 0x9A, 0x42, ++ 0xD9, 0xD1, 0x04, 0x98, 0x30, 0xF8, 0x30, 0x3B, 0x0B, 0x90, 0x24, 0x3B, ++ 0x9B, 0xB2, 0x0D, 0xF1, 0x37, 0x02, 0x19, 0x46, 0x08, 0xEE, 0x10, 0x3A, ++ 0xF7, 0xF7, 0xE4, 0xF8, 0x00, 0x28, 0x73, 0xD0, 0x9D, 0xF8, 0x37, 0x60, ++ 0x10, 0xAD, 0x4E, 0xB1, 0xAF, 0x19, 0x2B, 0x46, 0xC5, 0xF1, 0x02, 0x01, ++ 0xC2, 0x18, 0x52, 0x5C, 0x03, 0xF8, 0x01, 0x2B, 0xBB, 0x42, 0xF9, 0xD1, ++ 0x04, 0x9F, 0x38, 0x46, 0x01, 0x21, 0x2B, 0x46, 0x32, 0x46, 0x1C, 0x30, ++ 0xFF, 0xF7, 0x24, 0xFF, 0x01, 0x46, 0x0A, 0x90, 0x00, 0x28, 0xB0, 0xD0, ++ 0xBB, 0x8B, 0x43, 0x80, 0xFB, 0x8B, 0x83, 0x80, 0x3B, 0x8C, 0xC3, 0x80, ++ 0x97, 0xF8, 0x2C, 0x30, 0x97, 0xF8, 0x2D, 0x20, 0x43, 0xEA, 0x02, 0x23, ++ 0x03, 0x86, 0xFB, 0x8D, 0x43, 0x86, 0x03, 0xF0, 0x01, 0x03, 0xC3, 0xF1, ++ 0x02, 0x03, 0x43, 0x85, 0x00, 0x2E, 0x46, 0xD1, 0x0A, 0x9B, 0x1E, 0x72, ++ 0x27, 0x4A, 0x41, 0xF2, 0x3A, 0x03, 0xD3, 0x5C, 0x00, 0x2B, 0x40, 0xF0, ++ 0xA5, 0x82, 0x24, 0x4A, 0x41, 0xF2, 0x0A, 0x03, 0xD5, 0x5C, 0x00, 0x2D, ++ 0x48, 0xD1, 0x94, 0xF8, 0x70, 0x11, 0x00, 0x29, 0x44, 0xD0, 0x0A, 0x9B, ++ 0x26, 0x46, 0x03, 0xF1, 0x09, 0x07, 0x98, 0x46, 0x08, 0x46, 0x05, 0xE0, ++ 0x01, 0x35, 0xA8, 0x42, 0x06, 0xF1, 0x21, 0x06, 0x03, 0x46, 0x34, 0xDD, ++ 0x96, 0xF8, 0xFC, 0x30, 0x83, 0xB3, 0x98, 0xF8, 0x08, 0x20, 0x9A, 0x42, ++ 0xF2, 0xD1, 0x39, 0x46, 0x06, 0xF1, 0xFD, 0x00, 0x0A, 0xF0, 0x26, 0xFD, ++ 0x00, 0x28, 0x00, 0xF0, 0x2C, 0x83, 0x94, 0xF8, 0x70, 0x01, 0xE7, 0xE7, ++ 0x04, 0x99, 0x0F, 0x48, 0xC9, 0x8B, 0x41, 0xF2, 0x0E, 0x02, 0x82, 0x5A, ++ 0x91, 0x42, 0x7F, 0xF4, 0x72, 0xAF, 0x04, 0x99, 0x41, 0xF2, 0x10, 0x02, ++ 0x09, 0x8C, 0x82, 0x5A, 0x91, 0x42, 0x7F, 0xF4, 0x6A, 0xAF, 0x7C, 0xE7, ++ 0x06, 0x46, 0x10, 0xAD, 0x96, 0xE7, 0x0B, 0x46, 0x03, 0xF8, 0x08, 0x6F, ++ 0x2E, 0x44, 0x15, 0xF8, 0x01, 0x2B, 0x03, 0xF8, 0x01, 0x2F, 0xAE, 0x42, ++ 0xF9, 0xD1, 0xAF, 0xE7, 0xA8, 0xBA, 0x17, 0x00, 0x03, 0x46, 0x9D, 0x42, ++ 0x3F, 0xF4, 0x43, 0xAF, 0x18, 0xEE, 0x10, 0x1A, 0x0B, 0x98, 0xF7, 0xF7, ++ 0x45, 0xF9, 0x00, 0x28, 0x00, 0xF0, 0x3A, 0x82, 0x04, 0x9B, 0x9A, 0x79, ++ 0x83, 0x78, 0x00, 0x2A, 0x40, 0xF0, 0x56, 0x82, 0x59, 0x1E, 0x0D, 0x29, ++ 0x00, 0xF2, 0x4F, 0x82, 0x0E, 0x2B, 0x00, 0xF0, 0xEB, 0x82, 0x03, 0xEB, ++ 0x83, 0x03, 0x03, 0xF6, 0x67, 0x11, 0x10, 0x46, 0xFA, 0xF7, 0x98, 0xFE, ++ 0x0A, 0x99, 0x04, 0x9B, 0xC8, 0x62, 0x91, 0xF9, 0x3C, 0x20, 0x93, 0xF9, ++ 0x09, 0x30, 0x9A, 0x42, 0xB8, 0xBF, 0x81, 0xF8, 0x3C, 0x30, 0x04, 0x99, ++ 0x03, 0x88, 0x8A, 0x88, 0x9A, 0x42, 0x00, 0xD0, 0x8B, 0x80, 0x41, 0xF2, ++ 0xBD, 0x03, 0xB4, 0x4A, 0x00, 0x25, 0xD5, 0x54, 0x18, 0xEE, 0x10, 0x3A, ++ 0x00, 0x2B, 0x6C, 0xD0, 0x0B, 0x9B, 0x8D, 0xED, 0x05, 0x8A, 0x2C, 0x46, ++ 0xA8, 0x46, 0x06, 0x93, 0xDD, 0xE9, 0x05, 0x10, 0xF7, 0xF7, 0xFC, 0xF9, ++ 0x08, 0x90, 0x00, 0x28, 0x5F, 0xD0, 0x43, 0x78, 0xAA, 0x4A, 0x81, 0x78, ++ 0x11, 0x70, 0x5E, 0x1E, 0x02, 0x33, 0xB6, 0xB2, 0x09, 0x93, 0x00, 0xF1, ++ 0x03, 0x0A, 0x00, 0x2E, 0x44, 0xD0, 0x31, 0x46, 0x50, 0x46, 0xF7, 0xF7, ++ 0x09, 0xFA, 0x07, 0x46, 0x00, 0x28, 0x3D, 0xD0, 0x90, 0xF8, 0x01, 0x90, ++ 0x00, 0xF1, 0x02, 0x0B, 0x09, 0xF1, 0x02, 0x03, 0xF6, 0x1A, 0x58, 0x46, ++ 0x04, 0x21, 0xB6, 0xB2, 0x9A, 0x44, 0xF7, 0xF7, 0x1D, 0xFA, 0x00, 0x28, ++ 0x00, 0xF0, 0x81, 0x81, 0x49, 0x46, 0x58, 0x46, 0xF7, 0xF7, 0x36, 0xFA, ++ 0x07, 0xF1, 0x04, 0x08, 0x04, 0x46, 0x49, 0x46, 0x58, 0x46, 0x0E, 0xAA, ++ 0xF6, 0xF7, 0xE8, 0xFF, 0x05, 0x46, 0x00, 0x2C, 0xD7, 0xD0, 0x00, 0x2D, ++ 0xD5, 0xD0, 0x92, 0x4B, 0x98, 0xF8, 0x00, 0xC0, 0x1A, 0x78, 0xA7, 0x78, ++ 0xA3, 0xF1, 0x81, 0x00, 0x81, 0x1D, 0x98, 0xF8, 0x01, 0x30, 0x01, 0xF8, ++ 0x32, 0x70, 0x4C, 0xEA, 0x03, 0x21, 0x53, 0x1C, 0xDB, 0xB2, 0x07, 0x1D, ++ 0x10, 0x2B, 0x40, 0xF8, 0x32, 0x50, 0x80, 0xF8, 0x81, 0x30, 0x27, 0xF8, ++ 0x32, 0x10, 0x12, 0xD0, 0x4F, 0xF0, 0x00, 0x08, 0x00, 0x2E, 0xBA, 0xD1, ++ 0x06, 0x9B, 0x08, 0x9A, 0x05, 0x99, 0x9B, 0x1A, 0x19, 0x44, 0x09, 0x9B, ++ 0xA1, 0xEB, 0x03, 0x0B, 0x1F, 0xFA, 0x8B, 0xF1, 0xD3, 0x18, 0x05, 0x91, ++ 0x06, 0x93, 0x00, 0x29, 0x98, 0xD1, 0x0A, 0x99, 0x00, 0x23, 0x4B, 0x63, ++ 0x8B, 0x63, 0x41, 0xF2, 0x0A, 0x02, 0x77, 0x4B, 0x9B, 0x5C, 0x00, 0x2B, ++ 0x00, 0xF0, 0xB4, 0x80, 0x0A, 0x9A, 0x07, 0x9F, 0x76, 0x4C, 0x56, 0x8D, ++ 0x51, 0x8E, 0x13, 0x46, 0x4F, 0xF4, 0xA4, 0x65, 0x53, 0xF8, 0x02, 0x0F, ++ 0x12, 0x8E, 0x9B, 0x88, 0x05, 0xFB, 0x07, 0xF5, 0x67, 0x19, 0xA7, 0xF8, ++ 0x68, 0x31, 0xA7, 0xF8, 0x98, 0x21, 0xFF, 0x23, 0x0A, 0x9A, 0xA7, 0xF8, ++ 0x8E, 0x61, 0xC7, 0xF8, 0x64, 0x01, 0xA7, 0xF8, 0x9A, 0x11, 0x87, 0xF8, ++ 0x61, 0x31, 0x87, 0xF8, 0xBE, 0x31, 0x13, 0x7A, 0x05, 0xF1, 0xEC, 0x06, ++ 0x26, 0x44, 0x00, 0x2B, 0x40, 0xF0, 0xA2, 0x81, 0x0A, 0x9A, 0xD2, 0x6A, ++ 0xC7, 0xF8, 0x90, 0x21, 0xA7, 0xF8, 0xC2, 0x31, 0x07, 0x9B, 0x0A, 0x9A, ++ 0x0B, 0x98, 0x4F, 0xF4, 0xA4, 0x67, 0x07, 0xFB, 0x03, 0x47, 0x92, 0xF8, ++ 0x3D, 0x30, 0x87, 0xF8, 0x8B, 0x31, 0x92, 0xF8, 0x3E, 0x30, 0x87, 0xF8, ++ 0x8C, 0x31, 0x05, 0xF5, 0xCE, 0x78, 0x00, 0x23, 0xA0, 0x44, 0xC7, 0xF8, ++ 0xCC, 0x31, 0x18, 0xEE, 0x10, 0x1A, 0x42, 0x46, 0xF9, 0xF7, 0xA4, 0xFB, ++ 0x0A, 0x9B, 0xDB, 0x6A, 0x9B, 0x78, 0x00, 0x2B, 0x00, 0xF0, 0xB3, 0x81, ++ 0x05, 0xF5, 0xD6, 0x72, 0x18, 0xEE, 0x10, 0x1A, 0x0B, 0x98, 0x22, 0x44, ++ 0x0E, 0xAB, 0xF9, 0xF7, 0x6D, 0xFD, 0x80, 0xB1, 0x07, 0x9A, 0x4F, 0xF4, ++ 0xA4, 0x63, 0x03, 0xFB, 0x02, 0x43, 0xB3, 0xF8, 0x9A, 0x11, 0xD3, 0xF8, ++ 0xCC, 0x21, 0x41, 0xF4, 0x00, 0x71, 0x42, 0xF0, 0x01, 0x02, 0xA3, 0xF8, ++ 0x9A, 0x11, 0xC3, 0xF8, 0xCC, 0x21, 0x45, 0x4F, 0x97, 0xF8, 0x76, 0x31, ++ 0xDB, 0x07, 0x09, 0xD5, 0x07, 0x9B, 0x4F, 0xF4, 0xA4, 0x69, 0x09, 0xFB, ++ 0x03, 0x49, 0xD9, 0xF8, 0xCC, 0x31, 0xD8, 0x07, 0x00, 0xF1, 0x98, 0x81, ++ 0x00, 0x21, 0x88, 0x46, 0x40, 0x46, 0x32, 0x46, 0xFB, 0xF7, 0x52, 0xFA, ++ 0x0B, 0x9D, 0x18, 0xEE, 0x10, 0x1A, 0x28, 0x46, 0x32, 0x46, 0xF9, 0xF7, ++ 0xAD, 0xFB, 0x28, 0x46, 0x18, 0xEE, 0x10, 0x1A, 0x32, 0x46, 0xF9, 0xF7, ++ 0xB1, 0xFB, 0x28, 0x46, 0x18, 0xEE, 0x10, 0x1A, 0x32, 0x46, 0xF9, 0xF7, ++ 0x13, 0xFC, 0x07, 0x9A, 0x31, 0x4D, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, ++ 0x02, 0x44, 0x29, 0x6D, 0xD4, 0xF8, 0xCC, 0x31, 0x43, 0xF0, 0x00, 0x43, ++ 0x41, 0xF2, 0x3B, 0x02, 0xC4, 0xF8, 0xCC, 0x31, 0x25, 0x4B, 0x01, 0x20, ++ 0x98, 0x54, 0x2A, 0x6A, 0x00, 0x29, 0x00, 0xF0, 0x1C, 0x81, 0x00, 0x2A, ++ 0x00, 0xF0, 0x19, 0x81, 0x0B, 0x7E, 0x03, 0x2B, 0x08, 0xD1, 0x25, 0x4B, ++ 0x05, 0xF1, 0x40, 0x00, 0xD3, 0xF8, 0xD8, 0x31, 0x98, 0x47, 0xD5, 0xE9, ++ 0x11, 0x30, 0x98, 0x47, 0x0A, 0x9A, 0x14, 0x78, 0xDC, 0xB9, 0x19, 0x48, ++ 0x1F, 0x4B, 0x81, 0x88, 0x1B, 0x68, 0x01, 0x31, 0x89, 0xB2, 0x81, 0x80, ++ 0x1B, 0x88, 0x5B, 0x07, 0x11, 0xD5, 0x13, 0x7A, 0x00, 0x2B, 0x40, 0xF0, ++ 0x7A, 0x81, 0x1A, 0x4D, 0x0A, 0x9A, 0x04, 0x9C, 0xD2, 0x6A, 0x94, 0xF9, ++ 0x09, 0x00, 0x12, 0x88, 0x00, 0x90, 0xCD, 0xE9, 0x01, 0x35, 0x16, 0x48, ++ 0x23, 0x7B, 0xF7, 0xF7, 0x89, 0xFE, 0x0A, 0x99, 0x00, 0x25, 0x01, 0x22, ++ 0x0A, 0x70, 0x81, 0xF8, 0x3D, 0x50, 0x81, 0xF8, 0x3E, 0x50, 0x41, 0xF2, ++ 0xBD, 0x03, 0x08, 0x46, 0x05, 0x49, 0xCB, 0x5C, 0x00, 0x2B, 0x4D, 0xD0, ++ 0x0D, 0x4C, 0x83, 0x46, 0x04, 0xF1, 0x80, 0x0A, 0x04, 0xF1, 0x81, 0x09, ++ 0x43, 0xE0, 0x00, 0xBF, 0xA8, 0xBA, 0x17, 0x00, 0x64, 0xCB, 0x17, 0x00, ++ 0x65, 0xCB, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, 0xE4, 0xB8, 0x17, 0x00, ++ 0x30, 0x9D, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x48, 0xBF, 0x15, 0x00, 0x84, 0xBF, 0x15, 0x00, 0xE4, 0xCA, 0x17, 0x00, ++ 0x9A, 0xF8, 0x00, 0x70, 0x08, 0x2F, 0x2B, 0xD8, 0x5A, 0x46, 0x21, 0x68, ++ 0x52, 0xF8, 0x02, 0x0F, 0x4E, 0x78, 0x0E, 0x90, 0x92, 0x88, 0xAD, 0xF8, ++ 0x3C, 0x20, 0xBB, 0xF8, 0x06, 0x20, 0xBD, 0xF9, 0x3C, 0x10, 0x4F, 0xF0, ++ 0x01, 0x08, 0x02, 0xEB, 0x03, 0x22, 0x08, 0xFA, 0x07, 0xF3, 0x4A, 0x40, ++ 0x01, 0x3B, 0x02, 0xEA, 0x03, 0x22, 0x00, 0x23, 0x81, 0xEA, 0x02, 0x0C, ++ 0x0E, 0xA8, 0x1A, 0x46, 0x19, 0x46, 0xAD, 0xF8, 0x3C, 0xC0, 0xFF, 0xF7, ++ 0xDF, 0xFC, 0x68, 0xB3, 0x99, 0xF8, 0x00, 0x30, 0x01, 0x35, 0x9D, 0x42, ++ 0x04, 0xF1, 0x08, 0x04, 0x02, 0xDA, 0xA3, 0x79, 0x00, 0x2B, 0xCF, 0xD1, ++ 0x04, 0x98, 0x04, 0x23, 0x0C, 0x22, 0x41, 0xF2, 0x04, 0x01, 0xF6, 0xF7, ++ 0x2D, 0xF8, 0x01, 0x20, 0x5C, 0xE5, 0xB8, 0xF1, 0x00, 0x0F, 0x3F, 0xF4, ++ 0x62, 0xAE, 0x4C, 0xB1, 0x00, 0x2D, 0x7F, 0xF4, 0x88, 0xAE, 0x49, 0x46, ++ 0x58, 0x46, 0x0E, 0xAA, 0xF6, 0xF7, 0x66, 0xFE, 0x05, 0x46, 0x7E, 0xE6, ++ 0x49, 0x46, 0x58, 0x46, 0xF7, 0xF7, 0xA6, 0xF8, 0x04, 0x46, 0x00, 0x2D, ++ 0x3F, 0xF4, 0x6F, 0xAE, 0x00, 0x28, 0x3F, 0xF4, 0x4C, 0xAE, 0x74, 0xE6, ++ 0x23, 0x68, 0x41, 0x46, 0x02, 0x33, 0x32, 0x46, 0x0E, 0xA8, 0xFF, 0xF7, ++ 0xA9, 0xFC, 0x86, 0x46, 0x00, 0x28, 0xD1, 0xD0, 0xD8, 0x46, 0xB8, 0xE8, ++ 0x0F, 0x00, 0xF4, 0x46, 0xAC, 0xE8, 0x0F, 0x00, 0xB8, 0xE8, 0x0F, 0x00, ++ 0xAC, 0xE8, 0x0F, 0x00, 0xB8, 0xE8, 0x0F, 0x00, 0xAC, 0xE8, 0x0F, 0x00, ++ 0x98, 0xE8, 0x0F, 0x00, 0x8C, 0xE8, 0x0F, 0x00, 0x0E, 0x98, 0xCE, 0xF8, ++ 0x02, 0x00, 0xBD, 0xF8, 0x3C, 0x30, 0x8E, 0xF8, 0x08, 0x60, 0x21, 0x68, ++ 0xAE, 0xF8, 0x06, 0x30, 0x5E, 0xB1, 0x08, 0x36, 0x06, 0x39, 0x76, 0x44, ++ 0xA1, 0xEB, 0x0E, 0x01, 0x0E, 0xF1, 0x08, 0x03, 0xCA, 0x5C, 0x03, 0xF8, ++ 0x01, 0x2F, 0x9E, 0x42, 0xFA, 0xD1, 0x7E, 0x49, 0x8E, 0xF8, 0x3E, 0x70, ++ 0x8B, 0x88, 0xA2, 0x79, 0x8E, 0xF8, 0x3D, 0x20, 0x01, 0x33, 0x01, 0x22, ++ 0x8B, 0x80, 0x8E, 0xF8, 0x00, 0x20, 0x91, 0xE7, 0x04, 0x9B, 0x93, 0xF9, ++ 0x09, 0x20, 0x0A, 0x9B, 0x93, 0xF9, 0x3C, 0x30, 0x9A, 0x42, 0x7F, 0xF7, ++ 0xE2, 0xAD, 0x04, 0x9C, 0xA1, 0x88, 0xA0, 0x79, 0xFA, 0xF7, 0x64, 0xFC, ++ 0x0A, 0x9A, 0xD0, 0x62, 0x63, 0x7A, 0x82, 0xF8, 0x3C, 0x30, 0xD6, 0xE5, ++ 0x0A, 0x9B, 0x6E, 0x49, 0x07, 0x22, 0x03, 0xF1, 0x09, 0x00, 0x0A, 0xF0, ++ 0x9D, 0xFA, 0x00, 0x28, 0x7F, 0xF4, 0xE3, 0xAC, 0x9E, 0xE5, 0x4F, 0xF6, ++ 0xFF, 0x71, 0xB4, 0xE5, 0x01, 0x2A, 0xFA, 0xD1, 0x59, 0x1E, 0xA4, 0x29, ++ 0xF7, 0xD8, 0x03, 0xEB, 0x83, 0x03, 0x03, 0xF5, 0x9C, 0x51, 0x08, 0x31, ++ 0xA9, 0xE5, 0xB2, 0xFA, 0x82, 0xF2, 0x62, 0x48, 0x52, 0x09, 0xF7, 0xF7, ++ 0x95, 0xFD, 0xEB, 0xE6, 0x02, 0xF1, 0x09, 0x00, 0x0A, 0xF0, 0xAC, 0xFC, ++ 0xA8, 0xB1, 0x0A, 0x9B, 0x07, 0xF5, 0xB5, 0x77, 0x03, 0xF1, 0x08, 0x08, ++ 0x03, 0xF1, 0x28, 0x0E, 0xC4, 0x46, 0xBC, 0xE8, 0x0F, 0x00, 0xF4, 0x45, ++ 0x38, 0x60, 0x79, 0x60, 0xBA, 0x60, 0xFB, 0x60, 0xE0, 0x46, 0x07, 0xF1, ++ 0x10, 0x07, 0xF3, 0xD1, 0x9C, 0xF8, 0x00, 0x30, 0x3B, 0x70, 0x0A, 0x9B, ++ 0x07, 0x98, 0x19, 0x7A, 0x0A, 0x9B, 0xDA, 0x6A, 0x4F, 0xF4, 0xA4, 0x63, ++ 0x03, 0xFB, 0x00, 0x43, 0x00, 0x27, 0xC3, 0xF8, 0x90, 0x21, 0xA3, 0xF8, ++ 0xC2, 0x71, 0x00, 0x29, 0x3F, 0xF4, 0x38, 0xAE, 0x0B, 0x44, 0x05, 0xF2, ++ 0x6B, 0x11, 0x12, 0x88, 0x48, 0x48, 0x83, 0xF8, 0x6B, 0x71, 0x21, 0x44, ++ 0xF7, 0xF7, 0x5E, 0xFD, 0x2C, 0xE6, 0x40, 0x46, 0x01, 0x21, 0xFA, 0xF7, ++ 0xED, 0xFD, 0x10, 0xF0, 0x0F, 0x00, 0x1A, 0xBF, 0xB0, 0xFA, 0x80, 0xF0, ++ 0xC0, 0xF1, 0x1F, 0x03, 0x01, 0x23, 0x87, 0xF8, 0xC1, 0x31, 0x3D, 0xE6, ++ 0x18, 0xEE, 0x10, 0x1A, 0x0B, 0x98, 0x32, 0x46, 0xF9, 0xF7, 0x0C, 0xFC, ++ 0x00, 0x28, 0x3F, 0xF4, 0x5F, 0xAE, 0xD9, 0xF8, 0xCC, 0x31, 0x0B, 0x98, ++ 0x43, 0xF0, 0x02, 0x03, 0x18, 0xEE, 0x10, 0x1A, 0xC9, 0xF8, 0xCC, 0x31, ++ 0xF7, 0xF7, 0x24, 0xF8, 0x97, 0xF8, 0x76, 0x31, 0x59, 0x07, 0x80, 0x46, ++ 0x30, 0xD4, 0x9A, 0x07, 0x0A, 0xD4, 0x07, 0x9A, 0x4F, 0xF4, 0xA4, 0x63, ++ 0x03, 0xFB, 0x02, 0x43, 0xD3, 0xF8, 0xCC, 0x11, 0x11, 0xF0, 0x08, 0x01, ++ 0x3F, 0xF4, 0x44, 0xAE, 0x05, 0xF5, 0x86, 0x72, 0x18, 0xEE, 0x10, 0x1A, ++ 0x0B, 0x98, 0x22, 0x44, 0xF9, 0xF7, 0x08, 0xFC, 0x30, 0xBB, 0x01, 0x46, ++ 0x38, 0xE6, 0x02, 0xF1, 0x09, 0x05, 0x28, 0x46, 0x16, 0x46, 0x0A, 0xF0, ++ 0x33, 0xFC, 0x20, 0xB9, 0x1E, 0x4B, 0x22, 0x4D, 0x99, 0x88, 0x33, 0x7A, ++ 0x7A, 0xE6, 0x0A, 0x9A, 0x1B, 0x49, 0x13, 0x7A, 0x89, 0x88, 0x1A, 0x44, ++ 0x54, 0x72, 0x73, 0xE6, 0x40, 0xF6, 0xB4, 0x11, 0x15, 0xE5, 0x94, 0xF8, ++ 0x70, 0x31, 0xF6, 0xE4, 0x05, 0xF5, 0x8C, 0x72, 0x18, 0xEE, 0x10, 0x1A, ++ 0x0B, 0x98, 0x22, 0x44, 0xF9, 0xF7, 0x02, 0xFC, 0xA0, 0xB9, 0x97, 0xF8, ++ 0x76, 0x31, 0xC2, 0xE7, 0x07, 0x9A, 0x0B, 0x98, 0x4F, 0xF4, 0xA4, 0x63, ++ 0x03, 0xFB, 0x02, 0x43, 0x18, 0xEE, 0x10, 0x1A, 0xD3, 0xF8, 0xCC, 0x21, ++ 0x42, 0xF0, 0x04, 0x02, 0xC3, 0xF8, 0xCC, 0x21, 0xF6, 0xF7, 0xF2, 0xFF, ++ 0x01, 0x46, 0x01, 0xE6, 0xD9, 0xF8, 0xCC, 0x31, 0x0B, 0x98, 0x43, 0xF0, ++ 0x08, 0x03, 0x18, 0xEE, 0x10, 0x1A, 0x32, 0x46, 0xC9, 0xF8, 0xCC, 0x31, ++ 0xF9, 0xF7, 0x36, 0xFC, 0xDD, 0xE7, 0x00, 0xBF, 0xA8, 0xBA, 0x17, 0x00, ++ 0x54, 0xBF, 0x15, 0x00, 0x68, 0xBF, 0x15, 0x00, 0x5C, 0xBF, 0x15, 0x00, ++ 0x48, 0xBF, 0x15, 0x00, 0x00, 0x23, 0x1A, 0x46, 0x19, 0x46, 0xFF, 0xF7, ++ 0x71, 0xBB, 0x00, 0xBF, 0x2D, 0xE9, 0xF8, 0x43, 0x03, 0x78, 0x43, 0xB3, ++ 0x16, 0x4C, 0x07, 0x46, 0x4F, 0xF0, 0x00, 0x08, 0x04, 0xF5, 0x80, 0x56, ++ 0x6F, 0xF0, 0x7F, 0x05, 0x00, 0xF1, 0x01, 0x09, 0x02, 0xE0, 0x40, 0x34, ++ 0xB4, 0x42, 0x17, 0xD0, 0x23, 0x7A, 0xAB, 0xB1, 0x94, 0xF9, 0x44, 0x30, ++ 0xAB, 0x42, 0xF6, 0xDD, 0x23, 0x7C, 0x3A, 0x78, 0x9A, 0x42, 0xF2, 0xD1, ++ 0x49, 0x46, 0x04, 0xF1, 0x11, 0x00, 0x0A, 0xF0, 0x97, 0xF9, 0x00, 0x28, ++ 0xEB, 0xD1, 0x94, 0xF9, 0x44, 0x50, 0x04, 0xF1, 0x08, 0x08, 0x40, 0x34, ++ 0xB4, 0x42, 0xE7, 0xD1, 0x40, 0x46, 0xBD, 0xE8, 0xF8, 0x83, 0x98, 0x46, ++ 0x40, 0x46, 0xBD, 0xE8, 0xF8, 0x83, 0x00, 0xBF, 0xA8, 0xBA, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x47, 0x41, 0xF2, 0x0B, 0x03, 0xC2, 0x4D, 0xE9, 0x5C, ++ 0x2E, 0x68, 0x01, 0x29, 0x82, 0xB0, 0x00, 0xF2, 0xB8, 0x81, 0x96, 0xF8, ++ 0x6F, 0x01, 0x00, 0x27, 0x00, 0x28, 0x00, 0xF0, 0x57, 0x81, 0x33, 0x46, ++ 0x00, 0x24, 0x03, 0xE0, 0x01, 0x34, 0x84, 0x42, 0x00, 0xF0, 0x50, 0x81, ++ 0x9A, 0x78, 0x8A, 0x42, 0x03, 0xF1, 0x06, 0x03, 0xF6, 0xD1, 0x17, 0xB1, ++ 0x41, 0xF2, 0x0B, 0x03, 0xE9, 0x54, 0x4F, 0xF4, 0xBA, 0x73, 0x02, 0x21, ++ 0x04, 0x22, 0x4F, 0xF4, 0x00, 0x60, 0xF5, 0xF7, 0x03, 0xFE, 0x96, 0xF8, ++ 0x6E, 0x31, 0x80, 0xF8, 0x6E, 0x31, 0x07, 0x46, 0xD6, 0xE9, 0x58, 0x01, ++ 0xC7, 0xF8, 0x60, 0x01, 0xA7, 0xF8, 0x64, 0x11, 0x96, 0xF8, 0x70, 0x01, ++ 0x87, 0xF8, 0x70, 0x01, 0x96, 0xF8, 0x71, 0x31, 0x87, 0xF8, 0x71, 0x31, ++ 0x96, 0xF8, 0x6F, 0x31, 0x9C, 0x42, 0x80, 0xF2, 0x79, 0x81, 0x41, 0xF2, ++ 0x0B, 0x02, 0x04, 0xEB, 0x44, 0x04, 0x06, 0x21, 0x15, 0xF8, 0x02, 0x80, ++ 0x06, 0xEB, 0x44, 0x04, 0x11, 0xFB, 0x03, 0x61, 0xA3, 0x78, 0x43, 0x45, ++ 0x10, 0xD1, 0x97, 0xF8, 0x6F, 0x31, 0xD4, 0xF8, 0x00, 0xC0, 0x03, 0xEB, ++ 0x43, 0x02, 0x01, 0x33, 0x47, 0xF8, 0x12, 0xC0, 0x07, 0xEB, 0x42, 0x02, ++ 0xB4, 0xF8, 0x04, 0xC0, 0xA2, 0xF8, 0x04, 0xC0, 0x87, 0xF8, 0x6F, 0x31, ++ 0x06, 0x34, 0xA1, 0x42, 0xE8, 0xD1, 0xF0, 0xB1, 0x4F, 0xF0, 0x21, 0x0A, ++ 0xFC, 0x21, 0x1A, 0xFB, 0x00, 0x1A, 0x73, 0x18, 0x03, 0xF1, 0x20, 0x09, ++ 0x7A, 0x18, 0xD3, 0xF8, 0x00, 0xC0, 0x5C, 0x68, 0x98, 0x68, 0xD3, 0xF8, ++ 0x0C, 0xE0, 0xC2, 0xF8, 0x0C, 0xE0, 0x10, 0x33, 0x4B, 0x45, 0xC2, 0xF8, ++ 0x00, 0xC0, 0x54, 0x60, 0x90, 0x60, 0x02, 0xF1, 0x10, 0x02, 0xEE, 0xD1, ++ 0x21, 0x31, 0x1B, 0x78, 0x13, 0x70, 0x51, 0x45, 0xE5, 0xD1, 0x2B, 0x68, ++ 0xDF, 0xF8, 0x2C, 0xC2, 0xB3, 0xF8, 0x6C, 0x91, 0x81, 0x4C, 0xB9, 0xF1, ++ 0xC9, 0x0F, 0x28, 0xBF, 0x4F, 0xF0, 0x00, 0x09, 0xB8, 0xF1, 0x01, 0x0F, ++ 0x66, 0x46, 0x00, 0xF0, 0xE5, 0x80, 0x93, 0xF8, 0x71, 0x21, 0x7C, 0x4B, ++ 0x00, 0x2A, 0xA3, 0xF1, 0x04, 0x02, 0x0A, 0xBF, 0x13, 0x46, 0x4F, 0xF0, ++ 0x08, 0x0E, 0x4F, 0xF0, 0x0C, 0x0E, 0x78, 0x4A, 0x01, 0x20, 0x08, 0x21, ++ 0x10, 0x75, 0x15, 0x32, 0x61, 0x70, 0x58, 0x18, 0x13, 0xF8, 0x01, 0x1B, ++ 0x02, 0xF8, 0x01, 0x1F, 0x98, 0x42, 0xF9, 0xD1, 0x72, 0x4B, 0x01, 0x93, ++ 0xB9, 0xF1, 0x00, 0x0F, 0x40, 0xF0, 0x99, 0x80, 0xBE, 0xF1, 0x08, 0x0F, ++ 0x19, 0xD0, 0x01, 0x9B, 0x6E, 0x4A, 0x58, 0x1C, 0x32, 0x21, 0x01, 0x90, ++ 0x19, 0x70, 0x01, 0x9B, 0xAE, 0xF1, 0x08, 0x0E, 0x59, 0x1C, 0x5F, 0xFA, ++ 0x8E, 0xFE, 0x01, 0x91, 0x83, 0xF8, 0x00, 0xE0, 0x01, 0x9B, 0x18, 0x1D, ++ 0x12, 0xF8, 0x01, 0x1B, 0x03, 0xF8, 0x01, 0x1B, 0x98, 0x42, 0xF9, 0xD1, ++ 0x01, 0x9B, 0x73, 0x44, 0x01, 0x93, 0x41, 0xF2, 0x0B, 0x03, 0xEB, 0x5C, ++ 0x63, 0xB9, 0x01, 0x9B, 0x03, 0x22, 0x59, 0x1C, 0x01, 0x91, 0x1A, 0x70, ++ 0x01, 0x9B, 0x01, 0x22, 0x59, 0x1C, 0x01, 0x91, 0x1A, 0x70, 0x01, 0x9B, ++ 0x13, 0x44, 0x01, 0x93, 0xB9, 0xF1, 0x00, 0x0F, 0x36, 0xD1, 0xDF, 0xF8, ++ 0x7C, 0x81, 0x98, 0xF8, 0x76, 0x31, 0xD8, 0x07, 0x06, 0xD5, 0x56, 0x4B, ++ 0x01, 0xA8, 0xD3, 0xF8, 0x48, 0x31, 0x98, 0x47, 0x98, 0xF8, 0x76, 0x31, ++ 0x41, 0xF2, 0x0B, 0x02, 0xAA, 0x5C, 0x01, 0x2A, 0x4A, 0xD0, 0x5D, 0x07, ++ 0x04, 0xD5, 0x4F, 0x4B, 0x01, 0xA8, 0xD3, 0xF8, 0x44, 0x31, 0x98, 0x47, ++ 0x4D, 0x4D, 0x01, 0x98, 0x29, 0x46, 0x31, 0xF8, 0x03, 0x2B, 0x0A, 0xF0, ++ 0xB1, 0xF8, 0x4B, 0x4A, 0x01, 0x99, 0x12, 0x68, 0x2B, 0x88, 0xB2, 0xF9, ++ 0x00, 0x20, 0x0B, 0x44, 0x00, 0x2A, 0x01, 0x93, 0xA3, 0xEB, 0x04, 0x03, ++ 0x5D, 0xDB, 0x00, 0x22, 0xA7, 0xF8, 0x6C, 0x31, 0xC7, 0xF8, 0x68, 0x21, ++ 0x38, 0x46, 0xF5, 0xF7, 0x45, 0xFD, 0x02, 0xB0, 0xBD, 0xE8, 0xF0, 0x87, ++ 0x32, 0x78, 0x3B, 0x2A, 0x60, 0xD0, 0xDF, 0xF8, 0x08, 0x81, 0x98, 0xF8, ++ 0x76, 0x31, 0xD9, 0x07, 0x58, 0xD5, 0x39, 0x4B, 0x01, 0xA8, 0xD3, 0xF8, ++ 0x48, 0x31, 0x98, 0x47, 0xB9, 0xF1, 0x00, 0x0F, 0xC2, 0xD0, 0x01, 0x99, ++ 0x32, 0x78, 0x0B, 0x46, 0x76, 0x1A, 0x49, 0x44, 0x00, 0xE0, 0xF2, 0x5C, ++ 0x03, 0xF8, 0x01, 0x2B, 0x99, 0x42, 0xFA, 0xD1, 0x01, 0x9A, 0x98, 0xF8, ++ 0x76, 0x31, 0x4A, 0x44, 0x01, 0x92, 0x41, 0xF2, 0x0B, 0x02, 0xAA, 0x5C, ++ 0x01, 0x2A, 0xB4, 0xD1, 0x9E, 0x07, 0xB2, 0xD5, 0x29, 0x4B, 0x00, 0x21, ++ 0xD3, 0xF8, 0x50, 0x31, 0x01, 0xA8, 0x98, 0x47, 0x98, 0xF8, 0x76, 0x31, ++ 0xA9, 0xE7, 0x9C, 0xF8, 0x00, 0x20, 0x0A, 0x2A, 0x7F, 0xF4, 0x62, 0xAF, ++ 0x9C, 0xF8, 0x01, 0x60, 0x02, 0x36, 0x16, 0xF0, 0xFF, 0x06, 0x09, 0xD0, ++ 0x22, 0x49, 0x98, 0x19, 0x01, 0xE0, 0x11, 0xF8, 0x01, 0x2F, 0x03, 0xF8, ++ 0x01, 0x2B, 0x83, 0x42, 0xF9, 0xD1, 0x01, 0x9B, 0x33, 0x44, 0xA9, 0xEB, ++ 0x06, 0x09, 0x01, 0x93, 0x1F, 0xFA, 0x89, 0xF9, 0x66, 0x44, 0x49, 0xE7, ++ 0x01, 0x27, 0xB9, 0x42, 0x53, 0xD0, 0x39, 0x46, 0xA0, 0xE6, 0xB3, 0xF5, ++ 0x96, 0x7F, 0x9E, 0xD9, 0x16, 0x49, 0x17, 0x48, 0xB4, 0x22, 0xF7, 0xF7, ++ 0x99, 0xFD, 0x01, 0x9B, 0x1B, 0x1B, 0x96, 0xE7, 0x0A, 0x4B, 0x4F, 0xF0, ++ 0x08, 0x0E, 0x22, 0xE7, 0x01, 0x99, 0xAE, 0xE7, 0x70, 0x78, 0x01, 0x99, ++ 0x02, 0x30, 0x10, 0xF0, 0xFF, 0x00, 0x42, 0xD0, 0x0B, 0x46, 0xA6, 0xEB, ++ 0x03, 0x0C, 0x01, 0x44, 0x1C, 0xE0, 0x00, 0xBF, 0xA8, 0xBA, 0x17, 0x00, ++ 0xE8, 0x61, 0x18, 0x00, 0xB8, 0xB2, 0x15, 0x00, 0xD4, 0x61, 0x18, 0x00, ++ 0xF2, 0x61, 0x18, 0x00, 0xBC, 0xB2, 0x15, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x68, 0xCB, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, 0x18, 0x63, 0x18, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x9C, 0xBF, 0x15, 0x00, 0xE4, 0xB8, 0x17, 0x00, ++ 0x1C, 0xF8, 0x03, 0x20, 0x03, 0xF8, 0x01, 0x2B, 0x99, 0x42, 0xF9, 0xD1, ++ 0xDF, 0xF8, 0x48, 0x80, 0x01, 0x9B, 0x98, 0xF8, 0x76, 0x21, 0x03, 0x44, ++ 0xA9, 0xEB, 0x00, 0x09, 0x01, 0x93, 0xD3, 0x07, 0x1F, 0xFA, 0x89, 0xF9, ++ 0x06, 0x44, 0x7F, 0xF5, 0x6F, 0xAF, 0x68, 0xE7, 0x41, 0xF2, 0x0B, 0x03, ++ 0x15, 0xF8, 0x03, 0x80, 0xA3, 0xE6, 0x41, 0xF2, 0x0B, 0x03, 0x02, 0x22, ++ 0xEA, 0x54, 0x00, 0x20, 0xFF, 0xF7, 0xDE, 0xF8, 0x4F, 0xE7, 0xDF, 0xF8, ++ 0x10, 0x80, 0x98, 0xF8, 0x76, 0x31, 0xDB, 0x07, 0x3F, 0xF5, 0x55, 0xAF, ++ 0x5D, 0xE7, 0x00, 0xBF, 0xE4, 0xB8, 0x17, 0x00, 0xF0, 0xB5, 0x4C, 0x4B, ++ 0x1B, 0x68, 0x1B, 0x78, 0x01, 0x2B, 0x83, 0xB0, 0x04, 0xD1, 0x4A, 0x4A, ++ 0x13, 0x68, 0x23, 0xF4, 0x00, 0x13, 0x13, 0x60, 0x48, 0x4C, 0x49, 0x4D, ++ 0x23, 0x68, 0x5B, 0x07, 0x4E, 0xD4, 0x48, 0x4E, 0x41, 0xF2, 0x0A, 0x03, ++ 0xEB, 0x5C, 0x5B, 0xB9, 0x44, 0x4A, 0x19, 0x46, 0x02, 0xF5, 0x80, 0x54, ++ 0x80, 0x20, 0x11, 0x72, 0x82, 0xF8, 0x44, 0x00, 0x40, 0x32, 0x94, 0x42, ++ 0xF9, 0xD1, 0xA9, 0x80, 0x29, 0x68, 0x91, 0xF8, 0x70, 0x21, 0x01, 0x2A, ++ 0x5F, 0xD0, 0x00, 0x24, 0x20, 0x46, 0x41, 0xF2, 0x3A, 0x02, 0xA8, 0x54, ++ 0x91, 0xF8, 0x6E, 0x21, 0x91, 0xF8, 0x6F, 0x11, 0x08, 0x20, 0xCD, 0xE9, ++ 0x00, 0x41, 0x38, 0x49, 0xF7, 0xF7, 0xDC, 0xFA, 0x41, 0xF2, 0x0A, 0x03, ++ 0xEB, 0x5C, 0x83, 0xB9, 0x35, 0x49, 0x36, 0x4A, 0x0B, 0x68, 0x36, 0x48, ++ 0x43, 0xF0, 0x04, 0x03, 0x0B, 0x60, 0x13, 0x68, 0x03, 0x80, 0x13, 0x68, ++ 0x1B, 0x0C, 0x1B, 0x04, 0x43, 0xF4, 0xBB, 0x63, 0x43, 0xF0, 0x04, 0x03, ++ 0x13, 0x60, 0x73, 0x68, 0x01, 0x21, 0x43, 0xF0, 0x20, 0x03, 0x04, 0x20, ++ 0x73, 0x60, 0xF5, 0xF7, 0x01, 0xFE, 0x2B, 0x68, 0xD3, 0xF8, 0x68, 0x11, ++ 0x19, 0xB1, 0xB3, 0xF8, 0x6C, 0x21, 0xC8, 0x2A, 0x23, 0xD9, 0x03, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x40, 0xFF, 0xF7, 0xCE, 0xBD, 0x2B, 0x68, 0x25, 0x4A, ++ 0x93, 0xF8, 0x6E, 0x31, 0x24, 0x49, 0x1E, 0x4E, 0x10, 0x68, 0x24, 0x4A, ++ 0xC0, 0x8E, 0x4F, 0xF4, 0xA4, 0x67, 0x07, 0xFB, 0x03, 0x13, 0x03, 0x21, ++ 0x71, 0x77, 0x11, 0x69, 0x20, 0x4A, 0x73, 0x61, 0x01, 0x44, 0xD2, 0xF8, ++ 0xE0, 0x31, 0x06, 0xF1, 0x0C, 0x00, 0x98, 0x47, 0x01, 0x23, 0x33, 0x77, ++ 0x23, 0x68, 0x23, 0xF0, 0x04, 0x03, 0x23, 0x60, 0x92, 0xE7, 0x1A, 0x48, ++ 0x09, 0xF0, 0x60, 0xFF, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x40, 0xFF, 0xF7, ++ 0xA7, 0xBD, 0x91, 0xF8, 0xFC, 0x20, 0x07, 0x2A, 0x9B, 0xD1, 0x01, 0xF1, ++ 0xFD, 0x00, 0x14, 0x49, 0x09, 0xF0, 0x22, 0xFF, 0x41, 0xF2, 0x0A, 0x03, ++ 0xB0, 0xFA, 0x80, 0xF0, 0x40, 0x09, 0xEB, 0x5C, 0x29, 0x68, 0x04, 0x46, ++ 0x8F, 0xE7, 0x00, 0xBF, 0x74, 0x36, 0x17, 0x00, 0x6C, 0x00, 0x32, 0x40, ++ 0x4C, 0x00, 0x32, 0x40, 0xA8, 0xBA, 0x17, 0x00, 0x1C, 0x9E, 0x17, 0x00, ++ 0xCC, 0xBF, 0x15, 0x00, 0x94, 0x40, 0x04, 0x40, 0x20, 0x04, 0x32, 0x40, ++ 0x28, 0x25, 0x17, 0x00, 0xC8, 0x35, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0x00, 0x10, 0x50, 0x40, 0x88, 0x1A, 0x17, 0x00, 0x18, 0x63, 0x18, 0x00, ++ 0x54, 0xBF, 0x15, 0x00, 0x00, 0x22, 0x02, 0x81, 0xE7, 0xF7, 0xE0, 0xBA, ++ 0x2D, 0xE9, 0xF0, 0x41, 0x14, 0x46, 0x52, 0x78, 0x00, 0x2B, 0x18, 0xBF, ++ 0x02, 0x23, 0x52, 0x06, 0x44, 0xBF, 0x08, 0x33, 0xDB, 0xB2, 0x23, 0x44, ++ 0x06, 0x46, 0x9A, 0x7F, 0x08, 0x2A, 0x0D, 0x46, 0x03, 0xD0, 0x00, 0x27, ++ 0x38, 0x46, 0xBD, 0xE8, 0xF0, 0x81, 0xDA, 0x7F, 0x06, 0x2A, 0xF8, 0xD1, ++ 0x93, 0xF8, 0x26, 0x70, 0x00, 0x2F, 0xF4, 0xD1, 0x93, 0xF8, 0x27, 0x80, ++ 0xB8, 0xF1, 0x01, 0x0F, 0x07, 0xD0, 0xB8, 0xF1, 0x02, 0x0F, 0xED, 0xD1, ++ 0x13, 0x49, 0x80, 0x20, 0xF7, 0xF7, 0x2E, 0xFA, 0xE8, 0xE7, 0x93, 0xF8, ++ 0x3A, 0x70, 0x93, 0xF8, 0x3B, 0xC0, 0x93, 0xF8, 0x38, 0x00, 0x93, 0xF8, ++ 0x39, 0x20, 0x0B, 0x68, 0x0D, 0x49, 0x3F, 0x04, 0x47, 0xEA, 0x0C, 0x67, ++ 0x07, 0x43, 0x47, 0xEA, 0x02, 0x27, 0x3A, 0x46, 0x80, 0x20, 0xF7, 0xF7, ++ 0x19, 0xFA, 0x2B, 0x68, 0x9F, 0x42, 0x01, 0xD0, 0x47, 0x46, 0xCF, 0xE7, ++ 0x06, 0x4B, 0x30, 0x78, 0x9B, 0x69, 0x22, 0x46, 0x04, 0xF1, 0x10, 0x01, ++ 0x47, 0x46, 0x98, 0x47, 0xC6, 0xE7, 0x00, 0xBF, 0x08, 0xC0, 0x15, 0x00, ++ 0xE8, 0xBF, 0x15, 0x00, 0x88, 0x1A, 0x17, 0x00, 0xF8, 0xB5, 0x21, 0x4B, ++ 0x21, 0x4D, 0x1E, 0x68, 0x95, 0xF8, 0x44, 0x40, 0xB6, 0xF9, 0x00, 0x70, ++ 0x1F, 0x4B, 0x04, 0xEB, 0x84, 0x06, 0x00, 0x2F, 0x8E, 0x46, 0x03, 0xEB, ++ 0x06, 0x16, 0x23, 0xDB, 0xA7, 0x00, 0x07, 0xEB, 0x04, 0x0C, 0x03, 0xEB, ++ 0x0C, 0x1C, 0xCC, 0xF8, 0x0C, 0x00, 0x10, 0xB1, 0x01, 0x7C, 0x8C, 0xF8, ++ 0x10, 0x10, 0x3C, 0x44, 0x03, 0xEB, 0x04, 0x13, 0x31, 0x46, 0x5A, 0x64, ++ 0xA3, 0xF8, 0x4C, 0xE0, 0x13, 0x48, 0xF5, 0xF7, 0xB5, 0xFF, 0x95, 0xF8, ++ 0x44, 0x20, 0x12, 0x4B, 0x01, 0x32, 0xA3, 0xFB, 0x02, 0x13, 0xDB, 0x09, ++ 0x03, 0xEB, 0x43, 0x03, 0xA2, 0xEB, 0x83, 0x13, 0x85, 0xF8, 0x44, 0x30, ++ 0x30, 0x46, 0xF8, 0xBD, 0x04, 0xEB, 0x84, 0x01, 0x03, 0xEB, 0x01, 0x11, ++ 0xA7, 0x00, 0xB1, 0xF8, 0x4C, 0x10, 0x00, 0x29, 0xD3, 0xD0, 0x08, 0x49, ++ 0x08, 0x48, 0xC6, 0x22, 0xF7, 0xF7, 0xBA, 0xFB, 0x00, 0x26, 0xED, 0xE7, ++ 0x38, 0x36, 0x17, 0x00, 0xB0, 0xDE, 0x17, 0x00, 0xE0, 0x63, 0x18, 0x00, ++ 0xE8, 0xDE, 0x17, 0x00, 0xAB, 0xAA, 0xAA, 0xAA, 0x70, 0x79, 0x15, 0x00, ++ 0x14, 0xC0, 0x15, 0x00, 0x70, 0xB5, 0x0C, 0x4D, 0x42, 0x69, 0x04, 0x46, ++ 0x04, 0x21, 0x00, 0x20, 0xFF, 0xF7, 0xA6, 0xFF, 0x21, 0x46, 0x28, 0x46, ++ 0xF5, 0xF7, 0xCC, 0xFF, 0xA5, 0xF1, 0x08, 0x00, 0x21, 0x46, 0xF5, 0xF7, ++ 0x77, 0xFF, 0x05, 0x4B, 0xA5, 0xF1, 0x20, 0x00, 0xD3, 0xF8, 0x38, 0x31, ++ 0xBD, 0xE8, 0x70, 0x40, 0x18, 0x47, 0x00, 0xBF, 0x08, 0xDF, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x47, 0xB3, 0x4B, 0x01, 0xF0, ++ 0x7C, 0x04, 0x1A, 0x7A, 0x04, 0x3C, 0x00, 0xEB, 0x02, 0x0C, 0x01, 0xF4, ++ 0x80, 0x6E, 0x18, 0x2C, 0x0E, 0xD8, 0xDF, 0xE8, 0x04, 0xF0, 0x54, 0x0D, ++ 0x0D, 0x0D, 0x58, 0x0D, 0x0D, 0x0D, 0x8D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, ++ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0xB5, 0x00, ++ 0x00, 0x24, 0xA7, 0x4D, 0x2D, 0x68, 0x2D, 0x78, 0xAD, 0x07, 0x03, 0xD5, ++ 0x01, 0xF0, 0x3C, 0x01, 0x3C, 0x29, 0x02, 0xD0, 0x20, 0x46, 0xBD, 0xE8, ++ 0xF0, 0x87, 0xBE, 0xF1, 0x00, 0x0F, 0x00, 0xF0, 0xD1, 0x80, 0xBC, 0xF8, ++ 0x02, 0x10, 0x9E, 0x7A, 0x9E, 0x4C, 0x8D, 0x0B, 0x4F, 0xF4, 0xA4, 0x61, ++ 0xC5, 0xEB, 0x05, 0x17, 0x01, 0xFB, 0x06, 0xF1, 0x01, 0xEB, 0xC7, 0x01, ++ 0x21, 0x44, 0x2F, 0x01, 0x91, 0xF8, 0x3B, 0xE2, 0xBE, 0xF1, 0x00, 0x0F, ++ 0x00, 0xF0, 0xCC, 0x80, 0x91, 0xF8, 0x38, 0x12, 0x01, 0x29, 0x00, 0xF0, ++ 0xEB, 0x80, 0x02, 0x29, 0x00, 0xF0, 0xC1, 0x80, 0x0A, 0x1F, 0x01, 0x2A, ++ 0x40, 0xF2, 0xBD, 0x80, 0x1A, 0x7A, 0x04, 0x32, 0x1A, 0x72, 0xDC, 0xF8, ++ 0x00, 0x00, 0xC1, 0x17, 0xC3, 0xE9, 0x04, 0x01, 0x4F, 0xF4, 0xA4, 0x62, ++ 0x02, 0xFB, 0x06, 0xF2, 0x79, 0x1B, 0x02, 0xF5, 0xEC, 0x72, 0x02, 0xEB, ++ 0xC1, 0x02, 0x22, 0x44, 0x1A, 0x62, 0x01, 0x24, 0xC2, 0xE7, 0x14, 0x1D, ++ 0x1C, 0x72, 0x01, 0x24, 0xB5, 0xE7, 0x02, 0xF1, 0x08, 0x04, 0x1C, 0x72, ++ 0x30, 0xF8, 0x02, 0x80, 0xBC, 0xF8, 0x06, 0x40, 0x9C, 0xF8, 0x02, 0xA0, ++ 0x93, 0xF8, 0x30, 0x90, 0x4F, 0xEA, 0x08, 0x28, 0x1F, 0xFA, 0x88, 0xF8, ++ 0x46, 0x46, 0xF7, 0x17, 0x44, 0xEA, 0x07, 0x06, 0xBC, 0xF8, 0x04, 0x40, ++ 0x4A, 0xEA, 0x04, 0x44, 0x44, 0xEA, 0x08, 0x04, 0x49, 0xF0, 0x03, 0x09, ++ 0xC3, 0xE9, 0x04, 0x46, 0x83, 0xF8, 0x30, 0x90, 0xBE, 0xF1, 0x00, 0x0F, ++ 0x5F, 0xD0, 0x9E, 0x7A, 0xBC, 0xF8, 0x02, 0x50, 0x4F, 0xF4, 0xA4, 0x64, ++ 0x04, 0xFB, 0x06, 0xF4, 0xAD, 0x0B, 0x6E, 0x4E, 0x04, 0xF5, 0xEC, 0x74, ++ 0xC5, 0xEB, 0x05, 0x15, 0x04, 0xEB, 0xC5, 0x04, 0x34, 0x44, 0x1C, 0x62, ++ 0x01, 0x24, 0x80, 0xE7, 0xBE, 0xF1, 0x00, 0x0F, 0x50, 0xD0, 0x9E, 0x7A, ++ 0xBC, 0xF8, 0x02, 0x50, 0x4F, 0xF4, 0xA4, 0x64, 0x04, 0xFB, 0x06, 0xF4, ++ 0xAD, 0x0B, 0x63, 0x4E, 0x04, 0xF5, 0xEC, 0x74, 0xC5, 0xEB, 0x05, 0x15, ++ 0x04, 0xEB, 0xC5, 0x04, 0x34, 0x44, 0x02, 0xF1, 0x08, 0x05, 0x1D, 0x72, ++ 0xBC, 0xF8, 0x04, 0x60, 0x93, 0xF8, 0x30, 0x80, 0x1C, 0x62, 0x84, 0x5A, ++ 0xBC, 0xF8, 0x06, 0x50, 0x5D, 0x61, 0x44, 0xEA, 0x06, 0x44, 0x48, 0xF0, ++ 0x02, 0x05, 0x1C, 0x61, 0x83, 0xF8, 0x30, 0x50, 0x01, 0x24, 0x58, 0xE7, ++ 0xBE, 0xF1, 0x00, 0x0F, 0x2F, 0xD0, 0x9E, 0x7A, 0xBC, 0xF8, 0x02, 0x50, ++ 0x4F, 0xF4, 0xA4, 0x64, 0x04, 0xFB, 0x06, 0xF4, 0xAD, 0x0B, 0x4F, 0x4E, ++ 0x04, 0xF5, 0xEC, 0x74, 0xC5, 0xEB, 0x05, 0x15, 0x04, 0xEB, 0xC5, 0x04, ++ 0x34, 0x44, 0x02, 0xF1, 0x12, 0x05, 0x66, 0x46, 0x1D, 0x72, 0x56, 0xF8, ++ 0x02, 0x7F, 0x93, 0xF8, 0x30, 0x50, 0x76, 0x68, 0x1C, 0x62, 0x45, 0xF0, ++ 0x02, 0x04, 0x83, 0xF8, 0x30, 0x40, 0xC3, 0xE9, 0x04, 0x76, 0x01, 0x24, ++ 0x33, 0xE7, 0x5C, 0x7A, 0x42, 0x4D, 0x4F, 0xF4, 0x1E, 0x76, 0x06, 0xFB, ++ 0x04, 0x54, 0xA8, 0xE7, 0x5C, 0x7A, 0x3F, 0x4D, 0x4F, 0xF4, 0x1E, 0x76, ++ 0x06, 0xFB, 0x04, 0x54, 0xB7, 0xE7, 0x5C, 0x7A, 0x3B, 0x4D, 0x4F, 0xF4, ++ 0x1E, 0x76, 0x06, 0xFB, 0x04, 0x54, 0xD8, 0xE7, 0x59, 0x7A, 0x39, 0x4D, ++ 0x4F, 0xF4, 0x1E, 0x74, 0x04, 0xFB, 0x01, 0xF4, 0x29, 0x19, 0x91, 0xF8, ++ 0x98, 0x10, 0x01, 0x29, 0x43, 0xD0, 0x02, 0x29, 0x04, 0xD1, 0x34, 0x48, ++ 0xF7, 0xF7, 0x36, 0xF8, 0x00, 0x24, 0x15, 0xE7, 0x0A, 0x1F, 0x01, 0x2A, ++ 0xF7, 0xD9, 0x18, 0x7A, 0xBC, 0xF8, 0x02, 0x10, 0x9D, 0x7A, 0x2B, 0x4E, ++ 0x04, 0x30, 0x18, 0x72, 0xDC, 0xF8, 0x00, 0x40, 0x4F, 0xF4, 0xA4, 0x62, ++ 0x02, 0xFB, 0x05, 0xF2, 0x89, 0x0B, 0xE5, 0x17, 0xC1, 0xEB, 0x01, 0x11, ++ 0x02, 0xF5, 0xEC, 0x72, 0xC3, 0xE9, 0x04, 0x45, 0x02, 0xEB, 0xC1, 0x02, ++ 0x32, 0x44, 0x92, 0xF8, 0x63, 0x10, 0x00, 0x29, 0xDE, 0xD0, 0x1A, 0x62, ++ 0x01, 0x24, 0xF3, 0xE6, 0x19, 0x7A, 0x93, 0xF8, 0x30, 0xE0, 0x08, 0x31, ++ 0x19, 0x72, 0x82, 0x5A, 0x9C, 0xF8, 0x02, 0x80, 0xBC, 0xF8, 0x04, 0x00, ++ 0xBC, 0xF8, 0x06, 0x90, 0x12, 0x02, 0x92, 0xB2, 0xD1, 0x17, 0x48, 0xEA, ++ 0x00, 0x40, 0x49, 0xEA, 0x01, 0x09, 0x02, 0x43, 0x4E, 0xF0, 0x03, 0x0E, ++ 0xC3, 0xE9, 0x04, 0x29, 0x83, 0xF8, 0x30, 0xE0, 0x08, 0xE7, 0x19, 0x7A, ++ 0x93, 0xF8, 0x30, 0x70, 0x08, 0x31, 0x19, 0x72, 0x81, 0x5A, 0xBC, 0xF8, ++ 0x04, 0x80, 0x9C, 0xF8, 0x02, 0x00, 0xBC, 0xF8, 0x06, 0x60, 0x09, 0x02, ++ 0x89, 0xB2, 0x04, 0xF1, 0x38, 0x02, 0x40, 0xEA, 0x08, 0x44, 0x0C, 0x43, ++ 0xC9, 0x17, 0x47, 0xF0, 0x03, 0x07, 0x0E, 0x43, 0xC3, 0xE9, 0x04, 0x46, ++ 0x2A, 0x44, 0x83, 0xF8, 0x30, 0x70, 0xC0, 0xE7, 0xB0, 0xDE, 0x17, 0x00, ++ 0x34, 0x36, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, 0xA0, 0x65, 0x17, 0x00, ++ 0x68, 0x65, 0x17, 0x00, 0x34, 0xC0, 0x15, 0x00, 0x70, 0xB5, 0x18, 0x4E, ++ 0x18, 0x4A, 0xB3, 0x7A, 0x75, 0x7A, 0x12, 0x7C, 0x1B, 0x02, 0x43, 0xEA, ++ 0x05, 0x43, 0xF5, 0x7A, 0x04, 0x46, 0x00, 0x6E, 0x43, 0xEA, 0x05, 0x63, ++ 0xFF, 0x2A, 0x0D, 0x46, 0x43, 0xEA, 0x00, 0x03, 0x17, 0xD0, 0x41, 0xF0, ++ 0x80, 0x05, 0x43, 0xF0, 0x80, 0x03, 0xEA, 0x07, 0x48, 0xBF, 0x43, 0xF0, ++ 0x40, 0x03, 0x0D, 0x4A, 0x58, 0xBF, 0x23, 0xF0, 0x40, 0x03, 0x23, 0x66, ++ 0x20, 0x46, 0xD2, 0xF8, 0xA8, 0x32, 0x98, 0x47, 0x32, 0x6C, 0x29, 0x46, ++ 0x20, 0x46, 0xBD, 0xE8, 0x70, 0x40, 0xFF, 0xF7, 0xEF, 0xBD, 0x29, 0x06, ++ 0x58, 0xBF, 0x23, 0xF0, 0x80, 0x03, 0xE6, 0xD5, 0xE3, 0xE7, 0x00, 0xBF, ++ 0xB0, 0xDE, 0x17, 0x00, 0x00, 0x88, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0xF8, 0xB5, 0x21, 0x4B, 0x21, 0x4E, 0x1B, 0x7C, 0xFF, 0x2B, 0x04, 0x46, ++ 0x0D, 0x46, 0x21, 0xD0, 0xB2, 0x7A, 0xFF, 0x2A, 0x32, 0xD0, 0x01, 0xF0, ++ 0x01, 0x01, 0x45, 0xF0, 0x80, 0x05, 0x77, 0x7A, 0x20, 0x6E, 0x13, 0x02, ++ 0x43, 0xEA, 0x07, 0x43, 0x03, 0x43, 0x43, 0xF0, 0x82, 0x03, 0x11, 0xB3, ++ 0x43, 0xF0, 0x40, 0x03, 0x16, 0x49, 0x23, 0x66, 0x00, 0x22, 0xD1, 0xF8, ++ 0xA8, 0x32, 0x86, 0xF8, 0x32, 0x20, 0x20, 0x46, 0x98, 0x47, 0x32, 0x6C, ++ 0x29, 0x46, 0x20, 0x46, 0xBD, 0xE8, 0xF8, 0x40, 0xFF, 0xF7, 0xB8, 0xBD, ++ 0xB3, 0x7A, 0x71, 0x7A, 0x02, 0x6E, 0x1B, 0x02, 0x43, 0xEA, 0x01, 0x43, ++ 0x13, 0x43, 0x2A, 0x06, 0x0D, 0xD4, 0x23, 0xF0, 0x80, 0x03, 0x05, 0xF0, ++ 0x01, 0x01, 0x43, 0xF0, 0x02, 0x03, 0x00, 0x29, 0xDC, 0xD1, 0x23, 0xF0, ++ 0x40, 0x03, 0xDB, 0xE7, 0x00, 0x21, 0x80, 0x25, 0xCD, 0xE7, 0x05, 0xF0, ++ 0x01, 0x01, 0xD0, 0xE7, 0x00, 0x88, 0x17, 0x00, 0xB0, 0xDE, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x32, 0x4B, 0x01, 0x88, 0x70, 0xB4, 0x19, 0x80, ++ 0xC2, 0x8A, 0x5A, 0x80, 0x01, 0xF0, 0x88, 0x06, 0xC2, 0xF3, 0x0B, 0x14, ++ 0x00, 0x25, 0x02, 0xF0, 0x0F, 0x02, 0x88, 0x2E, 0x9C, 0x80, 0x9A, 0x71, ++ 0x8C, 0xB2, 0x83, 0xF8, 0x30, 0x50, 0x45, 0xD0, 0xDD, 0x71, 0x04, 0xF4, ++ 0x40, 0x72, 0xB2, 0xF5, 0x40, 0x7F, 0x04, 0xF0, 0xFC, 0x05, 0x0C, 0xBF, ++ 0x1E, 0x22, 0x18, 0x22, 0x88, 0x2D, 0x08, 0xBF, 0x02, 0x32, 0x0E, 0x04, ++ 0x44, 0xBF, 0x04, 0x32, 0xD2, 0xB2, 0x1A, 0x72, 0x02, 0x79, 0xD5, 0x07, ++ 0x44, 0xBF, 0x08, 0x22, 0x83, 0xF8, 0x30, 0x20, 0xE4, 0x05, 0x12, 0xD5, ++ 0x02, 0x8A, 0x9A, 0x84, 0x42, 0x8A, 0xDA, 0x84, 0x82, 0x8A, 0x1A, 0x85, ++ 0x02, 0x88, 0x91, 0x05, 0x12, 0xD5, 0xD2, 0x05, 0x18, 0xD5, 0x02, 0x8B, ++ 0x5A, 0x85, 0x42, 0x8B, 0x9A, 0x85, 0x82, 0x8B, 0xDA, 0x85, 0x70, 0xBC, ++ 0x70, 0x47, 0x82, 0x88, 0x9A, 0x84, 0xC2, 0x88, 0xDA, 0x84, 0x02, 0x89, ++ 0x1A, 0x85, 0x02, 0x88, 0x91, 0x05, 0xEC, 0xD4, 0x42, 0x89, 0x5A, 0x85, ++ 0x82, 0x89, 0x9A, 0x85, 0xC2, 0x89, 0xDA, 0x85, 0x70, 0xBC, 0x70, 0x47, ++ 0x02, 0x8A, 0x5A, 0x85, 0x42, 0x8A, 0x9A, 0x85, 0x82, 0x8A, 0xDA, 0x85, ++ 0x70, 0xBC, 0x70, 0x47, 0x04, 0xF4, 0x40, 0x72, 0xB2, 0xF5, 0x40, 0x7F, ++ 0x0C, 0xBF, 0xC5, 0x8B, 0x05, 0x8B, 0x05, 0xF0, 0x07, 0x05, 0xDD, 0x71, ++ 0xB1, 0xE7, 0x00, 0xBF, 0xB0, 0xDE, 0x17, 0x00, 0xF8, 0xB5, 0x05, 0x22, ++ 0x18, 0x23, 0x0C, 0x21, 0x41, 0xF2, 0x06, 0x40, 0xF5, 0xF7, 0x74, 0xF8, ++ 0x0F, 0x4A, 0x03, 0x46, 0x51, 0x7A, 0x0F, 0x48, 0x94, 0x69, 0x4F, 0xF4, ++ 0x1E, 0x75, 0x05, 0xFB, 0x01, 0x01, 0xD2, 0xE9, 0x04, 0x67, 0x51, 0xF8, ++ 0x26, 0x0F, 0x89, 0x88, 0x99, 0x80, 0xC3, 0xE9, 0x02, 0x67, 0x18, 0x60, ++ 0x91, 0x7A, 0x99, 0x74, 0xC4, 0xF3, 0x80, 0x24, 0x1C, 0x74, 0x12, 0x6A, ++ 0x92, 0xF8, 0x61, 0x20, 0x5A, 0x74, 0x18, 0x46, 0xBD, 0xE8, 0xF8, 0x40, ++ 0xF5, 0xF7, 0x84, 0xB8, 0xB0, 0xDE, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0xDF, 0xF8, 0x3C, 0x82, 0xD8, 0xF8, 0x00, 0x40, ++ 0x27, 0x78, 0x87, 0xB0, 0x17, 0xF0, 0x01, 0x07, 0x04, 0x46, 0x03, 0x93, ++ 0x08, 0xD0, 0x43, 0x6D, 0x03, 0xF0, 0x07, 0x03, 0x02, 0x2B, 0x7F, 0xD0, ++ 0x38, 0x46, 0x07, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x80, 0x4D, 0x89, 0x46, ++ 0x00, 0x2A, 0x40, 0xF0, 0xA2, 0x80, 0x02, 0x8E, 0x2B, 0x7A, 0xC6, 0x69, ++ 0xD4, 0x1A, 0x03, 0x9A, 0xA4, 0xB2, 0x10, 0x31, 0x12, 0xB1, 0x07, 0x2C, ++ 0x40, 0xF2, 0xA9, 0x80, 0x08, 0x22, 0x48, 0x46, 0xFA, 0xF7, 0x92, 0xFF, ++ 0x29, 0x7A, 0x8A, 0xB2, 0xD6, 0xE9, 0x02, 0x03, 0x08, 0x3C, 0x01, 0x33, ++ 0xA5, 0xB2, 0x1C, 0x1A, 0xA4, 0xB2, 0x4B, 0x19, 0x9C, 0x42, 0x01, 0x44, ++ 0x80, 0xF2, 0x82, 0x80, 0xDF, 0xF8, 0xD4, 0xA1, 0x13, 0x1B, 0x1D, 0x44, ++ 0xA2, 0x1A, 0x92, 0xB2, 0x48, 0x46, 0xAD, 0xB2, 0xFA, 0xF7, 0x7A, 0xFF, ++ 0x00, 0x22, 0x95, 0xB1, 0xDA, 0xF8, 0x00, 0x30, 0x76, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x93, 0x42, 0x4D, 0xDB, 0xD6, 0xE9, 0x02, 0x14, 0x01, 0x34, ++ 0x64, 0x1A, 0xA4, 0xB2, 0xAC, 0x42, 0xE7, 0xD3, 0x2C, 0x46, 0x2A, 0x46, ++ 0x48, 0x46, 0xFA, 0xF7, 0x65, 0xFF, 0xDF, 0xF8, 0x98, 0xE1, 0x0D, 0xF1, ++ 0x10, 0x0C, 0x08, 0x25, 0xD6, 0xE9, 0x02, 0x32, 0x01, 0x32, 0x98, 0xB2, ++ 0x92, 0xB2, 0xA2, 0xEB, 0x00, 0x0A, 0x1F, 0xFA, 0x8A, 0xFA, 0x29, 0x19, ++ 0x51, 0x45, 0x23, 0x44, 0x3B, 0xDD, 0xAA, 0xEB, 0x04, 0x0A, 0x1F, 0xFA, ++ 0x8A, 0xFA, 0x0A, 0xF1, 0xFF, 0x3B, 0xBA, 0xF1, 0x00, 0x0F, 0x37, 0xD0, ++ 0x82, 0x1A, 0x14, 0x44, 0x25, 0x44, 0xAD, 0xB2, 0x59, 0x1C, 0x59, 0x44, ++ 0xAC, 0xEB, 0x03, 0x00, 0x1A, 0x78, 0xC2, 0x54, 0x01, 0x33, 0x8B, 0x42, ++ 0xFA, 0xD1, 0xD4, 0x44, 0x65, 0xB3, 0xDE, 0xF8, 0x00, 0x30, 0x76, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x24, 0xA3, 0x42, 0xD2, 0xDA, 0x00, 0x2E, ++ 0xD0, 0xD1, 0x47, 0x49, 0x47, 0x48, 0x40, 0xF2, 0x66, 0x42, 0xF7, 0xF7, ++ 0x6F, 0xF8, 0x7F, 0xE7, 0xFF, 0xF7, 0x40, 0xFF, 0x00, 0x27, 0x38, 0x46, ++ 0x07, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x00, 0x2E, 0xAF, 0xD1, 0x3F, 0x49, ++ 0x3F, 0x48, 0x40, 0xF2, 0x3C, 0x42, 0xF7, 0xF7, 0x5F, 0xF8, 0x38, 0x46, ++ 0x07, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xAA, 0x46, 0x05, 0xF1, 0xFF, 0x3B, ++ 0x00, 0x25, 0xCB, 0xE7, 0x01, 0x44, 0x8A, 0x1A, 0x95, 0xB2, 0xD2, 0xE7, ++ 0x03, 0x9B, 0x00, 0x2B, 0x3C, 0xD1, 0xDD, 0xE9, 0x04, 0x23, 0xC9, 0xE9, ++ 0x04, 0x23, 0x01, 0x27, 0x38, 0x46, 0x07, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, ++ 0x2A, 0x44, 0x94, 0xB2, 0x95, 0xE7, 0x29, 0x6A, 0xEB, 0x79, 0x00, 0x93, ++ 0x58, 0x31, 0x05, 0xF1, 0x2A, 0x03, 0x05, 0xF1, 0x24, 0x02, 0x48, 0x46, ++ 0xFA, 0xF7, 0xCE, 0xFE, 0x29, 0x7A, 0x23, 0x8E, 0xE6, 0x69, 0x5C, 0x1A, ++ 0xA4, 0xB2, 0x8A, 0xB2, 0x5C, 0xE7, 0xB5, 0x68, 0x03, 0x91, 0x22, 0x46, ++ 0x48, 0x46, 0x1D, 0x44, 0xFA, 0xF7, 0xE6, 0xFE, 0x03, 0x99, 0xC4, 0xF1, ++ 0x08, 0x06, 0x04, 0xAB, 0xF6, 0xB2, 0x21, 0x44, 0xF2, 0x18, 0xC9, 0x1A, ++ 0xC8, 0x5C, 0x03, 0xF8, 0x01, 0x0B, 0x9A, 0x42, 0xFA, 0xD1, 0xD6, 0xF1, ++ 0x08, 0x06, 0x07, 0xD0, 0x2B, 0x46, 0xD2, 0x1A, 0x35, 0x44, 0x19, 0x78, ++ 0xD1, 0x54, 0x01, 0x33, 0x9D, 0x42, 0xFA, 0xD1, 0x48, 0x46, 0xFA, 0xF7, ++ 0x69, 0xFF, 0x04, 0x9A, 0xD9, 0xF8, 0x00, 0x30, 0x9A, 0x42, 0x0D, 0xD0, ++ 0xD8, 0xF8, 0x00, 0x30, 0x1B, 0x78, 0x9B, 0x07, 0x05, 0xD5, 0x03, 0x20, ++ 0xD8, 0xF7, 0xCE, 0xF9, 0x0F, 0x4B, 0x98, 0x42, 0x12, 0xD1, 0xFF, 0xF7, ++ 0xD1, 0xFE, 0x0D, 0xE7, 0xD9, 0xF8, 0x04, 0x30, 0x05, 0x9A, 0x9A, 0x42, ++ 0xEC, 0xD1, 0xD8, 0xF8, 0x00, 0x30, 0x1B, 0x78, 0x9A, 0x07, 0xA6, 0xD5, ++ 0x03, 0x20, 0xD8, 0xF7, 0xBB, 0xF9, 0x06, 0x4B, 0x98, 0x42, 0xA0, 0xD0, ++ 0x05, 0x48, 0xF6, 0xF7, 0xA1, 0xFD, 0xF9, 0xE6, 0xB0, 0xDE, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xA0, 0x96, 0x15, 0x00, 0x1C, 0xDF, 0x44, 0x21, ++ 0x44, 0xC0, 0x15, 0x00, 0x34, 0x36, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x10, 0xB5, 0x10, 0x48, 0xF5, 0xF7, 0xF8, 0xFB, 0x10, 0xB1, 0x04, 0x46, ++ 0x20, 0x46, 0x10, 0xBD, 0x0D, 0x48, 0xF5, 0xF7, 0xF1, 0xFB, 0x0D, 0x4B, ++ 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x04, 0x46, 0x06, 0xDB, ++ 0x62, 0x69, 0x04, 0x21, 0x00, 0x20, 0xFF, 0xF7, 0xC7, 0xFB, 0x20, 0x46, ++ 0x10, 0xBD, 0x00, 0x28, 0xF6, 0xD1, 0x06, 0x49, 0x06, 0x48, 0x40, 0xF2, ++ 0xEA, 0x42, 0xF6, 0xF7, 0xEB, 0xFF, 0xEF, 0xE7, 0x00, 0xDF, 0x17, 0x00, ++ 0x08, 0xDF, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x54, 0xC0, 0x15, 0x00, 0x10, 0xB5, 0x04, 0x46, 0x00, 0x20, 0x63, 0x79, ++ 0x62, 0x69, 0x83, 0x42, 0x14, 0xBF, 0x18, 0x21, 0x08, 0x21, 0xFF, 0xF7, ++ 0xA7, 0xFB, 0x08, 0xB1, 0xA3, 0x89, 0x83, 0x64, 0x10, 0xBD, 0x00, 0xBF, ++ 0x2D, 0xE9, 0xF0, 0x47, 0xA3, 0x4F, 0x8A, 0xB0, 0x05, 0x46, 0x14, 0x46, ++ 0x1A, 0xB3, 0x3E, 0x88, 0x97, 0xF8, 0x07, 0x80, 0x16, 0xF4, 0x80, 0x66, ++ 0x22, 0xD1, 0x97, 0xF8, 0x06, 0xA0, 0xBA, 0xF1, 0x00, 0x0F, 0x6A, 0xD0, ++ 0xBC, 0x6D, 0xBA, 0x88, 0x14, 0xB9, 0x31, 0xE1, 0x24, 0x68, 0xEC, 0xB1, ++ 0xA3, 0x79, 0x8B, 0x42, 0xFA, 0xD1, 0xE3, 0x79, 0x43, 0x45, 0xF7, 0xD1, ++ 0x63, 0x89, 0x93, 0x42, 0xF4, 0xD1, 0x23, 0x7A, 0x53, 0x45, 0x00, 0xF0, ++ 0x90, 0x80, 0x4F, 0xF0, 0x00, 0x0A, 0x50, 0x46, 0x0A, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x87, 0x3E, 0x88, 0x16, 0xF4, 0x80, 0x66, 0x90, 0x46, 0xDC, 0xD0, ++ 0xBC, 0x6D, 0xBA, 0x88, 0x97, 0xF8, 0x06, 0xA0, 0x00, 0x2C, 0xE1, 0xD1, ++ 0xBA, 0xF1, 0x00, 0x0F, 0xEB, 0xD1, 0x03, 0x91, 0xFF, 0xF7, 0x88, 0xFF, ++ 0x01, 0x26, 0x03, 0x99, 0x81, 0x71, 0x80, 0xF8, 0x07, 0x80, 0x06, 0x72, ++ 0xBA, 0x88, 0x80, 0xF8, 0x04, 0xA0, 0x39, 0x7A, 0x82, 0x4B, 0xC0, 0xF8, ++ 0x10, 0xA0, 0x41, 0x72, 0x19, 0x69, 0xDF, 0xF8, 0x0C, 0x92, 0x80, 0x4B, ++ 0x42, 0x81, 0x01, 0xF5, 0xC3, 0x31, 0x83, 0x63, 0xC0, 0x63, 0xD9, 0xF8, ++ 0xE0, 0x31, 0x04, 0x46, 0xA0, 0x31, 0x34, 0x30, 0x98, 0x47, 0x97, 0xF8, ++ 0x30, 0x30, 0xDA, 0x07, 0x00, 0xF1, 0xC9, 0x80, 0x2B, 0x6E, 0x23, 0xF0, ++ 0x20, 0x03, 0x2B, 0x66, 0xD9, 0xF8, 0xE8, 0x32, 0x01, 0x21, 0x28, 0x46, ++ 0x98, 0x47, 0x3B, 0x6C, 0xFA, 0x69, 0x73, 0x48, 0xC4, 0xE9, 0x04, 0x23, ++ 0x97, 0xF8, 0x31, 0x30, 0x63, 0x71, 0x2B, 0x8E, 0xA3, 0x81, 0x21, 0x46, ++ 0xF5, 0xF7, 0x08, 0xFB, 0x6B, 0x4B, 0x4F, 0xF0, 0x01, 0x0A, 0x1B, 0x69, ++ 0xA3, 0x61, 0x50, 0x46, 0x0A, 0xB0, 0xBD, 0xE8, 0xF0, 0x87, 0x97, 0xF8, ++ 0x30, 0x30, 0xD8, 0x07, 0x1D, 0xD5, 0x68, 0x4A, 0x01, 0x23, 0xD2, 0xF8, ++ 0xCC, 0x62, 0x04, 0xA9, 0x1A, 0x46, 0x28, 0x46, 0xB0, 0x47, 0x00, 0x28, ++ 0x9B, 0xD0, 0x2B, 0x8E, 0x63, 0x4A, 0x08, 0x3B, 0x12, 0x68, 0x2B, 0x86, ++ 0x13, 0x78, 0x99, 0x07, 0x0B, 0xD5, 0x6B, 0x6D, 0x03, 0xF0, 0x3C, 0x02, ++ 0x3C, 0x2A, 0x06, 0xD1, 0x23, 0xF0, 0x7C, 0x03, 0x43, 0xF4, 0x00, 0x53, ++ 0x43, 0xF0, 0x08, 0x03, 0x6B, 0x65, 0x5B, 0x4B, 0xB8, 0x7A, 0x4F, 0xF4, ++ 0xA4, 0x62, 0x02, 0xFB, 0x00, 0x30, 0x90, 0xF8, 0xC3, 0x34, 0x00, 0x2B, ++ 0x6D, 0xD1, 0x54, 0x4B, 0x28, 0x46, 0xD3, 0xF8, 0xE8, 0x32, 0x03, 0x21, ++ 0x98, 0x47, 0x4F, 0xF0, 0x01, 0x0A, 0x50, 0x46, 0x0A, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x87, 0x29, 0x8E, 0x94, 0xF8, 0x09, 0x80, 0xA3, 0x89, 0xDF, 0xF8, ++ 0x30, 0x91, 0xA1, 0xEB, 0x08, 0x08, 0x1F, 0xFA, 0x88, 0xF8, 0x43, 0x44, ++ 0x0A, 0xF1, 0x01, 0x0A, 0x84, 0xF8, 0x08, 0xA0, 0xA3, 0x81, 0x97, 0xF8, ++ 0x30, 0x30, 0xDB, 0x07, 0x22, 0xD5, 0xB6, 0xFA, 0x86, 0xF3, 0xD9, 0xF8, ++ 0xCC, 0x72, 0x5B, 0x09, 0x00, 0x22, 0x04, 0xF1, 0x1C, 0x01, 0x28, 0x46, ++ 0xB8, 0x47, 0x00, 0x28, 0x4C, 0xD0, 0x2B, 0x6E, 0x00, 0x2E, 0x57, 0xD0, ++ 0x61, 0x7A, 0x22, 0x69, 0x23, 0xF0, 0x20, 0x03, 0x43, 0xF0, 0x40, 0x03, ++ 0x2B, 0x66, 0x41, 0x44, 0x00, 0x23, 0x01, 0x93, 0x00, 0x93, 0xD9, 0xF8, ++ 0xA4, 0x62, 0x89, 0xB2, 0x28, 0x46, 0xB0, 0x47, 0x23, 0x69, 0x43, 0x44, ++ 0x23, 0x61, 0x87, 0xE7, 0x01, 0x27, 0x2B, 0x6E, 0x22, 0x69, 0x23, 0xF0, ++ 0x20, 0x03, 0x43, 0xF0, 0x40, 0x03, 0x2B, 0x66, 0x00, 0x23, 0xCD, 0xE9, ++ 0x00, 0x33, 0x28, 0x46, 0xD9, 0xF8, 0xA4, 0x52, 0xA8, 0x47, 0x23, 0x69, ++ 0x43, 0x44, 0x23, 0x61, 0x00, 0x2E, 0x7F, 0xF4, 0x73, 0xAF, 0x20, 0x46, ++ 0xFF, 0xF7, 0xEC, 0xFE, 0x62, 0x69, 0x39, 0x46, 0x00, 0x20, 0xFF, 0xF7, ++ 0x99, 0xFA, 0xD9, 0xF8, 0xD8, 0x31, 0x04, 0xF1, 0x34, 0x00, 0x98, 0x47, ++ 0x21, 0x46, 0x20, 0x48, 0xF5, 0xF7, 0xBA, 0xFA, 0x22, 0x48, 0x21, 0x46, ++ 0xF5, 0xF7, 0x66, 0xFA, 0x5C, 0xE7, 0xEA, 0x69, 0x00, 0xF2, 0xC4, 0x41, ++ 0x92, 0x68, 0x23, 0x46, 0x63, 0x30, 0xFF, 0xF7, 0x31, 0xFA, 0x01, 0x28, ++ 0x87, 0xD1, 0x04, 0xE7, 0x61, 0x7A, 0x41, 0x44, 0x89, 0xB2, 0x04, 0x27, ++ 0xC5, 0xE7, 0x32, 0x46, 0x53, 0x46, 0xD9, 0xF8, 0xCC, 0x62, 0x04, 0xF1, ++ 0x1C, 0x01, 0x28, 0x46, 0xB0, 0x47, 0x2D, 0xE7, 0xA0, 0x89, 0x61, 0x7A, ++ 0x22, 0x69, 0x23, 0xF0, 0x20, 0x03, 0x43, 0xF0, 0x40, 0x03, 0x08, 0x38, ++ 0xA0, 0x81, 0x41, 0x44, 0x2B, 0x66, 0x28, 0x46, 0x33, 0x46, 0xCD, 0xE9, ++ 0x00, 0x66, 0xD9, 0xF8, 0xA4, 0x52, 0x89, 0xB2, 0xA8, 0x47, 0x23, 0x69, ++ 0x43, 0x44, 0x23, 0x61, 0x01, 0x27, 0xB8, 0xE7, 0xA2, 0x46, 0xDC, 0xE6, ++ 0xB0, 0xDE, 0x17, 0x00, 0x00, 0x10, 0x50, 0x40, 0xC5, 0xD3, 0x14, 0x00, ++ 0x08, 0xDF, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x34, 0x36, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0x00, 0xDF, 0x17, 0x00, 0xF8, 0xB5, 0x03, 0x88, ++ 0x13, 0x4D, 0x13, 0xF4, 0x00, 0x6F, 0x04, 0x46, 0xC3, 0x8A, 0x0B, 0xD1, ++ 0x05, 0xF1, 0x60, 0x07, 0x00, 0xF1, 0x0A, 0x06, 0x30, 0x68, 0xB2, 0x88, ++ 0xBA, 0x80, 0x28, 0x66, 0xA5, 0xF8, 0x66, 0x30, 0x01, 0x20, 0xF8, 0xBD, ++ 0xB5, 0xF8, 0x66, 0x20, 0x9A, 0x42, 0x04, 0xD0, 0x00, 0xF1, 0x0A, 0x06, ++ 0x05, 0xF1, 0x60, 0x07, 0xEE, 0xE7, 0x05, 0xF1, 0x60, 0x07, 0x00, 0xF1, ++ 0x0A, 0x06, 0x39, 0x46, 0x30, 0x46, 0x06, 0x22, 0x09, 0xF0, 0xC6, 0xF8, ++ 0x00, 0x28, 0xEA, 0xD0, 0xE3, 0x8A, 0xE1, 0xE7, 0xB0, 0xDE, 0x17, 0x00, ++ 0xF0, 0xB4, 0x01, 0xB3, 0x00, 0x22, 0x87, 0x7A, 0x94, 0x46, 0x07, 0xE0, ++ 0x1E, 0x69, 0x1E, 0xB1, 0x01, 0x3C, 0xC3, 0xF8, 0x10, 0xC0, 0xC4, 0x72, ++ 0x8D, 0x42, 0x09, 0xD2, 0xBB, 0x18, 0xC4, 0x7A, 0x03, 0xF0, 0x3F, 0x03, ++ 0x01, 0x32, 0x00, 0xEB, 0x83, 0x03, 0x95, 0xB2, 0x00, 0x2C, 0xED, 0xD1, ++ 0x03, 0x89, 0x0F, 0x44, 0x19, 0x44, 0x07, 0xF0, 0x3F, 0x07, 0xC1, 0xF3, ++ 0x0B, 0x01, 0x87, 0x72, 0x01, 0x81, 0xF0, 0xBC, 0x70, 0x47, 0x87, 0x7A, ++ 0xF2, 0xE7, 0x00, 0xBF, 0xF8, 0xB5, 0x83, 0x7A, 0x04, 0x33, 0x50, 0xF8, ++ 0x23, 0x30, 0x53, 0xB3, 0xC1, 0x7A, 0x15, 0x4D, 0x15, 0x4F, 0x16, 0x4E, ++ 0x04, 0x46, 0x15, 0xE0, 0xA3, 0x7A, 0x22, 0x89, 0x18, 0x1D, 0x01, 0x33, ++ 0x03, 0xF0, 0x3F, 0x03, 0x01, 0x39, 0x4F, 0xF0, 0x00, 0x0C, 0x44, 0xF8, ++ 0x20, 0xC0, 0xC9, 0xB2, 0x18, 0x1D, 0xA3, 0x72, 0xE1, 0x72, 0x54, 0xF8, ++ 0x20, 0x00, 0x53, 0x1C, 0xC3, 0xF3, 0x0B, 0x03, 0x23, 0x81, 0x70, 0xB1, ++ 0x2B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xE4, 0xDA, 0x00, 0x29, ++ 0xE2, 0xD1, 0x39, 0x46, 0x4F, 0xF4, 0xD6, 0x62, 0x30, 0x46, 0xF6, 0xF7, ++ 0xF5, 0xFD, 0xE1, 0x7A, 0xDA, 0xE7, 0xF8, 0xBD, 0x38, 0x36, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x64, 0xC0, 0x15, 0x00, 0x2D, 0xE9, 0xF0, 0x41, ++ 0x9E, 0x23, 0x0C, 0x8A, 0x38, 0x4A, 0x03, 0xFB, 0x00, 0xF0, 0x00, 0xEB, ++ 0x14, 0x30, 0x02, 0xEB, 0x80, 0x00, 0xD0, 0xF8, 0x7C, 0x41, 0x4C, 0xB3, ++ 0x94, 0xF8, 0x21, 0x31, 0x49, 0x8A, 0xC3, 0xB1, 0xEF, 0xF3, 0x10, 0x83, ++ 0xDA, 0x07, 0x30, 0xD5, 0x30, 0x48, 0x31, 0x4D, 0x03, 0x68, 0x2E, 0x68, ++ 0x03, 0xF0, 0x60, 0x42, 0x77, 0x1C, 0xB2, 0xF1, 0xC0, 0x4F, 0x2F, 0x60, ++ 0x31, 0xD0, 0x2D, 0x4B, 0x80, 0x22, 0x1A, 0x60, 0x2F, 0xB1, 0x2C, 0x4B, ++ 0x2E, 0x60, 0x1B, 0x68, 0x0E, 0xB9, 0x03, 0xB1, 0x62, 0xB6, 0x22, 0x89, ++ 0xB2, 0xEB, 0x11, 0x1F, 0x4F, 0xEA, 0x11, 0x13, 0x06, 0xD0, 0x9B, 0x1A, ++ 0x99, 0xB2, 0x1B, 0x05, 0x04, 0xD5, 0x94, 0xF8, 0x21, 0x31, 0x9B, 0xB1, ++ 0xBD, 0xE8, 0xF0, 0x81, 0x22, 0x4D, 0x20, 0x46, 0xD5, 0xF8, 0xD8, 0x32, ++ 0xC1, 0xF3, 0x0B, 0x01, 0x98, 0x47, 0xD5, 0xF8, 0x38, 0x31, 0x1F, 0x48, ++ 0xBD, 0xE8, 0xF0, 0x41, 0x18, 0x47, 0x72, 0xB6, 0x1A, 0x4B, 0x01, 0x22, ++ 0x1A, 0x60, 0xC9, 0xE7, 0x1B, 0x48, 0xF6, 0xF7, 0x23, 0xFB, 0x01, 0x23, ++ 0x84, 0xF8, 0x21, 0x31, 0xE4, 0xE7, 0x19, 0x4A, 0x03, 0xF4, 0xF0, 0x33, ++ 0xD2, 0xF8, 0x00, 0xC0, 0xB3, 0xF5, 0xF0, 0x3F, 0x0C, 0xF1, 0x10, 0x0C, ++ 0xC3, 0xD0, 0x96, 0x46, 0x03, 0x68, 0x03, 0xF0, 0x60, 0x42, 0xB2, 0xF1, ++ 0xC0, 0x4F, 0x02, 0xD0, 0x10, 0x4B, 0x1B, 0x68, 0xB9, 0xE7, 0x03, 0xF4, ++ 0xF0, 0x33, 0xB3, 0xF5, 0xF0, 0x3F, 0xF7, 0xD0, 0xDE, 0xF8, 0x00, 0x30, ++ 0xA3, 0xEB, 0x0C, 0x03, 0x00, 0x2B, 0xEB, 0xDB, 0x00, 0x2F, 0xB6, 0xD0, ++ 0xAF, 0xE7, 0x00, 0xBF, 0x68, 0x65, 0x17, 0x00, 0x04, 0x05, 0x32, 0x40, ++ 0x6C, 0x28, 0x17, 0x00, 0x54, 0x00, 0x32, 0x40, 0x38, 0x61, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0xE8, 0xDE, 0x17, 0x00, 0x7C, 0xC0, 0x15, 0x00, ++ 0x20, 0x01, 0x32, 0x40, 0x2D, 0xE9, 0xF8, 0x43, 0x8D, 0x4F, 0x8E, 0x4B, ++ 0xBC, 0x7A, 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, 0x04, 0x34, 0x80, 0x46, ++ 0x94, 0xF8, 0xC3, 0x54, 0x89, 0x46, 0x00, 0x2D, 0x40, 0xF0, 0x90, 0x80, ++ 0xF8, 0x79, 0x88, 0x49, 0xBA, 0x88, 0x9E, 0x23, 0x03, 0xFB, 0x09, 0x03, ++ 0x01, 0xEB, 0x83, 0x03, 0xD3, 0xF8, 0x7C, 0x41, 0x23, 0x89, 0x9A, 0x42, ++ 0x00, 0xF0, 0xA5, 0x80, 0xD2, 0x1A, 0x12, 0xF4, 0x7C, 0x6F, 0xC2, 0xF3, ++ 0x0B, 0x03, 0x38, 0xD1, 0xA6, 0x7A, 0x1E, 0x44, 0x06, 0xF0, 0x3F, 0x06, ++ 0x01, 0x23, 0x04, 0xEB, 0x86, 0x06, 0x84, 0xF8, 0x20, 0x31, 0x33, 0x69, ++ 0x00, 0x2B, 0x6B, 0xD1, 0x8D, 0xB9, 0xD8, 0xF8, 0x60, 0x20, 0xB8, 0xF8, ++ 0x32, 0x30, 0x77, 0x49, 0x42, 0xF0, 0x20, 0x02, 0xC8, 0xF8, 0x60, 0x20, ++ 0x23, 0xF0, 0xFF, 0x03, 0xD1, 0xF8, 0xE8, 0x22, 0xA8, 0xF8, 0x32, 0x30, ++ 0x40, 0x46, 0x03, 0x21, 0x90, 0x47, 0x71, 0x4B, 0x33, 0x61, 0xE3, 0x7A, ++ 0x70, 0x4A, 0x01, 0x33, 0x12, 0x68, 0xDB, 0xB2, 0xE3, 0x72, 0xB2, 0xF9, ++ 0x00, 0x20, 0x00, 0x2A, 0xC0, 0xF2, 0xB1, 0x80, 0x01, 0x2B, 0x00, 0xF0, ++ 0xB9, 0x80, 0xC5, 0xF1, 0x01, 0x05, 0xED, 0xB2, 0xF9, 0x79, 0x48, 0x46, ++ 0x02, 0xF0, 0xFE, 0xFE, 0x28, 0x46, 0xBD, 0xE8, 0xF8, 0x83, 0x40, 0xF2, ++ 0xFE, 0x72, 0x93, 0x42, 0x40, 0xF2, 0x91, 0x80, 0x94, 0xF8, 0x20, 0x31, ++ 0x13, 0xB1, 0x94, 0xF8, 0x21, 0x31, 0x9B, 0xB3, 0x3B, 0x88, 0x1B, 0x05, ++ 0x21, 0xD4, 0x7A, 0x88, 0x4F, 0xF4, 0x9E, 0x73, 0x03, 0xFB, 0x09, 0x03, ++ 0x01, 0xEB, 0x43, 0x03, 0xA3, 0xF8, 0xEA, 0x21, 0x15, 0xBB, 0xD8, 0xF8, ++ 0x60, 0x20, 0xB8, 0xF8, 0x32, 0x30, 0x55, 0x49, 0x42, 0xF0, 0x20, 0x02, ++ 0x23, 0xF0, 0xFF, 0x03, 0xC8, 0xF8, 0x60, 0x20, 0xD1, 0xF8, 0xE8, 0x22, ++ 0xA8, 0xF8, 0x32, 0x30, 0x40, 0x46, 0x03, 0x21, 0x90, 0x47, 0xF9, 0x79, ++ 0x48, 0x46, 0x02, 0xF0, 0xCD, 0xFE, 0x01, 0x25, 0xCC, 0xE7, 0x4F, 0xF4, ++ 0x9E, 0x73, 0x03, 0xFB, 0x09, 0x03, 0x01, 0xEB, 0x43, 0x03, 0x7A, 0x88, ++ 0xB3, 0xF8, 0xEA, 0x31, 0x93, 0x42, 0xD3, 0xD1, 0xF9, 0x79, 0x48, 0x46, ++ 0x02, 0xF0, 0xBC, 0xFE, 0x00, 0x25, 0x28, 0x46, 0xBD, 0xE8, 0xF8, 0x83, ++ 0xC2, 0x69, 0x04, 0xF2, 0xC4, 0x41, 0x92, 0x68, 0x01, 0x23, 0x04, 0xF1, ++ 0x63, 0x00, 0xFF, 0xF7, 0x3B, 0xF8, 0x05, 0x46, 0xF8, 0x79, 0x3B, 0x49, ++ 0xBA, 0x88, 0x9E, 0x23, 0x03, 0xFB, 0x09, 0x03, 0x01, 0xEB, 0x83, 0x03, ++ 0x01, 0x2D, 0xD3, 0xF8, 0x7C, 0x41, 0x23, 0x89, 0x60, 0xD0, 0x9A, 0x42, ++ 0x09, 0xD0, 0xD2, 0x1A, 0x12, 0xF4, 0x7C, 0x6F, 0x4F, 0xF0, 0x00, 0x05, ++ 0xC2, 0xF3, 0x0B, 0x03, 0x3F, 0xF4, 0x62, 0xAF, 0x99, 0xE7, 0xD8, 0xF8, ++ 0x60, 0x20, 0xB8, 0xF8, 0x32, 0x30, 0x2E, 0x49, 0x42, 0xF0, 0x20, 0x02, ++ 0x23, 0xF0, 0xFF, 0x03, 0xC8, 0xF8, 0x60, 0x20, 0xD1, 0xF8, 0xE8, 0x22, ++ 0xA8, 0xF8, 0x32, 0x30, 0x40, 0x46, 0x03, 0x21, 0x90, 0x47, 0x23, 0x89, ++ 0x01, 0x25, 0x01, 0x20, 0x28, 0x4A, 0xA1, 0x7A, 0x84, 0xF8, 0x20, 0x01, ++ 0x12, 0x69, 0x62, 0x60, 0x04, 0xEB, 0x81, 0x00, 0x02, 0x69, 0x12, 0xB1, ++ 0xE2, 0x7A, 0x01, 0x3A, 0xE2, 0x72, 0x5A, 0x1C, 0x01, 0x31, 0xC2, 0xF3, ++ 0x0B, 0x02, 0x01, 0xF0, 0x3F, 0x01, 0x00, 0x23, 0x03, 0x61, 0x20, 0x46, ++ 0x22, 0x81, 0xA1, 0x72, 0xFF, 0xF7, 0x4E, 0xFE, 0x62, 0xE7, 0x18, 0x4A, ++ 0xA3, 0xF1, 0x3F, 0x01, 0x89, 0xB2, 0xD2, 0xF8, 0xD8, 0x32, 0x20, 0x46, ++ 0x98, 0x47, 0xBB, 0x88, 0x21, 0x89, 0x5B, 0x1A, 0xC3, 0xF3, 0x0B, 0x03, ++ 0x22, 0xE7, 0x40, 0x2B, 0x7F, 0xF6, 0x4C, 0xAF, 0x13, 0x49, 0x14, 0x48, ++ 0x40, 0xF2, 0xDB, 0x72, 0xF6, 0xF7, 0x5A, 0xFC, 0xE3, 0x7A, 0x43, 0xE7, ++ 0x0E, 0x4A, 0x0B, 0x4B, 0x11, 0x69, 0xD3, 0xF8, 0xE0, 0x31, 0x01, 0xF5, ++ 0x43, 0x41, 0x04, 0xF5, 0x88, 0x70, 0x50, 0x31, 0x98, 0x47, 0x3A, 0xE7, ++ 0x9A, 0x42, 0x7F, 0xF4, 0x03, 0xAF, 0x00, 0x25, 0xB9, 0xE7, 0x00, 0xBF, ++ 0xB0, 0xDE, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x87, 0xA9, 0xDC, 0xFE, 0x38, 0x36, 0x17, 0x00, ++ 0x00, 0x10, 0x50, 0x40, 0x70, 0x79, 0x15, 0x00, 0x90, 0xC0, 0x15, 0x00, ++ 0xC3, 0x7A, 0x03, 0xB9, 0x70, 0x47, 0x1A, 0x4B, 0x42, 0x68, 0x1B, 0x69, ++ 0xC3, 0xF5, 0x43, 0x43, 0x50, 0x33, 0xD3, 0x42, 0x10, 0xB5, 0x04, 0x46, ++ 0x00, 0xD4, 0x10, 0xBD, 0x83, 0x7A, 0x1A, 0x1D, 0x50, 0xF8, 0x22, 0x20, ++ 0x42, 0xB9, 0x02, 0x89, 0x01, 0x33, 0x01, 0x32, 0x03, 0xF0, 0x3F, 0x03, ++ 0xC2, 0xF3, 0x0B, 0x02, 0x83, 0x72, 0x02, 0x81, 0x20, 0x46, 0xFF, 0xF7, ++ 0xF1, 0xFD, 0xE3, 0x7A, 0x53, 0xB9, 0x0B, 0x4A, 0x0B, 0x4B, 0x11, 0x69, ++ 0xD3, 0xF8, 0xE0, 0x31, 0x01, 0xF5, 0x43, 0x41, 0x04, 0xF5, 0x88, 0x70, ++ 0x50, 0x31, 0x98, 0x47, 0x07, 0x48, 0x83, 0x6B, 0x00, 0x2B, 0xDC, 0xD0, ++ 0x04, 0x4B, 0xBD, 0xE8, 0x10, 0x40, 0xD3, 0xF8, 0x38, 0x31, 0x38, 0x30, ++ 0x18, 0x47, 0x00, 0xBF, 0x00, 0x10, 0x50, 0x40, 0x88, 0x1A, 0x17, 0x00, ++ 0xB0, 0xDE, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x47, 0x19, 0x4B, 0x1B, 0x7C, ++ 0xFF, 0x2B, 0x05, 0x46, 0x04, 0xD0, 0x03, 0x88, 0x03, 0xF0, 0xEC, 0x03, ++ 0xC4, 0x2B, 0x11, 0xD0, 0x15, 0x4F, 0x05, 0xF1, 0x04, 0x08, 0x07, 0xF5, ++ 0xA4, 0x56, 0xB9, 0x46, 0x3C, 0x46, 0x94, 0xF8, 0x64, 0x30, 0x1B, 0xB1, ++ 0x94, 0xF8, 0x62, 0x30, 0x02, 0x2B, 0x06, 0xD0, 0x04, 0xF5, 0xA4, 0x64, ++ 0xA6, 0x42, 0xF4, 0xD1, 0x00, 0x20, 0xBD, 0xE8, 0xF0, 0x87, 0x06, 0x22, ++ 0x04, 0xF1, 0x5C, 0x01, 0x40, 0x46, 0x08, 0xF0, 0x45, 0xFE, 0xA4, 0xEB, ++ 0x07, 0x0A, 0x00, 0x28, 0xEE, 0xD1, 0x07, 0x49, 0x07, 0x48, 0xF6, 0xF7, ++ 0x4D, 0xF9, 0x05, 0xF1, 0x0A, 0x01, 0x09, 0xEB, 0x0A, 0x00, 0xFD, 0xF7, ++ 0x49, 0xFD, 0xE7, 0xE7, 0x00, 0x88, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0x20, 0xC1, 0x15, 0x00, 0xA8, 0xC0, 0x15, 0x00, 0x13, 0x4B, 0x93, 0xF8, ++ 0x73, 0x20, 0x12, 0xB1, 0x11, 0xF4, 0x00, 0x71, 0x00, 0xD0, 0x70, 0x47, ++ 0x10, 0xB4, 0x42, 0x89, 0xB3, 0xF8, 0x6C, 0x40, 0x94, 0x42, 0x02, 0xD0, ++ 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, 0xB3, 0xF8, 0x6E, 0x40, 0x82, 0x89, ++ 0x94, 0x42, 0xF7, 0xD1, 0xB3, 0xF8, 0x70, 0x40, 0xC2, 0x89, 0x94, 0x42, ++ 0xF2, 0xD1, 0x02, 0x88, 0x02, 0xF4, 0xA0, 0x52, 0xB2, 0xF5, 0x80, 0x5F, ++ 0x06, 0xBF, 0x01, 0x22, 0x83, 0xF8, 0x72, 0x20, 0x83, 0xF8, 0x72, 0x10, ++ 0xE6, 0xE7, 0x00, 0xBF, 0xB0, 0xDE, 0x17, 0x00, 0xF8, 0xB5, 0xBD, 0xF8, ++ 0x1C, 0x60, 0x06, 0x9D, 0xFF, 0x2A, 0x00, 0xEB, 0x06, 0x07, 0x2E, 0xD0, ++ 0x14, 0x46, 0x82, 0x5D, 0x03, 0x3A, 0x12, 0x2A, 0x18, 0xD8, 0xDF, 0xE8, ++ 0x02, 0xF0, 0x2B, 0x17, 0x0A, 0x17, 0x30, 0x49, 0x17, 0x17, 0x17, 0x17, ++ 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x5C, 0x00, 0x1B, 0x78, ++ 0x4B, 0x4A, 0x4F, 0xF4, 0xA4, 0x61, 0x01, 0xFB, 0x03, 0x23, 0x93, 0xF8, ++ 0x62, 0x30, 0x02, 0x2B, 0x02, 0xD0, 0x7B, 0x78, 0x00, 0x2B, 0x6A, 0xD0, ++ 0x01, 0x26, 0x2B, 0x88, 0xFF, 0x2B, 0x0A, 0xD0, 0x44, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x57, 0xDB, 0x6F, 0xF0, 0xFF, 0x03, ++ 0x2A, 0x88, 0x13, 0x43, 0x2B, 0x80, 0x30, 0x46, 0xF8, 0xBD, 0x01, 0x26, ++ 0x30, 0x46, 0xF8, 0xBD, 0x08, 0x23, 0x2B, 0x80, 0x00, 0x26, 0x00, 0x23, ++ 0xF2, 0xE7, 0x7E, 0x78, 0x00, 0x2E, 0x52, 0xD0, 0x01, 0x2E, 0xE1, 0xD1, ++ 0x38, 0x4A, 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, 0x04, 0x23, 0x5E, 0x68, ++ 0x16, 0xF0, 0x02, 0x06, 0xD9, 0xD0, 0xBE, 0x78, 0x16, 0xF0, 0x01, 0x06, ++ 0x5A, 0xD0, 0x20, 0x46, 0x00, 0x22, 0xFF, 0x21, 0xF9, 0xF7, 0xDC, 0xFC, ++ 0x00, 0x26, 0xCE, 0xE7, 0x89, 0x1B, 0x03, 0x29, 0x2A, 0xDD, 0x1B, 0x78, ++ 0xFF, 0x2B, 0xC7, 0xD0, 0x29, 0x4A, 0x7E, 0x78, 0x4F, 0xF4, 0xA4, 0x61, ++ 0x01, 0xFB, 0x03, 0x23, 0x93, 0xF8, 0x62, 0x30, 0x1E, 0x43, 0xBD, 0xD1, ++ 0x06, 0x23, 0x2B, 0x80, 0xD1, 0xE7, 0x7B, 0x78, 0x01, 0x2B, 0x36, 0xD0, ++ 0x02, 0x2B, 0xB5, 0xD1, 0x22, 0x4A, 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, ++ 0x04, 0x23, 0x5E, 0x68, 0x16, 0xF0, 0x24, 0x06, 0xAD, 0xD0, 0x97, 0xF9, ++ 0x02, 0x30, 0xB9, 0x78, 0x00, 0x2B, 0x07, 0xDB, 0x0A, 0x09, 0x20, 0x46, ++ 0x01, 0xF0, 0x03, 0x01, 0xF9, 0xF7, 0xAE, 0xFC, 0x00, 0x26, 0xA0, 0xE7, ++ 0x00, 0x26, 0x9E, 0xE7, 0x17, 0x49, 0x18, 0x48, 0x40, 0xF6, 0x78, 0x12, ++ 0xF6, 0xF7, 0x00, 0xFB, 0x6F, 0xF0, 0xFF, 0x03, 0xA0, 0xE7, 0x0B, 0x23, ++ 0x2B, 0x80, 0x01, 0x26, 0xA7, 0xE7, 0x10, 0x4A, 0x4F, 0xF4, 0x1E, 0x73, ++ 0x03, 0xFB, 0x04, 0x23, 0x5B, 0x68, 0x9B, 0x07, 0x89, 0xD5, 0xB9, 0x78, ++ 0x01, 0x29, 0x86, 0xD8, 0x20, 0x46, 0xFF, 0x22, 0xF9, 0xF7, 0x8E, 0xFC, ++ 0x81, 0xE7, 0x07, 0xF1, 0x0A, 0x01, 0xB8, 0x1C, 0xD2, 0xF7, 0xB6, 0xFE, ++ 0x00, 0x26, 0x7A, 0xE7, 0xFF, 0x22, 0x20, 0x46, 0x11, 0x46, 0xF9, 0xF7, ++ 0x81, 0xFC, 0x74, 0xE7, 0x18, 0x88, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x68, 0x65, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0xBC, 0xC0, 0x15, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x43, 0x89, 0xB0, 0x1F, 0x46, 0x10, 0x9E, 0x34, 0x78, ++ 0xFF, 0x2C, 0x47, 0xD0, 0x69, 0x4D, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, ++ 0x04, 0x55, 0x00, 0xF0, 0xFC, 0x04, 0x80, 0x2C, 0x95, 0xF8, 0x62, 0x80, ++ 0x46, 0xD0, 0x0F, 0xD8, 0x40, 0x2C, 0x6B, 0xD0, 0x2C, 0xD9, 0x50, 0x2C, ++ 0x4F, 0xF0, 0x01, 0x04, 0x04, 0xD1, 0x13, 0x9A, 0x14, 0x70, 0x12, 0x9A, ++ 0x04, 0x23, 0x13, 0x80, 0x20, 0x46, 0x09, 0xB0, 0xBD, 0xE8, 0xF0, 0x83, ++ 0xC0, 0x2C, 0x21, 0xD0, 0x10, 0xD9, 0xD0, 0x2C, 0x15, 0xD1, 0x13, 0x9B, ++ 0x11, 0x98, 0xCD, 0xE9, 0x01, 0x23, 0x12, 0x9B, 0x00, 0x93, 0x3A, 0x46, ++ 0x33, 0x46, 0xFF, 0xF7, 0x11, 0xFF, 0x04, 0x46, 0x20, 0x46, 0x09, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x83, 0xA0, 0x2C, 0x0D, 0xD0, 0xB0, 0x2C, 0x02, 0xD1, ++ 0xFC, 0xF7, 0xBA, 0xFA, 0x40, 0xB1, 0x01, 0x24, 0x20, 0x46, 0x09, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x83, 0x00, 0xF0, 0xDC, 0x00, 0x10, 0x28, 0xF6, 0xD1, ++ 0xB8, 0xF1, 0x00, 0x0F, 0xF3, 0xD1, 0x12, 0x9A, 0x06, 0x23, 0x13, 0x80, ++ 0x01, 0x24, 0xCF, 0xE7, 0x00, 0xF0, 0xFC, 0x00, 0xB0, 0x28, 0x72, 0xD0, ++ 0x28, 0xD8, 0x40, 0x28, 0x2A, 0xD0, 0x80, 0x28, 0xE5, 0xD1, 0x00, 0x25, ++ 0x04, 0x20, 0x05, 0x91, 0xF4, 0xF7, 0x34, 0xFC, 0x01, 0x28, 0x05, 0x99, ++ 0x0E, 0xD1, 0x13, 0x9A, 0x3D, 0x4B, 0x10, 0x70, 0x12, 0x98, 0x1B, 0x68, ++ 0x3A, 0x4D, 0x04, 0x22, 0x02, 0x80, 0x93, 0xF8, 0x6E, 0x41, 0x34, 0x70, ++ 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x04, 0x55, 0xFF, 0x2F, 0xCC, 0xD0, ++ 0x95, 0xF8, 0x64, 0x30, 0x00, 0x2B, 0xC8, 0xD0, 0x34, 0x4B, 0x30, 0x78, ++ 0xD3, 0xF8, 0x54, 0x31, 0x11, 0x9A, 0x98, 0x47, 0x01, 0x24, 0xA1, 0xE7, ++ 0xD0, 0x28, 0xA8, 0xD0, 0x01, 0x24, 0xBD, 0xE7, 0x2F, 0x4B, 0x9A, 0x7C, ++ 0x00, 0x2A, 0xB8, 0xD0, 0x2E, 0x4A, 0x12, 0x68, 0x12, 0x78, 0x01, 0x3A, ++ 0x01, 0x2A, 0xB2, 0xD8, 0x9D, 0x68, 0x00, 0x2D, 0xAF, 0xD0, 0x18, 0x39, ++ 0x2A, 0x4F, 0x1F, 0xFA, 0x81, 0xF8, 0x01, 0x24, 0x02, 0xE0, 0x2D, 0x68, ++ 0x00, 0x2D, 0x87, 0xD0, 0x95, 0xF8, 0x62, 0x30, 0x02, 0x2B, 0xF8, 0xD1, ++ 0x95, 0xF8, 0x64, 0x30, 0x00, 0x2B, 0xF4, 0xD0, 0x95, 0xF8, 0xC0, 0x34, ++ 0x00, 0x2B, 0xF0, 0xD1, 0x11, 0x9B, 0xB7, 0xF8, 0x00, 0x90, 0x03, 0xF1, ++ 0x18, 0x00, 0x0D, 0xF1, 0x1E, 0x02, 0x41, 0x46, 0xF4, 0xF7, 0xFA, 0xFF, ++ 0xA9, 0xF1, 0x24, 0x01, 0x06, 0x46, 0x89, 0xB2, 0x0D, 0xF1, 0x1F, 0x02, ++ 0x19, 0x48, 0xF4, 0xF7, 0xF1, 0xFF, 0x9D, 0xF8, 0x1E, 0x30, 0x18, 0x49, ++ 0x02, 0x36, 0x81, 0x46, 0x07, 0x22, 0x30, 0x46, 0x53, 0xB9, 0x11, 0x9B, ++ 0x28, 0x46, 0x03, 0xF1, 0x0A, 0x01, 0xE1, 0xF7, 0xED, 0xFE, 0x00, 0x24, ++ 0xCD, 0xE7, 0xFC, 0xF7, 0x2F, 0xFA, 0x74, 0xE7, 0x08, 0xF0, 0x7C, 0xFC, ++ 0x00, 0x28, 0xC6, 0xD0, 0x9D, 0xF8, 0x1F, 0x30, 0x9D, 0xF8, 0x1E, 0x20, ++ 0x9A, 0x42, 0xC0, 0xD1, 0x09, 0xF1, 0x02, 0x01, 0x30, 0x46, 0x08, 0xF0, ++ 0x6F, 0xFC, 0x00, 0x28, 0xE3, 0xD0, 0xB8, 0xE7, 0x18, 0x88, 0x17, 0x00, ++ 0xA8, 0xBA, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x00, 0x88, 0x17, 0x00, ++ 0x78, 0x36, 0x17, 0x00, 0x14, 0x2C, 0x17, 0x00, 0x38, 0x2A, 0x17, 0x00, ++ 0x54, 0xBF, 0x15, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, 0xC6, 0x69, 0x8D, 0xB0, ++ 0xD6, 0xF8, 0x08, 0x90, 0x01, 0x23, 0x8D, 0xF8, 0x24, 0x30, 0x04, 0x46, ++ 0xB9, 0xF8, 0x00, 0x00, 0x10, 0xF4, 0x80, 0x60, 0x40, 0xF0, 0x8B, 0x80, ++ 0xB9, 0xF8, 0x16, 0x70, 0x17, 0xF0, 0x0F, 0x07, 0x00, 0xF0, 0x89, 0x80, ++ 0x0D, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xB9, 0xF8, 0x00, 0x30, 0x98, 0xF8, ++ 0x08, 0x20, 0x04, 0x92, 0xDF, 0xF8, 0x08, 0xE2, 0xB4, 0xF8, 0x30, 0xA0, ++ 0xBD, 0xF8, 0x10, 0x10, 0xAD, 0xF8, 0x16, 0x30, 0x4F, 0xF0, 0xFF, 0x0C, ++ 0x18, 0x46, 0xAD, 0xF8, 0x26, 0xC0, 0xB3, 0x68, 0xDE, 0xF8, 0xE0, 0x92, ++ 0x07, 0x93, 0x0D, 0xF1, 0x25, 0x0C, 0x01, 0x93, 0xCD, 0xF8, 0x0C, 0xC0, ++ 0x72, 0x4B, 0x06, 0x91, 0x0D, 0xF1, 0x26, 0x0C, 0x0A, 0x46, 0x00, 0x93, ++ 0x51, 0x46, 0x8D, 0xF8, 0x25, 0xB0, 0x80, 0xB2, 0xCD, 0xF8, 0x08, 0xC0, ++ 0x2B, 0x46, 0xC8, 0x47, 0xBD, 0xF8, 0x26, 0x10, 0xFF, 0x29, 0x00, 0xF0, ++ 0x90, 0x80, 0x0A, 0xF1, 0x0C, 0x03, 0x9B, 0xB2, 0x0A, 0x22, 0x4F, 0xF4, ++ 0x20, 0x50, 0xF4, 0xF7, 0xB5, 0xF8, 0x59, 0x46, 0x81, 0x46, 0x0A, 0xA8, ++ 0xD2, 0xF7, 0xFA, 0xFC, 0x9D, 0xF8, 0x25, 0x30, 0xD3, 0x46, 0x63, 0xB9, ++ 0x61, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xC0, 0xF2, ++ 0xAE, 0x80, 0x04, 0x9B, 0x06, 0x9F, 0xAA, 0xEB, 0x03, 0x0B, 0x1F, 0xFA, ++ 0x8B, 0xFA, 0x4B, 0x46, 0x3A, 0x46, 0x51, 0x46, 0x23, 0xF8, 0x0C, 0xAB, ++ 0x30, 0x46, 0xE6, 0xF7, 0x35, 0xFD, 0x98, 0xF8, 0x0A, 0x30, 0x89, 0xF8, ++ 0x08, 0x30, 0xBD, 0xF8, 0x16, 0x30, 0x89, 0xF8, 0x07, 0x50, 0xA9, 0xF8, ++ 0x02, 0x30, 0x94, 0xF9, 0x41, 0x50, 0xD2, 0xF7, 0x75, 0xFD, 0x0A, 0x9B, ++ 0x89, 0xF8, 0x06, 0x30, 0x1A, 0x0C, 0x89, 0xF8, 0x09, 0x50, 0xA9, 0xF8, ++ 0x04, 0x20, 0x48, 0x46, 0xF4, 0xF7, 0xAE, 0xF8, 0xBD, 0xF8, 0x26, 0x30, ++ 0x04, 0x2B, 0x10, 0xD1, 0xE1, 0x6B, 0xB9, 0xF8, 0x04, 0x30, 0x62, 0x6B, ++ 0x07, 0x98, 0xC1, 0xF3, 0x03, 0x11, 0x02, 0x91, 0x99, 0xF9, 0x09, 0x10, ++ 0x01, 0x91, 0x99, 0xF8, 0x06, 0x10, 0x00, 0x91, 0x59, 0x46, 0x07, 0xF0, ++ 0x15, 0xFB, 0x00, 0x20, 0x0D, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x0D, 0x46, ++ 0xD2, 0xF7, 0x4E, 0xFD, 0xFF, 0x2D, 0x38, 0xD0, 0x3C, 0x4B, 0x1B, 0x7C, ++ 0xFF, 0x2B, 0x31, 0xD0, 0x99, 0xF8, 0x04, 0x30, 0xDF, 0xF8, 0xEC, 0x80, ++ 0xDA, 0x07, 0x10, 0xD4, 0x98, 0xF8, 0x0A, 0x00, 0x37, 0x4A, 0xB9, 0xF8, ++ 0x04, 0x10, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x00, 0xF3, 0x5C, 0x33, ++ 0x98, 0x18, 0x9B, 0x5A, 0x8B, 0x42, 0x45, 0xD0, 0xFF, 0x23, 0x88, 0xF8, ++ 0x0A, 0x30, 0x22, 0x8E, 0x30, 0x48, 0x09, 0xAB, 0x49, 0x46, 0x02, 0xF0, ++ 0x81, 0xFB, 0x83, 0x46, 0x00, 0x28, 0x3F, 0xF4, 0x50, 0xAF, 0x9D, 0xF8, ++ 0x24, 0x00, 0x00, 0x28, 0x3F, 0xF4, 0x48, 0xAF, 0x2A, 0x4B, 0x20, 0x46, ++ 0xD3, 0xF8, 0xE4, 0x32, 0x03, 0x21, 0x98, 0x47, 0x9D, 0xF8, 0x24, 0x00, ++ 0x3E, 0xE7, 0x8D, 0xF8, 0x24, 0x00, 0xF0, 0xE7, 0xDF, 0xF8, 0x8C, 0x80, ++ 0xE1, 0xE7, 0x63, 0x6D, 0x13, 0xF4, 0xC0, 0x6F, 0x1E, 0xD1, 0x1E, 0x4B, ++ 0x9B, 0x68, 0x9B, 0xB3, 0xB9, 0xF8, 0x04, 0x10, 0x01, 0xE0, 0x1B, 0x68, ++ 0xB3, 0xB1, 0xB3, 0xF8, 0x5C, 0x20, 0x8A, 0x42, 0xF9, 0xD1, 0xB3, 0xF8, ++ 0x5E, 0x00, 0xB9, 0xF8, 0x06, 0x20, 0x90, 0x42, 0xF3, 0xD1, 0xB3, 0xF8, ++ 0x60, 0x00, 0xB9, 0xF8, 0x08, 0x20, 0x90, 0x42, 0xED, 0xD1, 0x93, 0xF8, ++ 0x63, 0x30, 0xDF, 0xF8, 0x4C, 0x80, 0x88, 0xF8, 0x0A, 0x30, 0xBE, 0xE7, ++ 0xFF, 0x23, 0xF8, 0xE7, 0x42, 0x88, 0xB9, 0xF8, 0x06, 0x30, 0x9A, 0x42, ++ 0xB4, 0xD1, 0x82, 0x88, 0xB9, 0xF8, 0x08, 0x30, 0x9A, 0x42, 0xAF, 0xD1, ++ 0xB1, 0xE7, 0x04, 0x9A, 0x93, 0x07, 0x3F, 0xF4, 0x4E, 0xAF, 0x0A, 0x49, ++ 0x0A, 0x48, 0x40, 0xF6, 0x97, 0x22, 0xF6, 0xF7, 0xE7, 0xF8, 0x46, 0xE7, ++ 0x2B, 0x46, 0xE0, 0xE7, 0xBA, 0xDE, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x00, 0x88, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, 0xB0, 0xDE, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0xD0, 0xC0, 0x15, 0x00, ++ 0x1D, 0x48, 0x70, 0xB5, 0x00, 0xF1, 0x10, 0x06, 0xF4, 0xF7, 0x5E, 0xFC, ++ 0x30, 0x46, 0x1B, 0x4C, 0xF4, 0xF7, 0x5A, 0xFC, 0x04, 0xF5, 0x92, 0x55, ++ 0x21, 0x46, 0x30, 0x46, 0x04, 0xF5, 0x92, 0x74, 0xF4, 0xF7, 0x56, 0xFC, ++ 0xAC, 0x42, 0xF7, 0xD1, 0x15, 0x48, 0xF4, 0xF7, 0x4D, 0xFC, 0x15, 0x48, ++ 0xF4, 0xF7, 0x4A, 0xFC, 0x14, 0x49, 0x12, 0x48, 0xF4, 0xF7, 0x4A, 0xFC, ++ 0x13, 0x49, 0x10, 0x48, 0xF4, 0xF7, 0x46, 0xFC, 0x12, 0x49, 0x0E, 0x48, ++ 0xF4, 0xF7, 0x42, 0xFC, 0x11, 0x4A, 0x12, 0x4B, 0x12, 0x48, 0x4F, 0xF6, ++ 0xFF, 0x71, 0xA2, 0xF8, 0x66, 0x10, 0x03, 0xF5, 0x70, 0x51, 0x00, 0x22, ++ 0x03, 0xF8, 0x34, 0x2C, 0x1A, 0x81, 0x43, 0xE9, 0x10, 0x03, 0x43, 0xF8, ++ 0x30, 0x3C, 0x50, 0x33, 0x99, 0x42, 0xF5, 0xD1, 0x70, 0xBD, 0x00, 0xBF, ++ 0xE8, 0xDE, 0x17, 0x00, 0x70, 0xCC, 0x17, 0x00, 0x00, 0xDF, 0x17, 0x00, ++ 0x08, 0xDF, 0x17, 0x00, 0x28, 0xDF, 0x17, 0x00, 0x6C, 0xDF, 0x17, 0x00, ++ 0xB0, 0xDF, 0x17, 0x00, 0xB0, 0xDE, 0x17, 0x00, 0x24, 0x64, 0x18, 0x00, ++ 0x75, 0xD2, 0x14, 0x00, 0x70, 0xB5, 0x90, 0xF9, 0x00, 0x30, 0x82, 0xB0, ++ 0x00, 0x2B, 0x01, 0xF0, 0x78, 0x02, 0x05, 0x46, 0xB8, 0xBF, 0x1A, 0x23, ++ 0x4F, 0xF0, 0x00, 0x00, 0xA8, 0xBF, 0x18, 0x23, 0x08, 0x2A, 0xAD, 0xF8, ++ 0x06, 0x00, 0x19, 0xD0, 0x01, 0xF0, 0x7C, 0x01, 0x04, 0x29, 0x1F, 0xD0, ++ 0x06, 0x33, 0xDC, 0xB2, 0x2E, 0x19, 0x31, 0x46, 0x02, 0x22, 0x0D, 0xF1, ++ 0x06, 0x00, 0x08, 0xF0, 0xF3, 0xFA, 0x28, 0x79, 0x10, 0xF0, 0x01, 0x00, ++ 0x0B, 0xD0, 0xBD, 0xF8, 0x06, 0x00, 0xA0, 0xF5, 0xC1, 0x60, 0xB0, 0xFA, ++ 0x80, 0xF0, 0x40, 0x09, 0x02, 0xB0, 0x70, 0xBD, 0x08, 0x33, 0xDB, 0xB2, ++ 0xE6, 0xE7, 0xBD, 0xF8, 0x06, 0x30, 0x08, 0x2B, 0x04, 0xD0, 0x01, 0x20, ++ 0x02, 0xB0, 0x70, 0xBD, 0x04, 0x33, 0xDD, 0xE7, 0xF3, 0x7A, 0x02, 0x2B, ++ 0xEE, 0xD0, 0x11, 0x2B, 0xF5, 0xD1, 0xB2, 0x78, 0xA3, 0x1C, 0x02, 0xF0, ++ 0x0F, 0x04, 0x03, 0xEB, 0x84, 0x04, 0x2C, 0x44, 0x14, 0xF8, 0x04, 0x3C, ++ 0xEF, 0x2B, 0xEA, 0xD1, 0x14, 0xF8, 0x03, 0x3C, 0xFF, 0x2B, 0xE6, 0xD1, ++ 0x14, 0xF8, 0x02, 0x3C, 0xFF, 0x2B, 0xE2, 0xD1, 0x14, 0xF8, 0x01, 0x0C, ++ 0xFA, 0x38, 0x18, 0xBF, 0x01, 0x20, 0xD3, 0xE7, 0x70, 0xB5, 0x90, 0xF9, ++ 0x00, 0x30, 0x82, 0xB0, 0x00, 0x2B, 0x01, 0xF0, 0x78, 0x05, 0x4F, 0xF0, ++ 0x00, 0x06, 0xB4, 0xBF, 0x1A, 0x23, 0x18, 0x23, 0x08, 0x2D, 0x14, 0x46, ++ 0xAD, 0xF8, 0x06, 0x60, 0x13, 0xD0, 0x01, 0xF0, 0x7C, 0x01, 0x04, 0x29, ++ 0x12, 0xD0, 0x99, 0x1D, 0x50, 0xFA, 0x81, 0xF1, 0x02, 0x22, 0x0D, 0xF1, ++ 0x06, 0x00, 0x08, 0xF0, 0x9F, 0xFA, 0xBD, 0xF8, 0x06, 0x10, 0x48, 0xF6, ++ 0x88, 0x63, 0x99, 0x42, 0x06, 0xD0, 0x02, 0xB0, 0x70, 0xBD, 0x08, 0x33, ++ 0xDB, 0xB2, 0xEC, 0xE7, 0x04, 0x33, 0xEA, 0xE7, 0x02, 0x48, 0x22, 0x46, ++ 0xF5, 0xF7, 0x6E, 0xFD, 0x02, 0xB0, 0x70, 0xBD, 0xEC, 0xC0, 0x15, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0x45, 0x6D, 0x2D, 0xED, 0x02, 0x8B, 0xAF, 0x04, ++ 0x87, 0xB0, 0x04, 0x46, 0x1F, 0xD4, 0xC1, 0x4B, 0x1B, 0x68, 0x1B, 0x78, ++ 0x9E, 0x07, 0x03, 0xD5, 0x05, 0xF0, 0x3C, 0x03, 0x3C, 0x2B, 0x16, 0xD0, ++ 0xBD, 0x4B, 0x1B, 0x7C, 0xFF, 0x2B, 0x71, 0xD0, 0xBC, 0x4E, 0xBD, 0x4D, ++ 0xB3, 0x72, 0x20, 0x46, 0xD5, 0xF8, 0xE4, 0x32, 0x80, 0x21, 0x98, 0x47, ++ 0x01, 0x27, 0xD5, 0xF8, 0x38, 0x31, 0xB9, 0x48, 0x98, 0x47, 0x38, 0x46, ++ 0x07, 0xB0, 0xBD, 0xEC, 0x02, 0x8B, 0xBD, 0xE8, 0xF0, 0x8F, 0xD4, 0xF8, ++ 0x1C, 0xA0, 0xB2, 0x4E, 0xDA, 0xF8, 0x08, 0x80, 0x00, 0x23, 0xB8, 0xF8, ++ 0x00, 0x90, 0x23, 0x66, 0x40, 0x46, 0xFF, 0x23, 0x73, 0x72, 0xB3, 0x72, ++ 0xFE, 0xF7, 0xE6, 0xFD, 0xA8, 0x01, 0x50, 0xD5, 0xC5, 0xF3, 0xC9, 0x37, ++ 0xDF, 0xF8, 0xBC, 0xB2, 0x10, 0x3F, 0xFF, 0xB2, 0x4F, 0xF4, 0x1E, 0x73, ++ 0x03, 0xFB, 0x07, 0xB3, 0x93, 0xF8, 0x25, 0x20, 0x00, 0x2A, 0x39, 0xD0, ++ 0x93, 0xF8, 0x22, 0x10, 0xA5, 0x48, 0xD3, 0xF8, 0xB0, 0x30, 0x77, 0x72, ++ 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, 0x01, 0x02, 0xB5, 0x61, 0x92, 0xF8, ++ 0x62, 0x20, 0xB1, 0x72, 0x02, 0x2A, 0x00, 0x93, 0x52, 0xD0, 0x09, 0xF4, ++ 0x40, 0x73, 0xB3, 0xF5, 0x40, 0x7F, 0x03, 0xD1, 0x23, 0x6E, 0x43, 0xF0, ++ 0x04, 0x03, 0x23, 0x66, 0x33, 0x88, 0x5B, 0x04, 0x00, 0xF1, 0x90, 0x80, ++ 0x98, 0x4B, 0x1B, 0x68, 0x1B, 0x78, 0x01, 0x2B, 0x09, 0xF0, 0x0C, 0x03, ++ 0x00, 0xF0, 0x90, 0x80, 0x08, 0x2B, 0x00, 0xF0, 0x97, 0x80, 0x4F, 0xF4, ++ 0x1E, 0x72, 0x02, 0xFB, 0x07, 0xB2, 0x92, 0xF8, 0x5D, 0x22, 0x01, 0x2A, ++ 0x40, 0xF2, 0xE7, 0x80, 0x04, 0x2B, 0x00, 0xF0, 0xFA, 0x80, 0x08, 0x2B, ++ 0x00, 0xF0, 0x97, 0x80, 0x00, 0x2B, 0x33, 0xD0, 0x85, 0x4B, 0x1B, 0x7C, ++ 0xFF, 0x2B, 0x01, 0xD0, 0x85, 0x4D, 0x8F, 0xE7, 0x84, 0x4D, 0x00, 0x27, ++ 0x93, 0xE7, 0x29, 0x46, 0x40, 0x46, 0xFF, 0xF7, 0x9D, 0xFB, 0x19, 0xF0, ++ 0x0C, 0x0F, 0x0B, 0xD1, 0xFF, 0xF7, 0xDA, 0xF8, 0x00, 0x28, 0xEB, 0xD0, ++ 0x33, 0x88, 0x59, 0x04, 0x55, 0xD5, 0x05, 0xF0, 0x7C, 0x03, 0x04, 0x2B, ++ 0x4B, 0xD0, 0x40, 0x46, 0x21, 0x46, 0xFF, 0xF7, 0x4D, 0xFB, 0x78, 0x4D, ++ 0x07, 0x46, 0x75, 0x4B, 0x1B, 0x7C, 0xFF, 0x2B, 0x3F, 0xF4, 0x77, 0xAF, ++ 0x00, 0x2F, 0x7F, 0xF4, 0x74, 0xAF, 0x6B, 0xE7, 0x96, 0xF8, 0x24, 0x30, ++ 0xDA, 0x07, 0xA8, 0xD4, 0x06, 0xF1, 0x24, 0x00, 0xF2, 0xF7, 0xB8, 0xFE, ++ 0xF0, 0x72, 0xA2, 0xE7, 0x19, 0xF4, 0x00, 0x6F, 0x00, 0xF0, 0xCF, 0x80, ++ 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, 0x07, 0xB3, 0x72, 0x88, 0xB3, 0xF8, ++ 0xE8, 0x31, 0x93, 0x42, 0xBE, 0xD0, 0x96, 0xF8, 0x30, 0x10, 0x4F, 0xF4, ++ 0x1E, 0x73, 0x03, 0xFB, 0x07, 0xB7, 0x8D, 0x07, 0xA7, 0xF8, 0xE8, 0x21, ++ 0x0A, 0xD5, 0x35, 0x6A, 0xD6, 0xE9, 0x04, 0x01, 0xD5, 0xE9, 0x10, 0x23, ++ 0x8B, 0x42, 0x08, 0xBF, 0x82, 0x42, 0xAB, 0xD2, 0xC5, 0xE9, 0x10, 0x01, ++ 0x5F, 0x4B, 0x1B, 0x68, 0x1B, 0x78, 0x01, 0x2B, 0x04, 0xD1, 0x98, 0xF8, ++ 0x00, 0x30, 0x80, 0x2B, 0x00, 0xF0, 0xCF, 0x80, 0x71, 0x7A, 0x57, 0x4D, ++ 0x20, 0x46, 0xFF, 0xF7, 0x17, 0xFD, 0x07, 0x46, 0xB9, 0xE7, 0x29, 0x46, ++ 0x40, 0x46, 0xFE, 0xF7, 0x39, 0xFB, 0x00, 0x28, 0xAD, 0xD0, 0xFF, 0x21, ++ 0x20, 0x46, 0xFF, 0xF7, 0x0B, 0xFD, 0x4F, 0x4D, 0x07, 0x46, 0xAC, 0xE7, ++ 0xB1, 0x69, 0x40, 0x46, 0xFE, 0xF7, 0x2C, 0xFB, 0x00, 0x28, 0x7F, 0xF4, ++ 0x69, 0xAF, 0x83, 0xE7, 0x08, 0x2B, 0x7F, 0xF4, 0x70, 0xAF, 0x29, 0x46, ++ 0x40, 0x46, 0xFF, 0xF7, 0x73, 0xFE, 0x00, 0x28, 0x3F, 0xF4, 0x7A, 0xAF, ++ 0x3B, 0x46, 0x22, 0x8E, 0x29, 0x46, 0x40, 0x46, 0xFF, 0xF7, 0xC0, 0xFE, ++ 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, 0x07, 0xB3, 0x93, 0xF8, 0x5D, 0x32, ++ 0x01, 0x2B, 0x40, 0xF2, 0x87, 0x80, 0x41, 0x4B, 0x93, 0xF8, 0x04, 0x31, ++ 0x73, 0xB1, 0xB3, 0x7A, 0x3C, 0x49, 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, ++ 0x03, 0x13, 0x93, 0xF8, 0x62, 0x20, 0x2A, 0xB9, 0xD3, 0xF8, 0x90, 0x21, ++ 0x92, 0x78, 0x01, 0x2A, 0x00, 0xF0, 0x8D, 0x80, 0x19, 0xF0, 0x40, 0x03, ++ 0x00, 0x93, 0x7F, 0xF4, 0x53, 0xAF, 0x09, 0xF0, 0x80, 0x03, 0x00, 0x2B, ++ 0x14, 0xBF, 0x4F, 0xF0, 0x01, 0x08, 0x4F, 0xF0, 0x00, 0x08, 0x71, 0xD0, ++ 0x96, 0xF8, 0x30, 0x30, 0x1A, 0x07, 0x40, 0xF1, 0x9A, 0x80, 0xF2, 0x79, ++ 0x4F, 0xF4, 0x9E, 0x73, 0xF5, 0x32, 0x03, 0xFB, 0x07, 0x23, 0x0B, 0xEB, ++ 0x43, 0x03, 0x19, 0xF4, 0x00, 0x6F, 0x72, 0x88, 0x03, 0xD0, 0x19, 0x88, ++ 0x91, 0x42, 0x3F, 0xF4, 0x35, 0xAF, 0x1F, 0x49, 0x1A, 0x80, 0x0B, 0x68, ++ 0x1B, 0x78, 0x9B, 0x07, 0x04, 0xD5, 0x05, 0xF0, 0x3C, 0x05, 0x3C, 0x2D, ++ 0x00, 0xF0, 0x8E, 0x80, 0x1C, 0x4D, 0x39, 0x46, 0xD5, 0xF8, 0xC4, 0x32, ++ 0x42, 0x46, 0x20, 0x46, 0x98, 0x47, 0x07, 0x46, 0x41, 0xE7, 0x00, 0x9A, ++ 0x00, 0x2A, 0x3F, 0xF4, 0x15, 0xAF, 0x92, 0xF8, 0x60, 0x20, 0x01, 0x3A, ++ 0x01, 0x2A, 0x3F, 0xF6, 0x0F, 0xAF, 0x19, 0xF4, 0x80, 0x4F, 0x3F, 0xF4, ++ 0x0B, 0xAF, 0x4F, 0xF4, 0x1E, 0x72, 0x02, 0xFB, 0x07, 0xB2, 0x02, 0x21, ++ 0x82, 0xF8, 0x5D, 0x12, 0x02, 0xE7, 0x09, 0xF0, 0xFC, 0x09, 0xB9, 0xF1, ++ 0x84, 0x0F, 0x7F, 0xF4, 0x05, 0xAF, 0x0A, 0x4D, 0x41, 0x46, 0xD5, 0xF8, ++ 0xD0, 0x32, 0x38, 0x46, 0x98, 0x47, 0x05, 0x4B, 0x1B, 0x7C, 0xFF, 0x2B, ++ 0x7F, 0xF4, 0x90, 0xAE, 0xFF, 0xE6, 0x72, 0x88, 0x37, 0xE7, 0x00, 0xBF, ++ 0x34, 0x36, 0x17, 0x00, 0x00, 0x88, 0x17, 0x00, 0xB0, 0xDE, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0xE8, 0xDE, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0x74, 0x36, 0x17, 0x00, 0x2C, 0x19, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, ++ 0x00, 0x9B, 0x00, 0x2B, 0x3F, 0xF4, 0x75, 0xAF, 0x93, 0xF8, 0x60, 0x30, ++ 0x01, 0x3B, 0x01, 0x2B, 0x3F, 0xF6, 0x6F, 0xAF, 0x08, 0x23, 0xC0, 0xE7, ++ 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, 0x07, 0xB3, 0x03, 0xF5, 0xF4, 0x73, ++ 0x93, 0xE7, 0x98, 0xF8, 0x01, 0x30, 0x00, 0x2B, 0x7F, 0xF4, 0x2C, 0xAF, ++ 0xCA, 0xE6, 0xD3, 0xF8, 0xCC, 0x21, 0x12, 0xF0, 0x0C, 0x0F, 0x3F, 0xF4, ++ 0x6D, 0xAF, 0x98, 0xF8, 0x04, 0x20, 0xD0, 0x07, 0x3F, 0xF5, 0x68, 0xAF, ++ 0xE2, 0x6B, 0x12, 0xF0, 0x0C, 0x0F, 0x3F, 0xF4, 0x63, 0xAF, 0xD3, 0xF8, ++ 0x90, 0x20, 0x01, 0x32, 0xC3, 0xF8, 0x90, 0x20, 0x98, 0xF8, 0x01, 0x20, ++ 0x11, 0x07, 0x7F, 0xF5, 0x59, 0xAF, 0xD3, 0xF8, 0x94, 0x20, 0x01, 0x32, ++ 0xC3, 0xF8, 0x94, 0x20, 0x52, 0xE7, 0xF1, 0x79, 0x38, 0x46, 0xE9, 0xF7, ++ 0x33, 0xFB, 0x00, 0x28, 0x3F, 0xF4, 0x5F, 0xAF, 0x61, 0x4D, 0x39, 0x46, ++ 0xD5, 0xF8, 0xD4, 0x32, 0x20, 0x46, 0x98, 0x47, 0x07, 0x46, 0xBC, 0xE6, ++ 0x33, 0x6A, 0x01, 0x93, 0x93, 0xF8, 0x60, 0x10, 0x01, 0x29, 0x03, 0xF1, ++ 0x64, 0x09, 0x64, 0xD0, 0x00, 0x29, 0x40, 0xF0, 0x97, 0x80, 0x08, 0xF1, ++ 0x0E, 0x03, 0x5B, 0x00, 0xDA, 0xE9, 0x01, 0x25, 0x58, 0x19, 0x08, 0xEE, ++ 0x10, 0x0A, 0x00, 0x2A, 0x52, 0xD0, 0xDA, 0xF8, 0x0C, 0x20, 0x20, 0x8E, ++ 0x01, 0x32, 0x52, 0x1B, 0x04, 0x30, 0xD2, 0x1A, 0xC0, 0x1A, 0x93, 0xB2, ++ 0x82, 0xB2, 0x9A, 0x42, 0x00, 0x92, 0x28, 0xBF, 0x1A, 0x46, 0x15, 0x46, ++ 0x01, 0x29, 0x2F, 0xD0, 0x00, 0x29, 0x50, 0xD0, 0x03, 0x29, 0x66, 0xD0, ++ 0x18, 0xEE, 0x10, 0x0A, 0x29, 0x46, 0xF3, 0xF7, 0x2F, 0xFB, 0x4F, 0xF0, ++ 0xFF, 0x33, 0x18, 0xEE, 0x10, 0x0A, 0x03, 0x22, 0x29, 0x46, 0xD6, 0xF7, ++ 0x29, 0xFF, 0xDA, 0xF8, 0x04, 0x30, 0x23, 0xB1, 0x00, 0x9A, 0x55, 0x1B, ++ 0xAD, 0xB2, 0x00, 0x2D, 0x67, 0xD1, 0x01, 0x9B, 0x93, 0xF8, 0x60, 0x30, ++ 0x13, 0xB1, 0x03, 0x2B, 0x7F, 0xF4, 0x2C, 0xAF, 0x03, 0x20, 0xD6, 0xF7, ++ 0x4F, 0xFF, 0x3A, 0x4B, 0x98, 0x42, 0x01, 0x46, 0x3F, 0xD1, 0x63, 0x6D, ++ 0x23, 0xF0, 0x7C, 0x03, 0x43, 0xF4, 0x00, 0x53, 0x43, 0xF0, 0x04, 0x03, ++ 0x63, 0x65, 0x1B, 0xE7, 0x4F, 0xF4, 0x1E, 0x72, 0x02, 0xFB, 0x07, 0xB2, ++ 0x02, 0xAB, 0x32, 0x49, 0x26, 0x32, 0x48, 0x46, 0xF3, 0xF7, 0xDA, 0xF8, ++ 0x10, 0x21, 0x02, 0xA8, 0xF3, 0xF7, 0x9A, 0xFA, 0x01, 0x9B, 0x93, 0xF8, ++ 0x60, 0x10, 0xBD, 0xE7, 0x22, 0x8E, 0x04, 0x32, 0xD3, 0x1A, 0x9D, 0xB2, ++ 0xB6, 0xE7, 0xD6, 0xE9, 0x04, 0x53, 0x28, 0x48, 0x2A, 0x0C, 0x42, 0xEA, ++ 0x03, 0x42, 0x08, 0xF1, 0x10, 0x03, 0x02, 0x60, 0x85, 0x80, 0x5B, 0x00, ++ 0x94, 0xE7, 0x32, 0x8A, 0x73, 0x8A, 0xAD, 0xF8, 0x08, 0x20, 0x49, 0x46, ++ 0x05, 0x22, 0x0D, 0xF1, 0x0B, 0x00, 0x8D, 0xF8, 0x0A, 0x30, 0x08, 0xF0, ++ 0x1F, 0xF8, 0x08, 0x21, 0x02, 0xA8, 0xF3, 0xF7, 0x75, 0xFA, 0x01, 0x9B, ++ 0x93, 0xF8, 0x60, 0x10, 0x9A, 0xE7, 0x1A, 0x48, 0xF5, 0xF7, 0xF4, 0xFA, ++ 0x0A, 0xE6, 0x32, 0x8A, 0x73, 0x8A, 0xAD, 0xF8, 0x08, 0x20, 0x49, 0x46, ++ 0x0D, 0x22, 0x0D, 0xF1, 0x0B, 0x00, 0x8D, 0xF8, 0x0A, 0x30, 0x08, 0xF0, ++ 0x07, 0xF8, 0x02, 0xA8, 0x10, 0x21, 0xF3, 0xF7, 0x5D, 0xFA, 0x87, 0xE7, ++ 0x03, 0x29, 0x3F, 0xF4, 0x66, 0xAF, 0x00, 0x23, 0x66, 0xE7, 0xD3, 0xF8, ++ 0x08, 0x90, 0x29, 0x46, 0x48, 0x46, 0xF3, 0xF7, 0xB1, 0xFA, 0x03, 0x20, ++ 0xD6, 0xF7, 0xE8, 0xFE, 0x20, 0x21, 0xC0, 0x43, 0xF3, 0xF7, 0x64, 0xF8, ++ 0x29, 0x46, 0x03, 0x46, 0x03, 0x22, 0x48, 0x46, 0xD6, 0xF7, 0xA6, 0xFE, ++ 0x83, 0xE7, 0x00, 0xBF, 0x88, 0x1A, 0x17, 0x00, 0x1C, 0xDF, 0x44, 0x21, ++ 0x88, 0x34, 0x17, 0x00, 0x00, 0xC1, 0x15, 0x00, 0x2D, 0xE9, 0xF0, 0x41, ++ 0x00, 0xEB, 0x81, 0x04, 0xD4, 0xF8, 0x7C, 0x61, 0x16, 0xB1, 0x00, 0x20, ++ 0xBD, 0xE8, 0xF0, 0x81, 0x15, 0x48, 0x0D, 0x46, 0x17, 0x46, 0xF4, 0xF7, ++ 0x1B, 0xF9, 0x80, 0x46, 0x00, 0x28, 0xF4, 0xD0, 0x31, 0x46, 0x4F, 0xF4, ++ 0x92, 0x72, 0xD1, 0xF7, 0x3B, 0xF8, 0x07, 0xF0, 0x3F, 0x02, 0x0F, 0x4B, ++ 0x88, 0xF8, 0x0C, 0x50, 0x88, 0xF8, 0x0A, 0x20, 0x19, 0x69, 0x0D, 0x4B, ++ 0xC8, 0xF8, 0x04, 0x10, 0xD3, 0xF8, 0xDC, 0x22, 0xA8, 0xF8, 0x08, 0x70, ++ 0xC8, 0xE9, 0x45, 0x28, 0x01, 0xF5, 0x43, 0x41, 0xC4, 0xF8, 0x7C, 0x81, ++ 0x08, 0xF5, 0x88, 0x70, 0xD3, 0xF8, 0xE0, 0x31, 0x50, 0x31, 0x98, 0x47, ++ 0x01, 0x20, 0xBD, 0xE8, 0xF0, 0x81, 0x00, 0xBF, 0xF8, 0xDE, 0x17, 0x00, ++ 0x00, 0x10, 0x50, 0x40, 0x88, 0x1A, 0x17, 0x00, 0x38, 0xB5, 0x10, 0x4B, ++ 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0xEB, 0x81, 0x04, 0x00, 0x2B, ++ 0xD4, 0xF8, 0x7C, 0x51, 0x0D, 0xDB, 0x0C, 0x4B, 0x05, 0xF5, 0x88, 0x70, ++ 0xD3, 0xF8, 0xD8, 0x31, 0x98, 0x47, 0x0A, 0x48, 0x29, 0x46, 0xF4, 0xF7, ++ 0x95, 0xF8, 0x00, 0x23, 0xC4, 0xF8, 0x7C, 0x31, 0x38, 0xBD, 0x00, 0x2D, ++ 0xEF, 0xD1, 0x06, 0x49, 0x06, 0x48, 0x40, 0xF6, 0x7F, 0x52, 0xF5, 0xF7, ++ 0xDD, 0xFC, 0xE8, 0xE7, 0x38, 0x36, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0xF8, 0xDE, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x10, 0xC1, 0x15, 0x00, ++ 0x08, 0x4B, 0x93, 0xF8, 0x73, 0x20, 0x62, 0xB9, 0x02, 0x88, 0xA3, 0xF8, ++ 0x6C, 0x20, 0x42, 0x88, 0xA3, 0xF8, 0x6E, 0x20, 0x82, 0x88, 0xA3, 0xF8, ++ 0x70, 0x20, 0x4F, 0xF4, 0x80, 0x72, 0xA3, 0xF8, 0x72, 0x20, 0x70, 0x47, ++ 0xB0, 0xDE, 0x17, 0x00, 0x03, 0x4B, 0x00, 0x22, 0x93, 0xF8, 0x72, 0x00, ++ 0xA3, 0xF8, 0x72, 0x20, 0x70, 0x47, 0x00, 0xBF, 0xB0, 0xDE, 0x17, 0x00, ++ 0x10, 0xB5, 0x4F, 0xF4, 0x00, 0x10, 0xF3, 0xF7, 0xDD, 0xFF, 0x03, 0x4B, ++ 0x03, 0x48, 0xD3, 0xF8, 0x38, 0x31, 0xBD, 0xE8, 0x10, 0x40, 0x18, 0x47, ++ 0x88, 0x1A, 0x17, 0x00, 0xE8, 0xDE, 0x17, 0x00, 0x06, 0x4B, 0x07, 0x4A, ++ 0x93, 0xF8, 0x44, 0x30, 0x03, 0xEB, 0x83, 0x03, 0x02, 0xEB, 0x03, 0x13, ++ 0xB3, 0xF8, 0x4C, 0x00, 0xB0, 0xFA, 0x80, 0xF0, 0x40, 0x09, 0x70, 0x47, ++ 0xB0, 0xDE, 0x17, 0x00, 0xE0, 0x63, 0x18, 0x00, 0xF8, 0xB5, 0x55, 0x4F, ++ 0x46, 0x7F, 0x05, 0x7F, 0x54, 0x4A, 0x4F, 0xF4, 0x1E, 0x74, 0x04, 0xFB, ++ 0x06, 0x74, 0xD4, 0xE9, 0x2C, 0xC3, 0x4F, 0xF4, 0xA4, 0x6E, 0x0E, 0xFB, ++ 0x05, 0x25, 0x1B, 0x68, 0xD5, 0xF8, 0xA8, 0xE4, 0x00, 0x22, 0x0A, 0x60, ++ 0x4B, 0xB3, 0xBE, 0xF1, 0x00, 0x0F, 0x26, 0xD0, 0xD5, 0xF8, 0xB0, 0x54, ++ 0xAA, 0x07, 0x06, 0xD5, 0x05, 0x8B, 0xB4, 0xF8, 0x34, 0xE0, 0x6C, 0xBA, ++ 0xA4, 0xB2, 0xA6, 0x45, 0x1B, 0xD0, 0xBC, 0xF1, 0x00, 0x0F, 0x04, 0xD0, ++ 0x9C, 0xF8, 0x60, 0x20, 0x01, 0x3A, 0x01, 0x2A, 0x1C, 0xD9, 0x93, 0xF8, ++ 0x60, 0x20, 0x04, 0x2A, 0x04, 0xD8, 0xDF, 0xE8, 0x02, 0xF0, 0x10, 0x20, ++ 0x27, 0x10, 0x3C, 0x00, 0x3D, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0x04, 0xDA, 0x3B, 0x49, 0x3C, 0x48, 0xC4, 0x22, 0xF5, 0xF7, ++ 0x53, 0xFC, 0x00, 0x20, 0xF8, 0xBD, 0xC2, 0x8B, 0x04, 0x24, 0xD5, 0x07, ++ 0x0C, 0x60, 0x54, 0xD5, 0x20, 0x46, 0xF8, 0xBD, 0x4F, 0xF4, 0x1E, 0x72, ++ 0x02, 0xFB, 0x06, 0x76, 0x96, 0xF8, 0x5D, 0x22, 0x01, 0x2A, 0xDA, 0xD8, ++ 0xED, 0xE7, 0xC2, 0x8B, 0x0C, 0x24, 0x0C, 0x60, 0xD4, 0x07, 0x35, 0xD5, ++ 0x08, 0x20, 0xF8, 0xBD, 0xC2, 0x8B, 0x08, 0x24, 0x0C, 0x60, 0xD1, 0x07, ++ 0xF8, 0xD4, 0xD3, 0xE9, 0x12, 0x21, 0x01, 0x32, 0x41, 0xF1, 0x00, 0x01, ++ 0x16, 0x46, 0x0F, 0x46, 0x19, 0x46, 0xE1, 0xE9, 0x12, 0x67, 0x06, 0x22, ++ 0x38, 0x30, 0x07, 0xF0, 0xCD, 0xFE, 0x20, 0x46, 0xF8, 0xBD, 0xC2, 0x8B, ++ 0x10, 0x24, 0xD2, 0x07, 0x0C, 0x60, 0x13, 0xD4, 0x93, 0xF8, 0x62, 0x20, ++ 0x0F, 0x2A, 0xD3, 0xE9, 0x12, 0x21, 0x0F, 0xD9, 0x02, 0x32, 0x41, 0xF1, ++ 0x00, 0x01, 0x14, 0x46, 0x0D, 0x46, 0x19, 0x46, 0xE1, 0xE9, 0x12, 0x45, ++ 0x08, 0x22, 0x38, 0x30, 0x07, 0xF0, 0xB4, 0xFE, 0x12, 0x20, 0xF8, 0xBD, ++ 0x12, 0x20, 0xF8, 0xBD, 0x01, 0x32, 0x41, 0xF1, 0x00, 0x01, 0xEE, 0xE7, ++ 0xD3, 0xE9, 0x12, 0x21, 0x01, 0x32, 0x41, 0xF1, 0x00, 0x01, 0x14, 0x46, ++ 0x0D, 0x46, 0x19, 0x46, 0xE1, 0xE9, 0x12, 0x45, 0x06, 0x22, 0x38, 0x30, ++ 0x07, 0xF0, 0x9E, 0xFE, 0xBA, 0xE7, 0xD3, 0xE9, 0x12, 0x21, 0x01, 0x32, ++ 0x41, 0xF1, 0x00, 0x01, 0x16, 0x46, 0x0F, 0x46, 0x19, 0x46, 0xE1, 0xE9, ++ 0x12, 0x67, 0x22, 0x46, 0x38, 0x30, 0x07, 0xF0, 0x8F, 0xFE, 0x20, 0x46, ++ 0xF8, 0xBD, 0x00, 0xBF, 0x68, 0x65, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x64, 0x7D, 0x15, 0x00, ++ 0xF0, 0xB5, 0xC3, 0x8B, 0x04, 0x46, 0xD8, 0x07, 0x83, 0xB0, 0x44, 0xD4, ++ 0xE0, 0x7E, 0x66, 0x7F, 0x22, 0x7F, 0xFF, 0x28, 0x44, 0xD0, 0x4F, 0xF4, ++ 0x9E, 0x71, 0x01, 0xFB, 0x06, 0x01, 0x21, 0x48, 0x98, 0x31, 0x00, 0xEB, ++ 0x41, 0x01, 0x1A, 0x25, 0x8F, 0x88, 0x78, 0x1C, 0xC0, 0xF3, 0x0B, 0x00, ++ 0x88, 0x80, 0x27, 0x84, 0xD9, 0x05, 0x1C, 0x4B, 0x4F, 0xF4, 0xA4, 0x61, ++ 0x01, 0xFB, 0x02, 0x33, 0x48, 0xBF, 0x06, 0x35, 0x93, 0xF8, 0x62, 0x30, ++ 0x43, 0xB9, 0x16, 0x4B, 0x4F, 0xF4, 0x1E, 0x72, 0x02, 0xFB, 0x06, 0x36, ++ 0x73, 0x68, 0x9B, 0x06, 0x48, 0xBF, 0x04, 0x35, 0x01, 0xA9, 0x84, 0xF8, ++ 0x32, 0x50, 0x20, 0x46, 0xFF, 0xF7, 0x16, 0xFF, 0x23, 0x8B, 0xA2, 0x88, ++ 0x22, 0x86, 0x5B, 0xBA, 0x9B, 0xB2, 0xB3, 0xF5, 0xC0, 0x6F, 0x28, 0x44, ++ 0x88, 0xBF, 0x08, 0x30, 0xC0, 0xB2, 0x01, 0x9B, 0x84, 0xF8, 0x33, 0x00, ++ 0x8C, 0xBF, 0x08, 0x21, 0x00, 0x21, 0x84, 0xF8, 0x42, 0x00, 0x84, 0xF8, ++ 0x34, 0x10, 0x84, 0xF8, 0x35, 0x30, 0x00, 0x23, 0xC4, 0xE9, 0x09, 0x33, ++ 0x03, 0xB0, 0xF0, 0xBD, 0x18, 0x25, 0xC7, 0xE7, 0x68, 0x65, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, 0x90, 0xF8, 0x1D, 0xA0, ++ 0xDF, 0xF8, 0x58, 0x92, 0x90, 0xF8, 0x1C, 0x80, 0x92, 0x4F, 0x4F, 0xF4, ++ 0x1E, 0x76, 0x06, 0xFB, 0x0A, 0xF6, 0x09, 0xEB, 0x06, 0x02, 0x4F, 0xF4, ++ 0xA4, 0x64, 0x04, 0xFB, 0x08, 0x74, 0xD2, 0xF8, 0xB4, 0x30, 0x94, 0xF8, ++ 0x62, 0xC0, 0xD3, 0xF8, 0x00, 0xB0, 0xD2, 0xF8, 0xB0, 0x30, 0x83, 0xB0, ++ 0x05, 0x46, 0x01, 0x93, 0xD4, 0xF8, 0xA8, 0x34, 0x00, 0x93, 0x0C, 0x46, ++ 0xBC, 0xF1, 0x00, 0x0F, 0x40, 0xF0, 0x8D, 0x80, 0x53, 0x68, 0x13, 0xF0, ++ 0x20, 0x03, 0x40, 0xF0, 0x9F, 0x80, 0xE9, 0x7E, 0xB5, 0xF8, 0x1E, 0xC0, ++ 0xFF, 0x29, 0x0C, 0xBF, 0xA4, 0xF1, 0x18, 0x00, 0xA4, 0xF1, 0x1A, 0x00, ++ 0x1C, 0xF4, 0x80, 0x72, 0x1D, 0xBF, 0x06, 0x38, 0x00, 0xF1, 0x1E, 0x04, ++ 0x02, 0x46, 0x00, 0xF1, 0x18, 0x04, 0xFF, 0x29, 0x00, 0xF0, 0x94, 0x80, ++ 0x6F, 0xF0, 0x7F, 0x0C, 0x4F, 0xF0, 0x00, 0x0E, 0x80, 0xF8, 0x00, 0xC0, ++ 0x80, 0xF8, 0x01, 0xE0, 0x21, 0x80, 0x29, 0x8C, 0xB5, 0xF8, 0x1E, 0xC0, ++ 0x09, 0x01, 0x1C, 0xF4, 0x00, 0x7F, 0xC1, 0x82, 0x63, 0xD1, 0x01, 0x88, ++ 0x0B, 0x43, 0x43, 0xF0, 0x08, 0x01, 0x1C, 0xF4, 0x00, 0x6F, 0x01, 0x80, ++ 0x69, 0xD0, 0x23, 0xF4, 0x40, 0x71, 0x41, 0xF0, 0x08, 0x01, 0x89, 0xB2, ++ 0x01, 0x80, 0x4F, 0xF4, 0xA4, 0x64, 0x1C, 0xF0, 0x04, 0x0F, 0x04, 0xFB, ++ 0x08, 0xF4, 0x18, 0xBF, 0x41, 0xF4, 0x00, 0x51, 0x04, 0xF1, 0x5C, 0x03, ++ 0x18, 0xBF, 0x01, 0x80, 0x07, 0xEB, 0x03, 0x0C, 0xFB, 0x5A, 0x43, 0x81, ++ 0xBC, 0xF8, 0x02, 0x30, 0x83, 0x81, 0x01, 0xF4, 0x40, 0x71, 0xBC, 0xF8, ++ 0x04, 0x30, 0xC3, 0x81, 0xB1, 0xF5, 0x80, 0x7F, 0x5C, 0xD0, 0xB1, 0xF5, ++ 0x00, 0x7F, 0x76, 0xD0, 0x00, 0x29, 0x40, 0xF0, 0x81, 0x80, 0xAB, 0x89, ++ 0x83, 0x80, 0xEB, 0x89, 0xC3, 0x80, 0x2B, 0x8A, 0x03, 0x81, 0x04, 0xF5, ++ 0xB2, 0x74, 0x3B, 0x5B, 0x03, 0x82, 0x3C, 0x44, 0x63, 0x88, 0x43, 0x82, ++ 0xA3, 0x88, 0x83, 0x82, 0xBB, 0xF1, 0x00, 0x0F, 0x1C, 0xD0, 0x00, 0x9B, ++ 0xD3, 0xB1, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x08, 0x77, 0xD7, 0xF8, ++ 0xB0, 0x34, 0x9B, 0x07, 0x0A, 0xD5, 0x6A, 0x7F, 0x2B, 0x8B, 0x4F, 0xF4, ++ 0x1E, 0x71, 0x01, 0xFB, 0x02, 0x92, 0x5B, 0xBA, 0x92, 0x8E, 0x9B, 0xB2, ++ 0x9A, 0x42, 0x07, 0xD0, 0x01, 0x9B, 0x00, 0x2B, 0x7B, 0xD0, 0x93, 0xF8, ++ 0x60, 0x30, 0x01, 0x3B, 0x01, 0x2B, 0x6E, 0xD9, 0x03, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x8F, 0x00, 0x23, 0x75, 0xE7, 0x21, 0x88, 0x41, 0xF0, 0x10, 0x01, ++ 0x21, 0x80, 0x01, 0x88, 0xB5, 0xF8, 0x1E, 0xC0, 0x0B, 0x43, 0x43, 0xF0, ++ 0x08, 0x01, 0x1C, 0xF4, 0x00, 0x6F, 0x01, 0x80, 0x95, 0xD1, 0x1C, 0xF4, ++ 0x80, 0x7F, 0x22, 0xD0, 0x43, 0xF4, 0x42, 0x71, 0x01, 0x80, 0x94, 0xE7, ++ 0x32, 0x4B, 0x11, 0x46, 0xD3, 0xF8, 0xB8, 0x33, 0x98, 0x47, 0x4F, 0xF4, ++ 0x00, 0x43, 0x44, 0xF8, 0x04, 0x0D, 0x56, 0xE7, 0x00, 0x21, 0x81, 0x75, ++ 0xC1, 0x75, 0x7A, 0xE7, 0x26, 0x36, 0x09, 0xEB, 0x06, 0x03, 0x39, 0xF8, ++ 0x06, 0x20, 0x82, 0x80, 0x5A, 0x88, 0xC2, 0x80, 0x9B, 0x88, 0x03, 0x81, ++ 0xAB, 0x89, 0x03, 0x82, 0xEB, 0x89, 0x43, 0x82, 0x2B, 0x8A, 0x83, 0x82, ++ 0xA6, 0xE7, 0x4F, 0xF4, 0xA4, 0x64, 0x04, 0xFB, 0x08, 0x74, 0x94, 0xF8, ++ 0x62, 0x40, 0x00, 0x2C, 0x27, 0xD1, 0x43, 0xF4, 0x84, 0x71, 0x01, 0x80, ++ 0x69, 0xE7, 0xAB, 0x89, 0x83, 0x80, 0xEB, 0x89, 0xC3, 0x80, 0x2B, 0x8A, ++ 0x03, 0x81, 0x6B, 0x8A, 0x03, 0x82, 0xAB, 0x8A, 0x43, 0x82, 0xEB, 0x8A, ++ 0x83, 0x82, 0x8D, 0xE7, 0x26, 0x36, 0x09, 0xEB, 0x06, 0x03, 0x39, 0xF8, ++ 0x06, 0x10, 0x91, 0x80, 0x59, 0x88, 0xD1, 0x80, 0x9B, 0x88, 0x13, 0x81, ++ 0xAB, 0x89, 0x13, 0x82, 0xEB, 0x89, 0x53, 0x82, 0x2B, 0x8A, 0x93, 0x82, ++ 0x6B, 0x8A, 0x13, 0x83, 0xAB, 0x8A, 0x53, 0x83, 0xEB, 0x8A, 0x93, 0x83, ++ 0x76, 0xE7, 0x02, 0x2C, 0x04, 0xBF, 0x43, 0xF4, 0x02, 0x71, 0x01, 0x80, ++ 0x3F, 0xE7, 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, 0x0A, 0x99, 0x99, 0xF8, ++ 0x5D, 0x32, 0x01, 0x2B, 0x88, 0xD9, 0x03, 0x88, 0x43, 0xF4, 0x80, 0x43, ++ 0x03, 0x80, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x18, 0x88, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, 0x2D, 0xE9, 0xF8, 0x43, ++ 0x06, 0x46, 0x54, 0x48, 0x75, 0x7F, 0x34, 0x7F, 0x4F, 0xF4, 0x1E, 0x73, ++ 0x03, 0xFB, 0x05, 0x03, 0x89, 0x46, 0xD3, 0xF8, 0xB4, 0x70, 0xD7, 0xF8, ++ 0x00, 0x80, 0xB8, 0xF1, 0x00, 0x0F, 0x4C, 0xD0, 0x17, 0x46, 0x4D, 0x4A, ++ 0x4F, 0xF4, 0xA4, 0x61, 0x01, 0xFB, 0x04, 0x24, 0xD4, 0xF8, 0xA8, 0x24, ++ 0x00, 0x2A, 0x42, 0xD0, 0xD4, 0xF8, 0xB0, 0x24, 0x92, 0x07, 0x05, 0xD5, ++ 0x32, 0x8B, 0x99, 0x8E, 0x53, 0xBA, 0x9B, 0xB2, 0x99, 0x42, 0x38, 0xD0, ++ 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, 0x05, 0x05, 0xD5, 0xF8, 0xB0, 0x30, ++ 0x23, 0xB1, 0x93, 0xF8, 0x60, 0x30, 0x01, 0x3B, 0x01, 0x2B, 0x40, 0xD9, ++ 0x98, 0xF8, 0x60, 0x30, 0x04, 0x2B, 0x67, 0xD8, 0xDF, 0xE8, 0x03, 0xF0, ++ 0x2A, 0x03, 0x40, 0x2A, 0x49, 0x00, 0x32, 0x8F, 0x42, 0xF4, 0x00, 0x53, ++ 0x03, 0xF4, 0xFE, 0x43, 0x43, 0xEA, 0x12, 0x23, 0x29, 0xF8, 0x08, 0x3C, ++ 0x96, 0xF8, 0x38, 0x30, 0x98, 0xF8, 0x61, 0x20, 0xA9, 0xF1, 0x08, 0x09, ++ 0x43, 0xEA, 0x82, 0x33, 0x43, 0xF4, 0x00, 0x53, 0xA9, 0xF8, 0x02, 0x30, ++ 0x73, 0x8F, 0xA9, 0xF8, 0x04, 0x30, 0xB3, 0x8F, 0xA9, 0xF8, 0x06, 0x30, ++ 0xC7, 0xB1, 0xF2, 0x6A, 0xD4, 0x68, 0x2B, 0x4B, 0x98, 0xF8, 0x62, 0x00, ++ 0x23, 0x40, 0x03, 0x43, 0xD3, 0x60, 0x48, 0x46, 0xBD, 0xE8, 0xF8, 0x83, ++ 0x33, 0x8F, 0x29, 0xF8, 0x04, 0x3C, 0x98, 0xF8, 0x61, 0x20, 0x73, 0x8F, ++ 0xA9, 0xF1, 0x04, 0x09, 0x43, 0xEA, 0x82, 0x33, 0xA9, 0xF8, 0x02, 0x30, ++ 0x00, 0x2F, 0xE6, 0xD1, 0xB2, 0x6C, 0x28, 0x32, 0xE4, 0xE7, 0x95, 0xF8, ++ 0x5D, 0x32, 0x01, 0x2B, 0xBA, 0xD8, 0xE6, 0xE7, 0x33, 0x8F, 0x29, 0xF8, ++ 0x08, 0x3C, 0x98, 0xF8, 0x61, 0x30, 0xA9, 0xF1, 0x08, 0x09, 0x9B, 0x03, ++ 0xCA, 0xE7, 0x98, 0xF8, 0x61, 0x30, 0x29, 0xF8, 0x12, 0x3C, 0xA9, 0xF1, ++ 0x12, 0x09, 0x33, 0x8F, 0xA9, 0xF8, 0x02, 0x30, 0x73, 0x8F, 0xA9, 0xF8, ++ 0x04, 0x30, 0xB3, 0x8F, 0xA9, 0xF8, 0x06, 0x30, 0xF3, 0x8F, 0xA9, 0xF8, ++ 0x08, 0x30, 0x45, 0xF6, 0x36, 0x43, 0xA9, 0xF8, 0x0A, 0x30, 0xA9, 0xF8, ++ 0x0C, 0x30, 0xA9, 0xF8, 0x0E, 0x30, 0xA9, 0xF8, 0x10, 0x30, 0xB7, 0xE7, ++ 0x09, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xB1, 0xDA, ++ 0x07, 0x49, 0x08, 0x48, 0x40, 0xF2, 0xD9, 0x22, 0xF5, 0xF7, 0xA8, 0xF9, ++ 0xAA, 0xE7, 0x00, 0xBF, 0x68, 0x65, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0x00, 0xFC, 0x0F, 0x00, 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x64, 0x7D, 0x15, 0x00, 0x70, 0xB5, 0x1A, 0x4D, 0x1A, 0x4E, 0xD5, 0xF8, ++ 0x68, 0x32, 0x04, 0x46, 0x98, 0x47, 0x60, 0x7F, 0xD5, 0xF8, 0x5C, 0x31, ++ 0x4F, 0xF4, 0x1E, 0x75, 0x05, 0xFB, 0x00, 0x60, 0x98, 0x47, 0xE3, 0x8B, ++ 0xE0, 0x62, 0x99, 0x04, 0x11, 0xD5, 0x63, 0x7F, 0x05, 0xFB, 0x03, 0x66, ++ 0xD6, 0xF8, 0x4C, 0x31, 0xD3, 0xF8, 0x9C, 0x20, 0xA2, 0x62, 0x93, 0xF8, ++ 0xA1, 0x30, 0x2B, 0xB1, 0x94, 0xF8, 0x36, 0x30, 0x43, 0xF0, 0x20, 0x03, ++ 0x84, 0xF8, 0x36, 0x30, 0x70, 0xBD, 0x94, 0xF8, 0x36, 0x30, 0x03, 0xF0, ++ 0x03, 0x02, 0x00, 0xEB, 0x82, 0x00, 0x42, 0x6A, 0x41, 0x69, 0xA1, 0x62, ++ 0x52, 0x03, 0x44, 0xBF, 0x43, 0xF0, 0x20, 0x03, 0x84, 0xF8, 0x36, 0x30, ++ 0x70, 0xBD, 0x00, 0xBF, 0x88, 0x1A, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, ++ 0xF0, 0xB5, 0x83, 0xB0, 0xC3, 0x7E, 0x00, 0x93, 0x04, 0x46, 0xC3, 0x8B, ++ 0x0F, 0x46, 0x16, 0x46, 0x16, 0x49, 0x02, 0x8C, 0x20, 0x20, 0xF4, 0xF7, ++ 0x29, 0xFF, 0xE3, 0x8B, 0xD9, 0x07, 0x1E, 0xD5, 0x13, 0x48, 0xF4, 0xF7, ++ 0xD3, 0xFE, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, 0x03, 0xD4, 0x72, 0xB6, ++ 0x10, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x10, 0x4D, 0x2B, 0x68, 0x3A, 0x46, ++ 0x01, 0x33, 0x31, 0x46, 0x20, 0x46, 0x2B, 0x60, 0xDF, 0xF7, 0x4A, 0xFD, ++ 0x2B, 0x68, 0x33, 0xB1, 0x09, 0x4A, 0x01, 0x3B, 0x12, 0x68, 0x2B, 0x60, ++ 0x0B, 0xB9, 0x02, 0xB1, 0x62, 0xB6, 0x03, 0xB0, 0xF0, 0xBD, 0xDF, 0xF7, ++ 0x61, 0xF9, 0xE3, 0x8B, 0xDA, 0x07, 0xDB, 0xD4, 0xDD, 0xE7, 0x00, 0xBF, ++ 0x3C, 0xC1, 0x15, 0x00, 0x58, 0xC1, 0x15, 0x00, 0x38, 0x61, 0x17, 0x00, ++ 0x6C, 0x28, 0x17, 0x00, 0x02, 0x8B, 0x53, 0xBA, 0x9B, 0xB2, 0xB3, 0xF5, ++ 0xC0, 0x6F, 0x10, 0xB5, 0x04, 0x46, 0x08, 0xD3, 0x4A, 0xF6, 0xAA, 0x23, ++ 0x21, 0xF8, 0x08, 0x3D, 0x03, 0x20, 0x00, 0x23, 0xCA, 0x80, 0x48, 0x80, ++ 0x8B, 0x80, 0x20, 0x46, 0x01, 0x22, 0xFF, 0xF7, 0xBB, 0xFE, 0x04, 0x4B, ++ 0x01, 0x46, 0xD3, 0xF8, 0x20, 0x34, 0x20, 0x46, 0xBD, 0xE8, 0x10, 0x40, ++ 0x18, 0x47, 0x00, 0xBF, 0x88, 0x1A, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0xC5, 0x8B, 0xDF, 0xF8, 0x7C, 0x82, 0x07, 0x7F, 0x4F, 0xF4, 0xA4, 0x6A, ++ 0x0E, 0x46, 0x29, 0x07, 0x83, 0xB0, 0x04, 0x46, 0x0A, 0xFB, 0x07, 0x8A, ++ 0x6B, 0xD4, 0x41, 0x7F, 0xDF, 0xF8, 0x64, 0xB2, 0x03, 0x8B, 0x4F, 0xF4, ++ 0x1E, 0x72, 0x02, 0xFB, 0x01, 0xB1, 0x5B, 0xBA, 0x88, 0x8E, 0x91, 0xF8, ++ 0x30, 0x20, 0x9B, 0xB2, 0x98, 0x42, 0x0F, 0xD0, 0x02, 0x2A, 0x16, 0xD0, ++ 0x8B, 0x49, 0x20, 0x20, 0xF4, 0xF7, 0xB4, 0xFE, 0x20, 0x46, 0x31, 0x46, ++ 0x4F, 0xF0, 0x00, 0x42, 0xFF, 0xF7, 0x78, 0xFF, 0x00, 0x20, 0x03, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x8F, 0x01, 0x3A, 0x25, 0xF4, 0x80, 0x75, 0x01, 0x2A, ++ 0xE5, 0x83, 0x02, 0xD9, 0x91, 0xF8, 0x30, 0x20, 0xE8, 0xE7, 0xDF, 0xF8, ++ 0x1C, 0x92, 0x20, 0x46, 0xD9, 0xF8, 0x2C, 0x34, 0x98, 0x47, 0x63, 0x7F, ++ 0x4F, 0xF4, 0x1E, 0x72, 0x02, 0xFB, 0x03, 0xBB, 0x9B, 0xF8, 0x30, 0x30, ++ 0x02, 0x2B, 0x00, 0xF0, 0xA2, 0x80, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, ++ 0x07, 0x87, 0x77, 0x4A, 0x3B, 0x6C, 0x77, 0x49, 0x1F, 0x79, 0x77, 0x4B, ++ 0x00, 0x2F, 0x0C, 0xBF, 0x0F, 0x46, 0x17, 0x46, 0xE7, 0x62, 0x7D, 0x69, ++ 0x93, 0xF8, 0xBD, 0x20, 0xC5, 0xF3, 0xC2, 0x28, 0xED, 0xB2, 0x00, 0x2A, ++ 0x40, 0xF0, 0xB4, 0x80, 0xD9, 0xF8, 0x38, 0x33, 0x50, 0x46, 0x01, 0xAA, ++ 0x0D, 0xF1, 0x03, 0x01, 0x98, 0x47, 0x05, 0xF0, 0x7C, 0x03, 0x58, 0xEA, ++ 0x03, 0x03, 0x0C, 0xBF, 0x9D, 0xF8, 0x03, 0x30, 0x9D, 0xF8, 0x04, 0x30, ++ 0x43, 0xEA, 0x03, 0x23, 0x7B, 0x62, 0xE3, 0x8B, 0xDB, 0x07, 0x4C, 0xD4, ++ 0xA1, 0x6C, 0xD9, 0xF8, 0x1C, 0x34, 0xA8, 0x31, 0x20, 0x46, 0x98, 0x47, ++ 0x45, 0xE0, 0x00, 0x23, 0xEA, 0x06, 0x01, 0x93, 0x5B, 0xD5, 0x5D, 0x4B, ++ 0xE3, 0x62, 0x15, 0xF0, 0x80, 0x05, 0x7D, 0xD1, 0xA8, 0x46, 0xDF, 0xF8, ++ 0x80, 0x91, 0x5B, 0x4F, 0xD9, 0xF8, 0x38, 0x33, 0x50, 0x46, 0x0D, 0xF1, ++ 0x03, 0x02, 0x0D, 0xF1, 0x02, 0x01, 0x98, 0x47, 0xE2, 0x6A, 0x4F, 0xF0, ++ 0x00, 0x0A, 0xA3, 0x68, 0x02, 0xEB, 0x8A, 0x00, 0x23, 0xF0, 0x60, 0x41, ++ 0x13, 0xF0, 0x80, 0x4F, 0x41, 0xF0, 0x00, 0x51, 0x14, 0xBF, 0x41, 0x61, ++ 0x43, 0x69, 0x97, 0xF8, 0xBD, 0x10, 0xC3, 0xF3, 0xC2, 0x20, 0x03, 0xF0, ++ 0x7F, 0x03, 0x51, 0xBB, 0x08, 0xBB, 0x03, 0x2B, 0x02, 0xEB, 0x8A, 0x01, ++ 0x1D, 0xD8, 0x9D, 0xF8, 0x02, 0x30, 0x43, 0xEA, 0x03, 0x23, 0x4B, 0x62, ++ 0x0A, 0xF1, 0x01, 0x0A, 0xBA, 0xF1, 0x04, 0x0F, 0xDD, 0xD1, 0x00, 0x23, ++ 0xC4, 0xE9, 0x09, 0x33, 0x01, 0x9A, 0x84, 0xF8, 0x32, 0x80, 0x84, 0xF8, ++ 0x33, 0x50, 0x84, 0xF8, 0x42, 0x50, 0x84, 0xF8, 0x35, 0x20, 0xD9, 0xF8, ++ 0x94, 0x33, 0x31, 0x46, 0x20, 0x46, 0x98, 0x47, 0x03, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x8F, 0x9D, 0xF8, 0x03, 0x30, 0x02, 0xEB, 0x8A, 0x01, 0x43, 0xEA, ++ 0x03, 0x23, 0x4B, 0x62, 0xDE, 0xE7, 0x19, 0x46, 0xD1, 0xF7, 0xF0, 0xFD, ++ 0xE2, 0x6A, 0x02, 0xEB, 0x8A, 0x03, 0x40, 0xEA, 0x00, 0x20, 0x58, 0x62, ++ 0xD4, 0xE7, 0x9A, 0xF8, 0xC0, 0x34, 0x00, 0x2B, 0x9F, 0xD1, 0xDA, 0xF8, ++ 0x40, 0x20, 0x2D, 0x4B, 0x11, 0x79, 0x2B, 0x4A, 0x00, 0x29, 0x18, 0xBF, ++ 0x13, 0x46, 0xC3, 0x62, 0x97, 0xE7, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, ++ 0x07, 0x83, 0x93, 0xF8, 0x62, 0x20, 0x52, 0xB3, 0x02, 0x2A, 0x04, 0xD1, ++ 0x9B, 0xF8, 0x70, 0x32, 0x00, 0x2B, 0x7F, 0xF4, 0x50, 0xAF, 0x24, 0x4B, ++ 0x1B, 0x78, 0x1B, 0xB9, 0xD9, 0xF8, 0x1C, 0x30, 0x20, 0x46, 0x98, 0x47, ++ 0x20, 0x46, 0xFF, 0xF7, 0x67, 0xFE, 0x6E, 0xE7, 0x00, 0x22, 0xC0, 0x21, ++ 0x20, 0x46, 0x01, 0xF0, 0x1D, 0xFB, 0x01, 0x28, 0x1C, 0xD0, 0x02, 0x28, ++ 0x15, 0xD0, 0xE3, 0x8B, 0x00, 0x25, 0x23, 0xF0, 0x80, 0x03, 0xE3, 0x83, ++ 0xA8, 0x46, 0x72, 0xE7, 0x05, 0xF0, 0x7F, 0x01, 0x40, 0x46, 0xD1, 0xF7, ++ 0xAD, 0xFD, 0x40, 0xEA, 0x00, 0x20, 0x78, 0x62, 0x55, 0xE7, 0x93, 0xF8, ++ 0xAC, 0x30, 0x00, 0x2B, 0x7F, 0xF4, 0x27, 0xAF, 0xD5, 0xE7, 0x12, 0x23, ++ 0x00, 0x25, 0x01, 0x93, 0xA8, 0x46, 0x5E, 0xE7, 0x01, 0xA9, 0x20, 0x46, ++ 0xFF, 0xF7, 0x46, 0xFB, 0xA3, 0x6C, 0x05, 0x46, 0x03, 0xF1, 0xA8, 0x01, ++ 0x03, 0xF1, 0xA0, 0x00, 0x18, 0x22, 0x07, 0xF0, 0x75, 0xFA, 0xED, 0xB2, ++ 0x4F, 0xF0, 0x18, 0x08, 0x4D, 0xE7, 0x00, 0xBF, 0x70, 0xC1, 0x15, 0x00, ++ 0x84, 0x3C, 0x18, 0x00, 0xC4, 0x3C, 0x18, 0x00, 0x2C, 0x19, 0x17, 0x00, ++ 0xB8, 0x34, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, ++ 0x88, 0x1A, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x41, 0x51, 0x4A, 0x43, 0x7F, ++ 0x4F, 0xF4, 0x1E, 0x75, 0x05, 0xFB, 0x03, 0x23, 0x86, 0xB0, 0xD3, 0xF8, ++ 0xB4, 0x30, 0x1E, 0x68, 0x8E, 0xB1, 0x90, 0xF8, 0x35, 0x30, 0x04, 0x46, ++ 0x6B, 0xB1, 0x90, 0xF8, 0x34, 0x30, 0x85, 0x6C, 0x96, 0xF8, 0x60, 0x20, ++ 0xED, 0x1A, 0x01, 0x2A, 0x05, 0xF1, 0xA8, 0x05, 0x06, 0xD0, 0x03, 0x2A, ++ 0x51, 0xD0, 0x00, 0x2A, 0x4F, 0xD0, 0x06, 0xB0, 0xBD, 0xE8, 0xF0, 0x81, ++ 0x07, 0x8E, 0x42, 0x4A, 0x00, 0x91, 0x3B, 0x44, 0x06, 0xF1, 0x50, 0x01, ++ 0xD2, 0xF8, 0x7C, 0x73, 0x2A, 0x46, 0xB8, 0x47, 0x3E, 0x4B, 0x1B, 0x68, ++ 0x1B, 0x78, 0x9A, 0x07, 0xED, 0xD5, 0x96, 0xF8, 0x60, 0x20, 0x01, 0x2A, ++ 0x06, 0xF1, 0x64, 0x08, 0x3E, 0xD1, 0x23, 0x8E, 0x94, 0xF8, 0x34, 0x70, ++ 0x0C, 0x33, 0x1F, 0x44, 0xBF, 0xB2, 0x39, 0x1F, 0x4F, 0xF0, 0xFF, 0x33, ++ 0x03, 0x22, 0x28, 0x46, 0xD6, 0xF7, 0xD8, 0xF8, 0xD6, 0xE9, 0x12, 0x03, ++ 0x32, 0x49, 0x94, 0xF8, 0x1C, 0xC0, 0x88, 0x80, 0x31, 0x4A, 0x00, 0x0C, ++ 0x4F, 0xF4, 0xA4, 0x6E, 0x40, 0xEA, 0x03, 0x40, 0x0E, 0xFB, 0x0C, 0x22, ++ 0x08, 0x60, 0x02, 0xAB, 0x40, 0x46, 0xF2, 0xF7, 0x9F, 0xFA, 0x02, 0xA8, ++ 0x10, 0x21, 0xF2, 0xF7, 0x5F, 0xFC, 0x96, 0xF8, 0x60, 0x20, 0xCA, 0xB1, ++ 0x03, 0x2A, 0x17, 0xD0, 0x03, 0x20, 0xD6, 0xF7, 0xF1, 0xF8, 0x39, 0x46, ++ 0x02, 0x46, 0x28, 0x46, 0xF2, 0xF7, 0x84, 0xFA, 0x39, 0x46, 0x28, 0x46, ++ 0xF2, 0xF7, 0x7A, 0xFC, 0x06, 0xB0, 0xBD, 0xE8, 0xF0, 0x81, 0x1D, 0x4B, ++ 0x1B, 0x68, 0x1B, 0x78, 0x9B, 0x07, 0xAA, 0xD5, 0x06, 0xF1, 0x64, 0x08, ++ 0x00, 0x27, 0xE4, 0xE7, 0x23, 0x8E, 0x94, 0xF8, 0x34, 0x70, 0x04, 0x33, ++ 0x1F, 0x44, 0xBF, 0xB2, 0x39, 0x1F, 0x4F, 0xF0, 0xFF, 0x33, 0x03, 0x22, ++ 0x28, 0x46, 0xD6, 0xF7, 0x97, 0xF8, 0x96, 0xF8, 0x60, 0x30, 0xB6, 0xF8, ++ 0x48, 0x10, 0xB6, 0xF8, 0x4A, 0x20, 0xAD, 0xF8, 0x08, 0x10, 0x8D, 0xF8, ++ 0x0A, 0x20, 0x41, 0x46, 0x4B, 0xB9, 0x05, 0x22, 0x0D, 0xF1, 0x0B, 0x00, ++ 0x07, 0xF0, 0xCA, 0xF9, 0x02, 0xA8, 0x08, 0x21, 0xF2, 0xF7, 0x20, 0xFC, ++ 0xC4, 0xE7, 0x0D, 0x22, 0x0D, 0xF1, 0x0B, 0x00, 0x07, 0xF0, 0xC0, 0xF9, ++ 0x02, 0xA8, 0x10, 0x21, 0xF2, 0xF7, 0x16, 0xFC, 0xBA, 0xE7, 0x00, 0xBF, ++ 0x68, 0x65, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x34, 0x36, 0x17, 0x00, ++ 0xA0, 0x34, 0x17, 0x00, 0x74, 0x88, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x41, ++ 0xC5, 0x6C, 0xC3, 0x8B, 0x2F, 0x69, 0x02, 0x8C, 0x2A, 0x81, 0x00, 0x26, ++ 0x13, 0xF0, 0x08, 0x02, 0x2E, 0x61, 0x04, 0x46, 0x07, 0xF4, 0x00, 0x06, ++ 0x88, 0x46, 0x07, 0xF0, 0x40, 0x47, 0x1C, 0xD0, 0x99, 0x06, 0x01, 0xD5, ++ 0x00, 0x2E, 0x6C, 0xD0, 0x9A, 0x05, 0x3E, 0xD4, 0xB7, 0xF1, 0x40, 0x4F, ++ 0x20, 0xD0, 0xE3, 0x7E, 0xFF, 0x2B, 0x22, 0xD1, 0x2B, 0x69, 0x62, 0x6A, ++ 0x01, 0x20, 0x02, 0xF4, 0x00, 0x12, 0x16, 0xB1, 0x43, 0xF0, 0x08, 0x03, ++ 0x2B, 0x61, 0x00, 0x2A, 0x47, 0xD0, 0x43, 0xF0, 0x01, 0x03, 0x28, 0x73, ++ 0x2B, 0x61, 0xBD, 0xE8, 0xF0, 0x81, 0x9B, 0x05, 0xE6, 0xD5, 0x43, 0x7F, ++ 0x2A, 0x49, 0x4F, 0xF4, 0x1E, 0x70, 0x00, 0xFB, 0x03, 0x13, 0xB7, 0xF1, ++ 0x40, 0x4F, 0x83, 0xF8, 0x32, 0x20, 0xDE, 0xD1, 0x2B, 0x69, 0x43, 0xF0, ++ 0x04, 0x03, 0x2B, 0x61, 0xDD, 0xE7, 0x31, 0x1E, 0x42, 0x46, 0x18, 0xBF, ++ 0x01, 0x21, 0x20, 0x46, 0x01, 0xF0, 0x3A, 0xF8, 0x63, 0x6A, 0x13, 0xF4, ++ 0x00, 0x12, 0x20, 0xD0, 0x03, 0xF4, 0x60, 0x13, 0xB3, 0xF5, 0x60, 0x1F, ++ 0x01, 0xD0, 0x00, 0x23, 0x6B, 0x73, 0x2B, 0x69, 0x00, 0x2E, 0xD2, 0xD0, ++ 0xCC, 0xE7, 0x19, 0x4B, 0x60, 0x7F, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0x1A, 0xDB, 0x00, 0x23, 0x1A, 0x46, 0x17, 0x21, 0xE0, 0xF7, ++ 0x0D, 0xFA, 0x12, 0x4A, 0x63, 0x7F, 0x4F, 0xF4, 0x1E, 0x71, 0x01, 0xFB, ++ 0x03, 0x23, 0x00, 0x22, 0x83, 0xF8, 0x32, 0x20, 0xAA, 0xE7, 0x2B, 0x69, ++ 0x0E, 0xB1, 0x43, 0xF0, 0x08, 0x03, 0x01, 0x22, 0x43, 0xF0, 0x01, 0x03, ++ 0x6A, 0x73, 0x28, 0x73, 0x2B, 0x61, 0xBD, 0xE8, 0xF0, 0x81, 0xFF, 0x28, ++ 0xE2, 0xD1, 0x08, 0x48, 0x08, 0x49, 0x4F, 0xF4, 0xA4, 0x62, 0xF4, 0xF7, ++ 0x89, 0xFE, 0x60, 0x7F, 0xDA, 0xE7, 0xFF, 0xF7, 0xC7, 0xF9, 0xE3, 0x8B, ++ 0x8E, 0xE7, 0x00, 0xBF, 0x68, 0x65, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x84, 0xC1, 0x15, 0x00, 0x70, 0x79, 0x15, 0x00, 0x70, 0xB5, 0x90, 0xF8, ++ 0x33, 0x30, 0x82, 0xB0, 0x04, 0x46, 0x0D, 0x46, 0x16, 0x46, 0x7B, 0xB1, ++ 0x90, 0xF8, 0x35, 0x20, 0x01, 0x92, 0x18, 0x46, 0x2B, 0x88, 0x2E, 0x44, ++ 0x43, 0xF4, 0x80, 0x43, 0x31, 0x18, 0x2B, 0x80, 0x20, 0x46, 0x00, 0x22, ++ 0xFF, 0xF7, 0x12, 0xFC, 0x02, 0xB0, 0x70, 0xBD, 0x01, 0xA9, 0xFF, 0xF7, ++ 0xCD, 0xF9, 0x01, 0x9B, 0x84, 0xF8, 0x33, 0x00, 0x84, 0xF8, 0x35, 0x30, ++ 0xEA, 0xE7, 0x00, 0xBF, 0x10, 0xB4, 0x0C, 0x88, 0x0B, 0x46, 0x44, 0xF4, ++ 0x80, 0x44, 0x11, 0x44, 0x1C, 0x80, 0x00, 0x22, 0x5D, 0xF8, 0x04, 0x4B, ++ 0xFF, 0xF7, 0xFA, 0xBB, 0xF0, 0xB5, 0x00, 0x22, 0x18, 0x4C, 0x85, 0xB0, ++ 0x05, 0x46, 0x0F, 0x46, 0x02, 0xE0, 0x01, 0x32, 0x20, 0x2A, 0x26, 0xD0, ++ 0xA5, 0x42, 0x96, 0xB2, 0x04, 0xF1, 0x18, 0x04, 0xF7, 0xD1, 0x12, 0x02, ++ 0x02, 0xF4, 0x7F, 0x42, 0x42, 0xF0, 0x08, 0x00, 0xF2, 0xF7, 0xF6, 0xFF, ++ 0x04, 0x28, 0x18, 0xD1, 0x17, 0xF4, 0x00, 0x03, 0x02, 0xD1, 0xEA, 0x7C, ++ 0x02, 0x2A, 0x06, 0xD9, 0x28, 0x7B, 0x31, 0x46, 0x05, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x40, 0x00, 0xF0, 0x65, 0xBC, 0x08, 0x49, 0x01, 0x32, 0xEA, 0x74, ++ 0x27, 0x22, 0xCD, 0xE9, 0x01, 0x21, 0x00, 0x93, 0x28, 0x7B, 0x02, 0x22, ++ 0x29, 0x46, 0x00, 0xF0, 0xBB, 0xFC, 0x05, 0xB0, 0xF0, 0xBD, 0x00, 0xBF, ++ 0xF4, 0xE4, 0x17, 0x00, 0xE5, 0xFE, 0x14, 0x00, 0x2D, 0xE9, 0xF0, 0x43, ++ 0x10, 0x46, 0x85, 0xB0, 0x14, 0x46, 0x0F, 0x46, 0xF2, 0xF7, 0xCC, 0xFF, ++ 0x03, 0x28, 0x09, 0xD0, 0x50, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0x72, 0xDB, 0x00, 0x20, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x83, ++ 0x4C, 0x4E, 0x4F, 0xEA, 0x14, 0x28, 0x08, 0xEB, 0x48, 0x03, 0x06, 0xEB, ++ 0xC3, 0x06, 0x96, 0xF8, 0x0D, 0x90, 0xB9, 0xF1, 0x00, 0x0F, 0x39, 0xD0, ++ 0xB9, 0xF1, 0x01, 0x0F, 0x29, 0xD1, 0xBB, 0x78, 0x00, 0x2B, 0x7C, 0xD1, ++ 0x05, 0x46, 0x30, 0x46, 0x96, 0xF8, 0x0F, 0x90, 0x00, 0xF0, 0xA0, 0xFF, ++ 0x41, 0x4B, 0x1B, 0x69, 0x73, 0x60, 0x05, 0x22, 0x2B, 0x46, 0x0C, 0x21, ++ 0x41, 0xF2, 0x0B, 0x40, 0x3D, 0x78, 0x7F, 0x78, 0xF2, 0xF7, 0xFA, 0xFC, ++ 0xA9, 0xF1, 0x04, 0x09, 0x4F, 0xFA, 0x89, 0xF9, 0x80, 0xF8, 0x02, 0x90, ++ 0x05, 0x70, 0x47, 0x70, 0xF2, 0xF7, 0x20, 0xFD, 0x73, 0x89, 0x00, 0x2B, ++ 0x39, 0xD1, 0x20, 0x46, 0x01, 0x21, 0xF2, 0xF7, 0xE3, 0xFE, 0x00, 0x20, ++ 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x83, 0x2F, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0xBC, 0xDA, 0x2F, 0x49, 0x2F, 0x48, 0x40, 0xF2, ++ 0x29, 0x12, 0xF4, 0xF7, 0xD3, 0xFD, 0xB5, 0xE7, 0xBA, 0x78, 0x33, 0x7C, ++ 0x72, 0xBB, 0xB0, 0x7B, 0xF1, 0x7B, 0x02, 0x92, 0x9B, 0x00, 0x43, 0xEA, ++ 0x40, 0x03, 0x43, 0xEA, 0x81, 0x13, 0xCD, 0xE9, 0x00, 0x32, 0x31, 0x46, ++ 0x73, 0x7C, 0x30, 0x7B, 0x01, 0x22, 0x00, 0xF0, 0x47, 0xFC, 0x3B, 0x78, ++ 0x7D, 0x78, 0x23, 0x4A, 0x1F, 0x48, 0x71, 0x89, 0x03, 0xEB, 0x83, 0x07, ++ 0xC3, 0xEB, 0x07, 0x13, 0x2B, 0x44, 0x02, 0xEB, 0xC3, 0x03, 0x83, 0xF8, ++ 0xA4, 0x81, 0x03, 0x69, 0x73, 0x60, 0x00, 0x29, 0xC5, 0xD0, 0x40, 0x46, ++ 0x00, 0xF0, 0x9A, 0xFB, 0xC1, 0xE7, 0x17, 0x49, 0x17, 0x48, 0xC8, 0x22, ++ 0xF4, 0xF7, 0xA4, 0xFD, 0x00, 0x20, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x83, ++ 0xB1, 0x7B, 0xF2, 0x7B, 0xCD, 0xF8, 0x08, 0x90, 0x9B, 0x00, 0x43, 0xEA, ++ 0x41, 0x03, 0x43, 0xEA, 0x82, 0x13, 0x25, 0x22, 0xCD, 0xE9, 0x00, 0x32, ++ 0x31, 0x46, 0x30, 0x7B, 0x73, 0x7C, 0x01, 0x22, 0x00, 0xF0, 0x16, 0xFC, ++ 0x49, 0x46, 0x20, 0x46, 0xF2, 0xF7, 0x8A, 0xFE, 0x6C, 0xE7, 0x40, 0x46, ++ 0x00, 0xF0, 0xF8, 0xFA, 0x20, 0x46, 0x00, 0x21, 0xF2, 0xF7, 0x82, 0xFE, ++ 0x64, 0xE7, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, 0xF4, 0xE4, 0x17, 0x00, ++ 0x00, 0x10, 0x50, 0x40, 0x70, 0x79, 0x15, 0x00, 0x64, 0x7D, 0x15, 0x00, ++ 0x68, 0x65, 0x17, 0x00, 0xF8, 0xB5, 0x8B, 0x78, 0x02, 0x2B, 0x01, 0xD0, ++ 0x00, 0x20, 0xF8, 0xBD, 0x02, 0xF4, 0x7F, 0x40, 0x40, 0xF0, 0x08, 0x00, ++ 0x0C, 0x46, 0x15, 0x0A, 0xF2, 0xF7, 0x0E, 0xFF, 0x04, 0x28, 0xF3, 0xD1, ++ 0x11, 0x4E, 0x05, 0xEB, 0x45, 0x03, 0x06, 0xEB, 0xC3, 0x06, 0x73, 0x7B, ++ 0x01, 0x2B, 0x04, 0xD0, 0x0E, 0x4B, 0x28, 0x46, 0x9B, 0x6A, 0x98, 0x47, ++ 0xE6, 0xE7, 0x70, 0x69, 0x00, 0xF0, 0x1E, 0xFF, 0xF3, 0x7B, 0x67, 0x78, ++ 0x26, 0x78, 0xC3, 0xF1, 0x04, 0x03, 0x1C, 0x18, 0x05, 0x22, 0x03, 0x23, ++ 0x0C, 0x21, 0x41, 0xF2, 0x0B, 0x40, 0xF2, 0xF7, 0x4D, 0xFC, 0x64, 0xB2, ++ 0x84, 0x70, 0x06, 0x70, 0x47, 0x70, 0xF2, 0xF7, 0x77, 0xFC, 0xE3, 0xE7, ++ 0xF4, 0xE4, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0xB7, 0x4F, 0xCE, 0x79, 0xB7, 0x4A, 0x4F, 0xF4, 0x1E, 0x75, 0x05, 0xFB, ++ 0x06, 0x75, 0x0C, 0x46, 0x95, 0xF8, 0x22, 0x30, 0x4F, 0xF4, 0xA4, 0x61, ++ 0x01, 0xFB, 0x03, 0x23, 0x85, 0xB0, 0x93, 0xF8, 0x64, 0x30, 0x1B, 0xB9, ++ 0x00, 0x20, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x06, 0x20, 0x94, 0xF8, ++ 0x0D, 0x80, 0xF2, 0xF7, 0xC7, 0xFE, 0x09, 0x28, 0x04, 0xF1, 0x0C, 0x09, ++ 0xF2, 0xD0, 0xB8, 0xF1, 0x01, 0x0F, 0x5B, 0xD0, 0xB8, 0xF1, 0x02, 0x0F, ++ 0x1B, 0xD0, 0xB8, 0xF1, 0x00, 0x0F, 0xE9, 0xD1, 0xB9, 0xF8, 0x03, 0x80, ++ 0x99, 0xF8, 0x02, 0xB0, 0xC8, 0xF3, 0x83, 0x0A, 0xBA, 0xF1, 0x08, 0x0F, ++ 0x04, 0xD8, 0xA1, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x00, 0xF0, 0x87, 0x80, ++ 0x25, 0x23, 0x00, 0x21, 0xCD, 0xE9, 0x00, 0x83, 0x30, 0x46, 0x5B, 0x46, ++ 0x02, 0x91, 0x01, 0x22, 0x00, 0xF0, 0x82, 0xFB, 0xD0, 0xE7, 0xB9, 0xF8, ++ 0x02, 0x10, 0xB1, 0xF5, 0x10, 0x4F, 0x4F, 0xEA, 0x11, 0x35, 0xC9, 0xD2, ++ 0xE3, 0x79, 0xFF, 0x2B, 0xC6, 0xD0, 0x09, 0x05, 0x2A, 0x46, 0x40, 0xF1, ++ 0xBA, 0x80, 0x93, 0x49, 0x4F, 0xF4, 0x00, 0x60, 0xF4, 0xF7, 0xA4, 0xFA, ++ 0xE3, 0x79, 0x03, 0xEB, 0x83, 0x02, 0xC3, 0xEB, 0x02, 0x13, 0x2B, 0x44, ++ 0x07, 0xEB, 0xC3, 0x07, 0x97, 0xF8, 0xA4, 0x51, 0x21, 0x2D, 0xB1, 0xD0, ++ 0x2E, 0x02, 0x46, 0xF0, 0x08, 0x06, 0x30, 0x46, 0xF2, 0xF7, 0x7C, 0xFE, ++ 0x04, 0x28, 0xA9, 0xD0, 0x31, 0x46, 0x42, 0xF2, 0x01, 0x00, 0xF2, 0xF7, ++ 0xE1, 0xFA, 0x30, 0x46, 0xF2, 0xF7, 0x72, 0xFE, 0x01, 0x28, 0x00, 0xF0, ++ 0xD2, 0x80, 0x30, 0x46, 0xF2, 0xF7, 0x6C, 0xFE, 0x03, 0x28, 0x00, 0xF0, ++ 0xCC, 0x80, 0x7F, 0x4B, 0x28, 0x46, 0x9B, 0x6A, 0x98, 0x47, 0x93, 0xE7, ++ 0xB9, 0xF8, 0x05, 0x50, 0xC5, 0xF3, 0x83, 0x06, 0x08, 0x2E, 0x8D, 0xD8, ++ 0xE3, 0x79, 0x7A, 0x49, 0x03, 0xEB, 0x83, 0x02, 0xC3, 0xEB, 0x02, 0x13, ++ 0x33, 0x44, 0x07, 0xEB, 0xC3, 0x07, 0x32, 0x46, 0x97, 0xF8, 0xA5, 0x71, ++ 0x4F, 0xF4, 0x00, 0x60, 0x3B, 0x46, 0xF4, 0xF7, 0x63, 0xFA, 0x21, 0x2F, ++ 0x3F, 0xF4, 0x7A, 0xAF, 0x4F, 0xEA, 0x07, 0x28, 0x48, 0xF0, 0x08, 0x08, ++ 0x40, 0x46, 0xF2, 0xF7, 0x43, 0xFE, 0x02, 0x28, 0x7F, 0xF4, 0x70, 0xAF, ++ 0x41, 0x46, 0x4F, 0xF4, 0x00, 0x50, 0xF2, 0xF7, 0xA7, 0xFA, 0x6A, 0x4A, ++ 0x99, 0xF8, 0x02, 0x10, 0x07, 0xEB, 0x47, 0x03, 0x02, 0xEB, 0xC3, 0x03, ++ 0x58, 0x7C, 0x88, 0x42, 0x03, 0xD1, 0x1B, 0x7C, 0xB3, 0x42, 0x00, 0xF0, ++ 0x9B, 0x80, 0x38, 0x46, 0x00, 0xF0, 0xF4, 0xF9, 0x40, 0x46, 0x00, 0x21, ++ 0xF2, 0xF7, 0x7E, 0xFD, 0x54, 0xE7, 0x60, 0x49, 0x4F, 0xF4, 0x00, 0x60, ++ 0x52, 0x46, 0xF4, 0xF7, 0x35, 0xFA, 0x51, 0x46, 0x30, 0x46, 0xE8, 0xF7, ++ 0x85, 0xF9, 0x00, 0x28, 0x4F, 0xD1, 0x95, 0xF8, 0x24, 0x30, 0x01, 0x2B, ++ 0x3F, 0xF4, 0x68, 0xAF, 0x00, 0xF0, 0x04, 0xFA, 0x21, 0x28, 0x04, 0x46, ++ 0x3F, 0xF4, 0x62, 0xAF, 0x53, 0x4D, 0x55, 0x4A, 0x00, 0xEB, 0x40, 0x01, ++ 0x05, 0xEB, 0xC1, 0x03, 0xC8, 0xF3, 0x40, 0x00, 0x12, 0x68, 0x83, 0xF8, ++ 0x10, 0xA0, 0x00, 0x27, 0x1E, 0x73, 0x83, 0xF8, 0x11, 0xB0, 0x98, 0x73, ++ 0x5F, 0x73, 0x90, 0x6B, 0xB9, 0xF8, 0x05, 0x20, 0x5A, 0x81, 0x4F, 0xEA, ++ 0x98, 0x18, 0x80, 0x45, 0x28, 0xBF, 0x80, 0x46, 0x83, 0xF8, 0x0F, 0x80, ++ 0xB9, 0xF8, 0x07, 0x00, 0xC9, 0x00, 0x00, 0x09, 0x92, 0xB2, 0x6F, 0x50, ++ 0x18, 0x81, 0x1A, 0xB9, 0x44, 0x4A, 0x12, 0x68, 0x52, 0x88, 0x5A, 0x81, ++ 0x30, 0x46, 0x21, 0x46, 0x00, 0xF0, 0x3C, 0xFA, 0x20, 0x02, 0x00, 0xF4, ++ 0x7F, 0x40, 0x40, 0xF0, 0x08, 0x00, 0x03, 0x21, 0xF2, 0xF7, 0x32, 0xFD, ++ 0x08, 0xE7, 0x3D, 0x49, 0x4F, 0xF4, 0x00, 0x60, 0xF4, 0xF7, 0xEA, 0xF9, ++ 0xE3, 0x79, 0x03, 0xEB, 0x83, 0x02, 0xC3, 0xEB, 0x02, 0x13, 0x2B, 0x44, ++ 0x07, 0xEB, 0xC3, 0x07, 0x97, 0xF8, 0xA5, 0x51, 0x44, 0xE7, 0x06, 0xEB, ++ 0x86, 0x03, 0xC6, 0xEB, 0x03, 0x13, 0x53, 0x44, 0x07, 0xEB, 0xC3, 0x07, ++ 0x97, 0xF8, 0xA4, 0x71, 0x3D, 0x02, 0x45, 0xF0, 0x08, 0x05, 0x28, 0x46, ++ 0xF2, 0xF7, 0xBA, 0xFD, 0x01, 0x28, 0x7F, 0xF4, 0x0B, 0xAF, 0x2A, 0x4B, ++ 0x27, 0x4A, 0x1B, 0x68, 0x07, 0xEB, 0x47, 0x01, 0x02, 0xEB, 0xC1, 0x02, ++ 0x99, 0x6B, 0xD2, 0x7B, 0x4F, 0xEA, 0x98, 0x13, 0x8B, 0x42, 0x28, 0xBF, ++ 0x0B, 0x46, 0x9A, 0x42, 0x12, 0xD0, 0x28, 0x46, 0x04, 0x21, 0xF2, 0xF7, ++ 0xFB, 0xFC, 0xE0, 0x79, 0x39, 0x46, 0x00, 0xF0, 0x1D, 0xFA, 0x25, 0x23, ++ 0xF1, 0xE6, 0x30, 0x46, 0x04, 0x21, 0xF2, 0xF7, 0xF1, 0xFC, 0xE0, 0x79, ++ 0x29, 0x46, 0x00, 0xF0, 0x13, 0xFA, 0xC3, 0xE6, 0x00, 0x23, 0xE6, 0xE6, ++ 0xB9, 0xF8, 0x03, 0x30, 0x00, 0x2B, 0x7F, 0xF4, 0x60, 0xAF, 0x18, 0x23, ++ 0x03, 0xFB, 0x07, 0x23, 0xA9, 0x09, 0xDB, 0x7B, 0xB3, 0xEB, 0x95, 0x1F, ++ 0x03, 0xD9, 0x18, 0x23, 0x03, 0xFB, 0x07, 0x23, 0xD9, 0x73, 0x18, 0x23, ++ 0x03, 0xFB, 0x07, 0x22, 0x05, 0xF0, 0x01, 0x05, 0x95, 0x74, 0xE0, 0x79, ++ 0x39, 0x46, 0x00, 0xF0, 0xD1, 0xF9, 0x40, 0x46, 0x03, 0x21, 0xF2, 0xF7, ++ 0xCB, 0xFC, 0xA1, 0xE6, 0x68, 0x65, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, ++ 0xB9, 0x34, 0x17, 0x00, 0xE4, 0xC1, 0x15, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0xC0, 0xC1, 0x15, 0x00, 0xF4, 0xE4, 0x17, 0x00, 0xA4, 0xC1, 0x15, 0x00, ++ 0x78, 0x36, 0x17, 0x00, 0xC8, 0x35, 0x17, 0x00, 0x08, 0xC2, 0x15, 0x00, ++ 0x10, 0xB5, 0x10, 0x46, 0x14, 0x46, 0xF2, 0xF7, 0x57, 0xFD, 0x02, 0x28, ++ 0x01, 0xD0, 0x00, 0x20, 0x10, 0xBD, 0x20, 0x0A, 0x00, 0xF0, 0x1A, 0xF9, ++ 0x20, 0x46, 0x00, 0x21, 0xF2, 0xF7, 0xA4, 0xFC, 0x00, 0x20, 0x10, 0xBD, ++ 0x70, 0xB5, 0x10, 0x46, 0x84, 0xB0, 0x14, 0x46, 0xF2, 0xF7, 0x44, 0xFD, ++ 0x01, 0x28, 0x02, 0xD0, 0x00, 0x20, 0x04, 0xB0, 0x70, 0xBD, 0x20, 0x0A, ++ 0x13, 0x4A, 0x00, 0xEB, 0x40, 0x05, 0x52, 0xF8, 0x35, 0x60, 0x02, 0xEB, ++ 0xC5, 0x05, 0x3E, 0xB9, 0x10, 0x4B, 0x6A, 0x68, 0x19, 0x69, 0x6B, 0x89, ++ 0x52, 0x1A, 0x12, 0xEB, 0x83, 0x23, 0x04, 0xD4, 0x00, 0xF0, 0x74, 0xF9, ++ 0x00, 0x20, 0x04, 0xB0, 0x70, 0xBD, 0x20, 0x46, 0x04, 0x21, 0x2C, 0x7B, ++ 0xF2, 0xF7, 0x7C, 0xFC, 0x08, 0x4B, 0x02, 0x93, 0x27, 0x22, 0x01, 0x92, ++ 0x00, 0x96, 0x20, 0x46, 0x33, 0x46, 0x29, 0x46, 0x02, 0x22, 0xEE, 0x74, ++ 0x00, 0xF0, 0xF8, 0xF9, 0xD4, 0xE7, 0x00, 0xBF, 0xF4, 0xE4, 0x17, 0x00, ++ 0x00, 0x10, 0x50, 0x40, 0xE5, 0xFE, 0x14, 0x00, 0x90, 0xF8, 0x46, 0x30, ++ 0x90, 0xF8, 0x47, 0x20, 0x19, 0x44, 0xB1, 0xFB, 0xF2, 0xF0, 0x02, 0xFB, ++ 0x10, 0x10, 0x70, 0x47, 0x90, 0xF8, 0x46, 0x30, 0x90, 0xF8, 0x48, 0x00, ++ 0x19, 0x44, 0x08, 0x40, 0x70, 0x47, 0x00, 0xBF, 0x03, 0x4B, 0x1B, 0x69, ++ 0xA0, 0xEB, 0x93, 0x20, 0xC0, 0xF3, 0xC0, 0x30, 0x70, 0x47, 0x00, 0xBF, ++ 0x00, 0x10, 0x50, 0x40, 0x70, 0xB5, 0x90, 0xF8, 0x46, 0x30, 0x03, 0x44, ++ 0x9A, 0x79, 0x02, 0x2A, 0x17, 0xD1, 0x00, 0x26, 0x04, 0x46, 0x35, 0x46, ++ 0x9D, 0x71, 0xA3, 0x88, 0x22, 0x68, 0x01, 0x33, 0xC3, 0xF3, 0x0B, 0x03, ++ 0xA3, 0x80, 0x01, 0x21, 0x20, 0x46, 0x90, 0x47, 0x54, 0xFA, 0x80, 0xF3, ++ 0x84, 0xF8, 0x46, 0x00, 0x9A, 0x79, 0x01, 0x36, 0x02, 0x2A, 0x76, 0xB2, ++ 0xEC, 0xD0, 0x30, 0x46, 0x70, 0xBD, 0x00, 0x26, 0x30, 0x46, 0x70, 0xBD, ++ 0x38, 0xB5, 0x85, 0x88, 0x03, 0x68, 0x49, 0x1B, 0xC1, 0xF3, 0x0B, 0x01, ++ 0x04, 0x46, 0x15, 0x46, 0x98, 0x47, 0x20, 0x44, 0x85, 0x71, 0x38, 0xBD, ++ 0xF8, 0xB5, 0x05, 0x46, 0x33, 0x48, 0x6F, 0x6A, 0x01, 0xEB, 0x41, 0x01, ++ 0x00, 0xEB, 0xC1, 0x00, 0xBF, 0x02, 0x44, 0x69, 0x03, 0xD5, 0x11, 0x46, ++ 0x4B, 0xB3, 0x00, 0x2A, 0x49, 0xD0, 0xA2, 0x88, 0x29, 0x8C, 0x23, 0x68, ++ 0x89, 0x1A, 0xC1, 0xF3, 0x0B, 0x01, 0x20, 0x46, 0x98, 0x47, 0x20, 0x44, ++ 0x02, 0x23, 0x83, 0x71, 0x94, 0xF8, 0x46, 0x30, 0x23, 0x44, 0x00, 0x26, ++ 0x9A, 0x79, 0x02, 0x2A, 0x13, 0xD1, 0x35, 0x46, 0x9D, 0x71, 0xA3, 0x88, ++ 0x22, 0x68, 0x01, 0x33, 0xC3, 0xF3, 0x0B, 0x03, 0xA3, 0x80, 0x01, 0x21, ++ 0x20, 0x46, 0x90, 0x47, 0x54, 0xFA, 0x80, 0xF3, 0x84, 0xF8, 0x46, 0x00, ++ 0x9A, 0x79, 0x01, 0x36, 0x02, 0x2A, 0x76, 0xB2, 0xEC, 0xD0, 0x30, 0x46, ++ 0xF8, 0xBD, 0x00, 0x2A, 0xD5, 0xD1, 0x19, 0x4B, 0xB5, 0xF8, 0x40, 0x00, ++ 0x1B, 0x69, 0xA0, 0xEB, 0x93, 0x23, 0x1B, 0x04, 0xCD, 0xD4, 0xEA, 0x8B, ++ 0xEB, 0x6C, 0x6F, 0xEA, 0x42, 0x42, 0x1C, 0x69, 0x6F, 0xEA, 0x52, 0x42, ++ 0xEA, 0x83, 0x44, 0xF0, 0x02, 0x04, 0x6A, 0x8F, 0x0E, 0x46, 0x29, 0x8F, ++ 0x19, 0x80, 0x1C, 0x61, 0xE9, 0x8F, 0xAC, 0x8F, 0x5A, 0x80, 0x2A, 0x8C, ++ 0x1A, 0x81, 0x9C, 0x80, 0xD9, 0x80, 0x58, 0x81, 0xDB, 0xE7, 0x09, 0x48, ++ 0xB5, 0xF8, 0x40, 0x20, 0x03, 0x69, 0xA2, 0xEB, 0x93, 0x23, 0x1E, 0x04, ++ 0xAD, 0xD4, 0x03, 0x69, 0x05, 0x48, 0xA2, 0xEB, 0x93, 0x22, 0xC2, 0xF3, ++ 0xC0, 0x32, 0xF4, 0xF7, 0x23, 0xF8, 0xA4, 0xE7, 0xF4, 0xE4, 0x17, 0x00, ++ 0x00, 0x10, 0x50, 0x40, 0x34, 0xC2, 0x15, 0x00, 0xF8, 0xB5, 0x0D, 0x4D, ++ 0x0D, 0x4E, 0xFF, 0x27, 0x2F, 0x73, 0x00, 0x24, 0x08, 0xE0, 0x0F, 0x2C, ++ 0x85, 0xF8, 0x24, 0x70, 0x03, 0xDD, 0x4C, 0x23, 0x03, 0xFB, 0x04, 0x63, ++ 0xEB, 0x62, 0x18, 0x35, 0x20, 0x02, 0x00, 0xF4, 0x7F, 0x40, 0x40, 0xF0, ++ 0x08, 0x00, 0x01, 0x34, 0x00, 0x21, 0xF2, 0xF7, 0x95, 0xFB, 0x20, 0x2C, ++ 0xEB, 0xD1, 0xF8, 0xBD, 0xF4, 0xE4, 0x17, 0x00, 0x74, 0xDB, 0x17, 0x00, ++ 0x11, 0x4B, 0x00, 0xEB, 0x40, 0x00, 0x03, 0xEB, 0xC0, 0x00, 0x42, 0x7B, ++ 0x03, 0x7B, 0x01, 0x7C, 0x72, 0xB1, 0x01, 0x2A, 0x0B, 0xD1, 0x03, 0xEB, ++ 0x83, 0x02, 0xC3, 0xEB, 0x02, 0x13, 0x0B, 0x4A, 0x0B, 0x44, 0x02, 0xEB, ++ 0xC3, 0x03, 0x21, 0x22, 0x83, 0xF8, 0xA5, 0x21, 0x70, 0x47, 0x70, 0x47, ++ 0x03, 0xEB, 0x83, 0x02, 0xC3, 0xEB, 0x02, 0x13, 0x04, 0x4A, 0x0B, 0x44, ++ 0x02, 0xEB, 0xC3, 0x03, 0x21, 0x22, 0x83, 0xF8, 0xA4, 0x21, 0x70, 0x47, ++ 0xF4, 0xE4, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, 0x00, 0x28, 0x09, 0x4B, ++ 0x14, 0xBF, 0x10, 0x20, 0x00, 0x20, 0x03, 0xEB, 0x40, 0x03, 0x14, 0xBF, ++ 0x20, 0x21, 0x10, 0x21, 0x33, 0xF8, 0x02, 0x2F, 0x22, 0xB1, 0x01, 0x30, ++ 0x88, 0x42, 0xF9, 0xDB, 0x21, 0x20, 0x70, 0x47, 0x80, 0xB2, 0x70, 0x47, ++ 0xF2, 0xDF, 0x17, 0x00, 0x38, 0xB5, 0x05, 0x02, 0x45, 0xF0, 0x08, 0x05, ++ 0x04, 0x46, 0x29, 0x46, 0x4F, 0xF4, 0x00, 0x50, 0xF2, 0xF7, 0x5A, 0xF8, ++ 0x29, 0x46, 0x42, 0xF2, 0x01, 0x00, 0xF2, 0xF7, 0x55, 0xF8, 0x16, 0x48, ++ 0x04, 0xEB, 0x44, 0x04, 0x00, 0xEB, 0xC4, 0x04, 0x62, 0x7B, 0x23, 0x7B, ++ 0x21, 0x7C, 0x92, 0xB1, 0x01, 0x2A, 0x0A, 0xD1, 0x03, 0xEB, 0x83, 0x02, ++ 0xC3, 0xEB, 0x02, 0x13, 0x0F, 0x4A, 0x0B, 0x44, 0x02, 0xEB, 0xC3, 0x03, ++ 0x21, 0x22, 0x83, 0xF8, 0xA5, 0x21, 0x28, 0x46, 0x00, 0x21, 0xBD, 0xE8, ++ 0x38, 0x40, 0xF2, 0xF7, 0x25, 0xBB, 0x03, 0xEB, 0x83, 0x02, 0xC3, 0xEB, ++ 0x02, 0x13, 0x07, 0x4A, 0x0B, 0x44, 0x02, 0xEB, 0xC3, 0x03, 0x21, 0x22, ++ 0x83, 0xF8, 0xA4, 0x21, 0x28, 0x46, 0x00, 0x21, 0xBD, 0xE8, 0x38, 0x40, ++ 0xF2, 0xF7, 0x14, 0xBB, 0xF4, 0xE4, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, ++ 0x07, 0x4B, 0x00, 0xEB, 0x40, 0x02, 0x03, 0xEB, 0xC2, 0x03, 0x00, 0x02, ++ 0x5A, 0x89, 0x00, 0xF4, 0x7F, 0x41, 0x41, 0xF0, 0x08, 0x01, 0x92, 0x02, ++ 0x42, 0xF2, 0x01, 0x00, 0xF1, 0xF7, 0x64, 0xBF, 0xF4, 0xE4, 0x17, 0x00, ++ 0x0A, 0x02, 0x02, 0xF4, 0x7F, 0x42, 0x38, 0xB5, 0x42, 0xF0, 0x08, 0x02, ++ 0x05, 0x46, 0x0C, 0x46, 0x06, 0x23, 0x00, 0x21, 0x28, 0x20, 0xF2, 0xF7, ++ 0xF7, 0xF8, 0x0A, 0x49, 0x04, 0xEB, 0x44, 0x04, 0x01, 0xEB, 0xC4, 0x04, ++ 0x62, 0x7B, 0x45, 0x70, 0x01, 0x3A, 0x18, 0xBF, 0x01, 0x22, 0x02, 0x70, ++ 0x22, 0x7C, 0x82, 0x70, 0xE2, 0x7B, 0xC2, 0x70, 0x22, 0x89, 0x82, 0x80, ++ 0xBD, 0xE8, 0x38, 0x40, 0xF2, 0xF7, 0x12, 0xB9, 0xF4, 0xE4, 0x17, 0x00, ++ 0xF8, 0xB5, 0x0D, 0x02, 0x45, 0xF0, 0x08, 0x05, 0xAD, 0xB2, 0x03, 0x23, ++ 0x0C, 0x46, 0x07, 0x46, 0x2A, 0x46, 0x00, 0x21, 0x2A, 0x20, 0xF2, 0xF7, ++ 0xD3, 0xF8, 0x12, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0x06, 0x46, 0x11, 0xDB, 0x0F, 0x49, 0x04, 0xEB, 0x44, 0x04, 0x01, 0xEB, ++ 0xC4, 0x04, 0x30, 0x46, 0x63, 0x7B, 0x77, 0x70, 0x01, 0x3B, 0x18, 0xBF, ++ 0x01, 0x23, 0x33, 0x70, 0x23, 0x7C, 0xB3, 0x70, 0xBD, 0xE8, 0xF8, 0x40, ++ 0xF2, 0xF7, 0xEA, 0xB8, 0x28, 0x46, 0xF2, 0xF7, 0x59, 0xFB, 0x04, 0x28, ++ 0xE8, 0xD0, 0x05, 0x49, 0x05, 0x48, 0x40, 0xF2, 0x05, 0x22, 0xF4, 0xF7, ++ 0x91, 0xF9, 0xE1, 0xE7, 0x38, 0x36, 0x17, 0x00, 0xF4, 0xE4, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x60, 0xC2, 0x15, 0x00, 0x2D, 0xE9, 0xF8, 0x43, ++ 0x10, 0x4E, 0x11, 0x4D, 0x80, 0x46, 0x87, 0xB2, 0x00, 0x24, 0x36, 0xF8, ++ 0x02, 0x3F, 0x8B, 0xB1, 0x2B, 0x7B, 0x43, 0x45, 0x0E, 0xD1, 0x1F, 0xFA, ++ 0x84, 0xF9, 0x4F, 0xEA, 0x09, 0x23, 0x03, 0xF4, 0x7F, 0x43, 0x43, 0xF0, ++ 0x08, 0x00, 0x04, 0x21, 0xF2, 0xF7, 0x88, 0xFA, 0x49, 0x46, 0x38, 0x46, ++ 0xFF, 0xF7, 0xAA, 0xFF, 0x01, 0x34, 0x20, 0x2C, 0x05, 0xF1, 0x18, 0x05, ++ 0xE5, 0xD1, 0xBD, 0xE8, 0xF8, 0x83, 0x00, 0xBF, 0xF2, 0xDF, 0x17, 0x00, ++ 0xF4, 0xE4, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, 0x8B, 0xB0, 0xDF, 0xF8, ++ 0x50, 0x92, 0xBD, 0xF8, 0x50, 0x40, 0x09, 0x94, 0xBD, 0xF8, 0x54, 0x40, ++ 0x07, 0x94, 0x16, 0x9C, 0x04, 0x94, 0x4F, 0xF4, 0x1E, 0x74, 0x04, 0xFB, ++ 0x00, 0x94, 0x87, 0x4F, 0x94, 0xF8, 0x22, 0x80, 0xDF, 0xF8, 0x30, 0xA2, ++ 0x03, 0x91, 0x06, 0x46, 0x4F, 0xF4, 0xA4, 0x60, 0x00, 0xFB, 0x08, 0x70, ++ 0x93, 0x46, 0x00, 0x6C, 0x08, 0x93, 0x00, 0x28, 0x00, 0xF0, 0xC4, 0x80, ++ 0xDA, 0xF8, 0x00, 0x30, 0x02, 0x79, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0xC0, 0xF2, 0x9B, 0x80, 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x08, 0x73, ++ 0x4F, 0xF4, 0xC0, 0x71, 0x93, 0xF8, 0xC0, 0x34, 0x13, 0x43, 0x14, 0xBF, ++ 0x01, 0x20, 0x00, 0x20, 0xDF, 0xF7, 0x14, 0xFB, 0x04, 0x46, 0x00, 0x28, ++ 0x00, 0xF0, 0x9B, 0x80, 0x4F, 0xF4, 0xA4, 0x65, 0x05, 0xFB, 0x08, 0xF5, ++ 0x78, 0x19, 0x21, 0x46, 0x05, 0x90, 0xF1, 0xF7, 0x05, 0xFC, 0x4F, 0xF4, ++ 0x1E, 0x72, 0xA3, 0x6C, 0x02, 0xFB, 0x06, 0xF2, 0x00, 0x21, 0x26, 0x32, ++ 0x6F, 0xF0, 0x2F, 0x0C, 0x83, 0xF8, 0x68, 0xC0, 0x83, 0xF8, 0x69, 0x10, ++ 0x83, 0xF8, 0x6A, 0x10, 0x83, 0xF8, 0x6B, 0x10, 0x39, 0xF8, 0x02, 0x10, ++ 0xA3, 0xF8, 0x6C, 0x10, 0x09, 0xEB, 0x02, 0x01, 0x5C, 0x35, 0xB1, 0xF8, ++ 0x02, 0xC0, 0xA3, 0xF8, 0x6E, 0xC0, 0xB1, 0xF8, 0x04, 0xC0, 0xA3, 0xF8, ++ 0x70, 0xC0, 0x37, 0xF8, 0x05, 0xC0, 0xA3, 0xF8, 0x72, 0xC0, 0x07, 0xEB, ++ 0x05, 0x0C, 0x03, 0xF1, 0x68, 0x00, 0xBC, 0xF8, 0x02, 0xE0, 0xA3, 0xF8, ++ 0x74, 0xE0, 0xBC, 0xF8, 0x04, 0xE0, 0x06, 0x90, 0x05, 0x98, 0xA3, 0xF8, ++ 0x76, 0xE0, 0x90, 0xF8, 0x62, 0x00, 0x02, 0x28, 0x5E, 0xD0, 0x39, 0xF8, ++ 0x02, 0x20, 0xA3, 0xF8, 0x78, 0x20, 0x4A, 0x88, 0xA3, 0xF8, 0x7A, 0x20, ++ 0x8A, 0x88, 0xA3, 0xF8, 0x7C, 0x20, 0x4E, 0x49, 0xB1, 0xF8, 0xFC, 0x21, ++ 0x01, 0x32, 0x92, 0xB2, 0xA1, 0xF8, 0xFC, 0x21, 0x10, 0x01, 0x00, 0x21, ++ 0xA3, 0xF8, 0x7E, 0x00, 0x03, 0x22, 0x84, 0xF8, 0x33, 0x10, 0x84, 0xF8, ++ 0x35, 0x10, 0x84, 0xF8, 0x1C, 0x80, 0x66, 0x77, 0xD0, 0x21, 0x20, 0x46, ++ 0x00, 0xF0, 0xE6, 0xFB, 0x01, 0x28, 0x70, 0xD0, 0x18, 0x25, 0xBB, 0xF1, ++ 0x01, 0x0F, 0x4A, 0xD0, 0xBB, 0xF1, 0x02, 0x0F, 0x54, 0xD0, 0xBB, 0xF1, ++ 0x00, 0x0F, 0x5C, 0xD0, 0xDA, 0xF8, 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0x69, 0xDB, 0x03, 0x26, 0xE1, 0x6C, 0x94, 0xF8, 0x35, 0x30, ++ 0x4A, 0x6A, 0x1D, 0x44, 0x01, 0x3A, 0x04, 0x9B, 0x2A, 0x44, 0x04, 0x35, ++ 0xC1, 0xE9, 0x0A, 0x25, 0x13, 0xB1, 0x63, 0x65, 0x03, 0x9B, 0xA3, 0x65, ++ 0x31, 0x46, 0x20, 0x46, 0x0B, 0xB0, 0xBD, 0xE8, 0xF0, 0x4F, 0xDF, 0xF7, ++ 0x97, 0xBA, 0x02, 0x2A, 0x7F, 0xF4, 0x62, 0xAF, 0x2D, 0x49, 0x2E, 0x48, ++ 0x4F, 0xF4, 0x09, 0x72, 0xF4, 0xF7, 0x92, 0xF8, 0x01, 0x20, 0x4F, 0xF4, ++ 0xC0, 0x71, 0xDF, 0xF7, 0x79, 0xFA, 0x04, 0x46, 0x00, 0x28, 0x7F, 0xF4, ++ 0x65, 0xAF, 0x0B, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x7A, 0x5B, 0xA3, 0xF8, ++ 0x78, 0x20, 0xBC, 0xF8, 0x02, 0x20, 0xA3, 0xF8, 0x7A, 0x20, 0xBC, 0xF8, ++ 0x04, 0x20, 0xA3, 0xF8, 0x7C, 0x20, 0x9E, 0xE7, 0xDA, 0xF8, 0x00, 0x30, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xE1, 0xDA, 0xDA, 0xE7, 0x06, 0x99, ++ 0x07, 0x9B, 0x00, 0x93, 0x29, 0x44, 0x08, 0x46, 0xDD, 0xE9, 0x08, 0x32, ++ 0x03, 0x99, 0xF5, 0xF7, 0x4D, 0xFA, 0x03, 0x26, 0x05, 0x44, 0xB4, 0xE7, ++ 0xDD, 0xE9, 0x06, 0x02, 0x03, 0x99, 0x15, 0x4E, 0x0B, 0x7C, 0x28, 0x44, ++ 0xF6, 0x5C, 0xF5, 0xF7, 0x5D, 0xFA, 0x05, 0x44, 0xA9, 0xE7, 0x03, 0x99, ++ 0x06, 0x98, 0x10, 0x4A, 0x0B, 0x7C, 0x28, 0x44, 0xD6, 0x5C, 0xF5, 0xF7, ++ 0x1B, 0xFA, 0x05, 0x44, 0x9F, 0xE7, 0x06, 0x99, 0x18, 0x22, 0x20, 0x46, ++ 0xFF, 0xF7, 0xD2, 0xF9, 0x94, 0xF8, 0x33, 0x50, 0x18, 0x35, 0x86, 0xE7, ++ 0x05, 0x49, 0x08, 0x48, 0x40, 0xF2, 0x6E, 0x22, 0xF4, 0xF7, 0x5A, 0xF8, ++ 0x03, 0x26, 0x8E, 0xE7, 0x18, 0x88, 0x17, 0x00, 0x20, 0x62, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xFC, 0x90, 0x15, 0x00, 0xC0, 0xB2, 0x15, 0x00, ++ 0x64, 0x7D, 0x15, 0x00, 0x68, 0x65, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0x35, 0x4B, 0x87, 0xB0, 0x81, 0x46, 0x8A, 0x46, ++ 0x93, 0x46, 0x10, 0x24, 0x33, 0xF8, 0x02, 0x5F, 0x35, 0xB1, 0x01, 0x34, ++ 0x20, 0x2C, 0xF9, 0xD1, 0x03, 0x20, 0x07, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, ++ 0x2E, 0x4A, 0xDF, 0xF8, 0xCC, 0x80, 0x04, 0xEB, 0x44, 0x03, 0x02, 0xEB, ++ 0xC3, 0x06, 0xDB, 0x00, 0x86, 0xF8, 0x0C, 0x90, 0x86, 0xF8, 0x10, 0xA0, ++ 0x05, 0x93, 0x06, 0xF0, 0xBB, 0xFB, 0x28, 0x49, 0x70, 0x74, 0x09, 0x68, ++ 0x27, 0x48, 0xB1, 0xF8, 0x02, 0xC0, 0x10, 0xF8, 0x0A, 0x00, 0x05, 0x9B, ++ 0x25, 0x49, 0x22, 0x4A, 0x02, 0x95, 0x09, 0xEB, 0x89, 0x07, 0xC9, 0xEB, ++ 0x07, 0x17, 0x57, 0x44, 0x00, 0x95, 0x34, 0x37, 0x51, 0xF8, 0x20, 0xE0, ++ 0xD5, 0x50, 0x08, 0xEB, 0xC7, 0x00, 0x27, 0x23, 0x01, 0x93, 0xA6, 0xF8, ++ 0x0A, 0xC0, 0x4F, 0xF0, 0x01, 0x0C, 0x86, 0xF8, 0x0F, 0xE0, 0x86, 0xF8, ++ 0x0E, 0xC0, 0x86, 0xF8, 0x0D, 0xC0, 0x31, 0x46, 0x2B, 0x46, 0x44, 0x71, ++ 0xA6, 0xF8, 0x08, 0xB0, 0x48, 0x46, 0x02, 0x22, 0xFF, 0xF7, 0x82, 0xFE, ++ 0x24, 0x02, 0x31, 0x46, 0x48, 0x46, 0x2B, 0x46, 0x2A, 0x46, 0xCD, 0xE9, ++ 0x01, 0x55, 0x00, 0x95, 0xFF, 0xF7, 0x78, 0xFE, 0x44, 0xF0, 0x08, 0x04, ++ 0x0E, 0x4B, 0xA4, 0xB2, 0x1B, 0x69, 0x48, 0xF8, 0x37, 0x30, 0x21, 0x46, ++ 0x4F, 0xF4, 0xFA, 0x22, 0x4F, 0xF4, 0x00, 0x50, 0xF1, 0xF7, 0x46, 0xFD, ++ 0x20, 0x46, 0x02, 0x21, 0xF2, 0xF7, 0xDE, 0xF8, 0x28, 0x46, 0x07, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x8F, 0x12, 0xE0, 0x17, 0x00, 0xF4, 0xE4, 0x17, 0x00, ++ 0xC8, 0x35, 0x17, 0x00, 0xC0, 0xB2, 0x15, 0x00, 0x7C, 0x28, 0x17, 0x00, ++ 0x00, 0x10, 0x50, 0x40, 0x68, 0x65, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x47, ++ 0x19, 0x4C, 0x1A, 0x4D, 0xDF, 0xF8, 0x68, 0xA0, 0xC4, 0xEB, 0x44, 0x29, ++ 0x4F, 0xEA, 0xC9, 0x19, 0x84, 0xB0, 0x07, 0x46, 0x1F, 0xFA, 0x89, 0xF9, ++ 0x04, 0xF1, 0x40, 0x06, 0x4F, 0xF0, 0x00, 0x08, 0x34, 0xF8, 0x02, 0x3F, ++ 0xCB, 0xB1, 0x2B, 0x7B, 0xBB, 0x42, 0x16, 0xD1, 0x09, 0xEB, 0xC4, 0x10, ++ 0xA0, 0xF5, 0x80, 0x70, 0x40, 0xF0, 0x08, 0x00, 0x80, 0xB2, 0x04, 0x21, ++ 0xF2, 0xF7, 0xAA, 0xF8, 0x27, 0x23, 0xCD, 0xE9, 0x00, 0x83, 0xCD, 0xF8, ++ 0x08, 0xA0, 0x00, 0x23, 0x02, 0x22, 0x29, 0x46, 0x38, 0x46, 0x85, 0xF8, ++ 0x13, 0x80, 0xFF, 0xF7, 0x25, 0xFE, 0xB4, 0x42, 0x05, 0xF1, 0x18, 0x05, ++ 0xDE, 0xD1, 0x04, 0xB0, 0xBD, 0xE8, 0xF0, 0x87, 0xF2, 0xDF, 0x17, 0x00, ++ 0xF4, 0xE4, 0x17, 0x00, 0xE5, 0xFE, 0x14, 0x00, 0xFF, 0x29, 0x2F, 0xD0, ++ 0xF8, 0xB5, 0xC3, 0xB2, 0x03, 0xEB, 0x83, 0x02, 0x16, 0x4F, 0xC3, 0xEB, ++ 0x02, 0x13, 0x53, 0xFA, 0x81, 0xF3, 0x07, 0xEB, 0xC3, 0x03, 0x0C, 0x46, ++ 0x93, 0xF8, 0xA5, 0x61, 0x21, 0x2E, 0x05, 0x46, 0x1C, 0xD0, 0x30, 0x02, ++ 0x40, 0xF0, 0x08, 0x00, 0xF2, 0xF7, 0x20, 0xF9, 0x01, 0x28, 0x15, 0xD1, ++ 0x0D, 0x4B, 0x06, 0xEB, 0x46, 0x06, 0x03, 0xEB, 0xC6, 0x06, 0x4F, 0xF4, ++ 0x9E, 0x71, 0x01, 0xFB, 0x05, 0x44, 0x73, 0x69, 0x07, 0xEB, 0x44, 0x04, ++ 0x9A, 0x88, 0xB4, 0xF8, 0x34, 0x31, 0x9B, 0x1A, 0x13, 0xF4, 0x7C, 0x6F, ++ 0x0C, 0xBF, 0x01, 0x20, 0x00, 0x20, 0xF8, 0xBD, 0x01, 0x20, 0xF8, 0xBD, ++ 0x02, 0x20, 0x70, 0x47, 0x68, 0x65, 0x17, 0x00, 0xF4, 0xE4, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x47, 0x04, 0x46, 0x50, 0x48, 0xE1, 0x7E, 0xD0, 0xF8, ++ 0x10, 0x90, 0xFF, 0x29, 0x23, 0xD0, 0x65, 0x7F, 0x4D, 0x4E, 0x4F, 0xF4, ++ 0x1E, 0x73, 0x03, 0xFB, 0x05, 0x63, 0x5A, 0x68, 0x97, 0x07, 0x1A, 0xD5, ++ 0x05, 0xEB, 0x85, 0x07, 0xC5, 0xEB, 0x07, 0x17, 0x7A, 0x18, 0x34, 0x32, ++ 0x06, 0xEB, 0xC2, 0x0C, 0x9C, 0xF8, 0x07, 0xE0, 0x9C, 0xF8, 0x05, 0x80, ++ 0x0E, 0xF1, 0x01, 0x0E, 0xB8, 0xF1, 0x21, 0x0F, 0x8C, 0xF8, 0x07, 0xE0, ++ 0x09, 0xD1, 0x00, 0x69, 0x56, 0xF8, 0x32, 0x20, 0xDF, 0xF8, 0x14, 0xC1, ++ 0x82, 0x1A, 0x62, 0x45, 0x48, 0xD8, 0xBD, 0xE8, 0xF0, 0x87, 0xDF, 0xF8, ++ 0x0C, 0xA1, 0x08, 0xEB, 0x48, 0x07, 0x0A, 0xEB, 0xC7, 0x07, 0x4F, 0xEA, ++ 0x08, 0x20, 0xC7, 0xF8, 0x04, 0x90, 0x40, 0xF0, 0x08, 0x00, 0xF2, 0xF7, ++ 0xC3, 0xF8, 0x01, 0x28, 0x4F, 0xEA, 0x48, 0x09, 0xEB, 0xD1, 0x7F, 0x69, ++ 0xE3, 0x8B, 0xB8, 0x88, 0x60, 0x84, 0xD9, 0x07, 0x57, 0xD4, 0x4F, 0xF4, ++ 0x1E, 0x72, 0x02, 0xFB, 0x05, 0x65, 0xD5, 0xF8, 0x4C, 0x21, 0x92, 0xF8, ++ 0xA2, 0x20, 0x52, 0x07, 0x03, 0xD5, 0x62, 0x6A, 0x42, 0xF4, 0x00, 0x12, ++ 0x62, 0x62, 0x21, 0x8C, 0x3A, 0x68, 0x43, 0xF0, 0x02, 0x03, 0x09, 0x1A, ++ 0xE3, 0x83, 0xC1, 0xF3, 0x0B, 0x01, 0x38, 0x46, 0x90, 0x47, 0x38, 0x44, ++ 0x01, 0x23, 0x83, 0x71, 0xE3, 0x8B, 0xDB, 0x07, 0x07, 0xD4, 0x1F, 0x4A, ++ 0x20, 0x4B, 0x12, 0x69, 0x9B, 0x8D, 0x03, 0xEB, 0x92, 0x23, 0xA4, 0xF8, ++ 0x40, 0x30, 0xC8, 0x44, 0x4F, 0xEA, 0xC8, 0x08, 0x5A, 0xF8, 0x08, 0x30, ++ 0x01, 0x33, 0x4A, 0xF8, 0x08, 0x30, 0xB6, 0xE7, 0x93, 0xF8, 0x24, 0x30, ++ 0x01, 0x2B, 0xB2, 0xD0, 0x17, 0x4B, 0x18, 0x48, 0x5A, 0x5C, 0x54, 0x23, ++ 0x03, 0xFB, 0x02, 0xF3, 0xC3, 0x58, 0x00, 0x2B, 0xA9, 0xD1, 0x15, 0x4B, ++ 0x53, 0xF8, 0x32, 0x30, 0x00, 0x2B, 0xA4, 0xD1, 0xBB, 0x18, 0x46, 0x33, ++ 0x56, 0xF8, 0x33, 0x30, 0x00, 0x2B, 0x9E, 0xD1, 0x23, 0x7F, 0x10, 0x48, ++ 0xA4, 0x26, 0x06, 0xFB, 0x03, 0x23, 0x9E, 0x33, 0x50, 0xF8, 0x33, 0x30, ++ 0x00, 0x2B, 0x94, 0xD1, 0x0C, 0x4B, 0x22, 0x8C, 0x1B, 0x6A, 0x28, 0x46, ++ 0xBD, 0xE8, 0xF0, 0x47, 0x18, 0x47, 0x03, 0xF0, 0x03, 0x02, 0x03, 0x2A, ++ 0x89, 0xD1, 0xA2, 0xE7, 0x00, 0x10, 0x50, 0x40, 0x68, 0x65, 0x17, 0x00, ++ 0xE4, 0xB8, 0x17, 0x00, 0xC0, 0xB2, 0x15, 0x00, 0x20, 0x62, 0x17, 0x00, ++ 0x24, 0x64, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, 0x88, 0x1A, 0x17, 0x00, ++ 0x40, 0x42, 0x0F, 0x00, 0xF4, 0xE4, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x47, ++ 0x05, 0x46, 0x1C, 0x48, 0x6C, 0x7F, 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, ++ 0x04, 0x03, 0x5E, 0x68, 0xB6, 0x07, 0x0E, 0xD5, 0xEB, 0x7E, 0x04, 0xEB, ++ 0x84, 0x06, 0xC4, 0xEB, 0x06, 0x14, 0x1C, 0x44, 0x34, 0x34, 0x00, 0xEB, ++ 0xC4, 0x04, 0xE3, 0x79, 0x01, 0x3B, 0xE3, 0x71, 0xEB, 0x8B, 0x9B, 0x07, ++ 0x02, 0xD4, 0x01, 0x20, 0xBD, 0xE8, 0xF0, 0x87, 0x66, 0x79, 0x21, 0x2E, ++ 0xF9, 0xD0, 0x30, 0x02, 0x40, 0xF0, 0x08, 0x00, 0x88, 0x46, 0x91, 0x46, ++ 0xF2, 0xF7, 0x20, 0xF8, 0x01, 0x28, 0xF0, 0xD1, 0x06, 0xEB, 0x46, 0x07, ++ 0xFF, 0x00, 0xDF, 0xF8, 0x20, 0xC0, 0x5C, 0xF8, 0x07, 0x40, 0x01, 0x3C, ++ 0x4C, 0xF8, 0x07, 0x40, 0x4B, 0x46, 0x42, 0x46, 0x28, 0x46, 0x31, 0x46, ++ 0xBD, 0xE8, 0xF0, 0x47, 0xFF, 0xF7, 0x46, 0xBB, 0x68, 0x65, 0x17, 0x00, ++ 0xF4, 0xE4, 0x17, 0x00, 0x38, 0xB5, 0x45, 0x69, 0x04, 0x46, 0x40, 0x22, ++ 0x00, 0x21, 0xA8, 0x1D, 0xCF, 0xF7, 0x58, 0xF9, 0x22, 0x7B, 0x21, 0x7C, ++ 0x0C, 0x4B, 0x4F, 0xF4, 0x9E, 0x70, 0x00, 0xFB, 0x02, 0x12, 0x03, 0xEB, ++ 0x42, 0x03, 0x00, 0x22, 0xB3, 0xF8, 0x34, 0x31, 0xAB, 0x80, 0x85, 0xF8, ++ 0x46, 0x20, 0xE3, 0x7B, 0x85, 0xF8, 0x47, 0x30, 0x5A, 0x1E, 0x1A, 0x42, ++ 0x12, 0xBF, 0x04, 0x4B, 0x04, 0x4B, 0x85, 0xF8, 0x48, 0x20, 0x2B, 0x60, ++ 0x38, 0xBD, 0x00, 0xBF, 0x68, 0x65, 0x17, 0x00, 0xDD, 0x04, 0x15, 0x00, ++ 0xF1, 0x04, 0x15, 0x00, 0x90, 0xF8, 0x47, 0x10, 0x59, 0xB1, 0x43, 0x1D, ++ 0x19, 0x44, 0x00, 0x20, 0x13, 0xF8, 0x01, 0x2F, 0x02, 0x2A, 0x04, 0xBF, ++ 0x01, 0x30, 0x40, 0xB2, 0x8B, 0x42, 0xF7, 0xD1, 0x70, 0x47, 0x08, 0x46, ++ 0x70, 0x47, 0x00, 0xBF, 0x11, 0x4A, 0x12, 0x4B, 0x12, 0x68, 0x10, 0xB5, ++ 0x00, 0xEB, 0x80, 0x04, 0xC0, 0xEB, 0x04, 0x10, 0x08, 0x44, 0x03, 0xEB, ++ 0xC0, 0x00, 0xB2, 0xF9, 0x00, 0x30, 0x90, 0xF8, 0xA4, 0x41, 0x00, 0x2B, ++ 0x08, 0xDB, 0x0B, 0x4B, 0x0B, 0x4A, 0x04, 0xEB, 0x44, 0x04, 0x03, 0xEB, ++ 0xC4, 0x04, 0x13, 0x69, 0x63, 0x60, 0x10, 0xBD, 0x20, 0x2C, 0xF4, 0xD9, ++ 0x07, 0x49, 0x08, 0x48, 0x40, 0xF2, 0x52, 0x32, 0xF3, 0xF7, 0xEA, 0xFD, ++ 0xED, 0xE7, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, ++ 0xF4, 0xE4, 0x17, 0x00, 0x00, 0x10, 0x50, 0x40, 0x70, 0x79, 0x15, 0x00, ++ 0x9C, 0xC2, 0x15, 0x00, 0x10, 0xF0, 0x0C, 0x0F, 0x11, 0xD1, 0x00, 0xF0, ++ 0xF0, 0x03, 0xC0, 0x2B, 0x0B, 0xD0, 0xD0, 0x2B, 0x05, 0xD0, 0xA3, 0xF1, ++ 0xA0, 0x00, 0xB0, 0xFA, 0x80, 0xF0, 0x40, 0x09, 0x70, 0x47, 0x0F, 0x29, ++ 0x24, 0xD8, 0x03, 0x29, 0x03, 0xD8, 0x01, 0x20, 0x70, 0x47, 0x00, 0x20, ++ 0x70, 0x47, 0x04, 0x39, 0x0B, 0x29, 0xF8, 0xD8, 0x01, 0xA3, 0x53, 0xF8, ++ 0x21, 0xF0, 0x00, 0xBF, 0xEF, 0x0F, 0x15, 0x00, 0xEB, 0x0F, 0x15, 0x00, ++ 0xEB, 0x0F, 0x15, 0x00, 0xEF, 0x0F, 0x15, 0x00, 0xEB, 0x0F, 0x15, 0x00, ++ 0xEB, 0x0F, 0x15, 0x00, 0xEB, 0x0F, 0x15, 0x00, 0xEF, 0x0F, 0x15, 0x00, ++ 0xEB, 0x0F, 0x15, 0x00, 0xEB, 0x0F, 0x15, 0x00, 0xEB, 0x0F, 0x15, 0x00, ++ 0xEF, 0x0F, 0x15, 0x00, 0xB1, 0xF1, 0x7F, 0x00, 0x18, 0xBF, 0x01, 0x20, ++ 0x70, 0x47, 0x00, 0xBF, 0x2D, 0xE9, 0xF0, 0x4F, 0x90, 0xF8, 0x08, 0xB0, ++ 0xB0, 0xF8, 0x00, 0x90, 0x1B, 0xF8, 0x01, 0xA0, 0x0C, 0x46, 0x85, 0xB0, ++ 0x80, 0x46, 0x51, 0x46, 0x48, 0x46, 0x1D, 0x46, 0xFF, 0xF7, 0xB4, 0xFF, ++ 0x0B, 0xEB, 0x04, 0x0C, 0x00, 0x28, 0x00, 0xF0, 0x81, 0x80, 0x98, 0xF8, ++ 0x09, 0x30, 0xFF, 0x2B, 0x24, 0xD0, 0x98, 0xF8, 0x0A, 0x70, 0xFF, 0x2F, ++ 0x20, 0xD0, 0x50, 0x49, 0x16, 0x46, 0x4F, 0xF4, 0xA4, 0x62, 0x02, 0xFB, ++ 0x07, 0x12, 0xD2, 0xF8, 0xA8, 0x24, 0x00, 0x2A, 0x6E, 0xD0, 0x98, 0xF8, ++ 0x30, 0x20, 0x12, 0x07, 0x6E, 0xD5, 0x09, 0xF0, 0xFC, 0x03, 0xD0, 0x2B, ++ 0x00, 0xF0, 0x84, 0x80, 0x46, 0x4B, 0x4F, 0xF4, 0xA4, 0x68, 0x08, 0xFB, ++ 0x07, 0xF8, 0x43, 0x44, 0xD3, 0xF8, 0xAC, 0x34, 0x00, 0x2B, 0x5B, 0xD0, ++ 0x0B, 0xF1, 0x13, 0x03, 0xB3, 0x42, 0x05, 0xDB, 0x00, 0x23, 0x01, 0x20, ++ 0x2B, 0x70, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xB1, 0x1E, 0xA1, 0xEB, ++ 0x0B, 0x01, 0x0C, 0xF1, 0x02, 0x00, 0x89, 0xB2, 0xF2, 0xF7, 0x3A, 0xFC, ++ 0x1F, 0xFA, 0x8B, 0xF3, 0x00, 0x28, 0xED, 0xD0, 0xB0, 0xF8, 0x02, 0xC0, ++ 0xAC, 0xF1, 0x04, 0x02, 0x01, 0x2A, 0xE7, 0xD8, 0x33, 0x4A, 0xCC, 0xEB, ++ 0x0C, 0x11, 0x08, 0xEB, 0xC1, 0x01, 0x11, 0x44, 0x4F, 0xEA, 0x0C, 0x12, ++ 0x03, 0x92, 0x91, 0xF8, 0x3B, 0x22, 0x00, 0x2A, 0xDA, 0xD0, 0xD1, 0xE9, ++ 0x76, 0xAB, 0x42, 0x68, 0x4F, 0xF0, 0x00, 0x0E, 0x22, 0xF0, 0x7F, 0x48, ++ 0xF3, 0x45, 0x08, 0xBF, 0xC2, 0x45, 0xF1, 0x46, 0xCE, 0xD2, 0x82, 0x46, ++ 0xDD, 0xF8, 0x0C, 0xB0, 0x5A, 0xF8, 0x0A, 0x2F, 0x00, 0x92, 0xDA, 0xF8, ++ 0x04, 0x20, 0x01, 0x92, 0xC1, 0xE9, 0x76, 0x89, 0x12, 0x30, 0x52, 0x46, ++ 0x02, 0xF8, 0x01, 0xEB, 0x82, 0x42, 0xFB, 0xD1, 0x4F, 0xF4, 0xA4, 0x60, ++ 0x00, 0xFB, 0x07, 0xF0, 0xAB, 0xEB, 0x0C, 0x0C, 0x21, 0x46, 0x00, 0xF5, ++ 0xEC, 0x70, 0x1A, 0x4C, 0x00, 0xEB, 0xCC, 0x00, 0x20, 0x44, 0x32, 0x46, ++ 0x00, 0xF0, 0xD2, 0xFA, 0xDD, 0xE9, 0x00, 0x34, 0x8C, 0x42, 0x08, 0xBF, ++ 0x83, 0x42, 0xA7, 0xD1, 0x00, 0x20, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, ++ 0x12, 0x4A, 0x4F, 0xF4, 0x1E, 0x70, 0x00, 0xFB, 0x03, 0x23, 0x5B, 0x68, ++ 0x1B, 0x07, 0xF3, 0xD5, 0x19, 0xF4, 0x80, 0x4F, 0xF0, 0xD1, 0x09, 0xF0, ++ 0xFC, 0x09, 0xB9, 0xF1, 0xC0, 0x0F, 0x02, 0xD0, 0xB9, 0xF1, 0xA0, 0x0F, ++ 0x90, 0xD1, 0xAA, 0xF1, 0x06, 0x01, 0x01, 0x29, 0x8C, 0xD8, 0x01, 0x20, ++ 0x28, 0x70, 0xE2, 0xE7, 0xAA, 0xF1, 0x0D, 0x01, 0x01, 0x29, 0x3F, 0xF6, ++ 0x77, 0xAF, 0x89, 0xF4, 0x80, 0x40, 0xC0, 0xF3, 0x80, 0x30, 0xD8, 0xE7, ++ 0x18, 0x88, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, 0xF8, 0xB5, 0x45, 0x7F, ++ 0x06, 0x7F, 0xFF, 0x2D, 0x2B, 0xD0, 0x19, 0x4F, 0x4F, 0xF4, 0xA4, 0x63, ++ 0x03, 0xFB, 0x06, 0x73, 0xD3, 0xF8, 0xA8, 0x04, 0xE0, 0xB1, 0x0C, 0x46, ++ 0x20, 0x46, 0x11, 0x46, 0xFF, 0xF7, 0xF0, 0xFE, 0xB0, 0xB1, 0x4F, 0xF4, ++ 0x1E, 0x73, 0x03, 0xFB, 0x05, 0xF5, 0x11, 0x4B, 0xE8, 0x5C, 0x10, 0xF0, ++ 0x01, 0x00, 0x0E, 0xD0, 0x04, 0xF0, 0xFC, 0x04, 0xD0, 0x2C, 0x12, 0xD0, ++ 0x4F, 0xF4, 0xA4, 0x63, 0x03, 0xFB, 0x06, 0x76, 0xD6, 0xF8, 0xAC, 0x34, ++ 0x00, 0x2B, 0x0C, 0xBF, 0x00, 0x20, 0x02, 0x20, 0xF8, 0xBD, 0x1D, 0x44, ++ 0x55, 0xF8, 0x22, 0x0C, 0xC0, 0xF3, 0xC0, 0x00, 0xF8, 0xBD, 0x00, 0x20, ++ 0xF8, 0xBD, 0x0D, 0x3A, 0x01, 0x2A, 0xE9, 0xD8, 0xF2, 0xE7, 0x00, 0xBF, ++ 0x18, 0x88, 0x17, 0x00, 0x8E, 0x65, 0x17, 0x00, 0xF8, 0xB5, 0x2A, 0x4C, ++ 0x03, 0x7F, 0x4F, 0xF4, 0xA4, 0x60, 0x00, 0xFB, 0x03, 0x43, 0x02, 0xEB, ++ 0x01, 0x0C, 0xD3, 0xF8, 0xAC, 0x04, 0x00, 0x28, 0x47, 0xD0, 0x4C, 0x23, ++ 0x53, 0x54, 0x10, 0x23, 0x8C, 0xF8, 0x01, 0x30, 0xD0, 0xE9, 0x12, 0x37, ++ 0x01, 0x33, 0x90, 0xF8, 0x61, 0x40, 0xAC, 0xF8, 0x02, 0x40, 0x47, 0xF1, ++ 0x00, 0x07, 0xC0, 0xE9, 0x12, 0x37, 0x0C, 0xF1, 0x04, 0x0E, 0x00, 0x24, ++ 0x01, 0xE0, 0xD0, 0xE9, 0x12, 0x37, 0xC4, 0xF1, 0x20, 0x06, 0xE3, 0x40, ++ 0xA4, 0xF1, 0x20, 0x05, 0x07, 0xFA, 0x06, 0xF6, 0x33, 0x43, 0x27, 0xFA, ++ 0x05, 0xF5, 0x08, 0x34, 0x2B, 0x43, 0x30, 0x2C, 0x0E, 0xF8, 0x01, 0x3B, ++ 0xED, 0xD1, 0x0C, 0xF1, 0x0A, 0x06, 0x0C, 0xF1, 0x12, 0x04, 0x33, 0x46, ++ 0x00, 0x25, 0x03, 0xF8, 0x01, 0x5B, 0xA3, 0x42, 0xFB, 0xD1, 0x12, 0x32, ++ 0x18, 0x23, 0x92, 0xB2, 0x00, 0xF0, 0x22, 0xFA, 0x00, 0x23, 0xC3, 0xF1, ++ 0x20, 0x05, 0x20, 0xFA, 0x03, 0xF2, 0xA3, 0xF1, 0x20, 0x04, 0x01, 0xFA, ++ 0x05, 0xF5, 0x2A, 0x43, 0x21, 0xFA, 0x04, 0xF4, 0x08, 0x33, 0x22, 0x43, ++ 0x40, 0x2B, 0x06, 0xF8, 0x01, 0x2B, 0xEE, 0xD1, 0x12, 0x20, 0xF8, 0xBD, ++ 0x18, 0x88, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, 0x0A, 0x68, 0x05, 0x68, ++ 0x4B, 0x68, 0xAE, 0x4C, 0xDF, 0xF8, 0xBC, 0x82, 0x8F, 0xB0, 0x0E, 0x46, ++ 0x6A, 0x40, 0x01, 0x92, 0x32, 0x46, 0x07, 0x46, 0x0D, 0x90, 0xF0, 0x68, ++ 0x01, 0x9E, 0x04, 0x91, 0x89, 0x68, 0x16, 0x60, 0x7E, 0x68, 0x07, 0x97, ++ 0x83, 0xEA, 0x06, 0x05, 0x55, 0x60, 0x13, 0x46, 0xBA, 0x68, 0x00, 0x95, ++ 0x81, 0xEA, 0x02, 0x09, 0xC3, 0xF8, 0x08, 0x90, 0xFB, 0x68, 0xCD, 0xF8, ++ 0x0C, 0x90, 0x43, 0x40, 0x02, 0x93, 0x07, 0xF1, 0x90, 0x03, 0x0C, 0x93, ++ 0x00, 0x9E, 0x01, 0x98, 0x02, 0x99, 0x03, 0x9D, 0xF3, 0xB2, 0x5F, 0xFA, ++ 0x80, 0xFC, 0xC6, 0xF3, 0x07, 0x2A, 0x4F, 0xEA, 0x10, 0x69, 0xE0, 0x5C, ++ 0x06, 0x90, 0x0A, 0x0E, 0x96, 0x48, 0x08, 0x93, 0x14, 0xF8, 0x0A, 0x30, ++ 0x87, 0x5C, 0x18, 0xF8, 0x02, 0x10, 0x05, 0x93, 0xC5, 0xF3, 0x07, 0x26, ++ 0xA3, 0x5C, 0x03, 0x9A, 0x0A, 0x97, 0xC2, 0xF3, 0x07, 0x4E, 0xA7, 0x5D, ++ 0x10, 0xF8, 0x0E, 0x20, 0x18, 0xF8, 0x09, 0xB0, 0x14, 0xF8, 0x0C, 0x50, ++ 0x38, 0x46, 0x06, 0x9F, 0x09, 0x90, 0x87, 0xEA, 0x0B, 0x0B, 0x05, 0x9F, ++ 0x80, 0xEA, 0x0B, 0x0B, 0x69, 0x40, 0x87, 0x48, 0x79, 0x40, 0x51, 0x40, ++ 0x10, 0xF8, 0x0A, 0x20, 0x5D, 0x40, 0x6A, 0x40, 0x18, 0xF8, 0x0E, 0x50, ++ 0x14, 0xF8, 0x0E, 0xE0, 0x6A, 0x40, 0x09, 0x04, 0x41, 0xEA, 0x02, 0x21, ++ 0x7F, 0x4A, 0x02, 0x9D, 0x12, 0xF8, 0x0C, 0x20, 0x5F, 0x46, 0x18, 0xF8, ++ 0x0A, 0xB0, 0x14, 0xF8, 0x09, 0xA0, 0x10, 0xF8, 0x09, 0x90, 0xCD, 0xF8, ++ 0x2C, 0x90, 0x53, 0x40, 0xC5, 0xF3, 0x07, 0x49, 0x06, 0x98, 0x18, 0xF8, ++ 0x0C, 0x50, 0x76, 0x4A, 0x83, 0xEA, 0x0B, 0x0B, 0x0A, 0x9B, 0x18, 0xF8, ++ 0x06, 0xC0, 0x5D, 0x40, 0x12, 0xF8, 0x09, 0x30, 0x92, 0x5D, 0x71, 0x4E, ++ 0x8A, 0xEA, 0x00, 0x00, 0x50, 0x40, 0x08, 0x9A, 0xB6, 0x5C, 0x18, 0xF8, ++ 0x02, 0x20, 0x8A, 0xEA, 0x06, 0x0A, 0x7B, 0x40, 0x0B, 0x9E, 0x05, 0x9F, ++ 0x8A, 0xEA, 0x0C, 0x0A, 0x18, 0xF8, 0x09, 0xC0, 0x14, 0xF8, 0x09, 0x90, ++ 0x8E, 0xEA, 0x05, 0x05, 0x56, 0x40, 0x7D, 0x40, 0x1B, 0x04, 0x09, 0x9F, ++ 0x80, 0xEA, 0x0C, 0x00, 0x8E, 0xEA, 0x0B, 0x0B, 0x43, 0xEA, 0x00, 0x20, ++ 0x89, 0xEA, 0x06, 0x03, 0x41, 0xEA, 0x0B, 0x02, 0x02, 0x99, 0x00, 0x9E, ++ 0x83, 0xEA, 0x07, 0x0B, 0x03, 0x9B, 0x89, 0xEA, 0x0A, 0x0A, 0x40, 0xEA, ++ 0x0A, 0x0C, 0x5F, 0xFA, 0x83, 0xFE, 0x4F, 0xEA, 0x13, 0x69, 0xC1, 0xF3, ++ 0x07, 0x20, 0xCB, 0xB2, 0x01, 0x99, 0x02, 0x93, 0x42, 0xEA, 0x05, 0x67, ++ 0x04, 0x9A, 0x03, 0x97, 0xC1, 0xF3, 0x07, 0x4A, 0x4C, 0xEA, 0x0B, 0x65, ++ 0x17, 0x60, 0x27, 0x5C, 0x55, 0x60, 0x36, 0x0E, 0x05, 0x95, 0x01, 0x97, ++ 0x4F, 0x4D, 0x14, 0xF8, 0x0A, 0x70, 0x06, 0x97, 0x18, 0xF8, 0x0A, 0x70, ++ 0x15, 0xF8, 0x00, 0xB0, 0xA2, 0x5D, 0x18, 0xF8, 0x06, 0x30, 0x08, 0x97, ++ 0xC1, 0xF3, 0x07, 0x2C, 0x14, 0xF8, 0x0E, 0x10, 0x15, 0xF8, 0x0A, 0xA0, ++ 0x18, 0xF8, 0x00, 0x00, 0x01, 0x9F, 0x09, 0x90, 0xA8, 0x5D, 0x0A, 0x90, ++ 0x4B, 0x40, 0x02, 0x98, 0x00, 0x9E, 0x25, 0x5C, 0x18, 0xF8, 0x09, 0x00, ++ 0x7B, 0x40, 0x83, 0xEA, 0x0A, 0x03, 0x14, 0xF8, 0x0C, 0xA0, 0x51, 0x40, ++ 0x57, 0x46, 0x68, 0x40, 0x8B, 0xEA, 0x01, 0x0B, 0x00, 0x97, 0x3B, 0x49, ++ 0x14, 0xF8, 0x09, 0xA0, 0x11, 0xF8, 0x09, 0x90, 0xCD, 0xF8, 0x2C, 0x90, ++ 0x78, 0x40, 0x08, 0x9F, 0x8B, 0xEA, 0x07, 0x01, 0x35, 0x4F, 0x08, 0x91, ++ 0x17, 0xF8, 0x0E, 0x90, 0x09, 0x99, 0x18, 0xF8, 0x0E, 0xE0, 0xC6, 0xF3, ++ 0x07, 0x46, 0x82, 0xEA, 0x09, 0x02, 0x17, 0xF8, 0x06, 0xB0, 0x17, 0xF8, ++ 0x0C, 0x90, 0x02, 0x9F, 0x18, 0xF8, 0x0C, 0xC0, 0x4A, 0x40, 0x2C, 0x49, ++ 0x80, 0xEA, 0x0B, 0x00, 0x11, 0xF8, 0x07, 0xB0, 0x0A, 0x99, 0x8A, 0xEA, ++ 0x05, 0x05, 0x89, 0xEA, 0x05, 0x05, 0x8E, 0xEA, 0x01, 0x0E, 0x18, 0xF8, ++ 0x07, 0x90, 0x0B, 0x99, 0x89, 0xEA, 0x01, 0x09, 0x08, 0x99, 0x1B, 0x04, ++ 0x43, 0xEA, 0x01, 0x21, 0x06, 0x9B, 0x8A, 0xEA, 0x0B, 0x0A, 0x18, 0xF8, ++ 0x06, 0xB0, 0xA6, 0x5D, 0x01, 0x9F, 0x83, 0xEA, 0x0E, 0x0E, 0x85, 0xEA, ++ 0x0B, 0x05, 0x87, 0xEA, 0x0E, 0x0E, 0x00, 0x04, 0x00, 0x9F, 0x8A, 0xEA, ++ 0x0C, 0x0A, 0x5A, 0x40, 0x40, 0xEA, 0x05, 0x20, 0x86, 0xEA, 0x0A, 0x0A, ++ 0x86, 0xEA, 0x09, 0x09, 0x11, 0x43, 0x87, 0xEA, 0x09, 0x09, 0x04, 0x9A, ++ 0x07, 0x9E, 0x03, 0x9F, 0x05, 0x9B, 0x40, 0xEA, 0x0A, 0x00, 0x41, 0xEA, ++ 0x0E, 0x61, 0x40, 0xEA, 0x09, 0x60, 0xC2, 0xE9, 0x02, 0x10, 0x35, 0x69, ++ 0x6F, 0x40, 0x17, 0x60, 0x35, 0x46, 0x76, 0x69, 0x01, 0x97, 0x5E, 0x40, ++ 0x56, 0x60, 0x00, 0x96, 0x2E, 0x46, 0xAD, 0x69, 0x69, 0x40, 0x91, 0x60, ++ 0xF3, 0x69, 0x03, 0x91, 0x43, 0x40, 0x02, 0x93, 0xD3, 0x60, 0x0C, 0x9B, ++ 0x06, 0xF1, 0x10, 0x01, 0x8B, 0x42, 0x07, 0x91, 0x7F, 0xF4, 0xC8, 0xAE, ++ 0x06, 0xE0, 0x00, 0xBF, 0xE4, 0xC2, 0x15, 0x00, 0xE4, 0xC3, 0x15, 0x00, ++ 0xE4, 0xC4, 0x15, 0x00, 0xDD, 0xF8, 0x00, 0xE0, 0x3E, 0x0E, 0x5F, 0xFA, ++ 0x8E, 0xF2, 0xDD, 0xE9, 0x02, 0x39, 0x14, 0xF8, 0x06, 0xC0, 0xA2, 0x5C, ++ 0x70, 0x46, 0x42, 0xEA, 0x0C, 0x62, 0x00, 0x92, 0x1D, 0x0E, 0x02, 0x9A, ++ 0x65, 0x5D, 0xF9, 0xB2, 0x5F, 0xFA, 0x89, 0xF3, 0x00, 0x0E, 0x61, 0x5C, ++ 0x20, 0x5C, 0xE3, 0x5C, 0xB8, 0x46, 0x5F, 0xFA, 0x82, 0xFC, 0x4F, 0xEA, ++ 0x19, 0x67, 0x43, 0xEA, 0x00, 0x63, 0xE7, 0x5D, 0x14, 0xF8, 0x0C, 0x00, ++ 0x41, 0xEA, 0x05, 0x61, 0xCE, 0xF3, 0x07, 0x25, 0x40, 0xEA, 0x07, 0x67, ++ 0x65, 0x5D, 0xC9, 0xF3, 0x07, 0x20, 0x41, 0xEA, 0x05, 0x21, 0x14, 0xF8, ++ 0x00, 0xB0, 0xC8, 0xF3, 0x07, 0x25, 0xC2, 0xF3, 0x07, 0x20, 0xCE, 0xF3, ++ 0x07, 0x46, 0xC9, 0xF3, 0x07, 0x4A, 0xC2, 0xF3, 0x07, 0x4C, 0xC8, 0xF3, ++ 0x07, 0x48, 0x65, 0x5D, 0x00, 0x9A, 0x20, 0x5C, 0x14, 0xF8, 0x0A, 0xE0, ++ 0x14, 0xF8, 0x0C, 0xC0, 0x14, 0xF8, 0x08, 0x80, 0xA6, 0x5D, 0x47, 0xEA, ++ 0x05, 0x27, 0x42, 0xEA, 0x0B, 0x24, 0x43, 0xEA, 0x00, 0x20, 0x04, 0x9A, ++ 0x0D, 0x9D, 0x41, 0xEA, 0x0E, 0x41, 0x44, 0xEA, 0x0C, 0x44, 0x40, 0xEA, ++ 0x08, 0x40, 0x47, 0xEA, 0x06, 0x46, 0xC2, 0xE9, 0x00, 0x14, 0xC2, 0xE9, ++ 0x02, 0x06, 0xD5, 0xF8, 0xA0, 0x30, 0x59, 0x40, 0x11, 0x60, 0xD5, 0xF8, ++ 0xA4, 0x30, 0x5C, 0x40, 0x54, 0x60, 0xD5, 0xF8, 0xA8, 0x30, 0x58, 0x40, ++ 0x90, 0x60, 0xD5, 0xF8, 0xAC, 0x30, 0x5E, 0x40, 0xD6, 0x60, 0x0F, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x8F, 0xD0, 0xE9, 0x01, 0x23, 0xF0, 0xB5, 0x19, 0x49, ++ 0x05, 0x68, 0xC7, 0x68, 0x54, 0x04, 0x04, 0xF0, 0x80, 0x76, 0x01, 0xEA, ++ 0xD5, 0x34, 0x34, 0x43, 0x6E, 0x00, 0x06, 0xF0, 0xFE, 0x36, 0x34, 0x43, ++ 0x4F, 0xEA, 0x43, 0x4E, 0x7E, 0x04, 0x0E, 0xF0, 0x80, 0x7E, 0x04, 0x60, ++ 0x01, 0xEA, 0xD2, 0x34, 0x52, 0x00, 0x06, 0xF0, 0x80, 0x7C, 0x44, 0xEA, ++ 0x0E, 0x04, 0x01, 0xEA, 0xD3, 0x36, 0x02, 0xF0, 0xFE, 0x32, 0x5B, 0x00, ++ 0x22, 0x43, 0x46, 0xEA, 0x0C, 0x06, 0x03, 0xF0, 0xFE, 0x33, 0x7C, 0x00, ++ 0x33, 0x43, 0x01, 0xEA, 0xD7, 0x31, 0x04, 0xF0, 0xFE, 0x34, 0x21, 0x43, ++ 0xC0, 0xE9, 0x01, 0x23, 0x2B, 0x06, 0x48, 0xBF, 0x81, 0xF0, 0x07, 0x41, ++ 0xC1, 0x60, 0xF0, 0xBD, 0x01, 0x01, 0x01, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0x29, 0x2A, 0xBD, 0xB0, 0x0B, 0xD8, 0x8B, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0xC0, 0xF2, 0x00, 0x81, 0x00, 0x20, 0x01, 0x46, ++ 0x3D, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x88, 0x46, 0x1D, 0x46, 0x31, 0xF8, ++ 0x04, 0x3B, 0x06, 0x46, 0x23, 0xF4, 0x60, 0x53, 0x14, 0x46, 0x0D, 0xF1, ++ 0x2E, 0x00, 0x12, 0x22, 0xAD, 0xF8, 0x2C, 0x30, 0x05, 0xF0, 0xC4, 0xFC, ++ 0xD6, 0xE9, 0x14, 0x13, 0xD6, 0xE9, 0x16, 0x72, 0xC5, 0xF5, 0x7F, 0x40, ++ 0xF4, 0x30, 0x80, 0xB2, 0x01, 0x90, 0xCD, 0xE9, 0x11, 0x37, 0xDF, 0xF8, ++ 0xEC, 0xE1, 0xDF, 0xF8, 0xEC, 0xC1, 0x10, 0x91, 0x13, 0x92, 0x10, 0xAE, ++ 0x0D, 0xF1, 0xD0, 0x0A, 0x01, 0x20, 0x02, 0xE0, 0x5E, 0xF8, 0x04, 0x0F, ++ 0x10, 0x36, 0xC2, 0xF3, 0x07, 0x2B, 0x5F, 0xFA, 0x82, 0xF9, 0x1C, 0xF8, ++ 0x0B, 0xB0, 0x1C, 0xF8, 0x09, 0x90, 0x8B, 0xEA, 0x00, 0x00, 0x4F, 0xEA, ++ 0x12, 0x6B, 0x40, 0xEA, 0x09, 0x60, 0xC2, 0xF3, 0x07, 0x49, 0x1C, 0xF8, ++ 0x0B, 0xB0, 0x1C, 0xF8, 0x09, 0x90, 0x40, 0xEA, 0x0B, 0x40, 0x40, 0xEA, ++ 0x09, 0x20, 0x41, 0x40, 0x4B, 0x40, 0x5F, 0x40, 0x7A, 0x40, 0x56, 0x45, ++ 0xC6, 0xE9, 0x06, 0x72, 0xC6, 0xE9, 0x04, 0x13, 0xDA, 0xD1, 0x10, 0x22, ++ 0x00, 0x21, 0x03, 0xA8, 0xCE, 0xF7, 0xF6, 0xFC, 0x0D, 0xF1, 0x0A, 0x06, ++ 0x00, 0x21, 0x07, 0xA8, 0x10, 0x22, 0xCE, 0xF7, 0xEF, 0xFC, 0x0D, 0xF1, ++ 0x1A, 0x07, 0x33, 0x46, 0x0D, 0xF1, 0x2A, 0x01, 0x33, 0xF8, 0x02, 0x2F, ++ 0x31, 0xF8, 0x02, 0x0F, 0x9F, 0x42, 0x82, 0xEA, 0x00, 0x02, 0x1A, 0x80, ++ 0xF6, 0xD1, 0x03, 0xA9, 0x10, 0xA8, 0xFF, 0xF7, 0x7B, 0xFD, 0x03, 0x9B, ++ 0x0F, 0x9A, 0x6D, 0x08, 0x08, 0xEB, 0x45, 0x08, 0x53, 0x40, 0xA8, 0xF1, ++ 0x02, 0x01, 0x08, 0xF1, 0x0A, 0x05, 0x03, 0x93, 0x0D, 0xF1, 0x0E, 0x02, ++ 0x32, 0xF8, 0x02, 0x3F, 0x31, 0xF8, 0x02, 0x0F, 0x43, 0x40, 0x8D, 0x42, ++ 0x13, 0x80, 0xF7, 0xD1, 0x03, 0xA9, 0x10, 0xA8, 0xFF, 0xF7, 0x62, 0xFD, ++ 0x01, 0x9B, 0x1C, 0x44, 0xA4, 0xB2, 0x10, 0x2C, 0x08, 0xF1, 0x0C, 0x09, ++ 0x26, 0xD9, 0xA4, 0xF1, 0x11, 0x0A, 0xCA, 0xF3, 0x0B, 0x1A, 0x08, 0xEB, ++ 0x0A, 0x18, 0x08, 0xF1, 0x1C, 0x08, 0x4D, 0x46, 0xAA, 0x1E, 0x33, 0x46, ++ 0x05, 0xF1, 0x0E, 0x00, 0x33, 0xF8, 0x02, 0x1F, 0x32, 0xF8, 0x02, 0xCF, ++ 0x81, 0xEA, 0x0C, 0x01, 0x90, 0x42, 0x19, 0x80, 0xF6, 0xD1, 0x10, 0x35, ++ 0x03, 0xA9, 0x10, 0xA8, 0xFF, 0xF7, 0x40, 0xFD, 0x45, 0x45, 0xEB, 0xD1, ++ 0xCA, 0xEB, 0x0A, 0x33, 0x10, 0x3C, 0x04, 0xEB, 0x03, 0x14, 0x0A, 0xF1, ++ 0x01, 0x0A, 0xA4, 0xB2, 0x09, 0xEB, 0x0A, 0x19, 0x07, 0xA9, 0x10, 0xA8, ++ 0xFF, 0xF7, 0x30, 0xFD, 0x07, 0xA8, 0xFF, 0xF7, 0x01, 0xFF, 0x10, 0x2C, ++ 0x34, 0xD0, 0x65, 0x08, 0x07, 0xA8, 0xFF, 0xF7, 0xFB, 0xFE, 0x65, 0xB1, ++ 0xA9, 0xF1, 0x02, 0x02, 0x02, 0xEB, 0x45, 0x0C, 0x39, 0x46, 0x31, 0xF8, ++ 0x02, 0x3F, 0x32, 0xF8, 0x02, 0x0F, 0x43, 0x40, 0x94, 0x45, 0x0B, 0x80, ++ 0xF7, 0xD1, 0xE3, 0x07, 0x39, 0xD4, 0x80, 0x23, 0xA4, 0x08, 0x05, 0xF0, ++ 0x01, 0x05, 0x3C, 0xAA, 0x05, 0xEB, 0x44, 0x04, 0x02, 0xEB, 0x44, 0x04, ++ 0x34, 0xF8, 0xD4, 0x2C, 0x53, 0x40, 0x24, 0xF8, 0xD4, 0x3C, 0x3A, 0x46, ++ 0x36, 0xF8, 0x02, 0x3F, 0x32, 0xF8, 0x02, 0x1F, 0xB7, 0x42, 0x83, 0xEA, ++ 0x01, 0x03, 0x33, 0x80, 0xF6, 0xD1, 0x03, 0xA9, 0x10, 0xA8, 0xFF, 0xF7, ++ 0xFB, 0xFC, 0xDD, 0xE9, 0x03, 0x01, 0x3D, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, ++ 0xA9, 0xF1, 0x02, 0x02, 0x39, 0x46, 0x09, 0xF1, 0x0E, 0x09, 0x31, 0xF8, ++ 0x02, 0x3F, 0x32, 0xF8, 0x02, 0x0F, 0x43, 0x40, 0x91, 0x45, 0x0B, 0x80, ++ 0xF7, 0xD1, 0xDE, 0xE7, 0x08, 0x49, 0x09, 0x48, 0x4F, 0xF4, 0xD6, 0x72, ++ 0xF3, 0xF7, 0x44, 0xF9, 0x00, 0x20, 0x01, 0x46, 0x3D, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x8F, 0x19, 0xF8, 0x15, 0x30, 0x43, 0xF4, 0x00, 0x43, 0xC1, 0xE7, ++ 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x64, 0x7D, 0x15, 0x00, ++ 0xBC, 0xC2, 0x15, 0x00, 0xE4, 0xC2, 0x15, 0x00, 0x81, 0x04, 0x4F, 0xEA, ++ 0xD0, 0x23, 0xC0, 0xF3, 0xC2, 0x22, 0x0C, 0xD4, 0x13, 0xF0, 0x06, 0x0F, ++ 0x03, 0xF0, 0x06, 0x02, 0x11, 0xD1, 0x00, 0xF0, 0x7F, 0x00, 0x62, 0xB9, ++ 0x03, 0x28, 0x8C, 0xBF, 0x00, 0x20, 0x01, 0x20, 0x70, 0x47, 0x07, 0x2A, ++ 0x0C, 0xD0, 0x03, 0xF0, 0x06, 0x02, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0x2A, ++ 0xF2, 0xD0, 0x00, 0x20, 0x70, 0x47, 0x00, 0xF0, 0x07, 0x00, 0x00, 0x2A, ++ 0xF9, 0xD1, 0xEB, 0xE7, 0x13, 0xF0, 0x06, 0x0F, 0x0C, 0xBF, 0x01, 0x20, ++ 0x00, 0x20, 0x70, 0x47, 0x2D, 0xE9, 0xF0, 0x4F, 0x07, 0x46, 0x40, 0x7F, ++ 0x87, 0xB0, 0x4F, 0xF0, 0xFF, 0x34, 0x09, 0x28, 0x05, 0x94, 0x02, 0xD9, ++ 0x07, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x89, 0x46, 0xF9, 0x6C, 0xC9, 0x4E, ++ 0x8C, 0x6C, 0x0D, 0x6D, 0x4F, 0xF4, 0x1E, 0x71, 0x01, 0xFB, 0x00, 0x60, ++ 0x90, 0x46, 0x90, 0xF8, 0x22, 0x10, 0xFA, 0x8B, 0x14, 0xF4, 0x00, 0x5F, ++ 0x08, 0xBF, 0x01, 0x23, 0x22, 0xF4, 0x00, 0x54, 0x05, 0xF4, 0x80, 0x05, ++ 0x02, 0xF4, 0x00, 0x52, 0xFF, 0x29, 0x01, 0x95, 0xFC, 0x83, 0x02, 0x92, ++ 0xE0, 0xD0, 0xBD, 0x4A, 0xD0, 0xF8, 0x4C, 0xA1, 0x12, 0x68, 0xB2, 0xF9, ++ 0x00, 0x20, 0x00, 0x2A, 0x50, 0xDB, 0xBA, 0xF8, 0xB4, 0x10, 0xBA, 0x6C, ++ 0x48, 0x1E, 0x05, 0xAC, 0xC0, 0xB2, 0x01, 0xEB, 0x41, 0x0E, 0x00, 0x90, ++ 0x03, 0x94, 0x0A, 0xEB, 0x8E, 0x0E, 0x02, 0xF1, 0x3C, 0x00, 0x02, 0xF1, ++ 0x4C, 0x0B, 0xA4, 0x46, 0x50, 0xF8, 0x04, 0x6B, 0xC6, 0xF3, 0x0D, 0x06, ++ 0x79, 0xB1, 0x74, 0x46, 0x00, 0x22, 0x02, 0xE0, 0x01, 0x32, 0x8A, 0x42, ++ 0x09, 0xD0, 0x34, 0xF8, 0x02, 0x5C, 0xB5, 0x42, 0xA4, 0xF1, 0x0C, 0x04, ++ 0xF6, 0xD1, 0x00, 0x9C, 0xA2, 0x1A, 0x8C, 0xF8, 0x00, 0x20, 0x00, 0x2B, ++ 0x40, 0xF0, 0xAD, 0x80, 0x83, 0x45, 0x0C, 0xF1, 0x01, 0x0C, 0xE3, 0xD1, ++ 0x97, 0xF8, 0x36, 0x30, 0x9A, 0xF8, 0xA3, 0x20, 0xC3, 0xF3, 0x82, 0x03, ++ 0x93, 0x42, 0x27, 0xD0, 0x01, 0x9B, 0x00, 0x2B, 0x64, 0xD0, 0xBA, 0xF8, ++ 0x92, 0x20, 0xBA, 0xF8, 0x90, 0x30, 0x01, 0x32, 0x01, 0x33, 0xAA, 0xF8, ++ 0x92, 0x20, 0xAA, 0xF8, 0x90, 0x30, 0xBA, 0xF8, 0x7E, 0x10, 0xBA, 0xF8, ++ 0x7C, 0x20, 0x1F, 0xFA, 0x89, 0xF9, 0xA9, 0xEB, 0x08, 0x03, 0x0B, 0x44, ++ 0x91, 0x44, 0xAA, 0xF8, 0x7E, 0x30, 0xAA, 0xF8, 0x7C, 0x90, 0x87, 0xE7, ++ 0xBA, 0xF1, 0x00, 0x0F, 0xAB, 0xD1, 0x90, 0x49, 0x90, 0x48, 0x00, 0x93, ++ 0x4F, 0xF4, 0x18, 0x62, 0xF3, 0xF7, 0x64, 0xF8, 0x00, 0x9B, 0xA2, 0xE7, ++ 0xBA, 0xF8, 0x90, 0x30, 0xBA, 0xF8, 0x92, 0x20, 0x01, 0x33, 0xAA, 0xF8, ++ 0x90, 0x30, 0x01, 0x9B, 0x01, 0x32, 0xAA, 0xF8, 0x92, 0x20, 0x00, 0x2B, ++ 0xD7, 0xD1, 0x02, 0x9B, 0x00, 0x2B, 0x3A, 0xD0, 0x83, 0x4E, 0x85, 0x4D, ++ 0x03, 0x9F, 0x00, 0x24, 0xB9, 0xF1, 0x00, 0x0F, 0x24, 0xD0, 0x17, 0xF8, ++ 0x01, 0x3B, 0xFF, 0x2B, 0x00, 0xF0, 0xEC, 0x80, 0x00, 0x2C, 0x00, 0xF0, ++ 0x41, 0x81, 0x03, 0xEB, 0x43, 0x02, 0xB8, 0xF1, 0x01, 0x0F, 0x0A, 0xEB, ++ 0x82, 0x02, 0x40, 0xF2, 0x7A, 0x81, 0x92, 0x88, 0x59, 0x00, 0x19, 0x44, ++ 0x0A, 0xEB, 0x81, 0x01, 0x02, 0x32, 0x8A, 0x80, 0xA9, 0xF1, 0x02, 0x09, ++ 0xA8, 0xF1, 0x02, 0x08, 0x71, 0x4A, 0x12, 0x68, 0xB2, 0xF9, 0x00, 0x20, ++ 0x00, 0x2A, 0xC0, 0xF2, 0x02, 0x81, 0x01, 0x34, 0x04, 0x2C, 0xD7, 0xD1, ++ 0x00, 0x23, 0x8A, 0xF8, 0x9B, 0x30, 0x3B, 0xE7, 0xBA, 0xF8, 0x92, 0x20, ++ 0xBA, 0xF8, 0x90, 0x30, 0x01, 0x32, 0x01, 0x33, 0xAA, 0xF8, 0x92, 0x20, ++ 0xAA, 0xF8, 0x90, 0x30, 0xC1, 0xE7, 0x66, 0x4E, 0x67, 0x4D, 0x03, 0x9F, ++ 0x1C, 0x46, 0xB9, 0xF1, 0x00, 0x0F, 0x3F, 0xF4, 0x29, 0xAF, 0x17, 0xF8, ++ 0x01, 0x3B, 0xFF, 0x2B, 0x00, 0xF0, 0xA5, 0x80, 0x00, 0x2C, 0x00, 0xF0, ++ 0xF0, 0x80, 0x03, 0xEB, 0x43, 0x02, 0xB8, 0xF1, 0x01, 0x0F, 0x0A, 0xEB, ++ 0x82, 0x02, 0x40, 0xF2, 0x43, 0x81, 0x92, 0x88, 0x59, 0x00, 0x19, 0x44, ++ 0x0A, 0xEB, 0x81, 0x01, 0x02, 0x32, 0x8A, 0x80, 0xA9, 0xF1, 0x02, 0x09, ++ 0xA8, 0xF1, 0x02, 0x08, 0x53, 0x4A, 0x12, 0x68, 0xB2, 0xF9, 0x00, 0x20, ++ 0x00, 0x2A, 0xC0, 0xF2, 0xB6, 0x80, 0x01, 0x34, 0x04, 0x2C, 0xD6, 0xD1, ++ 0x02, 0xE7, 0x97, 0xF8, 0x36, 0x30, 0x9A, 0xF8, 0xA3, 0x20, 0xC3, 0xF3, ++ 0x82, 0x03, 0x93, 0x42, 0x38, 0xD0, 0x01, 0x9B, 0x00, 0x2B, 0x69, 0xD1, ++ 0xBA, 0xF8, 0x92, 0x30, 0xBA, 0xF8, 0x90, 0x20, 0x01, 0x33, 0x1F, 0xFA, ++ 0x89, 0xF0, 0xAA, 0xF8, 0x92, 0x30, 0x02, 0x9B, 0x02, 0x44, 0xAA, 0xF8, ++ 0x90, 0x20, 0x00, 0x2B, 0x40, 0xF0, 0x8A, 0x80, 0x9D, 0xF8, 0x14, 0x30, ++ 0xFF, 0x2B, 0x3F, 0xF4, 0xE3, 0xAE, 0x0C, 0x22, 0x02, 0xFB, 0x03, 0xA3, ++ 0x04, 0x33, 0x3C, 0x4A, 0x5D, 0x88, 0x19, 0x88, 0x14, 0x68, 0xA0, 0xEB, ++ 0x08, 0x02, 0x2A, 0x44, 0x01, 0x44, 0x92, 0xB2, 0x89, 0xB2, 0x5A, 0x80, ++ 0x19, 0x80, 0xB4, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xBF, 0xF6, 0xCE, 0xAE, ++ 0x91, 0x42, 0xBF, 0xF4, 0xCB, 0xAE, 0x33, 0x49, 0x34, 0x48, 0x4F, 0xF4, ++ 0x1F, 0x62, 0x07, 0xB0, 0xBD, 0xE8, 0xF0, 0x4F, 0xF2, 0xF7, 0xA8, 0xBF, ++ 0xBA, 0xF8, 0x90, 0x30, 0xBA, 0xF8, 0x92, 0x20, 0x1F, 0xFA, 0x89, 0xF0, ++ 0x03, 0x44, 0xAA, 0xF8, 0x90, 0x30, 0x01, 0x9B, 0x01, 0x32, 0xAA, 0xF8, ++ 0x92, 0x20, 0x8B, 0xBB, 0x02, 0x9B, 0x00, 0x2B, 0x52, 0xD1, 0x9D, 0xF8, ++ 0x14, 0x30, 0xFF, 0x2B, 0x00, 0xF0, 0xFD, 0x80, 0x0C, 0x22, 0x02, 0xFB, ++ 0x03, 0xA3, 0x04, 0x33, 0xB9, 0xEB, 0x48, 0x0F, 0x9A, 0xF8, 0xA4, 0x20, ++ 0x80, 0xF0, 0xE9, 0x80, 0x01, 0x2A, 0x40, 0xF2, 0xF8, 0x80, 0x02, 0x2A, ++ 0x03, 0xD0, 0x00, 0x2B, 0x3F, 0xF4, 0x9A, 0xAE, 0xB9, 0xE7, 0xDA, 0xF8, ++ 0x00, 0x20, 0xA2, 0xF5, 0x92, 0x32, 0xF8, 0x3A, 0xCA, 0xF8, 0x00, 0x20, ++ 0x00, 0x2B, 0x3F, 0xF4, 0x8F, 0xAE, 0xAE, 0xE7, 0xBA, 0xF8, 0x90, 0x20, ++ 0xBA, 0xF8, 0x92, 0x30, 0x1F, 0xFA, 0x89, 0xF0, 0x02, 0x44, 0x01, 0x33, ++ 0xAA, 0xF8, 0x90, 0x20, 0xAA, 0xF8, 0x92, 0x30, 0x0A, 0xF1, 0x7C, 0x03, ++ 0x9F, 0xE7, 0x00, 0x2C, 0x75, 0xD0, 0xB8, 0xF1, 0x01, 0x0F, 0x7F, 0xF6, ++ 0x79, 0xAE, 0xA9, 0xF1, 0x02, 0x09, 0xA8, 0xF1, 0x02, 0x08, 0x6C, 0xE7, ++ 0x00, 0x2C, 0x00, 0xF0, 0x8C, 0x80, 0xB8, 0xF1, 0x01, 0x0F, 0x7F, 0xF6, ++ 0x2D, 0xAF, 0xA9, 0xF1, 0x02, 0x09, 0xA8, 0xF1, 0x02, 0x08, 0x24, 0xE7, ++ 0x68, 0x65, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x68, 0x8E, 0x15, 0x00, 0xE4, 0xC5, 0x15, 0x00, 0x9D, 0xF8, 0x14, 0x30, ++ 0xFF, 0x2B, 0x3F, 0xF4, 0x19, 0xAF, 0x0C, 0x22, 0x02, 0xFB, 0x03, 0xA3, ++ 0x00, 0x22, 0x04, 0x33, 0x8A, 0xF8, 0x9B, 0x20, 0x71, 0xE7, 0x03, 0xEB, ++ 0x43, 0x03, 0x0A, 0xEB, 0x83, 0x03, 0x9A, 0x88, 0xDB, 0x88, 0x9A, 0x42, ++ 0xBF, 0xF4, 0x41, 0xAF, 0x40, 0xF6, 0x61, 0x22, 0x31, 0x46, 0x28, 0x46, ++ 0xF2, 0xF7, 0x28, 0xFF, 0x39, 0xE7, 0x03, 0xEB, 0x43, 0x03, 0x0A, 0xEB, ++ 0x83, 0x03, 0x9A, 0x88, 0xDB, 0x88, 0x9A, 0x42, 0xBF, 0xF4, 0xF5, 0xAE, ++ 0x40, 0xF6, 0x33, 0x22, 0x31, 0x46, 0x28, 0x46, 0xF2, 0xF7, 0x18, 0xFF, ++ 0xED, 0xE6, 0xB8, 0xF1, 0x00, 0x0F, 0x6C, 0xD0, 0x03, 0xEB, 0x43, 0x01, ++ 0x0A, 0xEB, 0x81, 0x01, 0x08, 0xF1, 0xFF, 0x38, 0x8A, 0x88, 0x01, 0x32, ++ 0x92, 0xB2, 0xB8, 0xF1, 0x01, 0x0F, 0x8A, 0x80, 0x09, 0xF1, 0xFF, 0x39, ++ 0x19, 0xB2, 0x73, 0xD9, 0x59, 0x00, 0x04, 0xE7, 0xB8, 0xF1, 0x00, 0x0F, ++ 0x1B, 0xD0, 0x03, 0xEB, 0x43, 0x01, 0x0A, 0xEB, 0x81, 0x01, 0x08, 0xF1, ++ 0xFF, 0x38, 0x8A, 0x88, 0x01, 0x32, 0x92, 0xB2, 0xB8, 0xF1, 0x01, 0x0F, ++ 0x8A, 0x80, 0x09, 0xF1, 0xFF, 0x39, 0x19, 0xB2, 0x5B, 0xD9, 0x59, 0x00, ++ 0xB3, 0xE6, 0xB8, 0xF1, 0x02, 0x0F, 0x7F, 0xF6, 0x03, 0xAE, 0xA9, 0xF1, ++ 0x03, 0x09, 0xA8, 0xF1, 0x03, 0x08, 0x01, 0x24, 0xCF, 0xE6, 0x03, 0xEB, ++ 0x43, 0x02, 0x0A, 0xEB, 0x82, 0x02, 0xA0, 0x46, 0x92, 0x88, 0x19, 0xB2, ++ 0x01, 0xEB, 0x41, 0x01, 0x0A, 0xEB, 0x81, 0x01, 0x1F, 0xFA, 0x89, 0xF9, ++ 0xC8, 0x88, 0xA9, 0xEB, 0x08, 0x08, 0x4A, 0x44, 0x40, 0x44, 0x4F, 0xF0, ++ 0x00, 0x09, 0x8A, 0x80, 0xC8, 0x80, 0xC8, 0x46, 0x9A, 0xE6, 0xB8, 0xF1, ++ 0x02, 0x0F, 0x7F, 0xF6, 0xA1, 0xAE, 0xA9, 0xF1, 0x03, 0x09, 0xA8, 0xF1, ++ 0x03, 0x08, 0x01, 0x24, 0x72, 0xE6, 0x92, 0x88, 0x1F, 0xFA, 0x88, 0xF8, ++ 0x19, 0xB2, 0xDF, 0xE7, 0x92, 0x88, 0x1F, 0xFA, 0x88, 0xF8, 0x19, 0xB2, ++ 0x01, 0xEB, 0x41, 0x01, 0x0A, 0xEB, 0x81, 0x01, 0x1F, 0xFA, 0x89, 0xF9, ++ 0xC8, 0x88, 0xA9, 0xEB, 0x08, 0x08, 0x4A, 0x44, 0x40, 0x44, 0x4F, 0xF0, ++ 0x00, 0x09, 0x8A, 0x80, 0xC8, 0x80, 0xC8, 0x46, 0xB2, 0xE6, 0x03, 0xEB, ++ 0x43, 0x02, 0x0A, 0xEB, 0x82, 0x02, 0xA0, 0x46, 0x92, 0x88, 0x19, 0xB2, ++ 0xE6, 0xE7, 0x00, 0x2A, 0x3F, 0xF4, 0x19, 0xAF, 0x01, 0x3A, 0x8A, 0xF8, ++ 0xA4, 0x20, 0x00, 0x2B, 0x3F, 0xF4, 0xB0, 0xAD, 0xCF, 0xE6, 0x02, 0x9B, ++ 0x04, 0xE7, 0x1F, 0xFA, 0x88, 0xF8, 0xB3, 0xE7, 0x1F, 0xFA, 0x88, 0xF8, ++ 0xD4, 0xE7, 0x01, 0x32, 0x8A, 0xF8, 0xA4, 0x20, 0x00, 0x2B, 0x3F, 0xF4, ++ 0xA1, 0xAD, 0xC0, 0xE6, 0x03, 0x88, 0xA3, 0xB1, 0x10, 0xB4, 0x42, 0x88, ++ 0x44, 0x7A, 0x00, 0x21, 0x12, 0x04, 0x01, 0x72, 0xB2, 0xFB, 0xF3, 0xF1, ++ 0x8C, 0xB1, 0x83, 0x88, 0x5D, 0xF8, 0x04, 0x4B, 0x03, 0xEB, 0x43, 0x03, ++ 0x0B, 0x44, 0xC3, 0xF3, 0x98, 0x03, 0x83, 0x80, 0x01, 0x23, 0x43, 0x72, ++ 0x70, 0x47, 0x03, 0x7A, 0xFF, 0x2B, 0x1C, 0xBF, 0x01, 0x33, 0x03, 0x72, ++ 0x70, 0x47, 0x9A, 0x42, 0x24, 0xBF, 0x01, 0xF1, 0xFF, 0x33, 0x83, 0x80, ++ 0x4F, 0xF0, 0x01, 0x03, 0x38, 0xBF, 0x84, 0x80, 0x43, 0x72, 0x5D, 0xF8, ++ 0x04, 0x4B, 0x70, 0x47, 0xF8, 0xB5, 0x06, 0x46, 0x88, 0x04, 0x0C, 0x46, ++ 0xC1, 0xF3, 0xC2, 0x25, 0x19, 0xD4, 0xCB, 0x0A, 0x13, 0xF0, 0x06, 0x0F, ++ 0x40, 0xD1, 0xCF, 0xB2, 0x01, 0xF0, 0x7F, 0x05, 0x05, 0xF0, 0xF8, 0xF9, ++ 0x17, 0xF0, 0x7C, 0x0F, 0x5B, 0xD1, 0x96, 0xF8, 0xAD, 0x20, 0x04, 0xE0, ++ 0xB6, 0xF8, 0xAA, 0x30, 0xEB, 0x40, 0xD9, 0x07, 0x59, 0xD4, 0x6B, 0x1E, ++ 0x95, 0x42, 0xDD, 0xB2, 0xF6, 0xD8, 0x20, 0x46, 0xF8, 0xBD, 0x07, 0x2D, ++ 0x47, 0xD0, 0x04, 0x3D, 0x05, 0xF0, 0xE2, 0xF9, 0x04, 0xF0, 0x0F, 0x02, ++ 0x01, 0x2D, 0xF4, 0xD8, 0xDF, 0xE8, 0x05, 0xF0, 0x01, 0x0E, 0x72, 0xB3, ++ 0x53, 0x1E, 0x24, 0xF0, 0x0F, 0x04, 0x96, 0xF8, 0xB1, 0x20, 0x23, 0x43, ++ 0x98, 0xB2, 0x00, 0x2A, 0xE8, 0xD0, 0x40, 0xF4, 0x00, 0x70, 0xF8, 0xBD, ++ 0x0A, 0xB3, 0x24, 0xF0, 0x0F, 0x03, 0x51, 0x1E, 0x0B, 0x43, 0x98, 0xB2, ++ 0x63, 0x04, 0xDD, 0xD5, 0x03, 0x2A, 0x03, 0xD0, 0x96, 0xF8, 0xBD, 0x30, ++ 0x99, 0x42, 0xD7, 0xDD, 0x20, 0xF4, 0x80, 0x43, 0x98, 0xB2, 0xF8, 0xBD, ++ 0xC4, 0xF3, 0xC1, 0x05, 0x05, 0xF0, 0xB8, 0xF9, 0x35, 0x44, 0x04, 0xF0, ++ 0x07, 0x03, 0x05, 0xE0, 0x95, 0xF8, 0xA6, 0x20, 0xCB, 0xB2, 0xDA, 0x40, ++ 0xD2, 0x07, 0x24, 0xD4, 0x59, 0x1E, 0x00, 0x2B, 0xF6, 0xD1, 0x96, 0xF8, ++ 0xAE, 0x30, 0x03, 0x2B, 0xBD, 0xD8, 0x43, 0xB3, 0x96, 0xF8, 0xB2, 0x20, ++ 0x00, 0xF4, 0x80, 0x60, 0x43, 0xEA, 0x82, 0x23, 0x03, 0x43, 0x98, 0xB2, ++ 0xF8, 0xBD, 0x05, 0xF0, 0x9B, 0xF9, 0x20, 0x46, 0xB0, 0xE7, 0x96, 0xF8, ++ 0xAD, 0x20, 0x04, 0x2A, 0x38, 0xBF, 0x04, 0x22, 0xA5, 0xE7, 0x24, 0xF0, ++ 0x7F, 0x04, 0x44, 0xEA, 0x05, 0x00, 0x00, 0x2D, 0xA4, 0xD1, 0x40, 0xF4, ++ 0x80, 0x63, 0x98, 0xB2, 0xF8, 0xBD, 0x96, 0xF8, 0xB1, 0x20, 0x24, 0xF0, ++ 0x07, 0x04, 0x44, 0xEA, 0x03, 0x00, 0x00, 0x2A, 0x98, 0xD0, 0x40, 0xF4, ++ 0x00, 0x73, 0x98, 0xB2, 0xF8, 0xBD, 0x4F, 0xF4, 0x80, 0x60, 0xF8, 0xBD, ++ 0x8A, 0x04, 0x30, 0xB4, 0xC1, 0xF3, 0xC2, 0x23, 0x20, 0xD4, 0xCA, 0x0A, ++ 0x12, 0xF0, 0x06, 0x0F, 0x26, 0xD1, 0x11, 0xF0, 0x7C, 0x0F, 0x01, 0xF0, ++ 0x7F, 0x03, 0x71, 0xD1, 0x90, 0xF8, 0xAE, 0x40, 0x03, 0x2C, 0x28, 0xBF, ++ 0x03, 0x24, 0x04, 0xE0, 0xB0, 0xF8, 0xAA, 0x20, 0xDA, 0x40, 0xD5, 0x07, ++ 0x74, 0xD4, 0x5A, 0x1C, 0xA3, 0x42, 0xD3, 0xB2, 0xF6, 0xD3, 0x90, 0xF8, ++ 0xA5, 0x30, 0x01, 0x2B, 0x01, 0xD9, 0xD9, 0x02, 0x89, 0xB2, 0x08, 0x46, ++ 0x30, 0xBC, 0x70, 0x47, 0x07, 0x2B, 0xFA, 0xD0, 0x04, 0x3B, 0x01, 0xF0, ++ 0x0F, 0x02, 0x01, 0x2B, 0xF5, 0xD8, 0xDF, 0xE8, 0x03, 0xF0, 0x15, 0x30, ++ 0xC1, 0xF3, 0xC1, 0x04, 0x90, 0xF8, 0xAC, 0x50, 0x04, 0x44, 0x01, 0xF0, ++ 0x07, 0x03, 0x04, 0xE0, 0x94, 0xF8, 0xA6, 0x20, 0xDA, 0x40, 0xD2, 0x07, ++ 0x45, 0xD4, 0x5A, 0x1C, 0x9D, 0x42, 0xD3, 0xB2, 0xF6, 0xD8, 0x08, 0x46, ++ 0x30, 0xBC, 0x70, 0x47, 0x90, 0xF8, 0xAC, 0x30, 0x93, 0x42, 0xDA, 0xD9, ++ 0xB0, 0xF8, 0xA6, 0x30, 0xC1, 0xF3, 0x02, 0x14, 0x64, 0x00, 0x23, 0x41, ++ 0x03, 0xF0, 0x03, 0x03, 0x07, 0x33, 0x93, 0x42, 0xCF, 0xD9, 0x21, 0xF0, ++ 0x0F, 0x01, 0x01, 0x32, 0x90, 0xF8, 0xB1, 0x30, 0x11, 0x43, 0x89, 0xB2, ++ 0x00, 0x2B, 0xC6, 0xD0, 0x41, 0xF4, 0x00, 0x71, 0xC3, 0xE7, 0x90, 0xF8, ++ 0xAC, 0x30, 0x93, 0x42, 0xBF, 0xD9, 0xB0, 0xF8, 0xA6, 0x30, 0xC1, 0xF3, ++ 0x02, 0x14, 0x64, 0x00, 0x23, 0x41, 0x03, 0xF0, 0x03, 0x03, 0x5B, 0x00, ++ 0x07, 0x33, 0x93, 0x42, 0xB3, 0xD9, 0x21, 0xF0, 0x0F, 0x01, 0x53, 0x1C, ++ 0x0B, 0x43, 0x99, 0xB2, 0x5B, 0x04, 0xAC, 0xD5, 0x01, 0x2A, 0x03, 0xD0, ++ 0x90, 0xF8, 0xBD, 0x30, 0x93, 0x42, 0xA6, 0xD8, 0x21, 0xF4, 0x80, 0x41, ++ 0x89, 0xB2, 0xA2, 0xE7, 0x90, 0xF8, 0xAE, 0x40, 0x95, 0xE7, 0x90, 0xF8, ++ 0xB1, 0x20, 0x21, 0xF0, 0x07, 0x01, 0x19, 0x43, 0x00, 0x2A, 0x98, 0xD0, ++ 0x41, 0xF4, 0x00, 0x71, 0x89, 0xB2, 0x94, 0xE7, 0x21, 0xF0, 0x7F, 0x01, ++ 0x19, 0x43, 0x90, 0xE7, 0x2D, 0xE9, 0xF0, 0x4F, 0x01, 0xEB, 0x41, 0x01, ++ 0x00, 0xEB, 0x81, 0x01, 0x85, 0xB0, 0x4C, 0x89, 0xE6, 0x0A, 0xC4, 0xF3, ++ 0x80, 0x22, 0x01, 0x92, 0x71, 0x07, 0x4F, 0xEA, 0x54, 0x22, 0x05, 0x46, ++ 0x06, 0xF0, 0x04, 0x03, 0xC4, 0xF3, 0xC2, 0x27, 0x02, 0x92, 0xC4, 0xF3, ++ 0x40, 0x2B, 0xC4, 0xF3, 0xC1, 0x1A, 0x23, 0xD5, 0x07, 0x2F, 0x50, 0xD0, ++ 0xC4, 0xF3, 0x02, 0x19, 0x04, 0xF0, 0x0F, 0x04, 0xDF, 0xF8, 0x70, 0x83, ++ 0xD8, 0xF8, 0x00, 0x20, 0xB2, 0xF9, 0x00, 0x20, 0x00, 0x2A, 0x22, 0xDA, ++ 0x05, 0x2F, 0x27, 0xD9, 0x40, 0xF2, 0xB5, 0x22, 0xCA, 0x49, 0xCB, 0x48, ++ 0x03, 0x93, 0xF2, 0xF7, 0x0B, 0xFD, 0x95, 0xF8, 0xA5, 0x20, 0x03, 0x9B, ++ 0x05, 0x2A, 0x14, 0xD8, 0xDF, 0xE8, 0x12, 0xF0, 0xD6, 0x00, 0xD6, 0x00, ++ 0x31, 0x01, 0x31, 0x01, 0xF4, 0x00, 0x45, 0x01, 0x16, 0xF0, 0x06, 0x09, ++ 0x26, 0xD1, 0x04, 0xF0, 0x7F, 0x04, 0xDF, 0xF8, 0x2C, 0x83, 0xD8, 0xF8, ++ 0x00, 0x20, 0xB2, 0xF9, 0x00, 0x20, 0x00, 0x2A, 0x06, 0xDB, 0x05, 0x2F, ++ 0x17, 0xD8, 0xDF, 0xE8, 0x07, 0xF0, 0x22, 0x22, 0x0F, 0x0F, 0x50, 0x91, ++ 0x95, 0xF8, 0xA5, 0x10, 0x05, 0x29, 0xF4, 0xD8, 0xDF, 0xE8, 0x11, 0xF0, ++ 0xBD, 0x00, 0xBD, 0x00, 0x15, 0x01, 0x15, 0x01, 0xD8, 0x00, 0x29, 0x01, ++ 0xD8, 0xF8, 0x00, 0x20, 0xB2, 0xF9, 0x00, 0x20, 0x00, 0x2A, 0xC0, 0xF2, ++ 0xDF, 0x80, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xC4, 0xF3, 0xC1, 0x09, ++ 0x04, 0xF0, 0x07, 0x04, 0xD5, 0xE7, 0x4F, 0xF0, 0x00, 0x09, 0x4C, 0x46, ++ 0xAE, 0xE7, 0xD8, 0xF8, 0x00, 0x20, 0xB2, 0xF9, 0x00, 0x20, 0x03, 0x2C, ++ 0x04, 0xD8, 0x95, 0xF8, 0xB2, 0x10, 0x01, 0x29, 0x00, 0xF0, 0x7B, 0x81, ++ 0x00, 0x2A, 0xE6, 0xDA, 0xBB, 0xF1, 0x00, 0x0F, 0x40, 0xF0, 0x2E, 0x81, ++ 0xBA, 0xF1, 0x00, 0x0F, 0x40, 0xF0, 0x1C, 0x81, 0xB9, 0xF1, 0x00, 0x0F, ++ 0x40, 0xF0, 0xDC, 0x81, 0x95, 0xF8, 0xAD, 0x30, 0xA3, 0x42, 0x00, 0xF2, ++ 0xC9, 0x81, 0x95, 0xF8, 0xAE, 0x30, 0xA3, 0x42, 0xC0, 0xF0, 0xEE, 0x81, ++ 0xB5, 0xF8, 0xAA, 0x30, 0x23, 0xFA, 0x04, 0xF4, 0xE2, 0x07, 0xCA, 0xD4, ++ 0x93, 0x49, 0x95, 0x48, 0x40, 0xF2, 0x06, 0x32, 0x3B, 0xE0, 0xD8, 0xF8, ++ 0x00, 0x20, 0xB2, 0xF9, 0x00, 0x20, 0x00, 0x2A, 0xBF, 0xDA, 0x01, 0x9B, ++ 0x00, 0x2B, 0x40, 0xF0, 0xCB, 0x81, 0x95, 0xF8, 0xB1, 0x30, 0x5B, 0x45, ++ 0xC0, 0xF0, 0x52, 0x82, 0x95, 0xF8, 0xAF, 0x30, 0x53, 0x45, 0xC0, 0xF0, ++ 0x3F, 0x82, 0x95, 0xF8, 0xB0, 0x30, 0x4B, 0x45, 0xC0, 0xF0, 0x2C, 0x82, ++ 0x95, 0xF8, 0xAC, 0x30, 0xA3, 0x42, 0xC0, 0xF0, 0x19, 0x82, 0xB5, 0xF8, ++ 0xA6, 0x30, 0x4F, 0xEA, 0x49, 0x02, 0x13, 0x41, 0x03, 0xF0, 0x03, 0x03, ++ 0x07, 0x33, 0x9C, 0x42, 0x00, 0xF3, 0x82, 0x81, 0x06, 0x2C, 0x00, 0xF0, ++ 0x3E, 0x81, 0x09, 0x2C, 0x97, 0xD1, 0xBA, 0xF1, 0x00, 0x0F, 0x40, 0xF0, ++ 0x4B, 0x82, 0xB9, 0xF1, 0x02, 0x0F, 0x90, 0xD0, 0xB9, 0xF1, 0x05, 0x0F, ++ 0x8D, 0xD0, 0x75, 0x49, 0x77, 0x48, 0x4F, 0xF4, 0x48, 0x72, 0x05, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x4F, 0xF2, 0xF7, 0x5C, 0xBC, 0xD8, 0xF8, 0x00, 0x30, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xBF, 0xF6, 0x7E, 0xAF, 0x02, 0x9B, ++ 0x03, 0xF0, 0x03, 0x03, 0x03, 0x2B, 0x00, 0xF0, 0x21, 0x82, 0x95, 0xF8, ++ 0xAF, 0x30, 0x53, 0x45, 0xC0, 0xF0, 0x9E, 0x81, 0x95, 0xF8, 0xB0, 0x30, ++ 0x4B, 0x45, 0xC0, 0xF0, 0xD1, 0x81, 0x95, 0xF8, 0xAC, 0x30, 0xA3, 0x42, ++ 0xC0, 0xF0, 0xBE, 0x81, 0xB5, 0xF8, 0xA6, 0x30, 0x4F, 0xEA, 0x49, 0x09, ++ 0x43, 0xFA, 0x09, 0xF3, 0x03, 0xF0, 0x03, 0x03, 0x5B, 0x00, 0x07, 0x33, ++ 0x9C, 0x42, 0x7F, 0xF7, 0x5C, 0xAF, 0x5C, 0x49, 0x5F, 0x48, 0x40, 0xF2, ++ 0x2F, 0x32, 0xCC, 0xE7, 0xD8, 0xF8, 0x00, 0x20, 0xB2, 0xF9, 0x00, 0x20, ++ 0x00, 0x2A, 0xBF, 0xF6, 0x36, 0xAF, 0x16, 0xF0, 0x06, 0x0F, 0x40, 0xF0, ++ 0x2A, 0x81, 0x05, 0x2F, 0x3F, 0xF6, 0x49, 0xAF, 0x01, 0xA3, 0x53, 0xF8, ++ 0x27, 0xF0, 0x00, 0xBF, 0xE7, 0x21, 0x15, 0x00, 0xE7, 0x21, 0x15, 0x00, ++ 0x8D, 0x23, 0x15, 0x00, 0x8D, 0x23, 0x15, 0x00, 0x43, 0x22, 0x15, 0x00, ++ 0xC5, 0x22, 0x15, 0x00, 0xD8, 0xF8, 0x00, 0x20, 0xB2, 0xF9, 0x00, 0x20, ++ 0x95, 0xF8, 0xAD, 0x10, 0x03, 0x29, 0x60, 0xD8, 0x00, 0x2A, 0xBF, 0xF6, ++ 0x14, 0xAF, 0x04, 0x2F, 0x3F, 0xF4, 0x6B, 0xAF, 0x00, 0x2F, 0x3F, 0xF4, ++ 0x38, 0xAF, 0x42, 0x49, 0x46, 0x48, 0x4F, 0xF4, 0x36, 0x72, 0xF2, 0xF7, ++ 0xF9, 0xFB, 0x06, 0xE7, 0x01, 0x9B, 0x00, 0x2B, 0x40, 0xF0, 0x64, 0x81, ++ 0x95, 0xF8, 0xB1, 0x30, 0x5B, 0x45, 0xC0, 0xF0, 0x51, 0x81, 0x95, 0xF8, ++ 0xAF, 0x30, 0x53, 0x45, 0xC0, 0xF0, 0xD5, 0x80, 0x95, 0xF8, 0xB0, 0x30, ++ 0x4B, 0x45, 0xC0, 0xF0, 0xC2, 0x80, 0x95, 0xF8, 0xAC, 0x30, 0xA3, 0x42, ++ 0xC0, 0xF0, 0xD9, 0x80, 0x4D, 0x44, 0x95, 0xF8, 0xA6, 0x30, 0x23, 0xFA, ++ 0x04, 0xF4, 0xE3, 0x07, 0x3F, 0xF5, 0x01, 0xAF, 0x2E, 0x49, 0x34, 0x48, ++ 0x40, 0xF2, 0x12, 0x32, 0x71, 0xE7, 0xD8, 0xF8, 0x00, 0x20, 0xB2, 0xF9, ++ 0x00, 0x20, 0x95, 0xF8, 0xAD, 0x10, 0x03, 0x29, 0x77, 0xD8, 0x00, 0x2A, ++ 0xBF, 0xF6, 0xD7, 0xAE, 0x00, 0x2B, 0xA2, 0xD0, 0x25, 0x49, 0x2C, 0x48, ++ 0x40, 0xF2, 0xCA, 0x22, 0xF2, 0xF7, 0xC0, 0xFB, 0xCD, 0xE6, 0xD8, 0xF8, ++ 0x00, 0x20, 0xB2, 0xF9, 0x00, 0x20, 0x95, 0xF8, 0xAD, 0x10, 0x03, 0x29, ++ 0x56, 0xD8, 0x00, 0x2A, 0xBF, 0xF6, 0xC3, 0xAE, 0x05, 0x2F, 0x3F, 0xF4, ++ 0x5C, 0xAF, 0x00, 0x2F, 0x3F, 0xF4, 0xE7, 0xAE, 0x19, 0x49, 0x21, 0x48, ++ 0x40, 0xF2, 0xE7, 0x22, 0xF2, 0xF7, 0xA8, 0xFB, 0xB5, 0xE6, 0x00, 0x2A, ++ 0xBF, 0xF6, 0xB3, 0xAE, 0x04, 0x2F, 0x3F, 0xF4, 0x0A, 0xAF, 0x13, 0x49, ++ 0x1B, 0x48, 0x4F, 0xF4, 0x37, 0x72, 0xF2, 0xF7, 0x9B, 0xFB, 0xA8, 0xE6, ++ 0x0F, 0x49, 0x19, 0x48, 0x40, 0xF2, 0x02, 0x32, 0xF2, 0xF7, 0x94, 0xFB, ++ 0xD8, 0xF8, 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xFF, 0xF6, ++ 0xD7, 0xAE, 0xB4, 0xE6, 0x08, 0x49, 0x13, 0x48, 0x40, 0xF2, 0x01, 0x32, ++ 0xF2, 0xF7, 0x86, 0xFB, 0xD8, 0xF8, 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0xBF, 0xF6, 0xA8, 0xAE, 0xBA, 0xF1, 0x00, 0x0F, 0x3F, 0xF4, ++ 0xC5, 0xAE, 0xDF, 0xE7, 0x70, 0x79, 0x15, 0x00, 0x08, 0xC6, 0x15, 0x00, ++ 0xB0, 0xC7, 0x15, 0x00, 0xF0, 0xC8, 0x15, 0x00, 0xA8, 0xC9, 0x15, 0x00, ++ 0xA8, 0xC6, 0x15, 0x00, 0x3C, 0xC8, 0x15, 0x00, 0x48, 0xC6, 0x15, 0x00, ++ 0x04, 0xC7, 0x15, 0x00, 0xE8, 0xC6, 0x15, 0x00, 0x64, 0xC7, 0x15, 0x00, ++ 0x58, 0xC7, 0x15, 0x00, 0x38, 0x36, 0x17, 0x00, 0x00, 0x2A, 0xBF, 0xF6, ++ 0x6C, 0xAE, 0x05, 0x2F, 0x3F, 0xF4, 0x05, 0xAF, 0xA9, 0x49, 0xAA, 0x48, ++ 0x40, 0xF2, 0xEB, 0x22, 0xF2, 0xF7, 0x54, 0xFB, 0x61, 0xE6, 0x00, 0x2A, ++ 0xBF, 0xF6, 0x5F, 0xAE, 0xBA, 0x1E, 0x01, 0x2A, 0x7F, 0xF6, 0x54, 0xAF, ++ 0xA2, 0x49, 0xA4, 0x48, 0x40, 0xF2, 0xCE, 0x22, 0xF2, 0xF7, 0x46, 0xFB, ++ 0x53, 0xE6, 0x00, 0x2A, 0xBF, 0xF6, 0x6B, 0xAE, 0x01, 0x9B, 0x00, 0x2B, ++ 0x7F, 0xF4, 0x80, 0xAE, 0x40, 0xF2, 0xFB, 0x22, 0x9A, 0x49, 0x9D, 0x48, ++ 0xF2, 0xF7, 0x38, 0xFB, 0xD8, 0xF8, 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x20, ++ 0x72, 0xE6, 0xBA, 0xF1, 0x02, 0x0F, 0x7F, 0xF4, 0x58, 0xAE, 0xB9, 0xF1, ++ 0x03, 0x0F, 0x03, 0xD0, 0xB9, 0xF1, 0x06, 0x0F, 0x7F, 0xF4, 0x51, 0xAE, ++ 0x90, 0x49, 0x94, 0x48, 0x40, 0xF2, 0x1F, 0x32, 0xC1, 0xE6, 0x8E, 0x49, ++ 0x92, 0x48, 0x4F, 0xF4, 0x44, 0x72, 0xF2, 0xF7, 0x1D, 0xFB, 0xD8, 0xF8, ++ 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xFF, 0xF6, 0x31, 0xAF, ++ 0x3D, 0xE6, 0x87, 0x49, 0x8C, 0x48, 0x40, 0xF2, 0x0F, 0x32, 0xF2, 0xF7, ++ 0x0F, 0xFB, 0xD8, 0xF8, 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0xFF, 0xF6, 0x1E, 0xAF, 0x2F, 0xE6, 0x80, 0x49, 0x86, 0x48, 0x40, 0xF2, ++ 0x11, 0x32, 0xF2, 0xF7, 0x01, 0xFB, 0xD8, 0xF8, 0x00, 0x30, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0xFF, 0xF6, 0x1A, 0xAF, 0x21, 0xE6, 0x79, 0x49, ++ 0x80, 0x48, 0x40, 0xF2, 0xC2, 0x22, 0xF2, 0xF7, 0xF3, 0xFA, 0x00, 0xE6, ++ 0x75, 0x49, 0x7E, 0x48, 0x40, 0xF2, 0x1E, 0x32, 0xF2, 0xF7, 0xEC, 0xFA, ++ 0xD8, 0xF8, 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xFF, 0xF6, ++ 0x71, 0xAE, 0x0C, 0xE6, 0x6E, 0x49, 0x78, 0x48, 0x4F, 0xF4, 0x41, 0x72, ++ 0xF2, 0xF7, 0xDE, 0xFA, 0xD8, 0xF8, 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0xFF, 0xF6, 0x2A, 0xAE, 0xFE, 0xE5, 0x67, 0x49, 0x72, 0x48, ++ 0x40, 0xF2, 0x03, 0x32, 0xF2, 0xF7, 0xD0, 0xFA, 0xD8, 0xF8, 0x00, 0x30, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xFF, 0xF6, 0x17, 0xAE, 0xF0, 0xE5, ++ 0x60, 0x49, 0x6C, 0x48, 0x40, 0xF2, 0x19, 0x32, 0xF2, 0xF7, 0xC2, 0xFA, ++ 0xD8, 0xF8, 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xFF, 0xF6, ++ 0x28, 0xAE, 0xE2, 0xE5, 0x59, 0x49, 0x66, 0x48, 0x40, 0xF2, 0x05, 0x32, ++ 0xF2, 0xF7, 0xB4, 0xFA, 0xD8, 0xF8, 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0xFF, 0xF6, 0x05, 0xAE, 0xD4, 0xE5, 0x52, 0x49, 0x58, 0x48, ++ 0x4F, 0xF4, 0x4B, 0x72, 0xF2, 0xF7, 0xA6, 0xFA, 0xD8, 0xF8, 0x00, 0x30, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xFF, 0xF6, 0x55, 0xAE, 0xC6, 0xE5, ++ 0x4B, 0x49, 0x59, 0x48, 0x40, 0xF2, 0x0E, 0x32, 0xF2, 0xF7, 0x98, 0xFA, ++ 0xD8, 0xF8, 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xFF, 0xF6, ++ 0xA2, 0xAE, 0xB8, 0xE5, 0x44, 0x49, 0x50, 0x48, 0x40, 0xF2, 0x0D, 0x32, ++ 0xF2, 0xF7, 0x8A, 0xFA, 0xD8, 0xF8, 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0xFF, 0xF6, 0x8F, 0xAE, 0xAA, 0xE5, 0x3D, 0x49, 0x44, 0x48, ++ 0x40, 0xF2, 0x2E, 0x32, 0xF2, 0xF7, 0x7C, 0xFA, 0xD8, 0xF8, 0x00, 0x30, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xFF, 0xF6, 0x35, 0xAE, 0x9C, 0xE5, ++ 0x36, 0x49, 0x3B, 0x48, 0x40, 0xF2, 0x2D, 0x32, 0xF2, 0xF7, 0x6E, 0xFA, ++ 0xD8, 0xF8, 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xFF, 0xF6, ++ 0x22, 0xAE, 0x8E, 0xE5, 0x2F, 0x49, 0x36, 0x48, 0x40, 0xF2, 0x1D, 0x32, ++ 0xF2, 0xF7, 0x60, 0xFA, 0xD8, 0xF8, 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0xFF, 0xF6, 0xDA, 0xAD, 0x80, 0xE5, 0x28, 0x49, 0x2D, 0x48, ++ 0x4F, 0xF4, 0x47, 0x72, 0xF2, 0xF7, 0x52, 0xFA, 0xD8, 0xF8, 0x00, 0x30, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xFF, 0xF6, 0xC7, 0xAD, 0x72, 0xE5, ++ 0x21, 0x49, 0x27, 0x48, 0x40, 0xF2, 0x1B, 0x32, 0xF2, 0xF7, 0x44, 0xFA, ++ 0xD8, 0xF8, 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xFF, 0xF6, ++ 0xB4, 0xAD, 0x64, 0xE5, 0x1A, 0x49, 0x28, 0x48, 0x40, 0xF2, 0x1A, 0x32, ++ 0xF2, 0xF7, 0x36, 0xFA, 0xD8, 0xF8, 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0xFF, 0xF6, 0xA1, 0xAD, 0x56, 0xE5, 0x13, 0x49, 0x22, 0x48, ++ 0x40, 0xF2, 0x2B, 0x32, 0xF2, 0xF7, 0x28, 0xFA, 0xD8, 0xF8, 0x00, 0x30, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xFF, 0xF6, 0xD2, 0xAD, 0x48, 0xE5, ++ 0xBA, 0xF1, 0x02, 0x0F, 0x08, 0xD1, 0xB9, 0xF1, 0x05, 0x0F, 0x7F, 0xF4, ++ 0x42, 0xAD, 0x09, 0x49, 0x18, 0x48, 0x40, 0xF2, 0x21, 0x32, 0xB2, 0xE5, ++ 0xBA, 0xF1, 0x03, 0x0F, 0x7F, 0xF4, 0x39, 0xAD, 0xB9, 0xF1, 0x02, 0x0F, ++ 0x7F, 0xF4, 0x35, 0xAD, 0x02, 0x49, 0x13, 0x48, 0x40, 0xF2, 0x22, 0x32, ++ 0xA5, 0xE5, 0x00, 0xBF, 0x70, 0x79, 0x15, 0x00, 0xD8, 0x93, 0x15, 0x00, ++ 0x64, 0xC6, 0x15, 0x00, 0x48, 0xC7, 0x15, 0x00, 0xAC, 0xC8, 0x15, 0x00, ++ 0x10, 0xC8, 0x15, 0x00, 0xFC, 0xC7, 0x15, 0x00, 0x24, 0xC8, 0x15, 0x00, ++ 0x28, 0xC6, 0x15, 0x00, 0x64, 0xC8, 0x15, 0x00, 0x80, 0xC7, 0x15, 0x00, ++ 0x74, 0xC7, 0x15, 0x00, 0xD4, 0xC7, 0x15, 0x00, 0x98, 0xC7, 0x15, 0x00, ++ 0xE4, 0xC7, 0x15, 0x00, 0xA0, 0xC9, 0x15, 0x00, 0x34, 0xC9, 0x15, 0x00, ++ 0x68, 0xC9, 0x15, 0x00, 0x2D, 0xE9, 0xF0, 0x41, 0x04, 0x46, 0x04, 0xF0, ++ 0x89, 0xFD, 0x94, 0xF8, 0xA5, 0x10, 0x94, 0xF8, 0xAF, 0x20, 0xCB, 0x02, ++ 0x9B, 0xB2, 0x92, 0xB3, 0x55, 0x1E, 0xED, 0xB2, 0x05, 0x29, 0x2B, 0xD8, ++ 0xDF, 0xE8, 0x01, 0xF0, 0x6D, 0x6D, 0x2F, 0x2F, 0x94, 0x03, 0x94, 0xF8, ++ 0xAD, 0x10, 0x03, 0x29, 0x00, 0xF2, 0xD1, 0x80, 0x06, 0x05, 0x40, 0xF1, ++ 0xCE, 0x80, 0x94, 0xF8, 0xAE, 0x60, 0xB4, 0xF8, 0xAA, 0x20, 0x73, 0x1A, ++ 0x01, 0x33, 0x00, 0xF0, 0x7F, 0x07, 0x97, 0xFB, 0xF3, 0xF5, 0x03, 0xFB, ++ 0x15, 0x73, 0x19, 0x44, 0xC9, 0xB2, 0x22, 0xFA, 0x01, 0xF3, 0x13, 0xF0, ++ 0x01, 0x0F, 0x08, 0xBF, 0x31, 0x46, 0x00, 0x29, 0x00, 0xF0, 0x3F, 0x81, ++ 0x94, 0xF8, 0xB2, 0x20, 0x00, 0xF4, 0x80, 0x63, 0x43, 0xEA, 0x82, 0x23, ++ 0x0B, 0x43, 0x9B, 0xB2, 0x18, 0x46, 0xBD, 0xE8, 0xF0, 0x81, 0x15, 0x46, ++ 0xCC, 0xE7, 0x94, 0xF8, 0xAD, 0x10, 0x03, 0x29, 0x01, 0xD8, 0x06, 0x05, ++ 0xD5, 0xD4, 0x94, 0xF8, 0xB0, 0x70, 0x94, 0xF8, 0xAC, 0x60, 0x94, 0xF8, ++ 0xB1, 0xC0, 0x01, 0x37, 0xC0, 0xF3, 0xC1, 0x01, 0xB1, 0xFB, 0xF7, 0xFE, ++ 0x07, 0xFB, 0x1E, 0x11, 0x0C, 0x44, 0x06, 0xF1, 0x01, 0x0E, 0x00, 0xF0, ++ 0x07, 0x08, 0x94, 0xF8, 0xA6, 0x70, 0xB8, 0xFB, 0xFE, 0xF4, 0x0E, 0xFB, ++ 0x14, 0x84, 0xE7, 0x40, 0xFF, 0x07, 0x48, 0xBF, 0xE6, 0xB2, 0x52, 0x1B, ++ 0x0C, 0xF1, 0x01, 0x04, 0xC0, 0xF3, 0x40, 0x2C, 0x01, 0x32, 0xC0, 0xF3, ++ 0xC1, 0x10, 0xBC, 0xFB, 0xF4, 0xF7, 0xC9, 0x00, 0x04, 0xFB, 0x17, 0xC4, ++ 0x41, 0xEA, 0x44, 0x21, 0x90, 0xFB, 0xF2, 0xF4, 0x02, 0xFB, 0x14, 0x00, ++ 0x05, 0x44, 0x0B, 0x43, 0x43, 0xEA, 0xC5, 0x13, 0x9B, 0xB2, 0x33, 0x43, ++ 0x18, 0x46, 0xBD, 0xE8, 0xF0, 0x81, 0x94, 0xF8, 0xAE, 0x70, 0x94, 0xF8, ++ 0xAD, 0x20, 0xB4, 0xF8, 0xAA, 0x50, 0xB9, 0x1A, 0x01, 0x31, 0x00, 0xF0, ++ 0x7F, 0x0C, 0x9C, 0xFB, 0xF1, 0xF6, 0x01, 0xFB, 0x16, 0xC1, 0x0A, 0x44, ++ 0xD2, 0xB2, 0x25, 0xFA, 0x02, 0xF1, 0x11, 0xF0, 0x01, 0x0F, 0x08, 0xBF, ++ 0x3A, 0x46, 0x13, 0x43, 0x00, 0x2A, 0x00, 0xF0, 0xA2, 0x80, 0x01, 0x3A, ++ 0xD2, 0xB2, 0x02, 0x2A, 0x9E, 0xD8, 0x94, 0xF8, 0xB2, 0x20, 0x00, 0xF4, ++ 0x80, 0x60, 0x40, 0xEA, 0x82, 0x20, 0x03, 0x43, 0x9B, 0xB2, 0x95, 0xE7, ++ 0x94, 0xF8, 0xAD, 0x10, 0x03, 0x29, 0x40, 0xF2, 0x8C, 0x80, 0x94, 0xF8, ++ 0xB0, 0x10, 0xB4, 0xF8, 0xA6, 0x70, 0x94, 0xF8, 0xAC, 0xC0, 0x94, 0xF8, ++ 0xB1, 0x40, 0x4E, 0x1C, 0xC0, 0xF3, 0x02, 0x11, 0xB1, 0xFB, 0xF6, 0xFE, ++ 0x06, 0xFB, 0x1E, 0x11, 0x4E, 0x00, 0x37, 0x41, 0x07, 0xF0, 0x03, 0x07, ++ 0x0C, 0xF1, 0x01, 0x06, 0x00, 0xF0, 0x0F, 0x0C, 0x07, 0x37, 0xBC, 0xFB, ++ 0xF6, 0xFE, 0x06, 0xFB, 0x1E, 0xCC, 0xBC, 0x45, 0xCE, 0xB2, 0xA2, 0xEB, ++ 0x05, 0x02, 0x40, 0xF3, 0x81, 0x80, 0x02, 0xF1, 0x01, 0x0C, 0xC0, 0xF3, ++ 0xC1, 0x1E, 0x9E, 0xFB, 0xFC, 0xF2, 0x0C, 0xFB, 0x12, 0xE2, 0x15, 0x44, ++ 0xFF, 0xB2, 0xED, 0xB2, 0x09, 0x2F, 0x40, 0xF0, 0xAE, 0x80, 0x00, 0x2D, ++ 0x40, 0xF0, 0x98, 0x80, 0x02, 0x29, 0x00, 0xF0, 0xC0, 0x80, 0x05, 0x2E, ++ 0x14, 0xBF, 0x4F, 0xF0, 0x08, 0x0C, 0x4F, 0xF0, 0x09, 0x0C, 0x09, 0x01, ++ 0x09, 0xB2, 0x00, 0x25, 0x76, 0xE0, 0x94, 0xF8, 0xB0, 0x70, 0xB4, 0xF8, ++ 0xA6, 0x60, 0x94, 0xF8, 0xAC, 0xC0, 0x79, 0x1C, 0xC0, 0xF3, 0x02, 0x17, ++ 0xB7, 0xFB, 0xF1, 0xFE, 0x01, 0xFB, 0x1E, 0x77, 0x79, 0x00, 0x0E, 0x41, ++ 0x06, 0xF0, 0x03, 0x06, 0x0C, 0xF1, 0x01, 0x0C, 0x00, 0xF0, 0x0F, 0x01, ++ 0x76, 0x00, 0x07, 0x36, 0xB1, 0xFB, 0xFC, 0xFE, 0x0C, 0xFB, 0x1E, 0x11, ++ 0xB1, 0x42, 0xC0, 0xF3, 0x41, 0x2C, 0xA2, 0xEB, 0x05, 0x02, 0xC8, 0xBF, ++ 0xF1, 0xB2, 0x02, 0xF1, 0x01, 0x02, 0xC0, 0xF3, 0xC1, 0x1E, 0xD8, 0xBF, ++ 0xC9, 0xB2, 0xBC, 0xF1, 0x03, 0x0F, 0x18, 0xBF, 0x4F, 0xEA, 0x4C, 0x26, ++ 0x9E, 0xFB, 0xF2, 0xFC, 0x02, 0xFB, 0x1C, 0xEC, 0x94, 0xF8, 0xBC, 0x20, ++ 0x65, 0x44, 0x08, 0xBF, 0x4F, 0xF4, 0x80, 0x66, 0xED, 0xB2, 0xEA, 0xB1, ++ 0x02, 0x29, 0x1A, 0xD0, 0x94, 0xF8, 0xBD, 0x20, 0x8A, 0x42, 0x16, 0xD3, ++ 0x94, 0xF8, 0xBE, 0xC0, 0xFA, 0xB2, 0x94, 0x45, 0x11, 0xD3, 0x94, 0xF8, ++ 0xBF, 0x20, 0xAA, 0x42, 0x0D, 0xD3, 0x00, 0xF4, 0x80, 0x42, 0x12, 0xB2, ++ 0x0A, 0xE0, 0x07, 0x05, 0x7F, 0xF5, 0x71, 0xAF, 0xE1, 0xE6, 0x43, 0xF4, ++ 0x80, 0x63, 0x9B, 0xB2, 0x18, 0x46, 0xBD, 0xE8, 0xF0, 0x81, 0x00, 0x22, ++ 0x43, 0xEA, 0x07, 0x13, 0x43, 0xEA, 0xC5, 0x15, 0x29, 0x43, 0x31, 0x43, ++ 0x42, 0xEA, 0x01, 0x03, 0x9B, 0xB2, 0x18, 0x46, 0xBD, 0xE8, 0xF0, 0x81, ++ 0x57, 0x1C, 0xC0, 0xF3, 0xC1, 0x1E, 0x9E, 0xFB, 0xF7, 0xF2, 0x07, 0xFB, ++ 0x12, 0xE2, 0x15, 0x44, 0xBC, 0xF1, 0x06, 0x0F, 0xED, 0xB2, 0x5F, 0xFA, ++ 0x8C, 0xF7, 0x7F, 0xF4, 0x7B, 0xAF, 0x02, 0x2D, 0x20, 0xD0, 0x09, 0x01, ++ 0x09, 0xB2, 0xED, 0x01, 0x01, 0x34, 0xC0, 0xF3, 0x40, 0x20, 0xB0, 0xFB, ++ 0xF4, 0xF2, 0x04, 0xFB, 0x12, 0x00, 0x43, 0xEA, 0x40, 0x23, 0x2B, 0x43, ++ 0x0B, 0x43, 0x4C, 0xEA, 0x03, 0x03, 0x9B, 0xB2, 0x18, 0x46, 0xBD, 0xE8, ++ 0xF0, 0x81, 0x4F, 0xF4, 0x80, 0x63, 0xC5, 0xE6, 0x02, 0x2D, 0x16, 0xD1, ++ 0x05, 0x29, 0x2D, 0xD0, 0x09, 0x01, 0x09, 0xB2, 0xBC, 0x46, 0x4F, 0xF4, ++ 0x80, 0x75, 0xE1, 0xE7, 0x03, 0x29, 0x16, 0xD0, 0x06, 0x29, 0x14, 0xD0, ++ 0x09, 0x01, 0x09, 0xB2, 0x4F, 0xF4, 0x80, 0x75, 0xD8, 0xE7, 0x09, 0x01, ++ 0x09, 0xB2, 0xED, 0x01, 0x0F, 0xFA, 0x87, 0xFC, 0xD2, 0xE7, 0x03, 0x2D, ++ 0x1B, 0xD1, 0x02, 0x29, 0x0F, 0xD0, 0x09, 0x01, 0x09, 0xB2, 0xBC, 0x46, ++ 0x4F, 0xF4, 0xC0, 0x75, 0xC8, 0xE7, 0x71, 0x1E, 0xC9, 0xB2, 0x09, 0x01, ++ 0x4F, 0xF0, 0x06, 0x0C, 0x4F, 0xF4, 0x80, 0x75, 0xC0, 0xE7, 0xBC, 0x46, ++ 0x43, 0xE7, 0xBC, 0x46, 0x10, 0x21, 0x4F, 0xF4, 0xC0, 0x75, 0xB9, 0xE7, ++ 0xBC, 0x46, 0x40, 0x21, 0x4F, 0xF4, 0x80, 0x75, 0xB4, 0xE7, 0x09, 0x01, ++ 0x09, 0xB2, 0xED, 0x01, 0xBC, 0x46, 0xAF, 0xE7, 0xB0, 0xF8, 0xB4, 0x30, ++ 0x00, 0x2B, 0x4A, 0xD0, 0x2D, 0xE9, 0xF0, 0x4F, 0x03, 0xF1, 0xFF, 0x3B, ++ 0x1F, 0xFA, 0x8B, 0xFB, 0xBB, 0xF1, 0x01, 0x0F, 0x85, 0xB0, 0x8A, 0x46, ++ 0x00, 0xF1, 0x10, 0x09, 0x3A, 0xD9, 0x01, 0x25, 0x2F, 0x46, 0x0A, 0xF1, ++ 0x04, 0x04, 0x4E, 0x46, 0x00, 0x21, 0x0D, 0xE0, 0x13, 0x43, 0x04, 0xD1, ++ 0x73, 0x7A, 0x13, 0xB9, 0x73, 0x7D, 0x01, 0x2B, 0x0B, 0xD0, 0x01, 0x35, ++ 0xAF, 0xB2, 0x06, 0xF1, 0x0C, 0x08, 0x5F, 0x45, 0x46, 0x46, 0x20, 0xD2, ++ 0x22, 0x68, 0x54, 0xF8, 0x04, 0x3F, 0x9A, 0x42, 0xEC, 0xD9, 0x0C, 0x22, ++ 0x06, 0xEB, 0x02, 0x08, 0x31, 0x46, 0x01, 0xA8, 0x04, 0xF0, 0x3E, 0xFB, ++ 0x30, 0x46, 0x41, 0x46, 0x0C, 0x22, 0x04, 0xF0, 0x39, 0xFB, 0x0C, 0x22, ++ 0x01, 0xA9, 0x40, 0x46, 0x04, 0xF0, 0x34, 0xFB, 0x01, 0x35, 0x54, 0xE9, ++ 0x01, 0x32, 0x39, 0x46, 0xAF, 0xB2, 0x5F, 0x45, 0x44, 0xF8, 0x04, 0x2C, ++ 0x23, 0x60, 0x46, 0x46, 0xDE, 0xD3, 0x19, 0xB1, 0x8B, 0x46, 0xBB, 0xF1, ++ 0x01, 0x0F, 0xC4, 0xD8, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x70, 0x47, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0xB0, 0xF8, 0xB4, 0x50, 0x83, 0xB0, 0x06, 0x46, ++ 0x89, 0x46, 0x00, 0x2D, 0x00, 0xF0, 0xE2, 0x80, 0x6F, 0x1E, 0x1F, 0xFA, ++ 0x87, 0xF8, 0x08, 0xEB, 0x48, 0x08, 0x00, 0xF1, 0x0C, 0x03, 0x03, 0xEB, ++ 0x88, 0x08, 0x04, 0x46, 0x4F, 0xF0, 0x00, 0x0A, 0x41, 0xF6, 0x98, 0x1B, ++ 0x60, 0x89, 0xFE, 0xF7, 0xAD, 0xFE, 0x30, 0xB9, 0x63, 0x7B, 0x23, 0xB1, ++ 0x23, 0x89, 0x5B, 0x45, 0x07, 0xD8, 0x4F, 0xF0, 0x01, 0x0A, 0x0C, 0x34, ++ 0x44, 0x45, 0xF1, 0xD1, 0x4F, 0xEA, 0xCA, 0x00, 0x40, 0xB2, 0x96, 0xF8, ++ 0xA2, 0x40, 0x24, 0xF0, 0x08, 0x04, 0x04, 0x43, 0xE4, 0xB2, 0x86, 0xF8, ++ 0xA2, 0x40, 0x14, 0xF0, 0x02, 0x04, 0x09, 0xD1, 0x05, 0xF1, 0x80, 0x43, ++ 0x01, 0x3B, 0xD9, 0xF8, 0x00, 0x20, 0x59, 0xF8, 0x23, 0x30, 0x9A, 0x42, ++ 0x00, 0xF2, 0x9C, 0x80, 0x1F, 0xFA, 0x87, 0xFB, 0xCD, 0xF8, 0x00, 0xB0, ++ 0x4F, 0xF0, 0x02, 0x08, 0x00, 0x9C, 0xA6, 0xF8, 0x88, 0xB0, 0x04, 0xEB, ++ 0x44, 0x03, 0x06, 0xEB, 0x83, 0x03, 0x58, 0x89, 0xFE, 0xF7, 0x7A, 0xFE, ++ 0x63, 0x00, 0x01, 0x93, 0xE0, 0xB9, 0x00, 0x2F, 0x13, 0xDD, 0x82, 0x46, ++ 0x84, 0x46, 0x0C, 0xEB, 0x4C, 0x0C, 0x06, 0xEB, 0x8C, 0x04, 0x60, 0x89, ++ 0xFE, 0xF7, 0x6C, 0xFE, 0x0A, 0xF1, 0x01, 0x03, 0x1F, 0xFA, 0x83, 0xFA, ++ 0xD4, 0x46, 0x10, 0xB1, 0x4F, 0xF0, 0x00, 0x03, 0xA3, 0x73, 0xBA, 0x45, ++ 0xED, 0xDB, 0xDD, 0xE9, 0x00, 0x23, 0x13, 0x44, 0x06, 0xEB, 0x83, 0x04, ++ 0x01, 0x23, 0xA3, 0x73, 0xA8, 0x45, 0xA6, 0xF8, 0x8A, 0xB0, 0x76, 0xD2, ++ 0xA5, 0xEB, 0x08, 0x03, 0x03, 0xEB, 0x43, 0x03, 0x06, 0xEB, 0x83, 0x03, ++ 0x03, 0xE0, 0x1F, 0xFA, 0x80, 0xF8, 0xA8, 0x45, 0x6B, 0xD0, 0x99, 0x7B, ++ 0x08, 0xF1, 0x01, 0x00, 0x0C, 0x3B, 0x00, 0x29, 0xF5, 0xD0, 0xA5, 0xEB, ++ 0x08, 0x00, 0x08, 0xF1, 0x01, 0x08, 0x1F, 0xFA, 0x88, 0xF8, 0x80, 0xB2, ++ 0x45, 0x45, 0xA6, 0xF8, 0x8A, 0x00, 0x58, 0xD9, 0xA5, 0xEB, 0x08, 0x05, ++ 0xA7, 0xEB, 0x08, 0x08, 0x4F, 0xEA, 0x18, 0x48, 0x05, 0xEB, 0x45, 0x03, ++ 0x4F, 0xEA, 0x08, 0x48, 0x06, 0xEB, 0x83, 0x03, 0x02, 0xE0, 0x01, 0x3D, ++ 0x45, 0x45, 0x48, 0xD0, 0x99, 0x7B, 0x0C, 0x3B, 0x00, 0x29, 0xF8, 0xD0, ++ 0x05, 0xEB, 0x45, 0x03, 0x06, 0xEB, 0x83, 0x03, 0x59, 0xF8, 0x25, 0x20, ++ 0xB3, 0xF8, 0x08, 0xE0, 0x30, 0xB3, 0x31, 0x46, 0x00, 0x23, 0x4F, 0xF2, ++ 0x32, 0x38, 0x0C, 0xE0, 0x59, 0xF8, 0x23, 0x70, 0x97, 0x42, 0x02, 0xD3, ++ 0xA6, 0x46, 0x3A, 0x46, 0x1D, 0x46, 0x01, 0x33, 0x9C, 0xB2, 0xA0, 0x42, ++ 0x01, 0xF1, 0x0C, 0x01, 0x14, 0xD9, 0x8C, 0x7B, 0x9F, 0xB2, 0x00, 0x2C, ++ 0xF5, 0xD0, 0x5F, 0x45, 0xF3, 0xD0, 0x0C, 0x89, 0x44, 0x45, 0xE9, 0xD8, ++ 0x74, 0x45, 0xEE, 0xD3, 0x59, 0xF8, 0x23, 0x20, 0x1D, 0x46, 0x01, 0x33, ++ 0xA6, 0x46, 0x9C, 0xB2, 0xA0, 0x42, 0x01, 0xF1, 0x0C, 0x01, 0xEA, 0xD8, ++ 0x00, 0x23, 0xA6, 0xF8, 0x8C, 0x50, 0xA6, 0xF8, 0x8E, 0x30, 0x03, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x8F, 0x07, 0xEB, 0x47, 0x03, 0x06, 0xEB, 0x83, 0x03, ++ 0x5B, 0x7B, 0x00, 0x2B, 0x3F, 0xF4, 0x5C, 0xAF, 0x00, 0x94, 0xA3, 0x46, ++ 0x4F, 0xF0, 0x01, 0x08, 0x5C, 0xE7, 0x05, 0x46, 0xB8, 0xE7, 0x5D, 0x46, ++ 0x58, 0x46, 0xB5, 0xE7, 0x28, 0x46, 0x4F, 0xF0, 0xFF, 0x37, 0x38, 0xE7, ++ 0xC1, 0xF3, 0xC2, 0x23, 0x05, 0x2B, 0x5B, 0xD8, 0xDF, 0xE8, 0x03, 0xF0, ++ 0x03, 0x03, 0x27, 0x27, 0x0B, 0x32, 0xB0, 0xF8, 0xAA, 0x00, 0x01, 0xF0, ++ 0x7F, 0x01, 0xC8, 0x40, 0x00, 0xF0, 0x01, 0x00, 0x70, 0x47, 0xC1, 0xF3, ++ 0x02, 0x12, 0xB0, 0xF8, 0xA6, 0x00, 0x53, 0x00, 0x18, 0x41, 0x00, 0xF0, ++ 0x03, 0x00, 0x07, 0x30, 0x01, 0xF0, 0x0F, 0x03, 0x83, 0x42, 0xCC, 0xBF, ++ 0x00, 0x20, 0x01, 0x20, 0x06, 0x2B, 0xC1, 0xF3, 0xC1, 0x11, 0x24, 0xD0, ++ 0x09, 0x2B, 0x24, 0xD1, 0x21, 0xBB, 0x02, 0x2A, 0x21, 0xD0, 0x05, 0x2A, ++ 0x18, 0xBF, 0x00, 0x20, 0x70, 0x47, 0xC1, 0xF3, 0xC1, 0x03, 0x18, 0x44, ++ 0x01, 0xF0, 0x07, 0x01, 0x90, 0xF8, 0xA6, 0x00, 0xC8, 0x40, 0x00, 0xF0, ++ 0x01, 0x00, 0x70, 0x47, 0xB0, 0xF8, 0xA6, 0x00, 0xC1, 0xF3, 0x02, 0x13, ++ 0x5B, 0x00, 0x18, 0x41, 0x00, 0xF0, 0x03, 0x00, 0x40, 0x00, 0x07, 0x30, ++ 0x01, 0xF0, 0x0F, 0x01, 0x81, 0x42, 0xCC, 0xBF, 0x00, 0x20, 0x01, 0x20, ++ 0x70, 0x47, 0x02, 0x29, 0x06, 0xD0, 0x70, 0x47, 0x02, 0x29, 0x09, 0xD1, ++ 0x05, 0x2A, 0x08, 0xBF, 0x00, 0x20, 0x70, 0x47, 0x03, 0x2A, 0x09, 0xD0, ++ 0x06, 0x2A, 0x08, 0xBF, 0x00, 0x20, 0x70, 0x47, 0x03, 0x29, 0xF0, 0xD1, ++ 0x02, 0x2A, 0x08, 0xBF, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0xEA, 0xE7, ++ 0x01, 0x20, 0x70, 0x47, 0x2D, 0xE9, 0xF0, 0x4F, 0x82, 0x46, 0xB0, 0xF8, ++ 0x88, 0x70, 0xB0, 0xF8, 0x8A, 0x00, 0x9A, 0xF8, 0xAD, 0x30, 0x9A, 0xF8, ++ 0xAE, 0x60, 0x00, 0xEB, 0x40, 0x00, 0x07, 0xEB, 0x47, 0x07, 0x83, 0xB0, ++ 0x0A, 0xEB, 0x80, 0x0C, 0x0A, 0xEB, 0x87, 0x07, 0x14, 0x46, 0x0D, 0x46, ++ 0x08, 0x46, 0x52, 0x00, 0x4F, 0xF0, 0xFF, 0x31, 0x7F, 0x89, 0xBC, 0xF8, ++ 0x0A, 0x80, 0x00, 0x93, 0xCD, 0xF7, 0x86, 0xF9, 0x00, 0x2C, 0x7E, 0xD0, ++ 0x00, 0x9B, 0xA6, 0xEB, 0x03, 0x09, 0x01, 0x3C, 0x09, 0xF1, 0x01, 0x03, ++ 0xE4, 0xB2, 0x01, 0x93, 0x4F, 0xF0, 0x00, 0x0B, 0x5F, 0xFA, 0x8B, 0xF3, ++ 0x05, 0x2B, 0x5E, 0xD8, 0xDF, 0xE8, 0x03, 0xF0, 0x59, 0x41, 0x32, 0x23, ++ 0x13, 0x03, 0x41, 0x46, 0x50, 0x46, 0xFE, 0xF7, 0xF9, 0xFF, 0x80, 0x45, ++ 0x81, 0x46, 0x52, 0xD0, 0x01, 0x46, 0x50, 0x46, 0xFF, 0xF7, 0x5E, 0xFF, ++ 0x00, 0x28, 0x4C, 0xD0, 0xA5, 0xF8, 0x0A, 0x90, 0x49, 0xE0, 0x41, 0x46, ++ 0x50, 0x46, 0xFF, 0xF7, 0x77, 0xF8, 0x80, 0x45, 0x81, 0x46, 0x42, 0xD0, ++ 0x01, 0x46, 0x50, 0x46, 0xFF, 0xF7, 0x4E, 0xFF, 0x00, 0x28, 0x3C, 0xD0, ++ 0xA5, 0xF8, 0x08, 0x90, 0x39, 0xE0, 0x39, 0x46, 0x50, 0x46, 0xFE, 0xF7, ++ 0xD9, 0xFF, 0xB8, 0x42, 0x81, 0x46, 0x32, 0xD0, 0x01, 0x46, 0x50, 0x46, ++ 0xFF, 0xF7, 0x3E, 0xFF, 0x68, 0xB3, 0xA5, 0xF8, 0x06, 0x90, 0x2A, 0xE0, ++ 0x39, 0x46, 0x50, 0x46, 0xFF, 0xF7, 0x58, 0xF8, 0xB8, 0x42, 0x81, 0x46, ++ 0x23, 0xD0, 0x01, 0x46, 0x50, 0x46, 0xFF, 0xF7, 0x2F, 0xFF, 0xF0, 0xB1, ++ 0xA5, 0xF8, 0x04, 0x90, 0x1B, 0xE0, 0x00, 0x9B, 0x03, 0x2B, 0x03, 0xD8, ++ 0x9A, 0xF8, 0xA2, 0x30, 0x19, 0x07, 0x3B, 0xD4, 0xC7, 0xF3, 0xC2, 0x23, ++ 0x05, 0x2B, 0x4F, 0xEA, 0xD7, 0x22, 0x23, 0xD0, 0x12, 0xF0, 0x06, 0x0F, ++ 0x0B, 0xD0, 0x9A, 0xF8, 0xB1, 0x30, 0x01, 0x2B, 0x07, 0xD1, 0x87, 0xF4, ++ 0x00, 0x73, 0x6B, 0x80, 0x03, 0xE0, 0x50, 0x46, 0xFF, 0xF7, 0x1E, 0xFC, ++ 0x28, 0x80, 0x03, 0x2E, 0x09, 0xD8, 0x35, 0xF8, 0x1B, 0x20, 0x4F, 0xF6, ++ 0xFF, 0x73, 0x9A, 0x42, 0x04, 0xBF, 0x46, 0xF4, 0x80, 0x63, 0x25, 0xF8, ++ 0x1B, 0x30, 0x5C, 0x45, 0x0B, 0xF1, 0x01, 0x03, 0x01, 0xD0, 0x9B, 0x46, ++ 0x8A, 0xE7, 0x03, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x1A, 0x4A, 0xC7, 0xF3, ++ 0x41, 0x23, 0x01, 0x33, 0xA2, 0xFB, 0x03, 0x21, 0x21, 0xF0, 0x01, 0x02, ++ 0x02, 0xEB, 0x51, 0x02, 0x27, 0xF4, 0xC0, 0x67, 0x9B, 0x1A, 0x47, 0xEA, ++ 0x43, 0x23, 0x6B, 0x80, 0xBF, 0xB2, 0xD8, 0xE7, 0x04, 0xF0, 0x82, 0xF9, ++ 0x01, 0x99, 0x00, 0xF0, 0x7F, 0x02, 0x92, 0xFB, 0xF1, 0xF3, 0x01, 0xFB, ++ 0x13, 0x23, 0x00, 0x9A, 0x13, 0x44, 0xBA, 0xF8, 0xAA, 0x20, 0xDB, 0xB2, ++ 0xDA, 0x40, 0xD2, 0x07, 0x0F, 0xD5, 0x00, 0x2B, 0x08, 0xBF, 0x33, 0x46, ++ 0x5A, 0x1E, 0x02, 0x2A, 0x6B, 0x80, 0xCC, 0xD8, 0x9A, 0xF8, 0xB2, 0x10, ++ 0x00, 0xF4, 0x80, 0x62, 0x42, 0xEA, 0x81, 0x22, 0x13, 0x43, 0x6B, 0x80, ++ 0xC3, 0xE7, 0x33, 0x46, 0xF0, 0xE7, 0x00, 0xBF, 0xAB, 0xAA, 0xAA, 0xAA, ++ 0x2D, 0xE9, 0xF0, 0x47, 0x05, 0x46, 0x84, 0xB0, 0x01, 0xA9, 0x06, 0x22, ++ 0xFF, 0xF7, 0x1C, 0xFF, 0xB5, 0xF8, 0xB4, 0x10, 0x01, 0x29, 0x30, 0xD9, ++ 0x00, 0x26, 0x01, 0x24, 0xB0, 0x46, 0xA1, 0x46, 0x4F, 0xF6, 0xFF, 0x77, ++ 0x18, 0xE0, 0xB5, 0xF8, 0x88, 0x20, 0xA2, 0x42, 0x21, 0xD0, 0xB5, 0xF8, ++ 0x8A, 0x20, 0xA2, 0x42, 0x1D, 0xD0, 0xB5, 0xF8, 0x8C, 0x20, 0xA2, 0x42, ++ 0x19, 0xD0, 0x05, 0x2E, 0x17, 0xD8, 0x04, 0xAA, 0x02, 0xEB, 0x46, 0x02, ++ 0x32, 0xF8, 0x0C, 0xEC, 0xBE, 0x45, 0x17, 0xD1, 0xA1, 0x42, 0x06, 0xF1, ++ 0x01, 0x06, 0x10, 0xD9, 0x04, 0xEB, 0x44, 0x03, 0x05, 0xEB, 0x83, 0x03, ++ 0x4F, 0xEA, 0x44, 0x0C, 0xB3, 0xF9, 0x08, 0x20, 0x00, 0x2A, 0xDC, 0xDA, ++ 0x1A, 0x7B, 0x0A, 0x2A, 0xD9, 0xD8, 0x01, 0x34, 0xA4, 0xB2, 0xA1, 0x42, ++ 0xEE, 0xD8, 0x04, 0xB0, 0xBD, 0xE8, 0xF0, 0x87, 0x59, 0xB1, 0x2A, 0x46, ++ 0x00, 0x20, 0xB2, 0xF8, 0x0A, 0xA0, 0xF2, 0x45, 0x00, 0xF1, 0x01, 0x00, ++ 0x02, 0xF1, 0x0C, 0x02, 0xDC, 0xD0, 0x88, 0x42, 0xF5, 0xD1, 0x0C, 0xEB, ++ 0x04, 0x02, 0x05, 0xEB, 0x82, 0x02, 0xA3, 0xF8, 0x0A, 0xE0, 0xA3, 0xF8, ++ 0x08, 0x80, 0x21, 0x46, 0x82, 0xF8, 0x0D, 0x80, 0x28, 0x46, 0xA3, 0xF8, ++ 0x04, 0x80, 0xA3, 0xF8, 0x06, 0x80, 0x01, 0x34, 0x82, 0xF8, 0x0C, 0x80, ++ 0x82, 0xF8, 0x0E, 0x90, 0xFF, 0xF7, 0x12, 0xF8, 0xA4, 0xB2, 0xB5, 0xF8, ++ 0xB4, 0x10, 0xBF, 0xE7, 0x30, 0xB4, 0x90, 0xF8, 0xA5, 0x30, 0x05, 0x2B, ++ 0x00, 0xF2, 0x8C, 0x80, 0xDF, 0xE8, 0x03, 0xF0, 0x36, 0x36, 0x03, 0x03, ++ 0x70, 0x57, 0x90, 0xF8, 0xAF, 0x50, 0x90, 0xF8, 0xB1, 0x20, 0x90, 0xF8, ++ 0xB0, 0x30, 0x90, 0xF8, 0xA6, 0x40, 0x01, 0x35, 0x95, 0x40, 0x03, 0xFB, ++ 0x05, 0x55, 0xAD, 0xB2, 0x08, 0x21, 0x00, 0x23, 0x04, 0xF0, 0x01, 0x02, ++ 0x12, 0xFB, 0x05, 0xF2, 0x13, 0x44, 0x01, 0x39, 0x9B, 0xB2, 0x4F, 0xEA, ++ 0x54, 0x04, 0xF5, 0xD1, 0xB0, 0xF8, 0xAA, 0x20, 0x90, 0xF8, 0xB2, 0x10, ++ 0xC2, 0xF3, 0x80, 0x04, 0xC2, 0xF3, 0x40, 0x00, 0xC1, 0xF1, 0x01, 0x01, ++ 0x20, 0x44, 0x88, 0x40, 0x02, 0xF0, 0x01, 0x04, 0xC2, 0xF3, 0xC0, 0x02, ++ 0x20, 0x44, 0x8A, 0x40, 0x10, 0x44, 0x18, 0x44, 0x80, 0xB2, 0x0A, 0x28, ++ 0x28, 0xBF, 0x0A, 0x20, 0x30, 0xBC, 0x70, 0x47, 0xB0, 0xF8, 0xAA, 0x10, ++ 0x90, 0xF8, 0xB2, 0x30, 0xC1, 0xF3, 0x80, 0x02, 0xC1, 0xF3, 0x40, 0x00, ++ 0xC3, 0xF1, 0x01, 0x03, 0x10, 0x44, 0x98, 0x40, 0x01, 0xF0, 0x01, 0x04, ++ 0xC1, 0xF3, 0xC0, 0x02, 0x02, 0xFA, 0x03, 0xF3, 0x20, 0x44, 0x13, 0xFA, ++ 0x80, 0xF0, 0x80, 0xB2, 0x04, 0x23, 0x41, 0xFA, 0x03, 0xF2, 0x02, 0xF0, ++ 0x01, 0x02, 0x01, 0x33, 0x10, 0x44, 0x0C, 0x2B, 0x80, 0xB2, 0xF6, 0xD1, ++ 0xD9, 0xE7, 0x90, 0xF8, 0xB1, 0x30, 0xB0, 0xF8, 0xA6, 0x20, 0x90, 0xF8, ++ 0xAF, 0x40, 0x90, 0xF8, 0xB0, 0x10, 0x58, 0x1C, 0x02, 0xF0, 0x03, 0x03, ++ 0x04, 0xFB, 0x00, 0x00, 0x01, 0x2B, 0x01, 0xFB, 0x00, 0x00, 0x1F, 0xD0, ++ 0x02, 0x2B, 0x14, 0xBF, 0x08, 0x23, 0x0A, 0x23, 0x10, 0xFB, 0x03, 0xF0, ++ 0x80, 0xB2, 0xC0, 0xE7, 0xB0, 0xF8, 0xA6, 0x20, 0x90, 0xF8, 0xAF, 0x30, ++ 0x90, 0xF8, 0xB1, 0x40, 0x90, 0xF8, 0xB0, 0x10, 0x02, 0xF0, 0x03, 0x02, ++ 0x01, 0x33, 0x01, 0x3A, 0x03, 0xFA, 0x04, 0xF0, 0x01, 0x2A, 0x8C, 0xBF, ++ 0x08, 0x23, 0x09, 0x23, 0x01, 0xFB, 0x00, 0x00, 0x10, 0xFB, 0x03, 0xF0, ++ 0x80, 0xB2, 0xA8, 0xE7, 0x09, 0x23, 0xE1, 0xE7, 0x00, 0x20, 0xA7, 0xE7, ++ 0x2D, 0xE9, 0xF8, 0x4F, 0xB0, 0xF8, 0xB4, 0x40, 0x05, 0x46, 0x00, 0x2C, ++ 0x00, 0xF0, 0xF4, 0x80, 0x04, 0xF1, 0xFF, 0x38, 0x1F, 0xFA, 0x88, 0xF1, ++ 0x01, 0xEB, 0x41, 0x03, 0x00, 0xF1, 0x0C, 0x01, 0x01, 0xEB, 0x83, 0x01, ++ 0x4F, 0xF6, 0xFF, 0x76, 0x03, 0x46, 0x00, 0x22, 0x01, 0x20, 0x5E, 0x81, ++ 0x9A, 0x80, 0xDA, 0x80, 0x1A, 0x81, 0x1A, 0x73, 0x5A, 0x73, 0x98, 0x73, ++ 0x0C, 0x33, 0x99, 0x42, 0xF5, 0xD1, 0xC1, 0x46, 0x95, 0xF8, 0xA5, 0x30, ++ 0x05, 0x2B, 0x00, 0xF2, 0xD9, 0x80, 0xDF, 0xE8, 0x03, 0xF0, 0x4E, 0x4E, ++ 0x03, 0x03, 0x8A, 0x5E, 0x95, 0xF8, 0xAD, 0x20, 0xDB, 0x02, 0x00, 0x2A, ++ 0x00, 0xF0, 0xC7, 0x80, 0x99, 0xB2, 0x95, 0xF8, 0xB0, 0x20, 0x69, 0x81, ++ 0xA9, 0x18, 0x95, 0xF8, 0xB1, 0x60, 0x91, 0xF8, 0xA6, 0x70, 0x95, 0xF8, ++ 0xAF, 0x00, 0x43, 0xEA, 0x46, 0x23, 0xB7, 0xFA, 0x87, 0xF7, 0xC7, 0xF1, ++ 0x1F, 0x07, 0x43, 0xEA, 0xC0, 0x13, 0xFF, 0xB2, 0x43, 0xEA, 0xC2, 0x03, ++ 0x3B, 0x43, 0x9F, 0xB2, 0x09, 0xEB, 0x49, 0x09, 0x05, 0xEB, 0x89, 0x03, ++ 0x01, 0x26, 0x46, 0x45, 0x5F, 0x81, 0x80, 0xF2, 0x9B, 0x80, 0x28, 0x46, ++ 0xFF, 0xF7, 0x7E, 0xFA, 0xB5, 0xF8, 0xB4, 0x40, 0x00, 0x2C, 0x00, 0xF0, ++ 0x87, 0x80, 0x2B, 0x46, 0x00, 0x22, 0x02, 0xE0, 0xA2, 0x42, 0x00, 0xF0, ++ 0x81, 0x80, 0x59, 0x89, 0x81, 0x42, 0x02, 0xF1, 0x01, 0x02, 0x03, 0xF1, ++ 0x0C, 0x03, 0xF5, 0xD1, 0x01, 0x3C, 0xA6, 0x42, 0xE7, 0xDB, 0x00, 0x24, ++ 0xA1, 0xB2, 0x28, 0x46, 0xFE, 0xF7, 0x0A, 0xFF, 0xB5, 0xF8, 0xB4, 0x30, ++ 0x01, 0x34, 0x9C, 0x42, 0xF6, 0xD3, 0xBD, 0xE8, 0xF8, 0x8F, 0x95, 0xF8, ++ 0xAD, 0x20, 0x00, 0x2A, 0x7A, 0xD0, 0x92, 0xB2, 0x95, 0xF8, 0xB2, 0x10, ++ 0x95, 0xF8, 0xAE, 0x70, 0x6A, 0x81, 0xDB, 0x02, 0x43, 0xEA, 0x81, 0x23, ++ 0x3B, 0x43, 0x9F, 0xB2, 0xC2, 0xE7, 0x95, 0xF8, 0xAD, 0x30, 0x00, 0x2B, ++ 0x67, 0xD0, 0x95, 0xF8, 0xBC, 0x30, 0x00, 0x2B, 0x0C, 0xBF, 0x4F, 0xF4, ++ 0x28, 0x52, 0x4F, 0xF4, 0xD4, 0x42, 0x95, 0xF8, 0xB0, 0x30, 0xB5, 0xF8, ++ 0xA6, 0x60, 0x6A, 0x81, 0x5A, 0x00, 0x16, 0x41, 0x95, 0xF8, 0xAF, 0xA0, ++ 0x06, 0xF0, 0x03, 0x06, 0x1B, 0x01, 0x76, 0x00, 0x07, 0x36, 0x43, 0xEA, ++ 0xCA, 0x1A, 0x4A, 0xEA, 0x06, 0x07, 0x47, 0xF4, 0x20, 0x57, 0x39, 0x46, ++ 0x28, 0x46, 0xFF, 0xF7, 0x1B, 0xFD, 0x01, 0x3E, 0xF3, 0xB2, 0xB6, 0xB2, ++ 0x00, 0x28, 0x99, 0xD1, 0x06, 0x2B, 0xF0, 0xD1, 0x96, 0xE7, 0x95, 0xF8, ++ 0xB0, 0xA0, 0xB5, 0xF8, 0xA6, 0xB0, 0x95, 0xF8, 0xAF, 0x60, 0x95, 0xF8, ++ 0xB1, 0x30, 0x4F, 0xEA, 0x4A, 0x02, 0x4B, 0xFA, 0x02, 0xFB, 0xF6, 0x01, ++ 0x46, 0xEA, 0x43, 0x26, 0x0B, 0xF0, 0x03, 0x0B, 0x4F, 0xF4, 0x00, 0x53, ++ 0x4F, 0xEA, 0x0A, 0x1A, 0x0B, 0xF1, 0x07, 0x0B, 0x36, 0xB2, 0x6B, 0x81, ++ 0x4A, 0xEA, 0x0B, 0x07, 0x37, 0x43, 0x47, 0xF4, 0x00, 0x57, 0xBF, 0xB2, ++ 0x39, 0x46, 0x28, 0x46, 0xFF, 0xF7, 0xF0, 0xFC, 0x0B, 0xF1, 0xFF, 0x3B, ++ 0x5F, 0xFA, 0x8B, 0xF3, 0x1F, 0xFA, 0x8B, 0xFB, 0x00, 0x28, 0x7F, 0xF4, ++ 0x6B, 0xAF, 0x06, 0x2B, 0xEA, 0xD1, 0x67, 0xE7, 0x06, 0xEB, 0x46, 0x03, ++ 0x01, 0x36, 0x05, 0xEB, 0x83, 0x03, 0xB6, 0xB2, 0x04, 0xF1, 0xFF, 0x38, ++ 0x46, 0x45, 0x58, 0x81, 0xFF, 0xF6, 0x65, 0xAF, 0x00, 0x2C, 0x7F, 0xF4, ++ 0x7A, 0xAF, 0xBD, 0xE8, 0xF8, 0x8F, 0x4F, 0xF4, 0x80, 0x62, 0x9C, 0xE7, ++ 0x4F, 0xF4, 0x80, 0x62, 0x82, 0xE7, 0x4F, 0xF4, 0x80, 0x61, 0x36, 0xE7, ++ 0x4F, 0xF0, 0xFF, 0x39, 0xC8, 0x46, 0x21, 0xE7, 0x00, 0x27, 0x6F, 0x81, ++ 0x46, 0xE7, 0x00, 0xBF, 0x90, 0xF8, 0xAD, 0x30, 0x0B, 0x2B, 0xF0, 0xB4, ++ 0x0C, 0xD9, 0x90, 0xF8, 0xA2, 0x20, 0x04, 0x23, 0x01, 0x24, 0x22, 0xF0, ++ 0x04, 0x02, 0x13, 0x43, 0x80, 0xF8, 0xA2, 0x30, 0x01, 0xB1, 0x0C, 0x70, ++ 0xF0, 0xBC, 0x70, 0x47, 0xB0, 0xF8, 0x88, 0x30, 0x03, 0xEB, 0x43, 0x03, ++ 0x00, 0xEB, 0x83, 0x03, 0x5B, 0x89, 0xDB, 0x12, 0x13, 0xF0, 0x06, 0x0F, ++ 0x04, 0xD1, 0x00, 0x23, 0x90, 0xF8, 0xA2, 0x20, 0x1C, 0x46, 0xE6, 0xE7, ++ 0xB0, 0xF8, 0x8A, 0x30, 0x03, 0xEB, 0x43, 0x03, 0x00, 0xEB, 0x83, 0x03, ++ 0x5B, 0x89, 0xDB, 0x12, 0x13, 0xF0, 0x06, 0x0F, 0xEF, 0xD0, 0xB0, 0xF8, ++ 0x8C, 0x30, 0x03, 0xEB, 0x43, 0x03, 0x00, 0xEB, 0x83, 0x03, 0x5B, 0x89, ++ 0xDB, 0x12, 0x13, 0xF0, 0x06, 0x0F, 0xE4, 0xD0, 0x90, 0xF8, 0xA2, 0x20, ++ 0x12, 0xF0, 0x20, 0x04, 0x20, 0xD1, 0x90, 0xF8, 0xA4, 0x30, 0x44, 0x33, ++ 0x30, 0xF8, 0x13, 0x30, 0x03, 0xEB, 0x43, 0x03, 0x00, 0xEB, 0x83, 0x05, ++ 0x6B, 0x89, 0x13, 0xF4, 0x00, 0x5F, 0x4F, 0xEA, 0xD3, 0x27, 0xC3, 0xF3, ++ 0xC2, 0x26, 0x12, 0xD1, 0x17, 0xF0, 0x06, 0x0F, 0x1D, 0xD1, 0x03, 0xF0, ++ 0x7F, 0x03, 0x02, 0x2B, 0x15, 0xD9, 0x2D, 0x89, 0x40, 0xF2, 0x8E, 0x23, ++ 0x9D, 0x42, 0x86, 0xBF, 0x01, 0x24, 0x04, 0x23, 0x00, 0x23, 0xAA, 0xE7, ++ 0x04, 0x23, 0x01, 0x24, 0xA7, 0xE7, 0x07, 0x2E, 0x07, 0xD0, 0x03, 0xF0, ++ 0x0F, 0x06, 0xC3, 0xF3, 0x02, 0x13, 0x02, 0x2E, 0xEB, 0xD8, 0x00, 0x2B, ++ 0xE9, 0xD1, 0x2D, 0x89, 0x41, 0xF6, 0x98, 0x13, 0xE8, 0xE7, 0x03, 0xF0, ++ 0x07, 0x06, 0xC3, 0xF3, 0xC1, 0x03, 0xF2, 0xE7, 0xF8, 0xB5, 0x90, 0xF8, ++ 0xA2, 0x60, 0x16, 0xF0, 0x10, 0x05, 0x04, 0x46, 0x35, 0xD0, 0xB0, 0xF8, ++ 0xB4, 0x00, 0x00, 0x28, 0x5F, 0xD0, 0xB4, 0xF8, 0xBA, 0x70, 0x00, 0x23, ++ 0x02, 0xE0, 0x82, 0x42, 0xCB, 0xB2, 0x46, 0xD2, 0x03, 0xEB, 0x43, 0x02, ++ 0x04, 0xEB, 0x82, 0x02, 0x59, 0x1C, 0x55, 0x89, 0xBD, 0x42, 0xCA, 0xB2, ++ 0xF3, 0xD1, 0x9A, 0xB2, 0xA4, 0xF8, 0x88, 0x20, 0xA4, 0xF8, 0x8A, 0x20, ++ 0xA4, 0xF8, 0x8C, 0x20, 0x01, 0x38, 0x80, 0xB2, 0x04, 0xF1, 0x0C, 0x03, ++ 0x00, 0xEB, 0x40, 0x00, 0x03, 0xEB, 0x80, 0x00, 0x00, 0x22, 0x23, 0x46, ++ 0x9A, 0x80, 0xDA, 0x80, 0x0C, 0x33, 0x98, 0x42, 0xFA, 0xD1, 0x26, 0xF0, ++ 0x30, 0x06, 0x46, 0xF0, 0x20, 0x06, 0x00, 0x23, 0x84, 0xF8, 0xA2, 0x60, ++ 0x84, 0xF8, 0x9B, 0x30, 0x01, 0x25, 0x28, 0x46, 0xF8, 0xBD, 0x90, 0xF8, ++ 0x88, 0x00, 0x0C, 0x23, 0x03, 0xFB, 0x00, 0x40, 0x04, 0x30, 0xFE, 0xF7, ++ 0x73, 0xFC, 0xB4, 0xF8, 0xB4, 0x30, 0x00, 0x2B, 0xF1, 0xD0, 0x01, 0x3B, ++ 0x9A, 0xB2, 0x02, 0xEB, 0x42, 0x03, 0x04, 0xF1, 0x0C, 0x02, 0x02, 0xEB, ++ 0x83, 0x02, 0x2B, 0x46, 0xA3, 0x80, 0xE3, 0x80, 0x0C, 0x34, 0x94, 0x42, ++ 0xFA, 0xD1, 0x28, 0x46, 0xF8, 0xBD, 0xC1, 0xD1, 0x01, 0x38, 0xC3, 0xB2, ++ 0x03, 0xEB, 0x43, 0x03, 0x04, 0xEB, 0x83, 0x03, 0xC2, 0xB2, 0x00, 0x21, ++ 0x5F, 0x81, 0x19, 0x81, 0xA4, 0xF8, 0x88, 0x20, 0xA4, 0xF8, 0x8A, 0x20, ++ 0xA4, 0xF8, 0x8C, 0x20, 0xB7, 0xE7, 0xB4, 0xF8, 0xBA, 0x20, 0xA4, 0xF8, ++ 0xFE, 0x2B, 0x4F, 0xF0, 0xFF, 0x11, 0xFF, 0x22, 0xA4, 0xF8, 0xFC, 0x0B, ++ 0xC4, 0xF8, 0x88, 0x10, 0xA4, 0xF8, 0x8C, 0x20, 0xB7, 0xE7, 0x00, 0xBF, ++ 0xC2, 0x6C, 0x12, 0x69, 0xC2, 0xF3, 0x07, 0x21, 0xC2, 0xF3, 0x00, 0x42, ++ 0x0A, 0x44, 0x00, 0x23, 0x01, 0x31, 0xFE, 0xF7, 0xC9, 0xB9, 0x00, 0xBF, ++ 0x8A, 0x1A, 0x01, 0x23, 0xFE, 0xF7, 0xC4, 0xB9, 0xC3, 0x88, 0x99, 0x04, ++ 0x30, 0xB4, 0xC3, 0xF3, 0xC2, 0x22, 0x11, 0xD4, 0xD9, 0x0A, 0x11, 0xF0, ++ 0x06, 0x0F, 0x4A, 0xD1, 0x13, 0xF0, 0x7C, 0x0F, 0x03, 0xF0, 0x7F, 0x02, ++ 0x5D, 0xD1, 0xC3, 0xF3, 0x80, 0x23, 0x43, 0xEA, 0x42, 0x02, 0x3D, 0x4B, ++ 0x30, 0xBC, 0x53, 0xF8, 0x22, 0x00, 0x70, 0x47, 0x07, 0x2A, 0x37, 0xD0, ++ 0x51, 0x1F, 0x03, 0xF0, 0x0F, 0x04, 0x01, 0x29, 0x37, 0xD8, 0xDF, 0xE8, ++ 0x01, 0xF0, 0x01, 0x1B, 0xC3, 0xF3, 0x00, 0x21, 0x4A, 0x00, 0x11, 0x44, ++ 0x06, 0x22, 0x12, 0xFB, 0x04, 0x12, 0xC3, 0xF3, 0x41, 0x21, 0x0A, 0x44, ++ 0x31, 0x49, 0x51, 0xF8, 0x22, 0x00, 0xC3, 0xF3, 0xC0, 0x11, 0xC3, 0xF3, ++ 0x02, 0x12, 0xC3, 0xF3, 0x80, 0x33, 0xC8, 0x40, 0x01, 0x32, 0x30, 0xBC, ++ 0xB0, 0xFB, 0xF2, 0xF0, 0x98, 0x40, 0x70, 0x47, 0x00, 0x7A, 0x00, 0xF0, ++ 0x07, 0x00, 0x02, 0x28, 0x31, 0xD8, 0x28, 0x49, 0xC3, 0xF3, 0x41, 0x25, ++ 0x03, 0x22, 0x51, 0xF8, 0x20, 0x10, 0x12, 0xFB, 0x04, 0x52, 0xC3, 0xF3, ++ 0x02, 0x10, 0x01, 0x30, 0x51, 0xF8, 0x22, 0x30, 0xB3, 0xFB, 0xF0, 0xF0, ++ 0x30, 0xBC, 0x70, 0x47, 0x00, 0x20, 0x30, 0xBC, 0x70, 0x47, 0x03, 0xF0, ++ 0x07, 0x04, 0xC3, 0xF3, 0x40, 0x20, 0xC3, 0xF3, 0xC1, 0x11, 0x40, 0xEA, ++ 0x41, 0x01, 0x41, 0xEA, 0xC4, 0x04, 0x04, 0x2A, 0x19, 0x49, 0x14, 0xBF, ++ 0xC3, 0xF3, 0xC1, 0x03, 0xC3, 0xF3, 0x02, 0x13, 0x51, 0xF8, 0x24, 0x00, ++ 0x01, 0x33, 0x30, 0xBC, 0xB0, 0xFB, 0xF3, 0xF0, 0x70, 0x47, 0x14, 0x4B, ++ 0x04, 0x3A, 0x30, 0xBC, 0x53, 0xF8, 0x22, 0x00, 0x70, 0x47, 0xC2, 0x1E, ++ 0xC2, 0xF3, 0x46, 0x01, 0x02, 0xF0, 0xFE, 0x00, 0x08, 0x44, 0x06, 0x21, ++ 0x11, 0xFB, 0x04, 0x04, 0xC3, 0xF3, 0x41, 0x21, 0x0C, 0x44, 0x08, 0x49, ++ 0x51, 0xF8, 0x24, 0x00, 0xC3, 0xF3, 0x02, 0x13, 0x02, 0xF0, 0x01, 0x02, ++ 0x59, 0x1C, 0x30, 0xBC, 0x20, 0xFA, 0x02, 0xF3, 0xB3, 0xFB, 0xF1, 0xF0, ++ 0x70, 0x47, 0x00, 0xBF, 0x54, 0xCC, 0x15, 0x00, 0x74, 0xCC, 0x15, 0x00, ++ 0xA4, 0xD0, 0x15, 0x00, 0x44, 0xCF, 0x15, 0x00, 0x84, 0xD0, 0x15, 0x00, ++ 0x2D, 0xE9, 0xF8, 0x4F, 0xB0, 0xF8, 0x96, 0x30, 0x90, 0xF8, 0xA2, 0x80, ++ 0x90, 0xF8, 0xA5, 0x60, 0x03, 0xEB, 0x83, 0x03, 0x5B, 0x00, 0xA0, 0xF8, ++ 0x98, 0x30, 0x07, 0x46, 0x03, 0xF0, 0xB8, 0xFD, 0xB7, 0xF8, 0xB4, 0x10, ++ 0x80, 0xB2, 0xB0, 0xFB, 0xF1, 0xF3, 0x01, 0xFB, 0x13, 0x00, 0x00, 0x29, ++ 0x77, 0xD0, 0xB7, 0xF8, 0x88, 0xC0, 0x83, 0xB2, 0x08, 0xF0, 0x02, 0x08, ++ 0x00, 0x20, 0x4F, 0xF2, 0x33, 0x3E, 0x03, 0x44, 0xB3, 0xFB, 0xF1, 0xF5, ++ 0x01, 0xFB, 0x15, 0x35, 0x05, 0xEB, 0x45, 0x02, 0x92, 0x00, 0xAB, 0xB2, ++ 0x07, 0xEB, 0x02, 0x0A, 0x9C, 0x45, 0x02, 0xF1, 0x04, 0x02, 0x00, 0xF1, ++ 0x01, 0x00, 0x07, 0xEB, 0x02, 0x04, 0x4F, 0xEA, 0x45, 0x09, 0x58, 0xD0, ++ 0xBA, 0xF8, 0x08, 0x20, 0x72, 0x45, 0x54, 0xD8, 0xB8, 0xF1, 0x00, 0x0F, ++ 0x05, 0xD0, 0xBA, 0xF8, 0x0A, 0x20, 0xD2, 0x12, 0x12, 0xF0, 0x06, 0x0F, ++ 0x4B, 0xD0, 0x01, 0x2E, 0x42, 0xD9, 0x0C, 0xEB, 0x4C, 0x0C, 0x07, 0xEB, ++ 0x8C, 0x0C, 0xBC, 0xF8, 0x0A, 0x30, 0x98, 0x04, 0x4F, 0xEA, 0xD3, 0x26, ++ 0xC3, 0xF3, 0xC2, 0x22, 0x47, 0xD4, 0x16, 0xF0, 0x06, 0x06, 0x01, 0xD0, ++ 0xC3, 0xF3, 0xC1, 0x06, 0xE3, 0x88, 0x99, 0x04, 0x4F, 0xEA, 0xD3, 0x28, ++ 0xC3, 0xF3, 0xC2, 0x22, 0x36, 0xD4, 0x18, 0xF0, 0x06, 0x08, 0x01, 0xD0, ++ 0xC3, 0xF3, 0xC1, 0x08, 0xB7, 0xF8, 0x8A, 0x00, 0x00, 0xEB, 0x40, 0x00, ++ 0x07, 0xEB, 0x80, 0x00, 0xA9, 0x44, 0x04, 0x30, 0x07, 0xEB, 0x89, 0x09, ++ 0xFF, 0xF7, 0xFA, 0xFE, 0x99, 0xF8, 0x0D, 0x30, 0x82, 0x46, 0x5B, 0xBB, ++ 0xB7, 0xF8, 0x96, 0xB0, 0x20, 0x46, 0xFF, 0xF7, 0xF1, 0xFE, 0x50, 0x45, ++ 0x81, 0x46, 0x0D, 0xD3, 0x01, 0x3E, 0x46, 0x45, 0x23, 0xD2, 0x23, 0x7A, ++ 0x5B, 0x45, 0x10, 0xD3, 0x97, 0xF8, 0x9A, 0x30, 0x01, 0x33, 0xDB, 0xB2, ++ 0x02, 0x2B, 0x87, 0xF8, 0x9A, 0x30, 0x29, 0xD8, 0x01, 0x20, 0x87, 0xF8, ++ 0xA0, 0x50, 0x87, 0xF8, 0x9B, 0x00, 0xBD, 0xE8, 0xF8, 0x8F, 0x88, 0x42, ++ 0x8F, 0xD1, 0x00, 0x20, 0xBD, 0xE8, 0xF8, 0x8F, 0x07, 0x2A, 0x18, 0xD0, ++ 0xC3, 0xF3, 0x02, 0x18, 0xC8, 0xE7, 0x07, 0x2A, 0x11, 0xD0, 0xC3, 0xF3, ++ 0x02, 0x16, 0xB7, 0xE7, 0x4F, 0xF0, 0x20, 0x0B, 0xD2, 0xE7, 0xB7, 0xF8, ++ 0x8C, 0x00, 0x00, 0xEB, 0x40, 0x00, 0x07, 0xEB, 0x80, 0x00, 0x04, 0x30, ++ 0xFF, 0xF7, 0xBE, 0xFE, 0x81, 0x45, 0xDB, 0xD3, 0xCF, 0xE7, 0x00, 0x26, ++ 0xA6, 0xE7, 0x4F, 0xF0, 0x00, 0x08, 0xAF, 0xE7, 0x0F, 0x2B, 0x84, 0xBF, ++ 0x0F, 0x23, 0x87, 0xF8, 0x9A, 0x30, 0xD8, 0xE7, 0x90, 0xF8, 0xA2, 0x30, ++ 0x99, 0x06, 0x1F, 0xD4, 0x10, 0xB5, 0x90, 0xF8, 0x9B, 0x20, 0x04, 0x46, ++ 0xC2, 0xB9, 0xB0, 0xF8, 0x98, 0x20, 0x92, 0xB9, 0x5A, 0x06, 0x0B, 0xD5, ++ 0xB0, 0xF8, 0xB4, 0x20, 0x09, 0x2A, 0x03, 0xD9, 0xFF, 0xF7, 0x9E, 0xFB, ++ 0x94, 0xF8, 0xA2, 0x30, 0x23, 0xF0, 0x40, 0x03, 0x84, 0xF8, 0xA2, 0x30, ++ 0x20, 0x46, 0xBD, 0xE8, 0x10, 0x40, 0xFF, 0xF7, 0x29, 0xBF, 0x01, 0x3A, ++ 0xA0, 0xF8, 0x98, 0x20, 0x00, 0x20, 0x10, 0xBD, 0x00, 0x20, 0x70, 0x47, ++ 0x2D, 0xE9, 0xF0, 0x41, 0x29, 0x4F, 0x2A, 0x4E, 0xD7, 0xF8, 0x00, 0x80, ++ 0x4F, 0xF4, 0x1E, 0x73, 0xB8, 0xF9, 0x00, 0x20, 0x03, 0xFB, 0x00, 0x63, ++ 0x00, 0x2A, 0xD3, 0xF8, 0x4C, 0x51, 0x8A, 0xB0, 0x04, 0x46, 0x20, 0xDB, ++ 0x28, 0x46, 0xFF, 0xF7, 0xDF, 0xFB, 0xA5, 0xF8, 0xB4, 0x00, 0xB8, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0x22, 0xDB, 0x28, 0x46, 0xFF, 0xF7, 0x6A, 0xFC, ++ 0x69, 0x46, 0x28, 0x46, 0xFF, 0xF7, 0x3C, 0xF9, 0x28, 0x46, 0x00, 0x21, ++ 0xFF, 0xF7, 0x66, 0xFD, 0x4F, 0xF4, 0x1E, 0x70, 0x00, 0xFB, 0x04, 0x64, ++ 0x94, 0xF8, 0x56, 0x31, 0x43, 0xF0, 0x01, 0x03, 0x84, 0xF8, 0x56, 0x31, ++ 0x0A, 0xB0, 0xBD, 0xE8, 0xF0, 0x81, 0x00, 0x2D, 0xDC, 0xD1, 0x12, 0x49, ++ 0x12, 0x48, 0x40, 0xF6, 0xAF, 0x42, 0xF1, 0xF7, 0x03, 0xF9, 0xD7, 0xF8, ++ 0x00, 0x80, 0xD3, 0xE7, 0x40, 0xB1, 0x0A, 0x28, 0xD9, 0xD9, 0x0C, 0x49, ++ 0x0D, 0x48, 0x40, 0xF6, 0xB4, 0x42, 0xF1, 0xF7, 0xF7, 0xF8, 0xD2, 0xE7, ++ 0x08, 0x49, 0x0B, 0x48, 0x40, 0xF6, 0xB3, 0x42, 0xF1, 0xF7, 0xF0, 0xF8, ++ 0x3B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xC7, 0xDA, 0xB5, 0xF8, ++ 0xB4, 0x00, 0xE8, 0xE7, 0x38, 0x36, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x68, 0x8E, 0x15, 0x00, 0x0C, 0xCA, 0x15, 0x00, ++ 0xF4, 0xC9, 0x15, 0x00, 0x2D, 0xE9, 0xF0, 0x41, 0xDF, 0xF8, 0xBC, 0x80, ++ 0x29, 0x4D, 0xD8, 0xF8, 0x00, 0x40, 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, ++ 0x00, 0x53, 0x07, 0x46, 0xB4, 0xF9, 0x00, 0x00, 0xD3, 0xF8, 0x4C, 0x41, ++ 0x00, 0x28, 0x0D, 0x46, 0x16, 0x46, 0x20, 0xDB, 0x94, 0xF8, 0xAF, 0x30, ++ 0xAB, 0x42, 0x39, 0xD0, 0xD8, 0xF8, 0x00, 0x30, 0x84, 0xF8, 0xAF, 0x50, ++ 0xB3, 0xF9, 0x00, 0x20, 0x00, 0x2A, 0x26, 0xDB, 0x84, 0xF8, 0xB0, 0x60, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x17, 0xDB, 0x94, 0xF8, 0xA2, 0x30, ++ 0x9A, 0x06, 0x05, 0xD5, 0x63, 0xF0, 0x7F, 0x03, 0x84, 0xF8, 0xA2, 0x30, ++ 0xBD, 0xE8, 0xF0, 0x81, 0x38, 0x46, 0xBD, 0xE8, 0xF0, 0x41, 0xFF, 0xF7, ++ 0x69, 0xBF, 0x00, 0x2C, 0xDC, 0xD1, 0x11, 0x49, 0x11, 0x48, 0x40, 0xF6, ++ 0xCC, 0x42, 0xF1, 0xF7, 0x9F, 0xF8, 0xD5, 0xE7, 0x07, 0x2E, 0xE5, 0xD9, ++ 0x0C, 0x49, 0x0E, 0x48, 0x40, 0xF6, 0xD4, 0x42, 0xF1, 0xF7, 0x96, 0xF8, ++ 0xDE, 0xE7, 0x03, 0x2D, 0xD6, 0xD9, 0x08, 0x49, 0x0A, 0x48, 0x40, 0xF6, ++ 0xD2, 0x42, 0xF1, 0xF7, 0x8D, 0xF8, 0xD8, 0xF8, 0x00, 0x30, 0xCD, 0xE7, ++ 0x94, 0xF8, 0xB0, 0x30, 0xB3, 0x42, 0xC1, 0xD1, 0xD6, 0xE7, 0x00, 0xBF, ++ 0x68, 0x65, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x68, 0x8E, 0x15, 0x00, ++ 0x50, 0xCA, 0x15, 0x00, 0x34, 0xCA, 0x15, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0x4D, 0x4B, 0x8D, 0xB0, 0x1A, 0x68, 0x01, 0x90, ++ 0x04, 0x46, 0x4C, 0x48, 0xB2, 0xF9, 0x00, 0x20, 0x4F, 0xF4, 0x1E, 0x73, ++ 0x03, 0xFB, 0x04, 0x03, 0x00, 0x2A, 0xD3, 0xF8, 0x4C, 0xB1, 0x0C, 0x46, ++ 0x79, 0xDB, 0x9B, 0xF8, 0xB2, 0x20, 0xA2, 0x42, 0x72, 0xD0, 0x8B, 0xF8, ++ 0xB2, 0x40, 0x00, 0x2C, 0x6E, 0xD0, 0x9B, 0xF8, 0xA2, 0x20, 0x12, 0xF0, ++ 0x20, 0x07, 0x76, 0xD1, 0xBB, 0xF8, 0xB4, 0x90, 0xB8, 0x46, 0xB9, 0xF1, ++ 0x00, 0x0F, 0x15, 0xD1, 0x4D, 0xE0, 0x25, 0x44, 0x0C, 0xAB, 0x01, 0x37, ++ 0x0B, 0xEB, 0x85, 0x05, 0x03, 0xEB, 0x84, 0x04, 0xB8, 0xB2, 0x4F, 0xF0, ++ 0x01, 0x03, 0x81, 0x45, 0xAB, 0x73, 0xA6, 0xF8, 0x0A, 0xA0, 0xA6, 0xF8, ++ 0x08, 0x80, 0x85, 0xF8, 0x0D, 0x80, 0x44, 0xF8, 0x28, 0x8C, 0x38, 0xD9, ++ 0xBC, 0xB2, 0x04, 0xEB, 0x44, 0x06, 0x0B, 0xEB, 0x86, 0x06, 0x65, 0x00, ++ 0xB6, 0xF8, 0x0A, 0xA0, 0x50, 0x46, 0xFD, 0xF7, 0x19, 0xFF, 0x00, 0x28, ++ 0xDD, 0xD0, 0x4A, 0xF4, 0x80, 0x6A, 0xB9, 0xF1, 0x00, 0x0F, 0x16, 0xD0, ++ 0x58, 0x46, 0x4F, 0xF0, 0x00, 0x0C, 0x01, 0xE0, 0xCC, 0x45, 0xD2, 0xD0, ++ 0xB0, 0xF8, 0x0A, 0xE0, 0xD6, 0x45, 0x0C, 0xF1, 0x01, 0x0C, 0x00, 0xF1, ++ 0x0C, 0x00, 0xF5, 0xD1, 0x58, 0x46, 0xFE, 0xF7, 0x37, 0xFE, 0xBB, 0xF8, ++ 0xB4, 0x90, 0x82, 0x46, 0xB9, 0xF1, 0x00, 0x0F, 0xE8, 0xD1, 0x28, 0x19, ++ 0x0C, 0xAB, 0x0B, 0xEB, 0x80, 0x00, 0x03, 0xEB, 0x84, 0x04, 0x01, 0x25, ++ 0x85, 0x73, 0xA6, 0xF8, 0x0A, 0xA0, 0xA6, 0xF8, 0x08, 0x90, 0x80, 0xF8, ++ 0x0D, 0x90, 0x44, 0xF8, 0x28, 0x9C, 0x02, 0xA9, 0x58, 0x46, 0xFE, 0xF7, ++ 0xCF, 0xFF, 0x02, 0xA9, 0x58, 0x46, 0xFF, 0xF7, 0x1B, 0xF8, 0x01, 0x9A, ++ 0x11, 0x46, 0x10, 0x4A, 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, 0x01, 0x29, ++ 0x99, 0xF8, 0x56, 0x31, 0x43, 0xF0, 0x01, 0x03, 0x89, 0xF8, 0x56, 0x31, ++ 0x0D, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xBB, 0xF1, 0x00, 0x0F, 0x82, 0xD1, ++ 0x08, 0x49, 0x09, 0x48, 0x40, 0xF6, 0xEA, 0x42, 0xF0, 0xF7, 0xE2, 0xFF, ++ 0x7B, 0xE7, 0x62, 0xF0, 0x7F, 0x02, 0x8B, 0xF8, 0xA2, 0x20, 0x0D, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x8F, 0x38, 0x36, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x68, 0x8E, 0x15, 0x00, 0xB0, 0xF8, 0x54, 0x21, ++ 0x03, 0x29, 0x9A, 0xBF, 0x02, 0xF4, 0x80, 0x62, 0x12, 0xB2, 0x00, 0x22, ++ 0x10, 0xB4, 0x42, 0xEA, 0x01, 0x03, 0xD0, 0xF8, 0x48, 0x41, 0x43, 0xF0, ++ 0x00, 0x53, 0xC4, 0xE9, 0x05, 0x33, 0xC4, 0xE9, 0x07, 0x33, 0x5D, 0xF8, ++ 0x04, 0x4B, 0x70, 0x47, 0x90, 0xF8, 0xA5, 0x30, 0xC1, 0xF3, 0xC2, 0x22, ++ 0x93, 0x42, 0x13, 0xD3, 0x05, 0x2B, 0x70, 0xB5, 0x4F, 0xEA, 0xD1, 0x24, ++ 0x11, 0xD0, 0x04, 0x2B, 0x29, 0xD0, 0x02, 0x3B, 0x01, 0x2B, 0x12, 0xD8, ++ 0x14, 0xF0, 0x06, 0x03, 0x04, 0xF0, 0x06, 0x05, 0x26, 0xD1, 0x90, 0xF8, ++ 0xAD, 0x20, 0x03, 0x2A, 0x1B, 0xD8, 0x0D, 0xE0, 0x00, 0x23, 0x18, 0x46, ++ 0x70, 0x47, 0x05, 0x2A, 0x03, 0xD0, 0x90, 0xF8, 0xAD, 0x30, 0x03, 0x2B, ++ 0x15, 0xD8, 0x14, 0xF0, 0x06, 0x0F, 0x04, 0xF0, 0x06, 0x05, 0x13, 0xD1, ++ 0x4A, 0x05, 0xC1, 0xF3, 0x80, 0x23, 0x03, 0xD4, 0x90, 0xF8, 0xB2, 0x20, ++ 0x01, 0x2A, 0x04, 0xD0, 0xFF, 0xF7, 0x9A, 0xF8, 0x03, 0x1E, 0x18, 0xBF, ++ 0x01, 0x23, 0x18, 0x46, 0x70, 0xBD, 0x04, 0x2A, 0x1A, 0xD0, 0x00, 0x23, ++ 0x18, 0x46, 0x70, 0xBD, 0x04, 0x2A, 0x1A, 0xD9, 0x90, 0xF8, 0xAF, 0x60, ++ 0xC1, 0xF3, 0xC1, 0x13, 0x9E, 0x42, 0xF4, 0xD3, 0x63, 0x07, 0x08, 0xD5, ++ 0x07, 0x2A, 0xE7, 0xD0, 0xC1, 0xF3, 0x02, 0x13, 0x90, 0xF8, 0xB0, 0x20, ++ 0x9A, 0x42, 0xEA, 0xD3, 0xE0, 0xE7, 0x00, 0x2D, 0xDE, 0xD0, 0xC1, 0xF3, ++ 0xC1, 0x03, 0xF5, 0xE7, 0x14, 0xF0, 0x06, 0x0F, 0x04, 0xF0, 0x06, 0x05, ++ 0xCE, 0xD0, 0x8E, 0x05, 0xE2, 0xD5, 0x90, 0xF8, 0xB1, 0x30, 0x00, 0x2B, ++ 0xD5, 0xD0, 0xDD, 0xE7, 0x01, 0xEB, 0x41, 0x01, 0x00, 0xEB, 0x81, 0x03, ++ 0x2D, 0xE9, 0xF0, 0x47, 0x1F, 0x89, 0x80, 0x46, 0x41, 0xF6, 0x98, 0x10, ++ 0x87, 0x42, 0x38, 0xD9, 0xB3, 0xF8, 0x0A, 0x90, 0xD8, 0xF8, 0x94, 0xA0, ++ 0x48, 0x46, 0x15, 0x46, 0x8C, 0x00, 0xFD, 0xF7, 0x2F, 0xFE, 0x08, 0xB3, ++ 0x00, 0x26, 0x20, 0x1D, 0x40, 0x44, 0xFF, 0xF7, 0x8D, 0xFC, 0x2D, 0x4A, ++ 0x4F, 0xF4, 0x7A, 0x73, 0x30, 0x44, 0x03, 0xFB, 0x07, 0xF3, 0xB3, 0xFB, ++ 0xF0, 0xF3, 0x02, 0xFB, 0x03, 0xF3, 0x18, 0x0C, 0x75, 0xB1, 0x43, 0xF2, ++ 0x32, 0x33, 0x9F, 0x42, 0x1C, 0xD9, 0x44, 0xF6, 0xCB, 0x43, 0x9F, 0x42, ++ 0x21, 0xD8, 0x24, 0x4B, 0x5A, 0x78, 0xA2, 0xFB, 0x00, 0x34, 0xD8, 0x09, ++ 0x40, 0xEA, 0x44, 0x60, 0xBD, 0xE8, 0xF0, 0x87, 0x20, 0x4E, 0x21, 0x4B, ++ 0xC9, 0xF3, 0xC2, 0x29, 0x4F, 0xEA, 0x1A, 0x4A, 0xB9, 0xF1, 0x06, 0x0F, ++ 0x08, 0xBF, 0x1E, 0x46, 0xB6, 0xFB, 0xFA, 0xF6, 0xD1, 0xE7, 0x00, 0x20, ++ 0xBD, 0xE8, 0xF0, 0x87, 0x17, 0x4B, 0x1A, 0x78, 0xA2, 0xFB, 0x00, 0x34, ++ 0xD8, 0x09, 0x40, 0xEA, 0x44, 0x60, 0xBD, 0xE8, 0xF0, 0x87, 0x46, 0xF2, ++ 0x65, 0x63, 0x9F, 0x42, 0x0A, 0xD9, 0xB7, 0xF5, 0x00, 0x4F, 0x0F, 0xD2, ++ 0x0F, 0x4B, 0xDA, 0x78, 0xA2, 0xFB, 0x00, 0x34, 0xD8, 0x09, 0x40, 0xEA, ++ 0x44, 0x60, 0xD5, 0xE7, 0x0B, 0x4B, 0x9A, 0x78, 0xA2, 0xFB, 0x00, 0x34, ++ 0xD8, 0x09, 0x40, 0xEA, 0x44, 0x60, 0xCD, 0xE7, 0x49, 0xF6, 0x98, 0x13, ++ 0x9F, 0x42, 0x06, 0x4B, 0x94, 0xBF, 0x1A, 0x79, 0x5A, 0x79, 0xA2, 0xFB, ++ 0x00, 0x34, 0xD8, 0x09, 0x40, 0xEA, 0x44, 0x60, 0xC0, 0xE7, 0x00, 0xBF, ++ 0xB0, 0xE2, 0x0D, 0x00, 0x54, 0x25, 0x17, 0x00, 0x90, 0x53, 0x03, 0x00, ++ 0x10, 0x09, 0x05, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, 0x8F, 0xB0, 0x00, 0xF1, ++ 0x88, 0x09, 0x02, 0xAD, 0x01, 0x91, 0x04, 0x46, 0x4A, 0x46, 0x07, 0x46, ++ 0x00, 0xF1, 0x90, 0x06, 0x29, 0x46, 0x32, 0xF8, 0x02, 0x3B, 0x03, 0xEB, ++ 0x43, 0x03, 0x04, 0xEB, 0x83, 0x03, 0xB2, 0x42, 0x5B, 0x89, 0x21, 0xF8, ++ 0x02, 0x3B, 0xF4, 0xD1, 0xB4, 0xF8, 0x92, 0x10, 0x71, 0xB1, 0xD4, 0xF8, ++ 0x94, 0x20, 0xB4, 0xF8, 0x90, 0x30, 0x02, 0xEB, 0x42, 0x02, 0x1B, 0x04, ++ 0x93, 0xFB, 0xF1, 0xF3, 0x13, 0x44, 0xC3, 0xF3, 0x98, 0x03, 0x00, 0x22, ++ 0xC4, 0xE9, 0x24, 0x23, 0x04, 0xF1, 0x7C, 0x00, 0xFE, 0xF7, 0x2A, 0xF8, ++ 0xB4, 0xF8, 0xB4, 0x00, 0x00, 0x21, 0xA4, 0xF8, 0x7C, 0x10, 0xA4, 0xF8, ++ 0x7E, 0x10, 0x84, 0xF8, 0x9A, 0x10, 0x00, 0x28, 0x74, 0xD0, 0x01, 0x38, ++ 0x05, 0xAB, 0x80, 0xB2, 0x0D, 0xF1, 0x10, 0x0A, 0x03, 0xEB, 0x80, 0x00, ++ 0x52, 0x46, 0x23, 0x46, 0x4F, 0xF0, 0x01, 0x0C, 0x42, 0xF8, 0x04, 0x1B, ++ 0x82, 0x42, 0x83, 0xF8, 0x0E, 0xC0, 0x03, 0xF1, 0x0C, 0x03, 0xF7, 0xD1, ++ 0xB4, 0xF8, 0xBA, 0x20, 0x4F, 0xF6, 0xFF, 0x73, 0x9A, 0x42, 0x14, 0xD0, ++ 0x32, 0x4B, 0x20, 0x46, 0xD3, 0xF8, 0x6C, 0x32, 0x98, 0x47, 0x39, 0xF8, ++ 0x02, 0x3B, 0x35, 0xF8, 0x02, 0x2B, 0x03, 0xEB, 0x43, 0x03, 0x04, 0xEB, ++ 0x83, 0x03, 0x5B, 0x89, 0x93, 0x42, 0x47, 0xD1, 0xB1, 0x45, 0xF2, 0xD1, ++ 0x0F, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x4F, 0xF0, 0x00, 0x08, 0x1F, 0xFA, ++ 0x88, 0xFB, 0x0B, 0xEB, 0x4B, 0x00, 0x04, 0xEB, 0x80, 0x00, 0x04, 0x30, ++ 0xFD, 0xF7, 0xE6, 0xFF, 0x01, 0x22, 0x5F, 0xFA, 0x88, 0xF1, 0x20, 0x46, ++ 0x90, 0x44, 0xFF, 0xF7, 0x09, 0xFF, 0xB4, 0xF8, 0xB4, 0x10, 0x0E, 0xAB, ++ 0x03, 0xEB, 0x8B, 0x0B, 0x1F, 0xFA, 0x88, 0xF2, 0x91, 0x42, 0x4B, 0xF8, ++ 0x28, 0x0C, 0xE4, 0xD8, 0x51, 0x46, 0x20, 0x46, 0xFE, 0xF7, 0x26, 0xFE, ++ 0x51, 0x46, 0x20, 0x46, 0xFE, 0xF7, 0x72, 0xFE, 0x01, 0x9B, 0xCB, 0xB9, ++ 0x94, 0xF8, 0xA2, 0x20, 0xB4, 0xF8, 0xB4, 0x30, 0x42, 0xF0, 0x40, 0x02, ++ 0x84, 0xF8, 0xA2, 0x20, 0x83, 0xB1, 0x01, 0x3B, 0x9B, 0xB2, 0x03, 0xEB, ++ 0x43, 0x02, 0xDD, 0xF8, 0x04, 0x80, 0x04, 0xF1, 0x0C, 0x03, 0x03, 0xEB, ++ 0x82, 0x03, 0xA7, 0xF8, 0x04, 0x80, 0xA7, 0xF8, 0x06, 0x80, 0x0C, 0x37, ++ 0x9F, 0x42, 0xF8, 0xD1, 0x00, 0x20, 0xAC, 0xE7, 0x01, 0x20, 0x0F, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x8F, 0xB4, 0xF8, 0xBA, 0x20, 0x4F, 0xF6, 0xFF, 0x73, ++ 0x9A, 0x42, 0x9D, 0xD1, 0x0D, 0xF1, 0x10, 0x0A, 0xCC, 0xE7, 0x00, 0xBF, ++ 0x88, 0x1A, 0x17, 0x00, 0x38, 0xB5, 0x23, 0x4B, 0x23, 0x4A, 0x1B, 0x68, ++ 0x4F, 0xF4, 0x1E, 0x71, 0xB3, 0xF9, 0x00, 0x30, 0x01, 0xFB, 0x00, 0x20, ++ 0x00, 0x2B, 0xD0, 0xF8, 0x4C, 0x41, 0x2F, 0xDB, 0x20, 0x46, 0xFF, 0xF7, ++ 0x5D, 0xF9, 0xB4, 0xF8, 0xB4, 0x30, 0x59, 0x1E, 0x9A, 0x1E, 0x21, 0xEA, ++ 0xE1, 0x71, 0x03, 0x3B, 0x22, 0xEA, 0xE2, 0x72, 0x23, 0xEA, 0xE3, 0x73, ++ 0x00, 0x25, 0x4F, 0xF4, 0x80, 0x30, 0xA4, 0xF8, 0x88, 0x10, 0x4F, 0xF6, ++ 0xFF, 0x71, 0xA4, 0xF8, 0x8A, 0x20, 0xA4, 0xF8, 0x8C, 0x30, 0xC4, 0xF8, ++ 0x94, 0x00, 0xA4, 0xF8, 0xBA, 0x10, 0xA4, 0xF8, 0x8E, 0x50, 0x84, 0xF8, ++ 0xA2, 0x50, 0x01, 0x21, 0x20, 0x46, 0xFF, 0xF7, 0x13, 0xFF, 0x94, 0xF8, ++ 0xB4, 0x30, 0x84, 0xF8, 0x9B, 0x50, 0x04, 0x3B, 0x05, 0x22, 0x84, 0xF8, ++ 0xA0, 0x30, 0xA4, 0xF8, 0x98, 0x20, 0x38, 0xBD, 0x00, 0x2C, 0xCD, 0xD1, ++ 0x05, 0x49, 0x06, 0x48, 0x40, 0xF6, 0x76, 0x02, 0xF0, 0xF7, 0xDE, 0xFD, ++ 0xC6, 0xE7, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x68, 0x8E, 0x15, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, ++ 0xDF, 0xF8, 0xC4, 0xA3, 0x90, 0xF8, 0x23, 0x70, 0xDA, 0xF8, 0x00, 0x30, ++ 0xD0, 0xF8, 0x48, 0x81, 0xB3, 0xF9, 0x00, 0x30, 0x8B, 0xB0, 0x07, 0xF1, ++ 0x10, 0x02, 0xD2, 0xB2, 0x00, 0x2B, 0x04, 0x46, 0x06, 0x92, 0xC0, 0xF2, ++ 0xA9, 0x81, 0xDA, 0x4D, 0x07, 0xEB, 0x47, 0x03, 0x05, 0xEB, 0x83, 0x1B, ++ 0xC4, 0xF8, 0x4C, 0xB1, 0x9B, 0x01, 0x04, 0x93, 0xCD, 0xF7, 0xB4, 0xF9, ++ 0x83, 0x03, 0x05, 0x93, 0xCD, 0xF7, 0xB0, 0xF9, 0x4F, 0xF0, 0x01, 0x09, ++ 0x01, 0x30, 0x09, 0xFA, 0x00, 0xF9, 0x00, 0x21, 0x58, 0x46, 0xC0, 0x22, ++ 0xCC, 0xF7, 0xBE, 0xF8, 0x61, 0x68, 0x11, 0xF0, 0x02, 0x01, 0x09, 0xF1, ++ 0xFF, 0x39, 0x00, 0xF0, 0x9D, 0x80, 0x00, 0x21, 0x04, 0xF1, 0xB8, 0x00, ++ 0xF3, 0xF7, 0xB4, 0xFB, 0x63, 0x68, 0xAB, 0xF8, 0xAA, 0x00, 0x98, 0x06, ++ 0x4F, 0xEA, 0x47, 0x06, 0x00, 0xF1, 0x30, 0x82, 0x58, 0x07, 0x40, 0xF1, ++ 0xA3, 0x81, 0xC3, 0x4B, 0x07, 0x93, 0x04, 0x23, 0xB4, 0xF8, 0xEC, 0x00, ++ 0x8B, 0xF8, 0xA5, 0x30, 0xCD, 0xF8, 0x24, 0xB0, 0xF3, 0xF7, 0xBA, 0xFA, ++ 0x07, 0x9A, 0x03, 0x46, 0x10, 0x8F, 0x08, 0x93, 0xF3, 0xF7, 0xB4, 0xFA, ++ 0x08, 0x9B, 0x09, 0x9A, 0x98, 0x42, 0x28, 0xBF, 0x18, 0x46, 0xDA, 0xF8, ++ 0x00, 0x30, 0x82, 0xF8, 0xB0, 0x00, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0xC0, 0xF2, 0xC0, 0x83, 0x07, 0x9B, 0xB4, 0xF8, 0xEC, 0x00, 0x19, 0x8F, ++ 0xF3, 0xF7, 0xCA, 0xFB, 0xF2, 0x19, 0x05, 0xEB, 0x82, 0x12, 0x03, 0x46, ++ 0xB4, 0xF8, 0xEC, 0x00, 0xA2, 0xF8, 0xA6, 0x30, 0x09, 0x92, 0xF3, 0xF7, ++ 0x7D, 0xFA, 0x07, 0x9A, 0x03, 0x46, 0x10, 0x8F, 0x08, 0x93, 0xF3, 0xF7, ++ 0x77, 0xFA, 0x08, 0x9B, 0x09, 0x9A, 0x98, 0x42, 0x28, 0xBF, 0x18, 0x46, ++ 0xDA, 0xF8, 0x00, 0x30, 0x82, 0xF8, 0xAC, 0x00, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0xC0, 0xF2, 0x91, 0x83, 0xF3, 0x19, 0x05, 0xEB, 0x83, 0x13, ++ 0x08, 0x93, 0xB3, 0xF8, 0xAA, 0x00, 0x20, 0xF4, 0x7F, 0x60, 0x80, 0xB2, ++ 0xA3, 0xF8, 0xAA, 0x00, 0xF3, 0xF7, 0x96, 0xFA, 0x08, 0x9B, 0xDA, 0xF8, ++ 0x00, 0x20, 0x83, 0xF8, 0xAD, 0x00, 0xB2, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0xC0, 0xF2, 0x6D, 0x83, 0xF3, 0x19, 0x05, 0xEB, 0x83, 0x13, 0x08, 0x93, ++ 0xB3, 0xF8, 0xAA, 0x00, 0xF3, 0xF7, 0x92, 0xFA, 0x08, 0x9B, 0xDA, 0xF8, ++ 0x00, 0x20, 0x83, 0xF8, 0xAE, 0x00, 0xB2, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0xC0, 0xF2, 0x4E, 0x83, 0xB4, 0xF8, 0x54, 0x21, 0xF3, 0x19, 0x05, 0xEB, ++ 0x83, 0x13, 0xC2, 0xF3, 0x80, 0x22, 0x83, 0xF8, 0xB2, 0x20, 0xCD, 0xF7, ++ 0xD1, 0xF8, 0x00, 0x28, 0x40, 0xF0, 0x04, 0x83, 0xD4, 0xF8, 0xE8, 0x30, ++ 0x03, 0xF0, 0x03, 0x03, 0x01, 0x2B, 0x00, 0xF0, 0xD4, 0x83, 0x02, 0x2B, ++ 0x00, 0xF0, 0xD9, 0x83, 0xF3, 0x19, 0x05, 0xEB, 0x83, 0x13, 0x40, 0xF6, ++ 0xED, 0x62, 0xA3, 0xF8, 0xB6, 0x20, 0x88, 0xE1, 0x04, 0xF1, 0xB8, 0x00, ++ 0xF3, 0xF7, 0x18, 0xFB, 0x07, 0xEB, 0x47, 0x03, 0x05, 0xEB, 0x83, 0x13, ++ 0x07, 0x93, 0xA3, 0xF8, 0xAA, 0x00, 0xF3, 0xF7, 0x4D, 0xFA, 0x07, 0x9B, ++ 0xDA, 0xF8, 0x00, 0x20, 0x83, 0xF8, 0xAD, 0x00, 0xB2, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0x4F, 0xEA, 0x47, 0x06, 0xC0, 0xF2, 0xBC, 0x80, 0xF3, 0x19, ++ 0x05, 0xEB, 0x83, 0x13, 0x07, 0x93, 0xB3, 0xF8, 0xAA, 0x00, 0xF3, 0xF7, ++ 0x47, 0xFA, 0x07, 0x9B, 0xDA, 0xF8, 0x00, 0x20, 0x83, 0xF8, 0xAE, 0x00, ++ 0xB2, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xC0, 0xF2, 0x9E, 0x80, 0xF3, 0x19, ++ 0x05, 0xEB, 0x83, 0x13, 0xFF, 0x21, 0x83, 0xF8, 0xAC, 0x10, 0x94, 0xF8, ++ 0x2D, 0x11, 0x83, 0xF8, 0xAF, 0x10, 0xB2, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0xC0, 0xF2, 0x83, 0x80, 0xB4, 0xF8, 0x54, 0x11, 0xF3, 0x19, 0x05, 0xEB, ++ 0x83, 0x13, 0xC1, 0xF3, 0x80, 0x21, 0x83, 0xF8, 0xB2, 0x10, 0x58, 0x46, ++ 0x07, 0x92, 0xFE, 0xF7, 0x71, 0xFF, 0xF3, 0x19, 0x05, 0xEB, 0x83, 0x13, ++ 0x07, 0x9A, 0xA3, 0xF8, 0xB4, 0x00, 0xB2, 0xF9, 0x00, 0x20, 0x00, 0x2A, ++ 0xC0, 0xF2, 0x8D, 0x80, 0x3E, 0x44, 0x05, 0xEB, 0x86, 0x1A, 0x94, 0xF8, ++ 0x23, 0x30, 0x9A, 0xF8, 0xAF, 0x70, 0x9A, 0xF8, 0xB1, 0x00, 0x9A, 0xF8, ++ 0xB2, 0x10, 0x9A, 0xF8, 0xA5, 0x20, 0xCD, 0xE9, 0x02, 0x07, 0xCD, 0xE9, ++ 0x00, 0x21, 0x4F, 0xF4, 0x80, 0x50, 0x4B, 0x4A, 0x4B, 0x49, 0xF0, 0xF7, ++ 0x6F, 0xFA, 0xBA, 0xF8, 0xB4, 0x00, 0x9A, 0xF8, 0xAE, 0x10, 0x9A, 0xF8, ++ 0xAD, 0x20, 0x9A, 0xF8, 0xAC, 0x30, 0xCD, 0xE9, 0x02, 0x10, 0xCD, 0xE9, ++ 0x00, 0x32, 0x45, 0x49, 0x42, 0x4A, 0x9A, 0xF8, 0xB0, 0x30, 0x4F, 0xF4, ++ 0x80, 0x50, 0xF0, 0xF7, 0x5B, 0xFA, 0x94, 0xF8, 0x23, 0x00, 0xFF, 0xF7, ++ 0x5D, 0xFE, 0x04, 0x99, 0x88, 0x31, 0xB0, 0x01, 0x29, 0x44, 0x08, 0xF1, ++ 0x14, 0x02, 0x08, 0xF1, 0x24, 0x07, 0x31, 0xF8, 0x02, 0x3B, 0xDB, 0xB2, ++ 0x03, 0xEB, 0x43, 0x03, 0x00, 0xEB, 0x83, 0x03, 0x2B, 0x44, 0x5B, 0x89, ++ 0x43, 0xF0, 0x80, 0x43, 0x42, 0xF8, 0x04, 0x3B, 0x97, 0x42, 0xF0, 0xD1, ++ 0x58, 0x46, 0x00, 0x21, 0xFF, 0xF7, 0xB4, 0xF8, 0x32, 0x4A, 0x06, 0x99, ++ 0x12, 0x69, 0xD4, 0xF8, 0x48, 0x31, 0x31, 0x4F, 0x31, 0x48, 0xB6, 0x01, ++ 0x89, 0x02, 0xAA, 0x51, 0xA2, 0x69, 0x05, 0x9D, 0xC8, 0xF8, 0x0C, 0x10, ++ 0x4F, 0xF4, 0x08, 0x51, 0xC8, 0xE9, 0x01, 0x59, 0xC8, 0xF8, 0x00, 0x70, ++ 0xC8, 0xF8, 0x10, 0x00, 0xC3, 0xE9, 0x0D, 0x12, 0x94, 0xF8, 0x56, 0x31, ++ 0x43, 0xF0, 0x11, 0x03, 0x84, 0xF8, 0x56, 0x31, 0x0B, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x8F, 0x00, 0x29, 0x3F, 0xF4, 0x7A, 0xAF, 0x40, 0xF6, 0x21, 0x42, ++ 0x22, 0x49, 0x23, 0x48, 0xF0, 0xF7, 0x3C, 0xFC, 0xDA, 0xF8, 0x00, 0x20, ++ 0x70, 0xE7, 0x0B, 0x28, 0x7F, 0xF6, 0x5F, 0xAF, 0x40, 0xF6, 0x1E, 0x42, ++ 0x1C, 0x49, 0x1E, 0x48, 0xF0, 0xF7, 0x30, 0xFC, 0xDA, 0xF8, 0x00, 0x20, ++ 0x55, 0xE7, 0x0B, 0x28, 0x7F, 0xF6, 0x41, 0xAF, 0x17, 0x49, 0x1A, 0x48, ++ 0x40, 0xF6, 0x1C, 0x42, 0xF0, 0xF7, 0x24, 0xFC, 0x39, 0xE7, 0x00, 0x28, ++ 0x00, 0xF0, 0xFE, 0x81, 0x0A, 0x28, 0x7F, 0xF6, 0x6D, 0xAF, 0x11, 0x49, ++ 0x14, 0x48, 0x40, 0xF6, 0x28, 0x42, 0xF0, 0xF7, 0x17, 0xFC, 0x65, 0xE7, ++ 0x09, 0x2F, 0x7F, 0xF6, 0x54, 0xAE, 0x0C, 0x49, 0x10, 0x48, 0x40, 0xF6, ++ 0xEB, 0x22, 0xF0, 0xF7, 0x0D, 0xFC, 0x94, 0xF8, 0x23, 0x70, 0x4A, 0xE6, ++ 0xF4, 0xE7, 0x17, 0x00, 0xE4, 0xB8, 0x17, 0x00, 0x4C, 0xCC, 0x15, 0x00, ++ 0xC4, 0xCB, 0x15, 0x00, 0x08, 0xCC, 0x15, 0x00, 0x00, 0x10, 0x50, 0x40, ++ 0x1E, 0xAB, 0xDC, 0xBA, 0x04, 0x07, 0xFF, 0xFF, 0x70, 0x79, 0x15, 0x00, ++ 0xA8, 0xCB, 0x15, 0x00, 0x84, 0xCB, 0x15, 0x00, 0x60, 0xCB, 0x15, 0x00, ++ 0x0C, 0xCA, 0x15, 0x00, 0x64, 0xCA, 0x15, 0x00, 0x38, 0x36, 0x17, 0x00, ++ 0x04, 0xF1, 0xCB, 0x03, 0x02, 0x21, 0x18, 0x46, 0x8B, 0xF8, 0xA5, 0x10, ++ 0x09, 0x93, 0xCD, 0xF8, 0x20, 0xB0, 0xF3, 0xF7, 0x2B, 0xF9, 0x01, 0x46, ++ 0xD9, 0x48, 0x07, 0x91, 0xF3, 0xF7, 0x26, 0xF9, 0x07, 0x99, 0x08, 0x9A, ++ 0x09, 0x9B, 0x88, 0x42, 0x28, 0xBF, 0x08, 0x46, 0xDA, 0xF8, 0x00, 0x10, ++ 0x82, 0xF8, 0xB0, 0x00, 0xB1, 0xF9, 0x00, 0x20, 0x00, 0x2A, 0xC0, 0xF2, ++ 0x41, 0x82, 0x04, 0x9A, 0x02, 0xF1, 0xA6, 0x00, 0x19, 0x46, 0x04, 0x22, ++ 0x28, 0x44, 0x02, 0xF0, 0x6B, 0xFE, 0xF3, 0x19, 0x05, 0xEB, 0x83, 0x13, ++ 0xFF, 0x22, 0xB3, 0xF8, 0xAA, 0x00, 0x83, 0xF8, 0xA6, 0x20, 0x20, 0xF4, ++ 0x7F, 0x60, 0x07, 0x22, 0x80, 0xB2, 0x83, 0xF8, 0xAC, 0x20, 0xA3, 0xF8, ++ 0xAA, 0x00, 0x07, 0x93, 0xF3, 0xF7, 0x0A, 0xF9, 0x07, 0x9B, 0xDA, 0xF8, ++ 0x00, 0x20, 0x83, 0xF8, 0xAD, 0x00, 0xB2, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0xC0, 0xF2, 0x0F, 0x82, 0xF3, 0x19, 0x05, 0xEB, 0x83, 0x13, 0x07, 0x93, ++ 0xB3, 0xF8, 0xAA, 0x00, 0xF3, 0xF7, 0x06, 0xF9, 0x07, 0x9B, 0xDA, 0xF8, ++ 0x00, 0x20, 0x83, 0xF8, 0xAE, 0x00, 0xB2, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0xC0, 0xF2, 0xF0, 0x81, 0xB4, 0xF8, 0x54, 0x21, 0xF3, 0x19, 0x05, 0xEB, ++ 0x83, 0x13, 0xC2, 0xF3, 0x80, 0x22, 0x83, 0xF8, 0xB2, 0x20, 0xCC, 0xF7, ++ 0x45, 0xFF, 0x00, 0x28, 0x40, 0xF0, 0x88, 0x81, 0xB4, 0xF8, 0xC8, 0x30, ++ 0x13, 0xF4, 0x00, 0x6F, 0x06, 0xEB, 0x07, 0x03, 0x05, 0xEB, 0x83, 0x13, ++ 0x14, 0xBF, 0x40, 0xF6, 0xB5, 0x72, 0x40, 0xF6, 0xFF, 0x62, 0xA3, 0xF8, ++ 0xB6, 0x20, 0xF1, 0x19, 0x05, 0xEB, 0x81, 0x11, 0x94, 0xF8, 0x2D, 0x31, ++ 0xDA, 0xF8, 0x00, 0x20, 0x81, 0xF8, 0xAF, 0x30, 0xB2, 0xF9, 0x00, 0x10, ++ 0x00, 0x29, 0xC0, 0xF2, 0x31, 0x81, 0x03, 0x2B, 0x3F, 0xF6, 0xA9, 0xAE, ++ 0xDF, 0xE8, 0x13, 0xF0, 0x26, 0x01, 0x20, 0x01, 0x15, 0x01, 0x04, 0x01, ++ 0x05, 0x23, 0x94, 0xF8, 0x22, 0x10, 0xB4, 0xF8, 0x06, 0x01, 0x8B, 0xF8, ++ 0xA5, 0x30, 0x07, 0x91, 0xCD, 0xF8, 0x24, 0xB0, 0xF3, 0xF7, 0x8C, 0xF8, ++ 0x95, 0x4A, 0x03, 0x46, 0xB2, 0xF8, 0x50, 0x00, 0x08, 0x93, 0xF3, 0xF7, ++ 0x85, 0xF8, 0x08, 0x9B, 0x09, 0x9A, 0x98, 0x42, 0x28, 0xBF, 0x18, 0x46, ++ 0xDA, 0xF8, 0x00, 0x30, 0x82, 0xF8, 0xB0, 0x00, 0xB3, 0xF9, 0x00, 0x30, ++ 0x00, 0x2B, 0xC0, 0xF2, 0xE5, 0x81, 0x8B, 0x4B, 0xB4, 0xF8, 0x06, 0x01, ++ 0xB3, 0xF8, 0x50, 0x10, 0xF3, 0xF7, 0x9A, 0xF9, 0xF2, 0x19, 0x05, 0xEB, ++ 0x82, 0x12, 0x03, 0x46, 0xB4, 0xF8, 0x06, 0x01, 0xA2, 0xF8, 0xA6, 0x30, ++ 0x09, 0x92, 0xF3, 0xF7, 0x59, 0xF8, 0x82, 0x4A, 0x03, 0x46, 0xB2, 0xF8, ++ 0x50, 0x00, 0x08, 0x93, 0xF3, 0xF7, 0x52, 0xF8, 0x08, 0x9B, 0x09, 0x9A, ++ 0x98, 0x42, 0x28, 0xBF, 0x18, 0x46, 0xDA, 0xF8, 0x00, 0x30, 0x82, 0xF8, ++ 0xAC, 0x00, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xC0, 0xF2, 0xB4, 0x81, ++ 0xF3, 0x19, 0x05, 0xEB, 0x83, 0x13, 0x08, 0x93, 0xB3, 0xF8, 0xAA, 0x00, ++ 0x20, 0xF4, 0x7F, 0x60, 0x80, 0xB2, 0xA3, 0xF8, 0xAA, 0x00, 0xF3, 0xF7, ++ 0x65, 0xF8, 0x08, 0x9B, 0xDA, 0xF8, 0x00, 0x20, 0x83, 0xF8, 0xAD, 0x00, ++ 0xB2, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xC0, 0xF2, 0x90, 0x81, 0xF3, 0x19, ++ 0x05, 0xEB, 0x83, 0x13, 0x08, 0x93, 0xB3, 0xF8, 0xAA, 0x00, 0xF3, 0xF7, ++ 0x61, 0xF8, 0x08, 0x9B, 0xDA, 0xF8, 0x00, 0x20, 0x83, 0xF8, 0xAE, 0x00, ++ 0xB2, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xC0, 0xF2, 0x71, 0x81, 0xB4, 0xF8, ++ 0x54, 0x21, 0xF3, 0x19, 0x05, 0xEB, 0x83, 0x13, 0xC2, 0xF3, 0x80, 0x22, ++ 0x83, 0xF8, 0xB2, 0x20, 0xCC, 0xF7, 0xA0, 0xFE, 0x28, 0xB1, 0x5D, 0x4B, ++ 0x93, 0xF8, 0x43, 0x30, 0x99, 0x06, 0x00, 0xF1, 0x99, 0x81, 0x63, 0x68, ++ 0x5B, 0x07, 0x40, 0xF1, 0xEB, 0x80, 0xD4, 0xF8, 0xE8, 0x30, 0x03, 0xF0, ++ 0x03, 0x03, 0x01, 0x2B, 0x00, 0xF0, 0xBD, 0x81, 0x02, 0x2B, 0x00, 0xF0, ++ 0xB2, 0x81, 0xF3, 0x19, 0x05, 0xEB, 0x83, 0x13, 0x40, 0xF6, 0xED, 0x62, ++ 0xA3, 0xF8, 0xB6, 0x20, 0x50, 0x4B, 0x07, 0x99, 0x4F, 0xF4, 0xA4, 0x62, ++ 0x02, 0xFB, 0x01, 0x33, 0x93, 0xF8, 0x62, 0x20, 0x00, 0x2A, 0x40, 0xF0, ++ 0xDF, 0x80, 0xD3, 0xF8, 0xC8, 0x31, 0xD4, 0xF8, 0x48, 0x01, 0x13, 0xF4, ++ 0x80, 0x3F, 0xC1, 0x6B, 0x40, 0xF0, 0x69, 0x81, 0x41, 0xF0, 0x20, 0x01, ++ 0x00, 0x2B, 0xC1, 0x63, 0x06, 0xDB, 0xC3, 0xF3, 0x05, 0x63, 0x49, 0xEA, ++ 0x03, 0x59, 0x02, 0x2A, 0x00, 0xF0, 0x58, 0x81, 0x49, 0xF0, 0x80, 0x59, ++ 0x49, 0xF4, 0xC0, 0x29, 0x3D, 0x4B, 0x93, 0xF8, 0x45, 0x10, 0x94, 0xF8, ++ 0xFD, 0x30, 0x01, 0xF0, 0x03, 0x00, 0xC3, 0xF3, 0xC1, 0x03, 0x83, 0x42, ++ 0x06, 0xEB, 0x07, 0x02, 0x28, 0xBF, 0x03, 0x46, 0x05, 0xEB, 0x82, 0x12, ++ 0x01, 0x20, 0x83, 0x42, 0x82, 0xF8, 0xBC, 0x00, 0x00, 0xF0, 0x6A, 0x81, ++ 0x02, 0x2B, 0x00, 0xF0, 0x64, 0x81, 0x00, 0x2B, 0x00, 0xF0, 0x68, 0x81, ++ 0x04, 0x23, 0x82, 0xF8, 0xBD, 0x30, 0x2E, 0x4B, 0x94, 0xF8, 0xFD, 0xC0, ++ 0x93, 0xF8, 0x4B, 0x00, 0x93, 0xF8, 0x4A, 0x20, 0x8B, 0x08, 0xF1, 0x19, ++ 0x03, 0xEA, 0x5C, 0x13, 0x05, 0xEB, 0x81, 0x11, 0x03, 0xF0, 0x01, 0x03, ++ 0x81, 0xF8, 0xBE, 0x30, 0x94, 0xF8, 0x03, 0xC1, 0x94, 0xF8, 0x02, 0x31, ++ 0x0C, 0xF0, 0x01, 0x0C, 0x9B, 0x11, 0x00, 0xF0, 0x01, 0x00, 0x92, 0x11, ++ 0x43, 0xEA, 0x8C, 0x03, 0x42, 0xEA, 0x80, 0x02, 0x93, 0x42, 0x28, 0xBF, ++ 0x13, 0x46, 0x81, 0xF8, 0xBF, 0x30, 0xE8, 0xE6, 0xD4, 0xF8, 0xE8, 0x30, ++ 0x59, 0x06, 0x7F, 0xF5, 0x9E, 0xAD, 0x19, 0x4B, 0x9B, 0x89, 0x5B, 0x06, ++ 0x7F, 0xF5, 0x99, 0xAD, 0xF3, 0x19, 0x05, 0xEB, 0x83, 0x13, 0x01, 0x21, ++ 0x83, 0xF8, 0xB1, 0x10, 0x91, 0xE5, 0xD4, 0xF8, 0xE8, 0x30, 0x9B, 0x06, ++ 0x7F, 0xF5, 0x8D, 0xAD, 0x10, 0x4B, 0x9B, 0x89, 0x98, 0x06, 0x7F, 0xF5, ++ 0x88, 0xAD, 0xED, 0xE7, 0xB4, 0xF8, 0xC8, 0x30, 0x59, 0x06, 0x7F, 0xF5, ++ 0x82, 0xAD, 0xE2, 0xE7, 0xB4, 0xF8, 0xC8, 0x30, 0x98, 0x06, 0x7F, 0xF5, ++ 0x7C, 0xAD, 0xED, 0xE7, 0x03, 0x2B, 0x7F, 0xF6, 0xCC, 0xAE, 0x40, 0xF6, ++ 0xF9, 0x32, 0x07, 0x49, 0x07, 0x48, 0xF0, 0xF7, 0x31, 0xFA, 0x94, 0xF8, ++ 0x2D, 0x31, 0xDA, 0xF8, 0x00, 0x20, 0xC0, 0xE6, 0xF3, 0xB8, 0x17, 0x00, ++ 0xE4, 0xB8, 0x17, 0x00, 0x18, 0x88, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x34, 0xCA, 0x15, 0x00, 0x40, 0xF6, 0x27, 0x42, 0x88, 0x49, 0x89, 0x48, ++ 0x07, 0x93, 0xF0, 0xF7, 0x1B, 0xFA, 0xDA, 0xF8, 0x00, 0x20, 0xB2, 0xF9, ++ 0x00, 0x20, 0x00, 0x2A, 0xBF, 0xF6, 0x64, 0xAD, 0x07, 0x9B, 0xB3, 0xF8, ++ 0xB4, 0x00, 0xEF, 0xE5, 0x07, 0x9B, 0x1B, 0x6B, 0x13, 0xF0, 0x10, 0x0F, ++ 0xD4, 0xF8, 0xE8, 0x30, 0x3F, 0xF4, 0xF6, 0xAC, 0xD9, 0x06, 0x7F, 0xF5, ++ 0xF3, 0xAC, 0x05, 0x9A, 0x42, 0xF0, 0x40, 0x02, 0x05, 0x92, 0xED, 0xE4, ++ 0x7A, 0x4B, 0x9B, 0x89, 0x13, 0xF0, 0x01, 0x0F, 0xB4, 0xF8, 0xC8, 0x30, ++ 0x3F, 0xF4, 0x72, 0xAE, 0xDA, 0x07, 0x7F, 0xF5, 0x6F, 0xAE, 0x05, 0x9A, ++ 0x42, 0xF0, 0x40, 0x02, 0x05, 0x92, 0x69, 0xE6, 0xB4, 0xF8, 0xC8, 0x30, ++ 0x13, 0xF4, 0x00, 0x6F, 0x06, 0xEB, 0x07, 0x03, 0x05, 0xEB, 0x83, 0x13, ++ 0x14, 0xBF, 0x41, 0xF6, 0xFF, 0x62, 0x40, 0xF6, 0xFF, 0x62, 0xA3, 0xF8, ++ 0xB6, 0x20, 0x15, 0xE7, 0xD4, 0xF8, 0x48, 0x01, 0xD3, 0xF8, 0xC8, 0x31, ++ 0xC1, 0x6B, 0x00, 0x2B, 0x21, 0xF0, 0x20, 0x01, 0xC1, 0x63, 0xBF, 0xF6, ++ 0x24, 0xAF, 0x26, 0xE7, 0x03, 0x28, 0x7F, 0xF6, 0xAF, 0xAC, 0x0C, 0x28, ++ 0x3F, 0xF4, 0xAC, 0xAC, 0x5F, 0x49, 0x62, 0x48, 0x40, 0xF6, 0xA2, 0x32, ++ 0xF0, 0xF7, 0xC8, 0xF9, 0xA4, 0xE4, 0x03, 0x28, 0x7F, 0xF6, 0x90, 0xAC, ++ 0x0C, 0x28, 0x3F, 0xF4, 0x8D, 0xAC, 0x59, 0x49, 0x5C, 0x48, 0x4F, 0xF4, ++ 0x3A, 0x62, 0xF0, 0xF7, 0xBB, 0xF9, 0x85, 0xE4, 0x09, 0x28, 0x7F, 0xF6, ++ 0x6C, 0xAC, 0x54, 0x49, 0x58, 0x48, 0x40, 0xF6, 0x94, 0x32, 0xF0, 0xF7, ++ 0xB1, 0xF9, 0x64, 0xE4, 0x07, 0x28, 0x7F, 0xF6, 0x3D, 0xAC, 0x4F, 0x49, ++ 0x54, 0x48, 0x40, 0xF6, 0x8E, 0x32, 0xF0, 0xF7, 0xA7, 0xF9, 0x35, 0xE4, ++ 0x03, 0x28, 0x7F, 0xF6, 0x0D, 0xAE, 0x0C, 0x28, 0x3F, 0xF4, 0x0A, 0xAE, ++ 0x48, 0x49, 0x4B, 0x48, 0x40, 0xF6, 0xD9, 0x32, 0xF0, 0xF7, 0x9A, 0xF9, ++ 0x02, 0xE6, 0x03, 0x28, 0x7F, 0xF6, 0xEE, 0xAD, 0x0C, 0x28, 0x3F, 0xF4, ++ 0xEB, 0xAD, 0x42, 0x49, 0x45, 0x48, 0x40, 0xF6, 0xD7, 0x32, 0xF0, 0xF7, ++ 0x8D, 0xF9, 0xE3, 0xE5, 0x03, 0x28, 0x7F, 0xF6, 0xBC, 0xAD, 0x3D, 0x49, ++ 0x43, 0x48, 0x07, 0x93, 0x40, 0xF6, 0xCC, 0x32, 0xF0, 0xF7, 0x82, 0xF9, ++ 0x07, 0x9B, 0xB2, 0xE5, 0x03, 0x28, 0x7F, 0xF6, 0x8C, 0xAE, 0x0C, 0x28, ++ 0x3F, 0xF4, 0x89, 0xAE, 0x35, 0x49, 0x38, 0x48, 0x40, 0xF6, 0x22, 0x32, ++ 0xF0, 0xF7, 0x74, 0xF9, 0x81, 0xE6, 0x03, 0x28, 0x7F, 0xF6, 0x6D, 0xAE, ++ 0x0C, 0x28, 0x3F, 0xF4, 0x6A, 0xAE, 0x2F, 0x49, 0x32, 0x48, 0x4F, 0xF4, ++ 0x32, 0x62, 0xF0, 0xF7, 0x67, 0xF9, 0x62, 0xE6, 0x0B, 0x28, 0x7F, 0xF6, ++ 0x49, 0xAE, 0x2A, 0x49, 0x31, 0x48, 0x40, 0xF6, 0x1C, 0x32, 0xF0, 0xF7, ++ 0x5D, 0xF9, 0x41, 0xE6, 0x07, 0x28, 0x7F, 0xF6, 0x18, 0xAE, 0x25, 0x49, ++ 0x2A, 0x48, 0x40, 0xF6, 0x16, 0x32, 0xF0, 0xF7, 0x53, 0xF9, 0x10, 0xE6, ++ 0x49, 0xF0, 0x80, 0x59, 0x49, 0xF4, 0x00, 0x39, 0xA6, 0xE6, 0x21, 0xF0, ++ 0x20, 0x01, 0x00, 0x2B, 0xC1, 0x63, 0xBF, 0xF6, 0x96, 0xAE, 0x9B, 0xE6, ++ 0x94, 0xF8, 0x2D, 0x31, 0x23, 0xB9, 0x94, 0xF8, 0xFB, 0x30, 0x9A, 0x06, ++ 0x7F, 0xF5, 0x5F, 0xAE, 0x05, 0x9B, 0x43, 0xF0, 0x40, 0x03, 0x05, 0x93, ++ 0x59, 0xE6, 0xF3, 0x19, 0x05, 0xEB, 0x83, 0x13, 0x41, 0xF6, 0xED, 0x62, ++ 0xA3, 0xF8, 0xB6, 0x20, 0xB7, 0xE5, 0xF3, 0x19, 0x05, 0xEB, 0x83, 0x13, ++ 0x42, 0xF6, 0x74, 0x42, 0xA3, 0xF8, 0xB6, 0x20, 0xAF, 0xE5, 0x82, 0xF8, ++ 0xBD, 0x00, 0x9E, 0xE6, 0x00, 0x23, 0x82, 0xF8, 0xBD, 0x30, 0x9A, 0xE6, ++ 0x82, 0xF8, 0xBC, 0x30, 0xA5, 0xE5, 0xF3, 0x19, 0x05, 0xEB, 0x83, 0x13, ++ 0x42, 0xF6, 0x74, 0x42, 0xA3, 0xF8, 0xB6, 0x20, 0x4C, 0xE6, 0xF3, 0x19, ++ 0x05, 0xEB, 0x83, 0x13, 0x41, 0xF6, 0xED, 0x62, 0xA3, 0xF8, 0xB6, 0x20, ++ 0x44, 0xE6, 0x00, 0xBF, 0x70, 0x79, 0x15, 0x00, 0xF4, 0xC9, 0x15, 0x00, ++ 0xE4, 0xB8, 0x17, 0x00, 0xE8, 0xCA, 0x15, 0x00, 0x98, 0xCA, 0x15, 0x00, ++ 0x38, 0xCB, 0x15, 0x00, 0x50, 0xCA, 0x15, 0x00, 0x4C, 0xCB, 0x15, 0x00, ++ 0x84, 0xCA, 0x15, 0x00, 0x2D, 0xE9, 0xF0, 0x43, 0x46, 0x7F, 0x09, 0x2E, ++ 0x83, 0xB0, 0x04, 0x46, 0x00, 0xF2, 0x8D, 0x80, 0x4B, 0x4B, 0x4C, 0x4F, ++ 0x1A, 0x68, 0x4F, 0xF4, 0x1E, 0x73, 0xB2, 0xF9, 0x00, 0x20, 0x03, 0xFB, ++ 0x06, 0x73, 0x00, 0x2A, 0xD3, 0xF8, 0x4C, 0x51, 0x40, 0xDB, 0x95, 0xF8, ++ 0xA2, 0x30, 0x59, 0x07, 0x34, 0xD4, 0x03, 0xF0, 0xFD, 0x03, 0x4F, 0xF0, ++ 0x00, 0x08, 0xDF, 0xF8, 0x18, 0x91, 0x85, 0xF8, 0xA2, 0x30, 0xD9, 0xF8, ++ 0x10, 0x30, 0x2A, 0x68, 0x3F, 0x49, 0x9B, 0x1A, 0x8B, 0x42, 0x36, 0xD8, ++ 0x95, 0xF8, 0xA3, 0x20, 0x95, 0xF8, 0xA4, 0x30, 0x43, 0xEA, 0x82, 0x03, ++ 0x84, 0xF8, 0x36, 0x30, 0x28, 0x46, 0xFE, 0xF7, 0x65, 0xFF, 0xB0, 0xB1, ++ 0xE2, 0x8B, 0x94, 0xF8, 0x36, 0x30, 0x42, 0xF4, 0x00, 0x52, 0x23, 0xF0, ++ 0x03, 0x03, 0xE2, 0x83, 0x84, 0xF8, 0x36, 0x30, 0xB8, 0xF1, 0x00, 0x0F, ++ 0x59, 0xD1, 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, 0x06, 0x76, 0x96, 0xF8, ++ 0x56, 0x31, 0x43, 0xF0, 0x20, 0x03, 0x86, 0xF8, 0x56, 0x31, 0x03, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x83, 0x62, 0x6A, 0x92, 0x02, 0xC7, 0xD5, 0x43, 0xF0, ++ 0x02, 0x03, 0x4F, 0xF0, 0x01, 0x08, 0xC6, 0xE7, 0x00, 0x2D, 0xBC, 0xD1, ++ 0x26, 0x49, 0x27, 0x48, 0x40, 0xF6, 0x9A, 0x22, 0xF0, 0xF7, 0x9E, 0xF8, ++ 0xB5, 0xE7, 0x00, 0x21, 0x28, 0x46, 0xFF, 0xF7, 0xBB, 0xF9, 0x95, 0xF8, ++ 0xA3, 0x30, 0x01, 0x33, 0x00, 0x22, 0x03, 0xF0, 0x07, 0x03, 0x85, 0xF8, ++ 0xA3, 0x30, 0x85, 0xF8, 0x9B, 0x20, 0x85, 0xF8, 0xA4, 0x20, 0xD9, 0xF8, ++ 0x10, 0x20, 0x2A, 0x60, 0x9B, 0x00, 0x84, 0xF8, 0x36, 0x30, 0x00, 0x28, ++ 0xB8, 0xD0, 0x0D, 0xF1, 0x07, 0x01, 0x28, 0x46, 0xFE, 0xF7, 0xCE, 0xFC, ++ 0x9D, 0xF8, 0x07, 0x30, 0x53, 0xB9, 0x62, 0x6A, 0x22, 0xF4, 0x00, 0x12, ++ 0x62, 0x62, 0x95, 0xF8, 0xA2, 0x20, 0x22, 0xF0, 0x02, 0x02, 0x98, 0x46, ++ 0x85, 0xF8, 0xA2, 0x20, 0x4F, 0xF4, 0x1E, 0x73, 0x03, 0xFB, 0x06, 0x73, ++ 0x93, 0xF8, 0x56, 0x21, 0x42, 0xF0, 0x11, 0x02, 0x83, 0xF8, 0x56, 0x21, ++ 0x9A, 0xE7, 0x00, 0x23, 0x80, 0xF8, 0x36, 0x30, 0x03, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x83, 0x63, 0x6A, 0x43, 0xF4, 0x20, 0x13, 0x63, 0x62, 0xA0, 0xE7, ++ 0x38, 0x36, 0x17, 0x00, 0x68, 0x65, 0x17, 0x00, 0xA0, 0x86, 0x01, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x68, 0x8E, 0x15, 0x00, 0x00, 0x10, 0x50, 0x40, ++ 0x30, 0xB4, 0xCA, 0x0A, 0x12, 0xF0, 0x06, 0x0F, 0x9D, 0xF8, 0x08, 0x50, ++ 0x9D, 0xF8, 0x14, 0x40, 0x20, 0xD0, 0x02, 0xF0, 0x07, 0x02, 0x01, 0xF0, ++ 0x7F, 0x01, 0x04, 0x2A, 0x0C, 0xBF, 0x09, 0x09, 0xC1, 0xF3, 0xC1, 0x01, ++ 0x4B, 0xB9, 0xC3, 0x6B, 0x23, 0xF0, 0x04, 0x03, 0xC3, 0x63, 0x64, 0xB1, ++ 0x43, 0xF0, 0x10, 0x03, 0x30, 0xBC, 0xC3, 0x63, 0x70, 0x47, 0xA9, 0x42, ++ 0xF3, 0xD1, 0xC3, 0x6B, 0x43, 0xF0, 0x04, 0x03, 0xC3, 0x63, 0x00, 0x2C, ++ 0xF2, 0xD1, 0x23, 0xF0, 0x10, 0x03, 0x30, 0xBC, 0xC3, 0x63, 0x70, 0x47, ++ 0xC3, 0x6B, 0x23, 0xF0, 0x10, 0x03, 0xF8, 0xE7, 0x0B, 0x7B, 0x05, 0x2B, ++ 0x0E, 0xD1, 0x2D, 0xE9, 0xF0, 0x41, 0x4B, 0x7B, 0x84, 0xB0, 0x0C, 0x46, ++ 0x01, 0xF1, 0x0C, 0x07, 0x13, 0xB9, 0x0D, 0x88, 0x09, 0x2D, 0x05, 0xDC, ++ 0x00, 0x20, 0x04, 0xB0, 0xBD, 0xE8, 0xF0, 0x81, 0x00, 0x20, 0x70, 0x47, ++ 0x0B, 0x20, 0x97, 0xF8, 0x02, 0x80, 0x7E, 0x7A, 0xEE, 0xF7, 0xC8, 0xF9, ++ 0x08, 0xBB, 0xFB, 0x78, 0x3B, 0xBB, 0x69, 0x1F, 0x04, 0xF1, 0x11, 0x00, ++ 0x1D, 0x46, 0x01, 0x22, 0x07, 0x78, 0x43, 0x78, 0x26, 0x2F, 0x03, 0xF1, ++ 0x02, 0x03, 0x14, 0xD1, 0x8B, 0x42, 0xA1, 0xEB, 0x03, 0x01, 0x10, 0xDC, ++ 0x05, 0xB9, 0x03, 0x90, 0x02, 0x29, 0x18, 0x44, 0x4F, 0xF0, 0x01, 0x05, ++ 0xEE, 0xDC, 0x00, 0x92, 0xE1, 0x79, 0x20, 0x7A, 0x42, 0x46, 0x03, 0xAB, ++ 0x00, 0xF0, 0x1A, 0xFD, 0x01, 0xF0, 0x52, 0xF8, 0xD0, 0xE7, 0x00, 0x96, ++ 0xE1, 0x79, 0x20, 0x7A, 0x42, 0x46, 0x04, 0x23, 0x00, 0xF0, 0xF4, 0xFC, ++ 0xC8, 0xE7, 0x00, 0x96, 0xE1, 0x79, 0x20, 0x7A, 0x42, 0x46, 0x02, 0x23, ++ 0x00, 0xF0, 0xEC, 0xFC, 0xC0, 0xE7, 0x00, 0xBF, 0x08, 0xB5, 0x0B, 0x20, ++ 0xEE, 0xF7, 0x90, 0xF9, 0x01, 0x28, 0x07, 0xD0, 0x09, 0x4B, 0x1B, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x05, 0xDB, 0x00, 0x20, 0x08, 0xBD, ++ 0x01, 0xF0, 0xEA, 0xF8, 0x00, 0x20, 0x08, 0xBD, 0x04, 0x49, 0x05, 0x48, ++ 0x9D, 0x22, 0xEF, 0xF7, 0xD5, 0xFF, 0x00, 0x20, 0x08, 0xBD, 0x00, 0xBF, ++ 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x64, 0x7D, 0x15, 0x00, ++ 0x08, 0xB5, 0x0B, 0x20, 0xEE, 0xF7, 0x70, 0xF9, 0x04, 0x28, 0x07, 0xD0, ++ 0x09, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x05, 0xDB, ++ 0x00, 0x20, 0x08, 0xBD, 0x01, 0xF0, 0x3E, 0xF8, 0x00, 0x20, 0x08, 0xBD, ++ 0x04, 0x49, 0x05, 0x48, 0x81, 0x22, 0xEF, 0xF7, 0xB5, 0xFF, 0x00, 0x20, ++ 0x08, 0xBD, 0x00, 0xBF, 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x64, 0x7D, 0x15, 0x00, 0x3A, 0xB3, 0x93, 0x68, 0x10, 0xB4, 0x93, 0xB9, ++ 0x54, 0x69, 0x64, 0xB1, 0xFF, 0x28, 0x22, 0xD1, 0x00, 0x2C, 0x1A, 0xDD, ++ 0x18, 0x32, 0x10, 0x19, 0x01, 0xE0, 0x82, 0x42, 0x15, 0xD0, 0x12, 0xF8, ++ 0x01, 0x3B, 0x99, 0x42, 0xF9, 0xD1, 0x01, 0x20, 0x5D, 0xF8, 0x04, 0x4B, ++ 0x70, 0x47, 0xFF, 0x28, 0x13, 0xD0, 0x00, 0x2B, 0x09, 0xDD, 0x0C, 0x32, ++ 0x13, 0x44, 0x01, 0xE0, 0x9A, 0x42, 0x04, 0xD0, 0x12, 0xF8, 0x01, 0x1B, ++ 0x81, 0x42, 0xF9, 0xD1, 0xED, 0xE7, 0x00, 0x20, 0x5D, 0xF8, 0x04, 0x4B, ++ 0x70, 0x47, 0x01, 0x20, 0x70, 0x47, 0x18, 0x46, 0xE6, 0xE7, 0x54, 0x69, ++ 0xD8, 0xE7, 0x00, 0xBF, 0x38, 0xB5, 0x0A, 0x4D, 0x41, 0xF2, 0x98, 0x74, ++ 0x2B, 0x59, 0x63, 0xB1, 0x0B, 0x20, 0xEE, 0xF7, 0x1B, 0xF9, 0x03, 0x28, ++ 0x01, 0xD0, 0x00, 0x20, 0x38, 0xBD, 0x2B, 0x59, 0x18, 0x68, 0xB0, 0xFA, ++ 0x80, 0xF0, 0x40, 0x09, 0x38, 0xBD, 0x01, 0x20, 0x38, 0xBD, 0x00, 0xBF, ++ 0x78, 0xEF, 0x17, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, 0x83, 0x46, 0x80, 0x6C, ++ 0x89, 0xB0, 0x14, 0x46, 0x99, 0x46, 0x00, 0xF1, 0x68, 0x05, 0x00, 0x29, ++ 0x3B, 0xD1, 0xB0, 0xF8, 0x68, 0x10, 0xBE, 0x4A, 0xB2, 0xF8, 0xFC, 0x31, ++ 0x01, 0x33, 0x9B, 0xB2, 0x1E, 0x01, 0xA2, 0xF8, 0xFC, 0x31, 0xA0, 0xF8, ++ 0x7E, 0x60, 0x05, 0x22, 0x58, 0x46, 0xFC, 0xF7, 0x53, 0xFA, 0x01, 0x28, ++ 0x00, 0xF0, 0xC8, 0x80, 0x1B, 0x23, 0x03, 0x93, 0x18, 0x23, 0xE9, 0x18, ++ 0x05, 0x22, 0xEA, 0x54, 0x01, 0x22, 0x4A, 0x70, 0x99, 0xF8, 0x00, 0x20, ++ 0x8A, 0x70, 0x01, 0xF1, 0x03, 0x0A, 0x00, 0x2C, 0x7B, 0xD0, 0x03, 0x22, ++ 0x27, 0x20, 0xC8, 0x70, 0x0A, 0x71, 0x99, 0xF8, 0x01, 0x20, 0x4A, 0x71, ++ 0x8C, 0x71, 0x99, 0xF8, 0x02, 0x20, 0xCA, 0x71, 0x08, 0x33, 0xDB, 0xF8, ++ 0x4C, 0x00, 0x9B, 0xF8, 0x35, 0x20, 0x41, 0x6A, 0x13, 0x44, 0x01, 0x39, ++ 0x19, 0x44, 0x04, 0x33, 0xC0, 0xE9, 0x0A, 0x13, 0x09, 0xB0, 0xBD, 0xE8, ++ 0xF0, 0x8F, 0xA2, 0x4B, 0xA2, 0x4E, 0x00, 0x22, 0x41, 0xF2, 0xA8, 0x7C, ++ 0x6F, 0xF0, 0x2F, 0x01, 0x80, 0xF8, 0x69, 0x20, 0x80, 0xF8, 0x6A, 0x20, ++ 0x80, 0xF8, 0x6B, 0x20, 0x80, 0xF8, 0x68, 0x10, 0x13, 0xF8, 0x0C, 0x10, ++ 0x9B, 0x4A, 0x4F, 0xF4, 0x1E, 0x77, 0x07, 0xFB, 0x01, 0xF1, 0x41, 0xF2, ++ 0xA9, 0x78, 0x89, 0x5B, 0xA0, 0xF8, 0x6C, 0x10, 0x13, 0xF8, 0x0C, 0x10, ++ 0x07, 0xFB, 0x01, 0x61, 0x4F, 0xF4, 0xA4, 0x6E, 0x49, 0x88, 0xA0, 0xF8, ++ 0x6E, 0x10, 0x13, 0xF8, 0x0C, 0x10, 0x07, 0xFB, 0x01, 0x61, 0x89, 0x88, ++ 0xA0, 0xF8, 0x70, 0x10, 0x13, 0xF8, 0x08, 0x10, 0x0E, 0xFB, 0x01, 0xF1, ++ 0x89, 0x5A, 0xA0, 0xF8, 0x72, 0x10, 0x13, 0xF8, 0x08, 0x10, 0x0E, 0xFB, ++ 0x01, 0x21, 0x49, 0x88, 0xA0, 0xF8, 0x74, 0x10, 0x13, 0xF8, 0x08, 0x10, ++ 0x0E, 0xFB, 0x01, 0x21, 0x89, 0x88, 0xA0, 0xF8, 0x76, 0x10, 0x13, 0xF8, ++ 0x08, 0x10, 0x0E, 0xFB, 0x01, 0xF1, 0x02, 0xEB, 0x01, 0x0A, 0x9A, 0xF8, ++ 0x06, 0xA0, 0xBA, 0xF1, 0x02, 0x0F, 0x5F, 0xD0, 0x13, 0xF8, 0x0C, 0x20, ++ 0x07, 0xFB, 0x02, 0xF2, 0xD0, 0x21, 0x92, 0x5B, 0xA0, 0xF8, 0x78, 0x20, ++ 0x13, 0xF8, 0x0C, 0x20, 0x07, 0xFB, 0x02, 0x62, 0x52, 0x88, 0xA0, 0xF8, ++ 0x7A, 0x20, 0x13, 0xF8, 0x0C, 0x30, 0x07, 0xFB, 0x03, 0x66, 0xB3, 0x88, ++ 0xA0, 0xF8, 0x7C, 0x30, 0x63, 0xE7, 0x03, 0x9B, 0x01, 0x94, 0xC3, 0xF5, ++ 0xC0, 0x73, 0x9B, 0xB2, 0x02, 0x93, 0xCD, 0xF8, 0x14, 0xB0, 0x99, 0xF8, ++ 0x02, 0x30, 0x02, 0x9A, 0x05, 0x2B, 0xA2, 0xF1, 0x05, 0x04, 0xA4, 0xB2, ++ 0x00, 0xF0, 0xE2, 0x80, 0x27, 0x23, 0x8A, 0xF8, 0x00, 0x30, 0x99, 0xF8, ++ 0x01, 0x30, 0x8A, 0xF8, 0x02, 0x30, 0x00, 0x23, 0x8A, 0xF8, 0x03, 0x30, ++ 0x99, 0xF8, 0x02, 0x30, 0x8A, 0xF8, 0x04, 0x30, 0x05, 0x2B, 0x3A, 0xD0, ++ 0x03, 0x23, 0x8A, 0xF8, 0x01, 0x30, 0x02, 0x94, 0x0A, 0xF1, 0x05, 0x0A, ++ 0x05, 0x25, 0xFF, 0xF7, 0x15, 0xFF, 0x01, 0x9B, 0x2B, 0x44, 0x01, 0x93, ++ 0x08, 0xB9, 0x04, 0x2C, 0xD7, 0xD8, 0x5C, 0x4B, 0xDD, 0xF8, 0x14, 0xB0, ++ 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xC0, 0xF2, 0x9D, 0x80, ++ 0x01, 0x9B, 0x03, 0x9A, 0x13, 0x44, 0x52, 0xE7, 0x18, 0x22, 0x29, 0x46, ++ 0x58, 0x46, 0xFA, 0xF7, 0xE7, 0xFF, 0x9B, 0xF8, 0x33, 0x20, 0x02, 0xF1, ++ 0x18, 0x03, 0x1B, 0x32, 0x03, 0x92, 0x2E, 0xE7, 0x89, 0x5A, 0xA0, 0xF8, ++ 0x78, 0x10, 0x13, 0xF8, 0x08, 0x60, 0x0E, 0xFB, 0x06, 0x26, 0xD0, 0x21, ++ 0x76, 0x88, 0xA0, 0xF8, 0x7A, 0x60, 0x13, 0xF8, 0x08, 0x30, 0x0E, 0xFB, ++ 0x03, 0x22, 0x93, 0x88, 0xA0, 0xF8, 0x7C, 0x30, 0x07, 0xE7, 0xD9, 0xF8, ++ 0x5C, 0x20, 0x46, 0x49, 0x01, 0x32, 0x0D, 0x68, 0xC9, 0xF8, 0x5C, 0x20, ++ 0x0A, 0xF1, 0x05, 0x02, 0x04, 0x92, 0x00, 0x2D, 0x00, 0xF0, 0x45, 0x81, ++ 0xEB, 0x7C, 0x8A, 0xF8, 0x05, 0x30, 0x2B, 0x7C, 0x8A, 0xF8, 0x06, 0x30, ++ 0xD9, 0xE9, 0x0A, 0x12, 0xB9, 0xF8, 0x30, 0x30, 0xAA, 0xF8, 0x0F, 0x30, ++ 0xCA, 0xF8, 0x07, 0x10, 0xCA, 0xF8, 0x0B, 0x20, 0xAB, 0x7C, 0x8A, 0xF8, ++ 0x11, 0x30, 0x95, 0xF9, 0x14, 0x00, 0xEE, 0xF7, 0x21, 0xFF, 0xFF, 0x23, ++ 0x8A, 0xF8, 0x12, 0x00, 0x8A, 0xF8, 0x13, 0x30, 0x05, 0xF1, 0x0C, 0x00, ++ 0xAB, 0x1D, 0x13, 0xF8, 0x01, 0x1B, 0x03, 0xF1, 0x0D, 0x02, 0x52, 0x1B, ++ 0x83, 0x42, 0x02, 0xF8, 0x0A, 0x10, 0xF6, 0xD1, 0x6B, 0x7C, 0x8A, 0xF8, ++ 0x1A, 0x30, 0x02, 0x9A, 0xEB, 0x68, 0xCA, 0xF8, 0x1B, 0x30, 0x40, 0xF2, ++ 0x01, 0x14, 0x94, 0x42, 0x99, 0xF8, 0x20, 0x30, 0x28, 0xBF, 0x14, 0x46, ++ 0x0A, 0xF1, 0x1F, 0x02, 0xA4, 0xB2, 0x04, 0x92, 0x00, 0x2B, 0x40, 0xF0, ++ 0x05, 0x81, 0x1F, 0x3C, 0xA4, 0xB2, 0x99, 0xF8, 0x04, 0x30, 0x00, 0x2B, ++ 0x6D, 0xD1, 0x6B, 0x8B, 0x2B, 0x83, 0x03, 0x23, 0x1D, 0x48, 0xAB, 0x80, ++ 0x29, 0x46, 0xEE, 0xF7, 0xEB, 0xF9, 0x99, 0xF8, 0x20, 0x30, 0x00, 0x2B, ++ 0x40, 0xF0, 0x12, 0x81, 0x04, 0x9B, 0x02, 0x9A, 0xA3, 0xEB, 0x0A, 0x05, ++ 0xAB, 0x1E, 0x8A, 0xF8, 0x01, 0x30, 0x14, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x54, 0x1B, 0x00, 0x2B, 0xA4, 0xB2, 0x80, 0xF2, 0xF9, 0x80, ++ 0xAA, 0x42, 0x80, 0xF0, 0xF6, 0x80, 0x10, 0x49, 0x10, 0x48, 0xDD, 0xF8, ++ 0x10, 0xA0, 0x40, 0xF2, 0x07, 0x52, 0xEF, 0xF7, 0xCF, 0xFD, 0x02, 0x94, ++ 0x51, 0xE7, 0x01, 0x9B, 0x00, 0x2B, 0x7F, 0xF4, 0x5F, 0xAF, 0x09, 0x49, ++ 0x0A, 0x48, 0x40, 0xF2, 0x12, 0x52, 0xEF, 0xF7, 0xDB, 0xFD, 0x57, 0xE7, ++ 0x20, 0x62, 0x17, 0x00, 0x78, 0xEF, 0x17, 0x00, 0x8E, 0x65, 0x17, 0x00, ++ 0x74, 0x88, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, 0x10, 0x07, 0x18, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xF4, 0xD0, 0x15, 0x00, 0x0C, 0xD1, 0x15, 0x00, ++ 0x94, 0x4B, 0x1A, 0x68, 0x00, 0x2A, 0x3F, 0xF4, 0x19, 0xAF, 0x19, 0x2C, ++ 0x7F, 0xF6, 0x35, 0xAF, 0x02, 0x98, 0x99, 0xF8, 0x20, 0x10, 0xA0, 0xF1, ++ 0x1F, 0x03, 0x9B, 0xB2, 0x29, 0xB1, 0x02, 0x2B, 0x7F, 0xF6, 0x2B, 0xAF, ++ 0xA0, 0xF1, 0x22, 0x03, 0x9B, 0xB2, 0x99, 0xF8, 0x04, 0x10, 0x00, 0x29, ++ 0x3F, 0xF4, 0x04, 0xAF, 0x03, 0x2B, 0x7F, 0xF6, 0x20, 0xAF, 0x10, 0x8B, ++ 0x04, 0x3B, 0x9D, 0xB2, 0x00, 0x28, 0x40, 0xF0, 0xCF, 0x80, 0x0D, 0x2D, ++ 0x3F, 0xF6, 0xF8, 0xAE, 0x15, 0xE7, 0x04, 0x9A, 0x01, 0x23, 0x13, 0x70, ++ 0x2B, 0x8B, 0xA2, 0x1F, 0x92, 0xB2, 0x0A, 0xF1, 0x21, 0x01, 0x0B, 0x2B, ++ 0x06, 0x92, 0x8C, 0x46, 0x1B, 0xD8, 0x7C, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0xC0, 0xF2, 0xAE, 0x80, 0x05, 0xF1, 0x1C, 0x02, ++ 0x05, 0xF1, 0x28, 0x00, 0x13, 0x46, 0x05, 0x33, 0x12, 0xF8, 0x01, 0x1B, ++ 0x5B, 0x1B, 0x82, 0x42, 0x03, 0xF8, 0x0A, 0x10, 0xF6, 0xD1, 0x0C, 0x23, ++ 0x12, 0x3C, 0xA2, 0xB2, 0x2B, 0x83, 0x0A, 0xF1, 0x2D, 0x03, 0x06, 0x92, ++ 0x9C, 0x46, 0x99, 0xF8, 0x04, 0x30, 0x01, 0x2B, 0x3A, 0xD0, 0x2B, 0x8B, ++ 0x6E, 0x8B, 0xF6, 0x1A, 0x05, 0xF1, 0x1C, 0x07, 0xB6, 0xB2, 0x1F, 0x44, ++ 0x00, 0x2E, 0x3B, 0xD0, 0xCD, 0xF8, 0x1C, 0xA0, 0xE3, 0x46, 0xAA, 0x46, ++ 0x09, 0xE0, 0xBA, 0xF8, 0x18, 0x10, 0x36, 0x1B, 0xB6, 0xB2, 0x0C, 0x44, ++ 0x2F, 0x44, 0xAA, 0xF8, 0x18, 0x40, 0x00, 0x2E, 0x5D, 0xD0, 0x97, 0xF8, ++ 0x00, 0x80, 0xB9, 0x78, 0x7C, 0x78, 0x40, 0x46, 0x4A, 0x46, 0xFF, 0xF7, ++ 0xA9, 0xFD, 0xA5, 0x1C, 0x02, 0x34, 0xED, 0xB2, 0xE4, 0xB2, 0x00, 0x28, ++ 0xE7, 0xD0, 0xD9, 0x2D, 0xE5, 0xD8, 0x06, 0x9B, 0x9C, 0x42, 0x4A, 0xD8, ++ 0x4D, 0xB1, 0x59, 0x46, 0x78, 0x1A, 0xAB, 0x44, 0x01, 0xE0, 0x10, 0xF8, ++ 0x01, 0x80, 0x01, 0xF8, 0x01, 0x8B, 0x8B, 0x45, 0xF9, 0xD1, 0x06, 0x9B, ++ 0x1B, 0x1B, 0x9B, 0xB2, 0x06, 0x93, 0xD2, 0xE7, 0xD9, 0xF8, 0x08, 0x30, ++ 0x00, 0x2B, 0xC0, 0xD1, 0xD9, 0xF8, 0x14, 0x30, 0x00, 0x2B, 0xBC, 0xD1, ++ 0x6B, 0x8B, 0x2B, 0x83, 0x04, 0x9B, 0xC3, 0xF1, 0xFE, 0x0B, 0xE3, 0x44, ++ 0x02, 0x23, 0x8A, 0xF8, 0x20, 0xB0, 0x8C, 0xF8, 0x00, 0x30, 0x8C, 0xF8, ++ 0x01, 0x30, 0xEA, 0x7D, 0x28, 0x8B, 0x69, 0x8B, 0x99, 0xF8, 0x01, 0x30, ++ 0x54, 0x1C, 0x88, 0x42, 0x66, 0x46, 0xEC, 0x75, 0x43, 0xEA, 0x02, 0x23, ++ 0x23, 0xD2, 0x6F, 0xEA, 0x43, 0x43, 0x6F, 0xEA, 0x53, 0x43, 0xAC, 0xF8, ++ 0x02, 0x30, 0x33, 0x1D, 0x04, 0x93, 0x08, 0xE7, 0x22, 0x3C, 0xA4, 0xB2, ++ 0xF9, 0xE6, 0x03, 0x22, 0x8A, 0xF8, 0x01, 0x20, 0x36, 0x4A, 0x12, 0x68, ++ 0xB2, 0xF9, 0x00, 0x20, 0x00, 0x2A, 0x09, 0xDB, 0xDD, 0xF8, 0x10, 0xA0, ++ 0x02, 0x94, 0x1D, 0x46, 0x6B, 0xE6, 0x55, 0x46, 0xDC, 0x46, 0xDD, 0xF8, ++ 0x1C, 0xA0, 0xC9, 0xE7, 0x1D, 0x46, 0xDD, 0xF8, 0x10, 0xA0, 0x02, 0x94, ++ 0x61, 0xE6, 0xAC, 0xF8, 0x02, 0x30, 0x33, 0x1D, 0x04, 0x93, 0xE2, 0xE6, ++ 0x04, 0x9D, 0xA4, 0x23, 0x01, 0x24, 0x2B, 0x70, 0x6C, 0x70, 0xFF, 0xF7, ++ 0x6D, 0xFD, 0x20, 0xB1, 0xAC, 0x70, 0x04, 0x9B, 0x03, 0x33, 0x04, 0x93, ++ 0xE0, 0xE6, 0x04, 0x9B, 0x98, 0x70, 0xF8, 0xE7, 0x0B, 0x2A, 0x3F, 0xF6, ++ 0x4F, 0xAF, 0x21, 0x49, 0x21, 0x48, 0x40, 0xF2, 0x7D, 0x42, 0xEF, 0xF7, ++ 0xBF, 0xFC, 0x47, 0xE7, 0xB2, 0xF8, 0x1A, 0x80, 0x01, 0x29, 0x02, 0xF1, ++ 0x1C, 0x02, 0xA8, 0xEB, 0x00, 0x08, 0x02, 0xEB, 0x00, 0x07, 0x08, 0xD0, ++ 0xB8, 0xF1, 0x00, 0x0F, 0x1B, 0xD0, 0x7B, 0x78, 0x03, 0x33, 0xAB, 0x42, ++ 0xFF, 0xF6, 0x1A, 0xAE, 0x37, 0xE6, 0x7E, 0x78, 0x10, 0x5C, 0x97, 0xF8, ++ 0x02, 0xB0, 0x02, 0x36, 0xF6, 0xB2, 0x03, 0xE0, 0x7E, 0x78, 0x38, 0x78, ++ 0x02, 0x36, 0xF6, 0xB2, 0x4A, 0x46, 0x59, 0x46, 0xFF, 0xF7, 0x08, 0xFD, ++ 0x08, 0xB1, 0xD9, 0x2E, 0xE4, 0xD9, 0xB8, 0xEB, 0x06, 0x08, 0x37, 0x44, ++ 0xF0, 0xD1, 0x08, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0xBF, 0xF6, 0xFC, 0xAD, 0x05, 0x49, 0x07, 0x48, 0x40, 0xF2, 0x13, 0x42, ++ 0xEF, 0xF7, 0xA0, 0xFC, 0xF4, 0xE5, 0x00, 0xBF, 0x10, 0x07, 0x18, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0xD0, 0xD0, 0x15, 0x00, ++ 0x64, 0x7D, 0x15, 0x00, 0xF8, 0xB5, 0x2D, 0x4E, 0x41, 0xF2, 0xA9, 0x73, ++ 0xF2, 0x5C, 0x03, 0x2A, 0x42, 0xD8, 0x41, 0xF2, 0xA8, 0x73, 0xF3, 0x5C, ++ 0x09, 0x2B, 0x3D, 0xD8, 0x0D, 0x46, 0x28, 0x49, 0x4F, 0xF4, 0xA4, 0x63, ++ 0x03, 0xFB, 0x02, 0x13, 0x07, 0x46, 0x1B, 0x6C, 0x00, 0x2B, 0x3E, 0xD0, ++ 0x24, 0x48, 0x1B, 0x79, 0x00, 0x68, 0xB0, 0xF9, 0x00, 0x00, 0x00, 0x28, ++ 0x2D, 0xDB, 0x4F, 0xF4, 0xA4, 0x60, 0x00, 0xFB, 0x02, 0x12, 0x92, 0xF8, ++ 0xC0, 0x24, 0x13, 0x43, 0x14, 0xBF, 0x01, 0x20, 0x00, 0x20, 0x4F, 0xF4, ++ 0xC0, 0x71, 0xDA, 0xF7, 0x3D, 0xFE, 0x04, 0x46, 0xE0, 0xB1, 0x41, 0xF2, ++ 0xA9, 0x72, 0x41, 0xF2, 0xA8, 0x73, 0xB2, 0x5C, 0x02, 0x77, 0xF3, 0x5C, ++ 0x43, 0x77, 0x00, 0x23, 0x80, 0xF8, 0x33, 0x30, 0x80, 0xF8, 0x35, 0x30, ++ 0x15, 0xB9, 0x13, 0x4B, 0xC0, 0xE9, 0x15, 0x30, 0x20, 0x46, 0x3B, 0x46, ++ 0x2A, 0x46, 0x01, 0x21, 0xFF, 0xF7, 0xEC, 0xFC, 0x20, 0x46, 0x03, 0x21, ++ 0xBD, 0xE8, 0xF8, 0x40, 0xDA, 0xF7, 0x2E, 0xBE, 0xF8, 0xBD, 0x02, 0x2B, ++ 0xCF, 0xD1, 0x0B, 0x49, 0x0B, 0x48, 0x4F, 0xF4, 0x09, 0x72, 0xEF, 0xF7, ++ 0x29, 0xFC, 0x01, 0x20, 0xD1, 0xE7, 0x05, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0xF7, 0xDA, 0xF0, 0xE7, 0x78, 0xEF, 0x17, 0x00, ++ 0x18, 0x88, 0x17, 0x00, 0x38, 0x36, 0x17, 0x00, 0xA1, 0x5E, 0x15, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0xFC, 0x90, 0x15, 0x00, 0x00, 0x2A, 0x35, 0xD0, ++ 0x70, 0xB5, 0x04, 0x46, 0x92, 0xF8, 0x32, 0x00, 0x8A, 0xB0, 0x13, 0x46, ++ 0x58, 0xB9, 0x95, 0x8E, 0x22, 0x88, 0x95, 0x42, 0x28, 0xD1, 0xDD, 0x8E, ++ 0x62, 0x88, 0x95, 0x42, 0x24, 0xD1, 0xA2, 0x88, 0x1C, 0x8F, 0x94, 0x42, ++ 0x20, 0xD1, 0x93, 0xF8, 0x3A, 0x20, 0xE2, 0xB1, 0xD9, 0xB1, 0x4D, 0x78, ++ 0x8D, 0xF8, 0x04, 0x50, 0x6D, 0xB1, 0x01, 0xA8, 0x05, 0x44, 0xC0, 0xF1, ++ 0x02, 0x06, 0x44, 0x18, 0xA4, 0x5D, 0x00, 0xF8, 0x01, 0x4F, 0xA8, 0x42, ++ 0xF9, 0xD1, 0x9D, 0xF8, 0x04, 0x10, 0x91, 0x42, 0x01, 0xD0, 0x00, 0x20, ++ 0x08, 0xE0, 0x03, 0xF1, 0x3B, 0x00, 0x0D, 0xF1, 0x05, 0x01, 0x01, 0xF0, ++ 0x57, 0xFE, 0x00, 0x28, 0xF5, 0xD1, 0x01, 0x20, 0x0A, 0xB0, 0x70, 0xBD, ++ 0x01, 0x20, 0x70, 0x47, 0x2D, 0xE9, 0xF0, 0x47, 0x04, 0x46, 0xB1, 0xB1, ++ 0x64, 0x48, 0x65, 0x4D, 0xA0, 0xF1, 0x82, 0x07, 0xED, 0xF7, 0x78, 0xFF, ++ 0x00, 0x26, 0x25, 0xF8, 0x02, 0x6C, 0x28, 0x46, 0x06, 0x22, 0x00, 0x21, ++ 0x05, 0xF5, 0xF6, 0x75, 0xCA, 0xF7, 0xDE, 0xFE, 0xBD, 0x42, 0xF4, 0xD1, ++ 0xEC, 0xF7, 0x56, 0xFC, 0xC4, 0xE9, 0x0A, 0x01, 0x26, 0x66, 0x5B, 0x4E, ++ 0xDF, 0xF8, 0x6C, 0x81, 0x06, 0xF1, 0x88, 0x07, 0x0B, 0x20, 0xED, 0xF7, ++ 0x77, 0xFD, 0x01, 0x28, 0x39, 0xD1, 0x57, 0x4D, 0x4F, 0xF0, 0x00, 0x09, ++ 0x4F, 0xF0, 0x02, 0x0A, 0x03, 0xE0, 0x05, 0xF5, 0xF6, 0x75, 0xB5, 0x42, ++ 0x1A, 0xD0, 0xAB, 0x88, 0x01, 0x2B, 0xF8, 0xD1, 0x6B, 0x7D, 0x05, 0xF1, ++ 0x1C, 0x01, 0x19, 0x44, 0x22, 0x46, 0xA8, 0x1D, 0xFF, 0xF7, 0x8C, 0xFF, ++ 0x00, 0x28, 0xEE, 0xD0, 0x29, 0x46, 0xA5, 0xF8, 0x18, 0x90, 0x85, 0xF8, ++ 0x17, 0x90, 0xA5, 0xF8, 0x04, 0xA0, 0x38, 0x46, 0x05, 0xF5, 0xF6, 0x75, ++ 0xED, 0xF7, 0x3E, 0xFF, 0xB5, 0x42, 0xE4, 0xD1, 0x23, 0x6E, 0x94, 0xF8, ++ 0x65, 0x20, 0x01, 0x33, 0x93, 0x42, 0x23, 0x66, 0x5D, 0xDA, 0x03, 0x21, ++ 0x0B, 0x20, 0xED, 0xF7, 0x9D, 0xFC, 0xFF, 0xF7, 0x1F, 0xFC, 0x00, 0x28, ++ 0xC6, 0xD1, 0x20, 0x46, 0x00, 0x21, 0xBD, 0xE8, 0xF0, 0x47, 0xFF, 0xF7, ++ 0xFF, 0xBE, 0x01, 0x21, 0x0B, 0x20, 0xED, 0xF7, 0x8F, 0xFC, 0x23, 0x6E, ++ 0x06, 0xE0, 0x23, 0x6E, 0x94, 0xF8, 0x65, 0x20, 0x01, 0x33, 0x93, 0x42, ++ 0x23, 0x66, 0xB3, 0xDA, 0x23, 0x44, 0x94, 0xF8, 0x64, 0x00, 0x93, 0xF8, ++ 0x66, 0x10, 0xF1, 0xF7, 0xBB, 0xFF, 0x05, 0x46, 0x00, 0x28, 0xEE, 0xD0, ++ 0xC3, 0x78, 0x9B, 0x07, 0xEB, 0xD4, 0x4F, 0xF4, 0xBA, 0x73, 0x0B, 0x22, ++ 0x04, 0x21, 0x4F, 0xF4, 0x80, 0x50, 0xED, 0xF7, 0x77, 0xFA, 0x06, 0x46, ++ 0x28, 0x68, 0x30, 0x60, 0xAB, 0x88, 0xB3, 0x80, 0xE3, 0x78, 0x1B, 0xB9, ++ 0xF3, 0x78, 0x43, 0xF0, 0x01, 0x03, 0xF3, 0x70, 0x01, 0x25, 0x86, 0xF8, ++ 0x6F, 0x51, 0x94, 0xF8, 0x3A, 0x20, 0x86, 0xF8, 0xFC, 0x20, 0x04, 0xF1, ++ 0x3B, 0x01, 0x06, 0xF1, 0xFD, 0x00, 0x01, 0xF0, 0xE7, 0xFD, 0x86, 0xF8, ++ 0x70, 0x51, 0xA3, 0x8E, 0xA6, 0xF8, 0x60, 0x31, 0xE3, 0x8E, 0xA6, 0xF8, ++ 0x62, 0x31, 0x23, 0x8F, 0xA6, 0xF8, 0x64, 0x31, 0x41, 0xF2, 0xA9, 0x73, ++ 0x30, 0x46, 0x18, 0xF8, 0x03, 0x30, 0x86, 0xF8, 0x6E, 0x31, 0xBD, 0xE8, ++ 0xF0, 0x47, 0xED, 0xF7, 0x79, 0xBA, 0x13, 0x4B, 0x1B, 0x68, 0xB3, 0xF9, ++ 0x00, 0x30, 0x00, 0x2B, 0x09, 0xDB, 0x02, 0x21, 0x0B, 0x20, 0xED, 0xF7, ++ 0x39, 0xFC, 0x20, 0x46, 0x00, 0x21, 0xBD, 0xE8, 0xF0, 0x47, 0xFF, 0xF7, ++ 0x9F, 0xBE, 0xFF, 0xF7, 0xB5, 0xFB, 0x00, 0x28, 0xF1, 0xD0, 0xE3, 0x6D, ++ 0x00, 0x2B, 0xEE, 0xD0, 0x08, 0x49, 0x09, 0x48, 0x40, 0xF2, 0x22, 0x62, ++ 0xEF, 0xF7, 0x0E, 0xFB, 0xE7, 0xE7, 0x00, 0xBF, 0x10, 0x07, 0x18, 0x00, ++ 0x7E, 0xEF, 0x17, 0x00, 0x88, 0x06, 0x18, 0x00, 0x78, 0xEF, 0x17, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x70, 0x79, 0x15, 0x00, 0x1C, 0xD1, 0x15, 0x00, ++ 0x10, 0xB5, 0x08, 0x4C, 0x00, 0x21, 0x0B, 0x20, 0xED, 0xF7, 0x10, 0xFC, ++ 0x20, 0x46, 0x41, 0xF2, 0xB0, 0x72, 0x00, 0x21, 0x04, 0xF5, 0xBD, 0x54, ++ 0xCA, 0xF7, 0x08, 0xFE, 0x4F, 0xF0, 0xFF, 0x33, 0x23, 0x60, 0x10, 0xBD, ++ 0x78, 0xEF, 0x17, 0x00, 0xF0, 0xB5, 0xA3, 0xB0, 0x0B, 0x4C, 0x9D, 0xF8, ++ 0xA0, 0x50, 0x8D, 0xF8, 0x02, 0x50, 0x41, 0xF2, 0xA8, 0x75, 0x84, 0x46, ++ 0x41, 0xF2, 0xA9, 0x77, 0x08, 0x46, 0x66, 0x5B, 0x60, 0x55, 0x19, 0x46, ++ 0x68, 0x46, 0x04, 0xF8, 0x07, 0xC0, 0x8D, 0xF8, 0x00, 0x20, 0xFF, 0xF7, ++ 0x57, 0xFE, 0x66, 0x53, 0x23, 0xB0, 0xF0, 0xBD, 0x78, 0xEF, 0x17, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0xAB, 0xB0, 0x41, 0xF2, 0xA8, 0x76, 0x00, 0x92, ++ 0xC4, 0x4A, 0x41, 0xF2, 0xA9, 0x75, 0x91, 0x55, 0xCD, 0xE9, 0x01, 0x01, ++ 0x02, 0xF5, 0xBD, 0x51, 0x50, 0x55, 0x4F, 0xF0, 0xFF, 0x30, 0x08, 0x60, ++ 0x34, 0x99, 0x16, 0x46, 0x41, 0xF2, 0xA4, 0x74, 0x00, 0x22, 0x91, 0x42, ++ 0x32, 0x51, 0x34, 0xDD, 0xDF, 0xF8, 0xF0, 0x82, 0x1F, 0x46, 0x91, 0x46, ++ 0xBA, 0x46, 0x57, 0xF8, 0x04, 0x4B, 0x65, 0x78, 0xAB, 0x1C, 0x04, 0x2B, ++ 0x37, 0xD9, 0x88, 0x22, 0x00, 0x21, 0x40, 0x46, 0xCA, 0xF7, 0xBC, 0xFD, ++ 0xA3, 0x78, 0x88, 0xF8, 0x01, 0x30, 0xE3, 0x78, 0x22, 0x79, 0x88, 0xF8, ++ 0x02, 0x20, 0xD9, 0x07, 0x03, 0xD4, 0x9B, 0x07, 0x1C, 0xD4, 0x05, 0x2A, ++ 0x73, 0xD0, 0xDA, 0xF8, 0x00, 0x40, 0x02, 0x21, 0x00, 0x9A, 0x23, 0x79, ++ 0x8D, 0xF8, 0x20, 0x20, 0xA8, 0x4A, 0x02, 0x98, 0x8D, 0xF8, 0x22, 0x30, ++ 0x41, 0xF2, 0xA8, 0x75, 0x41, 0xF2, 0xA9, 0x73, 0x16, 0x46, 0x54, 0x5B, ++ 0x01, 0x9F, 0x50, 0x55, 0x08, 0xA8, 0xD7, 0x54, 0xFF, 0xF7, 0x04, 0xFE, ++ 0x74, 0x53, 0x2B, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x98, 0xF8, 0x00, 0x30, ++ 0x00, 0x9A, 0x93, 0x42, 0x4C, 0xD0, 0x34, 0x9B, 0x09, 0xF1, 0x01, 0x09, ++ 0x4B, 0x45, 0xC1, 0xD1, 0xF1, 0xE7, 0x04, 0x21, 0xDA, 0xE7, 0xA3, 0x2C, ++ 0x00, 0xF0, 0x25, 0x81, 0xA4, 0x2C, 0x40, 0xF0, 0x18, 0x81, 0x98, 0x78, ++ 0x88, 0xF8, 0x20, 0x00, 0x52, 0x1A, 0x92, 0xB2, 0x02, 0x2A, 0x0B, 0x44, ++ 0x00, 0xF2, 0x82, 0x80, 0x98, 0xF8, 0x03, 0x30, 0x01, 0x2B, 0x3E, 0x46, ++ 0x03, 0x9F, 0x2C, 0xD8, 0x04, 0x9C, 0x72, 0x2C, 0x23, 0x46, 0x94, 0xBF, ++ 0x00, 0x23, 0x01, 0x23, 0x88, 0xF8, 0x64, 0x30, 0x00, 0x2E, 0x00, 0xF0, ++ 0x2B, 0x81, 0xB6, 0xF8, 0x03, 0x20, 0xB1, 0x78, 0xB0, 0x88, 0x88, 0xF8, ++ 0x66, 0x40, 0x41, 0xF2, 0x88, 0x33, 0x9A, 0x42, 0x94, 0xBF, 0x00, 0x22, ++ 0x01, 0x22, 0x01, 0x23, 0x88, 0xF8, 0x64, 0x20, 0x88, 0xF8, 0x65, 0x30, ++ 0x00, 0x29, 0x40, 0xF0, 0x03, 0x81, 0x05, 0x9A, 0x88, 0xF8, 0x64, 0x10, ++ 0x94, 0x42, 0x06, 0xD0, 0x80, 0xF0, 0x59, 0x81, 0x04, 0x9B, 0x04, 0x33, ++ 0x88, 0xF8, 0x67, 0x30, 0x02, 0x23, 0x88, 0xF8, 0x65, 0x30, 0x00, 0x9B, ++ 0x88, 0xF8, 0x00, 0x30, 0x76, 0x4A, 0x13, 0x68, 0x01, 0x33, 0x08, 0xF1, ++ 0x88, 0x08, 0x13, 0x60, 0xAB, 0xE7, 0xEB, 0x1E, 0x0C, 0x2B, 0x40, 0xF2, ++ 0xDD, 0x80, 0xE3, 0x7A, 0x88, 0xF8, 0x03, 0x30, 0x02, 0x2B, 0x82, 0xD8, ++ 0x62, 0x79, 0x63, 0x7A, 0x04, 0x92, 0xA2, 0x79, 0x05, 0x92, 0xA8, 0xF8, ++ 0x30, 0x30, 0x08, 0xF1, 0x3A, 0x0E, 0x08, 0xF1, 0x34, 0x03, 0xA4, 0xEB, ++ 0x08, 0x01, 0x5A, 0x18, 0x12, 0xF8, 0x28, 0x2C, 0x03, 0xF8, 0x01, 0x2B, ++ 0x73, 0x45, 0xF8, 0xD1, 0xB8, 0xF8, 0x34, 0x20, 0x4F, 0xF6, 0xFF, 0x73, ++ 0x9A, 0x42, 0xA5, 0xF1, 0x10, 0x02, 0x08, 0xBF, 0x01, 0x23, 0x4F, 0xF0, ++ 0x02, 0x01, 0x92, 0xB2, 0x08, 0xBF, 0x88, 0xF8, 0x32, 0x30, 0x8A, 0x42, ++ 0x04, 0xF1, 0x12, 0x03, 0x88, 0xF8, 0x04, 0x10, 0x40, 0xF2, 0x47, 0x81, ++ 0x00, 0x21, 0x6F, 0xF0, 0x13, 0x00, 0x0C, 0x46, 0x6F, 0xF0, 0x08, 0x06, ++ 0x6F, 0xF0, 0x37, 0x0C, 0x0D, 0x46, 0xA0, 0xEB, 0x08, 0x01, 0x03, 0x97, ++ 0x06, 0x91, 0xA6, 0xEB, 0x08, 0x06, 0xAC, 0xEB, 0x08, 0x0C, 0x27, 0x46, ++ 0x58, 0x78, 0x1C, 0x78, 0x81, 0x1C, 0x91, 0x42, 0x00, 0xF2, 0x96, 0x80, ++ 0x0B, 0x2C, 0x3F, 0xF6, 0x66, 0xAF, 0x0B, 0x2C, 0x3F, 0xF6, 0x6C, 0xAF, ++ 0x0F, 0xF2, 0x04, 0x0B, 0x5B, 0xF8, 0x24, 0xF0, 0xA9, 0x58, 0x15, 0x00, ++ 0xB1, 0x56, 0x15, 0x00, 0x97, 0x58, 0x15, 0x00, 0xB1, 0x56, 0x15, 0x00, ++ 0xB1, 0x56, 0x15, 0x00, 0xB1, 0x56, 0x15, 0x00, 0xB1, 0x56, 0x15, 0x00, ++ 0xB1, 0x56, 0x15, 0x00, 0xB1, 0x56, 0x15, 0x00, 0xB1, 0x56, 0x15, 0x00, ++ 0x65, 0x58, 0x15, 0x00, 0x11, 0x58, 0x15, 0x00, 0x02, 0x29, 0x71, 0xD0, ++ 0x9C, 0x78, 0xFF, 0x2C, 0x7F, 0xF4, 0x4A, 0xAF, 0x00, 0xF1, 0xFF, 0x3B, ++ 0x5F, 0xFA, 0x8B, 0xFB, 0xBB, 0xF1, 0x08, 0x0F, 0x28, 0xBF, 0x4F, 0xF0, ++ 0x08, 0x0B, 0x01, 0x28, 0xC8, 0xF8, 0x14, 0xB0, 0x3F, 0xF4, 0x3C, 0xAF, ++ 0x08, 0xF1, 0x17, 0x00, 0xCD, 0xF8, 0x1C, 0xA0, 0xDD, 0xF8, 0x18, 0xA0, ++ 0x83, 0x44, 0x1C, 0x18, 0x14, 0xF8, 0x0A, 0x40, 0x00, 0xF8, 0x01, 0x4F, ++ 0x58, 0x45, 0xF8, 0xD1, 0x52, 0x1A, 0x92, 0xB2, 0x02, 0x2A, 0xDD, 0xF8, ++ 0x1C, 0xA0, 0x0B, 0x44, 0xAE, 0xD8, 0x2B, 0xE7, 0x8C, 0x1E, 0x08, 0x2C, ++ 0xA8, 0xBF, 0x08, 0x24, 0x02, 0x29, 0xC8, 0xF8, 0x08, 0x40, 0x3F, 0xF4, ++ 0x1D, 0xAF, 0x08, 0xF1, 0x0B, 0x00, 0x00, 0xEB, 0x04, 0x0B, 0x1C, 0x18, ++ 0xA4, 0x5D, 0x00, 0xF8, 0x01, 0x4F, 0x83, 0x45, 0xF9, 0xD1, 0x52, 0x1A, ++ 0x92, 0xB2, 0x02, 0x2A, 0x0B, 0x44, 0x95, 0xD8, 0x12, 0xE7, 0x52, 0x1A, ++ 0x92, 0xB2, 0x98, 0x78, 0x88, 0xF8, 0x04, 0x00, 0x02, 0x2A, 0x0B, 0x44, ++ 0x8C, 0xD8, 0x09, 0xE7, 0x22, 0x29, 0x25, 0xD8, 0x88, 0xF8, 0x3A, 0x00, ++ 0x00, 0x28, 0x3F, 0xF4, 0xFD, 0xAE, 0x00, 0xEB, 0x0E, 0x04, 0x70, 0x46, ++ 0x00, 0xEB, 0x03, 0x0B, 0x1B, 0xF8, 0x0C, 0xB0, 0x00, 0xF8, 0x01, 0xBF, ++ 0xA0, 0x42, 0xF7, 0xD1, 0x52, 0x1A, 0x92, 0xB2, 0x02, 0x2A, 0x0B, 0x44, ++ 0x3F, 0xF6, 0x74, 0xAF, 0xF0, 0xE6, 0x52, 0x1A, 0x92, 0xB2, 0x33, 0x2C, ++ 0x08, 0xBF, 0x1D, 0x46, 0x02, 0x2A, 0x0B, 0x44, 0x3F, 0xF6, 0x6A, 0xAF, ++ 0xE6, 0xE6, 0x1F, 0x46, 0xDE, 0xE6, 0x00, 0x23, 0x88, 0xF8, 0x65, 0x30, ++ 0xDA, 0xF8, 0x00, 0x40, 0x04, 0x21, 0xA9, 0xE6, 0x78, 0xEF, 0x17, 0x00, ++ 0x1C, 0x07, 0x18, 0x00, 0x88, 0x06, 0x18, 0x00, 0x01, 0x29, 0x08, 0xF1, ++ 0x66, 0x03, 0x00, 0xF0, 0x47, 0x81, 0x04, 0x9A, 0x41, 0x2A, 0x35, 0xBF, ++ 0x40, 0x20, 0x80, 0x20, 0x24, 0x22, 0x64, 0x22, 0x11, 0x1D, 0x03, 0xF8, ++ 0x01, 0x2B, 0xCA, 0xB2, 0x90, 0x42, 0xF9, 0xD2, 0x08, 0x23, 0xF4, 0xE6, ++ 0x05, 0x9B, 0xFF, 0x2B, 0x4E, 0xD0, 0x05, 0x9B, 0x00, 0x2B, 0x00, 0xF0, ++ 0x85, 0x80, 0x05, 0x9A, 0x88, 0xF8, 0x66, 0x20, 0x01, 0x23, 0x88, 0xF8, ++ 0x65, 0x30, 0x04, 0x9B, 0xA3, 0xF1, 0x53, 0x02, 0x08, 0xF1, 0x66, 0x03, ++ 0x2E, 0x2A, 0x30, 0xD8, 0xDF, 0xE8, 0x12, 0xF0, 0x39, 0x00, 0x31, 0x00, ++ 0x2F, 0x00, 0x2F, 0x00, 0x2F, 0x00, 0x2F, 0x00, 0x2F, 0x00, 0x2F, 0x00, ++ 0x2F, 0x00, 0x2F, 0x00, 0x2F, 0x00, 0x2F, 0x00, 0x2F, 0x00, 0x2F, 0x00, ++ 0x2F, 0x00, 0x2F, 0x00, 0x2F, 0x00, 0x2F, 0x00, 0x2F, 0x00, 0x2F, 0x00, ++ 0x2F, 0x00, 0x2F, 0x00, 0x2F, 0x00, 0x2F, 0x00, 0x2F, 0x00, 0x2F, 0x00, ++ 0x2F, 0x00, 0x2F, 0x00, 0x2F, 0x00, 0x2F, 0x00, 0x2F, 0x00, 0x2F, 0x00, ++ 0x2F, 0x00, 0x39, 0x00, 0x31, 0x00, 0x2F, 0x00, 0x39, 0x00, 0x31, 0x00, ++ 0x2F, 0x00, 0x39, 0x00, 0x31, 0x00, 0x2F, 0x00, 0x2F, 0x00, 0x39, 0x00, ++ 0x31, 0x00, 0x71, 0x01, 0x6E, 0x01, 0x01, 0x23, 0xAD, 0xE6, 0x05, 0x9B, ++ 0x04, 0x93, 0x04, 0x9B, 0x04, 0x3B, 0x88, 0xF8, 0x67, 0x30, 0x02, 0x23, ++ 0xA5, 0xE6, 0x05, 0x9B, 0x04, 0x93, 0x9D, 0xE6, 0x00, 0x2D, 0x8D, 0xD0, ++ 0xAB, 0x78, 0x04, 0x9A, 0x93, 0x42, 0x89, 0xD1, 0x68, 0x78, 0x43, 0x1E, ++ 0xDB, 0xB2, 0x1C, 0x2B, 0x28, 0xBF, 0x1C, 0x23, 0x59, 0x1E, 0x01, 0x28, ++ 0x05, 0xF1, 0x03, 0x05, 0xC9, 0xB2, 0x3F, 0xF4, 0x7D, 0xAF, 0x32, 0x46, ++ 0x08, 0xEB, 0x02, 0x04, 0xAE, 0x5C, 0x84, 0xF8, 0x66, 0x60, 0x91, 0x42, ++ 0x02, 0xF1, 0x01, 0x02, 0xF6, 0xD1, 0x01, 0x28, 0x3F, 0xF4, 0x70, 0xAF, ++ 0x88, 0xF8, 0x65, 0x30, 0x01, 0x2B, 0x7F, 0xF4, 0x80, 0xAE, 0x98, 0xF8, ++ 0x66, 0x30, 0x05, 0x93, 0x91, 0xE7, 0x98, 0xF8, 0x03, 0x30, 0x01, 0x2B, ++ 0x3F, 0xF6, 0x77, 0xAE, 0x04, 0x9B, 0x72, 0x2B, 0x94, 0xBF, 0x00, 0x23, ++ 0x01, 0x23, 0x88, 0xF8, 0x64, 0x30, 0x05, 0x9B, 0xFF, 0x2B, 0x7F, 0xF4, ++ 0x78, 0xAF, 0x55, 0xE7, 0x04, 0x9A, 0x08, 0xF1, 0x66, 0x03, 0x51, 0x3A, ++ 0x1E, 0x46, 0x30, 0x2A, 0x3F, 0xF6, 0x4B, 0xAF, 0x01, 0xA1, 0x51, 0xF8, ++ 0x22, 0xF0, 0x00, 0xBF, 0x9B, 0x5B, 0x15, 0x00, 0x27, 0x5C, 0x15, 0x00, ++ 0x9B, 0x5B, 0x15, 0x00, 0x9B, 0x5B, 0x15, 0x00, 0xF3, 0x58, 0x15, 0x00, ++ 0xF3, 0x58, 0x15, 0x00, 0xF3, 0x58, 0x15, 0x00, 0xF3, 0x58, 0x15, 0x00, ++ 0xF3, 0x58, 0x15, 0x00, 0xF3, 0x58, 0x15, 0x00, 0xF3, 0x58, 0x15, 0x00, ++ 0xF3, 0x58, 0x15, 0x00, 0xF3, 0x58, 0x15, 0x00, 0xF3, 0x58, 0x15, 0x00, ++ 0xF3, 0x58, 0x15, 0x00, 0xF3, 0x58, 0x15, 0x00, 0xF3, 0x58, 0x15, 0x00, ++ 0xF3, 0x58, 0x15, 0x00, 0xF3, 0x58, 0x15, 0x00, 0xF3, 0x58, 0x15, 0x00, ++ 0xF3, 0x58, 0x15, 0x00, 0xF3, 0x58, 0x15, 0x00, 0xF3, 0x58, 0x15, 0x00, ++ 0xF3, 0x58, 0x15, 0x00, 0xF3, 0x58, 0x15, 0x00, 0xF3, 0x58, 0x15, 0x00, ++ 0xF3, 0x58, 0x15, 0x00, 0xF3, 0x58, 0x15, 0x00, 0xF3, 0x58, 0x15, 0x00, ++ 0xF3, 0x58, 0x15, 0x00, 0xF3, 0x58, 0x15, 0x00, 0xF3, 0x58, 0x15, 0x00, ++ 0xF3, 0x58, 0x15, 0x00, 0xF3, 0x58, 0x15, 0x00, 0x91, 0x5B, 0x15, 0x00, ++ 0x91, 0x5B, 0x15, 0x00, 0x91, 0x5B, 0x15, 0x00, 0x87, 0x5B, 0x15, 0x00, ++ 0x87, 0x5B, 0x15, 0x00, 0x87, 0x5B, 0x15, 0x00, 0x7D, 0x5B, 0x15, 0x00, ++ 0x7D, 0x5B, 0x15, 0x00, 0x7D, 0x5B, 0x15, 0x00, 0x29, 0x5B, 0x15, 0x00, ++ 0x03, 0x5C, 0x15, 0x00, 0x29, 0x5B, 0x15, 0x00, 0x29, 0x5B, 0x15, 0x00, ++ 0xE9, 0x5B, 0x15, 0x00, 0x0D, 0x5C, 0x15, 0x00, 0x00, 0x25, 0x04, 0x20, ++ 0xA2, 0x24, 0x95, 0x22, 0x71, 0x1E, 0x0B, 0x46, 0x02, 0x33, 0x01, 0xF8, ++ 0x01, 0x2F, 0x02, 0x44, 0x2B, 0x44, 0x94, 0x42, 0xA3, 0xEB, 0x06, 0x03, ++ 0xF5, 0xDC, 0x40, 0x4A, 0xDB, 0xB2, 0x12, 0x68, 0x88, 0xF8, 0x65, 0x30, ++ 0xB2, 0xF9, 0x00, 0x20, 0x00, 0x2A, 0x03, 0xDB, 0x00, 0x2B, 0x7F, 0xF4, ++ 0x5F, 0xAF, 0xCB, 0xE6, 0x1C, 0x2B, 0xF9, 0xD9, 0x39, 0x49, 0x3A, 0x48, ++ 0x40, 0xF2, 0x01, 0x32, 0xEF, 0xF7, 0x06, 0xF8, 0x98, 0xF8, 0x65, 0x30, ++ 0x00, 0x2B, 0x7F, 0xF4, 0x51, 0xAF, 0xBD, 0xE6, 0x00, 0x25, 0x04, 0x20, ++ 0x91, 0x24, 0x64, 0x22, 0xD4, 0xE7, 0x00, 0x25, 0x04, 0x20, 0x41, 0x24, ++ 0x34, 0x22, 0xCF, 0xE7, 0x00, 0x25, 0x04, 0x20, 0x31, 0x24, 0x24, 0x22, ++ 0xCA, 0xE7, 0x01, 0x20, 0x02, 0x46, 0x00, 0x25, 0x0E, 0x24, 0xC5, 0xE7, ++ 0x00, 0x28, 0x7F, 0xF4, 0xB6, 0xAE, 0x04, 0x9A, 0x23, 0x2A, 0x7F, 0xF6, ++ 0x06, 0xAF, 0x30, 0x2A, 0x15, 0xD9, 0x40, 0x2A, 0x10, 0xD9, 0x70, 0x2A, ++ 0x3B, 0xD9, 0x80, 0x2A, 0x36, 0xD9, 0x90, 0x2A, 0x3F, 0xF6, 0xFB, 0xAE, ++ 0x90, 0x21, 0x84, 0x22, 0x10, 0x1D, 0x03, 0xF8, 0x01, 0x2B, 0xC2, 0xB2, ++ 0x91, 0x42, 0xF9, 0xD2, 0x04, 0x23, 0xA0, 0xE5, 0x40, 0x21, 0x34, 0x22, ++ 0xF4, 0xE7, 0x30, 0x21, 0x24, 0x22, 0xF1, 0xE7, 0x24, 0x22, 0x03, 0xF8, ++ 0x01, 0x2B, 0x04, 0x32, 0x44, 0x2A, 0xFA, 0xD1, 0x08, 0xF1, 0x6E, 0x06, ++ 0x08, 0x25, 0x04, 0x20, 0x91, 0x24, 0x64, 0x22, 0x96, 0xE7, 0x00, 0x25, ++ 0x04, 0x20, 0xAA, 0x24, 0x95, 0x22, 0x91, 0xE7, 0x24, 0x22, 0x03, 0xF8, ++ 0x01, 0x2B, 0x04, 0x32, 0x44, 0x2A, 0xFA, 0xD1, 0x08, 0xF1, 0x6E, 0x06, ++ 0x08, 0x25, 0x04, 0x20, 0x81, 0x24, 0x64, 0x22, 0x84, 0xE7, 0x0F, 0x24, ++ 0x01, 0x20, 0x00, 0x25, 0x0E, 0x22, 0x7F, 0xE7, 0x80, 0x21, 0x74, 0x22, ++ 0xCA, 0xE7, 0x70, 0x21, 0x64, 0x22, 0xC7, 0xE7, 0x05, 0x9A, 0x04, 0x92, ++ 0x69, 0xE6, 0x05, 0x9A, 0x04, 0x92, 0xB0, 0xE7, 0x38, 0x36, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x5C, 0xD1, 0x15, 0x00, 0x70, 0xB5, 0x15, 0x4D, ++ 0x2C, 0x68, 0xA5, 0xF5, 0xBD, 0x56, 0x01, 0x34, 0xA5, 0xF1, 0x90, 0x01, ++ 0x2C, 0x60, 0x33, 0x46, 0x01, 0x20, 0x9A, 0x88, 0x01, 0x2A, 0x88, 0xBF, ++ 0x98, 0x80, 0x03, 0xF5, 0xF6, 0x73, 0x8B, 0x42, 0xF7, 0xD1, 0x41, 0xF2, ++ 0xA4, 0x73, 0xF3, 0x58, 0x9C, 0x42, 0x0B, 0xDA, 0x04, 0x21, 0x0B, 0x20, ++ 0xED, 0xF7, 0x90, 0xF8, 0x0B, 0x22, 0xBD, 0xE8, 0x70, 0x40, 0x11, 0x46, ++ 0x4F, 0xF4, 0x30, 0x50, 0xEC, 0xF7, 0xF6, 0xBE, 0x00, 0x21, 0x0B, 0x20, ++ 0xED, 0xF7, 0x84, 0xF8, 0x4F, 0xF0, 0xFF, 0x33, 0x2B, 0x60, 0x70, 0xBD, ++ 0x18, 0x07, 0x18, 0x00, 0x2D, 0xE9, 0xF8, 0x43, 0x3E, 0x4C, 0x3F, 0x4E, ++ 0x04, 0xF5, 0xBD, 0x53, 0x31, 0x68, 0x1B, 0x68, 0xB1, 0xF9, 0x00, 0x10, ++ 0x03, 0xEB, 0x03, 0x13, 0x04, 0xEB, 0xC3, 0x05, 0x05, 0xF5, 0xB8, 0x55, ++ 0x00, 0x29, 0x05, 0xF1, 0x10, 0x05, 0x4F, 0xEA, 0xC3, 0x03, 0x3A, 0xDB, ++ 0x23, 0x44, 0x41, 0xF2, 0x13, 0x72, 0x9B, 0x5C, 0x01, 0x2B, 0x45, 0xD9, ++ 0x02, 0x2B, 0x50, 0xD1, 0x02, 0x21, 0x0B, 0x20, 0xED, 0xF7, 0x5C, 0xF8, ++ 0x30, 0x48, 0x2E, 0x4C, 0xA0, 0xF1, 0x88, 0x06, 0x06, 0xF1, 0x88, 0x09, ++ 0xED, 0xF7, 0xE4, 0xFA, 0x00, 0x27, 0x4F, 0xF0, 0x02, 0x08, 0x03, 0xE0, ++ 0x04, 0xF5, 0xF6, 0x74, 0xB4, 0x42, 0x18, 0xD0, 0xA3, 0x88, 0x01, 0x2B, ++ 0xF8, 0xD1, 0x63, 0x7D, 0x04, 0xF1, 0x1C, 0x01, 0x19, 0x44, 0x2A, 0x46, ++ 0xA0, 0x1D, 0xFF, 0xF7, 0x15, 0xFB, 0x00, 0x28, 0xEE, 0xD0, 0x21, 0x46, ++ 0x27, 0x83, 0xE7, 0x75, 0xA4, 0xF8, 0x04, 0x80, 0x48, 0x46, 0x04, 0xF5, ++ 0xF6, 0x74, 0xED, 0xF7, 0xC9, 0xFA, 0xB4, 0x42, 0xE6, 0xD1, 0x28, 0x46, ++ 0x00, 0x21, 0xBD, 0xE8, 0xF8, 0x43, 0xFF, 0xF7, 0x99, 0xBA, 0x1C, 0x44, ++ 0x41, 0xF2, 0x12, 0x73, 0xE3, 0x5C, 0x05, 0x2B, 0x19, 0xD0, 0x17, 0x49, ++ 0x17, 0x48, 0x40, 0xF2, 0xA3, 0x62, 0xEE, 0xF7, 0x09, 0xFF, 0x41, 0xF2, ++ 0x13, 0x73, 0xE3, 0x5C, 0x01, 0x2B, 0x05, 0xD8, 0x28, 0x46, 0x01, 0x21, ++ 0xBD, 0xE8, 0xF8, 0x43, 0xFF, 0xF7, 0x24, 0xBB, 0x02, 0x2B, 0xB3, 0xD0, ++ 0x33, 0x68, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x08, 0xDB, 0xBD, 0xE8, ++ 0xF8, 0x83, 0x41, 0xF2, 0x13, 0x73, 0xE3, 0x5C, 0x01, 0x2B, 0xEB, 0xD9, ++ 0x02, 0x2B, 0xA5, 0xD0, 0xBD, 0xE8, 0xF8, 0x43, 0x05, 0x49, 0x07, 0x48, ++ 0x40, 0xF2, 0xAF, 0x62, 0xEE, 0xF7, 0xE6, 0xBE, 0x78, 0xEF, 0x17, 0x00, ++ 0x38, 0x36, 0x17, 0x00, 0x10, 0x07, 0x18, 0x00, 0x70, 0x79, 0x15, 0x00, ++ 0x94, 0xD1, 0x15, 0x00, 0x64, 0x7D, 0x15, 0x00, 0x2D, 0xE9, 0xF0, 0x41, ++ 0xDF, 0xF8, 0xCC, 0x80, 0x2C, 0x4A, 0xD8, 0xF8, 0x00, 0x30, 0x14, 0x68, ++ 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x0C, 0xDB, 0x29, 0x4F, 0x04, 0xEB, ++ 0x04, 0x13, 0x07, 0xEB, 0xC3, 0x03, 0x41, 0xF2, 0x13, 0x72, 0x25, 0x01, ++ 0x9B, 0x5C, 0x01, 0x2B, 0x19, 0xD9, 0xBD, 0xE8, 0xF0, 0x81, 0x00, 0x2C, ++ 0x35, 0xDB, 0x22, 0x4F, 0x04, 0xEB, 0x04, 0x16, 0x07, 0xEB, 0xC6, 0x06, ++ 0x41, 0xF2, 0x12, 0x73, 0x25, 0x01, 0xF3, 0x5C, 0x05, 0x2B, 0x15, 0xD0, ++ 0x1D, 0x49, 0x1E, 0x48, 0x4F, 0xF4, 0xD7, 0x62, 0xEE, 0xF7, 0xAE, 0xFE, ++ 0x41, 0xF2, 0x13, 0x73, 0xF3, 0x5C, 0x01, 0x2B, 0x17, 0xD8, 0x2C, 0x44, ++ 0x07, 0xEB, 0xC4, 0x00, 0x00, 0xF5, 0xB8, 0x50, 0xBD, 0xE8, 0xF0, 0x41, ++ 0x10, 0x30, 0x00, 0x21, 0xFF, 0xF7, 0xC4, 0xBA, 0x41, 0xF2, 0x13, 0x73, ++ 0xF3, 0x5C, 0x01, 0x2B, 0xEF, 0xD9, 0xBD, 0xE8, 0xF0, 0x41, 0x0F, 0x49, ++ 0x10, 0x48, 0x40, 0xF2, 0xC1, 0x62, 0xEE, 0xF7, 0x91, 0xBE, 0xD8, 0xF8, ++ 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xF1, 0xDB, 0xBD, 0xE8, ++ 0xF0, 0x81, 0x08, 0x49, 0x0A, 0x48, 0x40, 0xF2, 0xB7, 0x62, 0xEE, 0xF7, ++ 0x83, 0xFE, 0xD8, 0xF8, 0x00, 0x30, 0xB3, 0xF9, 0x00, 0x30, 0x00, 0x2B, ++ 0xBD, 0xDB, 0xAD, 0xE7, 0x18, 0x07, 0x18, 0x00, 0x78, 0xEF, 0x17, 0x00, ++ 0x70, 0x79, 0x15, 0x00, 0x94, 0xD1, 0x15, 0x00, 0x64, 0x7D, 0x15, 0x00, ++ 0xC0, 0xD1, 0x15, 0x00, 0x38, 0x36, 0x17, 0x00, 0x70, 0xB5, 0x29, 0xB3, ++ 0x18, 0x4C, 0x04, 0xF5, 0xBD, 0x53, 0x05, 0x46, 0x1E, 0x68, 0xFE, 0xF7, ++ 0x01, 0xFF, 0x02, 0x46, 0x40, 0xB1, 0x0B, 0x20, 0xED, 0xF7, 0x20, 0xF8, ++ 0x03, 0x28, 0x1F, 0xD0, 0xBD, 0xE8, 0x70, 0x40, 0xFF, 0xF7, 0xC6, 0xBE, ++ 0x06, 0xEB, 0x06, 0x16, 0x04, 0xEB, 0xC6, 0x03, 0x01, 0x21, 0x03, 0xF5, ++ 0xB8, 0x53, 0x85, 0xF8, 0x5E, 0x10, 0x10, 0x33, 0x01, 0x46, 0x28, 0x46, ++ 0xFE, 0xF7, 0x00, 0xFF, 0x28, 0x46, 0x03, 0x21, 0xBD, 0xE8, 0x70, 0x40, ++ 0xDA, 0xF7, 0x42, 0xB8, 0x0B, 0x20, 0xEC, 0xF7, 0x5B, 0xFF, 0x05, 0x4B, ++ 0x4F, 0xF0, 0xFF, 0x32, 0x1A, 0x60, 0x70, 0xBD, 0xBD, 0xE8, 0x70, 0x40, ++ 0xFF, 0xF7, 0x60, 0xBF, 0x78, 0xEF, 0x17, 0x00, 0x18, 0x07, 0x18, 0x00, ++ 0x2D, 0xE9, 0xF0, 0x4F, 0x8B, 0xB0, 0xB6, 0x4F, 0x9D, 0xF8, 0x50, 0x40, ++ 0x03, 0x94, 0x9D, 0xF9, 0x54, 0x40, 0x04, 0x94, 0x07, 0xF5, 0xBD, 0x55, ++ 0x04, 0x46, 0x28, 0x68, 0x25, 0x7C, 0x8D, 0xF8, 0x20, 0x50, 0x65, 0x7C, ++ 0x8D, 0xF8, 0x21, 0x50, 0xA5, 0x7C, 0x8D, 0xF8, 0x22, 0x50, 0xE5, 0x7C, ++ 0x8D, 0xF8, 0x23, 0x50, 0x25, 0x7D, 0x8D, 0xF8, 0x24, 0x50, 0x00, 0x28, ++ 0x65, 0x7D, 0x9D, 0xF8, 0x58, 0x90, 0x8D, 0xF8, 0x25, 0x50, 0x0E, 0x46, ++ 0x90, 0x46, 0x05, 0x93, 0xC0, 0xF2, 0x1A, 0x81, 0x00, 0xEB, 0x00, 0x10, ++ 0x07, 0xEB, 0xC0, 0x00, 0x00, 0xF5, 0xB8, 0x57, 0x10, 0x37, 0x3A, 0x46, ++ 0x00, 0x21, 0x08, 0xA8, 0xFF, 0xF7, 0xEE, 0xF9, 0x10, 0xB9, 0x0B, 0xB0, ++ 0xBD, 0xE8, 0xF0, 0x8F, 0xBD, 0xF8, 0x20, 0x00, 0xBD, 0xF8, 0x24, 0x30, ++ 0x01, 0x93, 0x00, 0x21, 0xBD, 0xF8, 0x22, 0xE0, 0x97, 0x4B, 0x98, 0x4A, ++ 0x02, 0x94, 0x8C, 0x46, 0x0D, 0x46, 0x83, 0x46, 0x0B, 0xE0, 0x98, 0x88, ++ 0x01, 0x28, 0x00, 0xF0, 0xC1, 0x80, 0x03, 0x28, 0x00, 0xF0, 0xB4, 0x80, ++ 0x88, 0xB1, 0x03, 0xF5, 0xF6, 0x73, 0x93, 0x42, 0x14, 0xD0, 0xB3, 0xF8, ++ 0x06, 0xA0, 0xDA, 0x45, 0xEF, 0xD1, 0x18, 0x89, 0x70, 0x45, 0xEC, 0xD1, ++ 0x58, 0x89, 0x01, 0x9C, 0xA0, 0x42, 0xE8, 0xD1, 0x02, 0x9C, 0x1D, 0x46, ++ 0x10, 0xE0, 0x00, 0x2D, 0x08, 0xBF, 0x1D, 0x46, 0x03, 0xF5, 0xF6, 0x73, ++ 0x93, 0x42, 0xEA, 0xD1, 0x02, 0x9C, 0x00, 0x2D, 0x00, 0xF0, 0x42, 0x81, ++ 0x4F, 0xF4, 0xF6, 0x72, 0x00, 0x21, 0x28, 0x46, 0xCA, 0xF7, 0xDC, 0xF8, ++ 0xAB, 0x88, 0x03, 0x2B, 0xBF, 0xD0, 0x03, 0x9B, 0xBD, 0xF8, 0x20, 0x10, ++ 0xBD, 0xF8, 0x22, 0x20, 0xC5, 0xF8, 0x0C, 0x80, 0x00, 0x2B, 0xBD, 0xF8, ++ 0x24, 0x30, 0x6B, 0x81, 0x08, 0xBF, 0x05, 0x20, 0x05, 0xF1, 0x1C, 0x03, ++ 0x18, 0xBF, 0x04, 0x20, 0x02, 0x93, 0x04, 0xF1, 0x24, 0x08, 0x85, 0xF8, ++ 0x11, 0x90, 0xA8, 0x74, 0xE9, 0x80, 0x2A, 0x81, 0x18, 0x34, 0x05, 0xF1, ++ 0x1B, 0x03, 0x14, 0xF8, 0x01, 0x2B, 0x03, 0xF8, 0x01, 0x2F, 0x44, 0x45, ++ 0xF9, 0xD1, 0x02, 0x9B, 0xA6, 0xF1, 0x24, 0x09, 0x03, 0xF1, 0x0C, 0x0B, ++ 0xB9, 0xF1, 0x02, 0x0F, 0x4F, 0xF0, 0x00, 0x03, 0xCD, 0xE9, 0x06, 0x33, ++ 0x40, 0xF3, 0x56, 0x81, 0x4F, 0xF4, 0xE2, 0x7A, 0x3A, 0x46, 0x98, 0xF8, ++ 0x01, 0x40, 0x98, 0xF8, 0x00, 0x60, 0x98, 0xF8, 0x02, 0x70, 0x02, 0x34, ++ 0x08, 0xF1, 0x02, 0x00, 0x00, 0x2E, 0x71, 0xD0, 0x03, 0x2E, 0x7D, 0xD0, ++ 0xA9, 0x7C, 0x05, 0x29, 0x00, 0xF2, 0x81, 0x80, 0x2A, 0x2E, 0x00, 0xF0, ++ 0x8D, 0x80, 0x3D, 0x2E, 0x00, 0xF0, 0x8D, 0x80, 0xC0, 0x2E, 0x00, 0xF0, ++ 0x9A, 0x80, 0xFF, 0x2E, 0x02, 0xD1, 0x08, 0x2C, 0x00, 0xF2, 0xCD, 0x80, ++ 0x54, 0x45, 0x07, 0xDC, 0x39, 0x46, 0x30, 0x46, 0x01, 0x92, 0xFE, 0xF7, ++ 0xD5, 0xFD, 0x01, 0x9A, 0x00, 0x28, 0x46, 0xD1, 0xA0, 0x44, 0xA9, 0xEB, ++ 0x04, 0x09, 0xB9, 0xF1, 0x02, 0x0F, 0xD0, 0xDC, 0xCA, 0xF5, 0xE8, 0x7A, ++ 0x1F, 0xFA, 0x8A, 0xFA, 0xAB, 0x7D, 0xA5, 0xF8, 0x1A, 0xA0, 0x00, 0x2B, ++ 0x00, 0xF0, 0x94, 0x80, 0x04, 0x9B, 0x2B, 0x75, 0x2B, 0x7C, 0x06, 0x9A, ++ 0x04, 0x2A, 0x00, 0xF0, 0x06, 0x81, 0x03, 0x2A, 0x00, 0xF0, 0x05, 0x81, ++ 0x02, 0x2A, 0x00, 0xF0, 0x04, 0x81, 0x03, 0x99, 0x00, 0x29, 0x40, 0xF0, ++ 0xC0, 0x80, 0x0E, 0x2B, 0x00, 0xF0, 0x14, 0x81, 0x00, 0x2A, 0x00, 0xF0, ++ 0x06, 0x81, 0x07, 0x9B, 0x01, 0x2B, 0x0C, 0xBF, 0x54, 0x23, 0x53, 0x23, ++ 0x01, 0x22, 0xEB, 0x74, 0xAA, 0x80, 0x0B, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, ++ 0x00, 0x29, 0x41, 0xD0, 0x93, 0xF9, 0x14, 0xA0, 0x91, 0xF9, 0x14, 0x00, ++ 0x82, 0x45, 0xB8, 0xBF, 0x19, 0x46, 0x42, 0xE7, 0xBC, 0xF1, 0x00, 0x0F, ++ 0x34, 0xD0, 0x93, 0xF9, 0x14, 0xA0, 0x9C, 0xF9, 0x14, 0x00, 0x82, 0x45, ++ 0xB8, 0xBF, 0x9C, 0x46, 0x37, 0xE7, 0x43, 0x46, 0xAB, 0xEB, 0x03, 0x00, ++ 0xA0, 0x44, 0x19, 0x78, 0xC1, 0x54, 0x01, 0x33, 0x98, 0x45, 0xFA, 0xD1, ++ 0xA3, 0x44, 0xAA, 0xEB, 0x04, 0x0A, 0xAC, 0xE7, 0x02, 0x9B, 0x01, 0x92, ++ 0xAB, 0xEB, 0x03, 0x01, 0x69, 0x75, 0xA8, 0x1D, 0x41, 0x46, 0xFF, 0xF7, ++ 0xF5, 0xF8, 0x01, 0x9A, 0x00, 0x28, 0x95, 0xD1, 0xA8, 0x80, 0x02, 0xE7, ++ 0x02, 0x9B, 0xAB, 0xEB, 0x03, 0x01, 0xA9, 0x75, 0x01, 0x78, 0x29, 0x74, ++ 0x8C, 0xE7, 0x06, 0x29, 0x3F, 0xF4, 0x7F, 0xAF, 0x08, 0x29, 0x7F, 0xF6, ++ 0x7F, 0xAF, 0x0D, 0x29, 0x84, 0xD8, 0x7E, 0xE7, 0x00, 0x27, 0xEA, 0xE6, ++ 0x9C, 0x46, 0x08, 0xE7, 0x19, 0x46, 0x06, 0xE7, 0x06, 0x21, 0xA9, 0x74, ++ 0x7A, 0xE7, 0x18, 0x2C, 0x7F, 0xF4, 0x78, 0xAF, 0x4F, 0xF0, 0x07, 0x03, ++ 0xAB, 0x74, 0x98, 0xF8, 0x03, 0x10, 0x11, 0xF0, 0x03, 0x03, 0x07, 0x93, ++ 0x06, 0x9B, 0x18, 0xBF, 0x01, 0x23, 0x06, 0x93, 0x6A, 0xE7, 0x07, 0x2C, ++ 0x7F, 0xF4, 0x68, 0xAF, 0x4F, 0xF0, 0x09, 0x03, 0xAB, 0x74, 0x01, 0x78, ++ 0x00, 0x29, 0x3F, 0xF4, 0x61, 0xAF, 0x01, 0x29, 0x76, 0xD0, 0x02, 0x29, ++ 0x00, 0xF0, 0x97, 0x80, 0x03, 0x29, 0x06, 0x9B, 0x08, 0xBF, 0x04, 0x23, ++ 0x06, 0x93, 0x55, 0xE7, 0x78, 0xEF, 0x17, 0x00, 0x88, 0x06, 0x18, 0x00, ++ 0xAA, 0x88, 0x22, 0xB1, 0x95, 0xF9, 0x14, 0x20, 0x04, 0x99, 0x8A, 0x42, ++ 0x60, 0xDA, 0x04, 0x9A, 0x2A, 0x75, 0x03, 0x9A, 0x00, 0x2A, 0x42, 0xD1, ++ 0x05, 0x99, 0xA1, 0xF6, 0x6C, 0x13, 0x48, 0x2B, 0x6D, 0xD8, 0x40, 0xF6, ++ 0xB4, 0x13, 0x99, 0x42, 0x00, 0xF0, 0x82, 0x80, 0x48, 0x4A, 0xA1, 0xF6, ++ 0x67, 0x13, 0xA2, 0xFB, 0x03, 0x23, 0xC3, 0xF3, 0x87, 0x03, 0x2B, 0x74, ++ 0x4F, 0xE7, 0x24, 0x2F, 0x7F, 0xF4, 0x30, 0xAF, 0x09, 0x29, 0x11, 0xD0, ++ 0x0B, 0x2C, 0x0F, 0xD9, 0xD8, 0xF8, 0x03, 0x10, 0x4B, 0x04, 0x0B, 0xD5, ++ 0x98, 0xF8, 0x09, 0x10, 0x41, 0xB1, 0x01, 0x29, 0x71, 0xD0, 0x02, 0x29, ++ 0x72, 0xD0, 0x03, 0x29, 0x06, 0x9B, 0x08, 0xBF, 0x04, 0x23, 0x06, 0x93, ++ 0x4F, 0xF0, 0x0E, 0x03, 0xAB, 0x74, 0x17, 0xE7, 0x89, 0xB3, 0x0D, 0x46, ++ 0xBA, 0xE6, 0x30, 0x2B, 0x24, 0xD9, 0x40, 0x2B, 0x40, 0xD9, 0x90, 0x2B, ++ 0x4C, 0xD9, 0xA4, 0x2B, 0x59, 0xD8, 0x06, 0x9B, 0x00, 0x2B, 0x54, 0xD0, ++ 0x0A, 0x23, 0x07, 0x9A, 0x01, 0x2A, 0x0C, 0xBF, 0x74, 0x33, 0x75, 0x33, ++ 0x38, 0xE7, 0x03, 0x9A, 0x01, 0x2A, 0xCA, 0xD1, 0x05, 0x9A, 0xA2, 0xF5, ++ 0x9C, 0x51, 0xA1, 0xF1, 0x0D, 0x02, 0x92, 0xB2, 0xB2, 0xF5, 0x4D, 0x7F, ++ 0xC1, 0xD8, 0x26, 0x4A, 0xA1, 0xF1, 0x08, 0x03, 0xA2, 0xFB, 0x03, 0x23, ++ 0xC3, 0xF3, 0x87, 0x03, 0x2B, 0x74, 0x0A, 0xE7, 0x06, 0x9B, 0x23, 0xB3, ++ 0x00, 0x23, 0xE0, 0xE7, 0x2B, 0x7C, 0x04, 0xE7, 0x02, 0x23, 0x06, 0x93, ++ 0xE4, 0xE6, 0xBC, 0xF1, 0x00, 0x0F, 0x3F, 0xF4, 0x50, 0xAE, 0x9C, 0xF9, ++ 0x14, 0x30, 0x04, 0x9A, 0x93, 0x42, 0xBF, 0xF6, 0x4A, 0xAE, 0x65, 0x46, ++ 0x7E, 0xE6, 0x82, 0x23, 0x0C, 0xE7, 0x81, 0x23, 0x0A, 0xE7, 0x80, 0x23, ++ 0x08, 0xE7, 0x03, 0x9B, 0x2B, 0x74, 0xEC, 0xE6, 0x06, 0x9B, 0x8B, 0xB1, ++ 0x03, 0x23, 0xC2, 0xE7, 0x4F, 0xF0, 0x0C, 0x0A, 0xDC, 0xE6, 0x51, 0x23, ++ 0xFC, 0xE6, 0x73, 0x23, 0xFA, 0xE6, 0x03, 0x23, 0x06, 0x93, 0xC1, 0xE6, ++ 0x06, 0x9B, 0x43, 0xB1, 0x06, 0x23, 0xB4, 0xE7, 0x52, 0x23, 0xF1, 0xE6, ++ 0x76, 0x23, 0xEF, 0xE6, 0x0E, 0x23, 0x2B, 0x74, 0xD3, 0xE6, 0x79, 0x23, ++ 0xEA, 0xE6, 0x7C, 0x23, 0xE8, 0xE6, 0x7D, 0x23, 0xE6, 0xE6, 0x02, 0x23, ++ 0x06, 0x93, 0x91, 0xE7, 0x03, 0x23, 0x06, 0x93, 0x8E, 0xE7, 0x00, 0xBF, ++ 0xCD, 0xCC, 0xCC, 0xCC, 0x2D, 0xE9, 0xF0, 0x48, 0xC1, 0xF3, 0x0A, 0x57, ++ 0xA7, 0xF2, 0xFF, 0x34, 0x13, 0x2C, 0x0B, 0x46, 0x0D, 0x46, 0x02, 0x46, ++ 0x0F, 0xDC, 0x00, 0x2C, 0x2A, 0xDB, 0x1D, 0x49, 0x21, 0x41, 0x03, 0xEA, ++ 0x01, 0x00, 0x10, 0x43, 0x2F, 0xD0, 0x4F, 0xF4, 0x00, 0x23, 0x23, 0x41, ++ 0x1D, 0x44, 0x25, 0xEA, 0x01, 0x05, 0x00, 0x23, 0x25, 0xE0, 0x33, 0x2C, ++ 0x07, 0xDD, 0xB4, 0xF5, 0x80, 0x6F, 0x22, 0xD1, 0x00, 0xF0, 0x2E, 0xF8, ++ 0x02, 0x46, 0x0B, 0x46, 0x1D, 0xE0, 0xA7, 0xF2, 0x13, 0x47, 0x4F, 0xF0, ++ 0xFF, 0x31, 0x21, 0xFA, 0x07, 0xF7, 0x38, 0x42, 0x15, 0xD0, 0x01, 0x22, ++ 0xC4, 0xF1, 0x33, 0x03, 0x02, 0xFA, 0x03, 0xF3, 0xC3, 0x18, 0x28, 0xBF, ++ 0xAD, 0x18, 0x23, 0xEA, 0x07, 0x03, 0x08, 0xE0, 0x01, 0xF0, 0x00, 0x45, ++ 0x01, 0x34, 0x04, 0xBF, 0x45, 0xF0, 0x7F, 0x55, 0x45, 0xF4, 0x40, 0x15, ++ 0x00, 0x23, 0x1A, 0x46, 0x2B, 0x46, 0x10, 0x46, 0x19, 0x46, 0xBD, 0xE8, ++ 0xF0, 0x88, 0x00, 0xBF, 0xFF, 0xFF, 0x0F, 0x00, 0x81, 0xF0, 0x00, 0x41, ++ 0x02, 0xE0, 0x00, 0xBF, 0x83, 0xF0, 0x00, 0x43, 0x30, 0xB5, 0x4F, 0xEA, ++ 0x41, 0x04, 0x4F, 0xEA, 0x43, 0x05, 0x94, 0xEA, 0x05, 0x0F, 0x08, 0xBF, ++ 0x90, 0xEA, 0x02, 0x0F, 0x1F, 0xBF, 0x54, 0xEA, 0x00, 0x0C, 0x55, 0xEA, ++ 0x02, 0x0C, 0x7F, 0xEA, 0x64, 0x5C, 0x7F, 0xEA, 0x65, 0x5C, 0x00, 0xF0, ++ 0xE2, 0x80, 0x4F, 0xEA, 0x54, 0x54, 0xD4, 0xEB, 0x55, 0x55, 0xB8, 0xBF, ++ 0x6D, 0x42, 0x0C, 0xDD, 0x2C, 0x44, 0x80, 0xEA, 0x02, 0x02, 0x81, 0xEA, ++ 0x03, 0x03, 0x82, 0xEA, 0x00, 0x00, 0x83, 0xEA, 0x01, 0x01, 0x80, 0xEA, ++ 0x02, 0x02, 0x81, 0xEA, 0x03, 0x03, 0x36, 0x2D, 0x88, 0xBF, 0x30, 0xBD, ++ 0x11, 0xF0, 0x00, 0x4F, 0x4F, 0xEA, 0x01, 0x31, 0x4F, 0xF4, 0x80, 0x1C, ++ 0x4C, 0xEA, 0x11, 0x31, 0x02, 0xD0, 0x40, 0x42, 0x61, 0xEB, 0x41, 0x01, ++ 0x13, 0xF0, 0x00, 0x4F, 0x4F, 0xEA, 0x03, 0x33, 0x4C, 0xEA, 0x13, 0x33, ++ 0x02, 0xD0, 0x52, 0x42, 0x63, 0xEB, 0x43, 0x03, 0x94, 0xEA, 0x05, 0x0F, ++ 0x00, 0xF0, 0xA7, 0x80, 0xA4, 0xF1, 0x01, 0x04, 0xD5, 0xF1, 0x20, 0x0E, ++ 0x0D, 0xDB, 0x02, 0xFA, 0x0E, 0xFC, 0x22, 0xFA, 0x05, 0xF2, 0x80, 0x18, ++ 0x41, 0xF1, 0x00, 0x01, 0x03, 0xFA, 0x0E, 0xF2, 0x80, 0x18, 0x43, 0xFA, ++ 0x05, 0xF3, 0x59, 0x41, 0x0E, 0xE0, 0xA5, 0xF1, 0x20, 0x05, 0x0E, 0xF1, ++ 0x20, 0x0E, 0x01, 0x2A, 0x03, 0xFA, 0x0E, 0xFC, 0x28, 0xBF, 0x4C, 0xF0, ++ 0x02, 0x0C, 0x43, 0xFA, 0x05, 0xF3, 0xC0, 0x18, 0x51, 0xEB, 0xE3, 0x71, ++ 0x01, 0xF0, 0x00, 0x45, 0x07, 0xD5, 0x4F, 0xF0, 0x00, 0x0E, 0xDC, 0xF1, ++ 0x00, 0x0C, 0x7E, 0xEB, 0x00, 0x00, 0x6E, 0xEB, 0x01, 0x01, 0xB1, 0xF5, ++ 0x80, 0x1F, 0x1B, 0xD3, 0xB1, 0xF5, 0x00, 0x1F, 0x0C, 0xD3, 0x49, 0x08, ++ 0x5F, 0xEA, 0x30, 0x00, 0x4F, 0xEA, 0x3C, 0x0C, 0x04, 0xF1, 0x01, 0x04, ++ 0x4F, 0xEA, 0x44, 0x52, 0x12, 0xF5, 0x80, 0x0F, 0x80, 0xF0, 0x9A, 0x80, ++ 0xBC, 0xF1, 0x00, 0x4F, 0x08, 0xBF, 0x5F, 0xEA, 0x50, 0x0C, 0x50, 0xF1, ++ 0x00, 0x00, 0x41, 0xEB, 0x04, 0x51, 0x41, 0xEA, 0x05, 0x01, 0x30, 0xBD, ++ 0x5F, 0xEA, 0x4C, 0x0C, 0x40, 0x41, 0x41, 0xEB, 0x01, 0x01, 0x01, 0x3C, ++ 0x28, 0xBF, 0xB1, 0xF5, 0x80, 0x1F, 0xE9, 0xD2, 0x91, 0xF0, 0x00, 0x0F, ++ 0x04, 0xBF, 0x01, 0x46, 0x00, 0x20, 0xB1, 0xFA, 0x81, 0xF3, 0x08, 0xBF, ++ 0x20, 0x33, 0xA3, 0xF1, 0x0B, 0x03, 0xB3, 0xF1, 0x20, 0x02, 0x0C, 0xDA, ++ 0x0C, 0x32, 0x08, 0xDD, 0x02, 0xF1, 0x14, 0x0C, 0xC2, 0xF1, 0x0C, 0x02, ++ 0x01, 0xFA, 0x0C, 0xF0, 0x21, 0xFA, 0x02, 0xF1, 0x0C, 0xE0, 0x02, 0xF1, ++ 0x14, 0x02, 0xD8, 0xBF, 0xC2, 0xF1, 0x20, 0x0C, 0x01, 0xFA, 0x02, 0xF1, ++ 0x20, 0xFA, 0x0C, 0xFC, 0xDC, 0xBF, 0x41, 0xEA, 0x0C, 0x01, 0x90, 0x40, ++ 0xE4, 0x1A, 0xA2, 0xBF, 0x01, 0xEB, 0x04, 0x51, 0x29, 0x43, 0x30, 0xBD, ++ 0x6F, 0xEA, 0x04, 0x04, 0x1F, 0x3C, 0x1C, 0xDA, 0x0C, 0x34, 0x0E, 0xDC, ++ 0x04, 0xF1, 0x14, 0x04, 0xC4, 0xF1, 0x20, 0x02, 0x20, 0xFA, 0x04, 0xF0, ++ 0x01, 0xFA, 0x02, 0xF3, 0x40, 0xEA, 0x03, 0x00, 0x21, 0xFA, 0x04, 0xF3, ++ 0x45, 0xEA, 0x03, 0x01, 0x30, 0xBD, 0xC4, 0xF1, 0x0C, 0x04, 0xC4, 0xF1, ++ 0x20, 0x02, 0x20, 0xFA, 0x02, 0xF0, 0x01, 0xFA, 0x04, 0xF3, 0x40, 0xEA, ++ 0x03, 0x00, 0x29, 0x46, 0x30, 0xBD, 0x21, 0xFA, 0x04, 0xF0, 0x29, 0x46, ++ 0x30, 0xBD, 0x94, 0xF0, 0x00, 0x0F, 0x83, 0xF4, 0x80, 0x13, 0x06, 0xBF, ++ 0x81, 0xF4, 0x80, 0x11, 0x01, 0x34, 0x01, 0x3D, 0x4E, 0xE7, 0x7F, 0xEA, ++ 0x64, 0x5C, 0x18, 0xBF, 0x7F, 0xEA, 0x65, 0x5C, 0x29, 0xD0, 0x94, 0xEA, ++ 0x05, 0x0F, 0x08, 0xBF, 0x90, 0xEA, 0x02, 0x0F, 0x05, 0xD0, 0x54, 0xEA, ++ 0x00, 0x0C, 0x04, 0xBF, 0x19, 0x46, 0x10, 0x46, 0x30, 0xBD, 0x91, 0xEA, ++ 0x03, 0x0F, 0x1E, 0xBF, 0x00, 0x21, 0x00, 0x20, 0x30, 0xBD, 0x5F, 0xEA, ++ 0x54, 0x5C, 0x05, 0xD1, 0x40, 0x00, 0x49, 0x41, 0x28, 0xBF, 0x41, 0xF0, ++ 0x00, 0x41, 0x30, 0xBD, 0x14, 0xF5, 0x80, 0x04, 0x3C, 0xBF, 0x01, 0xF5, ++ 0x80, 0x11, 0x30, 0xBD, 0x01, 0xF0, 0x00, 0x45, 0x45, 0xF0, 0xFE, 0x41, ++ 0x41, 0xF4, 0x70, 0x01, 0x4F, 0xF0, 0x00, 0x00, 0x30, 0xBD, 0x7F, 0xEA, ++ 0x64, 0x5C, 0x1A, 0xBF, 0x19, 0x46, 0x10, 0x46, 0x7F, 0xEA, 0x65, 0x5C, ++ 0x1C, 0xBF, 0x0B, 0x46, 0x02, 0x46, 0x50, 0xEA, 0x01, 0x34, 0x06, 0xBF, ++ 0x52, 0xEA, 0x03, 0x35, 0x91, 0xEA, 0x03, 0x0F, 0x41, 0xF4, 0x00, 0x21, ++ 0x30, 0xBD, 0x00, 0xBF, 0x90, 0xF0, 0x00, 0x0F, 0x04, 0xBF, 0x00, 0x21, ++ 0x70, 0x47, 0x30, 0xB5, 0x4F, 0xF4, 0x80, 0x64, 0x04, 0xF1, 0x32, 0x04, ++ 0x4F, 0xF0, 0x00, 0x05, 0x4F, 0xF0, 0x00, 0x01, 0x50, 0xE7, 0x00, 0xBF, ++ 0x90, 0xF0, 0x00, 0x0F, 0x04, 0xBF, 0x00, 0x21, 0x70, 0x47, 0x30, 0xB5, ++ 0x4F, 0xF4, 0x80, 0x64, 0x04, 0xF1, 0x32, 0x04, 0x10, 0xF0, 0x00, 0x45, ++ 0x48, 0xBF, 0x40, 0x42, 0x4F, 0xF0, 0x00, 0x01, 0x3E, 0xE7, 0x00, 0xBF, ++ 0x42, 0x00, 0x4F, 0xEA, 0xE2, 0x01, 0x4F, 0xEA, 0x31, 0x01, 0x4F, 0xEA, ++ 0x02, 0x70, 0x1F, 0xBF, 0x12, 0xF0, 0x7F, 0x43, 0x93, 0xF0, 0x7F, 0x4F, ++ 0x81, 0xF0, 0x60, 0x51, 0x70, 0x47, 0x32, 0xF0, 0x7F, 0x42, 0x08, 0xBF, ++ 0x70, 0x47, 0x93, 0xF0, 0x7F, 0x4F, 0x04, 0xBF, 0x41, 0xF4, 0x00, 0x21, ++ 0x70, 0x47, 0x30, 0xB5, 0x4F, 0xF4, 0x60, 0x74, 0x01, 0xF0, 0x00, 0x45, ++ 0x21, 0xF0, 0x00, 0x41, 0x1C, 0xE7, 0x00, 0xBF, 0x50, 0xEA, 0x01, 0x02, ++ 0x08, 0xBF, 0x70, 0x47, 0x30, 0xB5, 0x4F, 0xF0, 0x00, 0x05, 0x0A, 0xE0, ++ 0x50, 0xEA, 0x01, 0x02, 0x08, 0xBF, 0x70, 0x47, 0x30, 0xB5, 0x11, 0xF0, ++ 0x00, 0x45, 0x02, 0xD5, 0x40, 0x42, 0x61, 0xEB, 0x41, 0x01, 0x4F, 0xF4, ++ 0x80, 0x64, 0x04, 0xF1, 0x32, 0x04, 0x5F, 0xEA, 0x91, 0x5C, 0x3F, 0xF4, ++ 0xD8, 0xAE, 0x4F, 0xF0, 0x03, 0x02, 0x5F, 0xEA, 0xDC, 0x0C, 0x18, 0xBF, ++ 0x03, 0x32, 0x5F, 0xEA, 0xDC, 0x0C, 0x18, 0xBF, 0x03, 0x32, 0x02, 0xEB, ++ 0xDC, 0x02, 0xC2, 0xF1, 0x20, 0x03, 0x00, 0xFA, 0x03, 0xFC, 0x20, 0xFA, ++ 0x02, 0xF0, 0x01, 0xFA, 0x03, 0xFE, 0x40, 0xEA, 0x0E, 0x00, 0x21, 0xFA, ++ 0x02, 0xF1, 0x14, 0x44, 0xBD, 0xE6, 0x00, 0xBF, 0x70, 0xB5, 0x4F, 0xF0, ++ 0xFF, 0x0C, 0x4C, 0xF4, 0xE0, 0x6C, 0x1C, 0xEA, 0x11, 0x54, 0x1D, 0xBF, ++ 0x1C, 0xEA, 0x13, 0x55, 0x94, 0xEA, 0x0C, 0x0F, 0x95, 0xEA, 0x0C, 0x0F, ++ 0x00, 0xF0, 0xDE, 0xF8, 0x2C, 0x44, 0x81, 0xEA, 0x03, 0x06, 0x21, 0xEA, ++ 0x4C, 0x51, 0x23, 0xEA, 0x4C, 0x53, 0x50, 0xEA, 0x01, 0x35, 0x18, 0xBF, ++ 0x52, 0xEA, 0x03, 0x35, 0x41, 0xF4, 0x80, 0x11, 0x43, 0xF4, 0x80, 0x13, ++ 0x38, 0xD0, 0xA0, 0xFB, 0x02, 0xCE, 0x4F, 0xF0, 0x00, 0x05, 0xE1, 0xFB, ++ 0x02, 0xE5, 0x06, 0xF0, 0x00, 0x42, 0xE0, 0xFB, 0x03, 0xE5, 0x4F, 0xF0, ++ 0x00, 0x06, 0xE1, 0xFB, 0x03, 0x56, 0x9C, 0xF0, 0x00, 0x0F, 0x18, 0xBF, ++ 0x4E, 0xF0, 0x01, 0x0E, 0xA4, 0xF1, 0xFF, 0x04, 0xB6, 0xF5, 0x00, 0x7F, ++ 0x64, 0xF5, 0x40, 0x74, 0x04, 0xD2, 0x5F, 0xEA, 0x4E, 0x0E, 0x6D, 0x41, ++ 0x46, 0xEB, 0x06, 0x06, 0x42, 0xEA, 0xC6, 0x21, 0x41, 0xEA, 0x55, 0x51, ++ 0x4F, 0xEA, 0xC5, 0x20, 0x40, 0xEA, 0x5E, 0x50, 0x4F, 0xEA, 0xCE, 0x2E, ++ 0xB4, 0xF1, 0xFD, 0x0C, 0x88, 0xBF, 0xBC, 0xF5, 0xE0, 0x6F, 0x1E, 0xD8, ++ 0xBE, 0xF1, 0x00, 0x4F, 0x08, 0xBF, 0x5F, 0xEA, 0x50, 0x0E, 0x50, 0xF1, ++ 0x00, 0x00, 0x41, 0xEB, 0x04, 0x51, 0x70, 0xBD, 0x06, 0xF0, 0x00, 0x46, ++ 0x46, 0xEA, 0x01, 0x01, 0x40, 0xEA, 0x02, 0x00, 0x81, 0xEA, 0x03, 0x01, ++ 0xB4, 0xEB, 0x5C, 0x04, 0xC2, 0xBF, 0xD4, 0xEB, 0x0C, 0x05, 0x41, 0xEA, ++ 0x04, 0x51, 0x70, 0xBD, 0x41, 0xF4, 0x80, 0x11, 0x4F, 0xF0, 0x00, 0x0E, ++ 0x01, 0x3C, 0x00, 0xF3, 0xAB, 0x80, 0x14, 0xF1, 0x36, 0x0F, 0xDE, 0xBF, ++ 0x00, 0x20, 0x01, 0xF0, 0x00, 0x41, 0x70, 0xBD, 0xC4, 0xF1, 0x00, 0x04, ++ 0x20, 0x3C, 0x35, 0xDA, 0x0C, 0x34, 0x1B, 0xDC, 0x04, 0xF1, 0x14, 0x04, ++ 0xC4, 0xF1, 0x20, 0x05, 0x00, 0xFA, 0x05, 0xF3, 0x20, 0xFA, 0x04, 0xF0, ++ 0x01, 0xFA, 0x05, 0xF2, 0x40, 0xEA, 0x02, 0x00, 0x01, 0xF0, 0x00, 0x42, ++ 0x21, 0xF0, 0x00, 0x41, 0x10, 0xEB, 0xD3, 0x70, 0x21, 0xFA, 0x04, 0xF6, ++ 0x42, 0xEB, 0x06, 0x01, 0x5E, 0xEA, 0x43, 0x0E, 0x08, 0xBF, 0x20, 0xEA, ++ 0xD3, 0x70, 0x70, 0xBD, 0xC4, 0xF1, 0x0C, 0x04, 0xC4, 0xF1, 0x20, 0x05, ++ 0x00, 0xFA, 0x04, 0xF3, 0x20, 0xFA, 0x05, 0xF0, 0x01, 0xFA, 0x04, 0xF2, ++ 0x40, 0xEA, 0x02, 0x00, 0x01, 0xF0, 0x00, 0x41, 0x10, 0xEB, 0xD3, 0x70, ++ 0x41, 0xF1, 0x00, 0x01, 0x5E, 0xEA, 0x43, 0x0E, 0x08, 0xBF, 0x20, 0xEA, ++ 0xD3, 0x70, 0x70, 0xBD, 0xC4, 0xF1, 0x20, 0x05, 0x00, 0xFA, 0x05, 0xF2, ++ 0x4E, 0xEA, 0x02, 0x0E, 0x20, 0xFA, 0x04, 0xF3, 0x01, 0xFA, 0x05, 0xF2, ++ 0x43, 0xEA, 0x02, 0x03, 0x21, 0xFA, 0x04, 0xF0, 0x01, 0xF0, 0x00, 0x41, ++ 0x21, 0xFA, 0x04, 0xF2, 0x20, 0xEA, 0x02, 0x00, 0x00, 0xEB, 0xD3, 0x70, ++ 0x5E, 0xEA, 0x43, 0x0E, 0x08, 0xBF, 0x20, 0xEA, 0xD3, 0x70, 0x70, 0xBD, ++ 0x94, 0xF0, 0x00, 0x0F, 0x0F, 0xD1, 0x01, 0xF0, 0x00, 0x46, 0x40, 0x00, ++ 0x41, 0xEB, 0x01, 0x01, 0x11, 0xF4, 0x80, 0x1F, 0x08, 0xBF, 0x01, 0x3C, ++ 0xF7, 0xD0, 0x41, 0xEA, 0x06, 0x01, 0x95, 0xF0, 0x00, 0x0F, 0x18, 0xBF, ++ 0x70, 0x47, 0x03, 0xF0, 0x00, 0x46, 0x52, 0x00, 0x43, 0xEB, 0x03, 0x03, ++ 0x13, 0xF4, 0x80, 0x1F, 0x08, 0xBF, 0x01, 0x3D, 0xF7, 0xD0, 0x43, 0xEA, ++ 0x06, 0x03, 0x70, 0x47, 0x94, 0xEA, 0x0C, 0x0F, 0x0C, 0xEA, 0x13, 0x55, ++ 0x18, 0xBF, 0x95, 0xEA, 0x0C, 0x0F, 0x0C, 0xD0, 0x50, 0xEA, 0x41, 0x06, ++ 0x18, 0xBF, 0x52, 0xEA, 0x43, 0x06, 0xD1, 0xD1, 0x81, 0xEA, 0x03, 0x01, ++ 0x01, 0xF0, 0x00, 0x41, 0x4F, 0xF0, 0x00, 0x00, 0x70, 0xBD, 0x50, 0xEA, ++ 0x41, 0x06, 0x06, 0xBF, 0x10, 0x46, 0x19, 0x46, 0x52, 0xEA, 0x43, 0x06, ++ 0x19, 0xD0, 0x94, 0xEA, 0x0C, 0x0F, 0x02, 0xD1, 0x50, 0xEA, 0x01, 0x36, ++ 0x13, 0xD1, 0x95, 0xEA, 0x0C, 0x0F, 0x05, 0xD1, 0x52, 0xEA, 0x03, 0x36, ++ 0x1C, 0xBF, 0x10, 0x46, 0x19, 0x46, 0x0A, 0xD1, 0x81, 0xEA, 0x03, 0x01, ++ 0x01, 0xF0, 0x00, 0x41, 0x41, 0xF0, 0xFE, 0x41, 0x41, 0xF4, 0x70, 0x01, ++ 0x4F, 0xF0, 0x00, 0x00, 0x70, 0xBD, 0x41, 0xF0, 0xFE, 0x41, 0x41, 0xF4, ++ 0x78, 0x01, 0x70, 0xBD, 0x70, 0xB5, 0x4F, 0xF0, 0xFF, 0x0C, 0x4C, 0xF4, ++ 0xE0, 0x6C, 0x1C, 0xEA, 0x11, 0x54, 0x1D, 0xBF, 0x1C, 0xEA, 0x13, 0x55, ++ 0x94, 0xEA, 0x0C, 0x0F, 0x95, 0xEA, 0x0C, 0x0F, 0x00, 0xF0, 0xA7, 0xF8, ++ 0xA4, 0xEB, 0x05, 0x04, 0x81, 0xEA, 0x03, 0x0E, 0x52, 0xEA, 0x03, 0x35, ++ 0x4F, 0xEA, 0x01, 0x31, 0x00, 0xF0, 0x88, 0x80, 0x4F, 0xEA, 0x03, 0x33, ++ 0x4F, 0xF0, 0x80, 0x55, 0x45, 0xEA, 0x13, 0x13, 0x43, 0xEA, 0x12, 0x63, ++ 0x4F, 0xEA, 0x02, 0x22, 0x45, 0xEA, 0x11, 0x15, 0x45, 0xEA, 0x10, 0x65, ++ 0x4F, 0xEA, 0x00, 0x26, 0x0E, 0xF0, 0x00, 0x41, 0x9D, 0x42, 0x08, 0xBF, ++ 0x96, 0x42, 0x44, 0xF1, 0xFD, 0x04, 0x04, 0xF5, 0x40, 0x74, 0x02, 0xD2, ++ 0x5B, 0x08, 0x4F, 0xEA, 0x32, 0x02, 0xB6, 0x1A, 0x65, 0xEB, 0x03, 0x05, ++ 0x5B, 0x08, 0x4F, 0xEA, 0x32, 0x02, 0x4F, 0xF4, 0x80, 0x10, 0x4F, 0xF4, ++ 0x00, 0x2C, 0xB6, 0xEB, 0x02, 0x0E, 0x75, 0xEB, 0x03, 0x0E, 0x22, 0xBF, ++ 0xB6, 0x1A, 0x75, 0x46, 0x40, 0xEA, 0x0C, 0x00, 0x5B, 0x08, 0x4F, 0xEA, ++ 0x32, 0x02, 0xB6, 0xEB, 0x02, 0x0E, 0x75, 0xEB, 0x03, 0x0E, 0x22, 0xBF, ++ 0xB6, 0x1A, 0x75, 0x46, 0x40, 0xEA, 0x5C, 0x00, 0x5B, 0x08, 0x4F, 0xEA, ++ 0x32, 0x02, 0xB6, 0xEB, 0x02, 0x0E, 0x75, 0xEB, 0x03, 0x0E, 0x22, 0xBF, ++ 0xB6, 0x1A, 0x75, 0x46, 0x40, 0xEA, 0x9C, 0x00, 0x5B, 0x08, 0x4F, 0xEA, ++ 0x32, 0x02, 0xB6, 0xEB, 0x02, 0x0E, 0x75, 0xEB, 0x03, 0x0E, 0x22, 0xBF, ++ 0xB6, 0x1A, 0x75, 0x46, 0x40, 0xEA, 0xDC, 0x00, 0x55, 0xEA, 0x06, 0x0E, ++ 0x18, 0xD0, 0x4F, 0xEA, 0x05, 0x15, 0x45, 0xEA, 0x16, 0x75, 0x4F, 0xEA, ++ 0x06, 0x16, 0x4F, 0xEA, 0xC3, 0x03, 0x43, 0xEA, 0x52, 0x73, 0x4F, 0xEA, ++ 0xC2, 0x02, 0x5F, 0xEA, 0x1C, 0x1C, 0xC0, 0xD1, 0x11, 0xF4, 0x80, 0x1F, ++ 0x0B, 0xD1, 0x41, 0xEA, 0x00, 0x01, 0x4F, 0xF0, 0x00, 0x00, 0x4F, 0xF0, ++ 0x00, 0x4C, 0xB6, 0xE7, 0x11, 0xF4, 0x80, 0x1F, 0x04, 0xBF, 0x01, 0x43, ++ 0x00, 0x20, 0xB4, 0xF1, 0xFD, 0x0C, 0x88, 0xBF, 0xBC, 0xF5, 0xE0, 0x6F, ++ 0x3F, 0xF6, 0xAF, 0xAE, 0xB5, 0xEB, 0x03, 0x0C, 0x04, 0xBF, 0xB6, 0xEB, ++ 0x02, 0x0C, 0x5F, 0xEA, 0x50, 0x0C, 0x50, 0xF1, 0x00, 0x00, 0x41, 0xEB, ++ 0x04, 0x51, 0x70, 0xBD, 0x0E, 0xF0, 0x00, 0x4E, 0x4E, 0xEA, 0x11, 0x31, ++ 0x14, 0xEB, 0x5C, 0x04, 0xC2, 0xBF, 0xD4, 0xEB, 0x0C, 0x05, 0x41, 0xEA, ++ 0x04, 0x51, 0x70, 0xBD, 0x41, 0xF4, 0x80, 0x11, 0x4F, 0xF0, 0x00, 0x0E, ++ 0x01, 0x3C, 0x90, 0xE6, 0x45, 0xEA, 0x06, 0x0E, 0x8D, 0xE6, 0x0C, 0xEA, ++ 0x13, 0x55, 0x94, 0xEA, 0x0C, 0x0F, 0x08, 0xBF, 0x95, 0xEA, 0x0C, 0x0F, ++ 0x3F, 0xF4, 0x3B, 0xAF, 0x94, 0xEA, 0x0C, 0x0F, 0x0A, 0xD1, 0x50, 0xEA, ++ 0x01, 0x34, 0x7F, 0xF4, 0x34, 0xAF, 0x95, 0xEA, 0x0C, 0x0F, 0x7F, 0xF4, ++ 0x25, 0xAF, 0x10, 0x46, 0x19, 0x46, 0x2C, 0xE7, 0x95, 0xEA, 0x0C, 0x0F, ++ 0x06, 0xD1, 0x52, 0xEA, 0x03, 0x35, 0x3F, 0xF4, 0xFD, 0xAE, 0x10, 0x46, ++ 0x19, 0x46, 0x22, 0xE7, 0x50, 0xEA, 0x41, 0x06, 0x18, 0xBF, 0x52, 0xEA, ++ 0x43, 0x06, 0x7F, 0xF4, 0xC5, 0xAE, 0x50, 0xEA, 0x41, 0x04, 0x7F, 0xF4, ++ 0x0D, 0xAF, 0x52, 0xEA, 0x43, 0x05, 0x7F, 0xF4, 0xEB, 0xAE, 0x12, 0xE7, ++ 0x4F, 0xF0, 0xFF, 0x3C, 0x06, 0xE0, 0x00, 0xBF, 0x4F, 0xF0, 0x01, 0x0C, ++ 0x02, 0xE0, 0x00, 0xBF, 0x4F, 0xF0, 0x01, 0x0C, 0x4D, 0xF8, 0x04, 0xCD, ++ 0x4F, 0xEA, 0x41, 0x0C, 0x7F, 0xEA, 0x6C, 0x5C, 0x4F, 0xEA, 0x43, 0x0C, ++ 0x18, 0xBF, 0x7F, 0xEA, 0x6C, 0x5C, 0x1B, 0xD0, 0x01, 0xB0, 0x50, 0xEA, ++ 0x41, 0x0C, 0x0C, 0xBF, 0x52, 0xEA, 0x43, 0x0C, 0x91, 0xEA, 0x03, 0x0F, ++ 0x02, 0xBF, 0x90, 0xEA, 0x02, 0x0F, 0x00, 0x20, 0x70, 0x47, 0x10, 0xF1, ++ 0x00, 0x0F, 0x91, 0xEA, 0x03, 0x0F, 0x58, 0xBF, 0x99, 0x42, 0x08, 0xBF, ++ 0x90, 0x42, 0x2C, 0xBF, 0xD8, 0x17, 0x6F, 0xEA, 0xE3, 0x70, 0x40, 0xF0, ++ 0x01, 0x00, 0x70, 0x47, 0x4F, 0xEA, 0x41, 0x0C, 0x7F, 0xEA, 0x6C, 0x5C, ++ 0x02, 0xD1, 0x50, 0xEA, 0x01, 0x3C, 0x07, 0xD1, 0x4F, 0xEA, 0x43, 0x0C, ++ 0x7F, 0xEA, 0x6C, 0x5C, 0xD6, 0xD1, 0x52, 0xEA, 0x03, 0x3C, 0xD3, 0xD0, ++ 0x5D, 0xF8, 0x04, 0x0B, 0x70, 0x47, 0x00, 0xBF, 0x84, 0x46, 0x10, 0x46, ++ 0x62, 0x46, 0x8C, 0x46, 0x19, 0x46, 0x63, 0x46, 0x00, 0xE0, 0x00, 0xBF, ++ 0x01, 0xB5, 0xFF, 0xF7, 0xB7, 0xFF, 0x00, 0x28, 0x48, 0xBF, 0x10, 0xF1, ++ 0x00, 0x0F, 0x01, 0xBD, 0x4D, 0xF8, 0x08, 0xED, 0xFF, 0xF7, 0xF4, 0xFF, ++ 0x0C, 0xBF, 0x01, 0x20, 0x00, 0x20, 0x5D, 0xF8, 0x08, 0xFB, 0x00, 0xBF, ++ 0x4D, 0xF8, 0x08, 0xED, 0xFF, 0xF7, 0xEA, 0xFF, 0x34, 0xBF, 0x01, 0x20, ++ 0x00, 0x20, 0x5D, 0xF8, 0x08, 0xFB, 0x00, 0xBF, 0x4D, 0xF8, 0x08, 0xED, ++ 0xFF, 0xF7, 0xE0, 0xFF, 0x94, 0xBF, 0x01, 0x20, 0x00, 0x20, 0x5D, 0xF8, ++ 0x08, 0xFB, 0x00, 0xBF, 0x4D, 0xF8, 0x08, 0xED, 0xFF, 0xF7, 0xCE, 0xFF, ++ 0x94, 0xBF, 0x01, 0x20, 0x00, 0x20, 0x5D, 0xF8, 0x08, 0xFB, 0x00, 0xBF, ++ 0x4D, 0xF8, 0x08, 0xED, 0xFF, 0xF7, 0xC4, 0xFF, 0x34, 0xBF, 0x01, 0x20, ++ 0x00, 0x20, 0x5D, 0xF8, 0x08, 0xFB, 0x00, 0xBF, 0x4A, 0x00, 0x11, 0xD2, ++ 0x12, 0xF5, 0x00, 0x12, 0x11, 0xD2, 0x0D, 0xD5, 0x6F, 0xF4, 0x78, 0x73, ++ 0xB3, 0xEB, 0x62, 0x52, 0x0E, 0xD4, 0x4F, 0xEA, 0xC1, 0x23, 0x43, 0xF0, ++ 0x00, 0x43, 0x43, 0xEA, 0x50, 0x53, 0x23, 0xFA, 0x02, 0xF0, 0x70, 0x47, ++ 0x4F, 0xF0, 0x00, 0x00, 0x70, 0x47, 0x50, 0xEA, 0x01, 0x30, 0x02, 0xD1, ++ 0x4F, 0xF0, 0xFF, 0x30, 0x70, 0x47, 0x4F, 0xF0, 0x00, 0x00, 0x70, 0x47, ++ 0x4F, 0xEA, 0x41, 0x02, 0xB2, 0xF1, 0xE0, 0x43, 0x24, 0xBF, 0xB3, 0xF5, ++ 0x00, 0x1C, 0xDC, 0xF1, 0xFE, 0x5C, 0x0D, 0xD9, 0x01, 0xF0, 0x00, 0x4C, ++ 0x4F, 0xEA, 0xC0, 0x02, 0x4C, 0xEA, 0x50, 0x70, 0xB2, 0xF1, 0x00, 0x4F, ++ 0x40, 0xEB, 0x83, 0x00, 0x08, 0xBF, 0x20, 0xF0, 0x01, 0x00, 0x70, 0x47, ++ 0x11, 0xF0, 0x80, 0x4F, 0x21, 0xD1, 0x13, 0xF1, 0x38, 0x72, 0xBC, 0xBF, ++ 0x01, 0xF0, 0x00, 0x40, 0x70, 0x47, 0x41, 0xF4, 0x80, 0x11, 0x4F, 0xEA, ++ 0x52, 0x52, 0xC2, 0xF1, 0x18, 0x02, 0xC2, 0xF1, 0x20, 0x0C, 0x10, 0xFA, ++ 0x0C, 0xF3, 0x20, 0xFA, 0x02, 0xF0, 0x18, 0xBF, 0x40, 0xF0, 0x01, 0x00, ++ 0x4F, 0xEA, 0xC1, 0x23, 0x4F, 0xEA, 0xD3, 0x23, 0x03, 0xFA, 0x0C, 0xFC, ++ 0x40, 0xEA, 0x0C, 0x00, 0x23, 0xFA, 0x02, 0xF3, 0x4F, 0xEA, 0x43, 0x03, ++ 0xCC, 0xE7, 0x7F, 0xEA, 0x62, 0x53, 0x07, 0xD1, 0x50, 0xEA, 0x01, 0x33, ++ 0x1E, 0xBF, 0x4F, 0xF0, 0xFE, 0x40, 0x40, 0xF4, 0x40, 0x00, 0x70, 0x47, ++ 0x01, 0xF0, 0x00, 0x40, 0x40, 0xF0, 0xFE, 0x40, 0x40, 0xF4, 0x00, 0x00, ++ 0x70, 0x47, 0x00, 0xBF, 0x53, 0xB9, 0x4A, 0xB9, 0x00, 0x29, 0x08, 0xBF, ++ 0x00, 0x28, 0x1C, 0xBF, 0x4F, 0xF0, 0xFF, 0x31, 0x4F, 0xF0, 0xFF, 0x30, ++ 0x00, 0xF0, 0x6C, 0xB9, 0xAD, 0xF1, 0x08, 0x0C, 0x6D, 0xE9, 0x04, 0xCE, ++ 0x00, 0xF0, 0x06, 0xF8, 0xDD, 0xF8, 0x04, 0xE0, 0xDD, 0xE9, 0x02, 0x23, ++ 0x04, 0xB0, 0x70, 0x47, 0x2D, 0xE9, 0xF0, 0x47, 0x08, 0x9E, 0x0D, 0x46, ++ 0x04, 0x46, 0x8E, 0x46, 0x00, 0x2B, 0x40, 0xF0, 0x82, 0x80, 0x8A, 0x42, ++ 0x17, 0x46, 0x46, 0xD9, 0xB2, 0xFA, 0x82, 0xF2, 0x4A, 0xB1, 0xC2, 0xF1, ++ 0x20, 0x01, 0x05, 0xFA, 0x02, 0xF3, 0x20, 0xFA, 0x01, 0xF1, 0x97, 0x40, ++ 0x41, 0xEA, 0x03, 0x0E, 0x94, 0x40, 0x4F, 0xEA, 0x17, 0x48, 0x23, 0x0C, ++ 0xBE, 0xFB, 0xF8, 0xFC, 0xB9, 0xB2, 0x08, 0xFB, 0x1C, 0xEE, 0x43, 0xEA, ++ 0x0E, 0x43, 0x0C, 0xFB, 0x01, 0xF0, 0x98, 0x42, 0x0A, 0xD9, 0xFB, 0x18, ++ 0x0C, 0xF1, 0xFF, 0x35, 0x80, 0xF0, 0x16, 0x81, 0x98, 0x42, 0x40, 0xF2, ++ 0x13, 0x81, 0xAC, 0xF1, 0x02, 0x0C, 0x3B, 0x44, 0x1B, 0x1A, 0xA4, 0xB2, ++ 0xB3, 0xFB, 0xF8, 0xF0, 0x08, 0xFB, 0x10, 0x33, 0x44, 0xEA, 0x03, 0x44, ++ 0x00, 0xFB, 0x01, 0xF1, 0xA1, 0x42, 0x09, 0xD9, 0x3C, 0x19, 0x00, 0xF1, ++ 0xFF, 0x33, 0x80, 0xF0, 0x01, 0x81, 0xA1, 0x42, 0x40, 0xF2, 0xFE, 0x80, ++ 0x02, 0x38, 0x3C, 0x44, 0x64, 0x1A, 0x40, 0xEA, 0x0C, 0x40, 0x00, 0x21, ++ 0x1E, 0xB1, 0xD4, 0x40, 0x00, 0x23, 0xC6, 0xE9, 0x00, 0x43, 0xBD, 0xE8, ++ 0xF0, 0x87, 0x02, 0xB9, 0xFF, 0xDE, 0xB2, 0xFA, 0x82, 0xF2, 0x00, 0x2A, ++ 0x4F, 0xD1, 0xCB, 0x1B, 0x4F, 0xEA, 0x17, 0x4E, 0x1F, 0xFA, 0x87, 0xF8, ++ 0x01, 0x21, 0xB3, 0xFB, 0xFE, 0xFC, 0x25, 0x0C, 0x0E, 0xFB, 0x1C, 0x33, ++ 0x45, 0xEA, 0x03, 0x45, 0x08, 0xFB, 0x0C, 0xF3, 0xAB, 0x42, 0x07, 0xD9, ++ 0x7D, 0x19, 0x0C, 0xF1, 0xFF, 0x30, 0x02, 0xD2, 0xAB, 0x42, 0x00, 0xF2, ++ 0xE7, 0x80, 0x84, 0x46, 0xED, 0x1A, 0xA3, 0xB2, 0xB5, 0xFB, 0xFE, 0xF0, ++ 0x0E, 0xFB, 0x10, 0x55, 0x43, 0xEA, 0x05, 0x44, 0x08, 0xFB, 0x00, 0xF8, ++ 0xA0, 0x45, 0x07, 0xD9, 0x3C, 0x19, 0x00, 0xF1, 0xFF, 0x33, 0x02, 0xD2, ++ 0xA0, 0x45, 0x00, 0xF2, 0xD7, 0x80, 0x18, 0x46, 0xA4, 0xEB, 0x08, 0x04, ++ 0x40, 0xEA, 0x0C, 0x40, 0xC0, 0xE7, 0x8B, 0x42, 0x08, 0xD9, 0x00, 0x2E, ++ 0x00, 0xF0, 0xAF, 0x80, 0x00, 0x21, 0xC6, 0xE9, 0x00, 0x05, 0x08, 0x46, ++ 0xBD, 0xE8, 0xF0, 0x87, 0xB3, 0xFA, 0x83, 0xF1, 0x00, 0x29, 0x4B, 0xD1, ++ 0xAB, 0x42, 0x02, 0xD3, 0x82, 0x42, 0x00, 0xF2, 0xB7, 0x80, 0x84, 0x1A, ++ 0x65, 0xEB, 0x03, 0x03, 0x01, 0x20, 0x9E, 0x46, 0x00, 0x2E, 0xAA, 0xD0, ++ 0xC6, 0xE9, 0x00, 0x4E, 0xA7, 0xE7, 0xC2, 0xF1, 0x20, 0x0C, 0x01, 0xFA, ++ 0x02, 0xF3, 0x97, 0x40, 0x20, 0xFA, 0x0C, 0xF0, 0x4F, 0xEA, 0x17, 0x4E, ++ 0x21, 0xFA, 0x0C, 0xFC, 0x18, 0x43, 0xBC, 0xFB, 0xFE, 0xF1, 0x05, 0x0C, ++ 0x0E, 0xFB, 0x11, 0xCC, 0x1F, 0xFA, 0x87, 0xF8, 0x45, 0xEA, 0x0C, 0x45, ++ 0x01, 0xFB, 0x08, 0xF3, 0xAB, 0x42, 0x04, 0xFA, 0x02, 0xF4, 0x09, 0xD9, ++ 0x7D, 0x19, 0x01, 0xF1, 0xFF, 0x3C, 0x80, 0xF0, 0x8B, 0x80, 0xAB, 0x42, ++ 0x40, 0xF2, 0x88, 0x80, 0x02, 0x39, 0x3D, 0x44, 0xEB, 0x1A, 0x85, 0xB2, ++ 0xB3, 0xFB, 0xFE, 0xF0, 0x0E, 0xFB, 0x10, 0x33, 0x45, 0xEA, 0x03, 0x45, ++ 0x00, 0xFB, 0x08, 0xF3, 0xAB, 0x42, 0x07, 0xD9, 0x7D, 0x19, 0x00, 0xF1, ++ 0xFF, 0x3C, 0x71, 0xD2, 0xAB, 0x42, 0x6F, 0xD9, 0x02, 0x38, 0x3D, 0x44, ++ 0xEB, 0x1A, 0x40, 0xEA, 0x01, 0x41, 0x78, 0xE7, 0xC1, 0xF1, 0x20, 0x0C, ++ 0x8B, 0x40, 0x22, 0xFA, 0x0C, 0xF7, 0x1F, 0x43, 0x20, 0xFA, 0x0C, 0xF4, ++ 0x05, 0xFA, 0x01, 0xF3, 0x4F, 0xEA, 0x17, 0x4E, 0x25, 0xFA, 0x0C, 0xF5, ++ 0x1C, 0x43, 0x23, 0x0C, 0xB5, 0xFB, 0xFE, 0xF9, 0x1F, 0xFA, 0x87, 0xF8, ++ 0x0E, 0xFB, 0x19, 0x55, 0x43, 0xEA, 0x05, 0x45, 0x09, 0xFB, 0x08, 0xFA, ++ 0xAA, 0x45, 0x02, 0xFA, 0x01, 0xF2, 0x00, 0xFA, 0x01, 0xF3, 0x08, 0xD9, ++ 0x7D, 0x19, 0x09, 0xF1, 0xFF, 0x30, 0x47, 0xD2, 0xAA, 0x45, 0x45, 0xD9, ++ 0xA9, 0xF1, 0x02, 0x09, 0x3D, 0x44, 0xA5, 0xEB, 0x0A, 0x05, 0xA4, 0xB2, ++ 0xB5, 0xFB, 0xFE, 0xF0, 0x0E, 0xFB, 0x10, 0x55, 0x44, 0xEA, 0x05, 0x44, ++ 0x00, 0xFB, 0x08, 0xF8, 0xA0, 0x45, 0x07, 0xD9, 0x3C, 0x19, 0x00, 0xF1, ++ 0xFF, 0x35, 0x2D, 0xD2, 0xA0, 0x45, 0x2B, 0xD9, 0x02, 0x38, 0x3C, 0x44, ++ 0x40, 0xEA, 0x09, 0x40, 0xA4, 0xEB, 0x08, 0x04, 0xA0, 0xFB, 0x02, 0x89, ++ 0x4C, 0x45, 0xC6, 0x46, 0x4D, 0x46, 0x19, 0xD3, 0x16, 0xD0, 0x5E, 0xB1, ++ 0xB3, 0xEB, 0x0E, 0x02, 0x64, 0xEB, 0x05, 0x04, 0x04, 0xFA, 0x0C, 0xFC, ++ 0xCA, 0x40, 0x4C, 0xEA, 0x02, 0x02, 0xCC, 0x40, 0xC6, 0xE9, 0x00, 0x24, ++ 0x00, 0x21, 0xBD, 0xE8, 0xF0, 0x87, 0x31, 0x46, 0x30, 0x46, 0x0E, 0xE7, ++ 0xAC, 0x46, 0xED, 0xE6, 0x18, 0x46, 0x01, 0xE7, 0x43, 0x45, 0xE6, 0xD2, ++ 0xB8, 0xEB, 0x02, 0x0E, 0x69, 0xEB, 0x07, 0x05, 0x01, 0x38, 0xE0, 0xE7, ++ 0x28, 0x46, 0xD3, 0xE7, 0x60, 0x46, 0x8F, 0xE7, 0x81, 0x46, 0xBA, 0xE7, ++ 0x61, 0x46, 0x77, 0xE7, 0x08, 0x46, 0x4B, 0xE7, 0xAC, 0xF1, 0x02, 0x0C, ++ 0x3D, 0x44, 0x15, 0xE7, 0x02, 0x38, 0x3C, 0x44, 0x26, 0xE7, 0x00, 0xBF, ++ 0x70, 0x47, 0x00, 0xBF, 0x00, 0x28, 0xB8, 0xBF, 0x40, 0x42, 0x70, 0x47, ++ 0x03, 0x2A, 0x70, 0xB4, 0x12, 0xD9, 0x40, 0xEA, 0x01, 0x05, 0xAD, 0x07, ++ 0x04, 0x46, 0x0B, 0x46, 0x1E, 0xD1, 0x19, 0x46, 0x20, 0x46, 0x53, 0xF8, ++ 0x04, 0x5B, 0x54, 0xF8, 0x04, 0x6B, 0xAE, 0x42, 0x16, 0xD1, 0x04, 0x3A, ++ 0x03, 0x2A, 0x20, 0x46, 0x19, 0x46, 0xF2, 0xD8, 0x56, 0x1E, 0xA2, 0xB1, ++ 0x01, 0x39, 0x44, 0x1E, 0x01, 0xE0, 0xC3, 0x18, 0x0C, 0xD0, 0x14, 0xF8, ++ 0x01, 0x5F, 0x11, 0xF8, 0x01, 0x2F, 0x95, 0x42, 0xA6, 0xEB, 0x04, 0x03, ++ 0xF5, 0xD0, 0xA8, 0x1A, 0x70, 0xBC, 0x70, 0x47, 0x56, 0x1E, 0xED, 0xE7, ++ 0x18, 0x46, 0x70, 0xBC, 0x70, 0x47, 0x10, 0x46, 0xF6, 0xE7, 0x00, 0xBF, ++ 0x84, 0x46, 0x41, 0xEA, 0x00, 0x03, 0x13, 0xF0, 0x03, 0x03, 0x6D, 0xD1, ++ 0x40, 0x3A, 0x41, 0xD3, 0x51, 0xF8, 0x04, 0x3B, 0x40, 0xF8, 0x04, 0x3B, ++ 0x51, 0xF8, 0x04, 0x3B, 0x40, 0xF8, 0x04, 0x3B, 0x51, 0xF8, 0x04, 0x3B, ++ 0x40, 0xF8, 0x04, 0x3B, 0x51, 0xF8, 0x04, 0x3B, 0x40, 0xF8, 0x04, 0x3B, ++ 0x51, 0xF8, 0x04, 0x3B, 0x40, 0xF8, 0x04, 0x3B, 0x51, 0xF8, 0x04, 0x3B, ++ 0x40, 0xF8, 0x04, 0x3B, 0x51, 0xF8, 0x04, 0x3B, 0x40, 0xF8, 0x04, 0x3B, ++ 0x51, 0xF8, 0x04, 0x3B, 0x40, 0xF8, 0x04, 0x3B, 0x51, 0xF8, 0x04, 0x3B, ++ 0x40, 0xF8, 0x04, 0x3B, 0x51, 0xF8, 0x04, 0x3B, 0x40, 0xF8, 0x04, 0x3B, ++ 0x51, 0xF8, 0x04, 0x3B, 0x40, 0xF8, 0x04, 0x3B, 0x51, 0xF8, 0x04, 0x3B, ++ 0x40, 0xF8, 0x04, 0x3B, 0x51, 0xF8, 0x04, 0x3B, 0x40, 0xF8, 0x04, 0x3B, ++ 0x51, 0xF8, 0x04, 0x3B, 0x40, 0xF8, 0x04, 0x3B, 0x51, 0xF8, 0x04, 0x3B, ++ 0x40, 0xF8, 0x04, 0x3B, 0x51, 0xF8, 0x04, 0x3B, 0x40, 0xF8, 0x04, 0x3B, ++ 0x40, 0x3A, 0xBD, 0xD2, 0x30, 0x32, 0x11, 0xD3, 0x51, 0xF8, 0x04, 0x3B, ++ 0x40, 0xF8, 0x04, 0x3B, 0x51, 0xF8, 0x04, 0x3B, 0x40, 0xF8, 0x04, 0x3B, ++ 0x51, 0xF8, 0x04, 0x3B, 0x40, 0xF8, 0x04, 0x3B, 0x51, 0xF8, 0x04, 0x3B, ++ 0x40, 0xF8, 0x04, 0x3B, 0x10, 0x3A, 0xED, 0xD2, 0x0C, 0x32, 0x05, 0xD3, ++ 0x51, 0xF8, 0x04, 0x3B, 0x40, 0xF8, 0x04, 0x3B, 0x04, 0x3A, 0xF9, 0xD2, ++ 0x04, 0x32, 0x08, 0xD0, 0xD2, 0x07, 0x1C, 0xBF, 0x11, 0xF8, 0x01, 0x3B, ++ 0x00, 0xF8, 0x01, 0x3B, 0x01, 0xD3, 0x0B, 0x88, 0x03, 0x80, 0x60, 0x46, ++ 0x70, 0x47, 0x00, 0xBF, 0x08, 0x2A, 0x13, 0xD3, 0x8B, 0x07, 0x8D, 0xD0, ++ 0x10, 0xF0, 0x03, 0x03, 0x8A, 0xD0, 0xC3, 0xF1, 0x04, 0x03, 0xD2, 0x1A, ++ 0xDB, 0x07, 0x1C, 0xBF, 0x11, 0xF8, 0x01, 0x3B, 0x00, 0xF8, 0x01, 0x3B, ++ 0x80, 0xD3, 0x31, 0xF8, 0x02, 0x3B, 0x20, 0xF8, 0x02, 0x3B, 0x7B, 0xE7, ++ 0x04, 0x3A, 0xD9, 0xD3, 0x01, 0x3A, 0x11, 0xF8, 0x01, 0x3B, 0x00, 0xF8, ++ 0x01, 0x3B, 0xF9, 0xD2, 0x0B, 0x78, 0x03, 0x70, 0x4B, 0x78, 0x43, 0x70, ++ 0x8B, 0x78, 0x83, 0x70, 0x60, 0x46, 0x70, 0x47, 0x88, 0x42, 0xF0, 0xB4, ++ 0x0D, 0xD9, 0x8B, 0x18, 0x83, 0x42, 0x0A, 0xD9, 0x84, 0x18, 0x32, 0xB1, ++ 0x22, 0x46, 0x13, 0xF8, 0x01, 0x4D, 0x02, 0xF8, 0x01, 0x4D, 0x99, 0x42, ++ 0xF9, 0xD1, 0xF0, 0xBC, 0x70, 0x47, 0x0F, 0x2A, 0x0E, 0xD8, 0x03, 0x46, ++ 0x54, 0x1E, 0x00, 0x2A, 0xF7, 0xD0, 0x01, 0x34, 0x0C, 0x44, 0x01, 0x3B, ++ 0x11, 0xF8, 0x01, 0x2B, 0x03, 0xF8, 0x01, 0x2F, 0xA1, 0x42, 0xF9, 0xD1, ++ 0xF0, 0xBC, 0x70, 0x47, 0x40, 0xEA, 0x01, 0x03, 0x9B, 0x07, 0x3F, 0xD1, ++ 0xA2, 0xF1, 0x10, 0x03, 0x23, 0xF0, 0x0F, 0x04, 0x01, 0xF1, 0x20, 0x07, ++ 0x27, 0x44, 0x1B, 0x09, 0x01, 0xF1, 0x10, 0x04, 0x00, 0xF1, 0x10, 0x05, ++ 0x54, 0xF8, 0x10, 0x6C, 0x45, 0xF8, 0x10, 0x6C, 0x54, 0xF8, 0x0C, 0x6C, ++ 0x45, 0xF8, 0x0C, 0x6C, 0x54, 0xF8, 0x08, 0x6C, 0x45, 0xF8, 0x08, 0x6C, ++ 0x54, 0xF8, 0x04, 0x6C, 0x45, 0xF8, 0x04, 0x6C, 0x10, 0x34, 0xBC, 0x42, ++ 0x05, 0xF1, 0x10, 0x05, 0xEA, 0xD1, 0x01, 0x33, 0x12, 0xF0, 0x0C, 0x0F, ++ 0x01, 0xEB, 0x03, 0x11, 0x02, 0xF0, 0x0F, 0x04, 0x00, 0xEB, 0x03, 0x13, ++ 0x17, 0xD0, 0x04, 0x3C, 0x24, 0xF0, 0x03, 0x0C, 0xA5, 0x08, 0x9C, 0x44, ++ 0x1C, 0x1F, 0x0E, 0x46, 0x56, 0xF8, 0x04, 0x7B, 0x44, 0xF8, 0x04, 0x7F, ++ 0x64, 0x45, 0xF9, 0xD1, 0x6C, 0x1C, 0x03, 0xEB, 0x84, 0x03, 0x01, 0xEB, ++ 0x84, 0x01, 0x02, 0xF0, 0x03, 0x02, 0xAD, 0xE7, 0x54, 0x1E, 0x03, 0x46, ++ 0xAD, 0xE7, 0x22, 0x46, 0xA8, 0xE7, 0x00, 0xBF, 0x0B, 0x4B, 0x0C, 0x48, ++ 0x19, 0x68, 0xD1, 0xE9, 0x2A, 0x23, 0x10, 0xB4, 0x0A, 0x4C, 0x00, 0xFB, ++ 0x02, 0xF0, 0x04, 0xFB, 0x03, 0x00, 0xA2, 0xFB, 0x04, 0x34, 0x04, 0x44, ++ 0x5A, 0x1C, 0x44, 0xF1, 0x00, 0x00, 0xC1, 0xE9, 0x2A, 0x20, 0x10, 0xBC, ++ 0x20, 0xF0, 0x00, 0x40, 0x70, 0x47, 0x00, 0xBF, 0x80, 0x01, 0x17, 0x00, ++ 0x2D, 0xF4, 0x51, 0x58, 0x2D, 0x7F, 0x95, 0x4C, 0x11, 0xF0, 0xFF, 0x01, ++ 0x03, 0x46, 0x44, 0xD0, 0x82, 0x07, 0x32, 0xD1, 0x70, 0xB4, 0x04, 0x68, ++ 0x41, 0xEA, 0x01, 0x26, 0x46, 0xEA, 0x06, 0x46, 0x86, 0xEA, 0x04, 0x05, ++ 0xA5, 0xF1, 0x01, 0x33, 0xA4, 0xF1, 0x01, 0x32, 0x23, 0xEA, 0x05, 0x03, ++ 0x22, 0xEA, 0x04, 0x02, 0x13, 0x43, 0x13, 0xF0, 0x80, 0x3F, 0x0F, 0xD1, ++ 0x50, 0xF8, 0x04, 0x4F, 0x84, 0xEA, 0x06, 0x05, 0xA5, 0xF1, 0x01, 0x32, ++ 0xA4, 0xF1, 0x01, 0x33, 0x22, 0xEA, 0x05, 0x02, 0x23, 0xEA, 0x04, 0x03, ++ 0x13, 0x43, 0x13, 0xF0, 0x80, 0x3F, 0xEF, 0xD0, 0x03, 0x78, 0x23, 0xB9, ++ 0x36, 0xE0, 0x10, 0xF8, 0x01, 0x3F, 0x00, 0x2B, 0x32, 0xD0, 0x99, 0x42, ++ 0xF9, 0xD1, 0x30, 0xE0, 0x8A, 0x42, 0x11, 0xD0, 0x9A, 0x07, 0x18, 0x46, ++ 0xCC, 0xD0, 0x18, 0x46, 0x13, 0xF8, 0x01, 0x2B, 0x00, 0x2A, 0xF5, 0xD1, ++ 0x10, 0x46, 0x70, 0x47, 0x99, 0x07, 0x18, 0x46, 0x07, 0xD0, 0x18, 0x46, ++ 0x01, 0x33, 0x02, 0x78, 0x00, 0x2A, 0xF7, 0xD1, 0x70, 0x47, 0x82, 0x07, ++ 0xF7, 0xD1, 0x02, 0x68, 0xA2, 0xF1, 0x01, 0x33, 0x23, 0xEA, 0x02, 0x03, ++ 0x13, 0xF0, 0x80, 0x3F, 0x08, 0xD1, 0x50, 0xF8, 0x04, 0x2F, 0xA2, 0xF1, ++ 0x01, 0x33, 0x23, 0xEA, 0x02, 0x03, 0x13, 0xF0, 0x80, 0x3F, 0xF6, 0xD0, ++ 0x03, 0x78, 0x00, 0x2B, 0xE8, 0xD0, 0x10, 0xF8, 0x01, 0x3F, 0x00, 0x2B, ++ 0xFB, 0xD1, 0x70, 0x47, 0x18, 0x46, 0x70, 0xBC, 0x70, 0x47, 0x00, 0xBF, ++ 0x80, 0xEA, 0x01, 0x02, 0x84, 0x46, 0x12, 0xF0, 0x03, 0x0F, 0x4F, 0xD1, ++ 0x11, 0xF0, 0x03, 0x0F, 0x32, 0xD1, 0x4D, 0xF8, 0x04, 0x4D, 0x11, 0xF0, ++ 0x04, 0x0F, 0x51, 0xF8, 0x04, 0x3B, 0x0B, 0xD0, 0xA3, 0xF1, 0x01, 0x32, ++ 0x9A, 0x43, 0x12, 0xF0, 0x80, 0x3F, 0x04, 0xBF, 0x4C, 0xF8, 0x04, 0x3B, ++ 0x51, 0xF8, 0x04, 0x3B, 0x16, 0xD1, 0x00, 0xBF, 0x51, 0xF8, 0x04, 0x4B, ++ 0xA3, 0xF1, 0x01, 0x32, 0x9A, 0x43, 0x12, 0xF0, 0x80, 0x3F, 0xA4, 0xF1, ++ 0x01, 0x32, 0x0B, 0xD1, 0x4C, 0xF8, 0x04, 0x3B, 0xA2, 0x43, 0x12, 0xF0, ++ 0x80, 0x3F, 0x04, 0xBF, 0x51, 0xF8, 0x04, 0x3B, 0x4C, 0xF8, 0x04, 0x4B, ++ 0xEA, 0xD0, 0x23, 0x46, 0x0C, 0xF8, 0x01, 0x3B, 0x13, 0xF0, 0xFF, 0x0F, ++ 0x4F, 0xEA, 0x33, 0x23, 0xF8, 0xD1, 0x5D, 0xF8, 0x04, 0x4B, 0x70, 0x47, ++ 0x11, 0xF0, 0x01, 0x0F, 0x06, 0xD0, 0x11, 0xF8, 0x01, 0x2B, 0x0C, 0xF8, ++ 0x01, 0x2B, 0x00, 0x2A, 0x08, 0xBF, 0x70, 0x47, 0x11, 0xF0, 0x02, 0x0F, ++ 0xBF, 0xD0, 0x31, 0xF8, 0x02, 0x2B, 0x12, 0xF0, 0xFF, 0x0F, 0x16, 0xBF, ++ 0x2C, 0xF8, 0x02, 0x2B, 0x8C, 0xF8, 0x00, 0x20, 0x12, 0xF4, 0x7F, 0x4F, ++ 0xB3, 0xD1, 0x70, 0x47, 0x11, 0xF8, 0x01, 0x2B, 0x0C, 0xF8, 0x01, 0x2B, ++ 0x00, 0x2A, 0xF9, 0xD1, 0x70, 0x47, 0x00, 0xBF, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xF8, 0x00, 0xF0, ++ 0x6D, 0xE9, 0x02, 0x45, 0x20, 0xF0, 0x07, 0x01, 0x6F, 0xF0, 0x00, 0x0C, ++ 0x10, 0xF0, 0x07, 0x04, 0x91, 0xF8, 0x20, 0xF0, 0x40, 0xF0, 0x49, 0x80, ++ 0x4F, 0xF0, 0x00, 0x04, 0x6F, 0xF0, 0x07, 0x00, 0xD1, 0xE9, 0x00, 0x23, ++ 0x91, 0xF8, 0x40, 0xF0, 0x00, 0xF1, 0x08, 0x00, 0x82, 0xFA, 0x4C, 0xF2, ++ 0xA4, 0xFA, 0x8C, 0xF2, 0x83, 0xFA, 0x4C, 0xF3, 0xA2, 0xFA, 0x8C, 0xF3, ++ 0x4B, 0xBB, 0xD1, 0xE9, 0x02, 0x23, 0x82, 0xFA, 0x4C, 0xF2, 0x00, 0xF1, ++ 0x08, 0x00, 0xA4, 0xFA, 0x8C, 0xF2, 0x83, 0xFA, 0x4C, 0xF3, 0xA2, 0xFA, ++ 0x8C, 0xF3, 0xE3, 0xB9, 0xD1, 0xE9, 0x04, 0x23, 0x82, 0xFA, 0x4C, 0xF2, ++ 0x00, 0xF1, 0x08, 0x00, 0xA4, 0xFA, 0x8C, 0xF2, 0x83, 0xFA, 0x4C, 0xF3, ++ 0xA2, 0xFA, 0x8C, 0xF3, 0x7B, 0xB9, 0xD1, 0xE9, 0x06, 0x23, 0x01, 0xF1, ++ 0x20, 0x01, 0x82, 0xFA, 0x4C, 0xF2, 0x00, 0xF1, 0x08, 0x00, 0xA4, 0xFA, ++ 0x8C, 0xF2, 0x83, 0xFA, 0x4C, 0xF3, 0xA2, 0xFA, 0x8C, 0xF3, 0x00, 0x2B, ++ 0xC6, 0xD0, 0x00, 0x2A, 0x04, 0xBF, 0x04, 0x30, 0x1A, 0x46, 0x12, 0xBA, ++ 0xB2, 0xFA, 0x82, 0xF2, 0xFD, 0xE8, 0x02, 0x45, 0x00, 0xEB, 0xD2, 0x00, ++ 0x70, 0x47, 0xD1, 0xE9, 0x00, 0x23, 0x04, 0xF0, 0x03, 0x05, 0xC4, 0xF1, ++ 0x00, 0x00, 0x4F, 0xEA, 0xC5, 0x05, 0x14, 0xF0, 0x04, 0x0F, 0x91, 0xF8, ++ 0x40, 0xF0, 0x0C, 0xFA, 0x05, 0xF5, 0x62, 0xEA, 0x05, 0x02, 0x1C, 0xBF, ++ 0x63, 0xEA, 0x05, 0x03, 0x62, 0x46, 0x4F, 0xF0, 0x00, 0x04, 0xA9, 0xE7, ++ 0x9A, 0xB3, 0xF0, 0xB4, 0x40, 0xEA, 0x01, 0x05, 0xAD, 0x07, 0x04, 0x46, ++ 0x03, 0x46, 0x08, 0x46, 0x28, 0xD0, 0x20, 0x78, 0x0E, 0x78, 0x86, 0x42, ++ 0x29, 0xD1, 0x01, 0x2A, 0x2A, 0xD0, 0x25, 0x46, 0x50, 0xB1, 0x15, 0xF8, ++ 0x01, 0x0F, 0x11, 0xF8, 0x01, 0x6F, 0xEB, 0x43, 0xB0, 0x42, 0x13, 0x44, ++ 0x1D, 0xD1, 0xE3, 0x18, 0xF4, 0xD1, 0x18, 0x46, 0xF0, 0xBC, 0x70, 0x47, ++ 0x07, 0x68, 0x1C, 0x46, 0x53, 0xF8, 0x04, 0x5B, 0xA5, 0xF1, 0x01, 0x36, ++ 0xBD, 0x42, 0x01, 0x46, 0x26, 0xEA, 0x05, 0x06, 0x00, 0xF1, 0x04, 0x00, ++ 0xDD, 0xD1, 0x04, 0x3A, 0x1C, 0x46, 0x01, 0x46, 0x0A, 0xD0, 0x16, 0xF0, ++ 0x80, 0x3F, 0x07, 0xD1, 0x03, 0x2A, 0xE9, 0xD8, 0xD3, 0xE7, 0x10, 0x46, ++ 0x70, 0x47, 0x80, 0x1B, 0xF0, 0xBC, 0x70, 0x47, 0x00, 0x20, 0xF0, 0xBC, ++ 0x70, 0x47, 0x00, 0xBF, 0x6D, 0x65, 0x6D, 0x20, 0x6F, 0x76, 0x65, 0x72, ++ 0x6C, 0x61, 0x70, 0x73, 0x3A, 0x20, 0x73, 0x74, 0x6B, 0x5F, 0x73, 0x74, ++ 0x61, 0x72, 0x74, 0x3D, 0x25, 0x78, 0x2C, 0x20, 0x62, 0x73, 0x73, 0x5F, ++ 0x65, 0x6E, 0x64, 0x3D, 0x25, 0x78, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x6D, 0x65, 0x6D, 0x20, 0x6F, 0x76, 0x65, 0x72, 0x6C, 0x61, 0x70, 0x73, ++ 0x3A, 0x20, 0x73, 0x74, 0x6B, 0x5F, 0x65, 0x6E, 0x64, 0x3D, 0x25, 0x78, ++ 0x2C, 0x20, 0x68, 0x6F, 0x73, 0x74, 0x5F, 0x62, 0x61, 0x73, 0x65, 0x3D, ++ 0x25, 0x78, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x68, 0x6F, 0x73, 0x74, ++ 0x74, 0x79, 0x70, 0x65, 0x3D, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, ++ 0x77, 0x61, 0x6B, 0x65, 0x75, 0x70, 0x21, 0x0D, 0x0A, 0x00, 0x00, 0x00, ++ 0x77, 0x69, 0x66, 0x69, 0x6D, 0x61, 0x69, 0x6E, 0x21, 0x0D, 0x0A, 0x00, ++ 0x10, 0x14, 0x08, 0x12, 0x3C, 0x00, 0x8A, 0x12, 0x07, 0x12, 0x0C, 0x13, ++ 0x08, 0x12, 0xC7, 0x11, 0x10, 0x14, 0x08, 0x12, 0x3C, 0x00, 0x8A, 0x12, ++ 0x07, 0x12, 0x0C, 0x13, 0x08, 0x12, 0x45, 0x11, 0x08, 0x12, 0x04, 0x11, ++ 0x78, 0x00, 0x8A, 0x12, 0x07, 0x12, 0x86, 0x11, 0x04, 0x11, 0x03, 0x11, ++ 0x08, 0x12, 0x04, 0x11, 0x78, 0x00, 0x8A, 0x12, 0x07, 0x12, 0x86, 0x11, ++ 0x04, 0x11, 0xC2, 0x10, 0x08, 0x12, 0x04, 0x11, 0x78, 0x00, 0x8A, 0x12, ++ 0x07, 0x12, 0xC3, 0x10, 0x04, 0x11, 0xC2, 0x10, 0x04, 0x11, 0x04, 0x11, ++ 0x78, 0x00, 0x8A, 0x12, 0x86, 0x11, 0xC3, 0x10, 0x04, 0x11, 0xC2, 0x10, ++ 0x04, 0x11, 0x04, 0x11, 0x78, 0x00, 0x8A, 0x12, 0x86, 0x11, 0xC3, 0x10, ++ 0x04, 0x11, 0xC2, 0x10, 0x04, 0x11, 0x04, 0x11, 0x78, 0x00, 0x8A, 0x12, ++ 0x07, 0x12, 0xC3, 0x10, 0x04, 0x11, 0xC2, 0x10, 0x08, 0x12, 0x04, 0x11, ++ 0x78, 0x00, 0x8A, 0x12, 0x07, 0x12, 0x0C, 0x13, 0x08, 0x12, 0x03, 0x11, ++ 0x04, 0x11, 0x04, 0x11, 0x78, 0x00, 0x8A, 0x12, 0x07, 0x12, 0x86, 0x11, ++ 0x04, 0x11, 0xC2, 0x10, 0x04, 0x11, 0x04, 0x11, 0x78, 0x00, 0x8A, 0x12, ++ 0x8A, 0x12, 0x0C, 0x13, 0x04, 0x11, 0x03, 0x11, 0x04, 0x11, 0x04, 0x11, ++ 0x78, 0x00, 0x8A, 0x12, 0x8A, 0x12, 0x86, 0x11, 0x04, 0x11, 0x03, 0x11, ++ 0x9D, 0x87, 0x25, 0x73, 0x3A, 0x20, 0x62, 0x61, 0x6E, 0x64, 0x3D, 0x25, ++ 0x64, 0x20, 0x66, 0x72, 0x65, 0x71, 0x3D, 0x25, 0x64, 0x20, 0x66, 0x72, ++ 0x65, 0x71, 0x31, 0x3D, 0x25, 0x64, 0x20, 0x63, 0x68, 0x61, 0x6E, 0x74, ++ 0x79, 0x70, 0x65, 0x3D, 0x25, 0x64, 0x20, 0x73, 0x78, 0x3D, 0x25, 0x64, ++ 0x0A, 0x00, 0x00, 0x00, 0x73, 0x65, 0x74, 0x63, 0x68, 0x61, 0x6E, 0x3A, ++ 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x73, 0x77, 0x69, 0x74, ++ 0x63, 0x68, 0x20, 0x62, 0x61, 0x6E, 0x64, 0x20, 0x25, 0x64, 0x20, 0x74, ++ 0x6F, 0x20, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x62, 0x61, 0x6E, 0x64, ++ 0x20, 0x3C, 0x20, 0x50, 0x48, 0x59, 0x5F, 0x42, 0x41, 0x4E, 0x44, 0x5F, ++ 0x4D, 0x41, 0x58, 0x00, 0x28, 0x6D, 0x64, 0x6D, 0x5F, 0x6D, 0x61, 0x6A, ++ 0x6F, 0x72, 0x5F, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, 0x67, ++ 0x65, 0x74, 0x66, 0x28, 0x29, 0x20, 0x2B, 0x20, 0x32, 0x29, 0x20, 0x2A, ++ 0x20, 0x31, 0x30, 0x20, 0x2B, 0x20, 0x6D, 0x64, 0x6D, 0x5F, 0x6D, 0x69, ++ 0x6E, 0x6F, 0x72, 0x5F, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5F, ++ 0x67, 0x65, 0x74, 0x66, 0x28, 0x29, 0x20, 0x3D, 0x3D, 0x20, 0x4E, 0x58, ++ 0x5F, 0x4D, 0x44, 0x4D, 0x5F, 0x56, 0x45, 0x52, 0x00, 0x00, 0x00, 0x00, ++ 0x9B, 0x87, 0x25, 0x73, 0x3A, 0x20, 0x72, 0x61, 0x64, 0x69, 0x6F, 0x20, ++ 0x25, 0x64, 0x20, 0x64, 0x6F, 0x65, 0x73, 0x20, 0x6E, 0x6F, 0x74, 0x20, ++ 0x65, 0x78, 0x69, 0x73, 0x74, 0x0A, 0x00, 0x00, 0x9D, 0x87, 0x25, 0x73, ++ 0x3A, 0x20, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x73, 0x61, ++ 0x6D, 0x65, 0x20, 0x63, 0x68, 0x61, 0x6E, 0x6E, 0x65, 0x6C, 0x2C, 0x20, ++ 0x64, 0x6F, 0x20, 0x6E, 0x6F, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x0A, 0x00, ++ 0x9B, 0x25, 0x73, 0x20, 0x4D, 0x41, 0x43, 0x20, 0x73, 0x74, 0x61, 0x74, ++ 0x65, 0x20, 0x21, 0x3D, 0x20, 0x49, 0x44, 0x4C, 0x45, 0x0A, 0x00, 0x00, ++ 0x70, 0x68, 0x79, 0x5F, 0x68, 0x77, 0x5F, 0x73, 0x65, 0x74, 0x5F, 0x63, ++ 0x68, 0x61, 0x6E, 0x6E, 0x65, 0x6C, 0x00, 0x00, 0x70, 0x68, 0x79, 0x5F, ++ 0x73, 0x65, 0x74, 0x5F, 0x63, 0x68, 0x61, 0x6E, 0x6E, 0x65, 0x6C, 0x00, ++ 0x70, 0x68, 0x79, 0x5F, 0x67, 0x65, 0x74, 0x5F, 0x63, 0x68, 0x61, 0x6E, ++ 0x6E, 0x65, 0x6C, 0x00, 0x70, 0x68, 0x79, 0x5F, 0x73, 0x74, 0x6F, 0x70, ++ 0x00, 0x00, 0x00, 0x00, 0x0C, 0x03, 0x0D, 0xFE, 0x11, 0xFE, 0x0D, 0x02, ++ 0x0E, 0xFF, 0x13, 0xFE, 0x0B, 0x02, 0x0C, 0xFD, 0x12, 0xFD, 0x0C, 0x03, ++ 0x0D, 0xFE, 0x13, 0xFD, 0x0B, 0x03, 0x0C, 0xFD, 0x14, 0xFD, 0x0A, 0x03, ++ 0x0B, 0xFC, 0x11, 0xFF, 0x0D, 0x01, 0x0E, 0xFF, 0x13, 0xFD, 0x0B, 0x03, ++ 0x0C, 0xFD, 0x12, 0xFE, 0x0C, 0x02, 0x0D, 0xFE, 0x12, 0xFE, 0x0C, 0x02, ++ 0x0D, 0xFE, 0x12, 0xFE, 0x0C, 0x02, 0x0D, 0xFE, 0x13, 0xFE, 0x0B, 0x02, ++ 0x0C, 0xFD, 0x1F, 0x00, 0x0C, 0x02, 0x0D, 0xFE, 0x11, 0x00, 0x0D, 0x00, ++ 0x0E, 0xFF, 0x13, 0x03, 0x0B, 0x03, 0x0C, 0xFD, 0x14, 0xFC, 0x0A, 0x04, ++ 0x0B, 0xFC, 0x12, 0xFF, 0x0C, 0x01, 0x0D, 0xFE, 0x11, 0xFE, 0x0D, 0x02, ++ 0x0E, 0xFF, 0x13, 0xFE, 0x0B, 0x02, 0x0C, 0xFD, 0x13, 0xFD, 0x0B, 0x03, ++ 0x0C, 0xFD, 0x12, 0xFF, 0x0C, 0x01, 0x0D, 0xFE, 0x12, 0xFD, 0x0C, 0x03, ++ 0x0D, 0xFE, 0x12, 0xFF, 0x0C, 0x01, 0x0D, 0xFE, 0x13, 0xFD, 0x0B, 0x03, ++ 0x0C, 0xFD, 0x13, 0xFE, 0x0B, 0x02, 0x0C, 0xFD, 0x1F, 0x00, 0x00, 0x00, ++ 0x69, 0x6E, 0x74, 0x63, 0x5F, 0x73, 0x70, 0x75, 0x72, 0x69, 0x6F, 0x75, ++ 0x73, 0x00, 0x00, 0x00, 0x18, 0x10, 0x0C, 0x08, 0x07, 0x06, 0x8B, 0x05, ++ 0x89, 0x04, 0x87, 0x03, 0x85, 0x02, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, ++ 0x73, 0x65, 0x74, 0x20, 0x74, 0x78, 0x67, 0x61, 0x69, 0x6E, 0x20, 0x74, ++ 0x61, 0x62, 0x6C, 0x65, 0x20, 0x32, 0x2E, 0x34, 0x67, 0x28, 0x70, 0x61, ++ 0x5F, 0x64, 0x72, 0x76, 0x5F, 0x69, 0x62, 0x69, 0x74, 0x29, 0x3A, 0x25, ++ 0x78, 0x0A, 0x00, 0x00, 0x77, 0x66, 0x20, 0x64, 0x66, 0x65, 0x20, 0x61, ++ 0x6E, 0x64, 0x20, 0x72, 0x66, 0x69, 0x6E, 0x74, 0x66, 0x20, 0x52, 0x58, ++ 0x4F, 0x4E, 0x21, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x77, 0x66, 0x20, 0x64, ++ 0x66, 0x65, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x72, 0x66, 0x69, 0x6E, 0x74, ++ 0x66, 0x20, 0x52, 0x58, 0x4F, 0x46, 0x46, 0x21, 0x0D, 0x0A, 0x00, 0x00, ++ 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x20, 0x64, 0x69, 0x76, 0x69, 0x73, ++ 0x69, 0x6F, 0x6E, 0x20, 0x62, 0x79, 0x20, 0x7A, 0x65, 0x72, 0x6F, 0x20, ++ 0x69, 0x6E, 0x20, 0x63, 0x61, 0x6C, 0x5F, 0x6C, 0x73, 0x20, 0x64, 0x65, ++ 0x74, 0x20, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x73, 0x6C, 0x6F, 0x70, ++ 0x65, 0x20, 0x74, 0x6F, 0x6F, 0x20, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x0D, ++ 0x0A, 0x00, 0x00, 0x00, 0x67, 0x61, 0x69, 0x6E, 0x20, 0x25, 0x78, 0x20, ++ 0x3A, 0x20, 0x66, 0x69, 0x74, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, ++ 0x20, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x67, 0x61, 0x69, 0x6E, ++ 0x20, 0x25, 0x78, 0x20, 0x3A, 0x20, 0x66, 0x69, 0x74, 0x5F, 0x66, 0x61, ++ 0x69, 0x6C, 0x65, 0x64, 0x21, 0x0D, 0x0A, 0x00, 0x63, 0x6F, 0x65, 0x66, ++ 0x5F, 0x49, 0x51, 0x20, 0x20, 0x69, 0x73, 0x20, 0x25, 0x64, 0x2E, 0x00, ++ 0x25, 0x30, 0x33, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x63, 0x61, 0x6C, 0x20, ++ 0x73, 0x64, 0x6D, 0x20, 0x20, 0x69, 0x73, 0x20, 0x25, 0x78, 0x0D, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x63, 0x61, 0x6C, 0x20, 0x66, 0x72, 0x65, 0x71, ++ 0x20, 0x69, 0x73, 0x20, 0x25, 0x78, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x63, 0x61, 0x6C, 0x20, 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x69, 0x73, 0x20, ++ 0x25, 0x78, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x72, 0x66, 0x65, 0x6E, ++ 0x20, 0x72, 0x65, 0x67, 0x20, 0x69, 0x73, 0x20, 0x25, 0x78, 0x0D, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x77, 0x66, 0x20, 0x64, 0x63, 0x63, 0x61, 0x6C, ++ 0x69, 0x62, 0x20, 0x62, 0x65, 0x67, 0x69, 0x6E, 0x21, 0x0D, 0x0A, 0x00, ++ 0x66, 0x69, 0x74, 0x2D, 0x69, 0x6E, 0x2D, 0x49, 0x20, 0x25, 0x78, 0x3A, ++ 0x20, 0x5B, 0x25, 0x64, 0x2C, 0x25, 0x64, 0x3B, 0x25, 0x64, 0x2C, 0x25, ++ 0x64, 0x3B, 0x25, 0x64, 0x2C, 0x25, 0x64, 0x3B, 0x25, 0x64, 0x2C, 0x25, ++ 0x64, 0x5D, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x66, 0x69, 0x74, 0x2D, ++ 0x69, 0x6E, 0x2D, 0x51, 0x20, 0x25, 0x78, 0x3A, 0x20, 0x5B, 0x25, 0x64, ++ 0x2C, 0x25, 0x64, 0x3B, 0x25, 0x64, 0x2C, 0x25, 0x64, 0x3B, 0x25, 0x64, ++ 0x2C, 0x25, 0x64, 0x3B, 0x25, 0x64, 0x2C, 0x25, 0x64, 0x5D, 0x0D, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x67, 0x61, 0x69, 0x6E, 0x20, 0x25, 0x78, 0x20, ++ 0x3A, 0x20, 0x63, 0x61, 0x6C, 0x49, 0x20, 0x25, 0x78, 0x2C, 0x20, 0x63, ++ 0x61, 0x6C, 0x51, 0x20, 0x25, 0x78, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x77, 0x66, 0x20, 0x64, 0x63, 0x63, 0x61, 0x6C, 0x69, 0x62, 0x20, 0x65, ++ 0x6E, 0x64, 0x21, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x63, 0x61, 0x6C, 0x5F, ++ 0x63, 0x66, 0x67, 0x3A, 0x25, 0x78, 0x2C, 0x20, 0x61, 0x6C, 0x70, 0x68, ++ 0x61, 0x3D, 0x25, 0x78, 0x0D, 0x0A, 0x00, 0x00, 0x70, 0x6C, 0x6C, 0x20, ++ 0x75, 0x6E, 0x6C, 0x6F, 0x63, 0x6B, 0x3A, 0x20, 0x25, 0x78, 0x0D, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x77, 0x66, 0x72, 0x66, 0x20, 0x6F, 0x6E, 0x0D, ++ 0x0A, 0x00, 0x00, 0x00, 0x77, 0x66, 0x72, 0x66, 0x20, 0x6F, 0x66, 0x66, ++ 0x0D, 0x0A, 0x00, 0x00, 0x20, 0x2A, 0x20, 0x63, 0x61, 0x6C, 0x20, 0x74, ++ 0x69, 0x61, 0x5F, 0x69, 0x71, 0x3A, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x20, 0x20, 0x49, 0x69, 0x30, 0x3D, 0x25, 0x64, 0x2C, 0x20, 0x49, 0x71, ++ 0x30, 0x3D, 0x25, 0x64, 0x2C, 0x20, 0x56, 0x69, 0x30, 0x3D, 0x25, 0x64, ++ 0x2C, 0x20, 0x56, 0x71, 0x30, 0x3D, 0x25, 0x64, 0x3B, 0x0D, 0x0A, 0x00, ++ 0x20, 0x20, 0x49, 0x69, 0x31, 0x3D, 0x25, 0x64, 0x2C, 0x20, 0x49, 0x71, ++ 0x31, 0x3D, 0x25, 0x64, 0x2C, 0x20, 0x56, 0x69, 0x31, 0x3D, 0x25, 0x64, ++ 0x2C, 0x20, 0x56, 0x71, 0x31, 0x3D, 0x25, 0x64, 0x3B, 0x0D, 0x0A, 0x00, ++ 0x20, 0x61, 0x64, 0x6A, 0x49, 0x69, 0x20, 0x3D, 0x20, 0x25, 0x64, 0x2C, ++ 0x20, 0x61, 0x64, 0x6A, 0x49, 0x71, 0x20, 0x3D, 0x20, 0x25, 0x64, 0x0D, ++ 0x0A, 0x00, 0x00, 0x00, 0x2D, 0x3E, 0x20, 0x49, 0x69, 0x30, 0x3D, 0x25, ++ 0x64, 0x2C, 0x20, 0x49, 0x71, 0x30, 0x3D, 0x25, 0x64, 0x2C, 0x20, 0x56, ++ 0x69, 0x30, 0x3D, 0x25, 0x64, 0x2C, 0x20, 0x56, 0x71, 0x30, 0x3D, 0x25, ++ 0x64, 0x3B, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x6C, 0x6E, 0x61, ++ 0x5F, 0x76, 0x63, 0x6D, 0x70, 0x3D, 0x25, 0x64, 0x2C, 0x20, 0x6C, 0x6E, ++ 0x61, 0x5F, 0x76, 0x63, 0x6D, 0x6E, 0x3D, 0x25, 0x64, 0x3B, 0x0D, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x73, 0x65, 0x74, 0x20, 0x67, 0x61, 0x69, 0x6E, ++ 0x20, 0x3D, 0x20, 0x25, 0x64, 0x3B, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x77, 0x66, 0x72, 0x66, 0x20, 0x63, 0x61, 0x6C, 0x69, 0x62, 0x0D, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x69, 0x64, 0x78, 0x5F, 0x6D, 0x61, 0x78, 0x20, ++ 0x3C, 0x3D, 0x20, 0x33, 0x00, 0x00, 0x00, 0x00, 0x69, 0x64, 0x78, 0x5F, ++ 0x6D, 0x69, 0x6E, 0x20, 0x3C, 0x3D, 0x20, 0x69, 0x64, 0x78, 0x5F, 0x6D, ++ 0x61, 0x78, 0x00, 0x00, 0x73, 0x66, 0x74, 0x20, 0x64, 0x69, 0x73, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x73, 0x66, 0x74, 0x72, 0x73, 0x74, 0x20, 0x64, ++ 0x6F, 0x6E, 0x65, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x6F, 0x61, 0x64, ++ 0x5F, 0x76, 0x61, 0x6C, 0x20, 0x3D, 0x20, 0x30, 0x78, 0x25, 0x78, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x72, 0x78, 0x75, 0x73, 0x65, 0x64, 0x3D, 0x25, ++ 0x64, 0x2C, 0x20, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x3D, 0x25, 0x64, 0x0D, ++ 0x0A, 0x00, 0x00, 0x00, 0x68, 0x6F, 0x73, 0x74, 0x5F, 0x62, 0x75, 0x66, ++ 0x5F, 0x64, 0x6D, 0x61, 0x5F, 0x61, 0x64, 0x64, 0x72, 0x20, 0x21, 0x3D, ++ 0x20, 0x30, 0x00, 0x00, 0x6B, 0x6D, 0x73, 0x67, 0x5F, 0x64, 0x73, 0x74, ++ 0x20, 0x21, 0x3D, 0x20, 0x4E, 0x55, 0x4C, 0x4C, 0x00, 0x00, 0x00, 0x00, ++ 0x69, 0x64, 0x20, 0x3C, 0x3D, 0x20, 0x54, 0x41, 0x53, 0x4B, 0x5F, 0x4D, ++ 0x41, 0x58, 0x00, 0x00, 0x6B, 0x65, 0x5F, 0x74, 0x61, 0x73, 0x6B, 0x5F, ++ 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x28, 0x6B, 0x6D, 0x73, 0x67, 0x5F, 0x64, ++ 0x73, 0x74, 0x2D, 0x3E, 0x64, 0x65, 0x73, 0x74, 0x5F, 0x69, 0x64, 0x29, ++ 0x00, 0x00, 0x00, 0x00, 0x68, 0x6F, 0x73, 0x74, 0x6D, 0x73, 0x67, 0x62, ++ 0x75, 0x66, 0x20, 0x21, 0x3D, 0x20, 0x30, 0x00, 0x68, 0x6F, 0x73, 0x74, ++ 0x5F, 0x6D, 0x73, 0x67, 0x5F, 0x62, 0x75, 0x66, 0x20, 0x21, 0x3D, 0x20, ++ 0x30, 0x00, 0x00, 0x00, 0x69, 0x70, 0x63, 0x5F, 0x65, 0x6D, 0x62, 0x5F, ++ 0x6B, 0x6D, 0x73, 0x67, 0x5F, 0x66, 0x77, 0x64, 0x3A, 0x20, 0x6E, 0x6F, ++ 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x20, 0x6D, 0x73, 0x67, 0x69, ++ 0x64, 0x3D, 0x25, 0x78, 0x2C, 0x73, 0x72, 0x63, 0x69, 0x64, 0x3D, 0x25, ++ 0x78, 0x2C, 0x64, 0x73, 0x74, 0x69, 0x64, 0x3D, 0x25, 0x78, 0x0D, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x65, 0x72, 0x72, 0x21, 0x21, 0x21, 0x20, 0x69, ++ 0x70, 0x63, 0x20, 0x6D, 0x73, 0x67, 0x20, 0x6E, 0x6F, 0x20, 0x62, 0x75, ++ 0x66, 0x66, 0x65, 0x72, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x75, 0x73, 0x62, ++ 0x20, 0x69, 0x6E, 0x20, 0x25, 0x64, 0x2C, 0x20, 0x66, 0x72, 0x65, 0x65, ++ 0x20, 0x25, 0x64, 0x2C, 0x20, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, ++ 0x6B, 0x6D, 0x73, 0x67, 0x5F, 0x73, 0x72, 0x63, 0x2D, 0x3E, 0x70, 0x61, ++ 0x72, 0x61, 0x6D, 0x5F, 0x6C, 0x65, 0x6E, 0x20, 0x3C, 0x3D, 0x20, 0x73, ++ 0x69, 0x7A, 0x65, 0x6F, 0x66, 0x28, 0x6D, 0x73, 0x67, 0x2D, 0x3E, 0x70, ++ 0x61, 0x72, 0x61, 0x6D, 0x29, 0x00, 0x00, 0x00, 0x73, 0x65, 0x6E, 0x64, ++ 0x20, 0x6D, 0x73, 0x67, 0x20, 0x63, 0x66, 0x67, 0x20, 0x74, 0x6F, 0x20, ++ 0x68, 0x6F, 0x73, 0x74, 0x20, 0x68, 0x61, 0x73, 0x20, 0x6E, 0x6F, 0x20, ++ 0x64, 0x73, 0x63, 0x72, 0x21, 0x0D, 0x0A, 0x00, 0x63, 0x68, 0x61, 0x6E, ++ 0x20, 0x6E, 0x6F, 0x74, 0x69, 0x66, 0x79, 0x3A, 0x20, 0x25, 0x78, 0x0D, ++ 0x0A, 0x00, 0x00, 0x00, 0x42, 0x54, 0x20, 0x77, 0x61, 0x6B, 0x65, 0x75, ++ 0x70, 0x20, 0x68, 0x6F, 0x73, 0x74, 0x3A, 0x25, 0x78, 0x0A, 0x00, 0x00, ++ 0x70, 0x6D, 0x69, 0x63, 0x20, 0x67, 0x70, 0x69, 0x6F, 0x0A, 0x00, 0x00, ++ 0x77, 0x6B, 0x62, 0x74, 0x3D, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, ++ 0x50, 0x4D, 0x49, 0x43, 0x5F, 0x45, 0x52, 0x52, 0x49, 0x52, 0x51, 0x3D, ++ 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, ++ 0x00, 0x10, 0x00, 0x00, 0x63, 0x68, 0x61, 0x6E, 0x6E, 0x65, 0x6C, 0x5F, ++ 0x69, 0x64, 0x78, 0x20, 0x3C, 0x20, 0x49, 0x50, 0x43, 0x5F, 0x44, 0x4D, ++ 0x41, 0x5F, 0x43, 0x48, 0x41, 0x4E, 0x4E, 0x45, 0x4C, 0x5F, 0x4D, 0x41, ++ 0x58, 0x00, 0x00, 0x00, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x23, 0x20, ++ 0x3D, 0x25, 0x64, 0x20, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x76, 0x69, 0x66, 0x2D, 0x3E, 0x75, 0x2E, 0x73, 0x74, 0x61, 0x2E, 0x6C, ++ 0x61, 0x73, 0x74, 0x65, 0x73, 0x74, 0x5F, 0x63, 0x6F, 0x6E, 0x6E, 0x5F, ++ 0x76, 0x61, 0x6C, 0x69, 0x64, 0x20, 0x3D, 0x3D, 0x20, 0x31, 0x00, 0x00, ++ 0x73, 0x74, 0x61, 0x2D, 0x3E, 0x6C, 0x61, 0x73, 0x74, 0x65, 0x73, 0x74, ++ 0x5F, 0x63, 0x6F, 0x6E, 0x6E, 0x5F, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x20, ++ 0x3D, 0x3D, 0x20, 0x31, 0x00, 0x00, 0x00, 0x00, 0x61, 0x70, 0x6D, 0x20, ++ 0x73, 0x74, 0x61, 0x3A, 0x25, 0x64, 0x0A, 0x00, 0x74, 0x3A, 0x25, 0x64, ++ 0x2C, 0x20, 0x72, 0x3A, 0x25, 0x64, 0x2C, 0x20, 0x72, 0x72, 0x3A, 0x25, ++ 0x64, 0x0A, 0x00, 0x00, 0x73, 0x74, 0x61, 0x74, 0x20, 0x6C, 0x6F, 0x73, ++ 0x73, 0x31, 0x0A, 0x00, 0x63, 0x6C, 0x65, 0x61, 0x72, 0x0A, 0x00, 0x00, ++ 0x73, 0x74, 0x61, 0x74, 0x20, 0x6C, 0x6F, 0x73, 0x73, 0x0A, 0x00, 0x00, ++ 0x74, 0x78, 0x64, 0x65, 0x73, 0x63, 0x5F, 0x74, 0x6D, 0x70, 0x2D, 0x3E, ++ 0x68, 0x6F, 0x73, 0x74, 0x2E, 0x73, 0x74, 0x61, 0x69, 0x64, 0x20, 0x3C, ++ 0x20, 0x4E, 0x58, 0x5F, 0x52, 0x45, 0x4D, 0x4F, 0x54, 0x45, 0x5F, 0x53, ++ 0x54, 0x41, 0x5F, 0x4D, 0x41, 0x58, 0x00, 0x00, 0x73, 0x74, 0x61, 0x20, ++ 0x69, 0x6E, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x3A, 0x25, 0x64, 0x0A, 0x00, ++ 0x74, 0x78, 0x64, 0x65, 0x73, 0x63, 0x5F, 0x74, 0x6D, 0x70, 0x2D, 0x3E, ++ 0x68, 0x6F, 0x73, 0x74, 0x2E, 0x66, 0x6C, 0x61, 0x67, 0x73, 0x20, 0x26, ++ 0x20, 0x54, 0x58, 0x55, 0x5F, 0x43, 0x4E, 0x54, 0x52, 0x4C, 0x5F, 0x52, ++ 0x45, 0x54, 0x52, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xD9, 0x67, 0x12, 0x00, 0xF9, 0x67, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x73, 0x65, 0x74, 0x5F, 0x6E, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5F, 0x70, ++ 0x6F, 0x6F, 0x6C, 0x5F, 0x69, 0x64, 0x3A, 0x20, 0x49, 0x6E, 0x76, 0x61, ++ 0x6C, 0x69, 0x64, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x20, 0x70, ++ 0x61, 0x73, 0x73, 0x65, 0x64, 0x3A, 0x20, 0x25, 0x78, 0x0A, 0x00, 0x00, ++ 0x73, 0x65, 0x74, 0x5F, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6E, 0x3A, ++ 0x20, 0x49, 0x6E, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x20, 0x62, 0x75, 0x66, ++ 0x66, 0x65, 0x72, 0x20, 0x70, 0x61, 0x73, 0x73, 0x65, 0x64, 0x3A, 0x20, ++ 0x25, 0x78, 0x0A, 0x00, 0x73, 0x65, 0x74, 0x5F, 0x6E, 0x75, 0x6D, 0x5F, ++ 0x75, 0x73, 0x65, 0x72, 0x73, 0x3A, 0x20, 0x49, 0x6E, 0x76, 0x61, 0x6C, ++ 0x69, 0x64, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x20, 0x70, 0x61, ++ 0x73, 0x73, 0x65, 0x64, 0x3A, 0x20, 0x25, 0x78, 0x0A, 0x00, 0x00, 0x00, ++ 0x73, 0x65, 0x74, 0x5F, 0x6E, 0x65, 0x78, 0x74, 0x5F, 0x62, 0x75, 0x66, ++ 0x66, 0x65, 0x72, 0x5F, 0x61, 0x64, 0x64, 0x72, 0x3A, 0x20, 0x49, 0x6E, ++ 0x76, 0x61, 0x6C, 0x69, 0x64, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, ++ 0x20, 0x70, 0x61, 0x73, 0x73, 0x65, 0x64, 0x3A, 0x20, 0x25, 0x78, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x4D, 0x65, 0x6D, 0x4D, 0x67, 0x72, 0x45, 0x72, ++ 0x72, 0x3A, 0x20, 0x53, 0x75, 0x62, 0x70, 0x6F, 0x6F, 0x6C, 0x20, 0x4E, ++ 0x55, 0x4C, 0x4C, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x53, 0x77, 0x45, 0x72, ++ 0x3A, 0x4E, 0x6F, 0x53, 0x69, 0x7A, 0x65, 0x41, 0x6C, 0x6C, 0x6F, 0x63, ++ 0x20, 0x3A, 0x20, 0x25, 0x64, 0x0A, 0x0D, 0x00, 0x67, 0x65, 0x74, 0x5F, ++ 0x6E, 0x65, 0x78, 0x74, 0x5F, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5F, ++ 0x61, 0x64, 0x64, 0x72, 0x3A, 0x20, 0x49, 0x6E, 0x76, 0x61, 0x6C, 0x69, ++ 0x64, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x20, 0x70, 0x61, 0x73, ++ 0x73, 0x65, 0x64, 0x3A, 0x20, 0x25, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x67, 0x65, 0x74, 0x5F, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6E, 0x3A, ++ 0x20, 0x49, 0x6E, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x20, 0x62, 0x75, 0x66, ++ 0x66, 0x65, 0x72, 0x20, 0x70, 0x61, 0x73, 0x73, 0x65, 0x64, 0x3A, 0x20, ++ 0x25, 0x78, 0x0A, 0x00, 0x53, 0x77, 0x45, 0x72, 0x3A, 0x41, 0x6C, 0x6C, ++ 0x63, 0x45, 0x72, 0x72, 0x50, 0x74, 0x72, 0x6E, 0x20, 0x3A, 0x20, 0x25, ++ 0x64, 0x2C, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x3A, 0x20, 0x30, ++ 0x78, 0x25, 0x78, 0x0A, 0x0D, 0x00, 0x00, 0x00, 0x67, 0x65, 0x74, 0x5F, ++ 0x6E, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5F, 0x70, 0x6F, 0x6F, 0x6C, 0x5F, ++ 0x69, 0x64, 0x3A, 0x20, 0x49, 0x6E, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x20, ++ 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x20, 0x70, 0x61, 0x73, 0x73, 0x65, ++ 0x64, 0x3A, 0x20, 0x25, 0x78, 0x0A, 0x00, 0x00, 0x64, 0x65, 0x63, 0x72, ++ 0x5F, 0x6E, 0x75, 0x6D, 0x5F, 0x75, 0x73, 0x65, 0x72, 0x73, 0x3A, 0x20, ++ 0x49, 0x6E, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x20, 0x62, 0x75, 0x66, 0x66, ++ 0x65, 0x72, 0x20, 0x70, 0x61, 0x73, 0x73, 0x65, 0x64, 0x3A, 0x20, 0x25, ++ 0x78, 0x0A, 0x00, 0x00, 0x73, 0x65, 0x74, 0x5F, 0x75, 0x73, 0x65, 0x72, ++ 0x5F, 0x69, 0x64, 0x3A, 0x20, 0x49, 0x6E, 0x76, 0x61, 0x6C, 0x69, 0x64, ++ 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x20, 0x70, 0x61, 0x73, 0x73, ++ 0x65, 0x64, 0x3A, 0x20, 0x25, 0x78, 0x0A, 0x00, 0x6E, 0x61, 0x74, 0x69, ++ 0x76, 0x65, 0x5F, 0x69, 0x64, 0x20, 0x3D, 0x3D, 0x20, 0x32, 0x00, 0x00, ++ 0x67, 0x65, 0x74, 0x5F, 0x75, 0x73, 0x65, 0x72, 0x5F, 0x69, 0x64, 0x3A, ++ 0x20, 0x49, 0x6E, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x20, 0x62, 0x75, 0x66, ++ 0x66, 0x65, 0x72, 0x20, 0x70, 0x61, 0x73, 0x73, 0x65, 0x64, 0x3A, 0x20, ++ 0x25, 0x78, 0x0A, 0x00, 0x72, 0x65, 0x70, 0x3A, 0x20, 0x6E, 0x6F, 0x20, ++ 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x2C, 0x20, 0x25, 0x64, 0x0D, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x72, 0x65, 0x70, 0x3A, 0x20, 0x6E, 0x6F, 0x20, ++ 0x64, 0x65, 0x73, 0x63, 0x0D, 0x0A, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, ++ 0x6D, 0x20, 0x65, 0x72, 0x72, 0x6F, 0x72, 0x0D, 0x0A, 0x00, 0x00, 0x00, ++ 0x63, 0x6E, 0x74, 0x20, 0x65, 0x72, 0x72, 0x6F, 0x72, 0x0D, 0x0A, 0x00, ++ 0x69, 0x3D, 0x25, 0x64, 0x2C, 0x20, 0x6E, 0x75, 0x6D, 0x3D, 0x25, 0x64, ++ 0x2C, 0x20, 0x72, 0x78, 0x64, 0x65, 0x73, 0x63, 0x3D, 0x25, 0x78, 0x2C, ++ 0x20, 0x25, 0x78, 0x2C, 0x20, 0x25, 0x78, 0x0D, 0x0A, 0x00, 0x00, 0x00, ++ 0x61, 0x63, 0x3E, 0x3D, 0x4E, 0x58, 0x5F, 0x54, 0x58, 0x51, 0x5F, 0x43, ++ 0x4E, 0x54, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x61, 0x63, 0x20, 0x3C, ++ 0x20, 0x4E, 0x58, 0x5F, 0x54, 0x58, 0x51, 0x5F, 0x43, 0x4E, 0x54, 0x20, ++ 0x2B, 0x20, 0x31, 0x00, 0x74, 0x78, 0x64, 0x65, 0x73, 0x63, 0x5F, 0x6E, ++ 0x65, 0x77, 0x20, 0x21, 0x3D, 0x20, 0x4E, 0x55, 0x4C, 0x4C, 0x00, 0x00, ++ 0x6D, 0x73, 0x67, 0x20, 0x63, 0x72, 0x63, 0x20, 0x65, 0x72, 0x72, 0x0D, ++ 0x0A, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x74, 0x5F, 0x73, 0x74, 0x61, 0x74, ++ 0x75, 0x73, 0x20, 0x21, 0x3D, 0x20, 0x30, 0x00, 0x73, 0x6F, 0x66, 0x74, ++ 0x77, 0x6B, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x64, 0x6D, 0x61, 0x20, ++ 0x69, 0x6E, 0x74, 0x20, 0x25, 0x78, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x73, 0x64, 0x69, 0x6F, 0x20, 0x69, 0x6E, 0x76, 0x61, 0x6C, 0x69, 0x64, ++ 0x3A, 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x3D, 0x25, 0x78, 0x0D, ++ 0x0A, 0x00, 0x00, 0x00, 0x73, 0x64, 0x69, 0x6F, 0x20, 0x68, 0x6F, 0x73, ++ 0x74, 0x20, 0x72, 0x65, 0x73, 0x65, 0x74, 0x0D, 0x0A, 0x00, 0x00, 0x00, ++ 0x61, 0x68, 0x62, 0x32, 0x73, 0x64, 0x69, 0x6F, 0x20, 0x74, 0x78, 0x20, ++ 0x61, 0x62, 0x6F, 0x72, 0x74, 0x0D, 0x0A, 0x00, 0x53, 0x44, 0x49, 0x4F, ++ 0x32, 0x41, 0x48, 0x42, 0x5F, 0x4C, 0x4C, 0x53, 0x54, 0x5F, 0x48, 0x44, ++ 0x52, 0x5F, 0x45, 0x52, 0x52, 0x0D, 0x0A, 0x00, 0x73, 0x64, 0x69, 0x6F, ++ 0x20, 0x65, 0x72, 0x72, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x3D, ++ 0x25, 0x78, 0x2C, 0x30, 0x78, 0x34, 0x35, 0x3D, 0x25, 0x78, 0x0A, 0x00, ++ 0x6D, 0x73, 0x67, 0x72, 0x78, 0x75, 0x73, 0x65, 0x64, 0x3D, 0x25, 0x64, ++ 0x2C, 0x20, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x3D, 0x25, 0x64, 0x0D, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x74, 0x78, 0x63, 0x75, 0x73, 0x65, 0x64, 0x3D, ++ 0x25, 0x64, 0x2C, 0x20, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x3D, 0x25, 0x64, ++ 0x0D, 0x0A, 0x00, 0x00, 0x74, 0x78, 0x63, 0x6D, 0x73, 0x67, 0x75, 0x73, ++ 0x65, 0x64, 0x3D, 0x25, 0x64, 0x2C, 0x20, 0x6D, 0x73, 0x67, 0x74, 0x6F, ++ 0x74, 0x61, 0x6C, 0x3D, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x77, 0x61, 0x69, 0x74, 0x20, 0x69, 0x6F, 0x20, 0x65, 0x6E, 0x61, 0x62, ++ 0x6C, 0x65, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x69, 0x6F, 0x20, 0x65, ++ 0x6E, 0x61, 0x62, 0x6C, 0x65, 0x0D, 0x0A, 0x00, 0x65, 0x72, 0x72, 0x3A, ++ 0x20, 0x6E, 0x6F, 0x20, 0x6D, 0x73, 0x67, 0x20, 0x70, 0x6B, 0x74, 0x21, ++ 0x0D, 0x0A, 0x00, 0x00, 0x65, 0x72, 0x72, 0x3A, 0x20, 0x6E, 0x6F, 0x20, ++ 0x64, 0x73, 0x63, 0x72, 0x21, 0x0D, 0x0A, 0x00, 0x6F, 0x70, 0x65, 0x6E, ++ 0x3A, 0x25, 0x64, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x55, 0x4C, 0x50, 0x49, ++ 0x20, 0x63, 0x6C, 0x6B, 0x20, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x65, ++ 0x64, 0x0D, 0x0A, 0x00, 0x65, 0x72, 0x72, 0x21, 0x21, 0x20, 0x6E, 0x6F, ++ 0x20, 0x75, 0x73, 0x62, 0x20, 0x75, 0x6C, 0x70, 0x69, 0x20, 0x63, 0x6C, ++ 0x6B, 0x0D, 0x0A, 0x00, 0x77, 0x61, 0x69, 0x74, 0x20, 0x63, 0x66, 0x67, ++ 0x0A, 0x00, 0x00, 0x00, 0x46, 0x49, 0x46, 0x4F, 0x20, 0x45, 0x52, 0x52, ++ 0x4F, 0x52, 0x3A, 0x20, 0x6F, 0x76, 0x65, 0x72, 0x66, 0x6C, 0x6F, 0x77, ++ 0x2C, 0x20, 0x61, 0x64, 0x64, 0x72, 0x20, 0x69, 0x73, 0x20, 0x25, 0x64, ++ 0x2C, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x20, 0x69, 0x73, 0x20, 0x25, 0x64, ++ 0x2C, 0x20, 0x54, 0x6F, 0x74, 0x61, 0x6C, 0x20, 0x52, 0x41, 0x4D, 0x20, ++ 0x69, 0x73, 0x20, 0x25, 0x64, 0x00, 0x00, 0x00, 0x65, 0x72, 0x72, 0x21, ++ 0x21, 0x21, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E, 0x6D, 0x65, 0x6E, 0x74, ++ 0x20, 0x65, 0x72, 0x72, 0x0D, 0x0A, 0x00, 0x00, 0x45, 0x50, 0x30, 0x20, ++ 0x53, 0x45, 0x54, 0x55, 0x50, 0x20, 0x45, 0x52, 0x52, 0x4F, 0x52, 0x2C, ++ 0x20, 0x64, 0x69, 0x72, 0x20, 0x65, 0x72, 0x72, 0x6F, 0x72, 0x00, 0x00, ++ 0x45, 0x50, 0x30, 0x20, 0x53, 0x45, 0x54, 0x55, 0x50, 0x20, 0x45, 0x52, ++ 0x52, 0x4F, 0x52, 0x2C, 0x20, 0x77, 0x4C, 0x65, 0x6E, 0x67, 0x74, 0x68, ++ 0x20, 0x69, 0x73, 0x20, 0x7A, 0x65, 0x72, 0x6F, 0x00, 0x00, 0x00, 0x00, ++ 0x55, 0x6E, 0x6B, 0x6E, 0x6F, 0x77, 0x6E, 0x20, 0x64, 0x65, 0x73, 0x63, ++ 0x72, 0x69, 0x70, 0x74, 0x6F, 0x72, 0x3A, 0x20, 0x25, 0x64, 0x00, 0x00, ++ 0x45, 0x70, 0x30, 0x20, 0x73, 0x65, 0x6E, 0x64, 0x20, 0x6C, 0x65, 0x6E, ++ 0x67, 0x74, 0x68, 0x20, 0x65, 0x72, 0x72, 0x20, 0x25, 0x75, 0x2D, 0x25, ++ 0x75, 0x00, 0x00, 0x00, 0x73, 0x74, 0x61, 0x72, 0x74, 0x20, 0x72, 0x65, ++ 0x62, 0x6F, 0x6F, 0x74, 0x20, 0x25, 0x64, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x72, 0x65, 0x73, 0x65, 0x74, 0x0D, 0x0A, 0x00, 0x65, 0x78, 0x69, 0x74, ++ 0x0D, 0x0A, 0x00, 0x00, 0x75, 0x73, 0x62, 0x20, 0x77, 0x61, 0x6B, 0x65, ++ 0x75, 0x70, 0x0A, 0x00, 0x77, 0x61, 0x6B, 0x65, 0x75, 0x70, 0x20, 0x75, ++ 0x73, 0x62, 0x0A, 0x00, 0x69, 0x72, 0x71, 0x20, 0x25, 0x78, 0x0D, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x77, 0x6C, 0x61, 0x6E, 0x5F, 0x75, 0x73, 0x62, ++ 0x5F, 0x73, 0x75, 0x73, 0x70, 0x65, 0x6E, 0x64, 0x00, 0x00, 0x00, 0x00, ++ 0x52, 0x3A, 0x25, 0x64, 0x0A, 0x00, 0x00, 0x00, 0x77, 0x64, 0x6C, 0x20, ++ 0x65, 0x72, 0x72, 0x20, 0x25, 0x58, 0x20, 0x25, 0x64, 0x20, 0x25, 0x64, ++ 0x0A, 0x00, 0x00, 0x00, 0x77, 0x6D, 0x6C, 0x20, 0x65, 0x72, 0x72, 0x20, ++ 0x25, 0x58, 0x20, 0x25, 0x64, 0x20, 0x25, 0x64, 0x0A, 0x00, 0x00, 0x00, ++ 0x65, 0x72, 0x72, 0x21, 0x21, 0x21, 0x20, 0x6E, 0x6F, 0x20, 0x72, 0x78, ++ 0x20, 0x6D, 0x73, 0x67, 0x20, 0x65, 0x6C, 0x65, 0x6D, 0x0D, 0x0A, 0x00, ++ 0x74, 0x79, 0x70, 0x65, 0x20, 0x65, 0x72, 0x72, 0x20, 0x25, 0x58, 0x0D, ++ 0x0A, 0x00, 0x00, 0x00, 0x6C, 0x65, 0x6E, 0x20, 0x65, 0x72, 0x72, 0x20, ++ 0x25, 0x58, 0x20, 0x25, 0x64, 0x0A, 0x00, 0x00, 0x75, 0x73, 0x62, 0x20, ++ 0x77, 0x6C, 0x61, 0x6E, 0x20, 0x72, 0x65, 0x63, 0x76, 0x20, 0x65, 0x72, ++ 0x72, 0x21, 0x21, 0x21, 0x20, 0x25, 0x64, 0x2C, 0x20, 0x25, 0x64, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x23, 0x23, 0x23, 0x65, 0x72, 0x72, 0x23, 0x23, ++ 0x23, 0x20, 0x25, 0x78, 0x0D, 0x0A, 0x00, 0x00, 0x75, 0x73, 0x62, 0x20, ++ 0x77, 0x6C, 0x61, 0x6E, 0x20, 0x73, 0x65, 0x6E, 0x64, 0x20, 0x65, 0x72, ++ 0x72, 0x21, 0x21, 0x21, 0x20, 0x25, 0x64, 0x2C, 0x20, 0x25, 0x64, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x6F, 0x70, 0x65, 0x6E, 0x20, 0x72, 0x65, 0x73, ++ 0x3A, 0x25, 0x64, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x65, 0x72, 0x72, 0x21, ++ 0x21, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x65, 0x72, 0x72, 0x20, ++ 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x72, 0x65, 0x74, 0x20, ++ 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x09, 0x02, 0x20, 0x00, ++ 0x01, 0x01, 0x00, 0xA0, 0xFA, 0x09, 0x04, 0x00, 0x00, 0x02, 0xFF, 0xFF, ++ 0xFF, 0x00, 0x07, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, 0x07, 0x05, 0x82, ++ 0x02, 0x00, 0x02, 0x00, 0x05, 0x0F, 0x0C, 0x00, 0x01, 0x07, 0x10, 0x02, ++ 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, ++ 0x9C, 0xA6, 0x00, 0x88, 0x00, 0x01, 0x01, 0x02, 0x03, 0x01, 0x00, 0x00, ++ 0x0A, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, ++ 0x06, 0x03, 0x30, 0x00, 0x31, 0x00, 0x00, 0x00, 0x0A, 0x03, 0x77, 0x00, ++ 0x6C, 0x00, 0x61, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x10, 0x03, 0x61, 0x00, ++ 0x69, 0x00, 0x63, 0x00, 0x73, 0x00, 0x65, 0x00, 0x6D, 0x00, 0x69, 0x00, ++ 0x12, 0x03, 0x41, 0x00, 0x49, 0x00, 0x43, 0x00, 0x20, 0x00, 0x57, 0x00, ++ 0x6C, 0x00, 0x61, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x12, 0x03, 0x32, 0x00, ++ 0x30, 0x00, 0x31, 0x00, 0x39, 0x00, 0x30, 0x00, 0x32, 0x00, 0x32, 0x00, ++ 0x37, 0x00, 0x00, 0x00, 0x04, 0x03, 0x09, 0x04, 0x75, 0x73, 0x62, 0x5F, ++ 0x77, 0x6C, 0x61, 0x6E, 0x5F, 0x72, 0x78, 0x5F, 0x70, 0x6B, 0x74, 0x5F, ++ 0x66, 0x72, 0x65, 0x65, 0x5F, 0x6C, 0x69, 0x73, 0x74, 0x5F, 0x69, 0x6E, ++ 0x69, 0x74, 0x20, 0x61, 0x6C, 0x6C, 0x6F, 0x63, 0x20, 0x66, 0x61, 0x69, ++ 0x6C, 0x3A, 0x20, 0x25, 0x64, 0x0A, 0x00, 0x00, 0x77, 0x66, 0x72, 0x0D, ++ 0x0A, 0x00, 0x00, 0x00, 0x68, 0x6F, 0x73, 0x74, 0x20, 0x75, 0x73, 0x62, ++ 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x20, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x69, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x3C, 0x3D, 0x20, 0x68, 0x6F, 0x73, ++ 0x74, 0x5F, 0x69, 0x66, 0x5F, 0x70, 0x61, 0x72, 0x61, 0x6D, 0x2D, 0x3E, ++ 0x64, 0x65, 0x73, 0x63, 0x5F, 0x73, 0x69, 0x7A, 0x65, 0x00, 0x00, 0x00, ++ 0x20, 0x68, 0x6F, 0x73, 0x74, 0x20, 0x72, 0x78, 0x3A, 0x20, 0x64, 0x73, ++ 0x63, 0x72, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x3D, 0x20, 0x25, 0x64, ++ 0x0D, 0x0A, 0x00, 0x00, 0x23, 0x77, 0x66, 0x3A, 0x25, 0x58, 0x0A, 0x00, ++ 0x23, 0x77, 0x65, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x77, 0x64, 0x20, 0x72, ++ 0x78, 0x20, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x65, 0x72, 0x72, 0x21, ++ 0x20, 0x77, 0x64, 0x20, 0x6E, 0x6F, 0x20, 0x72, 0x78, 0x20, 0x62, 0x75, ++ 0x66, 0x0A, 0x00, 0x00, 0x77, 0x64, 0x20, 0x72, 0x78, 0x20, 0x6D, 0x61, ++ 0x78, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, 0x25, 0x64, 0x0D, 0x0A, 0x00, ++ 0x68, 0x6F, 0x73, 0x74, 0x5F, 0x72, 0x65, 0x61, 0x64, 0x79, 0x0A, 0x00, ++ 0x77, 0x6C, 0x61, 0x6E, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x72, 0x65, ++ 0x63, 0x76, 0x20, 0x72, 0x65, 0x74, 0x20, 0x25, 0x64, 0x0A, 0x00, 0x00, ++ 0x65, 0x72, 0x72, 0x3A, 0x20, 0x6E, 0x6F, 0x20, 0x77, 0x6C, 0x61, 0x6E, ++ 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x62, 0x75, 0x66, 0x0A, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, ++ 0x68, 0x6F, 0x73, 0x74, 0x20, 0x69, 0x70, 0x63, 0x20, 0x73, 0x74, 0x61, ++ 0x72, 0x74, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x20, 0x69, 0x70, 0x63, ++ 0x20, 0x68, 0x6F, 0x73, 0x74, 0x20, 0x72, 0x78, 0x3A, 0x20, 0x6E, 0x6F, ++ 0x62, 0x75, 0x66, 0x66, 0x2C, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x3D, ++ 0x20, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x4D, 0x4D, 0x5F, 0x53, ++ 0x54, 0x41, 0x5F, 0x54, 0x4F, 0x5F, 0x4B, 0x45, 0x59, 0x28, 0x4E, 0x58, ++ 0x5F, 0x52, 0x45, 0x4D, 0x4F, 0x54, 0x45, 0x5F, 0x53, 0x54, 0x41, 0x5F, ++ 0x4D, 0x41, 0x58, 0x20, 0x2D, 0x20, 0x31, 0x29, 0x20, 0x3C, 0x3D, 0x20, ++ 0x6E, 0x78, 0x6D, 0x61, 0x63, 0x5F, 0x73, 0x74, 0x61, 0x5F, 0x6B, 0x65, ++ 0x79, 0x5F, 0x6D, 0x61, 0x78, 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x5F, ++ 0x67, 0x65, 0x74, 0x66, 0x28, 0x29, 0x00, 0x00, 0x6C, 0x70, 0x20, 0x25, ++ 0x64, 0x2C, 0x20, 0x61, 0x63, 0x74, 0x73, 0x6C, 0x70, 0x3A, 0x25, 0x64, ++ 0x2C, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x3D, 0x25, 0x78, 0x0D, 0x0A, 0x00, ++ 0x63, 0x74, 0x78, 0x74, 0x2D, 0x3E, 0x69, 0x64, 0x78, 0x20, 0x21, 0x3D, ++ 0x20, 0x43, 0x48, 0x41, 0x4E, 0x5F, 0x43, 0x54, 0x58, 0x54, 0x5F, 0x55, ++ 0x4E, 0x55, 0x53, 0x45, 0x44, 0x00, 0x00, 0x00, 0x73, 0x6F, 0x66, 0x74, ++ 0x77, 0x61, 0x6B, 0x65, 0x75, 0x70, 0x20, 0x69, 0x73, 0x20, 0x70, 0x65, ++ 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x61, ++ 0x6C, 0x6C, 0x6F, 0x77, 0x0D, 0x0A, 0x00, 0x00, 0x74, 0x69, 0x6D, 0x65, ++ 0x72, 0x3A, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x61, 0x6C, 0x6C, 0x6F, 0x77, ++ 0x20, 0x25, 0x78, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x6C, 0x61, 0x73, 0x74, ++ 0x20, 0x3C, 0x20, 0x31, 0x30, 0x6D, 0x73, 0x2C, 0x20, 0x6E, 0x6F, 0x74, ++ 0x20, 0x61, 0x6C, 0x6C, 0x6F, 0x77, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x6E, 0x6F, 0x74, 0x20, 0x61, 0x6C, 0x6C, 0x6F, 0x77, 0x0D, 0x0A, 0x00, ++ 0x6F, 0x66, 0x66, 0x73, 0x65, 0x74, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x61, ++ 0x6C, 0x6C, 0x6F, 0x77, 0x65, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x0A, 0x43, 0x4F, 0x4E, 0x54, 0x52, 0x4F, 0x4C, 0x3D, 0x25, 0x30, 0x38, ++ 0x78, 0x2C, 0x20, 0x78, 0x50, 0x53, 0x52, 0x20, 0x20, 0x20, 0x3D, 0x25, ++ 0x30, 0x38, 0x78, 0x0A, 0x50, 0x53, 0x50, 0x20, 0x20, 0x20, 0x20, 0x3D, ++ 0x25, 0x30, 0x38, 0x78, 0x2C, 0x20, 0x4D, 0x53, 0x50, 0x20, 0x20, 0x20, ++ 0x20, 0x3D, 0x25, 0x30, 0x38, 0x78, 0x0A, 0x50, 0x52, 0x49, 0x4D, 0x41, ++ 0x53, 0x4B, 0x3D, 0x25, 0x30, 0x38, 0x78, 0x2C, 0x20, 0x4C, 0x52, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x3D, 0x25, 0x30, 0x38, 0x78, 0x0A, 0x00, 0x00, ++ 0x0A, 0x57, 0x72, 0x6F, 0x6E, 0x67, 0x20, 0x50, 0x53, 0x50, 0x21, 0x00, ++ 0x0A, 0x44, 0x75, 0x6D, 0x70, 0x4D, 0x53, 0x50, 0x3A, 0x00, 0x00, 0x00, ++ 0x0A, 0x5B, 0x25, 0x30, 0x38, 0x78, 0x5D, 0x3A, 0x00, 0x00, 0x00, 0x00, ++ 0x20, 0x25, 0x30, 0x38, 0x58, 0x00, 0x00, 0x00, 0x0A, 0x52, 0x25, 0x2D, ++ 0x34, 0x64, 0x3A, 0x20, 0x25, 0x30, 0x38, 0x58, 0x00, 0x00, 0x00, 0x00, ++ 0x0A, 0x53, 0x50, 0x20, 0x20, 0x20, 0x3A, 0x20, 0x25, 0x30, 0x38, 0x58, ++ 0x0A, 0x4C, 0x52, 0x20, 0x20, 0x20, 0x3A, 0x20, 0x25, 0x30, 0x38, 0x58, ++ 0x0A, 0x50, 0x43, 0x20, 0x20, 0x20, 0x3A, 0x20, 0x25, 0x30, 0x38, 0x58, ++ 0x0A, 0x78, 0x50, 0x53, 0x52, 0x20, 0x3A, 0x20, 0x25, 0x30, 0x38, 0x58, ++ 0x0A, 0x50, 0x53, 0x50, 0x20, 0x20, 0x3A, 0x20, 0x25, 0x30, 0x38, 0x58, ++ 0x0A, 0x4D, 0x53, 0x50, 0x20, 0x20, 0x3A, 0x20, 0x25, 0x30, 0x38, 0x58, ++ 0x00, 0x00, 0x00, 0x00, 0x0A, 0x43, 0x50, 0x55, 0x49, 0x44, 0x3A, 0x20, ++ 0x25, 0x30, 0x38, 0x58, 0x0A, 0x49, 0x43, 0x53, 0x52, 0x20, 0x3A, 0x20, ++ 0x25, 0x30, 0x38, 0x58, 0x0A, 0x56, 0x54, 0x4F, 0x52, 0x20, 0x3A, 0x20, ++ 0x25, 0x30, 0x38, 0x58, 0x0A, 0x41, 0x49, 0x52, 0x43, 0x52, 0x3A, 0x20, ++ 0x25, 0x30, 0x38, 0x58, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x53, 0x48, 0x43, ++ 0x53, 0x52, 0x3A, 0x20, 0x25, 0x30, 0x38, 0x58, 0x0A, 0x43, 0x46, 0x53, ++ 0x52, 0x20, 0x3A, 0x20, 0x25, 0x30, 0x38, 0x58, 0x0A, 0x48, 0x46, 0x53, ++ 0x52, 0x20, 0x3A, 0x20, 0x25, 0x30, 0x38, 0x58, 0x0A, 0x44, 0x46, 0x53, ++ 0x52, 0x20, 0x3A, 0x20, 0x25, 0x30, 0x38, 0x58, 0x0A, 0x41, 0x46, 0x53, ++ 0x52, 0x20, 0x3A, 0x20, 0x25, 0x30, 0x38, 0x58, 0x00, 0x00, 0x00, 0x00, ++ 0x0A, 0x4D, 0x4D, 0x46, 0x53, 0x52, 0x3A, 0x20, 0x25, 0x30, 0x32, 0x58, ++ 0x0A, 0x20, 0x20, 0x49, 0x41, 0x43, 0x43, 0x56, 0x49, 0x4F, 0x4C, 0x20, ++ 0x3A, 0x25, 0x64, 0x09, 0x44, 0x41, 0x43, 0x43, 0x56, 0x49, 0x4F, 0x4C, ++ 0x20, 0x3A, 0x25, 0x64, 0x0A, 0x20, 0x20, 0x4D, 0x55, 0x4E, 0x53, 0x54, ++ 0x4B, 0x45, 0x52, 0x52, 0x3A, 0x25, 0x64, 0x09, 0x4D, 0x53, 0x54, 0x4B, ++ 0x45, 0x52, 0x52, 0x20, 0x20, 0x3A, 0x25, 0x64, 0x0A, 0x20, 0x20, 0x4D, ++ 0x4C, 0x53, 0x50, 0x45, 0x52, 0x52, 0x20, 0x20, 0x3A, 0x25, 0x64, 0x09, ++ 0x4D, 0x4D, 0x41, 0x52, 0x56, 0x41, 0x4C, 0x49, 0x44, 0x3A, 0x25, 0x64, ++ 0x00, 0x00, 0x00, 0x00, 0x0A, 0x4D, 0x4D, 0x46, 0x41, 0x52, 0x3A, 0x20, ++ 0x25, 0x30, 0x38, 0x58, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x42, 0x46, 0x53, ++ 0x52, 0x20, 0x3A, 0x20, 0x25, 0x30, 0x32, 0x58, 0x0A, 0x20, 0x20, 0x49, ++ 0x42, 0x55, 0x53, 0x45, 0x52, 0x52, 0x20, 0x20, 0x20, 0x20, 0x3A, 0x25, ++ 0x64, 0x09, 0x50, 0x52, 0x45, 0x43, 0x49, 0x53, 0x45, 0x52, 0x52, 0x3A, ++ 0x25, 0x64, 0x0A, 0x20, 0x20, 0x49, 0x4D, 0x50, 0x52, 0x45, 0x43, 0x49, ++ 0x53, 0x45, 0x52, 0x52, 0x3A, 0x25, 0x64, 0x09, 0x55, 0x4E, 0x53, 0x54, ++ 0x4B, 0x45, 0x52, 0x52, 0x20, 0x3A, 0x25, 0x64, 0x0A, 0x20, 0x20, 0x53, ++ 0x54, 0x4B, 0x45, 0x52, 0x52, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3A, 0x25, ++ 0x64, 0x09, 0x4C, 0x53, 0x50, 0x45, 0x52, 0x52, 0x20, 0x20, 0x20, 0x3A, ++ 0x25, 0x64, 0x0A, 0x20, 0x20, 0x42, 0x46, 0x41, 0x52, 0x56, 0x41, 0x4C, ++ 0x49, 0x44, 0x20, 0x20, 0x3A, 0x25, 0x64, 0x00, 0x0A, 0x42, 0x46, 0x41, ++ 0x52, 0x20, 0x3A, 0x20, 0x25, 0x30, 0x38, 0x58, 0x00, 0x00, 0x00, 0x00, ++ 0x0A, 0x55, 0x46, 0x53, 0x52, 0x20, 0x3A, 0x20, 0x25, 0x30, 0x34, 0x58, ++ 0x0A, 0x20, 0x20, 0x55, 0x4E, 0x44, 0x45, 0x46, 0x49, 0x4E, 0x53, 0x54, ++ 0x52, 0x3A, 0x25, 0x64, 0x09, 0x49, 0x4E, 0x56, 0x53, 0x54, 0x41, 0x54, ++ 0x45, 0x20, 0x3A, 0x25, 0x64, 0x0A, 0x20, 0x20, 0x49, 0x4E, 0x56, 0x50, ++ 0x43, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3A, 0x25, 0x64, 0x09, 0x4E, 0x4F, ++ 0x43, 0x50, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3A, 0x25, 0x64, 0x0A, 0x20, ++ 0x20, 0x55, 0x4E, 0x41, 0x4C, 0x49, 0x47, 0x4E, 0x45, 0x44, 0x20, 0x3A, ++ 0x25, 0x64, 0x09, 0x44, 0x49, 0x56, 0x42, 0x59, 0x5A, 0x45, 0x52, 0x4F, ++ 0x3A, 0x25, 0x64, 0x00, 0x0A, 0x4D, 0x6F, 0x64, 0x65, 0x20, 0x3A, 0x20, ++ 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x00, 0x00, 0x0A, 0x50, 0x72, 0x69, ++ 0x76, 0x20, 0x3A, 0x20, 0x55, 0x73, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, ++ 0x0A, 0x50, 0x72, 0x69, 0x76, 0x20, 0x3A, 0x20, 0x50, 0x72, 0x69, 0x76, ++ 0x69, 0x6C, 0x65, 0x67, 0x65, 0x64, 0x00, 0x00, 0x0A, 0x4D, 0x6F, 0x64, ++ 0x65, 0x20, 0x3A, 0x20, 0x48, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x72, 0x00, ++ 0x0A, 0x53, 0x74, 0x61, 0x63, 0x6B, 0x3A, 0x20, 0x50, 0x53, 0x50, 0x00, ++ 0x0A, 0x53, 0x74, 0x61, 0x63, 0x6B, 0x3A, 0x20, 0x4D, 0x53, 0x50, 0x00, ++ 0x0A, 0x43, 0x4E, 0x54, 0x52, 0x4C, 0x3A, 0x20, 0x25, 0x30, 0x38, 0x58, ++ 0x0A, 0x50, 0x4D, 0x41, 0x53, 0x4B, 0x3A, 0x20, 0x25, 0x30, 0x38, 0x58, ++ 0x0A, 0x46, 0x4D, 0x41, 0x53, 0x4B, 0x3A, 0x20, 0x25, 0x30, 0x38, 0x58, ++ 0x0A, 0x42, 0x41, 0x53, 0x45, 0x50, 0x3A, 0x20, 0x25, 0x30, 0x38, 0x58, ++ 0x00, 0x00, 0x00, 0x00, 0x0A, 0x44, 0x75, 0x6D, 0x70, 0x50, 0x53, 0x50, ++ 0x3A, 0x00, 0x00, 0x00, 0x50, 0x61, 0x6E, 0x69, 0x63, 0x2E, 0x2E, 0x2E, ++ 0x0A, 0x00, 0x00, 0x00, 0x0A, 0x2B, 0x2B, 0x20, 0x43, 0x4D, 0x34, 0x20, ++ 0x46, 0x61, 0x75, 0x6C, 0x74, 0x20, 0x48, 0x61, 0x6E, 0x64, 0x6C, 0x65, ++ 0x72, 0x20, 0x2B, 0x2B, 0x0A, 0x0A, 0x46, 0x61, 0x75, 0x6C, 0x74, 0x54, ++ 0x79, 0x70, 0x65, 0x3A, 0x20, 0x00, 0x00, 0x00, 0x4D, 0x65, 0x6D, 0x4D, ++ 0x61, 0x6E, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6C, 0x74, 0x00, 0x00, ++ 0x42, 0x75, 0x73, 0x46, 0x61, 0x75, 0x6C, 0x74, 0x00, 0x00, 0x00, 0x00, ++ 0x55, 0x73, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6C, 0x74, 0x00, 0x00, ++ 0x48, 0x61, 0x72, 0x64, 0x46, 0x61, 0x75, 0x6C, 0x74, 0x00, 0x00, 0x00, ++ 0x0A, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, 0x78, 0x74, 0x3A, 0x00, 0x00, ++ 0x0A, 0x0A, 0x2D, 0x2D, 0x20, 0x43, 0x4D, 0x34, 0x20, 0x46, 0x61, 0x75, ++ 0x6C, 0x74, 0x20, 0x48, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x72, 0x20, 0x2D, ++ 0x2D, 0x0A, 0x0A, 0x00, 0x9A, 0x25, 0x73, 0x20, 0x2D, 0x20, 0x62, 0x75, ++ 0x69, 0x6C, 0x64, 0x3A, 0x20, 0x25, 0x73, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x25, 0x64, 0x2C, 0x20, 0x25, ++ 0x64, 0x0D, 0x0A, 0x00, 0x72, 0x65, 0x73, 0x65, 0x74, 0x20, 0x64, 0x6F, ++ 0x6E, 0x65, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x64, 0x2C, 0x00, 0x00, ++ 0x74, 0x3D, 0x25, 0x78, 0x0D, 0x0A, 0x00, 0x00, 0x6E, 0x6F, 0x74, 0x20, ++ 0x70, 0x61, 0x73, 0x74, 0x3A, 0x20, 0x25, 0x64, 0x2C, 0x25, 0x64, 0x0D, ++ 0x0A, 0x00, 0x00, 0x00, 0x70, 0x61, 0x73, 0x73, 0x3A, 0x20, 0x25, 0x64, ++ 0x2C, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x68, 0x61, 0x6C, ++ 0x5F, 0x6D, 0x61, 0x63, 0x68, 0x77, 0x5F, 0x74, 0x69, 0x6D, 0x65, 0x5F, ++ 0x70, 0x61, 0x73, 0x74, 0x28, 0x74, 0x69, 0x6D, 0x65, 0x72, 0x2D, 0x3E, ++ 0x74, 0x69, 0x6D, 0x65, 0x20, 0x2D, 0x20, 0x67, 0x5F, 0x77, 0x69, 0x66, ++ 0x69, 0x5F, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x73, 0x2E, 0x70, ++ 0x77, 0x72, 0x5F, 0x6F, 0x70, 0x65, 0x6E, 0x5F, 0x73, 0x79, 0x73, 0x64, ++ 0x65, 0x6C, 0x61, 0x79, 0x29, 0x00, 0x00, 0x00, 0x73, 0x6C, 0x70, 0x3A, ++ 0x25, 0x78, 0x2C, 0x25, 0x78, 0x0D, 0x0A, 0x00, 0x62, 0x74, 0x0A, 0x00, ++ 0x6C, 0x70, 0x3D, 0x25, 0x64, 0x2C, 0x20, 0x69, 0x67, 0x6E, 0x6F, 0x72, ++ 0x65, 0x3D, 0x25, 0x64, 0x0A, 0x00, 0x00, 0x00, 0x77, 0x2C, 0x20, 0x00, ++ 0x72, 0x77, 0x6E, 0x78, 0x5F, 0x65, 0x6E, 0x76, 0x2E, 0x70, 0x72, 0x65, ++ 0x76, 0x5F, 0x68, 0x77, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x3D, ++ 0x3D, 0x20, 0x6E, 0x78, 0x6D, 0x61, 0x63, 0x5F, 0x63, 0x75, 0x72, 0x72, ++ 0x65, 0x6E, 0x74, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, ++ 0x74, 0x66, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x77, 0x65, 0x0D, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x72, 0x77, 0x6E, 0x78, 0x6C, 0x5F, 0x72, 0x65, ++ 0x73, 0x65, 0x74, 0x5F, 0x65, 0x76, 0x74, 0x00, 0x74, 0x78, 0x64, 0x65, ++ 0x73, 0x63, 0x5F, 0x61, 0x72, 0x72, 0x61, 0x79, 0x5B, 0x30, 0x5D, 0x20, ++ 0x26, 0x26, 0x20, 0x74, 0x78, 0x5F, 0x68, 0x77, 0x5F, 0x64, 0x65, 0x73, ++ 0x63, 0x5F, 0x61, 0x72, 0x72, 0x61, 0x79, 0x5B, 0x30, 0x5D, 0x00, 0x00, ++ 0x72, 0x63, 0x5F, 0x73, 0x73, 0x20, 0x21, 0x3D, 0x20, 0x4E, 0x55, 0x4C, ++ 0x4C, 0x00, 0x00, 0x00, 0x74, 0x78, 0x6C, 0x20, 0x3A, 0x25, 0x78, 0x2C, ++ 0x20, 0x6C, 0x65, 0x6E, 0x3D, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, ++ 0x74, 0x78, 0x6C, 0x5F, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5F, 0x67, ++ 0x65, 0x74, 0x28, 0x74, 0x78, 0x64, 0x65, 0x73, 0x63, 0x29, 0x20, 0x21, ++ 0x3D, 0x20, 0x4E, 0x55, 0x4C, 0x4C, 0x00, 0x00, 0x74, 0x68, 0x64, 0x2D, ++ 0x3E, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5F, 0x70, 0x62, 0x64, 0x5F, 0x70, ++ 0x74, 0x72, 0x00, 0x00, 0x6E, 0x65, 0x78, 0x74, 0x64, 0x65, 0x73, 0x63, ++ 0x20, 0x21, 0x3D, 0x20, 0x4E, 0x55, 0x4C, 0x4C, 0x00, 0x00, 0x00, 0x00, ++ 0x61, 0x67, 0x67, 0x5F, 0x64, 0x65, 0x73, 0x63, 0x2D, 0x3E, 0x73, 0x74, ++ 0x61, 0x74, 0x75, 0x73, 0x20, 0x26, 0x20, 0x41, 0x47, 0x47, 0x5F, 0x42, ++ 0x41, 0x5F, 0x52, 0x45, 0x43, 0x45, 0x49, 0x56, 0x45, 0x44, 0x00, 0x00, ++ 0x6E, 0x78, 0x6D, 0x61, 0x63, 0x5F, 0x74, 0x78, 0x5F, 0x62, 0x63, 0x6E, ++ 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, 0x74, 0x66, 0x28, ++ 0x29, 0x20, 0x21, 0x3D, 0x20, 0x32, 0x00, 0x00, 0x6E, 0x78, 0x6D, 0x61, ++ 0x63, 0x5F, 0x74, 0x78, 0x5F, 0x61, 0x63, 0x5F, 0x33, 0x5F, 0x73, 0x74, ++ 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, 0x74, 0x66, 0x28, 0x29, 0x20, 0x21, ++ 0x3D, 0x20, 0x32, 0x00, 0x6E, 0x78, 0x6D, 0x61, 0x63, 0x5F, 0x74, 0x78, ++ 0x5F, 0x61, 0x63, 0x5F, 0x32, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5F, ++ 0x67, 0x65, 0x74, 0x66, 0x28, 0x29, 0x20, 0x21, 0x3D, 0x20, 0x32, 0x00, ++ 0x6E, 0x78, 0x6D, 0x61, 0x63, 0x5F, 0x74, 0x78, 0x5F, 0x61, 0x63, 0x5F, ++ 0x31, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, 0x74, 0x66, ++ 0x28, 0x29, 0x20, 0x21, 0x3D, 0x20, 0x32, 0x00, 0x6E, 0x78, 0x6D, 0x61, ++ 0x63, 0x5F, 0x74, 0x78, 0x5F, 0x61, 0x63, 0x5F, 0x30, 0x5F, 0x73, 0x74, ++ 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, 0x74, 0x66, 0x28, 0x29, 0x20, 0x21, ++ 0x3D, 0x20, 0x32, 0x00, 0x6E, 0x78, 0x6D, 0x61, 0x63, 0x5F, 0x74, 0x78, ++ 0x5F, 0x68, 0x69, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, ++ 0x74, 0x66, 0x28, 0x29, 0x20, 0x21, 0x3D, 0x20, 0x32, 0x00, 0x00, 0x00, ++ 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5F, 0x63, 0x61, 0x74, 0x65, 0x67, ++ 0x6F, 0x72, 0x79, 0x20, 0x3C, 0x20, 0x28, 0x4E, 0x58, 0x5F, 0x54, 0x58, ++ 0x51, 0x5F, 0x43, 0x4E, 0x54, 0x2B, 0x32, 0x29, 0x00, 0x00, 0x00, 0x00, ++ 0x65, 0x72, 0x72, 0x21, 0x21, 0x21, 0x20, 0x74, 0x78, 0x6C, 0x20, 0x63, ++ 0x66, 0x6D, 0x20, 0x6E, 0x6F, 0x20, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, ++ 0x20, 0x66, 0x6F, 0x72, 0x20, 0x75, 0x73, 0x62, 0x0D, 0x0A, 0x00, 0x00, ++ 0x63, 0x66, 0x6D, 0x20, 0x66, 0x6C, 0x75, 0x73, 0x68, 0x3A, 0x20, 0x25, ++ 0x78, 0x2C, 0x20, 0x73, 0x6E, 0x3D, 0x25, 0x64, 0x2C, 0x20, 0x73, 0x74, ++ 0x3D, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x63, 0x66, 0x6D, 0x73, ++ 0x3A, 0x20, 0x25, 0x78, 0x2C, 0x20, 0x73, 0x6E, 0x3D, 0x25, 0x64, 0x2C, ++ 0x20, 0x73, 0x74, 0x3D, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x61, 0x67, 0x67, 0x5F, 0x64, 0x65, 0x73, 0x63, 0x20, 0x21, 0x3D, 0x20, ++ 0x4E, 0x55, 0x4C, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x6B, 0x65, 0x79, 0x5F, ++ 0x69, 0x64, 0x78, 0x5F, 0x68, 0x77, 0x20, 0x3E, 0x3D, 0x20, 0x4D, 0x4D, ++ 0x5F, 0x53, 0x45, 0x43, 0x5F, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4C, 0x54, ++ 0x5F, 0x4B, 0x45, 0x59, 0x5F, 0x43, 0x4F, 0x55, 0x4E, 0x54, 0x00, 0x00, ++ 0x6B, 0x65, 0x5F, 0x65, 0x76, 0x74, 0x5F, 0x67, 0x65, 0x74, 0x28, 0x29, ++ 0x20, 0x26, 0x20, 0x65, 0x76, 0x74, 0x5F, 0x62, 0x69, 0x74, 0x00, 0x00, ++ 0x74, 0x78, 0x64, 0x65, 0x73, 0x63, 0x5F, 0x66, 0x69, 0x72, 0x73, 0x74, ++ 0x20, 0x21, 0x3D, 0x20, 0x4E, 0x55, 0x4C, 0x4C, 0x00, 0x00, 0x00, 0x00, ++ 0x62, 0x75, 0x67, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x73, 0x64, 0x69, 0x6F, ++ 0x20, 0x74, 0x61, 0x69, 0x6C, 0x20, 0x65, 0x72, 0x72, 0x6F, 0x72, 0x0D, ++ 0x0A, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, ++ 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, ++ 0x00, 0x08, 0x00, 0x00, 0x28, 0x74, 0x68, 0x64, 0x2D, 0x3E, 0x64, 0x61, ++ 0x74, 0x61, 0x73, 0x74, 0x61, 0x72, 0x74, 0x70, 0x74, 0x72, 0x20, 0x26, ++ 0x20, 0x30, 0x78, 0x30, 0x31, 0x29, 0x20, 0x3D, 0x3D, 0x20, 0x30, 0x00, ++ 0x62, 0x61, 0x6E, 0x64, 0x20, 0x21, 0x3D, 0x20, 0x50, 0x48, 0x59, 0x5F, ++ 0x42, 0x41, 0x4E, 0x44, 0x5F, 0x4D, 0x41, 0x58, 0x00, 0x00, 0x00, 0x00, ++ 0x76, 0x69, 0x66, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x65, 0x72, 0x72, ++ 0x6F, 0x72, 0x3A, 0x25, 0x64, 0x0A, 0x00, 0x00, 0x6E, 0x6F, 0x20, 0x70, ++ 0x72, 0x6F, 0x62, 0x65, 0x20, 0x62, 0x75, 0x66, 0x3A, 0x25, 0x64, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x74, 0x78, 0x64, 0x65, 0x73, 0x63, 0x20, 0x21, ++ 0x3D, 0x20, 0x4E, 0x55, 0x4C, 0x4C, 0x00, 0x00, 0x61, 0x67, 0x67, 0x5F, ++ 0x64, 0x65, 0x73, 0x63, 0x5F, 0x6E, 0x65, 0x77, 0x20, 0x21, 0x3D, 0x20, ++ 0x4E, 0x55, 0x4C, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x63, 0x6F, 0x5F, 0x6C, ++ 0x69, 0x73, 0x74, 0x5F, 0x70, 0x69, 0x63, 0x6B, 0x28, 0x26, 0x74, 0x78, ++ 0x6C, 0x69, 0x73, 0x74, 0x2D, 0x3E, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, ++ 0x61, 0x74, 0x65, 0x73, 0x29, 0x20, 0x3D, 0x3D, 0x20, 0x26, 0x61, 0x67, ++ 0x67, 0x5F, 0x64, 0x65, 0x73, 0x63, 0x5F, 0x6F, 0x6C, 0x64, 0x2D, 0x3E, ++ 0x6C, 0x69, 0x73, 0x74, 0x5F, 0x68, 0x64, 0x72, 0x00, 0x00, 0x00, 0x00, ++ 0x74, 0x78, 0x64, 0x65, 0x73, 0x63, 0x5F, 0x6E, 0x20, 0x21, 0x3D, 0x20, ++ 0x4E, 0x55, 0x4C, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x66, 0x6F, 0x72, 0x6D, ++ 0x61, 0x74, 0x5F, 0x6D, 0x6F, 0x64, 0x20, 0x3E, 0x20, 0x46, 0x4F, 0x52, ++ 0x4D, 0x41, 0x54, 0x4D, 0x4F, 0x44, 0x5F, 0x4E, 0x4F, 0x4E, 0x5F, 0x48, ++ 0x54, 0x5F, 0x44, 0x55, 0x50, 0x5F, 0x4F, 0x46, 0x44, 0x4D, 0x00, 0x00, ++ 0x28, 0x2A, 0x6E, 0x73, 0x73, 0x20, 0x3E, 0x20, 0x30, 0x29, 0x20, 0x26, ++ 0x26, 0x20, 0x28, 0x2A, 0x6E, 0x73, 0x73, 0x20, 0x3C, 0x3D, 0x20, 0x34, ++ 0x29, 0x00, 0x00, 0x00, 0x6D, 0x63, 0x73, 0x5F, 0x69, 0x64, 0x78, 0x20, ++ 0x3C, 0x3D, 0x20, 0x39, 0x00, 0x00, 0x00, 0x00, 0x6D, 0x63, 0x73, 0x5F, ++ 0x69, 0x64, 0x78, 0x20, 0x3C, 0x3D, 0x20, 0x33, 0x31, 0x00, 0x00, 0x00, ++ 0x69, 0x73, 0x5F, 0x6D, 0x70, 0x64, 0x75, 0x5F, 0x66, 0x69, 0x72, 0x73, ++ 0x74, 0x28, 0x74, 0x78, 0x64, 0x65, 0x73, 0x63, 0x29, 0x00, 0x00, 0x00, ++ 0x21, 0x69, 0x73, 0x5F, 0x6D, 0x70, 0x64, 0x75, 0x5F, 0x6C, 0x61, 0x73, ++ 0x74, 0x28, 0x74, 0x78, 0x64, 0x65, 0x73, 0x63, 0x29, 0x00, 0x00, 0x00, ++ 0x74, 0x78, 0x64, 0x65, 0x73, 0x63, 0x5F, 0x70, 0x72, 0x65, 0x76, 0x20, ++ 0x3D, 0x3D, 0x20, 0x61, 0x67, 0x67, 0x5F, 0x64, 0x65, 0x73, 0x63, 0x5F, ++ 0x6F, 0x6C, 0x64, 0x2D, 0x3E, 0x74, 0x78, 0x64, 0x65, 0x73, 0x63, 0x5F, ++ 0x6C, 0x61, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00, 0x61, 0x5F, 0x74, 0x68, ++ 0x64, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x26, 0x20, 0x52, ++ 0x45, 0x54, 0x52, 0x59, 0x5F, 0x4C, 0x49, 0x4D, 0x49, 0x54, 0x5F, 0x52, ++ 0x45, 0x41, 0x43, 0x48, 0x45, 0x44, 0x5F, 0x42, 0x49, 0x54, 0x00, 0x00, ++ 0x1A, 0x00, 0x1C, 0x00, 0x36, 0x00, 0x3C, 0x00, 0x75, 0x00, 0x82, 0x00, ++ 0xEA, 0x00, 0x04, 0x01, 0x34, 0x00, 0x39, 0x00, 0x6C, 0x00, 0x78, 0x00, ++ 0xEA, 0x00, 0x04, 0x01, 0xD4, 0x01, 0x08, 0x02, 0x4E, 0x00, 0x56, 0x00, ++ 0xA2, 0x00, 0xB4, 0x00, 0x5F, 0x01, 0x86, 0x01, 0xBE, 0x02, 0x0C, 0x03, ++ 0x68, 0x00, 0x73, 0x00, 0xD8, 0x00, 0xF0, 0x00, 0xD4, 0x01, 0x08, 0x02, ++ 0xA8, 0x03, 0x10, 0x04, 0x9C, 0x00, 0xAD, 0x00, 0x44, 0x01, 0x68, 0x01, ++ 0xBE, 0x02, 0x0C, 0x03, 0x7C, 0x05, 0x18, 0x06, 0xD0, 0x00, 0xE7, 0x00, ++ 0xB0, 0x01, 0xE0, 0x01, 0xA8, 0x03, 0x10, 0x04, 0x50, 0x07, 0x20, 0x08, ++ 0xEA, 0x00, 0x04, 0x01, 0xE6, 0x01, 0x1C, 0x02, 0x1D, 0x04, 0x92, 0x04, ++ 0x3A, 0x08, 0x24, 0x09, 0x04, 0x01, 0x20, 0x01, 0x1C, 0x02, 0x58, 0x02, ++ 0x92, 0x04, 0x14, 0x05, 0x24, 0x09, 0x28, 0x0A, 0x38, 0x01, 0x5A, 0x01, ++ 0x88, 0x02, 0xD0, 0x02, 0x7C, 0x05, 0x18, 0x06, 0xF8, 0x0A, 0x30, 0x0C, ++ 0x5A, 0x01, 0x81, 0x01, 0xD0, 0x02, 0x20, 0x03, 0x18, 0x06, 0xC5, 0x06, ++ 0x30, 0x0C, 0x8A, 0x0D, 0x01, 0x01, 0x02, 0x02, 0x04, 0x05, 0x08, 0x09, ++ 0x02, 0x02, 0x04, 0x04, 0x08, 0x09, 0x0F, 0x11, 0x03, 0x03, 0x06, 0x06, ++ 0x0B, 0x0D, 0x16, 0x19, 0x04, 0x04, 0x07, 0x08, 0x0F, 0x11, 0x1E, 0x21, ++ 0x05, 0x06, 0x0B, 0x0C, 0x16, 0x19, 0x2C, 0x31, 0x07, 0x08, 0x0E, 0x0F, ++ 0x1E, 0x21, 0x3B, 0x41, 0x08, 0x09, 0x10, 0x11, 0x21, 0x25, 0x42, 0x4A, ++ 0x09, 0x0A, 0x11, 0x13, 0x25, 0x29, 0x4A, 0x52, 0x0A, 0x0B, 0x15, 0x17, ++ 0x2C, 0x31, 0x58, 0x62, 0x0B, 0x0D, 0x17, 0x19, 0x31, 0x37, 0x62, 0x6D, ++ 0x74, 0x78, 0x6C, 0x5F, 0x68, 0x65, 0x5F, 0x65, 0x64, 0x63, 0x61, 0x5F, ++ 0x71, 0x75, 0x65, 0x75, 0x65, 0x5F, 0x68, 0x61, 0x6C, 0x74, 0x65, 0x64, ++ 0x28, 0x61, 0x63, 0x29, 0x00, 0x00, 0x00, 0x00, 0x68, 0x64, 0x72, 0x64, ++ 0x65, 0x73, 0x63, 0x2D, 0x3E, 0x66, 0x72, 0x6D, 0x6C, 0x65, 0x6E, 0x20, ++ 0x3E, 0x3D, 0x20, 0x48, 0x45, 0x5F, 0x54, 0x52, 0x49, 0x47, 0x5F, 0x46, ++ 0x52, 0x4D, 0x5F, 0x4D, 0x49, 0x4E, 0x5F, 0x4C, 0x45, 0x4E, 0x00, 0x00, ++ 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x5F, 0x6D, 0x6F, 0x64, 0x20, 0x3D, ++ 0x3D, 0x20, 0x46, 0x4F, 0x52, 0x4D, 0x41, 0x54, 0x4D, 0x4F, 0x44, 0x5F, ++ 0x48, 0x45, 0x5F, 0x53, 0x55, 0x00, 0x00, 0x00, 0x6D, 0x63, 0x73, 0x5F, ++ 0x69, 0x64, 0x78, 0x20, 0x3C, 0x3D, 0x20, 0x31, 0x31, 0x00, 0x00, 0x00, ++ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, ++ 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, ++ 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, ++ 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x05, 0x00, 0x05, 0x00, 0x04, 0x00, ++ 0x06, 0x00, 0x06, 0x00, 0x05, 0x00, 0x07, 0x00, 0x06, 0x00, 0x06, 0x00, ++ 0x08, 0x00, 0x07, 0x00, 0x06, 0x00, 0x08, 0x00, 0x08, 0x00, 0x07, 0x00, ++ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, ++ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, ++ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, ++ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, ++ 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, ++ 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, ++ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, ++ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, ++ 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, ++ 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, ++ 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, ++ 0x04, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, ++ 0x22, 0x00, 0x20, 0x00, 0x1D, 0x00, 0x90, 0x00, 0x88, 0x00, 0x7A, 0x00, ++ 0x44, 0x00, 0x41, 0x00, 0x3A, 0x00, 0x20, 0x01, 0x10, 0x01, 0xF5, 0x00, ++ 0x67, 0x00, 0x61, 0x00, 0x57, 0x00, 0xB0, 0x01, 0x98, 0x01, 0x6F, 0x01, ++ 0x89, 0x00, 0x82, 0x00, 0x75, 0x00, 0x40, 0x02, 0x20, 0x02, 0xEA, 0x01, ++ 0xCE, 0x00, 0xC3, 0x00, 0xAF, 0x00, 0x60, 0x03, 0x30, 0x03, 0xDF, 0x02, ++ 0x13, 0x01, 0x04, 0x01, 0xEA, 0x00, 0x80, 0x04, 0x40, 0x04, 0xD4, 0x03, ++ 0x35, 0x01, 0x24, 0x01, 0x07, 0x01, 0x11, 0x05, 0xC9, 0x04, 0x4E, 0x04, ++ 0x58, 0x01, 0x45, 0x01, 0x24, 0x01, 0xA1, 0x05, 0x51, 0x05, 0xC9, 0x04, ++ 0x9C, 0x01, 0x86, 0x01, 0x5F, 0x01, 0xC1, 0x06, 0x61, 0x06, 0xBE, 0x05, ++ 0xCA, 0x01, 0xB1, 0x01, 0x86, 0x01, 0x81, 0x07, 0x16, 0x07, 0x61, 0x06, ++ 0x04, 0x02, 0xE7, 0x01, 0xB6, 0x01, 0x71, 0x08, 0xF9, 0x07, 0x2D, 0x07, ++ 0x3D, 0x02, 0x1D, 0x02, 0xE7, 0x01, 0x61, 0x09, 0xDC, 0x08, 0xF9, 0x07, ++ 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x05, 0x00, 0x05, 0x00, 0x04, 0x00, ++ 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x09, 0x00, 0x08, 0x00, ++ 0x04, 0x00, 0x04, 0x00, 0x03, 0x00, 0x0E, 0x00, 0x0D, 0x00, 0x0C, 0x00, ++ 0x05, 0x00, 0x05, 0x00, 0x04, 0x00, 0x13, 0x00, 0x12, 0x00, 0x10, 0x00, ++ 0x07, 0x00, 0x07, 0x00, 0x06, 0x00, 0x1C, 0x00, 0x1A, 0x00, 0x17, 0x00, ++ 0x09, 0x00, 0x09, 0x00, 0x08, 0x00, 0x25, 0x00, 0x23, 0x00, 0x1F, 0x00, ++ 0x0A, 0x00, 0x0A, 0x00, 0x09, 0x00, 0x29, 0x00, 0x27, 0x00, 0x23, 0x00, ++ 0x0B, 0x00, 0x0B, 0x00, 0x0A, 0x00, 0x2E, 0x00, 0x2B, 0x00, 0x27, 0x00, ++ 0x0D, 0x00, 0x0D, 0x00, 0x0B, 0x00, 0x37, 0x00, 0x34, 0x00, 0x2E, 0x00, ++ 0x0F, 0x00, 0x0E, 0x00, 0x0D, 0x00, 0x3D, 0x00, 0x39, 0x00, 0x34, 0x00, ++ 0x11, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x44, 0x00, 0x40, 0x00, 0x3A, 0x00, ++ 0x12, 0x00, 0x11, 0x00, 0x10, 0x00, 0x4C, 0x00, 0x47, 0x00, 0x40, 0x00, ++ 0x08, 0x10, 0x20, 0x04, 0x50, 0x94, 0x15, 0x00, 0x98, 0x94, 0x15, 0x00, ++ 0x08, 0x94, 0x15, 0x00, 0x72, 0x68, 0x64, 0x2D, 0x3E, 0x66, 0x69, 0x72, ++ 0x73, 0x74, 0x5F, 0x70, 0x62, 0x64, 0x5F, 0x70, 0x74, 0x72, 0x20, 0x21, ++ 0x3D, 0x20, 0x30, 0x00, 0x6E, 0x6F, 0x20, 0x68, 0x6F, 0x73, 0x74, 0x20, ++ 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x3A, 0x25, 0x64, 0x0D, 0x0A, 0x00, ++ 0x72, 0x78, 0x62, 0x75, 0x66, 0x31, 0x20, 0x25, 0x30, 0x38, 0x78, 0x2C, ++ 0x25, 0x30, 0x38, 0x78, 0x3A, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x20, ++ 0x25, 0x30, 0x38, 0x78, 0x2C, 0x20, 0x65, 0x6E, 0x64, 0x20, 0x25, 0x30, ++ 0x38, 0x78, 0x2C, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x25, 0x30, 0x38, ++ 0x78, 0x2C, 0x20, 0x77, 0x72, 0x70, 0x74, 0x72, 0x20, 0x25, 0x30, 0x38, ++ 0x78, 0x2C, 0x20, 0x72, 0x64, 0x70, 0x74, 0x72, 0x20, 0x25, 0x30, 0x38, ++ 0x78, 0x0D, 0x0A, 0x00, 0x68, 0x6F, 0x73, 0x74, 0x20, 0x62, 0x75, 0x66, ++ 0x66, 0x65, 0x72, 0x20, 0x72, 0x65, 0x63, 0x6F, 0x76, 0x65, 0x72, 0x79, ++ 0x0D, 0x0A, 0x00, 0x00, 0x70, 0x64, 0x20, 0x21, 0x3D, 0x20, 0x4E, 0x55, ++ 0x4C, 0x4C, 0x00, 0x00, 0x70, 0x64, 0x2D, 0x3E, 0x70, 0x62, 0x64, 0x2E, ++ 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x61, 0x72, 0x74, 0x70, 0x74, 0x72, ++ 0x20, 0x21, 0x3D, 0x20, 0x30, 0x00, 0x00, 0x00, 0x64, 0x6D, 0x61, 0x5F, ++ 0x68, 0x64, 0x72, 0x64, 0x65, 0x73, 0x63, 0x2D, 0x3E, 0x68, 0x64, 0x2E, ++ 0x66, 0x69, 0x72, 0x73, 0x74, 0x5F, 0x70, 0x62, 0x64, 0x5F, 0x70, 0x74, ++ 0x72, 0x20, 0x3D, 0x3D, 0x20, 0x30, 0x00, 0x00, 0x70, 0x62, 0x64, 0x20, ++ 0x21, 0x3D, 0x20, 0x4E, 0x55, 0x4C, 0x4C, 0x00, 0x72, 0x78, 0x6C, 0x20, ++ 0x65, 0x72, 0x72, 0x2C, 0x20, 0x6E, 0x6F, 0x20, 0x62, 0x75, 0x66, 0x20, ++ 0x25, 0x64, 0x0A, 0x00, 0x6E, 0x6F, 0x20, 0x74, 0x78, 0x5F, 0x64, 0x73, ++ 0x63, 0x72, 0x5F, 0x68, 0x64, 0x72, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x6E, 0x6F, 0x20, 0x74, 0x78, 0x5F, 0x64, 0x73, 0x63, 0x72, 0x5F, 0x68, ++ 0x64, 0x72, 0x21, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x6D, 0x70, 0x64, 0x75, ++ 0x5F, 0x6C, 0x65, 0x6E, 0x20, 0x21, 0x3D, 0x20, 0x30, 0x00, 0x00, 0x00, ++ 0x6D, 0x70, 0x64, 0x75, 0x5F, 0x6C, 0x65, 0x6E, 0x20, 0x3C, 0x3D, 0x20, ++ 0x52, 0x57, 0x4E, 0x58, 0x5F, 0x4D, 0x41, 0x58, 0x5F, 0x41, 0x4D, 0x53, ++ 0x44, 0x55, 0x5F, 0x52, 0x58, 0x00, 0x00, 0x00, 0x72, 0x68, 0x64, 0x2D, ++ 0x3E, 0x75, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6E, 0x72, 0x78, 0x20, ++ 0x3D, 0x3D, 0x20, 0x52, 0x58, 0x5F, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, ++ 0x5F, 0x44, 0x45, 0x53, 0x43, 0x5F, 0x50, 0x41, 0x54, 0x54, 0x45, 0x52, ++ 0x4E, 0x00, 0x00, 0x00, 0x72, 0x78, 0x62, 0x75, 0x66, 0x32, 0x20, 0x25, ++ 0x30, 0x38, 0x78, 0x2C, 0x25, 0x30, 0x38, 0x78, 0x3A, 0x20, 0x73, 0x74, ++ 0x61, 0x72, 0x74, 0x20, 0x25, 0x30, 0x38, 0x78, 0x2C, 0x20, 0x65, 0x6E, ++ 0x64, 0x20, 0x25, 0x30, 0x38, 0x78, 0x2C, 0x20, 0x72, 0x65, 0x61, 0x64, ++ 0x20, 0x25, 0x30, 0x38, 0x78, 0x2C, 0x20, 0x77, 0x72, 0x70, 0x74, 0x72, ++ 0x20, 0x25, 0x30, 0x38, 0x78, 0x2C, 0x20, 0x72, 0x64, 0x70, 0x74, 0x72, ++ 0x20, 0x25, 0x30, 0x38, 0x78, 0x0D, 0x0A, 0x00, 0x25, 0x73, 0x3A, 0x20, ++ 0x73, 0x74, 0x61, 0x5F, 0x69, 0x64, 0x78, 0x3D, 0x25, 0x64, 0x0A, 0x00, ++ 0x73, 0x74, 0x61, 0x5F, 0x6D, 0x67, 0x6D, 0x74, 0x5F, 0x72, 0x65, 0x67, ++ 0x69, 0x73, 0x74, 0x65, 0x72, 0x00, 0x00, 0x00, 0x73, 0x74, 0x61, 0x5F, ++ 0x6D, 0x67, 0x6D, 0x74, 0x5F, 0x75, 0x6E, 0x72, 0x65, 0x67, 0x69, 0x73, ++ 0x74, 0x65, 0x72, 0x00, 0x6D, 0x61, 0x63, 0x20, 0x69, 0x73, 0x3A, 0x25, ++ 0x78, 0x2C, 0x20, 0x25, 0x78, 0x2C, 0x20, 0x70, 0x32, 0x70, 0x3D, 0x25, ++ 0x64, 0x0D, 0x0A, 0x00, 0x73, 0x65, 0x74, 0x20, 0x6D, 0x61, 0x63, 0x3A, ++ 0x25, 0x78, 0x2C, 0x25, 0x78, 0x2C, 0x20, 0x6D, 0x61, 0x73, 0x6B, 0x3A, ++ 0x25, 0x78, 0x2C, 0x25, 0x78, 0x2C, 0x70, 0x32, 0x70, 0x3D, 0x25, 0x64, ++ 0x0D, 0x0A, 0x00, 0x00, 0x76, 0x69, 0x66, 0x2D, 0x3E, 0x70, 0x32, 0x70, ++ 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x21, 0x3D, 0x20, 0x50, 0x32, ++ 0x50, 0x5F, 0x49, 0x4E, 0x56, 0x41, 0x4C, 0x49, 0x44, 0x5F, 0x49, 0x44, ++ 0x58, 0x00, 0x00, 0x00, 0x25, 0x73, 0x3A, 0x25, 0x64, 0x2C, 0x25, 0x64, ++ 0x2C, 0x25, 0x64, 0x2C, 0x25, 0x64, 0x2C, 0x25, 0x64, 0x0D, 0x0A, 0x00, ++ 0x76, 0x69, 0x66, 0x20, 0x75, 0x6E, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, ++ 0x65, 0x72, 0x3A, 0x25, 0x64, 0x2C, 0x20, 0x25, 0x64, 0x0A, 0x00, 0x00, ++ 0x76, 0x69, 0x66, 0x20, 0x75, 0x6E, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, ++ 0x65, 0x72, 0x20, 0x6D, 0x67, 0x6D, 0x74, 0x3A, 0x25, 0x64, 0x0A, 0x00, ++ 0x25, 0x73, 0x3A, 0x25, 0x64, 0x2C, 0x25, 0x64, 0x2C, 0x25, 0x64, 0x0D, ++ 0x0A, 0x00, 0x00, 0x00, 0x76, 0x69, 0x66, 0x5F, 0x6D, 0x67, 0x6D, 0x74, ++ 0x5F, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x00, 0x00, 0x00, ++ 0x76, 0x69, 0x66, 0x5F, 0x6D, 0x67, 0x6D, 0x74, 0x5F, 0x75, 0x6E, 0x72, ++ 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x00, 0x73, 0x6C, 0x65, 0x65, ++ 0x70, 0x3A, 0x6C, 0x69, 0x6E, 0x6B, 0x6C, 0x6F, 0x73, 0x73, 0x0D, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x6E, 0x78, 0x6D, 0x61, 0x63, 0x5F, 0x74, 0x69, ++ 0x6D, 0x65, 0x5F, 0x6F, 0x6E, 0x5F, 0x61, 0x69, 0x72, 0x5F, 0x76, 0x61, ++ 0x6C, 0x69, 0x64, 0x5F, 0x67, 0x65, 0x74, 0x66, 0x28, 0x29, 0x20, 0x21, ++ 0x3D, 0x20, 0x30, 0x00, 0x64, 0x74, 0x69, 0x6D, 0x3A, 0x25, 0x64, 0x2C, ++ 0x25, 0x64, 0x2C, 0x25, 0x64, 0x2C, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, ++ 0x2A, 0x28, 0x76, 0x6F, 0x6C, 0x61, 0x74, 0x69, 0x6C, 0x65, 0x20, 0x75, ++ 0x69, 0x6E, 0x74, 0x38, 0x5F, 0x74, 0x20, 0x2A, 0x29, 0x26, 0x67, 0x5F, ++ 0x61, 0x6F, 0x6E, 0x5F, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2E, 0x64, ++ 0x74, 0x69, 0x6D, 0x5F, 0x63, 0x6E, 0x74, 0x5F, 0x61, 0x6F, 0x6E, 0x73, ++ 0x68, 0x61, 0x72, 0x65, 0x64, 0x20, 0x3C, 0x20, 0x2A, 0x28, 0x76, 0x6F, ++ 0x6C, 0x61, 0x74, 0x69, 0x6C, 0x65, 0x20, 0x75, 0x69, 0x6E, 0x74, 0x38, ++ 0x5F, 0x74, 0x20, 0x2A, 0x29, 0x26, 0x67, 0x5F, 0x61, 0x6F, 0x6E, 0x5F, ++ 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2E, 0x64, 0x74, 0x69, 0x6D, 0x5F, ++ 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x5F, 0x61, 0x6F, 0x6E, 0x73, 0x68, ++ 0x61, 0x72, 0x65, 0x64, 0x00, 0x00, 0x00, 0x00, 0x62, 0x63, 0x6E, 0x3A, ++ 0x6C, 0x69, 0x6E, 0x6B, 0x6C, 0x6F, 0x73, 0x73, 0x0D, 0x0A, 0x00, 0x00, ++ 0x4C, 0x2C, 0x00, 0x00, 0x9B, 0x84, 0x4B, 0x65, 0x79, 0x69, 0x64, 0x78, ++ 0x20, 0x69, 0x6E, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x2C, 0x25, 0x30, 0x32, ++ 0x58, 0x0A, 0x00, 0x00, 0x9B, 0x84, 0x49, 0x6E, 0x76, 0x61, 0x6C, 0x69, ++ 0x64, 0x20, 0x6B, 0x65, 0x79, 0x69, 0x64, 0x78, 0x0A, 0x00, 0x00, 0x00, ++ 0x9B, 0x84, 0x49, 0x6E, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x20, 0x53, 0x54, ++ 0x41, 0x3A, 0x25, 0x64, 0x0A, 0x00, 0x00, 0x00, 0x76, 0x69, 0x66, 0x5F, ++ 0x73, 0x74, 0x61, 0x20, 0x3D, 0x3D, 0x20, 0x76, 0x69, 0x66, 0x00, 0x00, ++ 0x54, 0x3D, 0x25, 0x64, 0x2C, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, ++ 0x42, 0x43, 0x4E, 0x3A, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x62, 0x63, 0x6E, 0x20, 0x64, 0x6F, 0x6E, 0x65, 0x20, 0x74, 0x69, 0x6D, ++ 0x65, 0x6F, 0x75, 0x74, 0x0D, 0x0A, 0x00, 0x00, 0x66, 0x63, 0x73, 0x20, ++ 0x6F, 0x6B, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x66, 0x63, 0x73, 0x20, ++ 0x6E, 0x6F, 0x74, 0x20, 0x6F, 0x6B, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x69, 0x64, 0x6C, 0x65, 0x20, 0x65, 0x72, 0x72, 0x0D, 0x0A, 0x00, 0x00, ++ 0x69, 0x64, 0x6C, 0x65, 0x20, 0x69, 0x6E, 0x74, 0x20, 0x65, 0x72, 0x72, ++ 0x0D, 0x0A, 0x00, 0x00, 0x65, 0x76, 0x74, 0x20, 0x21, 0x3D, 0x20, 0x4D, ++ 0x4D, 0x5F, 0x54, 0x42, 0x54, 0x54, 0x5F, 0x45, 0x56, 0x54, 0x5F, 0x4D, ++ 0x41, 0x53, 0x4B, 0x00, 0x61, 0x64, 0x64, 0x20, 0x67, 0x74, 0x6B, 0x3A, ++ 0x25, 0x64, 0x2C, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x73, 0x74, 0x61, 0x5F, ++ 0x69, 0x64, 0x78, 0x20, 0x3C, 0x20, 0x53, 0x54, 0x41, 0x5F, 0x4D, 0x41, ++ 0x58, 0x00, 0x00, 0x00, 0x61, 0x64, 0x64, 0x20, 0x70, 0x74, 0x6B, 0x3A, ++ 0x25, 0x64, 0x2C, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x6B, 0x65, 0x5F, 0x73, ++ 0x74, 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, 0x74, 0x28, 0x54, 0x41, 0x53, ++ 0x4B, 0x5F, 0x4D, 0x4D, 0x29, 0x20, 0x3D, 0x3D, 0x20, 0x4D, 0x4D, 0x5F, ++ 0x48, 0x4F, 0x53, 0x54, 0x5F, 0x42, 0x59, 0x50, 0x41, 0x53, 0x53, 0x45, ++ 0x44, 0x00, 0x00, 0x00, 0x6B, 0x65, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65, ++ 0x5F, 0x67, 0x65, 0x74, 0x28, 0x54, 0x41, 0x53, 0x4B, 0x5F, 0x4D, 0x4D, ++ 0x29, 0x20, 0x21, 0x3D, 0x20, 0x4D, 0x4D, 0x5F, 0x4E, 0x4F, 0x5F, 0x49, ++ 0x44, 0x4C, 0x45, 0x00, 0x66, 0x6F, 0x72, 0x63, 0x65, 0x20, 0x69, 0x64, ++ 0x6C, 0x65, 0x20, 0x72, 0x65, 0x71, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x66, 0x6F, 0x72, 0x63, 0x65, 0x20, 0x69, 0x64, 0x6C, 0x65, 0x20, 0x65, ++ 0x78, 0x69, 0x74, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x28, 0x6B, 0x65, 0x5F, ++ 0x73, 0x74, 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, 0x74, 0x28, 0x54, 0x41, ++ 0x53, 0x4B, 0x5F, 0x4D, 0x4D, 0x29, 0x20, 0x21, 0x3D, 0x20, 0x4D, 0x4D, ++ 0x5F, 0x48, 0x4F, 0x53, 0x54, 0x5F, 0x42, 0x59, 0x50, 0x41, 0x53, 0x53, ++ 0x45, 0x44, 0x29, 0x20, 0x26, 0x26, 0x20, 0x28, 0x6B, 0x65, 0x5F, 0x73, ++ 0x74, 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, 0x74, 0x28, 0x54, 0x41, 0x53, ++ 0x4B, 0x5F, 0x4D, 0x4D, 0x29, 0x20, 0x21, 0x3D, 0x20, 0x4D, 0x4D, 0x5F, ++ 0x49, 0x44, 0x4C, 0x45, 0x29, 0x00, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, ++ 0x6D, 0x2D, 0x3E, 0x6B, 0x65, 0x79, 0x5F, 0x69, 0x64, 0x78, 0x20, 0x3C, ++ 0x20, 0x4D, 0x41, 0x43, 0x5F, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4C, 0x54, ++ 0x5F, 0x4D, 0x46, 0x50, 0x5F, 0x4B, 0x45, 0x59, 0x5F, 0x43, 0x4F, 0x55, ++ 0x4E, 0x54, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, 0x6D, 0x2D, 0x3E, 0x6B, ++ 0x65, 0x79, 0x2E, 0x6C, 0x65, 0x6E, 0x67, 0x74, 0x68, 0x20, 0x3C, 0x3D, ++ 0x20, 0x4D, 0x41, 0x43, 0x5F, 0x53, 0x45, 0x43, 0x5F, 0x4B, 0x45, 0x59, ++ 0x5F, 0x4C, 0x45, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, ++ 0x6D, 0x2D, 0x3E, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x5F, 0x73, 0x75, ++ 0x69, 0x74, 0x65, 0x20, 0x3C, 0x3D, 0x20, 0x4D, 0x41, 0x43, 0x5F, 0x43, ++ 0x49, 0x50, 0x48, 0x45, 0x52, 0x5F, 0x42, 0x49, 0x50, 0x5F, 0x43, 0x4D, ++ 0x41, 0x43, 0x5F, 0x31, 0x32, 0x38, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, ++ 0x6D, 0x2D, 0x3E, 0x68, 0x77, 0x5F, 0x6B, 0x65, 0x79, 0x5F, 0x69, 0x64, ++ 0x78, 0x20, 0x3C, 0x3D, 0x20, 0x4D, 0x4D, 0x5F, 0x53, 0x45, 0x43, 0x5F, ++ 0x4D, 0x41, 0x58, 0x5F, 0x4D, 0x46, 0x50, 0x5F, 0x4B, 0x45, 0x59, 0x5F, ++ 0x4E, 0x42, 0x52, 0x00, 0x76, 0x69, 0x66, 0x2D, 0x3E, 0x74, 0x79, 0x70, ++ 0x65, 0x20, 0x3D, 0x3D, 0x20, 0x56, 0x49, 0x46, 0x5F, 0x53, 0x54, 0x41, ++ 0x00, 0x00, 0x00, 0x00, 0x6B, 0x65, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65, ++ 0x5F, 0x67, 0x65, 0x74, 0x28, 0x64, 0x65, 0x73, 0x74, 0x5F, 0x69, 0x64, ++ 0x29, 0x20, 0x3D, 0x3D, 0x20, 0x4D, 0x4D, 0x5F, 0x49, 0x44, 0x4C, 0x45, ++ 0x00, 0x00, 0x00, 0x00, 0x73, 0x65, 0x74, 0x20, 0x6D, 0x75, 0x20, 0x65, ++ 0x64, 0x63, 0x61, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x44, 0x48, 0x43, 0x50, ++ 0x65, 0x64, 0x3A, 0x25, 0x64, 0x2C, 0x25, 0x78, 0x2E, 0x0D, 0x0A, 0x00, ++ 0x73, 0x65, 0x74, 0x20, 0x61, 0x67, 0x67, 0x20, 0x64, 0x69, 0x73, 0x61, ++ 0x62, 0x6C, 0x65, 0x3D, 0x25, 0x64, 0x2C, 0x20, 0x64, 0x69, 0x73, 0x61, ++ 0x62, 0x6C, 0x65, 0x5F, 0x72, 0x78, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x67, 0x65, 0x74, 0x20, 0x6D, 0x61, 0x63, 0x61, 0x64, 0x64, 0x72, 0x3A, ++ 0x20, 0x25, 0x78, 0x2C, 0x20, 0x25, 0x78, 0x0D, 0x0A, 0x00, 0x00, 0x00, ++ 0x73, 0x65, 0x74, 0x20, 0x74, 0x78, 0x6F, 0x70, 0x20, 0x72, 0x65, 0x71, ++ 0x3A, 0x20, 0x62, 0x6B, 0x3A, 0x25, 0x78, 0x2C, 0x20, 0x62, 0x65, 0x3A, ++ 0x25, 0x78, 0x2C, 0x20, 0x76, 0x69, 0x3A, 0x25, 0x78, 0x2C, 0x20, 0x76, ++ 0x6F, 0x3A, 0x25, 0x78, 0x2C, 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x6E, 0x61, ++ 0x76, 0x3D, 0x25, 0x64, 0x2C, 0x20, 0x63, 0x66, 0x65, 0x3D, 0x25, 0x64, ++ 0x0A, 0x00, 0x00, 0x00, 0x73, 0x65, 0x74, 0x20, 0x76, 0x65, 0x6E, 0x64, ++ 0x6F, 0x72, 0x20, 0x74, 0x72, 0x78, 0x3A, 0x20, 0x30, 0x78, 0x25, 0x78, ++ 0x2C, 0x20, 0x30, 0x78, 0x25, 0x78, 0x2C, 0x20, 0x30, 0x78, 0x25, 0x78, ++ 0x2C, 0x20, 0x30, 0x78, 0x25, 0x78, 0x2C, 0x20, 0x30, 0x78, 0x25, 0x78, ++ 0x0A, 0x00, 0x00, 0x00, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x20, 0x73, ++ 0x74, 0x61, 0x72, 0x74, 0x0D, 0x0A, 0x00, 0x00, 0x64, 0x72, 0x69, 0x76, ++ 0x65, 0x72, 0x20, 0x73, 0x74, 0x6F, 0x70, 0x0D, 0x0A, 0x00, 0x00, 0x00, ++ 0x69, 0x73, 0x20, 0x35, 0x67, 0x3D, 0x25, 0x64, 0x2C, 0x20, 0x73, 0x77, ++ 0x5F, 0x65, 0x6E, 0x3D, 0x25, 0x64, 0x2C, 0x20, 0x76, 0x65, 0x6E, 0x64, ++ 0x6F, 0x72, 0x5F, 0x69, 0x6E, 0x66, 0x6F, 0x3D, 0x30, 0x78, 0x25, 0x78, ++ 0x0D, 0x0A, 0x00, 0x00, 0x72, 0x65, 0x61, 0x64, 0x20, 0x78, 0x74, 0x61, ++ 0x6C, 0x5F, 0x63, 0x61, 0x70, 0x20, 0x65, 0x66, 0x75, 0x73, 0x65, 0x3D, ++ 0x25, 0x78, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x75, 0x73, 0x65, 0x72, ++ 0x20, 0x63, 0x61, 0x70, 0x3A, 0x30, 0x78, 0x25, 0x78, 0x0A, 0x00, 0x00, ++ 0x75, 0x73, 0x65, 0x72, 0x20, 0x63, 0x61, 0x70, 0x5F, 0x66, 0x69, 0x6E, ++ 0x65, 0x3A, 0x30, 0x78, 0x25, 0x78, 0x0A, 0x00, 0x73, 0x65, 0x74, 0x20, ++ 0x78, 0x74, 0x61, 0x6C, 0x5F, 0x63, 0x61, 0x70, 0x20, 0x30, 0x78, 0x25, ++ 0x78, 0x0A, 0x00, 0x00, 0x73, 0x65, 0x74, 0x20, 0x78, 0x74, 0x61, 0x6C, ++ 0x5F, 0x63, 0x61, 0x70, 0x5F, 0x66, 0x69, 0x6E, 0x65, 0x20, 0x30, 0x78, ++ 0x25, 0x78, 0x0A, 0x00, 0x32, 0x2E, 0x34, 0x67, 0x3A, 0x62, 0x65, 0x66, ++ 0x6F, 0x72, 0x65, 0x20, 0x25, 0x64, 0x3A, 0x20, 0x64, 0x63, 0x3D, 0x25, ++ 0x34, 0x78, 0x2C, 0x20, 0x76, 0x63, 0x6D, 0x3D, 0x25, 0x34, 0x78, 0x0D, ++ 0x0A, 0x00, 0x00, 0x00, 0x32, 0x2E, 0x34, 0x67, 0x3A, 0x61, 0x66, 0x74, ++ 0x65, 0x72, 0x20, 0x20, 0x25, 0x64, 0x3A, 0x20, 0x64, 0x63, 0x3D, 0x25, ++ 0x34, 0x78, 0x2C, 0x20, 0x76, 0x63, 0x6D, 0x3D, 0x25, 0x34, 0x78, 0x0D, ++ 0x0A, 0x00, 0x00, 0x00, 0x35, 0x67, 0x3A, 0x62, 0x65, 0x66, 0x6F, 0x72, ++ 0x65, 0x20, 0x25, 0x64, 0x3A, 0x20, 0x64, 0x63, 0x3D, 0x25, 0x34, 0x78, ++ 0x2C, 0x20, 0x76, 0x63, 0x6D, 0x3D, 0x25, 0x34, 0x78, 0x0D, 0x0A, 0x00, ++ 0x35, 0x67, 0x3A, 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x20, 0x25, 0x64, ++ 0x3A, 0x20, 0x64, 0x63, 0x3D, 0x25, 0x34, 0x78, 0x2C, 0x20, 0x76, 0x63, ++ 0x6D, 0x3D, 0x25, 0x34, 0x78, 0x0D, 0x0A, 0x00, 0x6E, 0x78, 0x6D, 0x61, ++ 0x63, 0x5F, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x5F, 0x73, 0x74, ++ 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, 0x74, 0x66, 0x28, 0x29, 0x20, 0x3D, ++ 0x3D, 0x20, 0x48, 0x57, 0x5F, 0x49, 0x44, 0x4C, 0x45, 0x00, 0x00, 0x00, ++ 0x6B, 0x65, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, 0x74, ++ 0x28, 0x64, 0x65, 0x73, 0x74, 0x5F, 0x69, 0x64, 0x29, 0x20, 0x21, 0x3D, ++ 0x20, 0x4D, 0x4D, 0x5F, 0x4E, 0x4F, 0x5F, 0x49, 0x44, 0x4C, 0x45, 0x00, ++ 0x76, 0x69, 0x66, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x61, 0x63, ++ 0x74, 0x69, 0x76, 0x65, 0x3A, 0x25, 0x64, 0x2C, 0x25, 0x64, 0x2C, 0x25, ++ 0x64, 0x2C, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x68, 0x65, 0x20, 0x65, ++ 0x6E, 0x61, 0x62, 0x6C, 0x65, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x76, 0x69, 0x66, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x69, 0x6E, ++ 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x3A, 0x25, 0x64, 0x2C, 0x25, 0x64, ++ 0x0D, 0x0A, 0x00, 0x00, 0xA8, 0x1F, 0x17, 0x00, 0x35, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x74, 0x69, 0x6D, 0x65, 0x72, 0x20, 0x70, 0x61, ++ 0x73, 0x74, 0x3A, 0x20, 0x63, 0x62, 0x3D, 0x25, 0x78, 0x2C, 0x20, 0x74, ++ 0x69, 0x6D, 0x65, 0x3D, 0x25, 0x78, 0x2C, 0x20, 0x63, 0x75, 0x72, 0x72, ++ 0x3D, 0x25, 0x78, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x68, 0x61, 0x6C, ++ 0x5F, 0x6D, 0x61, 0x63, 0x68, 0x77, 0x5F, 0x74, 0x69, 0x6D, 0x65, 0x5F, ++ 0x70, 0x61, 0x73, 0x74, 0x28, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x29, 0x00, ++ 0x74, 0x69, 0x6D, 0x65, 0x72, 0x2D, 0x3E, 0x63, 0x62, 0x00, 0x00, 0x00, ++ 0x25, 0x73, 0x3A, 0x20, 0x73, 0x74, 0x61, 0x20, 0x70, 0x72, 0x6F, 0x62, ++ 0x65, 0x20, 0x66, 0x61, 0x69, 0x6C, 0x3A, 0x25, 0x64, 0x0A, 0x00, 0x00, ++ 0x25, 0x73, 0x3A, 0x20, 0x73, 0x74, 0x61, 0x20, 0x70, 0x72, 0x6F, 0x62, ++ 0x65, 0x20, 0x73, 0x75, 0x63, 0x63, 0x0A, 0x00, 0x6D, 0x6D, 0x5F, 0x62, ++ 0x63, 0x6E, 0x5F, 0x65, 0x6E, 0x76, 0x2E, 0x74, 0x78, 0x5F, 0x63, 0x66, ++ 0x6D, 0x00, 0x00, 0x00, 0x74, 0x68, 0x69, 0x73, 0x20, 0x77, 0x69, 0x6C, ++ 0x6C, 0x65, 0x20, 0x6E, 0x65, 0x76, 0x65, 0x72, 0x20, 0x68, 0x61, 0x70, ++ 0x70, 0x65, 0x6E, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x61, 0x70, 0x6D, 0x20, ++ 0x73, 0x65, 0x6E, 0x64, 0x20, 0x6E, 0x75, 0x6C, 0x6C, 0x20, 0x74, 0x6F, ++ 0x20, 0x70, 0x72, 0x6F, 0x62, 0x65, 0x20, 0x73, 0x74, 0x61, 0x3A, 0x20, ++ 0x73, 0x74, 0x61, 0x5F, 0x69, 0x64, 0x78, 0x3D, 0x25, 0x64, 0x0A, 0x00, ++ 0x21, 0x6D, 0x6D, 0x5F, 0x62, 0x63, 0x6E, 0x5F, 0x65, 0x6E, 0x76, 0x2E, ++ 0x74, 0x78, 0x5F, 0x63, 0x66, 0x6D, 0x00, 0x00, 0x61, 0x70, 0x6D, 0x5F, ++ 0x70, 0x72, 0x6F, 0x62, 0x65, 0x5F, 0x73, 0x74, 0x61, 0x5F, 0x63, 0x66, ++ 0x6D, 0x00, 0x00, 0x00, 0x28, 0x70, 0x32, 0x70, 0x67, 0x6F, 0x5F, 0x76, ++ 0x69, 0x66, 0x2D, 0x3E, 0x63, 0x68, 0x61, 0x6E, 0x5F, 0x63, 0x74, 0x78, ++ 0x74, 0x2D, 0x3E, 0x70, 0x32, 0x70, 0x67, 0x6F, 0x5F, 0x76, 0x69, 0x66, ++ 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x3D, 0x3D, 0x20, 0x49, 0x4E, ++ 0x56, 0x41, 0x4C, 0x49, 0x44, 0x5F, 0x56, 0x49, 0x46, 0x5F, 0x49, 0x44, ++ 0x58, 0x29, 0x20, 0x7C, 0x7C, 0x20, 0x28, 0x70, 0x32, 0x70, 0x67, 0x6F, ++ 0x5F, 0x76, 0x69, 0x66, 0x2D, 0x3E, 0x63, 0x68, 0x61, 0x6E, 0x5F, 0x63, ++ 0x74, 0x78, 0x74, 0x2D, 0x3E, 0x70, 0x32, 0x70, 0x67, 0x6F, 0x5F, 0x76, ++ 0x69, 0x66, 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x3D, 0x3D, 0x20, ++ 0x70, 0x32, 0x70, 0x67, 0x6F, 0x5F, 0x76, 0x69, 0x66, 0x2D, 0x3E, 0x69, ++ 0x6E, 0x64, 0x65, 0x78, 0x29, 0x00, 0x00, 0x00, 0x6F, 0x74, 0x68, 0x5F, ++ 0x63, 0x74, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x6E, 0x62, 0x5F, 0x76, ++ 0x69, 0x66, 0x5F, 0x6F, 0x74, 0x68, 0x5F, 0x63, 0x74, 0x78, 0x74, 0x20, ++ 0x3E, 0x20, 0x31, 0x00, 0x6E, 0x6F, 0x61, 0x5F, 0x69, 0x64, 0x78, 0x20, ++ 0x3C, 0x20, 0x50, 0x32, 0x50, 0x5F, 0x4E, 0x4F, 0x41, 0x5F, 0x4E, 0x42, ++ 0x5F, 0x4D, 0x41, 0x58, 0x00, 0x00, 0x00, 0x00, 0x76, 0x69, 0x66, 0x2D, ++ 0x3E, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x3C, 0x20, 0x33, 0x32, 0x00, ++ 0x76, 0x69, 0x66, 0x2D, 0x3E, 0x74, 0x62, 0x74, 0x74, 0x5F, 0x73, 0x77, ++ 0x69, 0x74, 0x63, 0x68, 0x2E, 0x70, 0x32, 0x70, 0x5F, 0x6E, 0x6F, 0x61, ++ 0x5F, 0x76, 0x69, 0x66, 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x3D, ++ 0x3D, 0x20, 0x49, 0x4E, 0x56, 0x41, 0x4C, 0x49, 0x44, 0x5F, 0x56, 0x49, ++ 0x46, 0x5F, 0x49, 0x44, 0x58, 0x00, 0x00, 0x00, 0x63, 0x68, 0x5F, 0x73, ++ 0x77, 0x69, 0x74, 0x63, 0x68, 0x20, 0x21, 0x3D, 0x20, 0x4E, 0x55, 0x4C, ++ 0x4C, 0x00, 0x00, 0x00, 0x63, 0x68, 0x61, 0x6E, 0x5F, 0x65, 0x6E, 0x76, ++ 0x2E, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x26, 0x20, 0x43, 0x48, ++ 0x41, 0x4E, 0x5F, 0x52, 0x4F, 0x43, 0x5F, 0x53, 0x43, 0x41, 0x4E, 0x5F, ++ 0x50, 0x45, 0x4E, 0x44, 0x49, 0x4E, 0x47, 0x5F, 0x4D, 0x41, 0x53, 0x4B, ++ 0x00, 0x00, 0x00, 0x00, 0x28, 0x63, 0x68, 0x61, 0x6E, 0x5F, 0x65, 0x6E, ++ 0x76, 0x2E, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x26, 0x20, 0x43, ++ 0x4F, 0x5F, 0x42, 0x49, 0x54, 0x28, 0x43, 0x48, 0x41, 0x4E, 0x5F, 0x45, ++ 0x4E, 0x56, 0x5F, 0x52, 0x4F, 0x43, 0x5F, 0x42, 0x49, 0x54, 0x29, 0x29, ++ 0x20, 0x3D, 0x3D, 0x20, 0x30, 0x00, 0x00, 0x00, 0x28, 0x63, 0x68, 0x61, ++ 0x6E, 0x5F, 0x65, 0x6E, 0x76, 0x2E, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, ++ 0x20, 0x26, 0x20, 0x43, 0x4F, 0x5F, 0x42, 0x49, 0x54, 0x28, 0x43, 0x48, ++ 0x41, 0x4E, 0x5F, 0x45, 0x4E, 0x56, 0x5F, 0x53, 0x43, 0x41, 0x4E, 0x5F, ++ 0x42, 0x49, 0x54, 0x29, 0x29, 0x20, 0x3D, 0x3D, 0x20, 0x30, 0x00, 0x00, ++ 0x28, 0x76, 0x6F, 0x69, 0x64, 0x20, 0x2A, 0x29, 0x63, 0x68, 0x5F, 0x73, ++ 0x77, 0x69, 0x74, 0x63, 0x68, 0x20, 0x3D, 0x3D, 0x20, 0x65, 0x6E, 0x76, ++ 0x00, 0x00, 0x00, 0x00, 0x63, 0x68, 0x61, 0x6E, 0x5F, 0x65, 0x6E, 0x76, ++ 0x2E, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x5F, 0x63, 0x74, 0x78, ++ 0x74, 0x00, 0x00, 0x00, 0x4E, 0x6F, 0x20, 0x63, 0x74, 0x78, 0x74, 0x20, ++ 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6C, 0x65, 0x64, 0x20, 0x70, 0x72, ++ 0x65, 0x5F, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x0A, 0x00, 0x00, 0x00, ++ 0x63, 0x74, 0x78, 0x74, 0x2D, 0x3E, 0x69, 0x64, 0x78, 0x20, 0x3D, 0x3D, ++ 0x20, 0x43, 0x48, 0x41, 0x4E, 0x5F, 0x43, 0x54, 0x58, 0x54, 0x5F, 0x55, ++ 0x4E, 0x55, 0x53, 0x45, 0x44, 0x00, 0x00, 0x00, 0x72, 0x6F, 0x63, 0x3A, ++ 0x20, 0x25, 0x64, 0x2C, 0x20, 0x64, 0x75, 0x72, 0x3D, 0x25, 0x64, 0x2C, ++ 0x20, 0x73, 0x74, 0x3D, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x63, 0x74, 0x78, 0x74, 0x2D, 0x3E, 0x6E, 0x62, 0x5F, 0x6C, 0x69, 0x6E, ++ 0x6B, 0x65, 0x64, 0x5F, 0x76, 0x69, 0x66, 0x20, 0x3D, 0x3D, 0x20, 0x30, ++ 0x00, 0x00, 0x00, 0x00, 0x76, 0x69, 0x66, 0x2D, 0x3E, 0x63, 0x68, 0x61, ++ 0x6E, 0x5F, 0x63, 0x74, 0x78, 0x74, 0x20, 0x3D, 0x3D, 0x20, 0x4E, 0x55, ++ 0x4C, 0x4C, 0x00, 0x00, 0x63, 0x68, 0x61, 0x6E, 0x5F, 0x65, 0x6E, 0x76, ++ 0x2E, 0x6E, 0x62, 0x5F, 0x73, 0x63, 0x68, 0x65, 0x64, 0x5F, 0x63, 0x74, ++ 0x78, 0x74, 0x20, 0x3C, 0x3D, 0x20, 0x32, 0x00, 0x63, 0x68, 0x5F, 0x73, ++ 0x77, 0x69, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00, 0x63, 0x68, 0x61, 0x6E, ++ 0x20, 0x6C, 0x69, 0x6E, 0x6B, 0x3A, 0x25, 0x64, 0x2C, 0x25, 0x64, 0x2C, ++ 0x25, 0x64, 0x2C, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x63, 0x74, 0x78, 0x74, ++ 0x20, 0x21, 0x3D, 0x20, 0x4E, 0x55, 0x4C, 0x4C, 0x00, 0x00, 0x00, 0x00, ++ 0x63, 0x68, 0x61, 0x6E, 0x20, 0x75, 0x6E, 0x6C, 0x69, 0x6E, 0x6B, 0x3A, ++ 0x20, 0x25, 0x64, 0x2C, 0x25, 0x64, 0x2C, 0x25, 0x64, 0x2C, 0x25, 0x64, ++ 0x2C, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x63, 0x68, 0x61, 0x6E, ++ 0x5F, 0x65, 0x6E, 0x76, 0x2E, 0x6E, 0x62, 0x5F, 0x73, 0x63, 0x68, 0x65, ++ 0x64, 0x5F, 0x63, 0x74, 0x78, 0x74, 0x20, 0x3C, 0x3D, 0x20, 0x31, 0x00, ++ 0x25, 0x73, 0x3A, 0x25, 0x78, 0x0D, 0x0A, 0x00, 0x70, 0x73, 0x3A, 0x6C, ++ 0x69, 0x6E, 0x6B, 0x6C, 0x6F, 0x73, 0x73, 0x0D, 0x0A, 0x00, 0x00, 0x00, ++ 0x25, 0x73, 0x3A, 0x25, 0x64, 0x2C, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, ++ 0x70, 0x73, 0x5F, 0x65, 0x6E, 0x61, 0x62, 0x6C, 0x65, 0x5F, 0x63, 0x66, ++ 0x6D, 0x00, 0x00, 0x00, 0x70, 0x73, 0x5F, 0x64, 0x69, 0x73, 0x61, 0x62, ++ 0x6C, 0x65, 0x5F, 0x63, 0x66, 0x6D, 0x00, 0x00, 0x70, 0x73, 0x5F, 0x75, ++ 0x70, 0x6D, 0x5F, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, ++ 0x70, 0x73, 0x5F, 0x75, 0x70, 0x6D, 0x5F, 0x65, 0x78, 0x69, 0x74, 0x00, ++ 0x76, 0x69, 0x66, 0x2D, 0x3E, 0x70, 0x32, 0x70, 0x00, 0x00, 0x00, 0x00, ++ 0x76, 0x69, 0x66, 0x2D, 0x3E, 0x70, 0x32, 0x70, 0x20, 0x26, 0x26, 0x20, ++ 0x28, 0x6E, 0x6F, 0x61, 0x5F, 0x69, 0x6E, 0x73, 0x74, 0x20, 0x3C, 0x20, ++ 0x50, 0x32, 0x50, 0x5F, 0x4E, 0x4F, 0x41, 0x5F, 0x4E, 0x42, 0x5F, 0x4D, ++ 0x41, 0x58, 0x29, 0x00, 0x76, 0x69, 0x66, 0x2D, 0x3E, 0x70, 0x32, 0x70, ++ 0x5F, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x3C, 0x20, 0x4E, 0x58, 0x5F, ++ 0x50, 0x32, 0x50, 0x5F, 0x56, 0x49, 0x46, 0x5F, 0x4D, 0x41, 0x58, 0x00, ++ 0x74, 0x64, 0x73, 0x5F, 0x65, 0x6E, 0x76, 0x00, 0x25, 0x73, 0x3A, 0x25, ++ 0x64, 0x0D, 0x0A, 0x00, 0x70, 0x61, 0x72, 0x61, 0x6D, 0x2D, 0x3E, 0x63, ++ 0x68, 0x61, 0x6E, 0x5F, 0x63, 0x6E, 0x74, 0x20, 0x3E, 0x20, 0x30, 0x00, ++ 0x6B, 0x65, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, 0x74, ++ 0x28, 0x54, 0x41, 0x53, 0x4B, 0x5F, 0x53, 0x43, 0x41, 0x4E, 0x29, 0x20, ++ 0x3D, 0x3D, 0x20, 0x53, 0x43, 0x41, 0x4E, 0x5F, 0x57, 0x41, 0x49, 0x54, ++ 0x5F, 0x43, 0x48, 0x41, 0x4E, 0x4E, 0x45, 0x4C, 0x00, 0x00, 0x00, 0x00, ++ 0x6B, 0x65, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, 0x74, ++ 0x28, 0x54, 0x41, 0x53, 0x4B, 0x5F, 0x53, 0x43, 0x41, 0x4E, 0x29, 0x20, ++ 0x3D, 0x3D, 0x20, 0x53, 0x43, 0x41, 0x4E, 0x5F, 0x57, 0x41, 0x49, 0x54, ++ 0x5F, 0x42, 0x45, 0x41, 0x43, 0x4F, 0x4E, 0x5F, 0x50, 0x52, 0x4F, 0x42, ++ 0x45, 0x5F, 0x52, 0x53, 0x50, 0x00, 0x00, 0x00, 0x73, 0x63, 0x61, 0x6E, ++ 0x5F, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5F, 0x72, 0x65, 0x71, 0x5F, 0x68, ++ 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x72, 0x00, 0x00, 0x73, 0x63, 0x61, 0x6E, ++ 0x5F, 0x63, 0x61, 0x6E, 0x63, 0x65, 0x6C, 0x5F, 0x72, 0x65, 0x71, 0x5F, ++ 0x68, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x72, 0x00, 0x50, 0x21, 0x17, 0x00, ++ 0x04, 0x00, 0x00, 0x00, 0x73, 0x63, 0x61, 0x6E, 0x5F, 0x73, 0x65, 0x6E, ++ 0x64, 0x5F, 0x63, 0x61, 0x6E, 0x63, 0x65, 0x6C, 0x5F, 0x63, 0x66, 0x6D, ++ 0x00, 0x00, 0x00, 0x00, 0x6E, 0x78, 0x6D, 0x61, 0x63, 0x5F, 0x63, 0x75, ++ 0x72, 0x72, 0x65, 0x6E, 0x74, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5F, ++ 0x67, 0x65, 0x74, 0x66, 0x28, 0x29, 0x20, 0x21, 0x3D, 0x20, 0x48, 0x57, ++ 0x5F, 0x49, 0x44, 0x4C, 0x45, 0x00, 0x00, 0x00, 0x21, 0x68, 0x61, 0x6C, ++ 0x5F, 0x61, 0x6F, 0x6E, 0x74, 0x69, 0x6D, 0x65, 0x72, 0x5F, 0x74, 0x69, ++ 0x6D, 0x65, 0x5F, 0x70, 0x61, 0x73, 0x74, 0x28, 0x74, 0x69, 0x6D, 0x65, ++ 0x72, 0x2D, 0x3E, 0x74, 0x69, 0x6D, 0x65, 0x20, 0x2B, 0x20, 0x35, 0x30, ++ 0x30, 0x30, 0x29, 0x00, 0x65, 0x72, 0x72, 0x6F, 0x72, 0x3A, 0x20, 0x74, ++ 0x68, 0x65, 0x72, 0x65, 0x20, 0x69, 0x73, 0x20, 0x6E, 0x6F, 0x20, 0x6B, ++ 0x65, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x72, 0x20, 0x69, 0x6E, 0x20, 0x67, ++ 0x65, 0x6E, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x72, 0x20, 0x61, 0x6E, 0x79, ++ 0x6D, 0x6F, 0x72, 0x65, 0x0D, 0x0A, 0x00, 0x00, 0x65, 0x72, 0x72, 0x6F, ++ 0x72, 0x3A, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, 0x69, 0x73, 0x20, ++ 0x6E, 0x6F, 0x20, 0x6D, 0x6D, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x72, 0x20, ++ 0x69, 0x6E, 0x20, 0x67, 0x65, 0x6E, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x72, ++ 0x20, 0x61, 0x6E, 0x79, 0x6D, 0x6F, 0x72, 0x65, 0x0D, 0x0A, 0x00, 0x00, ++ 0x21, 0x28, 0x74, 0x69, 0x6D, 0x65, 0x72, 0x5F, 0x70, 0x65, 0x6E, 0x64, ++ 0x69, 0x6E, 0x67, 0x20, 0x26, 0x20, 0x48, 0x41, 0x4C, 0x5F, 0x41, 0x43, ++ 0x30, 0x5F, 0x54, 0x49, 0x4D, 0x45, 0x52, 0x5F, 0x42, 0x49, 0x54, 0x29, ++ 0x00, 0x00, 0x00, 0x00, 0x21, 0x28, 0x74, 0x69, 0x6D, 0x65, 0x72, 0x5F, ++ 0x70, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x26, 0x20, 0x48, 0x41, ++ 0x4C, 0x5F, 0x41, 0x43, 0x31, 0x5F, 0x54, 0x49, 0x4D, 0x45, 0x52, 0x5F, ++ 0x42, 0x49, 0x54, 0x29, 0x00, 0x00, 0x00, 0x00, 0x21, 0x28, 0x74, 0x69, ++ 0x6D, 0x65, 0x72, 0x5F, 0x70, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x20, ++ 0x26, 0x20, 0x48, 0x41, 0x4C, 0x5F, 0x41, 0x43, 0x32, 0x5F, 0x54, 0x49, ++ 0x4D, 0x45, 0x52, 0x5F, 0x42, 0x49, 0x54, 0x29, 0x00, 0x00, 0x00, 0x00, ++ 0x21, 0x28, 0x74, 0x69, 0x6D, 0x65, 0x72, 0x5F, 0x70, 0x65, 0x6E, 0x64, ++ 0x69, 0x6E, 0x67, 0x20, 0x26, 0x20, 0x48, 0x41, 0x4C, 0x5F, 0x41, 0x43, ++ 0x33, 0x5F, 0x54, 0x49, 0x4D, 0x45, 0x52, 0x5F, 0x42, 0x49, 0x54, 0x29, ++ 0x00, 0x00, 0x00, 0x00, 0x21, 0x28, 0x74, 0x69, 0x6D, 0x65, 0x72, 0x5F, ++ 0x70, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x26, 0x20, 0x48, 0x41, ++ 0x4C, 0x5F, 0x49, 0x44, 0x4C, 0x45, 0x5F, 0x54, 0x49, 0x4D, 0x45, 0x52, ++ 0x5F, 0x42, 0x49, 0x54, 0x29, 0x00, 0x00, 0x00, 0x21, 0x28, 0x74, 0x69, ++ 0x6D, 0x65, 0x72, 0x5F, 0x70, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x20, ++ 0x26, 0x20, 0x48, 0x41, 0x4C, 0x5F, 0x48, 0x45, 0x5F, 0x54, 0x42, 0x5F, ++ 0x54, 0x49, 0x4D, 0x45, 0x52, 0x5F, 0x42, 0x49, 0x54, 0x29, 0x00, 0x00, ++ 0x21, 0x28, 0x74, 0x69, 0x6D, 0x65, 0x72, 0x5F, 0x70, 0x65, 0x6E, 0x64, ++ 0x69, 0x6E, 0x67, 0x20, 0x26, 0x20, 0x48, 0x41, 0x4C, 0x5F, 0x48, 0x49, ++ 0x51, 0x5F, 0x54, 0x49, 0x4D, 0x45, 0x52, 0x5F, 0x42, 0x49, 0x54, 0x29, ++ 0x00, 0x00, 0x00, 0x00, 0x52, 0x58, 0x5F, 0x46, 0x49, 0x46, 0x4F, 0x5F, ++ 0x4F, 0x56, 0x45, 0x52, 0x5F, 0x46, 0x4C, 0x4F, 0x57, 0x20, 0x68, 0x61, ++ 0x70, 0x70, 0x65, 0x6E, 0x2C, 0x20, 0x68, 0x77, 0x20, 0x72, 0x65, 0x63, ++ 0x6F, 0x76, 0x65, 0x72, 0x79, 0x20, 0x69, 0x74, 0x73, 0x65, 0x6C, 0x66, ++ 0x0D, 0x0A, 0x00, 0x00, 0x21, 0x28, 0x67, 0x65, 0x6E, 0x69, 0x72, 0x71, ++ 0x5F, 0x70, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x26, 0x20, 0x4E, ++ 0x58, 0x4D, 0x41, 0x43, 0x5F, 0x50, 0x48, 0x59, 0x5F, 0x45, 0x52, 0x52, ++ 0x5F, 0x42, 0x49, 0x54, 0x29, 0x00, 0x00, 0x00, 0x21, 0x28, 0x67, 0x65, ++ 0x6E, 0x69, 0x72, 0x71, 0x5F, 0x70, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, ++ 0x20, 0x26, 0x20, 0x4E, 0x58, 0x4D, 0x41, 0x43, 0x5F, 0x4D, 0x41, 0x43, ++ 0x5F, 0x50, 0x48, 0x59, 0x49, 0x46, 0x5F, 0x55, 0x4E, 0x44, 0x45, 0x52, ++ 0x5F, 0x52, 0x55, 0x4E, 0x5F, 0x42, 0x49, 0x54, 0x29, 0x00, 0x00, 0x00, ++ 0x21, 0x28, 0x67, 0x65, 0x6E, 0x69, 0x72, 0x71, 0x5F, 0x70, 0x65, 0x6E, ++ 0x64, 0x69, 0x6E, 0x67, 0x20, 0x26, 0x20, 0x4E, 0x58, 0x4D, 0x41, 0x43, ++ 0x5F, 0x4D, 0x41, 0x43, 0x5F, 0x50, 0x48, 0x59, 0x49, 0x46, 0x5F, 0x4F, ++ 0x56, 0x45, 0x52, 0x46, 0x4C, 0x4F, 0x57, 0x5F, 0x42, 0x49, 0x54, 0x29, ++ 0x00, 0x00, 0x00, 0x00, 0x21, 0x28, 0x67, 0x65, 0x6E, 0x69, 0x72, 0x71, ++ 0x5F, 0x70, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x26, 0x20, 0x4E, ++ 0x58, 0x4D, 0x41, 0x43, 0x5F, 0x50, 0x54, 0x5F, 0x45, 0x52, 0x52, 0x4F, ++ 0x52, 0x5F, 0x42, 0x49, 0x54, 0x29, 0x00, 0x00, 0x21, 0x28, 0x67, 0x65, ++ 0x6E, 0x69, 0x72, 0x71, 0x5F, 0x70, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, ++ 0x20, 0x26, 0x20, 0x4E, 0x58, 0x4D, 0x41, 0x43, 0x5F, 0x41, 0x43, 0x5F, ++ 0x30, 0x5F, 0x54, 0x58, 0x5F, 0x44, 0x4D, 0x41, 0x5F, 0x44, 0x45, 0x41, ++ 0x44, 0x5F, 0x42, 0x49, 0x54, 0x29, 0x00, 0x00, 0x21, 0x28, 0x67, 0x65, ++ 0x6E, 0x69, 0x72, 0x71, 0x5F, 0x70, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, ++ 0x20, 0x26, 0x20, 0x4E, 0x58, 0x4D, 0x41, 0x43, 0x5F, 0x41, 0x43, 0x5F, ++ 0x31, 0x5F, 0x54, 0x58, 0x5F, 0x44, 0x4D, 0x41, 0x5F, 0x44, 0x45, 0x41, ++ 0x44, 0x5F, 0x42, 0x49, 0x54, 0x29, 0x00, 0x00, 0x21, 0x28, 0x67, 0x65, ++ 0x6E, 0x69, 0x72, 0x71, 0x5F, 0x70, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, ++ 0x20, 0x26, 0x20, 0x4E, 0x58, 0x4D, 0x41, 0x43, 0x5F, 0x41, 0x43, 0x5F, ++ 0x32, 0x5F, 0x54, 0x58, 0x5F, 0x44, 0x4D, 0x41, 0x5F, 0x44, 0x45, 0x41, ++ 0x44, 0x5F, 0x42, 0x49, 0x54, 0x29, 0x00, 0x00, 0x21, 0x28, 0x67, 0x65, ++ 0x6E, 0x69, 0x72, 0x71, 0x5F, 0x70, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, ++ 0x20, 0x26, 0x20, 0x4E, 0x58, 0x4D, 0x41, 0x43, 0x5F, 0x41, 0x43, 0x5F, ++ 0x33, 0x5F, 0x54, 0x58, 0x5F, 0x44, 0x4D, 0x41, 0x5F, 0x44, 0x45, 0x41, ++ 0x44, 0x5F, 0x42, 0x49, 0x54, 0x29, 0x00, 0x00, 0x21, 0x28, 0x67, 0x65, ++ 0x6E, 0x69, 0x72, 0x71, 0x5F, 0x70, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, ++ 0x20, 0x26, 0x20, 0x4E, 0x58, 0x4D, 0x41, 0x43, 0x5F, 0x42, 0x43, 0x4E, ++ 0x5F, 0x54, 0x58, 0x5F, 0x44, 0x4D, 0x41, 0x5F, 0x44, 0x45, 0x41, 0x44, ++ 0x5F, 0x42, 0x49, 0x54, 0x29, 0x00, 0x00, 0x00, 0x21, 0x28, 0x67, 0x65, ++ 0x6E, 0x69, 0x72, 0x71, 0x5F, 0x70, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, ++ 0x20, 0x26, 0x20, 0x4E, 0x58, 0x4D, 0x41, 0x43, 0x5F, 0x52, 0x58, 0x5F, ++ 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x5F, 0x44, 0x4D, 0x41, 0x5F, 0x44, ++ 0x45, 0x41, 0x44, 0x5F, 0x42, 0x49, 0x54, 0x29, 0x00, 0x00, 0x00, 0x00, ++ 0x21, 0x28, 0x67, 0x65, 0x6E, 0x69, 0x72, 0x71, 0x5F, 0x70, 0x65, 0x6E, ++ 0x64, 0x69, 0x6E, 0x67, 0x20, 0x26, 0x20, 0x4E, 0x58, 0x4D, 0x41, 0x43, ++ 0x5F, 0x52, 0x58, 0x5F, 0x50, 0x41, 0x59, 0x4C, 0x4F, 0x41, 0x44, 0x5F, ++ 0x44, 0x4D, 0x41, 0x5F, 0x44, 0x45, 0x41, 0x44, 0x5F, 0x42, 0x49, 0x54, ++ 0x29, 0x00, 0x00, 0x00, 0x21, 0x28, 0x67, 0x65, 0x6E, 0x69, 0x72, 0x71, ++ 0x5F, 0x70, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x26, 0x20, 0x4E, ++ 0x58, 0x4D, 0x41, 0x43, 0x5F, 0x48, 0x57, 0x5F, 0x45, 0x52, 0x52, 0x5F, ++ 0x42, 0x49, 0x54, 0x29, 0x00, 0x00, 0x00, 0x00, 0x21, 0x28, 0x67, 0x65, ++ 0x6E, 0x69, 0x72, 0x71, 0x5F, 0x70, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, ++ 0x20, 0x26, 0x20, 0x4E, 0x58, 0x4D, 0x41, 0x43, 0x5F, 0x48, 0x49, 0x5F, ++ 0x54, 0x58, 0x5F, 0x44, 0x4D, 0x41, 0x5F, 0x44, 0x45, 0x41, 0x44, 0x5F, ++ 0x42, 0x49, 0x54, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, ++ 0xFF, 0xFF, 0xFF, 0xFF, 0x0A, 0x08, 0x06, 0x04, 0x0B, 0x09, 0x07, 0x05, ++ 0xA5, 0xC6, 0x84, 0xF8, 0x99, 0xEE, 0x8D, 0xF6, 0x0D, 0xFF, 0xBD, 0xD6, ++ 0xB1, 0xDE, 0x54, 0x91, 0x50, 0x60, 0x03, 0x02, 0xA9, 0xCE, 0x7D, 0x56, ++ 0x19, 0xE7, 0x62, 0xB5, 0xE6, 0x4D, 0x9A, 0xEC, 0x45, 0x8F, 0x9D, 0x1F, ++ 0x40, 0x89, 0x87, 0xFA, 0x15, 0xEF, 0xEB, 0xB2, 0xC9, 0x8E, 0x0B, 0xFB, ++ 0xEC, 0x41, 0x67, 0xB3, 0xFD, 0x5F, 0xEA, 0x45, 0xBF, 0x23, 0xF7, 0x53, ++ 0x96, 0xE4, 0x5B, 0x9B, 0xC2, 0x75, 0x1C, 0xE1, 0xAE, 0x3D, 0x6A, 0x4C, ++ 0x5A, 0x6C, 0x41, 0x7E, 0x02, 0xF5, 0x4F, 0x83, 0x5C, 0x68, 0xF4, 0x51, ++ 0x34, 0xD1, 0x08, 0xF9, 0x93, 0xE2, 0x73, 0xAB, 0x53, 0x62, 0x3F, 0x2A, ++ 0x0C, 0x08, 0x52, 0x95, 0x65, 0x46, 0x5E, 0x9D, 0x28, 0x30, 0xA1, 0x37, ++ 0x0F, 0x0A, 0xB5, 0x2F, 0x09, 0x0E, 0x36, 0x24, 0x9B, 0x1B, 0x3D, 0xDF, ++ 0x26, 0xCD, 0x69, 0x4E, 0xCD, 0x7F, 0x9F, 0xEA, 0x1B, 0x12, 0x9E, 0x1D, ++ 0x74, 0x58, 0x2E, 0x34, 0x2D, 0x36, 0xB2, 0xDC, 0xEE, 0xB4, 0xFB, 0x5B, ++ 0xF6, 0xA4, 0x4D, 0x76, 0x61, 0xB7, 0xCE, 0x7D, 0x7B, 0x52, 0x3E, 0xDD, ++ 0x71, 0x5E, 0x97, 0x13, 0xF5, 0xA6, 0x68, 0xB9, 0x00, 0x00, 0x2C, 0xC1, ++ 0x60, 0x40, 0x1F, 0xE3, 0xC8, 0x79, 0xED, 0xB6, 0xBE, 0xD4, 0x46, 0x8D, ++ 0xD9, 0x67, 0x4B, 0x72, 0xDE, 0x94, 0xD4, 0x98, 0xE8, 0xB0, 0x4A, 0x85, ++ 0x6B, 0xBB, 0x2A, 0xC5, 0xE5, 0x4F, 0x16, 0xED, 0xC5, 0x86, 0xD7, 0x9A, ++ 0x55, 0x66, 0x94, 0x11, 0xCF, 0x8A, 0x10, 0xE9, 0x06, 0x04, 0x81, 0xFE, ++ 0xF0, 0xA0, 0x44, 0x78, 0xBA, 0x25, 0xE3, 0x4B, 0xF3, 0xA2, 0xFE, 0x5D, ++ 0xC0, 0x80, 0x8A, 0x05, 0xAD, 0x3F, 0xBC, 0x21, 0x48, 0x70, 0x04, 0xF1, ++ 0xDF, 0x63, 0xC1, 0x77, 0x75, 0xAF, 0x63, 0x42, 0x30, 0x20, 0x1A, 0xE5, ++ 0x0E, 0xFD, 0x6D, 0xBF, 0x4C, 0x81, 0x14, 0x18, 0x35, 0x26, 0x2F, 0xC3, ++ 0xE1, 0xBE, 0xA2, 0x35, 0xCC, 0x88, 0x39, 0x2E, 0x57, 0x93, 0xF2, 0x55, ++ 0x82, 0xFC, 0x47, 0x7A, 0xAC, 0xC8, 0xE7, 0xBA, 0x2B, 0x32, 0x95, 0xE6, ++ 0xA0, 0xC0, 0x98, 0x19, 0xD1, 0x9E, 0x7F, 0xA3, 0x66, 0x44, 0x7E, 0x54, ++ 0xAB, 0x3B, 0x83, 0x0B, 0xCA, 0x8C, 0x29, 0xC7, 0xD3, 0x6B, 0x3C, 0x28, ++ 0x79, 0xA7, 0xE2, 0xBC, 0x1D, 0x16, 0x76, 0xAD, 0x3B, 0xDB, 0x56, 0x64, ++ 0x4E, 0x74, 0x1E, 0x14, 0xDB, 0x92, 0x0A, 0x0C, 0x6C, 0x48, 0xE4, 0xB8, ++ 0x5D, 0x9F, 0x6E, 0xBD, 0xEF, 0x43, 0xA6, 0xC4, 0xA8, 0x39, 0xA4, 0x31, ++ 0x37, 0xD3, 0x8B, 0xF2, 0x32, 0xD5, 0x43, 0x8B, 0x59, 0x6E, 0xB7, 0xDA, ++ 0x8C, 0x01, 0x64, 0xB1, 0xD2, 0x9C, 0xE0, 0x49, 0xB4, 0xD8, 0xFA, 0xAC, ++ 0x07, 0xF3, 0x25, 0xCF, 0xAF, 0xCA, 0x8E, 0xF4, 0xE9, 0x47, 0x18, 0x10, ++ 0xD5, 0x6F, 0x88, 0xF0, 0x6F, 0x4A, 0x72, 0x5C, 0x24, 0x38, 0xF1, 0x57, ++ 0xC7, 0x73, 0x51, 0x97, 0x23, 0xCB, 0x7C, 0xA1, 0x9C, 0xE8, 0x21, 0x3E, ++ 0xDD, 0x96, 0xDC, 0x61, 0x86, 0x0D, 0x85, 0x0F, 0x90, 0xE0, 0x42, 0x7C, ++ 0xC4, 0x71, 0xAA, 0xCC, 0xD8, 0x90, 0x05, 0x06, 0x01, 0xF7, 0x12, 0x1C, ++ 0xA3, 0xC2, 0x5F, 0x6A, 0xF9, 0xAE, 0xD0, 0x69, 0x91, 0x17, 0x58, 0x99, ++ 0x27, 0x3A, 0xB9, 0x27, 0x38, 0xD9, 0x13, 0xEB, 0xB3, 0x2B, 0x33, 0x22, ++ 0xBB, 0xD2, 0x70, 0xA9, 0x89, 0x07, 0xA7, 0x33, 0xB6, 0x2D, 0x22, 0x3C, ++ 0x92, 0x15, 0x20, 0xC9, 0x49, 0x87, 0xFF, 0xAA, 0x78, 0x50, 0x7A, 0xA5, ++ 0x8F, 0x03, 0xF8, 0x59, 0x80, 0x09, 0x17, 0x1A, 0xDA, 0x65, 0x31, 0xD7, ++ 0xC6, 0x84, 0xB8, 0xD0, 0xC3, 0x82, 0xB0, 0x29, 0x77, 0x5A, 0x11, 0x1E, ++ 0xCB, 0x7B, 0xFC, 0xA8, 0xD6, 0x6D, 0x3A, 0x2C, 0x64, 0x65, 0x6C, 0x61, ++ 0x79, 0x20, 0x3E, 0x20, 0x30, 0x00, 0x00, 0x00, 0x64, 0x65, 0x6C, 0x61, ++ 0x79, 0x20, 0x3C, 0x20, 0x4B, 0x45, 0x5F, 0x54, 0x49, 0x4D, 0x45, 0x52, ++ 0x5F, 0x44, 0x45, 0x4C, 0x41, 0x59, 0x5F, 0x4D, 0x41, 0x58, 0x00, 0x00, ++ 0x74, 0x69, 0x6D, 0x65, 0x72, 0x00, 0x00, 0x00, 0x21, 0x66, 0x69, 0x72, ++ 0x73, 0x74, 0x20, 0x7C, 0x7C, 0x20, 0x21, 0x6B, 0x65, 0x5F, 0x74, 0x69, ++ 0x6D, 0x65, 0x5F, 0x70, 0x61, 0x73, 0x74, 0x28, 0x66, 0x69, 0x72, 0x73, ++ 0x74, 0x2D, 0x3E, 0x74, 0x69, 0x6D, 0x65, 0x29, 0x00, 0x00, 0x00, 0x00, ++ 0x6D, 0x73, 0x67, 0x20, 0x21, 0x3D, 0x20, 0x4E, 0x55, 0x4C, 0x4C, 0x00, ++ 0x9D, 0x80, 0x44, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6E, ++ 0x67, 0x20, 0x6D, 0x73, 0x67, 0x3A, 0x25, 0x78, 0x20, 0x66, 0x72, 0x6F, ++ 0x6D, 0x20, 0x74, 0x73, 0x6B, 0x3A, 0x25, 0x78, 0x20, 0x74, 0x6F, 0x20, ++ 0x74, 0x73, 0x6B, 0x3A, 0x25, 0x78, 0x0A, 0x00, 0x74, 0x6F, 0x74, 0x61, ++ 0x6C, 0x73, 0x69, 0x7A, 0x65, 0x20, 0x3E, 0x3D, 0x20, 0x73, 0x69, 0x7A, ++ 0x65, 0x6F, 0x66, 0x28, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x6D, ++ 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x5F, 0x66, 0x72, 0x65, 0x65, 0x29, 0x00, ++ 0x66, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x21, 0x3D, 0x20, 0x4E, 0x55, 0x4C, ++ 0x4C, 0x00, 0x00, 0x00, 0x28, 0x75, 0x69, 0x6E, 0x74, 0x33, 0x32, 0x5F, ++ 0x74, 0x29, 0x6D, 0x65, 0x6D, 0x5F, 0x70, 0x74, 0x72, 0x20, 0x3E, 0x20, ++ 0x28, 0x75, 0x69, 0x6E, 0x74, 0x33, 0x32, 0x5F, 0x74, 0x29, 0x6E, 0x6F, ++ 0x64, 0x65, 0x00, 0x00, 0x70, 0x72, 0x65, 0x76, 0x5F, 0x6E, 0x6F, 0x64, ++ 0x65, 0x20, 0x21, 0x3D, 0x20, 0x4E, 0x55, 0x4C, 0x4C, 0x00, 0x00, 0x00, ++ 0x73, 0x74, 0x61, 0x74, 0x65, 0x5F, 0x68, 0x61, 0x6E, 0x64, 0x6C, 0x65, ++ 0x72, 0x2D, 0x3E, 0x6D, 0x73, 0x67, 0x5F, 0x74, 0x61, 0x62, 0x6C, 0x65, ++ 0x5B, 0x69, 0x5D, 0x2E, 0x66, 0x75, 0x6E, 0x63, 0x00, 0x00, 0x00, 0x00, ++ 0x74, 0x79, 0x70, 0x65, 0x20, 0x3C, 0x20, 0x54, 0x41, 0x53, 0x4B, 0x5F, ++ 0x4D, 0x41, 0x58, 0x00, 0x6B, 0x65, 0x5F, 0x74, 0x61, 0x73, 0x6B, 0x5F, ++ 0x6C, 0x6F, 0x63, 0x61, 0x6C, 0x28, 0x74, 0x79, 0x70, 0x65, 0x29, 0x00, ++ 0x69, 0x64, 0x78, 0x20, 0x3C, 0x20, 0x54, 0x41, 0x53, 0x4B, 0x5F, 0x44, ++ 0x45, 0x53, 0x43, 0x5B, 0x74, 0x79, 0x70, 0x65, 0x5D, 0x2E, 0x69, 0x64, ++ 0x78, 0x5F, 0x6D, 0x61, 0x78, 0x00, 0x00, 0x00, 0x6B, 0x65, 0x5F, 0x73, ++ 0x74, 0x61, 0x74, 0x65, 0x69, 0x64, 0x5F, 0x70, 0x74, 0x72, 0x00, 0x00, ++ 0x80, 0x9D, 0x73, 0x65, 0x74, 0x20, 0x74, 0x73, 0x6B, 0x3A, 0x25, 0x78, ++ 0x3A, 0x25, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x9A, 0x80, 0x4E, 0x6F, ++ 0x20, 0x68, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x72, 0x20, 0x66, 0x6F, 0x75, ++ 0x6E, 0x64, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x6D, 0x73, 0x67, 0x3A, 0x25, ++ 0x78, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x74, 0x73, 0x6B, 0x3A, 0x25, ++ 0x78, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x73, 0x6B, 0x3A, 0x25, 0x78, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x24, 0x9F, 0x15, 0x00, 0x1C, 0x9F, 0x15, 0x00, ++ 0xCC, 0x9C, 0x17, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x70, 0xB5, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0xB4, 0xA4, 0x15, 0x00, 0xF0, 0x9F, 0x17, 0x00, ++ 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xBF, 0x15, 0x00, ++ 0x18, 0xBF, 0x15, 0x00, 0xA4, 0xBA, 0x17, 0x00, 0x02, 0x00, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x8C, 0xB8, 0x15, 0x00, 0xE0, 0xB8, 0x17, 0x00, ++ 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0xBB, 0x15, 0x00, ++ 0x60, 0xBA, 0x17, 0x00, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x64, 0xBE, 0x15, 0x00, 0x90, 0xBA, 0x17, 0x00, 0x04, 0x00, 0x01, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x2C, 0xC2, 0x15, 0x00, 0xF4, 0xDF, 0x17, 0x00, ++ 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0xB0, 0xD0, 0x15, 0x00, 0x74, 0xEF, 0x17, 0x00, ++ 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x65, 0x76, 0x65, ++ 0x6E, 0x74, 0x20, 0x3C, 0x20, 0x4B, 0x45, 0x5F, 0x45, 0x56, 0x54, 0x5F, ++ 0x4D, 0x41, 0x58, 0x29, 0x20, 0x26, 0x26, 0x20, 0x6B, 0x65, 0x5F, 0x65, ++ 0x76, 0x74, 0x5F, 0x68, 0x64, 0x6C, 0x72, 0x5B, 0x65, 0x76, 0x65, 0x6E, ++ 0x74, 0x5D, 0x2E, 0x66, 0x75, 0x6E, 0x63, 0x00, 0x6C, 0x69, 0x73, 0x74, ++ 0x5F, 0x68, 0x64, 0x72, 0x20, 0x21, 0x3D, 0x20, 0x4E, 0x55, 0x4C, 0x4C, ++ 0x00, 0x00, 0x00, 0x00, 0x6C, 0x69, 0x73, 0x74, 0x20, 0x21, 0x3D, 0x20, ++ 0x4E, 0x55, 0x4C, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x28, 0x70, 0x72, 0x65, ++ 0x76, 0x5F, 0x65, 0x6C, 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x20, 0x3D, 0x3D, ++ 0x20, 0x4E, 0x55, 0x4C, 0x4C, 0x29, 0x20, 0x7C, 0x7C, 0x20, 0x28, 0x70, ++ 0x72, 0x65, 0x76, 0x5F, 0x65, 0x6C, 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x2D, ++ 0x3E, 0x6E, 0x65, 0x78, 0x74, 0x20, 0x3D, 0x3D, 0x20, 0x65, 0x6C, 0x65, ++ 0x6D, 0x65, 0x6E, 0x74, 0x29, 0x00, 0x00, 0x00, 0x65, 0x6C, 0x65, 0x6D, ++ 0x65, 0x6E, 0x74, 0x20, 0x21, 0x3D, 0x20, 0x4E, 0x55, 0x4C, 0x4C, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x96, 0x30, 0x07, 0x77, 0x2C, 0x61, 0x0E, 0xEE, ++ 0xBA, 0x51, 0x09, 0x99, 0x19, 0xC4, 0x6D, 0x07, 0x8F, 0xF4, 0x6A, 0x70, ++ 0x35, 0xA5, 0x63, 0xE9, 0xA3, 0x95, 0x64, 0x9E, 0x32, 0x88, 0xDB, 0x0E, ++ 0xA4, 0xB8, 0xDC, 0x79, 0x1E, 0xE9, 0xD5, 0xE0, 0x88, 0xD9, 0xD2, 0x97, ++ 0x2B, 0x4C, 0xB6, 0x09, 0xBD, 0x7C, 0xB1, 0x7E, 0x07, 0x2D, 0xB8, 0xE7, ++ 0x91, 0x1D, 0xBF, 0x90, 0x64, 0x10, 0xB7, 0x1D, 0xF2, 0x20, 0xB0, 0x6A, ++ 0x48, 0x71, 0xB9, 0xF3, 0xDE, 0x41, 0xBE, 0x84, 0x7D, 0xD4, 0xDA, 0x1A, ++ 0xEB, 0xE4, 0xDD, 0x6D, 0x51, 0xB5, 0xD4, 0xF4, 0xC7, 0x85, 0xD3, 0x83, ++ 0x56, 0x98, 0x6C, 0x13, 0xC0, 0xA8, 0x6B, 0x64, 0x7A, 0xF9, 0x62, 0xFD, ++ 0xEC, 0xC9, 0x65, 0x8A, 0x4F, 0x5C, 0x01, 0x14, 0xD9, 0x6C, 0x06, 0x63, ++ 0x63, 0x3D, 0x0F, 0xFA, 0xF5, 0x0D, 0x08, 0x8D, 0xC8, 0x20, 0x6E, 0x3B, ++ 0x5E, 0x10, 0x69, 0x4C, 0xE4, 0x41, 0x60, 0xD5, 0x72, 0x71, 0x67, 0xA2, ++ 0xD1, 0xE4, 0x03, 0x3C, 0x47, 0xD4, 0x04, 0x4B, 0xFD, 0x85, 0x0D, 0xD2, ++ 0x6B, 0xB5, 0x0A, 0xA5, 0xFA, 0xA8, 0xB5, 0x35, 0x6C, 0x98, 0xB2, 0x42, ++ 0xD6, 0xC9, 0xBB, 0xDB, 0x40, 0xF9, 0xBC, 0xAC, 0xE3, 0x6C, 0xD8, 0x32, ++ 0x75, 0x5C, 0xDF, 0x45, 0xCF, 0x0D, 0xD6, 0xDC, 0x59, 0x3D, 0xD1, 0xAB, ++ 0xAC, 0x30, 0xD9, 0x26, 0x3A, 0x00, 0xDE, 0x51, 0x80, 0x51, 0xD7, 0xC8, ++ 0x16, 0x61, 0xD0, 0xBF, 0xB5, 0xF4, 0xB4, 0x21, 0x23, 0xC4, 0xB3, 0x56, ++ 0x99, 0x95, 0xBA, 0xCF, 0x0F, 0xA5, 0xBD, 0xB8, 0x9E, 0xB8, 0x02, 0x28, ++ 0x08, 0x88, 0x05, 0x5F, 0xB2, 0xD9, 0x0C, 0xC6, 0x24, 0xE9, 0x0B, 0xB1, ++ 0x87, 0x7C, 0x6F, 0x2F, 0x11, 0x4C, 0x68, 0x58, 0xAB, 0x1D, 0x61, 0xC1, ++ 0x3D, 0x2D, 0x66, 0xB6, 0x90, 0x41, 0xDC, 0x76, 0x06, 0x71, 0xDB, 0x01, ++ 0xBC, 0x20, 0xD2, 0x98, 0x2A, 0x10, 0xD5, 0xEF, 0x89, 0x85, 0xB1, 0x71, ++ 0x1F, 0xB5, 0xB6, 0x06, 0xA5, 0xE4, 0xBF, 0x9F, 0x33, 0xD4, 0xB8, 0xE8, ++ 0xA2, 0xC9, 0x07, 0x78, 0x34, 0xF9, 0x00, 0x0F, 0x8E, 0xA8, 0x09, 0x96, ++ 0x18, 0x98, 0x0E, 0xE1, 0xBB, 0x0D, 0x6A, 0x7F, 0x2D, 0x3D, 0x6D, 0x08, ++ 0x97, 0x6C, 0x64, 0x91, 0x01, 0x5C, 0x63, 0xE6, 0xF4, 0x51, 0x6B, 0x6B, ++ 0x62, 0x61, 0x6C, 0x1C, 0xD8, 0x30, 0x65, 0x85, 0x4E, 0x00, 0x62, 0xF2, ++ 0xED, 0x95, 0x06, 0x6C, 0x7B, 0xA5, 0x01, 0x1B, 0xC1, 0xF4, 0x08, 0x82, ++ 0x57, 0xC4, 0x0F, 0xF5, 0xC6, 0xD9, 0xB0, 0x65, 0x50, 0xE9, 0xB7, 0x12, ++ 0xEA, 0xB8, 0xBE, 0x8B, 0x7C, 0x88, 0xB9, 0xFC, 0xDF, 0x1D, 0xDD, 0x62, ++ 0x49, 0x2D, 0xDA, 0x15, 0xF3, 0x7C, 0xD3, 0x8C, 0x65, 0x4C, 0xD4, 0xFB, ++ 0x58, 0x61, 0xB2, 0x4D, 0xCE, 0x51, 0xB5, 0x3A, 0x74, 0x00, 0xBC, 0xA3, ++ 0xE2, 0x30, 0xBB, 0xD4, 0x41, 0xA5, 0xDF, 0x4A, 0xD7, 0x95, 0xD8, 0x3D, ++ 0x6D, 0xC4, 0xD1, 0xA4, 0xFB, 0xF4, 0xD6, 0xD3, 0x6A, 0xE9, 0x69, 0x43, ++ 0xFC, 0xD9, 0x6E, 0x34, 0x46, 0x88, 0x67, 0xAD, 0xD0, 0xB8, 0x60, 0xDA, ++ 0x73, 0x2D, 0x04, 0x44, 0xE5, 0x1D, 0x03, 0x33, 0x5F, 0x4C, 0x0A, 0xAA, ++ 0xC9, 0x7C, 0x0D, 0xDD, 0x3C, 0x71, 0x05, 0x50, 0xAA, 0x41, 0x02, 0x27, ++ 0x10, 0x10, 0x0B, 0xBE, 0x86, 0x20, 0x0C, 0xC9, 0x25, 0xB5, 0x68, 0x57, ++ 0xB3, 0x85, 0x6F, 0x20, 0x09, 0xD4, 0x66, 0xB9, 0x9F, 0xE4, 0x61, 0xCE, ++ 0x0E, 0xF9, 0xDE, 0x5E, 0x98, 0xC9, 0xD9, 0x29, 0x22, 0x98, 0xD0, 0xB0, ++ 0xB4, 0xA8, 0xD7, 0xC7, 0x17, 0x3D, 0xB3, 0x59, 0x81, 0x0D, 0xB4, 0x2E, ++ 0x3B, 0x5C, 0xBD, 0xB7, 0xAD, 0x6C, 0xBA, 0xC0, 0x20, 0x83, 0xB8, 0xED, ++ 0xB6, 0xB3, 0xBF, 0x9A, 0x0C, 0xE2, 0xB6, 0x03, 0x9A, 0xD2, 0xB1, 0x74, ++ 0x39, 0x47, 0xD5, 0xEA, 0xAF, 0x77, 0xD2, 0x9D, 0x15, 0x26, 0xDB, 0x04, ++ 0x83, 0x16, 0xDC, 0x73, 0x12, 0x0B, 0x63, 0xE3, 0x84, 0x3B, 0x64, 0x94, ++ 0x3E, 0x6A, 0x6D, 0x0D, 0xA8, 0x5A, 0x6A, 0x7A, 0x0B, 0xCF, 0x0E, 0xE4, ++ 0x9D, 0xFF, 0x09, 0x93, 0x27, 0xAE, 0x00, 0x0A, 0xB1, 0x9E, 0x07, 0x7D, ++ 0x44, 0x93, 0x0F, 0xF0, 0xD2, 0xA3, 0x08, 0x87, 0x68, 0xF2, 0x01, 0x1E, ++ 0xFE, 0xC2, 0x06, 0x69, 0x5D, 0x57, 0x62, 0xF7, 0xCB, 0x67, 0x65, 0x80, ++ 0x71, 0x36, 0x6C, 0x19, 0xE7, 0x06, 0x6B, 0x6E, 0x76, 0x1B, 0xD4, 0xFE, ++ 0xE0, 0x2B, 0xD3, 0x89, 0x5A, 0x7A, 0xDA, 0x10, 0xCC, 0x4A, 0xDD, 0x67, ++ 0x6F, 0xDF, 0xB9, 0xF9, 0xF9, 0xEF, 0xBE, 0x8E, 0x43, 0xBE, 0xB7, 0x17, ++ 0xD5, 0x8E, 0xB0, 0x60, 0xE8, 0xA3, 0xD6, 0xD6, 0x7E, 0x93, 0xD1, 0xA1, ++ 0xC4, 0xC2, 0xD8, 0x38, 0x52, 0xF2, 0xDF, 0x4F, 0xF1, 0x67, 0xBB, 0xD1, ++ 0x67, 0x57, 0xBC, 0xA6, 0xDD, 0x06, 0xB5, 0x3F, 0x4B, 0x36, 0xB2, 0x48, ++ 0xDA, 0x2B, 0x0D, 0xD8, 0x4C, 0x1B, 0x0A, 0xAF, 0xF6, 0x4A, 0x03, 0x36, ++ 0x60, 0x7A, 0x04, 0x41, 0xC3, 0xEF, 0x60, 0xDF, 0x55, 0xDF, 0x67, 0xA8, ++ 0xEF, 0x8E, 0x6E, 0x31, 0x79, 0xBE, 0x69, 0x46, 0x8C, 0xB3, 0x61, 0xCB, ++ 0x1A, 0x83, 0x66, 0xBC, 0xA0, 0xD2, 0x6F, 0x25, 0x36, 0xE2, 0x68, 0x52, ++ 0x95, 0x77, 0x0C, 0xCC, 0x03, 0x47, 0x0B, 0xBB, 0xB9, 0x16, 0x02, 0x22, ++ 0x2F, 0x26, 0x05, 0x55, 0xBE, 0x3B, 0xBA, 0xC5, 0x28, 0x0B, 0xBD, 0xB2, ++ 0x92, 0x5A, 0xB4, 0x2B, 0x04, 0x6A, 0xB3, 0x5C, 0xA7, 0xFF, 0xD7, 0xC2, ++ 0x31, 0xCF, 0xD0, 0xB5, 0x8B, 0x9E, 0xD9, 0x2C, 0x1D, 0xAE, 0xDE, 0x5B, ++ 0xB0, 0xC2, 0x64, 0x9B, 0x26, 0xF2, 0x63, 0xEC, 0x9C, 0xA3, 0x6A, 0x75, ++ 0x0A, 0x93, 0x6D, 0x02, 0xA9, 0x06, 0x09, 0x9C, 0x3F, 0x36, 0x0E, 0xEB, ++ 0x85, 0x67, 0x07, 0x72, 0x13, 0x57, 0x00, 0x05, 0x82, 0x4A, 0xBF, 0x95, ++ 0x14, 0x7A, 0xB8, 0xE2, 0xAE, 0x2B, 0xB1, 0x7B, 0x38, 0x1B, 0xB6, 0x0C, ++ 0x9B, 0x8E, 0xD2, 0x92, 0x0D, 0xBE, 0xD5, 0xE5, 0xB7, 0xEF, 0xDC, 0x7C, ++ 0x21, 0xDF, 0xDB, 0x0B, 0xD4, 0xD2, 0xD3, 0x86, 0x42, 0xE2, 0xD4, 0xF1, ++ 0xF8, 0xB3, 0xDD, 0x68, 0x6E, 0x83, 0xDA, 0x1F, 0xCD, 0x16, 0xBE, 0x81, ++ 0x5B, 0x26, 0xB9, 0xF6, 0xE1, 0x77, 0xB0, 0x6F, 0x77, 0x47, 0xB7, 0x18, ++ 0xE6, 0x5A, 0x08, 0x88, 0x70, 0x6A, 0x0F, 0xFF, 0xCA, 0x3B, 0x06, 0x66, ++ 0x5C, 0x0B, 0x01, 0x11, 0xFF, 0x9E, 0x65, 0x8F, 0x69, 0xAE, 0x62, 0xF8, ++ 0xD3, 0xFF, 0x6B, 0x61, 0x45, 0xCF, 0x6C, 0x16, 0x78, 0xE2, 0x0A, 0xA0, ++ 0xEE, 0xD2, 0x0D, 0xD7, 0x54, 0x83, 0x04, 0x4E, 0xC2, 0xB3, 0x03, 0x39, ++ 0x61, 0x26, 0x67, 0xA7, 0xF7, 0x16, 0x60, 0xD0, 0x4D, 0x47, 0x69, 0x49, ++ 0xDB, 0x77, 0x6E, 0x3E, 0x4A, 0x6A, 0xD1, 0xAE, 0xDC, 0x5A, 0xD6, 0xD9, ++ 0x66, 0x0B, 0xDF, 0x40, 0xF0, 0x3B, 0xD8, 0x37, 0x53, 0xAE, 0xBC, 0xA9, ++ 0xC5, 0x9E, 0xBB, 0xDE, 0x7F, 0xCF, 0xB2, 0x47, 0xE9, 0xFF, 0xB5, 0x30, ++ 0x1C, 0xF2, 0xBD, 0xBD, 0x8A, 0xC2, 0xBA, 0xCA, 0x30, 0x93, 0xB3, 0x53, ++ 0xA6, 0xA3, 0xB4, 0x24, 0x05, 0x36, 0xD0, 0xBA, 0x93, 0x06, 0xD7, 0xCD, ++ 0x29, 0x57, 0xDE, 0x54, 0xBF, 0x67, 0xD9, 0x23, 0x2E, 0x7A, 0x66, 0xB3, ++ 0xB8, 0x4A, 0x61, 0xC4, 0x02, 0x1B, 0x68, 0x5D, 0x94, 0x2B, 0x6F, 0x2A, ++ 0x37, 0xBE, 0x0B, 0xB4, 0xA1, 0x8E, 0x0C, 0xC3, 0x1B, 0xDF, 0x05, 0x5A, ++ 0x8D, 0xEF, 0x02, 0x2D, 0x61, 0x64, 0x64, 0x72, 0x20, 0x3D, 0x3D, 0x20, ++ 0x65, 0x6E, 0x64, 0x00, 0x00, 0x50, 0xF2, 0x01, 0x01, 0x00, 0x00, 0x00, ++ 0x00, 0x50, 0xF2, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x03, ++ 0x04, 0x08, 0x02, 0x01, 0x01, 0x00, 0x02, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, ++ 0xFF, 0xFF, 0x00, 0x00, 0x02, 0x04, 0x0B, 0x16, 0x0C, 0x12, 0x18, 0x24, ++ 0x30, 0x48, 0x60, 0x6C, 0x01, 0x00, 0x00, 0x01, 0x02, 0x02, 0x03, 0x03, ++ 0x03, 0x00, 0x00, 0x00, 0x44, 0x42, 0x47, 0x5F, 0x53, 0x45, 0x56, 0x5F, ++ 0x4D, 0x49, 0x4E, 0x20, 0x3C, 0x3D, 0x20, 0x70, 0x72, 0x65, 0x66, 0x69, ++ 0x78, 0x20, 0x26, 0x26, 0x20, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x20, ++ 0x3C, 0x20, 0x44, 0x42, 0x47, 0x5F, 0x53, 0x45, 0x56, 0x5F, 0x4D, 0x41, ++ 0x58, 0x00, 0x00, 0x00, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, ++ 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x00, 0x00, 0x00, 0x00, ++ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, ++ 0x43, 0x44, 0x45, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x03, 0x02, 0x06, 0x07, ++ 0x00, 0x00, 0x04, 0x02, 0x03, 0x02, 0x06, 0x07, 0x00, 0x00, 0x04, 0x03, ++ 0x03, 0x00, 0x06, 0x07, 0x00, 0x00, 0x00, 0x05, 0x05, 0x00, 0x06, 0x07, ++ 0x00, 0x00, 0x00, 0x05, 0x05, 0x00, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x65, 0x72, 0x72, 0x2C, 0x20, 0x77, 0x6C, 0x61, 0x6E, 0x20, 0x66, 0x63, ++ 0x20, 0x74, 0x69, 0x6D, 0x65, 0x6F, 0x75, 0x74, 0x0A, 0x00, 0x00, 0x00, ++ 0x72, 0x65, 0x62, 0x6F, 0x6F, 0x74, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x67, 0x70, 0x69, 0x6F, 0x77, 0x72, 0x20, 0x69, 0x73, 0x20, 0x6E, 0x6F, ++ 0x74, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6F, 0x72, 0x74, 0x0A, 0x00, 0x00, ++ 0x9D, 0x81, 0x44, 0x42, 0x47, 0x3A, 0x20, 0x53, 0x65, 0x74, 0x74, 0x69, ++ 0x6E, 0x67, 0x20, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x20, ++ 0x66, 0x69, 0x6C, 0x74, 0x65, 0x72, 0x3A, 0x20, 0x30, 0x78, 0x25, 0x30, ++ 0x38, 0x78, 0x0A, 0x00, 0x9D, 0x81, 0x44, 0x42, 0x47, 0x3A, 0x20, 0x53, ++ 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x6D, 0x6F, 0x64, 0x75, 0x6C, ++ 0x65, 0x20, 0x66, 0x69, 0x6C, 0x74, 0x65, 0x72, 0x3A, 0x20, 0x30, 0x78, ++ 0x25, 0x30, 0x38, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x9D, 0x81, 0x44, 0x42, ++ 0x47, 0x3A, 0x20, 0x42, 0x6F, 0x6F, 0x74, 0x20, 0x4E, 0x50, 0x43, 0x20, ++ 0x25, 0x64, 0x0A, 0x00, 0x9D, 0x81, 0x44, 0x42, 0x47, 0x3A, 0x20, 0x57, ++ 0x72, 0x69, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x6D, 0x65, 0x6D, 0x6F, 0x72, ++ 0x79, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6D, 0x61, 0x73, 0x6B, 0x3A, ++ 0x30, 0x78, 0x25, 0x30, 0x38, 0x78, 0x2C, 0x20, 0x64, 0x61, 0x74, 0x61, ++ 0x3A, 0x30, 0x78, 0x25, 0x30, 0x38, 0x78, 0x20, 0x2F, 0x20, 0x25, 0x64, ++ 0x3A, 0x20, 0x5B, 0x30, 0x78, 0x25, 0x30, 0x38, 0x78, 0x5D, 0x20, 0x3D, ++ 0x20, 0x30, 0x78, 0x25, 0x30, 0x38, 0x78, 0x20, 0x2F, 0x20, 0x25, 0x64, ++ 0x0A, 0x00, 0x00, 0x00, 0x9D, 0x81, 0x44, 0x42, 0x47, 0x3A, 0x20, 0x57, ++ 0x72, 0x69, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x6D, 0x65, 0x6D, 0x6F, 0x72, ++ 0x79, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x30, 0x78, 0x25, 0x30, 0x38, ++ 0x78, 0x20, 0x2F, 0x20, 0x25, 0x64, 0x3A, 0x20, 0x5B, 0x30, 0x78, 0x25, ++ 0x30, 0x38, 0x78, 0x5D, 0x20, 0x3D, 0x20, 0x30, 0x78, 0x25, 0x30, 0x38, ++ 0x78, 0x20, 0x2F, 0x20, 0x25, 0x64, 0x0A, 0x00, 0x9D, 0x81, 0x44, 0x42, ++ 0x47, 0x3A, 0x20, 0x52, 0x65, 0x61, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x6D, ++ 0x65, 0x6D, 0x6F, 0x72, 0x79, 0x3A, 0x20, 0x5B, 0x30, 0x78, 0x25, 0x30, ++ 0x38, 0x78, 0x5D, 0x20, 0x3D, 0x20, 0x30, 0x78, 0x25, 0x30, 0x38, 0x78, ++ 0x20, 0x2F, 0x20, 0x25, 0x64, 0x0A, 0x00, 0x00, 0x9D, 0x81, 0x42, 0x6F, ++ 0x6F, 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3D, 0x25, 0x78, 0x2C, 0x20, ++ 0x61, 0x64, 0x64, 0x72, 0x3D, 0x30, 0x78, 0x25, 0x30, 0x38, 0x78, 0x0D, ++ 0x0A, 0x00, 0x00, 0x00, 0x64, 0x65, 0x6C, 0x61, 0x79, 0x20, 0x25, 0x64, ++ 0x0D, 0x0A, 0x00, 0x00, 0x49, 0x6E, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x20, ++ 0x62, 0x6F, 0x6F, 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x0D, 0x0A, 0x00, ++ 0x9D, 0x81, 0x44, 0x42, 0x47, 0x3A, 0x20, 0x46, 0x57, 0x20, 0x73, 0x74, ++ 0x61, 0x72, 0x74, 0x65, 0x64, 0x0A, 0x00, 0x00, 0x9D, 0x81, 0x44, 0x42, ++ 0x47, 0x3A, 0x20, 0x57, 0x72, 0x69, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x6D, ++ 0x65, 0x6D, 0x6F, 0x72, 0x79, 0x20, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x20, ++ 0x5B, 0x30, 0x78, 0x25, 0x30, 0x38, 0x78, 0x20, 0x7E, 0x20, 0x30, 0x78, ++ 0x25, 0x30, 0x38, 0x78, 0x5D, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x7B, ++ 0x30, 0x78, 0x25, 0x30, 0x38, 0x78, 0x2C, 0x20, 0x2E, 0x2E, 0x2E, 0x7D, ++ 0x2C, 0x20, 0x77, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x3A, 0x20, 0x25, ++ 0x30, 0x32, 0x78, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x70, 0x22, 0x17, 0x00, ++ 0x0C, 0x00, 0x00, 0x00, 0x9B, 0x41, 0x53, 0x53, 0x45, 0x52, 0x54, 0x20, ++ 0x28, 0x25, 0x73, 0x29, 0x20, 0x61, 0x74, 0x20, 0x25, 0x73, 0x3A, 0x25, ++ 0x64, 0x0A, 0x00, 0x00, 0x9B, 0x57, 0x41, 0x52, 0x4E, 0x49, 0x4E, 0x47, ++ 0x20, 0x28, 0x25, 0x73, 0x29, 0x20, 0x61, 0x74, 0x20, 0x25, 0x73, 0x3A, ++ 0x25, 0x64, 0x0A, 0x00, 0x45, 0x72, 0x72, 0x3A, 0x20, 0x55, 0x46, 0x20, ++ 0x68, 0x6F, 0x73, 0x74, 0x20, 0x72, 0x78, 0x20, 0x62, 0x75, 0x66, 0x66, ++ 0x20, 0x4E, 0x55, 0x4C, 0x4C, 0x0D, 0x0A, 0x00, 0x09, 0x2D, 0x20, 0x00, ++ 0x25, 0x73, 0x25, 0x73, 0x25, 0x73, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x20, 0x20, 0x00, 0x00, 0x25, 0x30, 0x32, 0x78, 0x20, 0x00, 0x00, 0x00, ++ 0x25, 0x30, 0x38, 0x78, 0x3A, 0x00, 0x00, 0x00, 0x20, 0x25, 0x30, 0x34, ++ 0x58, 0x20, 0x25, 0x30, 0x34, 0x58, 0x00, 0x00, 0x20, 0x25, 0x30, 0x32, ++ 0x58, 0x20, 0x25, 0x30, 0x32, 0x58, 0x20, 0x25, 0x30, 0x32, 0x58, 0x20, ++ 0x25, 0x30, 0x32, 0x58, 0x00, 0x00, 0x00, 0x00, 0x20, 0x25, 0x30, 0x34, ++ 0x58, 0x00, 0x00, 0x00, 0x20, 0x25, 0x30, 0x32, 0x58, 0x00, 0x00, 0x00, ++ 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x20, 0x68, 0x65, 0x6C, ++ 0x70, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x00, 0x00, 0x68, 0x65, 0x6C, 0x70, ++ 0x00, 0x00, 0x00, 0x00, 0x20, 0x72, 0x20, 0x61, 0x64, 0x64, 0x72, 0x20, ++ 0x3C, 0x63, 0x6E, 0x74, 0x3E, 0x20, 0x3C, 0x73, 0x7A, 0x3E, 0x00, 0x00, ++ 0x20, 0x77, 0x20, 0x61, 0x64, 0x64, 0x72, 0x20, 0x76, 0x61, 0x6C, 0x00, ++ 0x77, 0x00, 0x00, 0x00, 0x20, 0x64, 0x62, 0x67, 0x20, 0x6D, 0x73, 0x6B, ++ 0x00, 0x00, 0x00, 0x00, 0x64, 0x6D, 0x00, 0x00, 0x20, 0x77, 0x66, 0x63, ++ 0x74, 0x20, 0x76, 0x61, 0x6C, 0x28, 0x69, 0x6E, 0x20, 0x73, 0x29, 0x00, ++ 0x77, 0x66, 0x63, 0x74, 0x00, 0x00, 0x00, 0x00, 0x65, 0x72, 0x72, 0x3A, ++ 0x20, 0x63, 0x6D, 0x64, 0x5F, 0x66, 0x72, 0x65, 0x65, 0x5F, 0x6C, 0x69, ++ 0x73, 0x74, 0x20, 0x65, 0x6D, 0x70, 0x74, 0x79, 0x0D, 0x0A, 0x00, 0x00, ++ 0x61, 0x69, 0x63, 0x3E, 0x20, 0x00, 0x00, 0x00, 0x4E, 0x6F, 0x20, 0x6D, ++ 0x6F, 0x72, 0x65, 0x20, 0x63, 0x6D, 0x64, 0x73, 0x20, 0x73, 0x75, 0x70, ++ 0x70, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x2E, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x2A, 0x2A, 0x20, 0x54, 0x6F, 0x6F, 0x20, 0x6D, 0x61, 0x6E, 0x79, 0x20, ++ 0x61, 0x72, 0x67, 0x73, 0x20, 0x28, 0x6D, 0x61, 0x78, 0x2E, 0x20, 0x25, ++ 0x64, 0x29, 0x20, 0x2A, 0x2A, 0x0A, 0x00, 0x00, 0x55, 0x6E, 0x6B, 0x6E, ++ 0x6F, 0x77, 0x6E, 0x20, 0x63, 0x6F, 0x6D, 0x6D, 0x61, 0x6E, 0x64, 0x20, ++ 0x27, 0x25, 0x73, 0x27, 0x0A, 0x00, 0x00, 0x00, 0x55, 0x73, 0x61, 0x67, ++ 0x65, 0x3A, 0x0A, 0x25, 0x73, 0x0A, 0x00, 0x00, 0x63, 0x6F, 0x6D, 0x6D, ++ 0x61, 0x6E, 0x64, 0x20, 0x66, 0x61, 0x69, 0x6C, 0x0D, 0x0A, 0x00, 0x00, ++ 0x63, 0x75, 0x72, 0x20, 0x64, 0x62, 0x67, 0x5F, 0x6D, 0x73, 0x6B, 0x3A, ++ 0x20, 0x30, 0x78, 0x25, 0x78, 0x0A, 0x00, 0x00, 0x63, 0x66, 0x67, 0x20, ++ 0x64, 0x62, 0x67, 0x5F, 0x6D, 0x73, 0x6B, 0x3A, 0x20, 0x30, 0x78, 0x25, ++ 0x78, 0x0A, 0x00, 0x00, 0x69, 0x6E, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x20, ++ 0x61, 0x72, 0x67, 0x73, 0x0A, 0x00, 0x00, 0x00, 0x69, 0x6E, 0x76, 0x61, ++ 0x6C, 0x69, 0x64, 0x20, 0x66, 0x75, 0x6E, 0x63, 0x3A, 0x20, 0x25, 0x64, ++ 0x0A, 0x00, 0x00, 0x00, 0x55, 0x73, 0x61, 0x67, 0x65, 0x3A, 0x0A, 0x20, ++ 0x20, 0x72, 0x20, 0x61, 0x64, 0x64, 0x72, 0x20, 0x3C, 0x63, 0x6E, 0x74, ++ 0x3E, 0x0A, 0x00, 0x00, 0x5B, 0x30, 0x78, 0x25, 0x30, 0x38, 0x58, 0x5D, ++ 0x20, 0x3D, 0x20, 0x30, 0x78, 0x25, 0x30, 0x38, 0x58, 0x0D, 0x0A, 0x00, ++ 0x5B, 0x30, 0x78, 0x25, 0x30, 0x38, 0x58, 0x5D, 0x20, 0x3D, 0x20, 0x30, ++ 0x78, 0x25, 0x30, 0x32, 0x58, 0x0D, 0x0A, 0x00, 0x5B, 0x30, 0x78, 0x25, ++ 0x30, 0x38, 0x58, 0x5D, 0x20, 0x3D, 0x20, 0x30, 0x78, 0x25, 0x30, 0x34, ++ 0x58, 0x0D, 0x0A, 0x00, 0x55, 0x73, 0x61, 0x67, 0x65, 0x3A, 0x0A, 0x20, ++ 0x20, 0x77, 0x20, 0x61, 0x64, 0x64, 0x72, 0x20, 0x76, 0x61, 0x6C, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x55, 0x73, 0x61, 0x67, 0x65, 0x3A, 0x0A, 0x20, ++ 0x77, 0x66, 0x63, 0x74, 0x20, 0x76, 0x61, 0x6C, 0x28, 0x69, 0x6E, 0x20, ++ 0x73, 0x29, 0x0A, 0x00, 0x63, 0x75, 0x72, 0x20, 0x77, 0x66, 0x63, 0x74, ++ 0x3A, 0x20, 0x25, 0x75, 0x73, 0x0A, 0x00, 0x00, 0x63, 0x66, 0x67, 0x20, ++ 0x77, 0x66, 0x63, 0x74, 0x20, 0x25, 0x75, 0x73, 0x0A, 0x00, 0x00, 0x00, ++ 0x77, 0x66, 0x63, 0x74, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x6F, 0x66, 0x20, ++ 0x72, 0x61, 0x6E, 0x67, 0x65, 0x0A, 0x00, 0x00, 0x08, 0x20, 0x08, 0x00, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, ++ 0xDD, 0x07, 0x00, 0x50, 0xF2, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x6B, 0x65, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65, ++ 0x5F, 0x67, 0x65, 0x74, 0x28, 0x64, 0x65, 0x73, 0x74, 0x5F, 0x69, 0x64, ++ 0x29, 0x20, 0x3D, 0x3D, 0x20, 0x4D, 0x45, 0x5F, 0x42, 0x55, 0x53, 0x59, ++ 0x00, 0x00, 0x00, 0x00, 0x76, 0x69, 0x66, 0x5F, 0x6D, 0x67, 0x6D, 0x74, ++ 0x5F, 0x65, 0x6E, 0x76, 0x2E, 0x6D, 0x6F, 0x6E, 0x69, 0x74, 0x6F, 0x72, ++ 0x5F, 0x76, 0x69, 0x66, 0x20, 0x21, 0x3D, 0x20, 0x49, 0x4E, 0x56, 0x41, ++ 0x4C, 0x49, 0x44, 0x5F, 0x56, 0x49, 0x46, 0x5F, 0x49, 0x44, 0x58, 0x00, ++ 0xD8, 0x22, 0x17, 0x00, 0x18, 0x00, 0x00, 0x00, 0x62, 0x69, 0x74, 0x5F, ++ 0x70, 0x6F, 0x73, 0x20, 0x3C, 0x20, 0x4D, 0x41, 0x43, 0x5F, 0x52, 0x41, ++ 0x54, 0x45, 0x53, 0x45, 0x54, 0x5F, 0x4C, 0x45, 0x4E, 0x00, 0x00, 0x00, ++ 0x72, 0x61, 0x74, 0x65, 0x73, 0x2D, 0x3E, 0x6C, 0x65, 0x6E, 0x67, 0x74, ++ 0x68, 0x20, 0x21, 0x3D, 0x20, 0x30, 0x00, 0x00, 0x4C, 0x4F, 0x43, 0x41, ++ 0x4C, 0x5F, 0x43, 0x41, 0x50, 0x41, 0x28, 0x48, 0x45, 0x29, 0x00, 0x00, ++ 0x4C, 0x4F, 0x43, 0x41, 0x4C, 0x5F, 0x43, 0x41, 0x50, 0x41, 0x28, 0x56, ++ 0x48, 0x54, 0x29, 0x00, 0x4C, 0x4F, 0x43, 0x41, 0x4C, 0x5F, 0x43, 0x41, ++ 0x50, 0x41, 0x28, 0x48, 0x54, 0x29, 0x00, 0x00, 0x76, 0x69, 0x66, 0x2D, ++ 0x3E, 0x63, 0x68, 0x61, 0x6E, 0x5F, 0x63, 0x74, 0x78, 0x74, 0x20, 0x21, ++ 0x3D, 0x20, 0x4E, 0x55, 0x4C, 0x4C, 0x00, 0x00, 0x63, 0x75, 0x72, 0x72, ++ 0x3D, 0x25, 0x78, 0x2C, 0x20, 0x62, 0x73, 0x73, 0x3D, 0x25, 0x78, 0x0D, ++ 0x0A, 0x00, 0x00, 0x00, 0x6D, 0x69, 0x63, 0x5F, 0x63, 0x61, 0x6C, 0x63, ++ 0x5F, 0x70, 0x74, 0x72, 0x2D, 0x3E, 0x6C, 0x61, 0x73, 0x74, 0x5F, 0x6D, ++ 0x5F, 0x69, 0x5F, 0x6C, 0x65, 0x6E, 0x20, 0x3C, 0x20, 0x34, 0x00, 0x00, ++ 0x72, 0x65, 0x61, 0x73, 0x73, 0x6F, 0x63, 0x0D, 0x0A, 0x00, 0x00, 0x00, ++ 0x76, 0x69, 0x66, 0x2D, 0x3E, 0x75, 0x2E, 0x73, 0x74, 0x61, 0x2E, 0x61, ++ 0x70, 0x5F, 0x69, 0x64, 0x20, 0x3D, 0x3D, 0x20, 0x49, 0x4E, 0x56, 0x41, ++ 0x4C, 0x49, 0x44, 0x5F, 0x53, 0x54, 0x41, 0x5F, 0x49, 0x44, 0x58, 0x00, ++ 0x63, 0x6F, 0x6E, 0x6E, 0x20, 0x6C, 0x6F, 0x73, 0x73, 0x20, 0x69, 0x6E, ++ 0x64, 0x0D, 0x0A, 0x00, 0x6B, 0x65, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65, ++ 0x5F, 0x67, 0x65, 0x74, 0x28, 0x54, 0x41, 0x53, 0x4B, 0x5F, 0x53, 0x4D, ++ 0x29, 0x20, 0x3D, 0x3D, 0x20, 0x53, 0x4D, 0x5F, 0x53, 0x43, 0x41, 0x4E, ++ 0x4E, 0x49, 0x4E, 0x47, 0x00, 0x00, 0x00, 0x00, 0x6B, 0x65, 0x5F, 0x73, ++ 0x74, 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, 0x74, 0x28, 0x54, 0x41, 0x53, ++ 0x4B, 0x5F, 0x53, 0x4D, 0x29, 0x20, 0x3D, 0x3D, 0x20, 0x53, 0x4D, 0x5F, ++ 0x4A, 0x4F, 0x49, 0x4E, 0x49, 0x4E, 0x47, 0x00, 0x6D, 0x61, 0x74, 0x63, ++ 0x68, 0x3A, 0x20, 0x25, 0x34, 0x78, 0x3A, 0x25, 0x34, 0x78, 0x3A, 0x25, ++ 0x34, 0x78, 0x2C, 0x20, 0x25, 0x64, 0x0A, 0x00, 0x28, 0x6B, 0x65, 0x5F, ++ 0x73, 0x74, 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, 0x74, 0x28, 0x54, 0x41, ++ 0x53, 0x4B, 0x5F, 0x53, 0x4D, 0x29, 0x20, 0x3D, 0x3D, 0x20, 0x53, 0x4D, ++ 0x5F, 0x42, 0x53, 0x53, 0x5F, 0x50, 0x41, 0x52, 0x41, 0x4D, 0x5F, 0x53, ++ 0x45, 0x54, 0x54, 0x49, 0x4E, 0x47, 0x29, 0x20, 0x7C, 0x7C, 0x20, 0x28, ++ 0x6B, 0x65, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, 0x74, ++ 0x28, 0x54, 0x41, 0x53, 0x4B, 0x5F, 0x53, 0x4D, 0x29, 0x20, 0x3D, 0x3D, ++ 0x20, 0x53, 0x4D, 0x5F, 0x49, 0x44, 0x4C, 0x45, 0x29, 0x20, 0x7C, 0x7C, ++ 0x20, 0x28, 0x6B, 0x65, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5F, 0x67, ++ 0x65, 0x74, 0x28, 0x54, 0x41, 0x53, 0x4B, 0x5F, 0x53, 0x4D, 0x29, 0x20, ++ 0x3D, 0x3D, 0x20, 0x53, 0x4D, 0x5F, 0x44, 0x49, 0x53, 0x43, 0x4F, 0x4E, ++ 0x4E, 0x45, 0x43, 0x54, 0x49, 0x4E, 0x47, 0x29, 0x00, 0x00, 0x00, 0x00, ++ 0x6B, 0x65, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, 0x74, ++ 0x28, 0x54, 0x41, 0x53, 0x4B, 0x5F, 0x53, 0x4D, 0x29, 0x20, 0x3D, 0x3D, ++ 0x20, 0x53, 0x4D, 0x5F, 0x42, 0x53, 0x53, 0x5F, 0x50, 0x41, 0x52, 0x41, ++ 0x4D, 0x5F, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4E, 0x47, 0x00, 0x00, 0x00, ++ 0x6B, 0x65, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, 0x74, ++ 0x28, 0x54, 0x41, 0x53, 0x4B, 0x5F, 0x53, 0x4D, 0x29, 0x20, 0x3D, 0x3D, ++ 0x20, 0x53, 0x4D, 0x5F, 0x44, 0x49, 0x53, 0x43, 0x4F, 0x4E, 0x4E, 0x45, ++ 0x43, 0x54, 0x49, 0x4E, 0x47, 0x00, 0x00, 0x00, 0x28, 0x6B, 0x65, 0x5F, ++ 0x73, 0x74, 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, 0x74, 0x28, 0x54, 0x41, ++ 0x53, 0x4B, 0x5F, 0x53, 0x4D, 0x29, 0x20, 0x3D, 0x3D, 0x20, 0x53, 0x4D, ++ 0x5F, 0x42, 0x53, 0x53, 0x5F, 0x50, 0x41, 0x52, 0x41, 0x4D, 0x5F, 0x53, ++ 0x45, 0x54, 0x54, 0x49, 0x4E, 0x47, 0x29, 0x20, 0x7C, 0x7C, 0x20, 0x28, ++ 0x6B, 0x65, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, 0x74, ++ 0x28, 0x54, 0x41, 0x53, 0x4B, 0x5F, 0x53, 0x4D, 0x29, 0x20, 0x3D, 0x3D, ++ 0x20, 0x53, 0x4D, 0x5F, 0x44, 0x49, 0x53, 0x43, 0x4F, 0x4E, 0x4E, 0x45, ++ 0x43, 0x54, 0x49, 0x4E, 0x47, 0x29, 0x00, 0x00, 0x73, 0x6D, 0x20, 0x63, ++ 0x6F, 0x65, 0x78, 0x20, 0x74, 0x73, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x6F, ++ 0x75, 0x74, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x6B, 0x65, 0x5F, 0x73, ++ 0x74, 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, 0x74, 0x28, 0x54, 0x41, 0x53, ++ 0x4B, 0x5F, 0x53, 0x4D, 0x29, 0x20, 0x3D, 0x3D, 0x20, 0x53, 0x4D, 0x5F, ++ 0x53, 0x54, 0x41, 0x5F, 0x41, 0x44, 0x44, 0x49, 0x4E, 0x47, 0x00, 0x00, ++ 0x98, 0x23, 0x17, 0x00, 0x15, 0x00, 0x00, 0x00, 0x74, 0x78, 0x20, 0x63, ++ 0x66, 0x6D, 0x3A, 0x25, 0x64, 0x2C, 0x25, 0x78, 0x0D, 0x0A, 0x00, 0x00, ++ 0x63, 0x6F, 0x5F, 0x6C, 0x69, 0x73, 0x74, 0x5F, 0x69, 0x73, 0x5F, 0x65, ++ 0x6D, 0x70, 0x74, 0x79, 0x28, 0x26, 0x73, 0x6D, 0x5F, 0x65, 0x6E, 0x76, ++ 0x2E, 0x62, 0x73, 0x73, 0x5F, 0x63, 0x6F, 0x6E, 0x66, 0x69, 0x67, 0x29, ++ 0x00, 0x00, 0x00, 0x00, 0x64, 0x65, 0x6C, 0x65, 0x74, 0x65, 0x20, 0x72, ++ 0x65, 0x6F, 0x75, 0x72, 0x63, 0x65, 0x73, 0x0D, 0x0A, 0x00, 0x00, 0x00, ++ 0x64, 0x65, 0x61, 0x75, 0x74, 0x68, 0x2F, 0x64, 0x69, 0x73, 0x61, 0x73, ++ 0x73, 0x6F, 0x63, 0x3A, 0x25, 0x78, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x64, 0x69, 0x73, 0x63, 0x6F, 0x6E, 0x6E, 0x63, 0x74, 0x3A, 0x25, 0x64, ++ 0x2C, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x63, 0x6F, 0x6E, 0x6E, ++ 0x65, 0x63, 0x74, 0x3A, 0x25, 0x64, 0x2C, 0x25, 0x64, 0x2C, 0x61, 0x69, ++ 0x64, 0x3D, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x61, 0x75, 0x74, 0x68, ++ 0x5F, 0x68, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x72, 0x3A, 0x25, 0x64, 0x0D, ++ 0x0A, 0x00, 0x00, 0x00, 0x61, 0x73, 0x73, 0x6F, 0x63, 0x5F, 0x72, 0x73, ++ 0x70, 0x5F, 0x68, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x72, 0x3A, 0x25, 0x64, ++ 0x0D, 0x0A, 0x00, 0x00, 0x64, 0x65, 0x61, 0x75, 0x74, 0x68, 0x5F, 0x68, ++ 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x72, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, ++ 0x63, 0x6F, 0x6E, 0x6E, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x0D, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x64, 0x65, 0x61, 0x75, 0x74, 0x68, 0x5F, 0x68, ++ 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x72, 0x3A, 0x20, 0x72, 0x65, 0x61, 0x73, ++ 0x6F, 0x6E, 0x20, 0x63, 0x6F, 0x64, 0x65, 0x20, 0x3D, 0x25, 0x64, 0x0D, ++ 0x0A, 0x00, 0x00, 0x00, 0x42, 0x53, 0x53, 0x5F, 0x43, 0x41, 0x50, 0x41, ++ 0x28, 0x62, 0x73, 0x73, 0x2C, 0x20, 0x56, 0x41, 0x4C, 0x49, 0x44, 0x29, ++ 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x08, 0x06, ++ 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x02, 0x73, 0x6D, 0x5F, 0x61, ++ 0x75, 0x74, 0x68, 0x5F, 0x73, 0x65, 0x6E, 0x64, 0x00, 0x00, 0x00, 0x00, ++ 0x73, 0x6D, 0x5F, 0x61, 0x73, 0x73, 0x6F, 0x63, 0x5F, 0x72, 0x65, 0x71, ++ 0x5F, 0x73, 0x65, 0x6E, 0x64, 0x00, 0x00, 0x00, 0x6B, 0x65, 0x5F, 0x73, ++ 0x74, 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, 0x74, 0x28, 0x54, 0x41, 0x53, ++ 0x4B, 0x5F, 0x41, 0x50, 0x4D, 0x29, 0x20, 0x3D, 0x3D, 0x20, 0x41, 0x50, ++ 0x4D, 0x5F, 0x42, 0x43, 0x4E, 0x5F, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4E, ++ 0x47, 0x00, 0x00, 0x00, 0x61, 0x70, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, ++ 0x3A, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x28, 0x6B, 0x65, 0x5F, ++ 0x73, 0x74, 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, 0x74, 0x28, 0x54, 0x41, ++ 0x53, 0x4B, 0x5F, 0x41, 0x50, 0x4D, 0x29, 0x20, 0x3D, 0x3D, 0x20, 0x41, ++ 0x50, 0x4D, 0x5F, 0x42, 0x53, 0x53, 0x5F, 0x50, 0x41, 0x52, 0x41, 0x4D, ++ 0x5F, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4E, 0x47, 0x29, 0x20, 0x7C, 0x7C, ++ 0x20, 0x28, 0x6B, 0x65, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5F, 0x67, ++ 0x65, 0x74, 0x28, 0x54, 0x41, 0x53, 0x4B, 0x5F, 0x41, 0x50, 0x4D, 0x29, ++ 0x20, 0x3D, 0x3D, 0x20, 0x41, 0x50, 0x4D, 0x5F, 0x49, 0x44, 0x4C, 0x45, ++ 0x29, 0x20, 0x7C, 0x7C, 0x20, 0x28, 0x6B, 0x65, 0x5F, 0x73, 0x74, 0x61, ++ 0x74, 0x65, 0x5F, 0x67, 0x65, 0x74, 0x28, 0x54, 0x41, 0x53, 0x4B, 0x5F, ++ 0x41, 0x50, 0x4D, 0x29, 0x20, 0x3D, 0x3D, 0x20, 0x41, 0x50, 0x4D, 0x5F, ++ 0x53, 0x54, 0x4F, 0x50, 0x50, 0x49, 0x4E, 0x47, 0x29, 0x00, 0x00, 0x00, ++ 0x6B, 0x65, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, 0x74, ++ 0x28, 0x54, 0x41, 0x53, 0x4B, 0x5F, 0x41, 0x50, 0x4D, 0x29, 0x20, 0x3D, ++ 0x3D, 0x20, 0x41, 0x50, 0x4D, 0x5F, 0x42, 0x53, 0x53, 0x5F, 0x50, 0x41, ++ 0x52, 0x41, 0x4D, 0x5F, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4E, 0x47, 0x00, ++ 0x6B, 0x65, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, 0x74, ++ 0x28, 0x54, 0x41, 0x53, 0x4B, 0x5F, 0x41, 0x50, 0x4D, 0x29, 0x20, 0x3D, ++ 0x3D, 0x20, 0x41, 0x50, 0x4D, 0x5F, 0x53, 0x54, 0x4F, 0x50, 0x50, 0x49, ++ 0x4E, 0x47, 0x00, 0x00, 0x28, 0x6B, 0x65, 0x5F, 0x73, 0x74, 0x61, 0x74, ++ 0x65, 0x5F, 0x67, 0x65, 0x74, 0x28, 0x54, 0x41, 0x53, 0x4B, 0x5F, 0x41, ++ 0x50, 0x4D, 0x29, 0x20, 0x3D, 0x3D, 0x20, 0x41, 0x50, 0x4D, 0x5F, 0x53, ++ 0x54, 0x4F, 0x50, 0x50, 0x49, 0x4E, 0x47, 0x29, 0x20, 0x7C, 0x7C, 0x20, ++ 0x28, 0x6B, 0x65, 0x5F, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, ++ 0x74, 0x28, 0x54, 0x41, 0x53, 0x4B, 0x5F, 0x41, 0x50, 0x4D, 0x29, 0x20, ++ 0x3D, 0x3D, 0x20, 0x41, 0x50, 0x4D, 0x5F, 0x49, 0x44, 0x4C, 0x45, 0x29, ++ 0x00, 0x00, 0x00, 0x00, 0x61, 0x70, 0x20, 0x73, 0x74, 0x6F, 0x70, 0x0D, ++ 0x0A, 0x00, 0x00, 0x00, 0x63, 0x6F, 0x5F, 0x6C, 0x69, 0x73, 0x74, 0x5F, ++ 0x69, 0x73, 0x5F, 0x65, 0x6D, 0x70, 0x74, 0x79, 0x28, 0x26, 0x61, 0x70, ++ 0x6D, 0x5F, 0x65, 0x6E, 0x76, 0x2E, 0x62, 0x73, 0x73, 0x5F, 0x63, 0x6F, ++ 0x6E, 0x66, 0x69, 0x67, 0x29, 0x00, 0x00, 0x00, 0x40, 0x24, 0x17, 0x00, ++ 0x0D, 0x00, 0x00, 0x00, 0x73, 0x63, 0x61, 0x6E, 0x75, 0x20, 0x63, 0x61, ++ 0x6E, 0x63, 0x65, 0x6C, 0x3A, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, ++ 0x73, 0x63, 0x61, 0x6E, 0x75, 0x20, 0x69, 0x64, 0x6C, 0x65, 0x20, 0x63, ++ 0x61, 0x6E, 0x63, 0x65, 0x6C, 0x20, 0x63, 0x66, 0x6D, 0x0D, 0x0A, 0x00, ++ 0x73, 0x63, 0x61, 0x6E, 0x75, 0x20, 0x73, 0x63, 0x61, 0x6E, 0x6E, 0x69, ++ 0x6E, 0x67, 0x20, 0x76, 0x6E, 0x64, 0x72, 0x20, 0x69, 0x65, 0x0D, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x73, 0x63, 0x61, 0x6E, 0x6E, 0x69, 0x6E, 0x67, ++ 0x20, 0x73, 0x63, 0x61, 0x6E, 0x75, 0x20, 0x72, 0x65, 0x71, 0x3A, 0x25, ++ 0x64, 0x2C, 0x25, 0x64, 0x0A, 0x00, 0x00, 0x00, 0x21, 0x4D, 0x41, 0x43, ++ 0x5F, 0x41, 0x44, 0x44, 0x52, 0x5F, 0x47, 0x52, 0x4F, 0x55, 0x50, 0x28, ++ 0x26, 0x70, 0x61, 0x72, 0x61, 0x6D, 0x2D, 0x3E, 0x62, 0x73, 0x73, 0x69, ++ 0x64, 0x29, 0x00, 0x00, 0x73, 0x63, 0x61, 0x6E, 0x75, 0x20, 0x76, 0x6E, ++ 0x64, 0x72, 0x20, 0x69, 0x65, 0x0D, 0x0A, 0x00, 0x73, 0x63, 0x61, 0x6E, ++ 0x20, 0x63, 0x61, 0x6E, 0x63, 0x65, 0x6C, 0x20, 0x63, 0x66, 0x6D, 0x20, ++ 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x24, 0x17, 0x00, ++ 0x04, 0x00, 0x00, 0x00, 0xC8, 0x24, 0x17, 0x00, 0x05, 0x00, 0x00, 0x00, ++ 0xF0, 0x24, 0x17, 0x00, 0x07, 0x00, 0x00, 0x00, 0x73, 0x63, 0x61, 0x6E, ++ 0x75, 0x5F, 0x63, 0x6F, 0x6E, 0x66, 0x69, 0x72, 0x6D, 0x3A, 0x25, 0x64, ++ 0x2C, 0x25, 0x64, 0x2C, 0x25, 0x64, 0x0A, 0x00, 0x5B, 0x48, 0x49, 0x44, ++ 0x44, 0x45, 0x4E, 0x5D, 0x00, 0x00, 0x00, 0x00, 0x44, 0x49, 0x52, 0x45, ++ 0x43, 0x54, 0x2D, 0x00, 0x6A, 0x6F, 0x69, 0x6E, 0x3A, 0x25, 0x73, 0x2C, ++ 0x25, 0x64, 0x0A, 0x00, 0x66, 0x69, 0x78, 0x3D, 0x25, 0x78, 0x2C, 0x20, ++ 0x6E, 0x6F, 0x5F, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6C, 0x65, 0x3D, ++ 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x20, 0x25, 0x64, 0x20, ++ 0x25, 0x64, 0x20, 0x30, 0x78, 0x25, 0x78, 0x20, 0x25, 0x64, 0x20, 0x25, ++ 0x78, 0x20, 0x25, 0x73, 0x0A, 0x00, 0x00, 0x00, 0x28, 0x69, 0x65, 0x5F, ++ 0x62, 0x75, 0x66, 0x20, 0x2D, 0x20, 0x43, 0x50, 0x55, 0x32, 0x48, 0x57, ++ 0x28, 0x69, 0x65, 0x2D, 0x3E, 0x62, 0x75, 0x66, 0x29, 0x29, 0x20, 0x3C, ++ 0x3D, 0x20, 0x53, 0x43, 0x41, 0x4E, 0x5F, 0x4D, 0x41, 0x58, 0x5F, 0x49, ++ 0x45, 0x5F, 0x4C, 0x45, 0x4E, 0x00, 0x00, 0x00, 0x73, 0x63, 0x61, 0x6E, ++ 0x75, 0x5F, 0x73, 0x74, 0x61, 0x72, 0x74, 0x3A, 0x25, 0x64, 0x2C, 0x25, ++ 0x64, 0x2C, 0x25, 0x64, 0x2C, 0x25, 0x64, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x72, 0x78, 0x20, 0x61, 0x72, 0x70, 0x72, 0x65, 0x71, 0x3A, 0x20, 0x69, ++ 0x70, 0x3D, 0x25, 0x78, 0x2E, 0x20, 0x76, 0x69, 0x66, 0x20, 0x69, 0x70, ++ 0x3D, 0x25, 0x78, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x72, 0x78, 0x20, 0x61, ++ 0x72, 0x70, 0x72, 0x65, 0x73, 0x70, 0x0A, 0x00, 0x72, 0x78, 0x5F, 0x73, ++ 0x74, 0x61, 0x74, 0x5F, 0x64, 0x65, 0x73, 0x63, 0x2D, 0x3E, 0x76, 0x61, ++ 0x6C, 0x2E, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x3D, 0x3D, 0x20, ++ 0x30, 0x00, 0x00, 0x00, 0x75, 0x6E, 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x73, ++ 0x74, 0x61, 0x74, 0x3A, 0x25, 0x64, 0x00, 0x00, 0x54, 0x4B, 0x49, 0x50, ++ 0x20, 0x49, 0x43, 0x56, 0x20, 0x45, 0x52, 0x52, 0x0A, 0x00, 0x00, 0x00, ++ 0x64, 0x65, 0x66, 0x72, 0x61, 0x67, 0x20, 0x21, 0x3D, 0x20, 0x4E, 0x55, ++ 0x4C, 0x4C, 0x00, 0x00, 0x72, 0x78, 0x5F, 0x72, 0x65, 0x6F, 0x72, 0x64, ++ 0x2D, 0x3E, 0x6F, 0x6F, 0x6F, 0x5F, 0x70, 0x6B, 0x74, 0x5F, 0x63, 0x6E, ++ 0x74, 0x00, 0x00, 0x00, 0x6F, 0x6C, 0x64, 0x5F, 0x77, 0x69, 0x6E, 0x5F, ++ 0x62, 0x61, 0x72, 0x20, 0x64, 0x65, 0x74, 0x0D, 0x0A, 0x00, 0x00, 0x00, ++ 0x72, 0x65, 0x6F, 0x72, 0x64, 0x2D, 0x3E, 0x6F, 0x6F, 0x6F, 0x5F, 0x70, ++ 0x6B, 0x74, 0x5F, 0x63, 0x6E, 0x74, 0x3C, 0x3D, 0x36, 0x34, 0x00, 0x00, ++ 0x25, 0x73, 0x3A, 0x20, 0x73, 0x65, 0x6E, 0x64, 0x5F, 0x64, 0x65, 0x61, ++ 0x75, 0x74, 0x68, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x74, 0x61, 0x73, 0x6B, ++ 0x5F, 0x69, 0x64, 0x78, 0x20, 0x21, 0x3D, 0x20, 0x30, 0x78, 0x46, 0x46, ++ 0x00, 0x00, 0x00, 0x00, 0x28, 0x6D, 0x61, 0x63, 0x68, 0x64, 0x72, 0x5F, ++ 0x6C, 0x65, 0x6E, 0x67, 0x74, 0x68, 0x20, 0x26, 0x20, 0x30, 0x78, 0x33, ++ 0x29, 0x20, 0x3D, 0x3D, 0x20, 0x30, 0x00, 0x00, 0x72, 0x78, 0x20, 0x65, ++ 0x61, 0x70, 0x6F, 0x6C, 0x3A, 0x25, 0x78, 0x2C, 0x25, 0x64, 0x0D, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x57, 0x45, 0x50, 0x20, 0x49, 0x43, 0x56, 0x20, ++ 0x45, 0x52, 0x52, 0x20, 0x25, 0x78, 0x0A, 0x00, 0x72, 0x65, 0x6F, 0x72, ++ 0x64, 0x20, 0x21, 0x3D, 0x20, 0x4E, 0x55, 0x4C, 0x4C, 0x00, 0x00, 0x00, ++ 0x72, 0x78, 0x75, 0x5F, 0x63, 0x6E, 0x74, 0x72, 0x6C, 0x5F, 0x73, 0x70, ++ 0x75, 0x72, 0x69, 0x6F, 0x75, 0x73, 0x5F, 0x63, 0x68, 0x65, 0x63, 0x6B, ++ 0x00, 0x00, 0x00, 0x00, 0x74, 0x78, 0x75, 0x20, 0x64, 0x69, 0x73, 0x63, ++ 0x61, 0x72, 0x64, 0x3A, 0x20, 0x25, 0x64, 0x2C, 0x20, 0x25, 0x78, 0x2C, ++ 0x20, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x72, 0x65, 0x74, 0x72, ++ 0x61, 0x6E, 0x73, 0x6D, 0x69, 0x74, 0x20, 0x74, 0x78, 0x75, 0x20, 0x64, ++ 0x69, 0x73, 0x63, 0x61, 0x72, 0x64, 0x0A, 0x00, 0x70, 0x6F, 0x72, 0x74, ++ 0x20, 0x66, 0x69, 0x6C, 0x74, 0x65, 0x72, 0x3A, 0x25, 0x64, 0x0D, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x68, 0x6F, 0x73, 0x74, 0x2D, 0x3E, 0x73, 0x74, ++ 0x61, 0x69, 0x64, 0x20, 0x21, 0x3D, 0x20, 0x49, 0x4E, 0x56, 0x41, 0x4C, ++ 0x49, 0x44, 0x5F, 0x53, 0x54, 0x41, 0x5F, 0x49, 0x44, 0x58, 0x00, 0x00, ++ 0x68, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x20, 0x61, 0x64, 0x64, 0x62, 0x61, ++ 0x5F, 0x72, 0x65, 0x71, 0x3A, 0x74, 0x69, 0x64, 0x3D, 0x25, 0x64, 0x0D, ++ 0x0A, 0x00, 0x00, 0x00, 0x68, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x20, 0x61, ++ 0x64, 0x64, 0x62, 0x61, 0x5F, 0x72, 0x73, 0x70, 0x3A, 0x74, 0x69, 0x64, ++ 0x3D, 0x25, 0x64, 0x2C, 0x20, 0x69, 0x64, 0x78, 0x3D, 0x25, 0x64, 0x0D, ++ 0x0A, 0x00, 0x00, 0x00, 0x68, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x20, 0x72, ++ 0x78, 0x5F, 0x64, 0x65, 0x6C, 0x62, 0x61, 0x3A, 0x74, 0x69, 0x64, 0x3D, ++ 0x25, 0x64, 0x2C, 0x20, 0x73, 0x74, 0x61, 0x69, 0x64, 0x78, 0x3D, 0x25, ++ 0x64, 0x0D, 0x0A, 0x00, 0x68, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x20, 0x74, ++ 0x78, 0x5F, 0x64, 0x65, 0x6C, 0x62, 0x61, 0x3A, 0x74, 0x69, 0x64, 0x3D, ++ 0x25, 0x64, 0x2C, 0x20, 0x73, 0x74, 0x61, 0x69, 0x64, 0x78, 0x3D, 0x25, ++ 0x64, 0x0D, 0x0A, 0x00, 0x2C, 0x25, 0x17, 0x00, 0x05, 0x00, 0x00, 0x00, ++ 0x6D, 0x6F, 0x76, 0x65, 0x20, 0x77, 0x69, 0x6E, 0x20, 0x73, 0x69, 0x6E, ++ 0x63, 0x65, 0x20, 0x66, 0x6C, 0x75, 0x73, 0x68, 0x3A, 0x20, 0x73, 0x75, ++ 0x63, 0x63, 0x3D, 0x25, 0x64, 0x2C, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x70, ++ 0x61, 0x73, 0x74, 0x3D, 0x25, 0x64, 0x0A, 0x00, 0x6B, 0x65, 0x5F, 0x73, ++ 0x74, 0x61, 0x74, 0x65, 0x5F, 0x67, 0x65, 0x74, 0x28, 0x4B, 0x45, 0x5F, ++ 0x42, 0x55, 0x49, 0x4C, 0x44, 0x5F, 0x49, 0x44, 0x28, 0x54, 0x41, 0x53, ++ 0x4B, 0x5F, 0x42, 0x41, 0x4D, 0x2C, 0x20, 0x62, 0x61, 0x6D, 0x5F, 0x69, ++ 0x64, 0x78, 0x29, 0x29, 0x20, 0x3D, 0x3D, 0x20, 0x42, 0x41, 0x4D, 0x5F, ++ 0x44, 0x45, 0x4C, 0x45, 0x54, 0x45, 0x00, 0x00, 0x62, 0x61, 0x6D, 0x5F, ++ 0x69, 0x64, 0x78, 0x20, 0x3C, 0x20, 0x42, 0x41, 0x4D, 0x5F, 0x49, 0x4E, ++ 0x56, 0x41, 0x4C, 0x49, 0x44, 0x5F, 0x54, 0x41, 0x53, 0x4B, 0x5F, 0x49, ++ 0x44, 0x58, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, ++ 0x1B, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x63, 0x7C, 0x77, 0x7B, ++ 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, ++ 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, ++ 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, ++ 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7, 0x23, 0xC3, ++ 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, ++ 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, ++ 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, ++ 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB, ++ 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, ++ 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, ++ 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, ++ 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, ++ 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, ++ 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, ++ 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, ++ 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, ++ 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, ++ 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, ++ 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, ++ 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 0x8C, 0xA1, 0x89, 0x0D, ++ 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16, ++ 0xC6, 0xF8, 0xEE, 0xF6, 0xFF, 0xD6, 0xDE, 0x91, 0x60, 0x02, 0xCE, 0x56, ++ 0xE7, 0xB5, 0x4D, 0xEC, 0x8F, 0x1F, 0x89, 0xFA, 0xEF, 0xB2, 0x8E, 0xFB, ++ 0x41, 0xB3, 0x5F, 0x45, 0x23, 0x53, 0xE4, 0x9B, 0x75, 0xE1, 0x3D, 0x4C, ++ 0x6C, 0x7E, 0xF5, 0x83, 0x68, 0x51, 0xD1, 0xF9, 0xE2, 0xAB, 0x62, 0x2A, ++ 0x08, 0x95, 0x46, 0x9D, 0x30, 0x37, 0x0A, 0x2F, 0x0E, 0x24, 0x1B, 0xDF, ++ 0xCD, 0x4E, 0x7F, 0xEA, 0x12, 0x1D, 0x58, 0x34, 0x36, 0xDC, 0xB4, 0x5B, ++ 0xA4, 0x76, 0xB7, 0x7D, 0x52, 0xDD, 0x5E, 0x13, 0xA6, 0xB9, 0x00, 0xC1, ++ 0x40, 0xE3, 0x79, 0xB6, 0xD4, 0x8D, 0x67, 0x72, 0x94, 0x98, 0xB0, 0x85, ++ 0xBB, 0xC5, 0x4F, 0xED, 0x86, 0x9A, 0x66, 0x11, 0x8A, 0xE9, 0x04, 0xFE, ++ 0xA0, 0x78, 0x25, 0x4B, 0xA2, 0x5D, 0x80, 0x05, 0x3F, 0x21, 0x70, 0xF1, ++ 0x63, 0x77, 0xAF, 0x42, 0x20, 0xE5, 0xFD, 0xBF, 0x81, 0x18, 0x26, 0xC3, ++ 0xBE, 0x35, 0x88, 0x2E, 0x93, 0x55, 0xFC, 0x7A, 0xC8, 0xBA, 0x32, 0xE6, ++ 0xC0, 0x19, 0x9E, 0xA3, 0x44, 0x54, 0x3B, 0x0B, 0x8C, 0xC7, 0x6B, 0x28, ++ 0xA7, 0xBC, 0x16, 0xAD, 0xDB, 0x64, 0x74, 0x14, 0x92, 0x0C, 0x48, 0xB8, ++ 0x9F, 0xBD, 0x43, 0xC4, 0x39, 0x31, 0xD3, 0xF2, 0xD5, 0x8B, 0x6E, 0xDA, ++ 0x01, 0xB1, 0x9C, 0x49, 0xD8, 0xAC, 0xF3, 0xCF, 0xCA, 0xF4, 0x47, 0x10, ++ 0x6F, 0xF0, 0x4A, 0x5C, 0x38, 0x57, 0x73, 0x97, 0xCB, 0xA1, 0xE8, 0x3E, ++ 0x96, 0x61, 0x0D, 0x0F, 0xE0, 0x7C, 0x71, 0xCC, 0x90, 0x06, 0xF7, 0x1C, ++ 0xC2, 0x6A, 0xAE, 0x69, 0x17, 0x99, 0x3A, 0x27, 0xD9, 0xEB, 0x2B, 0x22, ++ 0xD2, 0xA9, 0x07, 0x33, 0x2D, 0x3C, 0x15, 0xC9, 0x87, 0xAA, 0x50, 0xA5, ++ 0x03, 0x59, 0x09, 0x1A, 0x65, 0xD7, 0x84, 0xD0, 0x82, 0x29, 0x5A, 0x1E, ++ 0x7B, 0xA8, 0x6D, 0x2C, 0xA5, 0x84, 0x99, 0x8D, 0x0D, 0xBD, 0xB1, 0x54, ++ 0x50, 0x03, 0xA9, 0x7D, 0x19, 0x62, 0xE6, 0x9A, 0x45, 0x9D, 0x40, 0x87, ++ 0x15, 0xEB, 0xC9, 0x0B, 0xEC, 0x67, 0xFD, 0xEA, 0xBF, 0xF7, 0x96, 0x5B, ++ 0xC2, 0x1C, 0xAE, 0x6A, 0x5A, 0x41, 0x02, 0x4F, 0x5C, 0xF4, 0x34, 0x08, ++ 0x93, 0x73, 0x53, 0x3F, 0x0C, 0x52, 0x65, 0x5E, 0x28, 0xA1, 0x0F, 0xB5, ++ 0x09, 0x36, 0x9B, 0x3D, 0x26, 0x69, 0xCD, 0x9F, 0x1B, 0x9E, 0x74, 0x2E, ++ 0x2D, 0xB2, 0xEE, 0xFB, 0xF6, 0x4D, 0x61, 0xCE, 0x7B, 0x3E, 0x71, 0x97, ++ 0xF5, 0x68, 0x00, 0x2C, 0x60, 0x1F, 0xC8, 0xED, 0xBE, 0x46, 0xD9, 0x4B, ++ 0xDE, 0xD4, 0xE8, 0x4A, 0x6B, 0x2A, 0xE5, 0x16, 0xC5, 0xD7, 0x55, 0x94, ++ 0xCF, 0x10, 0x06, 0x81, 0xF0, 0x44, 0xBA, 0xE3, 0xF3, 0xFE, 0xC0, 0x8A, ++ 0xAD, 0xBC, 0x48, 0x04, 0xDF, 0xC1, 0x75, 0x63, 0x30, 0x1A, 0x0E, 0x6D, ++ 0x4C, 0x14, 0x35, 0x2F, 0xE1, 0xA2, 0xCC, 0x39, 0x57, 0xF2, 0x82, 0x47, ++ 0xAC, 0xE7, 0x2B, 0x95, 0xA0, 0x98, 0xD1, 0x7F, 0x66, 0x7E, 0xAB, 0x83, ++ 0xCA, 0x29, 0xD3, 0x3C, 0x79, 0xE2, 0x1D, 0x76, 0x3B, 0x56, 0x4E, 0x1E, ++ 0xDB, 0x0A, 0x6C, 0xE4, 0x5D, 0x6E, 0xEF, 0xA6, 0xA8, 0xA4, 0x37, 0x8B, ++ 0x32, 0x43, 0x59, 0xB7, 0x8C, 0x64, 0xD2, 0xE0, 0xB4, 0xFA, 0x07, 0x25, ++ 0xAF, 0x8E, 0xE9, 0x18, 0xD5, 0x88, 0x6F, 0x72, 0x24, 0xF1, 0xC7, 0x51, ++ 0x23, 0x7C, 0x9C, 0x21, 0xDD, 0xDC, 0x86, 0x85, 0x90, 0x42, 0xC4, 0xAA, ++ 0xD8, 0x05, 0x01, 0x12, 0xA3, 0x5F, 0xF9, 0xD0, 0x91, 0x58, 0x27, 0xB9, ++ 0x38, 0x13, 0xB3, 0x33, 0xBB, 0x70, 0x89, 0xA7, 0xB6, 0x22, 0x92, 0x20, ++ 0x49, 0xFF, 0x78, 0x7A, 0x8F, 0xF8, 0x80, 0x17, 0xDA, 0x31, 0xC6, 0xB8, ++ 0xC3, 0xB0, 0x77, 0x11, 0xCB, 0xFC, 0xD6, 0x3A, 0x72, 0x63, 0x5F, 0x72, ++ 0x73, 0x2D, 0x3E, 0x61, 0x74, 0x74, 0x65, 0x6D, 0x70, 0x74, 0x73, 0x20, ++ 0x3E, 0x3D, 0x20, 0x72, 0x63, 0x5F, 0x72, 0x73, 0x2D, 0x3E, 0x73, 0x75, ++ 0x63, 0x63, 0x65, 0x73, 0x73, 0x00, 0x00, 0x00, 0x66, 0x6F, 0x72, 0x6D, ++ 0x61, 0x74, 0x5F, 0x6D, 0x6F, 0x64, 0x20, 0x3C, 0x3D, 0x20, 0x46, 0x4F, ++ 0x52, 0x4D, 0x41, 0x54, 0x4D, 0x4F, 0x44, 0x5F, 0x48, 0x45, 0x5F, 0x53, ++ 0x55, 0x00, 0x00, 0x00, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x5F, 0x6D, ++ 0x6F, 0x64, 0x20, 0x3C, 0x20, 0x46, 0x4F, 0x52, 0x4D, 0x41, 0x54, 0x4D, ++ 0x4F, 0x44, 0x5F, 0x48, 0x54, 0x5F, 0x4D, 0x46, 0x00, 0x00, 0x00, 0x00, ++ 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x5F, 0x6D, 0x6F, 0x64, 0x20, 0x3C, ++ 0x20, 0x46, 0x4F, 0x52, 0x4D, 0x41, 0x54, 0x4D, 0x4F, 0x44, 0x5F, 0x56, ++ 0x48, 0x54, 0x00, 0x00, 0x28, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x5F, ++ 0x6D, 0x6F, 0x64, 0x20, 0x3D, 0x3D, 0x20, 0x46, 0x4F, 0x52, 0x4D, 0x41, ++ 0x54, 0x4D, 0x4F, 0x44, 0x5F, 0x48, 0x54, 0x5F, 0x4D, 0x46, 0x29, 0x20, ++ 0x7C, 0x7C, 0x20, 0x28, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x5F, 0x6D, ++ 0x6F, 0x64, 0x20, 0x3D, 0x3D, 0x20, 0x46, 0x4F, 0x52, 0x4D, 0x41, 0x54, ++ 0x4D, 0x4F, 0x44, 0x5F, 0x48, 0x54, 0x5F, 0x47, 0x46, 0x29, 0x00, 0x00, ++ 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x5F, 0x6D, 0x6F, 0x64, 0x20, 0x3D, ++ 0x3D, 0x20, 0x46, 0x4F, 0x52, 0x4D, 0x41, 0x54, 0x4D, 0x4F, 0x44, 0x5F, ++ 0x56, 0x48, 0x54, 0x20, 0x7C, 0x7C, 0x20, 0x66, 0x6F, 0x72, 0x6D, 0x61, ++ 0x74, 0x5F, 0x6D, 0x6F, 0x64, 0x20, 0x3D, 0x3D, 0x20, 0x46, 0x4F, 0x52, ++ 0x4D, 0x41, 0x54, 0x4D, 0x4F, 0x44, 0x5F, 0x4E, 0x4F, 0x4E, 0x5F, 0x48, ++ 0x54, 0x00, 0x00, 0x00, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x5F, 0x6D, ++ 0x6F, 0x64, 0x20, 0x3D, 0x3D, 0x20, 0x46, 0x4F, 0x52, 0x4D, 0x41, 0x54, ++ 0x4D, 0x4F, 0x44, 0x5F, 0x56, 0x48, 0x54, 0x00, 0x28, 0x66, 0x6F, 0x72, ++ 0x6D, 0x61, 0x74, 0x5F, 0x6D, 0x6F, 0x64, 0x20, 0x3D, 0x3D, 0x20, 0x46, ++ 0x4F, 0x52, 0x4D, 0x41, 0x54, 0x4D, 0x4F, 0x44, 0x5F, 0x48, 0x45, 0x5F, ++ 0x53, 0x55, 0x29, 0x20, 0x7C, 0x7C, 0x20, 0x28, 0x66, 0x6F, 0x72, 0x6D, ++ 0x61, 0x74, 0x5F, 0x6D, 0x6F, 0x64, 0x20, 0x3D, 0x3D, 0x20, 0x46, 0x4F, ++ 0x52, 0x4D, 0x41, 0x54, 0x4D, 0x4F, 0x44, 0x5F, 0x4E, 0x4F, 0x4E, 0x5F, ++ 0x48, 0x54, 0x29, 0x00, 0x70, 0x72, 0x65, 0x5F, 0x74, 0x79, 0x70, 0x65, ++ 0x20, 0x3D, 0x3D, 0x20, 0x31, 0x00, 0x00, 0x00, 0x73, 0x67, 0x69, 0x20, ++ 0x3D, 0x3D, 0x20, 0x30, 0x00, 0x00, 0x00, 0x00, 0x62, 0x77, 0x20, 0x3D, ++ 0x3D, 0x20, 0x42, 0x57, 0x5F, 0x32, 0x30, 0x4D, 0x48, 0x5A, 0x00, 0x00, ++ 0x6E, 0x73, 0x73, 0x20, 0x3D, 0x3D, 0x20, 0x30, 0x00, 0x00, 0x00, 0x00, ++ 0x6D, 0x63, 0x73, 0x20, 0x3E, 0x3D, 0x20, 0x72, 0x63, 0x5F, 0x73, 0x73, ++ 0x2D, 0x3E, 0x72, 0x5F, 0x69, 0x64, 0x78, 0x5F, 0x6D, 0x69, 0x6E, 0x00, ++ 0x6D, 0x63, 0x73, 0x20, 0x3C, 0x3D, 0x20, 0x72, 0x63, 0x5F, 0x73, 0x73, ++ 0x2D, 0x3E, 0x72, 0x5F, 0x69, 0x64, 0x78, 0x5F, 0x6D, 0x61, 0x78, 0x00, ++ 0x28, 0x72, 0x63, 0x5F, 0x73, 0x73, 0x2D, 0x3E, 0x72, 0x61, 0x74, 0x65, ++ 0x5F, 0x6D, 0x61, 0x70, 0x5F, 0x6C, 0x20, 0x26, 0x20, 0x43, 0x4F, 0x5F, ++ 0x42, 0x49, 0x54, 0x28, 0x6D, 0x63, 0x73, 0x29, 0x29, 0x00, 0x00, 0x00, ++ 0x70, 0x72, 0x65, 0x5F, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3D, 0x3D, 0x20, ++ 0x30, 0x00, 0x00, 0x00, 0x73, 0x67, 0x69, 0x20, 0x3C, 0x3D, 0x20, 0x72, ++ 0x63, 0x5F, 0x73, 0x73, 0x2D, 0x3E, 0x73, 0x68, 0x6F, 0x72, 0x74, 0x5F, ++ 0x67, 0x69, 0x00, 0x00, 0x62, 0x77, 0x20, 0x3C, 0x3D, 0x20, 0x72, 0x63, ++ 0x5F, 0x73, 0x73, 0x2D, 0x3E, 0x62, 0x77, 0x5F, 0x6D, 0x61, 0x78, 0x00, ++ 0x6E, 0x73, 0x73, 0x20, 0x3C, 0x3D, 0x20, 0x72, 0x63, 0x5F, 0x73, 0x73, ++ 0x2D, 0x3E, 0x6E, 0x6F, 0x5F, 0x73, 0x73, 0x00, 0x6D, 0x63, 0x73, 0x20, ++ 0x3C, 0x3D, 0x20, 0x72, 0x63, 0x5F, 0x73, 0x73, 0x2D, 0x3E, 0x6D, 0x63, ++ 0x73, 0x5F, 0x6D, 0x61, 0x78, 0x00, 0x00, 0x00, 0x28, 0x72, 0x63, 0x5F, ++ 0x73, 0x73, 0x2D, 0x3E, 0x72, 0x61, 0x74, 0x65, 0x5F, 0x6D, 0x61, 0x70, ++ 0x2E, 0x68, 0x74, 0x5B, 0x6E, 0x73, 0x73, 0x5D, 0x20, 0x26, 0x20, 0x43, ++ 0x4F, 0x5F, 0x42, 0x49, 0x54, 0x28, 0x6D, 0x63, 0x73, 0x29, 0x29, 0x00, ++ 0x6D, 0x63, 0x73, 0x20, 0x3C, 0x3D, 0x20, 0x28, 0x37, 0x20, 0x2B, 0x20, ++ 0x28, 0x72, 0x63, 0x5F, 0x73, 0x73, 0x2D, 0x3E, 0x72, 0x61, 0x74, 0x65, ++ 0x5F, 0x6D, 0x61, 0x70, 0x2E, 0x76, 0x68, 0x74, 0x20, 0x3E, 0x3E, 0x20, ++ 0x28, 0x6E, 0x73, 0x73, 0x20, 0x3C, 0x3C, 0x20, 0x31, 0x29, 0x20, 0x26, ++ 0x20, 0x4D, 0x41, 0x43, 0x5F, 0x56, 0x48, 0x54, 0x5F, 0x4D, 0x43, 0x53, ++ 0x5F, 0x4D, 0x41, 0x50, 0x5F, 0x4D, 0x53, 0x4B, 0x29, 0x29, 0x00, 0x00, ++ 0x28, 0x28, 0x6D, 0x63, 0x73, 0x20, 0x3D, 0x3D, 0x20, 0x36, 0x29, 0x20, ++ 0x26, 0x26, 0x20, 0x28, 0x62, 0x77, 0x20, 0x3D, 0x3D, 0x20, 0x42, 0x57, ++ 0x5F, 0x38, 0x30, 0x4D, 0x48, 0x5A, 0x29, 0x20, 0x26, 0x26, 0x20, 0x28, ++ 0x28, 0x6E, 0x73, 0x73, 0x20, 0x3D, 0x3D, 0x20, 0x33, 0x29, 0x20, 0x7C, ++ 0x7C, 0x20, 0x28, 0x6E, 0x73, 0x73, 0x20, 0x3D, 0x3D, 0x20, 0x36, 0x29, ++ 0x29, 0x29, 0x20, 0x3D, 0x3D, 0x20, 0x30, 0x00, 0x28, 0x28, 0x6D, 0x63, ++ 0x73, 0x20, 0x3D, 0x3D, 0x20, 0x39, 0x29, 0x20, 0x26, 0x26, 0x20, 0x28, ++ 0x62, 0x77, 0x20, 0x3D, 0x3D, 0x20, 0x42, 0x57, 0x5F, 0x32, 0x30, 0x4D, ++ 0x48, 0x5A, 0x29, 0x20, 0x26, 0x26, 0x20, 0x28, 0x6E, 0x73, 0x73, 0x20, ++ 0x21, 0x3D, 0x20, 0x32, 0x29, 0x20, 0x26, 0x26, 0x20, 0x28, 0x6E, 0x73, ++ 0x73, 0x20, 0x21, 0x3D, 0x20, 0x35, 0x29, 0x29, 0x20, 0x3D, 0x3D, 0x20, ++ 0x30, 0x00, 0x00, 0x00, 0x28, 0x28, 0x6D, 0x63, 0x73, 0x20, 0x3D, 0x3D, ++ 0x20, 0x39, 0x29, 0x20, 0x26, 0x26, 0x20, 0x28, 0x62, 0x77, 0x20, 0x3D, ++ 0x3D, 0x20, 0x42, 0x57, 0x5F, 0x38, 0x30, 0x4D, 0x48, 0x5A, 0x29, 0x20, ++ 0x26, 0x26, 0x20, 0x28, 0x6E, 0x73, 0x73, 0x20, 0x3D, 0x3D, 0x20, 0x35, ++ 0x29, 0x29, 0x20, 0x3D, 0x3D, 0x20, 0x30, 0x00, 0x28, 0x28, 0x6D, 0x63, ++ 0x73, 0x20, 0x3D, 0x3D, 0x20, 0x39, 0x29, 0x20, 0x26, 0x26, 0x20, 0x28, ++ 0x62, 0x77, 0x20, 0x3D, 0x3D, 0x20, 0x42, 0x57, 0x5F, 0x31, 0x36, 0x30, ++ 0x4D, 0x48, 0x5A, 0x29, 0x20, 0x26, 0x26, 0x20, 0x28, 0x6E, 0x73, 0x73, ++ 0x20, 0x3D, 0x3D, 0x20, 0x32, 0x29, 0x29, 0x20, 0x3D, 0x3D, 0x20, 0x30, ++ 0x00, 0x00, 0x00, 0x00, 0x67, 0x69, 0x20, 0x3C, 0x3D, 0x20, 0x32, 0x00, ++ 0x6D, 0x63, 0x73, 0x20, 0x3C, 0x3D, 0x20, 0x28, 0x37, 0x20, 0x2B, 0x20, ++ 0x32, 0x20, 0x2A, 0x20, 0x28, 0x72, 0x63, 0x5F, 0x73, 0x73, 0x2D, 0x3E, ++ 0x72, 0x61, 0x74, 0x65, 0x5F, 0x6D, 0x61, 0x70, 0x2E, 0x68, 0x65, 0x20, ++ 0x3E, 0x3E, 0x20, 0x28, 0x6E, 0x73, 0x73, 0x20, 0x3C, 0x3C, 0x20, 0x31, ++ 0x29, 0x20, 0x26, 0x20, 0x4D, 0x41, 0x43, 0x5F, 0x48, 0x45, 0x5F, 0x4D, ++ 0x43, 0x53, 0x5F, 0x4D, 0x41, 0x50, 0x5F, 0x4D, 0x53, 0x4B, 0x29, 0x29, ++ 0x00, 0x00, 0x00, 0x00, 0x72, 0x63, 0x5F, 0x73, 0x73, 0x2D, 0x3E, 0x6E, ++ 0x6F, 0x5F, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x73, 0x20, 0x3E, 0x3D, ++ 0x20, 0x31, 0x00, 0x00, 0x72, 0x63, 0x5F, 0x73, 0x73, 0x2D, 0x3E, 0x6E, ++ 0x6F, 0x5F, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x73, 0x20, 0x3C, 0x3D, ++ 0x20, 0x52, 0x43, 0x5F, 0x4D, 0x41, 0x58, 0x5F, 0x4E, 0x5F, 0x53, 0x41, ++ 0x4D, 0x50, 0x4C, 0x45, 0x00, 0x00, 0x00, 0x00, 0x72, 0x63, 0x5F, 0x73, ++ 0x73, 0x2D, 0x3E, 0x62, 0x77, 0x5F, 0x6D, 0x61, 0x78, 0x20, 0x3C, 0x3D, ++ 0x20, 0x42, 0x57, 0x5F, 0x31, 0x36, 0x30, 0x4D, 0x48, 0x5A, 0x00, 0x00, ++ 0x72, 0x63, 0x5F, 0x73, 0x73, 0x2D, 0x3E, 0x6E, 0x6F, 0x5F, 0x73, 0x73, ++ 0x20, 0x3C, 0x20, 0x38, 0x00, 0x00, 0x00, 0x00, 0x73, 0x74, 0x61, 0x2D, ++ 0x3E, 0x73, 0x74, 0x61, 0x69, 0x64, 0x20, 0x3C, 0x20, 0x4E, 0x58, 0x5F, ++ 0x52, 0x45, 0x4D, 0x4F, 0x54, 0x45, 0x5F, 0x53, 0x54, 0x41, 0x5F, 0x4D, ++ 0x41, 0x58, 0x00, 0x00, 0x72, 0x63, 0x5F, 0x73, 0x73, 0x2D, 0x3E, 0x6D, ++ 0x63, 0x73, 0x5F, 0x6D, 0x61, 0x78, 0x20, 0x3C, 0x20, 0x31, 0x32, 0x00, ++ 0x28, 0x72, 0x63, 0x5F, 0x73, 0x73, 0x2D, 0x3E, 0x72, 0x5F, 0x69, 0x64, ++ 0x78, 0x5F, 0x6D, 0x69, 0x6E, 0x20, 0x3C, 0x3D, 0x20, 0x48, 0x57, 0x5F, ++ 0x52, 0x41, 0x54, 0x45, 0x5F, 0x31, 0x31, 0x4D, 0x42, 0x50, 0x53, 0x29, ++ 0x20, 0x7C, 0x7C, 0x20, 0x28, 0x72, 0x63, 0x5F, 0x73, 0x73, 0x2D, 0x3E, ++ 0x72, 0x5F, 0x69, 0x64, 0x78, 0x5F, 0x6D, 0x69, 0x6E, 0x20, 0x3D, 0x3D, ++ 0x20, 0x4D, 0x41, 0x43, 0x5F, 0x52, 0x41, 0x54, 0x45, 0x53, 0x45, 0x54, ++ 0x5F, 0x4C, 0x45, 0x4E, 0x29, 0x00, 0x00, 0x00, 0x28, 0x72, 0x63, 0x5F, ++ 0x73, 0x73, 0x2D, 0x3E, 0x72, 0x5F, 0x69, 0x64, 0x78, 0x5F, 0x6D, 0x61, ++ 0x78, 0x20, 0x3C, 0x3D, 0x20, 0x48, 0x57, 0x5F, 0x52, 0x41, 0x54, 0x45, ++ 0x5F, 0x31, 0x31, 0x4D, 0x42, 0x50, 0x53, 0x29, 0x20, 0x7C, 0x7C, 0x20, ++ 0x28, 0x72, 0x63, 0x5F, 0x73, 0x73, 0x2D, 0x3E, 0x72, 0x5F, 0x69, 0x64, ++ 0x78, 0x5F, 0x6D, 0x61, 0x78, 0x20, 0x3D, 0x3D, 0x20, 0x4D, 0x41, 0x43, ++ 0x5F, 0x52, 0x41, 0x54, 0x45, 0x53, 0x45, 0x54, 0x5F, 0x4C, 0x45, 0x4E, ++ 0x29, 0x00, 0x00, 0x00, 0x72, 0x63, 0x5F, 0x73, 0x73, 0x2D, 0x3E, 0x6D, ++ 0x63, 0x73, 0x5F, 0x6D, 0x61, 0x78, 0x20, 0x3C, 0x20, 0x31, 0x30, 0x00, ++ 0x72, 0x63, 0x5F, 0x73, 0x73, 0x2D, 0x3E, 0x6E, 0x6F, 0x5F, 0x73, 0x73, ++ 0x20, 0x3C, 0x3D, 0x20, 0x33, 0x00, 0x00, 0x00, 0x72, 0x63, 0x5F, 0x73, ++ 0x73, 0x2D, 0x3E, 0x72, 0x5F, 0x69, 0x64, 0x78, 0x5F, 0x6D, 0x69, 0x6E, ++ 0x20, 0x3C, 0x20, 0x4D, 0x41, 0x43, 0x5F, 0x52, 0x41, 0x54, 0x45, 0x53, ++ 0x45, 0x54, 0x5F, 0x4C, 0x45, 0x4E, 0x00, 0x00, 0x72, 0x63, 0x5F, 0x73, ++ 0x73, 0x2D, 0x3E, 0x72, 0x5F, 0x69, 0x64, 0x78, 0x5F, 0x6D, 0x61, 0x78, ++ 0x20, 0x3C, 0x20, 0x4D, 0x41, 0x43, 0x5F, 0x52, 0x41, 0x54, 0x45, 0x53, ++ 0x45, 0x54, 0x5F, 0x4C, 0x45, 0x4E, 0x00, 0x00, 0x72, 0x63, 0x5F, 0x73, ++ 0x73, 0x2D, 0x3E, 0x62, 0x77, 0x5F, 0x6D, 0x61, 0x78, 0x20, 0x3D, 0x3D, ++ 0x20, 0x42, 0x57, 0x5F, 0x32, 0x30, 0x4D, 0x48, 0x5A, 0x00, 0x00, 0x00, ++ 0x25, 0x73, 0x3A, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x5F, ++ 0x69, 0x64, 0x3D, 0x25, 0x69, 0x20, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, ++ 0x5F, 0x6D, 0x6F, 0x64, 0x3D, 0x25, 0x69, 0x20, 0x70, 0x72, 0x65, 0x5F, ++ 0x74, 0x79, 0x70, 0x65, 0x3D, 0x25, 0x69, 0x20, 0x73, 0x68, 0x6F, 0x72, ++ 0x74, 0x5F, 0x67, 0x69, 0x3D, 0x25, 0x69, 0x20, 0x6D, 0x61, 0x78, 0x5F, ++ 0x62, 0x77, 0x3D, 0x25, 0x69, 0x0A, 0x00, 0x00, 0x25, 0x73, 0x3A, 0x20, ++ 0x6E, 0x73, 0x73, 0x5F, 0x6D, 0x61, 0x78, 0x3D, 0x25, 0x69, 0x20, 0x6D, ++ 0x63, 0x73, 0x5F, 0x6D, 0x61, 0x78, 0x3D, 0x25, 0x69, 0x20, 0x72, 0x5F, ++ 0x69, 0x64, 0x78, 0x5F, 0x6D, 0x69, 0x6E, 0x3D, 0x25, 0x69, 0x20, 0x72, ++ 0x5F, 0x69, 0x64, 0x78, 0x5F, 0x6D, 0x61, 0x78, 0x3D, 0x25, 0x69, 0x20, ++ 0x6E, 0x6F, 0x5F, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x73, 0x3D, 0x25, ++ 0x69, 0x0A, 0x00, 0x00, 0x72, 0x63, 0x5F, 0x69, 0x6E, 0x69, 0x74, 0x00, ++ 0x20, 0x7C, 0x9F, 0x00, 0x20, 0xF3, 0xA0, 0x00, 0xA0, 0x17, 0x52, 0x00, ++ 0xA0, 0x8E, 0x53, 0x00, 0xF8, 0x52, 0x23, 0x00, 0xF8, 0xC9, 0x24, 0x00, ++ 0x18, 0xF5, 0x15, 0x00, 0x18, 0x6C, 0x17, 0x00, 0xF9, 0x06, 0x11, 0x00, ++ 0x62, 0x07, 0x12, 0x00, 0x35, 0x08, 0x14, 0x00, 0xD1, 0x10, 0x04, 0x00, ++ 0x0A, 0x4E, 0x04, 0x00, 0x7D, 0xC8, 0x04, 0x00, 0x7D, 0x83, 0x08, 0x00, ++ 0xB1, 0x03, 0x09, 0x00, 0x1A, 0x04, 0x0A, 0x00, 0x68, 0x08, 0x02, 0x00, ++ 0x05, 0x27, 0x02, 0x00, 0x3F, 0x64, 0x02, 0x00, 0xFE, 0xAC, 0x05, 0x00, ++ 0x76, 0x02, 0x06, 0x00, 0x67, 0xAD, 0x06, 0x00, 0xF0, 0x5A, 0x01, 0x00, ++ 0x59, 0x6F, 0x01, 0x00, 0x2A, 0x98, 0x01, 0x00, 0xBE, 0x41, 0x04, 0x00, ++ 0xD9, 0x81, 0x04, 0x00, 0x0D, 0x02, 0x05, 0x00, 0x34, 0x04, 0x01, 0x00, ++ 0x83, 0x13, 0x01, 0x00, 0x1F, 0x32, 0x01, 0x00, 0x7F, 0xD6, 0x02, 0x00, ++ 0x3B, 0x01, 0x03, 0x00, 0xB3, 0x56, 0x03, 0x00, 0x78, 0xAD, 0x00, 0x00, ++ 0xAC, 0xB7, 0x00, 0x00, 0x15, 0xCC, 0x00, 0x00, 0xDF, 0x20, 0x02, 0x00, ++ 0xEC, 0x40, 0x02, 0x00, 0x07, 0x81, 0x02, 0x00, 0x1A, 0x82, 0x00, 0x00, ++ 0xC1, 0x89, 0x00, 0x00, 0x10, 0x99, 0x00, 0x00, 0x55, 0xE4, 0x01, 0x00, ++ 0xD2, 0x00, 0x02, 0x00, 0xCD, 0x39, 0x02, 0x00, 0xA5, 0x73, 0x00, 0x00, ++ 0x73, 0x7A, 0x00, 0x00, 0x0E, 0x88, 0x00, 0x00, 0xE6, 0xB3, 0x01, 0x00, ++ 0x8A, 0xCD, 0x01, 0x00, 0xD2, 0x00, 0x02, 0x00, 0x15, 0x68, 0x00, 0x00, ++ 0x34, 0x6E, 0x00, 0x00, 0x73, 0x7A, 0x00, 0x00, 0x3F, 0x6B, 0x01, 0x00, ++ 0x9E, 0x80, 0x01, 0x00, 0x5A, 0xAB, 0x01, 0x00, 0xBC, 0x56, 0x00, 0x00, ++ 0xD6, 0x5B, 0x00, 0x00, 0x0A, 0x66, 0x00, 0x00, 0xEC, 0x46, 0x01, 0x00, ++ 0x27, 0x5A, 0x01, 0x00, 0x9E, 0x80, 0x01, 0x00, 0x11, 0x4E, 0x00, 0x00, ++ 0xA8, 0x52, 0x00, 0x00, 0xD7, 0x5B, 0x00, 0x00, 0x99, 0x22, 0x01, 0x00, ++ 0xB1, 0x33, 0x01, 0x00, 0xE1, 0x55, 0x01, 0x00, 0x63, 0x45, 0x00, 0x00, ++ 0x78, 0x49, 0x00, 0x00, 0xA2, 0x51, 0x00, 0x00, 0x8A, 0x05, 0x01, 0x00, ++ 0xEC, 0x14, 0x01, 0x00, 0xB1, 0x33, 0x01, 0x00, 0x74, 0x3E, 0x00, 0x00, ++ 0x21, 0x42, 0x00, 0x00, 0x7A, 0x49, 0x00, 0x00, 0x00, 0x10, 0x27, 0x00, ++ 0x3C, 0x5C, 0x29, 0x00, 0xB4, 0xF4, 0x2D, 0x00, 0x00, 0x88, 0x13, 0x00, ++ 0x1E, 0xAE, 0x14, 0x00, 0x5A, 0xFA, 0x16, 0x00, 0x55, 0x05, 0x0D, 0x00, ++ 0x69, 0xC9, 0x0D, 0x00, 0x91, 0x51, 0x0F, 0x00, 0x00, 0xC4, 0x09, 0x00, ++ 0x0F, 0x57, 0x0A, 0x00, 0x2D, 0x7D, 0x0B, 0x00, 0xAA, 0x82, 0x06, 0x00, ++ 0xB4, 0xE4, 0x06, 0x00, 0xC8, 0xA8, 0x07, 0x00, 0x00, 0xE2, 0x04, 0x00, ++ 0x87, 0x2B, 0x05, 0x00, 0x96, 0xBE, 0x05, 0x00, 0x1C, 0x57, 0x04, 0x00, ++ 0x78, 0x98, 0x04, 0x00, 0x30, 0x1B, 0x05, 0x00, 0x00, 0xE8, 0x03, 0x00, ++ 0xD2, 0x22, 0x04, 0x00, 0x78, 0x98, 0x04, 0x00, 0x55, 0x41, 0x03, 0x00, ++ 0x5A, 0x72, 0x03, 0x00, 0x64, 0xD4, 0x03, 0x00, 0x00, 0xEE, 0x02, 0x00, ++ 0x1E, 0x1A, 0x03, 0x00, 0x5A, 0x72, 0x03, 0x00, 0xAA, 0x9A, 0x02, 0x00, ++ 0xE1, 0xC1, 0x02, 0x00, 0x50, 0x10, 0x03, 0x00, 0x00, 0x58, 0x02, 0x00, ++ 0x4B, 0x7B, 0x02, 0x00, 0xE1, 0xC1, 0x02, 0x00, 0x00, 0x04, 0xA6, 0x00, ++ 0x00, 0xC8, 0xAF, 0x00, 0x00, 0x50, 0xC3, 0x00, 0x00, 0x02, 0x53, 0x00, ++ 0x00, 0xE4, 0x57, 0x00, 0x00, 0xA8, 0x61, 0x00, 0xAA, 0x56, 0x37, 0x00, ++ 0x00, 0x98, 0x3A, 0x00, 0xAA, 0x1A, 0x41, 0x00, 0x00, 0x81, 0x29, 0x00, ++ 0x00, 0xF2, 0x2B, 0x00, 0x00, 0xD4, 0x30, 0x00, 0x55, 0xAB, 0x1B, 0x00, ++ 0x00, 0x4C, 0x1D, 0x00, 0x55, 0x8D, 0x20, 0x00, 0x80, 0xC0, 0x14, 0x00, ++ 0x00, 0xF9, 0x15, 0x00, 0x00, 0x6A, 0x18, 0x00, 0x38, 0x72, 0x12, 0x00, ++ 0x00, 0x88, 0x13, 0x00, 0x8E, 0xB3, 0x15, 0x00, 0x00, 0x9A, 0x10, 0x00, ++ 0x00, 0x94, 0x11, 0x00, 0x00, 0x88, 0x13, 0x00, 0xAA, 0xD5, 0x0D, 0x00, ++ 0x00, 0xA6, 0x0E, 0x00, 0xAA, 0x46, 0x10, 0x00, 0x80, 0x73, 0x0C, 0x00, ++ 0x00, 0x2F, 0x0D, 0x00, 0x00, 0xA6, 0x0E, 0x00, 0x55, 0x11, 0x0B, 0x00, ++ 0x00, 0xB8, 0x0B, 0x00, 0x55, 0x05, 0x0D, 0x00, 0x00, 0xF6, 0x09, 0x00, ++ 0x00, 0x8C, 0x0A, 0x00, 0x00, 0xB8, 0x0B, 0x00, 0x00, 0x02, 0x53, 0x00, ++ 0x00, 0xE4, 0x57, 0x00, 0x00, 0xA8, 0x61, 0x00, 0x00, 0x81, 0x29, 0x00, ++ 0x00, 0xF2, 0x2B, 0x00, 0x00, 0xD4, 0x30, 0x00, 0x55, 0xAB, 0x1B, 0x00, ++ 0x00, 0x4C, 0x1D, 0x00, 0x55, 0x8D, 0x20, 0x00, 0x80, 0xC0, 0x14, 0x00, ++ 0x00, 0xF9, 0x15, 0x00, 0x00, 0x6A, 0x18, 0x00, 0xAA, 0xD5, 0x0D, 0x00, ++ 0x00, 0xA6, 0x0E, 0x00, 0xAA, 0x46, 0x10, 0x00, 0x40, 0x60, 0x0A, 0x00, ++ 0x80, 0xFC, 0x0A, 0x00, 0x00, 0x35, 0x0C, 0x00, 0x1C, 0x39, 0x09, 0x00, ++ 0x00, 0xC4, 0x09, 0x00, 0xC7, 0xD9, 0x0A, 0x00, 0x00, 0x4D, 0x08, 0x00, ++ 0x00, 0xCA, 0x08, 0x00, 0x00, 0xC4, 0x09, 0x00, 0xD5, 0xEA, 0x06, 0x00, ++ 0x00, 0x53, 0x07, 0x00, 0x55, 0x23, 0x08, 0x00, 0xC0, 0x39, 0x06, 0x00, ++ 0x80, 0x97, 0x06, 0x00, 0x00, 0x53, 0x07, 0x00, 0xAA, 0x88, 0x05, 0x00, ++ 0x00, 0xDC, 0x05, 0x00, 0xAA, 0x82, 0x06, 0x00, 0x00, 0xFB, 0x04, 0x00, ++ 0x00, 0x46, 0x05, 0x00, 0x00, 0xDC, 0x05, 0x00, 0x3B, 0x89, 0x16, 0x00, ++ 0x4F, 0x48, 0x14, 0x00, 0xC7, 0xD9, 0x0A, 0x00, 0x00, 0xC4, 0x09, 0x00, ++ 0x0D, 0x02, 0x05, 0x00, 0xD9, 0x81, 0x04, 0x00, 0x07, 0x81, 0x02, 0x00, ++ 0xEC, 0x40, 0x02, 0x00, 0x9E, 0x44, 0x0B, 0x00, 0x27, 0x24, 0x0A, 0x00, ++ 0xE4, 0x6C, 0x05, 0x00, 0x00, 0xE2, 0x04, 0x00, 0x07, 0x81, 0x02, 0x00, ++ 0xEC, 0x40, 0x02, 0x00, 0x83, 0x40, 0x01, 0x00, 0x76, 0x20, 0x01, 0x00, ++ 0x14, 0x83, 0x07, 0x00, 0xC5, 0xC2, 0x06, 0x00, 0xED, 0x9D, 0x03, 0x00, ++ 0x55, 0x41, 0x03, 0x00, 0x5A, 0xAB, 0x01, 0x00, 0x9E, 0x80, 0x01, 0x00, ++ 0xAD, 0xD5, 0x00, 0x00, 0x4F, 0xC0, 0x00, 0x00, 0x4F, 0xA2, 0x05, 0x00, ++ 0x14, 0x12, 0x05, 0x00, 0x72, 0xB6, 0x02, 0x00, 0x00, 0x71, 0x02, 0x00, ++ 0x83, 0x40, 0x01, 0x00, 0x76, 0x20, 0x01, 0x00, 0x42, 0xA0, 0x00, 0x00, ++ 0x3B, 0x90, 0x00, 0x00, 0x8A, 0xC1, 0x03, 0x00, 0x62, 0x61, 0x03, 0x00, ++ 0xF7, 0xCE, 0x01, 0x00, 0xAB, 0xA0, 0x01, 0x00, 0xAD, 0xD5, 0x00, 0x00, ++ 0x4F, 0xC0, 0x00, 0x00, 0xD6, 0x6A, 0x00, 0x00, 0x27, 0x60, 0x00, 0x00, ++ 0x27, 0xD1, 0x02, 0x00, 0x0A, 0x89, 0x02, 0x00, 0x39, 0x5B, 0x01, 0x00, ++ 0x80, 0x38, 0x01, 0x00, 0x42, 0xA0, 0x00, 0x00, 0x3B, 0x90, 0x00, 0x00, ++ 0x21, 0x50, 0x00, 0x00, 0x1E, 0x48, 0x00, 0x00, 0x07, 0x81, 0x02, 0x00, ++ 0xEC, 0x40, 0x02, 0x00, 0xA4, 0x34, 0x01, 0x00, 0xC7, 0x15, 0x01, 0x00, ++ 0x73, 0x8E, 0x00, 0x00, 0x35, 0x80, 0x00, 0x00, 0x3A, 0x47, 0x00, 0x00, ++ 0x1A, 0x40, 0x00, 0x00, 0xEC, 0x40, 0x02, 0x00, 0x3B, 0x07, 0x02, 0x00, ++ 0xC7, 0x15, 0x01, 0x00, 0x00, 0xFA, 0x00, 0x00, 0x35, 0x80, 0x00, 0x00, ++ 0x62, 0x73, 0x00, 0x00, 0x1A, 0x40, 0x00, 0x00, 0xB1, 0x39, 0x00, 0x00, ++ 0xC5, 0xE0, 0x01, 0x00, 0xB1, 0xB0, 0x01, 0x00, 0x7B, 0xE7, 0x00, 0x00, ++ 0x55, 0xD0, 0x00, 0x00, 0xD6, 0x6A, 0x00, 0x00, 0x27, 0x60, 0x00, 0x00, ++ 0x6B, 0x35, 0x00, 0x00, 0x14, 0x30, 0x00, 0x00, 0xB1, 0xB0, 0x01, 0x00, ++ 0x6C, 0x85, 0x01, 0x00, 0x55, 0xD0, 0x00, 0x00, 0x80, 0xBB, 0x00, 0x00, ++ 0x27, 0x60, 0x00, 0x00, 0x8A, 0x56, 0x00, 0x00, 0x14, 0x30, 0x00, 0x00, ++ 0x45, 0x2B, 0x00, 0x00, 0x00, 0x6A, 0x18, 0x00, 0xE0, 0x4B, 0x10, 0x00, ++ 0x00, 0x35, 0x0C, 0x00, 0xC0, 0x2D, 0x08, 0x00, 0x80, 0x1A, 0x06, 0x00, ++ 0xE0, 0x16, 0x04, 0x00, 0x40, 0x0D, 0x03, 0x00, 0x20, 0xBF, 0x02, 0x00, ++ 0x24, 0xCE, 0x15, 0x00, 0xB4, 0xCE, 0x15, 0x00, 0x94, 0xCD, 0x15, 0x00, ++ 0xB8, 0xD0, 0x15, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, ++ 0x39, 0x4B, 0x15, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x15, 0x4C, 0x15, 0x00, ++ 0x01, 0x10, 0x00, 0x00, 0xD5, 0x4B, 0x15, 0x00, 0x61, 0x76, 0x61, 0x69, ++ 0x6C, 0x20, 0x3E, 0x3D, 0x20, 0x42, 0x43, 0x4E, 0x5F, 0x46, 0x49, 0x58, ++ 0x45, 0x44, 0x5F, 0x53, 0x49, 0x5A, 0x45, 0x5F, 0x46, 0x49, 0x45, 0x4C, ++ 0x44, 0x53, 0x5F, 0x4C, 0x45, 0x4E, 0x00, 0x00, 0x72, 0x65, 0x70, 0x6F, ++ 0x72, 0x74, 0x5F, 0x6C, 0x65, 0x6E, 0x20, 0x3C, 0x3D, 0x20, 0x62, 0x75, ++ 0x66, 0x5F, 0x6C, 0x65, 0x6E, 0x00, 0x00, 0x00, 0x72, 0x65, 0x70, 0x6F, ++ 0x72, 0x74, 0x73, 0x5F, 0x6C, 0x65, 0x6E, 0x20, 0x3E, 0x20, 0x30, 0x00, ++ 0x21, 0x72, 0x6D, 0x5F, 0x6E, 0x6F, 0x5F, 0x6D, 0x6F, 0x72, 0x65, 0x5F, ++ 0x6D, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x5F, 0x74, 0x6F, 0x5F, 0x72, ++ 0x65, 0x70, 0x6F, 0x72, 0x74, 0x28, 0x29, 0x20, 0x7C, 0x7C, 0x20, 0x28, ++ 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2D, 0x3E, 0x72, 0x65, 0x70, ++ 0x6F, 0x72, 0x74, 0x5F, 0x73, 0x65, 0x6E, 0x74, 0x20, 0x3D, 0x3D, 0x20, ++ 0x30, 0x29, 0x00, 0x00, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2D, ++ 0x3E, 0x63, 0x68, 0x61, 0x6E, 0x5F, 0x63, 0x6E, 0x74, 0x20, 0x3C, 0x3D, ++ 0x20, 0x43, 0x4F, 0x5F, 0x41, 0x52, 0x52, 0x41, 0x59, 0x5F, 0x53, 0x49, ++ 0x5A, 0x45, 0x28, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2D, 0x3E, ++ 0x63, 0x68, 0x61, 0x6E, 0x5F, 0x6C, 0x69, 0x73, 0x74, 0x29, 0x00, 0x00, ++ 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2D, 0x3E, 0x74, 0x79, 0x70, ++ 0x65, 0x20, 0x3D, 0x3D, 0x20, 0x4D, 0x41, 0x43, 0x5F, 0x4D, 0x45, 0x41, ++ 0x53, 0x5F, 0x52, 0x45, 0x51, 0x5F, 0x54, 0x59, 0x50, 0x45, 0x5F, 0x42, ++ 0x45, 0x41, 0x43, 0x4F, 0x4E, 0x00, 0x00, 0x00, 0x72, 0x6D, 0x5F, 0x65, ++ 0x6E, 0x76, 0x2E, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5F, 0x72, 0x65, ++ 0x71, 0x75, 0x65, 0x73, 0x74, 0x20, 0x3E, 0x3D, 0x20, 0x30, 0x00, 0x00, ++ 0x64, 0x69, 0x20, 0x53, 0x65, 0x70, 0x20, 0x31, 0x33, 0x20, 0x32, 0x30, ++ 0x32, 0x32, 0x20, 0x31, 0x30, 0x3A, 0x34, 0x37, 0x3A, 0x31, 0x34, 0x20, ++ 0x2D, 0x20, 0x67, 0x37, 0x34, 0x32, 0x30, 0x33, 0x31, 0x37, 0x31, 0x00, ++ 0x76, 0x36, 0x2E, 0x34, 0x2E, 0x33, 0x2E, 0x31, 0x00, 0x00, 0x00, 0x00, ++ 0xF8, 0xB5, 0x00, 0xBF, 0xF8, 0xBC, 0x08, 0xBC, 0x9E, 0x46, 0x70, 0x47, ++ 0xF8, 0xB5, 0x00, 0xBF, 0xF8, 0xBC, 0x08, 0xBC, 0x9E, 0x46, 0x70, 0x47, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x01, 0x17, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x04, 0x17, 0x00, ++ 0xDC, 0x04, 0x17, 0x00, 0x44, 0x05, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x0E, 0x33, 0xCD, 0xAB, 0x34, 0x12, 0x6D, 0xE6, 0xEC, 0xDE, 0x05, 0x00, ++ 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x20, 0x0E, 0x00, 0x00, 0x04, 0x0E, 0x20, 0x00, 0x30, ++ 0x00, 0x00, 0x00, 0x5B, 0x4B, 0x00, 0x00, 0x04, 0x8E, 0x00, 0x00, 0x30, ++ 0x00, 0x00, 0x00, 0x32, 0x7B, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x40, ++ 0x26, 0x00, 0x00, 0xF8, 0x11, 0x00, 0x00, 0x04, 0x8E, 0x00, 0x19, 0x48, ++ 0x20, 0x00, 0x00, 0x9C, 0x91, 0x01, 0x00, 0x08, 0x00, 0x80, 0x00, 0x38, ++ 0x00, 0x00, 0x00, 0x0A, 0x11, 0x44, 0x10, 0x08, 0x00, 0x80, 0x01, 0x38, ++ 0x41, 0x46, 0x00, 0x0C, 0x14, 0x00, 0xD0, 0x08, 0x00, 0x00, 0x00, 0x30, ++ 0x00, 0x00, 0x00, 0x01, 0x17, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x30, ++ 0x00, 0x00, 0x00, 0x3C, 0x1A, 0x00, 0x00, 0x04, 0x00, 0x00, 0x02, 0x38, ++ 0x01, 0x00, 0x00, 0x40, 0x1D, 0x00, 0x00, 0x08, 0x8E, 0x00, 0x08, 0x38, ++ 0x50, 0x00, 0x00, 0x14, 0x20, 0x00, 0x00, 0x08, 0x8E, 0x00, 0x00, 0x40, ++ 0x7B, 0x00, 0x00, 0xA4, 0x01, 0x01, 0x00, 0x00, 0x9F, 0x33, 0x00, 0x30, ++ 0x00, 0x07, 0x00, 0x41, 0x20, 0x44, 0x10, 0x04, 0x00, 0x00, 0x00, 0x90, ++ 0x00, 0x00, 0x00, 0x49, 0x2F, 0x84, 0x0E, 0xF0, 0x2C, 0x84, 0x0E, 0xEC, ++ 0x2C, 0x84, 0x0E, 0xEC, 0x32, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x30, ++ 0x01, 0x01, 0x00, 0x48, 0x32, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x30, ++ 0x02, 0x02, 0x00, 0x48, 0x32, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x30, ++ 0x00, 0x00, 0x00, 0x46, 0x11, 0x00, 0x00, 0x04, 0x06, 0x00, 0x01, 0x58, ++ 0x72, 0x04, 0x04, 0x3D, 0x39, 0x44, 0x20, 0xDC, 0xD2, 0xD4, 0x1D, 0x08, ++ 0x06, 0x00, 0x0A, 0x48, 0xDC, 0x44, 0x20, 0xDC, 0x3C, 0xD4, 0x1D, 0x08, ++ 0x04, 0x00, 0x05, 0x38, 0xC3, 0xF1, 0xF1, 0x0E, 0xDC, 0x44, 0x20, 0x34, ++ 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x42, 0x00, 0x00, 0x04, ++ 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x33, 0x45, 0x44, 0x10, 0x04, ++ 0x00, 0x80, 0x00, 0x38, 0x9C, 0x10, 0x00, 0x22, 0x48, 0x44, 0x10, 0x08, ++ 0x00, 0x80, 0x00, 0x38, 0x9C, 0x50, 0xD4, 0x23, 0x17, 0x44, 0x10, 0x08, ++ 0x00, 0xA0, 0x00, 0x90, 0x00, 0x00, 0x00, 0x32, 0x63, 0x00, 0x00, 0x18, ++ 0x60, 0x00, 0x00, 0x14, 0x51, 0x00, 0x00, 0x1C, 0x57, 0x00, 0x00, 0x10, ++ 0x00, 0x80, 0x02, 0x38, 0x01, 0x00, 0x00, 0x0C, 0x66, 0x44, 0xD0, 0x08, ++ 0x0F, 0x20, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x03, 0x38, 0x01, 0x26, 0x00, 0x0C, 0x5A, 0x44, 0xD0, 0x08, ++ 0x00, 0x00, 0x00, 0x30, 0x30, 0x02, 0x02, 0x3D, 0x5D, 0x00, 0x00, 0x04, ++ 0x00, 0x00, 0x00, 0x30, 0x00, 0x01, 0x00, 0x3E, 0x66, 0x00, 0x00, 0x04, ++ 0x00, 0x80, 0x02, 0x38, 0x01, 0x16, 0x00, 0x0C, 0x66, 0x44, 0x20, 0x34, ++ 0x00, 0x80, 0x02, 0x38, 0x01, 0x0A, 0x00, 0x0C, 0x66, 0x44, 0x20, 0x34, ++ 0x04, 0x80, 0x00, 0x38, 0x00, 0x00, 0x00, 0xFF, 0x7B, 0x00, 0x00, 0x08, ++ 0x2F, 0x80, 0x00, 0x38, 0x00, 0x00, 0x00, 0x26, 0x6C, 0x00, 0x00, 0x08, ++ 0xAF, 0x04, 0x04, 0x38, 0x10, 0x10, 0x19, 0x1F, 0x6F, 0x00, 0x00, 0x08, ++ 0xAF, 0x0C, 0x00, 0x20, 0x71, 0x00, 0x00, 0x04, 0xAF, 0x0C, 0x00, 0x60, ++ 0x79, 0x00, 0x70, 0x18, 0x77, 0x00, 0x00, 0x14, 0x75, 0x00, 0x00, 0x10, ++ 0xAF, 0x0C, 0x14, 0x28, 0x84, 0x00, 0xB0, 0x09, 0xAF, 0x0C, 0x0A, 0x28, ++ 0x84, 0x00, 0xB0, 0x09, 0xAF, 0x0C, 0x06, 0x28, 0x84, 0x00, 0xB0, 0x09, ++ 0x86, 0x80, 0x04, 0x28, 0x7D, 0x00, 0x00, 0x08, 0x86, 0x00, 0x00, 0x38, ++ 0x00, 0x00, 0x80, 0x22, 0x80, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x30, ++ 0x01, 0xF1, 0xF1, 0x0E, 0x83, 0x48, 0x00, 0x36, 0x00, 0x00, 0x02, 0x28, ++ 0x85, 0x00, 0x00, 0x08, 0x8E, 0x00, 0x02, 0x38, 0x31, 0x04, 0x04, 0x3D, ++ 0x88, 0x00, 0x00, 0x08, 0x8E, 0x00, 0x05, 0x38, 0x21, 0x18, 0x24, 0x1F, ++ 0x8B, 0x00, 0x00, 0x08, 0x8E, 0x00, 0x00, 0x30, 0x21, 0x30, 0x16, 0xA0, ++ 0x8E, 0x00, 0x00, 0x04, 0x8E, 0x00, 0x00, 0x30, 0x12, 0x00, 0xF1, 0x0E, ++ 0x91, 0x00, 0x00, 0x34, 0xCC, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x50, ++ 0x94, 0x00, 0x00, 0x04, 0xFE, 0x95, 0x00, 0x38, 0x00, 0x00, 0x01, 0x32, ++ 0x97, 0x00, 0x00, 0x04, 0xFE, 0x1F, 0x00, 0x50, 0x00, 0x00, 0x01, 0x5A, ++ 0x9B, 0x98, 0xC9, 0x6D, 0xB9, 0xD4, 0x19, 0xFC, 0x86, 0x01, 0x00, 0x30, ++ 0x73, 0x03, 0x84, 0x3D, 0x9E, 0x00, 0x00, 0x04, 0x8E, 0x00, 0x00, 0x30, ++ 0x00, 0x00, 0x00, 0x0A, 0xA1, 0x00, 0x00, 0x04, 0x8E, 0x00, 0x00, 0x30, ++ 0x00, 0x00, 0xC0, 0x22, 0xA4, 0x00, 0x00, 0x04, 0x8E, 0x02, 0x00, 0x90, ++ 0x01, 0x00, 0x01, 0x32, 0xAA, 0x00, 0x40, 0x8E, 0xB0, 0x00, 0x00, 0xC8, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x00, 0x00, 0x30, ++ 0x01, 0x00, 0x01, 0x32, 0xCB, 0x00, 0x00, 0x04, 0x8E, 0x00, 0x00, 0x30, ++ 0x00, 0x00, 0x00, 0x29, 0x11, 0x50, 0x04, 0x94, 0xB6, 0x19, 0x00, 0x30, ++ 0x00, 0x00, 0x01, 0x32, 0xB3, 0x00, 0x00, 0x04, 0xB6, 0x19, 0x00, 0x30, ++ 0x31, 0x04, 0x04, 0x3D, 0xB6, 0x00, 0x00, 0x04, 0xB6, 0x19, 0x00, 0x30, ++ 0x00, 0x00, 0x80, 0x22, 0x97, 0x00, 0x00, 0x04, 0x86, 0x01, 0x00, 0x30, ++ 0x73, 0x04, 0x84, 0x3D, 0xBC, 0x00, 0x00, 0x04, 0x8E, 0x00, 0x00, 0x30, ++ 0x00, 0x00, 0x03, 0x29, 0xBF, 0x00, 0x00, 0x04, 0x8E, 0x02, 0xEE, 0x9A, ++ 0x00, 0x01, 0x01, 0x32, 0xC5, 0x00, 0x00, 0x7C, 0xB0, 0x00, 0x00, 0xCC, ++ 0xB0, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x00, 0x00, 0x30, ++ 0x00, 0x01, 0x01, 0x32, 0xC8, 0x00, 0x00, 0x04, 0x8E, 0x02, 0x00, 0x30, ++ 0x00, 0x00, 0x00, 0x29, 0x11, 0x50, 0x04, 0x94, 0x8E, 0x03, 0x00, 0x50, ++ 0x00, 0x00, 0x00, 0x29, 0x11, 0x50, 0x04, 0x94, 0x35, 0x00, 0x00, 0xC0, ++ 0x06, 0x00, 0x01, 0x38, 0x72, 0x04, 0x04, 0x3D, 0xD2, 0x00, 0x00, 0x08, ++ 0x04, 0x00, 0x00, 0x30, 0x41, 0xF1, 0xF1, 0x0E, 0xD5, 0x00, 0x00, 0x34, ++ 0x04, 0x00, 0x04, 0x28, 0xD7, 0x00, 0x00, 0x08, 0x0E, 0x00, 0x08, 0x28, ++ 0xD9, 0x00, 0x00, 0x08, 0x8E, 0x01, 0x00, 0x30, 0x52, 0x00, 0xF1, 0x0E, ++ 0xDC, 0x00, 0x00, 0x34, 0x8E, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0x29, ++ 0x11, 0x50, 0x04, 0x94, 0x00, 0x00, 0x02, 0x38, 0x00, 0x00, 0x00, 0x32, ++ 0xE2, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x60, 0xE6, 0x00, 0x00, 0xD8, ++ 0xE9, 0x00, 0x00, 0xD4, 0xEC, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x30, ++ 0x21, 0xF1, 0xF1, 0x0E, 0xEF, 0x48, 0x00, 0x36, 0x00, 0x00, 0x00, 0x30, ++ 0x21, 0x24, 0x00, 0x0C, 0xEF, 0x48, 0x00, 0x36, 0x00, 0x00, 0x00, 0x30, ++ 0x21, 0x00, 0x00, 0x0C, 0xEF, 0x48, 0x00, 0x36, 0x00, 0x00, 0x02, 0x28, ++ 0x7B, 0x00, 0x00, 0x08, 0xFE, 0x1E, 0x00, 0x50, 0x00, 0x00, 0x01, 0x5A, ++ 0xF5, 0x98, 0xC9, 0x6D, 0xF8, 0xD4, 0x19, 0xFC, 0x8E, 0x02, 0x00, 0x30, ++ 0x40, 0x00, 0x00, 0x32, 0xFB, 0x00, 0x00, 0x04, 0x8E, 0x02, 0xEE, 0x3A, ++ 0x80, 0x00, 0x00, 0x32, 0xFB, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x30, ++ 0x01, 0xF1, 0xF1, 0x0E, 0xFE, 0x48, 0x00, 0x36, 0x00, 0x00, 0x02, 0x28, ++ 0x00, 0x01, 0x00, 0x08, 0x8E, 0x00, 0x02, 0x38, 0x31, 0x04, 0x04, 0x3D, ++ 0x03, 0x01, 0x00, 0x08, 0x8E, 0x00, 0x05, 0x38, 0x21, 0x18, 0x24, 0x1F, ++ 0x06, 0x01, 0x00, 0x08, 0x8E, 0x00, 0x00, 0x30, 0x21, 0x30, 0x16, 0xA0, ++ 0x09, 0x01, 0x00, 0x04, 0x8E, 0x00, 0x00, 0x30, 0x12, 0x00, 0xF1, 0x0E, ++ 0x0C, 0x01, 0x00, 0x34, 0xF6, 0x14, 0x00, 0x30, 0x00, 0x00, 0x01, 0x32, ++ 0x14, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x11, 0x01, 0x00, 0x04, ++ 0xEC, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x50, 0xF1, 0x00, 0x00, 0x04, ++ 0xF6, 0x14, 0x00, 0x30, 0x00, 0x00, 0x03, 0x32, 0x17, 0x01, 0x00, 0x04, ++ 0x86, 0x10, 0x00, 0x30, 0x73, 0x04, 0x84, 0x3D, 0x1A, 0x01, 0x00, 0x04, ++ 0x8E, 0x10, 0x00, 0x50, 0x00, 0x00, 0xC0, 0x22, 0xCB, 0xC0, 0x47, 0x8E, ++ 0x1E, 0x01, 0x30, 0xCB, 0xB6, 0x19, 0x00, 0x30, 0x00, 0x00, 0x04, 0x32, ++ 0x21, 0x01, 0x00, 0x04, 0xB6, 0x19, 0x00, 0x30, 0x31, 0x04, 0x04, 0x3D, ++ 0x24, 0x01, 0x00, 0x04, 0xB6, 0x19, 0x00, 0x30, 0x00, 0x00, 0x80, 0x22, ++ 0x11, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x86, 0x01, 0x00, 0x30, 0x73, 0x04, 0x84, 0x3D, ++ 0x2D, 0x01, 0x00, 0x04, 0x8E, 0x03, 0x00, 0x50, 0x00, 0x00, 0x00, 0x29, ++ 0x11, 0x50, 0x04, 0x94, 0x31, 0x01, 0x00, 0xC0, 0x0E, 0x80, 0x0C, 0x38, ++ 0x00, 0x00, 0x00, 0xFF, 0x34, 0x01, 0x00, 0x08, 0x04, 0x00, 0x00, 0x30, ++ 0x03, 0xF1, 0xF1, 0x0F, 0x37, 0x01, 0x00, 0x34, 0x00, 0x00, 0x02, 0x28, ++ 0x39, 0x01, 0x00, 0x08, 0x8E, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0x29, ++ 0x11, 0x50, 0x04, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x58, 0x72, 0x04, 0x04, 0x3D, ++ 0x43, 0x45, 0x20, 0xDC, 0xD2, 0xD4, 0x1D, 0x08, 0x06, 0x00, 0x0A, 0x48, ++ 0xDC, 0x44, 0x20, 0xDC, 0x46, 0xD5, 0x1D, 0x08, 0x04, 0x00, 0x05, 0x38, ++ 0x41, 0xF1, 0xF1, 0x0E, 0xDC, 0x44, 0x20, 0x34, 0x0E, 0x80, 0x02, 0x28, ++ 0xDC, 0x00, 0x00, 0x08, 0x35, 0x00, 0x00, 0x48, 0x4A, 0x01, 0x00, 0x04, ++ 0x8F, 0x63, 0x96, 0x78, 0x0F, 0x00, 0x00, 0x41, 0x4F, 0x01, 0x00, 0x8C, ++ 0xC4, 0x50, 0x04, 0x08, 0x74, 0x45, 0x10, 0x90, 0x0F, 0x62, 0xC8, 0x88, ++ 0x5A, 0x01, 0x00, 0xC0, 0x74, 0x45, 0x10, 0x90, 0x54, 0x45, 0x10, 0x08, ++ 0x57, 0x45, 0x10, 0x94, 0x8F, 0x62, 0x00, 0x30, 0x00, 0x00, 0x00, 0x29, ++ 0x7A, 0x51, 0x04, 0x94, 0x8F, 0x63, 0x00, 0x30, 0x00, 0x00, 0x00, 0x29, ++ 0x7A, 0x45, 0x10, 0x04, 0x05, 0xE0, 0x00, 0x38, 0x31, 0x01, 0x01, 0x3D, ++ 0x5D, 0x45, 0x10, 0x08, 0x0F, 0x60, 0x32, 0xA8, 0x74, 0x45, 0x10, 0x90, ++ 0x54, 0x01, 0x00, 0x08, 0x57, 0x45, 0x10, 0x94, 0x67, 0x45, 0x10, 0xC6, ++ 0x63, 0x55, 0x18, 0xC4, 0x0F, 0xE0, 0x02, 0x58, 0x07, 0xEA, 0xEE, 0x0F, ++ 0x74, 0x01, 0x00, 0x80, 0x6B, 0x45, 0x20, 0x34, 0x0F, 0xE0, 0x02, 0x58, ++ 0x07, 0xEA, 0xEE, 0x0E, 0x74, 0x01, 0x00, 0x80, 0x6B, 0x45, 0x20, 0x34, ++ 0x00, 0x40, 0x00, 0x30, 0x01, 0x00, 0x00, 0x33, 0x6E, 0x01, 0x00, 0x04, ++ 0x05, 0x40, 0x03, 0x38, 0x73, 0x03, 0x03, 0x3D, 0x71, 0x01, 0x00, 0x08, ++ 0x07, 0x60, 0x00, 0x30, 0x00, 0x00, 0x00, 0x33, 0x74, 0x01, 0x00, 0x04, ++ 0x8F, 0x60, 0x00, 0x30, 0x00, 0x00, 0x00, 0x29, 0x77, 0x51, 0x04, 0x94, ++ 0x8F, 0x60, 0x00, 0x40, 0x7D, 0x45, 0x10, 0xA0, 0x7A, 0x45, 0x10, 0x04, ++ 0x8F, 0x60, 0x00, 0x30, 0x01, 0x01, 0x00, 0x64, 0x11, 0x44, 0x10, 0x04, ++ 0x8F, 0x60, 0x00, 0x30, 0x01, 0x01, 0x00, 0x64, 0x80, 0x45, 0x10, 0x04, ++ 0x8F, 0x61, 0x00, 0x30, 0x01, 0x00, 0x00, 0x42, 0x83, 0x01, 0x00, 0x04, ++ 0x00, 0x80, 0x02, 0x38, 0x00, 0x00, 0x00, 0x32, 0x86, 0x45, 0x10, 0x08, ++ 0x8F, 0x61, 0x0A, 0x28, 0x88, 0x01, 0x00, 0x08, 0x8F, 0x61, 0x0A, 0x48, ++ 0x8B, 0x01, 0x00, 0xBC, 0x8E, 0x01, 0x00, 0x08, 0x8F, 0x61, 0x00, 0x30, ++ 0x01, 0x00, 0x00, 0x34, 0x05, 0x00, 0x00, 0x04, 0x8F, 0x61, 0x00, 0x30, ++ 0x00, 0x00, 0x00, 0x34, 0x08, 0x00, 0x00, 0x04, 0x8F, 0x00, 0x00, 0x30, ++ 0x0F, 0xED, 0xEA, 0x0E, 0x94, 0x01, 0x00, 0x36, 0x00, 0x80, 0x03, 0x38, ++ 0x00, 0x00, 0x00, 0x34, 0x97, 0x01, 0x00, 0x08, 0x05, 0x80, 0x02, 0x38, ++ 0x02, 0x00, 0x01, 0x29, 0x9A, 0x01, 0x00, 0x08, 0x8F, 0x02, 0x00, 0x30, ++ 0x9C, 0x20, 0x00, 0x22, 0x9D, 0x01, 0x00, 0x04, 0x8F, 0x02, 0x00, 0x30, ++ 0x9C, 0x50, 0xD4, 0x23, 0xA0, 0x01, 0x00, 0x04, 0x8F, 0x02, 0x14, 0x28, ++ 0xA2, 0x01, 0x00, 0x08, 0x8F, 0x02, 0x00, 0x30, 0x01, 0x02, 0x01, 0x43, ++ 0xA5, 0x01, 0x00, 0x04, 0x8F, 0x12, 0x00, 0x30, 0x00, 0x01, 0x00, 0x32, ++ 0xA8, 0x01, 0x00, 0x04, 0x8F, 0x13, 0xEE, 0x5A, 0x0F, 0x00, 0x00, 0x41, ++ 0xAC, 0x01, 0x00, 0x7C, 0xF9, 0x00, 0x00, 0x08, 0x8F, 0x13, 0x2C, 0x59, ++ 0x00, 0x00, 0x00, 0x29, 0xB0, 0x01, 0x00, 0x8C, 0xF9, 0x00, 0x00, 0x08, ++ 0x8F, 0x13, 0x00, 0x20, 0x11, 0x50, 0x04, 0x94, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x76, 0x76, 0x00, ++ 0x70, 0xF8, 0xF8, 0x1D, 0x70, 0xF8, 0xF8, 0x1D, 0x70, 0xF8, 0xF8, 0x1D, ++ 0x70, 0xF8, 0xF8, 0x1D, 0x72, 0x6E, 0x6E, 0x00, 0x69, 0xF8, 0xF8, 0x1D, ++ 0x69, 0xF8, 0xF8, 0x1D, 0x69, 0xF8, 0xF8, 0x1D, 0x69, 0xF8, 0xF8, 0x1D, ++ 0x7B, 0x76, 0x76, 0x00, 0x70, 0xF8, 0xF8, 0x1D, 0x70, 0xF8, 0xF8, 0x1D, ++ 0x70, 0xF8, 0xF8, 0x1D, 0x70, 0xF8, 0xF8, 0x1D, 0x85, 0x7E, 0x7E, 0x00, ++ 0x76, 0xF8, 0xF4, 0x1D, 0x76, 0xF8, 0xF4, 0x1D, 0x76, 0xF8, 0xF4, 0x1D, ++ 0x76, 0xF8, 0xF8, 0x1D, 0x8A, 0x81, 0x81, 0x00, 0x7B, 0xF8, 0xF8, 0x1D, ++ 0x7B, 0xF8, 0xF8, 0x1D, 0x7B, 0xF8, 0xF8, 0x1D, 0x7B, 0xF8, 0xF8, 0x1D, ++ 0x8D, 0x81, 0x81, 0x00, 0x7B, 0xF8, 0xF8, 0x1D, 0x7B, 0xF8, 0xF8, 0x1D, ++ 0x7B, 0xF8, 0xF8, 0x1D, 0x7B, 0xF8, 0xF8, 0x1D, 0x8A, 0x81, 0x81, 0x00, ++ 0x7B, 0xF8, 0xF8, 0x1D, 0x7C, 0xF8, 0xF8, 0x1D, 0x7B, 0xF8, 0xF8, 0x1D, ++ 0x7B, 0xF8, 0xF8, 0x1D, 0x40, 0x7E, 0x7E, 0x00, 0x7B, 0xF8, 0xF8, 0x1D, ++ 0x7B, 0xF8, 0xF8, 0x1D, 0x7B, 0xF8, 0xF8, 0x1D, 0x7B, 0xF8, 0xF8, 0x1D, ++ 0x92, 0x8B, 0x8B, 0x00, 0x87, 0xF8, 0xF8, 0x1D, 0x89, 0xF8, 0xF8, 0x1D, ++ 0x87, 0xF8, 0xF8, 0x1D, 0x87, 0xF8, 0xF8, 0x1D, 0x55, 0x51, 0x51, 0x00, ++ 0x4C, 0xF8, 0xF8, 0x1D, 0x4C, 0xF8, 0xF8, 0x1D, 0x89, 0xF8, 0xF8, 0x1D, ++ 0x89, 0xF8, 0xF8, 0x1D, 0x54, 0x51, 0x51, 0x00, 0x4C, 0xF8, 0xF8, 0x1D, ++ 0x4C, 0xF8, 0xF8, 0x1D, 0x88, 0xF8, 0xF8, 0x1D, 0x88, 0xF8, 0xF8, 0x1D, ++ 0x53, 0x4F, 0x4F, 0x00, 0x4A, 0xF8, 0xF8, 0x1D, 0x4A, 0xF8, 0xF8, 0x1D, ++ 0x4A, 0xF8, 0xF8, 0x1D, 0x4A, 0xF8, 0xF8, 0x1D, 0x53, 0x4F, 0x4F, 0x00, ++ 0x4A, 0xF8, 0xF8, 0x1D, 0x4A, 0xF8, 0xF8, 0x1D, 0x4A, 0xF8, 0xF8, 0x1D, ++ 0x4A, 0xF8, 0xF8, 0x1D, 0x53, 0x4F, 0x4F, 0x00, 0x4A, 0xF8, 0xF8, 0x1D, ++ 0x4A, 0xF8, 0xF8, 0x1D, 0x4A, 0xF8, 0xF8, 0x1D, 0x4A, 0xF8, 0xF8, 0x1D, ++ 0x53, 0x4E, 0x4E, 0x00, 0x49, 0xF8, 0xF8, 0x1D, 0x48, 0xF8, 0xF8, 0x1D, ++ 0x48, 0xF8, 0xF8, 0x1D, 0x48, 0xF8, 0xF8, 0x1D, 0x52, 0x4D, 0x4D, 0x00, ++ 0x47, 0xF8, 0xF8, 0x1D, 0x47, 0xF8, 0xF8, 0x1D, 0x47, 0xF8, 0xF8, 0x1D, ++ 0x47, 0xF8, 0xF8, 0x1D, 0x55, 0x4F, 0x4F, 0x00, 0x4B, 0xF8, 0xF8, 0x1D, ++ 0x4A, 0xF8, 0xF8, 0x1D, 0x4A, 0xF8, 0xF8, 0x1D, 0x4A, 0xF8, 0xF8, 0x1D, ++ 0x53, 0x4E, 0x4E, 0x00, 0x49, 0xF8, 0xF8, 0x1D, 0x48, 0xF8, 0xF8, 0x1D, ++ 0x48, 0xF8, 0xF8, 0x1D, 0x48, 0xF8, 0xF8, 0x1D, 0x4D, 0x49, 0x49, 0x00, ++ 0x44, 0xF8, 0xF8, 0x1D, 0x44, 0xF8, 0xF8, 0x1D, 0x44, 0xF8, 0xF8, 0x1D, ++ 0x44, 0xF8, 0xF8, 0x1D, 0x8F, 0x51, 0x51, 0x00, 0x49, 0xF8, 0xF8, 0x1D, ++ 0x48, 0xF8, 0xF8, 0x1D, 0x48, 0xF8, 0xF8, 0x1D, 0x48, 0xF8, 0xF8, 0x1D, ++ 0x77, 0x42, 0x42, 0x00, 0x3F, 0xF8, 0xF8, 0x1D, 0x3C, 0xF8, 0xF8, 0x1D, ++ 0x3C, 0xF8, 0xF8, 0x1D, 0x3C, 0xF8, 0xF8, 0x1D, 0x75, 0x42, 0x42, 0x00, ++ 0x9E, 0xF8, 0xF8, 0x1D, 0x3C, 0xF8, 0xF8, 0x1D, 0x3C, 0xF8, 0xF8, 0x1D, ++ 0x3C, 0xF8, 0xF8, 0x1D, 0x5C, 0x55, 0x55, 0x00, 0x4C, 0xF8, 0xF8, 0x1D, ++ 0x4C, 0xF8, 0xF8, 0x1D, 0x4C, 0xF8, 0xF8, 0x1D, 0x4C, 0xF8, 0xF8, 0x1D, ++ 0x5C, 0x53, 0x53, 0x00, 0x4C, 0xF8, 0xF8, 0x1D, 0x4B, 0xF8, 0xF8, 0x1D, ++ 0x4B, 0xF8, 0xF8, 0x1D, 0x4B, 0xF8, 0xF8, 0x1D, 0x9E, 0xF8, 0xF8, 0x00, ++ 0x8C, 0xF8, 0xF8, 0x1D, 0x4A, 0xF8, 0xF8, 0x1D, 0x4A, 0xF8, 0xF8, 0x1D, ++ 0x4A, 0xF8, 0xF8, 0x1D, 0x40, 0x89, 0x89, 0x00, 0x46, 0xF8, 0xF8, 0x18, ++ 0x45, 0xF8, 0xCF, 0x18, 0x44, 0xF8, 0xCF, 0x18, 0x44, 0xF8, 0xCF, 0x18, ++ 0x5F, 0x56, 0x56, 0x00, 0x4F, 0xF8, 0xF8, 0x1D, 0x4F, 0xF8, 0xF8, 0x1D, ++ 0x4F, 0xF8, 0xF8, 0x1D, 0x4F, 0xF8, 0xF8, 0x1D, 0x5E, 0x55, 0x55, 0x00, ++ 0x4E, 0xF8, 0xF8, 0x1D, 0x4E, 0xF8, 0xF8, 0x1D, 0x4E, 0xF8, 0xF8, 0x1D, ++ 0x4E, 0xF8, 0xF8, 0x1D, 0x5F, 0x56, 0x56, 0x00, 0x4F, 0xF8, 0xF8, 0x1D, ++ 0x4F, 0xF8, 0xF8, 0x1D, 0x4F, 0xF8, 0xF8, 0x1D, 0x4F, 0xF8, 0xF8, 0x1D, ++ 0x61, 0x55, 0x55, 0x00, 0x50, 0xF8, 0xF8, 0x1D, 0x4E, 0xF8, 0xF8, 0x1D, ++ 0x4E, 0xF8, 0xF8, 0x1D, 0x4E, 0xF8, 0xF8, 0x1D, 0x5F, 0x53, 0x53, 0x00, ++ 0x4D, 0xF8, 0xF8, 0x1D, 0x4C, 0xF8, 0xF8, 0x1D, 0x4C, 0xF8, 0xF8, 0x1D, ++ 0x4C, 0xF8, 0xF8, 0x1D, 0x5F, 0x55, 0x55, 0x00, 0x4F, 0xF8, 0xF8, 0x1D, ++ 0x4E, 0xF8, 0xF8, 0x1D, 0x4E, 0xF8, 0xF8, 0x1D, 0x4E, 0xF8, 0xF8, 0x1D, ++ 0xAA, 0x55, 0x55, 0x00, 0x54, 0xF8, 0xF8, 0x1D, 0x4E, 0xF8, 0xF8, 0x1D, ++ 0x4E, 0xF8, 0xF8, 0x1D, 0x4E, 0xF8, 0xF8, 0x1D, 0xA6, 0x59, 0x59, 0x00, ++ 0x4D, 0xF8, 0xF8, 0x1D, 0x4C, 0xF8, 0xF8, 0x1D, 0x4C, 0xF8, 0xF8, 0x1D, ++ 0x4C, 0xF8, 0xF8, 0x1D, 0x9B, 0x4F, 0x4F, 0x00, 0x4E, 0xF8, 0xF8, 0x1D, ++ 0x46, 0xF8, 0xF8, 0x1D, 0x46, 0xF8, 0xF8, 0x1D, 0x46, 0xF8, 0xF8, 0x1D, ++ 0xA5, 0xF8, 0xF8, 0x00, 0x94, 0xF8, 0xF8, 0x1D, 0x4C, 0xF8, 0xF8, 0x1D, ++ 0x4C, 0xF8, 0xF8, 0x1D, 0x4C, 0xF8, 0xF8, 0x1D, 0xA4, 0x98, 0x98, 0x00, ++ 0x4D, 0xF8, 0xF8, 0x1D, 0x4C, 0xF8, 0xF8, 0x1D, 0x4C, 0xF8, 0xF8, 0x1D, ++ 0x4C, 0xF8, 0xF8, 0x1D, 0x86, 0x46, 0x46, 0x00, 0xB3, 0xF8, 0xF8, 0x1D, ++ 0x3D, 0xF8, 0xF8, 0x1D, 0x3D, 0xF8, 0xF8, 0x1D, 0x3D, 0xF8, 0xF8, 0x1D, ++ 0x40, 0x8E, 0x8E, 0x00, 0x48, 0xF8, 0xF8, 0x1A, 0x48, 0xF8, 0xDF, 0x1A, ++ 0x46, 0xF8, 0xDF, 0x1A, 0x46, 0xF8, 0xDF, 0x1A, 0x40, 0x7F, 0x7F, 0x00, ++ 0x75, 0xD2, 0xD2, 0x18, 0x3A, 0xD2, 0xD2, 0x18, 0x3A, 0xD2, 0xD2, 0x18, ++ 0x39, 0xD2, 0xD2, 0x18, 0x40, 0x45, 0x45, 0x00, 0x64, 0x86, 0x86, 0x0F, ++ 0x3E, 0x86, 0x86, 0x0F, 0x3D, 0x86, 0x86, 0x0F, 0x3D, 0x86, 0x86, 0x0F, ++ 0x64, 0x5C, 0x5C, 0x00, 0x56, 0xF8, 0xF8, 0x1D, 0x55, 0xF8, 0xF8, 0x1D, ++ 0x55, 0xF8, 0xF8, 0x1D, 0x55, 0xF8, 0xF8, 0x1D, 0x68, 0x5B, 0x5B, 0x00, ++ 0x58, 0xF8, 0xF8, 0x1D, 0x55, 0xF8, 0xF8, 0x1D, 0x55, 0xF8, 0xF8, 0x1D, ++ 0x55, 0xF8, 0xF8, 0x1D, 0x64, 0x5A, 0x5A, 0x00, 0x55, 0xF8, 0xF8, 0x1D, ++ 0x54, 0xF8, 0xF8, 0x1D, 0x54, 0xF8, 0xF8, 0x1D, 0x54, 0xF8, 0xF8, 0x1D, ++ 0xB5, 0x5A, 0x5A, 0x00, 0x5B, 0xF8, 0xF8, 0x1D, 0x55, 0xF8, 0xF8, 0x1D, ++ 0x54, 0xF8, 0xF8, 0x1D, 0x54, 0xF8, 0xF8, 0x1D, 0xB0, 0xF8, 0xF8, 0x00, ++ 0xA3, 0xF8, 0xF8, 0x1D, 0x52, 0xF8, 0xF8, 0x1D, 0x52, 0xF8, 0xF8, 0x1D, ++ 0x52, 0xF8, 0xF8, 0x1D, 0xAE, 0xA4, 0xA4, 0x00, 0x54, 0xF8, 0xF8, 0x1D, ++ 0x52, 0xF8, 0xF8, 0x1D, 0x52, 0xF8, 0xF8, 0x1D, 0x52, 0xF8, 0xF8, 0x1D, ++ 0x40, 0x9A, 0x9A, 0x00, 0x4E, 0xF8, 0xF8, 0x1D, 0x4D, 0xF8, 0xF8, 0x1D, ++ 0x4C, 0xF8, 0xF8, 0x1D, 0x4C, 0xF8, 0xF8, 0x1D, 0x40, 0x9C, 0x9C, 0x00, ++ 0x95, 0xF8, 0xF8, 0x1D, 0x49, 0xF8, 0xF8, 0x1D, 0x4A, 0xF8, 0xF8, 0x1D, ++ 0x4A, 0xF8, 0xF8, 0x1D, 0x40, 0x49, 0x49, 0x00, 0x6F, 0x97, 0x97, 0x11, ++ 0x42, 0x97, 0x97, 0x11, 0x41, 0x97, 0x97, 0x11, 0x41, 0x97, 0x97, 0x11, ++ 0x74, 0x6E, 0x6E, 0x00, 0x69, 0xF8, 0xF8, 0x1D, 0x69, 0xF8, 0xF8, 0x1D, ++ 0x69, 0xF8, 0xF8, 0x1D, 0x69, 0xF8, 0xF8, 0x1D, 0x40, 0x6E, 0x6E, 0x00, ++ 0x69, 0xF8, 0xDE, 0x1A, 0x69, 0xF8, 0xDE, 0x1A, 0x69, 0xF8, 0xDE, 0x1A, ++ 0x69, 0xF8, 0xDE, 0x1A, 0x40, 0x75, 0x75, 0x00, 0x6E, 0xF8, 0x78, 0x0D, ++ 0x6E, 0xF8, 0x78, 0x0D, 0x6E, 0xF8, 0x78, 0x0D, 0x6E, 0xF8, 0x79, 0x0D, ++ 0x85, 0x78, 0x78, 0x00, 0x73, 0xF8, 0xF8, 0x1D, 0x73, 0xF8, 0xF8, 0x1D, ++ 0x73, 0xF8, 0xF8, 0x1D, 0x73, 0xF8, 0xF8, 0x1D, 0x40, 0x78, 0x78, 0x00, ++ 0x73, 0xF8, 0xF8, 0x1D, 0x73, 0xF8, 0xF8, 0x1D, 0x73, 0xF8, 0xF8, 0x1D, ++ 0x73, 0xF8, 0xF8, 0x1D, 0x40, 0x78, 0x78, 0x00, 0x73, 0xF8, 0x81, 0x0E, ++ 0x73, 0xF8, 0x81, 0x0E, 0x73, 0xF8, 0x81, 0x0E, 0x73, 0xF8, 0x82, 0x0E, ++ 0x40, 0x40, 0x40, 0x00, 0x73, 0xF8, 0x82, 0x0E, 0x73, 0xF8, 0x82, 0x0E, ++ 0x73, 0xF8, 0x82, 0x0E, 0x73, 0xF8, 0x82, 0x0E, 0x40, 0x81, 0x81, 0x00, ++ 0x7E, 0xF8, 0x92, 0x10, 0x7E, 0xF8, 0x92, 0x10, 0x7E, 0xF8, 0x92, 0x10, ++ 0x7E, 0xF8, 0x92, 0x10, 0x40, 0x40, 0x40, 0x00, 0x7E, 0xF8, 0x92, 0x10, ++ 0x7E, 0xF8, 0x92, 0x10, 0x7E, 0xF8, 0x92, 0x10, 0x7E, 0xF8, 0x92, 0x10, ++ 0x40, 0x73, 0x73, 0x00, 0x6B, 0xB2, 0xB2, 0x14, 0x35, 0xB2, 0xB2, 0x14, ++ 0x35, 0xB2, 0xB2, 0x14, 0x35, 0xB2, 0xB2, 0x14, 0x40, 0x40, 0x40, 0x00, ++ 0x60, 0x82, 0x82, 0x0E, 0x3D, 0x82, 0x82, 0x0E, 0x3C, 0x82, 0x82, 0x0E, ++ 0x3C, 0x82, 0x82, 0x0E, 0x40, 0x40, 0x40, 0x00, 0x66, 0x8B, 0x8B, 0x0F, ++ 0x3F, 0x8B, 0x8B, 0x0F, 0x3D, 0x8B, 0x8B, 0x0F, 0x3D, 0x8B, 0x8B, 0x0F, ++ 0x40, 0x40, 0x40, 0x00, 0x3D, 0x68, 0x68, 0x0B, 0x1E, 0x68, 0x68, 0x0B, ++ 0x1E, 0x68, 0x68, 0x0B, 0x1E, 0x68, 0x68, 0x0B, 0x40, 0x22, 0x22, 0x00, ++ 0x18, 0x43, 0x43, 0x06, 0x29, 0x43, 0x43, 0x06, 0x18, 0x43, 0x43, 0x06, ++ 0x18, 0x43, 0x43, 0x06, 0x40, 0x40, 0x40, 0x00, 0x72, 0x9D, 0x9D, 0x12, ++ 0x43, 0x9D, 0x9D, 0x12, 0x41, 0x9D, 0x9D, 0x12, 0x41, 0x9D, 0x9D, 0x12, ++ 0x40, 0x40, 0x40, 0x00, 0x42, 0x75, 0x75, 0x0D, 0x20, 0x75, 0x75, 0x0D, ++ 0x20, 0x75, 0x75, 0x0D, 0x20, 0x75, 0x75, 0x0D, 0x40, 0x23, 0x23, 0x00, ++ 0x19, 0x4C, 0x4C, 0x08, 0x2C, 0x4C, 0x4C, 0x08, 0x19, 0x4C, 0x4C, 0x08, ++ 0x19, 0x4C, 0x4C, 0x08, 0x38, 0x48, 0x58, 0x68, 0x78, 0x88, 0x98, 0xA8, ++ 0xB8, 0xC8, 0xD8, 0xF8, 0x48, 0x58, 0x68, 0x78, 0x88, 0x98, 0xA8, 0xB8, ++ 0xC8, 0xD8, 0xE8, 0x08, 0x58, 0x68, 0x78, 0x88, 0x98, 0xA8, 0xB8, 0xC8, ++ 0xD8, 0xE8, 0xF8, 0x09, 0x01, 0x03, 0x1E, 0x00, 0x00, 0x75, 0x19, 0x03, ++ 0x00, 0x75, 0x19, 0x03, 0x80, 0x80, 0x80, 0x80, 0x22, 0x3E, 0x39, 0x00, ++ 0xB4, 0x00, 0x0F, 0x04, 0x63, 0xA3, 0xAC, 0x0F, 0x80, 0x80, 0x80, 0x80, ++ 0x22, 0x3E, 0x39, 0x00, 0xB4, 0x00, 0x0F, 0x04, 0x63, 0xA3, 0x8C, 0x0F, ++ 0x80, 0x80, 0x80, 0x80, 0x22, 0x3E, 0x39, 0x00, 0xB4, 0x00, 0x0F, 0x04, ++ 0x62, 0x03, 0x8D, 0x0F, 0x80, 0x80, 0x80, 0x80, 0x34, 0x3E, 0x39, 0x00, ++ 0xB4, 0x00, 0x0F, 0x44, 0x61, 0x03, 0x8D, 0x0F, 0x80, 0x80, 0x80, 0x80, ++ 0x46, 0x3E, 0x39, 0x00, 0xB4, 0x00, 0x0F, 0x84, 0x60, 0x23, 0x8D, 0x0F, ++ 0x80, 0x80, 0x80, 0x80, 0x58, 0x3E, 0x39, 0x00, 0xB4, 0x00, 0x0F, 0xC4, ++ 0x60, 0xE3, 0x0C, 0x0F, 0x80, 0x80, 0x80, 0x80, 0xB4, 0x3E, 0x39, 0x00, ++ 0xB4, 0x00, 0x0F, 0x44, 0x60, 0xE3, 0x8C, 0x0E, 0x80, 0x80, 0x80, 0x80, ++ 0x46, 0x3E, 0x39, 0x00, 0xB4, 0x00, 0x0F, 0x84, 0x60, 0xC3, 0x0C, 0x0E, ++ 0x80, 0x80, 0x80, 0x80, 0x22, 0x3E, 0x39, 0x00, 0xB4, 0x00, 0x0F, 0x04, ++ 0x60, 0xCB, 0x0C, 0x0E, 0x80, 0x80, 0x80, 0x80, 0x34, 0x3E, 0x39, 0x00, ++ 0xB4, 0x00, 0x0F, 0x44, 0x60, 0xB3, 0x0C, 0x0E, 0x80, 0x80, 0x80, 0x80, ++ 0x34, 0x3E, 0x2A, 0x00, 0xB5, 0x5A, 0x2F, 0x44, 0x60, 0xD3, 0x0C, 0x0E, ++ 0x80, 0x80, 0x80, 0x80, 0x34, 0x3E, 0x2A, 0x00, 0xB5, 0x5A, 0x2F, 0x44, ++ 0x60, 0x1B, 0x0F, 0x0E, 0x80, 0x80, 0x80, 0x80, 0xA2, 0x3E, 0x2A, 0x00, ++ 0xB5, 0x5A, 0x3F, 0x04, 0x60, 0x9B, 0x11, 0x0E, 0x80, 0x80, 0x80, 0x80, ++ 0xD8, 0x3E, 0x2A, 0x00, 0xB5, 0x5A, 0x3F, 0xC4, 0x60, 0xFB, 0x11, 0x0E, ++ 0x80, 0x80, 0x80, 0x80, 0x58, 0x3F, 0x2A, 0x00, 0xB5, 0x5A, 0x3F, 0xC4, ++ 0x60, 0xFB, 0x11, 0x0E, 0x80, 0x80, 0x80, 0x80, 0xD8, 0x3F, 0x2A, 0x00, ++ 0xB5, 0x5A, 0x3F, 0xC4, 0x60, 0xFB, 0x11, 0x0E, 0x80, 0x80, 0x80, 0x80, ++ 0x22, 0x2E, 0x39, 0x00, 0xB4, 0x00, 0x0F, 0x04, 0x63, 0xA3, 0xAC, 0x0F, ++ 0x80, 0x80, 0x80, 0x80, 0x22, 0x2E, 0x39, 0x00, 0xB4, 0x00, 0x0F, 0x04, ++ 0x63, 0xA3, 0x8C, 0x0F, 0x80, 0x80, 0x80, 0x80, 0x22, 0x2E, 0x39, 0x00, ++ 0xB4, 0x00, 0x0F, 0x04, 0x62, 0x03, 0x8D, 0x0F, 0x80, 0x80, 0x80, 0x80, ++ 0x34, 0x2E, 0x39, 0x00, 0xB4, 0x00, 0x0F, 0x44, 0x61, 0x03, 0x8D, 0x0F, ++ 0x80, 0x80, 0x80, 0x80, 0x46, 0x2E, 0x39, 0x00, 0xB4, 0x00, 0x0F, 0x84, ++ 0x60, 0x23, 0x8D, 0x0F, 0x80, 0x80, 0x80, 0x80, 0x58, 0x2E, 0x39, 0x00, ++ 0xB4, 0x00, 0x0F, 0xC4, 0x60, 0xE3, 0x0C, 0x0F, 0x80, 0x80, 0x80, 0x80, ++ 0xB4, 0x2E, 0x39, 0x00, 0xB4, 0x00, 0x0F, 0x44, 0x60, 0xE3, 0x8C, 0x0E, ++ 0x80, 0x80, 0x80, 0x80, 0x46, 0x2E, 0x39, 0x00, 0xB4, 0x00, 0x0F, 0x84, ++ 0x60, 0xC3, 0x0C, 0x0E, 0x80, 0x80, 0x80, 0x80, 0x22, 0x2E, 0x39, 0x00, ++ 0xB4, 0x00, 0x0F, 0x04, 0x60, 0xCB, 0x0C, 0x0E, 0x80, 0x80, 0x80, 0x80, ++ 0x34, 0x2E, 0x39, 0x00, 0xB4, 0x00, 0x0F, 0x44, 0x60, 0xB3, 0x0C, 0x0E, ++ 0x80, 0x80, 0x80, 0x80, 0x34, 0x2E, 0x2A, 0x00, 0xB5, 0x5A, 0x2F, 0x44, ++ 0x60, 0xD3, 0x0C, 0x0E, 0x80, 0x80, 0x80, 0x80, 0x34, 0x2E, 0x2A, 0x00, ++ 0xB5, 0x5A, 0x2F, 0x44, 0x60, 0x1B, 0x0F, 0x0E, 0x80, 0x80, 0x80, 0x80, ++ 0xA2, 0x2E, 0x2A, 0x00, 0xB5, 0x5A, 0x2F, 0x04, 0x60, 0x9B, 0x11, 0x0E, ++ 0x80, 0x80, 0x80, 0x80, 0xD8, 0x2E, 0x2A, 0x00, 0xB5, 0x5A, 0x2F, 0xC4, ++ 0x60, 0xFB, 0x11, 0x0E, 0x80, 0x80, 0x80, 0x80, 0x58, 0x2F, 0x2A, 0x00, ++ 0xB5, 0x5A, 0x2F, 0xC4, 0x60, 0xFB, 0x11, 0x0E, 0x80, 0x80, 0x80, 0x80, ++ 0xD8, 0x2F, 0x2A, 0x00, 0xB5, 0x5A, 0x2F, 0xC4, 0x60, 0xFB, 0x11, 0x0E, ++ 0x80, 0x80, 0x80, 0x80, 0x00, 0xBE, 0x7F, 0x00, 0x6C, 0x00, 0x0F, 0x03, ++ 0x60, 0xE7, 0x0C, 0xE8, 0x80, 0x80, 0x80, 0x80, 0x00, 0xBE, 0x7F, 0x00, ++ 0x6C, 0x00, 0x2F, 0x03, 0x60, 0xD7, 0x0C, 0xE8, 0x80, 0x80, 0x80, 0x80, ++ 0x00, 0xBE, 0x7F, 0x00, 0x6C, 0x00, 0xEF, 0x03, 0x60, 0x9F, 0x0D, 0xE8, ++ 0x80, 0x80, 0x80, 0x80, 0x6D, 0xBE, 0x7F, 0x00, 0x6C, 0x00, 0xEF, 0x83, ++ 0x60, 0x9F, 0x0D, 0xE8, 0x80, 0x80, 0x80, 0x80, 0x00, 0x3E, 0x55, 0x00, ++ 0xFC, 0x00, 0x6F, 0x1B, 0x60, 0x07, 0x0D, 0x78, 0x80, 0x80, 0x80, 0x80, ++ 0x00, 0x3E, 0x55, 0x00, 0xFC, 0x00, 0x6F, 0x1B, 0x60, 0x17, 0x0D, 0x78, ++ 0x80, 0x80, 0x80, 0x80, 0x12, 0x3E, 0x55, 0x00, 0xFC, 0x00, 0xEF, 0x5B, ++ 0x60, 0x1F, 0x0D, 0x78, 0x80, 0x80, 0x80, 0x80, 0x6D, 0x3E, 0x55, 0x00, ++ 0xFC, 0x00, 0xEF, 0x9B, 0x60, 0x9F, 0x0D, 0x68, 0x80, 0x80, 0x80, 0x80, ++ 0x00, 0x3E, 0x55, 0x00, 0xFC, 0x00, 0x2F, 0x1B, 0x60, 0x87, 0xEC, 0x79, ++ 0x80, 0x80, 0x80, 0x80, 0x00, 0x3E, 0x55, 0x00, 0xFC, 0x00, 0x6F, 0x1B, ++ 0x60, 0x87, 0xEC, 0x79, 0x80, 0x80, 0x80, 0x80, 0x00, 0x3E, 0x55, 0x00, ++ 0xFC, 0x00, 0x6F, 0x1B, 0x60, 0x07, 0xAD, 0x79, 0x80, 0x80, 0x80, 0x80, ++ 0x00, 0x3E, 0x55, 0x00, 0xFC, 0x00, 0x6F, 0x1B, 0x60, 0x07, 0x0D, 0x79, ++ 0x80, 0x80, 0x80, 0x80, 0x00, 0x3E, 0x55, 0x00, 0xFC, 0x00, 0x6F, 0x1B, ++ 0x60, 0x07, 0x0D, 0x78, 0x80, 0x80, 0x80, 0x80, 0x00, 0x3E, 0x55, 0x00, ++ 0xFC, 0x00, 0x6F, 0x1B, 0x60, 0x17, 0x0D, 0x78, 0x80, 0x80, 0x80, 0x80, ++ 0x12, 0x3E, 0x55, 0x00, 0xFC, 0x00, 0xEF, 0x5B, 0x60, 0x1F, 0x0D, 0x78, ++ 0x80, 0x80, 0x80, 0x80, 0x6D, 0x3E, 0x55, 0x00, 0xFC, 0x00, 0xEF, 0x9B, ++ 0x60, 0x9F, 0x0D, 0x68, 0x80, 0x80, 0x80, 0x80, 0x34, 0x3E, 0x39, 0x00, ++ 0xB4, 0x00, 0x19, 0x44, 0x70, 0xE3, 0xAC, 0x0F, 0x80, 0x80, 0x80, 0x80, ++ 0x46, 0x3E, 0x39, 0x00, 0xB4, 0x00, 0x19, 0x84, 0x70, 0x63, 0x8C, 0x0F, ++ 0x80, 0x80, 0x80, 0x80, 0x34, 0x3E, 0x39, 0x00, 0xB4, 0x00, 0x19, 0x44, ++ 0x70, 0x03, 0x11, 0x0F, 0x80, 0x80, 0x80, 0x80, 0x46, 0x3E, 0x39, 0x00, ++ 0xB4, 0x00, 0x19, 0x84, 0x70, 0x43, 0x8D, 0x0E, 0x80, 0x80, 0x80, 0x80, ++ 0x34, 0x3E, 0x39, 0x00, 0xB4, 0x00, 0x19, 0x44, 0x70, 0xE3, 0x10, 0x0E, ++ 0x80, 0x80, 0x80, 0x80, 0x58, 0x3E, 0xB9, 0x00, 0xB4, 0x00, 0x19, 0xC4, ++ 0x70, 0xE3, 0x0C, 0x0F, 0x80, 0x80, 0x80, 0x80, 0xB4, 0x3E, 0xB9, 0x00, ++ 0xB4, 0x00, 0x19, 0x44, 0x70, 0xC3, 0x8C, 0x0E, 0x80, 0x80, 0x80, 0x80, ++ 0x46, 0x3E, 0xB9, 0x00, 0xB4, 0x00, 0x19, 0x84, 0x70, 0x03, 0x11, 0x0E, ++ 0x80, 0x80, 0x80, 0x80, 0x34, 0x3E, 0xB9, 0x00, 0xB4, 0x00, 0x19, 0x44, ++ 0x70, 0xEB, 0x0C, 0x0E, 0x80, 0x80, 0x80, 0x80, 0x46, 0x3E, 0xB9, 0x00, ++ 0xB4, 0x00, 0x19, 0x84, 0x70, 0xD3, 0x0C, 0x0E, 0x80, 0x80, 0x80, 0x80, ++ 0x46, 0x3E, 0xAA, 0x00, 0xB5, 0x5A, 0x39, 0x84, 0x70, 0xF3, 0x0C, 0x0E, ++ 0x80, 0x80, 0x80, 0x80, 0x46, 0x3E, 0xAA, 0x00, 0xB5, 0x5A, 0x39, 0x84, ++ 0x70, 0x3B, 0x0D, 0x0E, 0x80, 0x80, 0x80, 0x80, 0xB4, 0x3E, 0xAA, 0x00, ++ 0xB5, 0x5A, 0x39, 0x44, 0x70, 0xBB, 0x11, 0x0E, 0x80, 0x80, 0x80, 0x80, ++ 0xEB, 0x3E, 0xAA, 0x00, 0xB5, 0x5A, 0x39, 0x04, 0x70, 0xFB, 0x11, 0x0E, ++ 0x80, 0x80, 0x80, 0x80, 0x6B, 0x3F, 0xAA, 0x00, 0xB5, 0x5A, 0x39, 0x04, ++ 0x70, 0xFB, 0x11, 0x0E, 0x80, 0x80, 0x80, 0x80, 0xEB, 0x3F, 0xAA, 0x00, ++ 0xB5, 0x5A, 0x39, 0x04, 0x70, 0xFB, 0x11, 0x0E, 0x80, 0x80, 0x80, 0x80, ++ 0x34, 0x2E, 0x39, 0x00, 0xB4, 0x00, 0x0F, 0x44, 0x70, 0xE3, 0xAC, 0x0F, ++ 0x80, 0x80, 0x80, 0x80, 0x46, 0x2E, 0x39, 0x00, 0xB4, 0x00, 0x0F, 0x84, ++ 0x70, 0x63, 0x8C, 0x0F, 0x80, 0x80, 0x80, 0x80, 0x34, 0x2E, 0x39, 0x00, ++ 0xB4, 0x00, 0x0F, 0x44, 0x70, 0x03, 0x11, 0x0F, 0x80, 0x80, 0x80, 0x80, ++ 0x46, 0x2E, 0x39, 0x00, 0xB4, 0x00, 0x0F, 0x84, 0x70, 0x43, 0x8D, 0x0E, ++ 0x80, 0x80, 0x80, 0x80, 0x34, 0x2E, 0x39, 0x00, 0xB4, 0x00, 0x0F, 0x44, ++ 0x70, 0xE3, 0x10, 0x0E, 0x80, 0x80, 0x80, 0x80, 0x58, 0x2E, 0xB9, 0x00, ++ 0xB4, 0x00, 0x0F, 0xC4, 0x70, 0xE3, 0x0C, 0x0F, 0x80, 0x80, 0x80, 0x80, ++ 0xB4, 0x2E, 0xB9, 0x00, 0xB4, 0x00, 0x0F, 0x44, 0x70, 0xC3, 0x8C, 0x0E, ++ 0x80, 0x80, 0x80, 0x80, 0x46, 0x2E, 0xB9, 0x00, 0xB4, 0x00, 0x0F, 0x84, ++ 0x70, 0x03, 0x11, 0x0E, 0x80, 0x80, 0x80, 0x80, 0x34, 0x2E, 0xB9, 0x00, ++ 0xB4, 0x00, 0x0F, 0x44, 0x70, 0xEB, 0x0C, 0x0E, 0x80, 0x80, 0x80, 0x80, ++ 0x46, 0x2E, 0xB9, 0x00, 0xB4, 0x00, 0x0F, 0x84, 0x70, 0xD3, 0x0C, 0x0E, ++ 0x80, 0x80, 0x80, 0x80, 0x46, 0x2E, 0xAA, 0x00, 0xB5, 0x5A, 0x2F, 0x84, ++ 0x70, 0xF3, 0x0C, 0x0E, 0x80, 0x80, 0x80, 0x80, 0x46, 0x2E, 0xAA, 0x00, ++ 0xB5, 0x5A, 0x2F, 0x84, 0x70, 0x3B, 0x0D, 0x0E, 0x80, 0x80, 0x80, 0x80, ++ 0xB4, 0x2E, 0xAA, 0x00, 0xB5, 0x5A, 0x2F, 0x44, 0x70, 0xBB, 0x11, 0x0E, ++ 0x80, 0x80, 0x80, 0x80, 0xEB, 0x2E, 0xAA, 0x00, 0xB5, 0x5A, 0x2F, 0x04, ++ 0x70, 0xFB, 0x11, 0x0E, 0x80, 0x80, 0x80, 0x80, 0x6B, 0x2F, 0xAA, 0x00, ++ 0xB5, 0x5A, 0x2F, 0x04, 0x70, 0xFB, 0x11, 0x0E, 0x80, 0x80, 0x80, 0x80, ++ 0xEB, 0x2F, 0xAA, 0x00, 0xB5, 0x5A, 0x2F, 0x04, 0x70, 0xFB, 0x11, 0x0E, ++ 0x7F, 0xC1, 0x9F, 0x00, 0x0A, 0x01, 0x82, 0x00, 0x0C, 0x81, 0x82, 0x00, ++ 0x10, 0x81, 0x82, 0x00, 0x10, 0x01, 0x83, 0x00, 0x16, 0x01, 0x83, 0x00, ++ 0x16, 0x01, 0x84, 0x00, 0x60, 0x01, 0x84, 0x00, 0x67, 0x01, 0x93, 0x00, ++ 0x67, 0x41, 0x99, 0x00, 0x7F, 0x41, 0x99, 0x00, 0x7F, 0xC1, 0x99, 0x00, ++ 0x7F, 0x81, 0x9A, 0x00, 0x7F, 0x81, 0x9B, 0x00, 0x3F, 0xC1, 0x9C, 0x00, ++ 0x3F, 0xC1, 0x8F, 0x00, 0x08, 0x01, 0x82, 0x00, 0x0A, 0x01, 0x82, 0x00, ++ 0x0C, 0x81, 0x82, 0x00, 0x10, 0x81, 0x82, 0x00, 0x10, 0x01, 0x83, 0x00, ++ 0x16, 0x01, 0x83, 0x00, 0x16, 0x01, 0x84, 0x00, 0x20, 0x01, 0x84, 0x00, ++ 0x20, 0x01, 0x85, 0x00, 0x20, 0x01, 0x8C, 0x00, 0x27, 0x81, 0x8C, 0x00, ++ 0x27, 0x01, 0x8E, 0x00, 0x27, 0x01, 0x9B, 0x00, 0x3F, 0x01, 0x9B, 0x00, ++ 0x3F, 0xC1, 0x9C, 0x00, 0x3F, 0xC1, 0x8F, 0x00, 0x00, 0xC6, 0xFF, 0x00, ++ 0x00, 0xC6, 0x40, 0x00, 0x00, 0x06, 0x41, 0x00, 0x00, 0x46, 0x41, 0x00, ++ 0x00, 0x86, 0x90, 0x00, 0x00, 0xC6, 0x90, 0x00, 0x00, 0x06, 0xB1, 0x00, ++ 0x00, 0x46, 0xB1, 0x00, 0x00, 0x86, 0xB1, 0x00, 0x00, 0x06, 0xB2, 0x00, ++ 0x00, 0xC6, 0xB2, 0x00, 0x00, 0x46, 0xB9, 0x00, 0x00, 0xC6, 0xB9, 0x00, ++ 0x00, 0x46, 0xBA, 0x00, 0x00, 0x46, 0xBB, 0x00, 0x00, 0xC6, 0xBC, 0x00, ++ 0x82, 0x01, 0x83, 0x01, 0x40, 0x02, 0x41, 0x02, 0x80, 0x02, 0x81, 0x02, ++ 0x82, 0x02, 0x83, 0x02, 0x40, 0x03, 0x41, 0x03, 0x80, 0x03, 0x81, 0x03, ++ 0x00, 0x04, 0x01, 0x04, 0x40, 0x04, 0x41, 0x04, 0x60, 0x60, 0x00, 0x00, ++ 0x3B, 0x18, 0xB3, 0x03, 0x68, 0x51, 0x2E, 0x1A, 0x48, 0x51, 0x2E, 0x1A, ++ 0x00, 0x00, 0x00, 0x00, 0x84, 0x18, 0x20, 0x56, 0x84, 0x18, 0x20, 0x56, ++ 0x00, 0x00, 0x00, 0x00, 0x08, 0x50, 0x2A, 0x7A, 0xC8, 0x50, 0x1B, 0x79, ++ 0xC8, 0xD0, 0x2A, 0x7A, 0x40, 0x40, 0x00, 0x00, 0x02, 0x00, 0x10, 0x00, ++ 0x64, 0x32, 0x00, 0x00, 0x00, 0x87, 0x93, 0x03, 0x00, 0x20, 0x03, 0x00, ++ 0x00, 0x20, 0x03, 0x00, 0x30, 0x75, 0x00, 0x00, 0xB0, 0xAD, 0x01, 0x00, ++ 0x20, 0xA1, 0x07, 0x00, 0x20, 0xA1, 0x07, 0x00, 0x20, 0xA1, 0x07, 0x00, ++ 0x20, 0xA1, 0x07, 0x00, 0x10, 0x27, 0x00, 0x00, 0x40, 0x0D, 0x03, 0x00, ++ 0x40, 0x00, 0x20, 0x00, 0x10, 0x27, 0x50, 0xC3, 0xA0, 0x0F, 0x40, 0x1F, ++ 0x84, 0x03, 0x05, 0x08, 0x01, 0x00, 0x00, 0x02, 0x60, 0x00, 0x00, 0x00, ++ 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x1A, 0x00, 0x20, 0x20, 0x00, 0x00, 0x20, 0x20, 0x1A, 0x00, ++ 0xE0, 0x57, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, ++ 0x40, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0xFC, 0x00, 0x00, ++ 0x00, 0xFC, 0x19, 0x00, 0xF4, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0xE0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x02, 0xFF, 0x71, 0x04, 0x00, 0x10, 0x0E, 0x00, 0x03, 0x01, 0x08, 0x8F, ++ 0x03, 0xE6, 0xE0, 0xD0, 0xD6, 0x06, 0xD6, 0x06, 0x00, 0x00, 0x01, 0xF3, ++ 0x01, 0x0A, 0x00, 0x0F, 0x08, 0x01, 0x09, 0x08, 0x08, 0x08, 0x08, 0x0A, ++ 0x09, 0x09, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ++ 0x03, 0x01, 0x00, 0x00, 0xBC, 0x06, 0x04, 0x04, 0x00, 0x00, 0x1C, 0x00, ++ 0x00, 0x80, 0x00, 0x00, 0x08, 0x0A, 0x02, 0x04, 0x01, 0x00, 0xF0, 0x00, ++ 0x08, 0x04, 0x00, 0x04, 0x04, 0x04, 0x09, 0x06, 0x04, 0x01, 0x04, 0x01, ++ 0x05, 0x14, 0x38, 0x01, 0x38, 0x01, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x8C, 0x00, 0x00, 0x00, ++ 0x7D, 0xA6, 0x12, 0x00, 0x91, 0xA1, 0x12, 0x00, 0xA5, 0xA6, 0x12, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0xA1, 0x12, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0xA1, 0x12, 0x00, ++ 0xD1, 0xA1, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7D, 0xA3, 0x12, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDD, 0x6D, 0x12, 0x00, ++ 0x88, 0x00, 0x00, 0x00, 0x8C, 0x00, 0x00, 0x00, 0x05, 0xC7, 0x12, 0x00, ++ 0xE1, 0xB8, 0x14, 0x00, 0x75, 0xBB, 0x14, 0x00, 0x2D, 0xBE, 0x14, 0x00, ++ 0xE9, 0xBC, 0x14, 0x00, 0x81, 0xBC, 0x14, 0x00, 0x29, 0xAC, 0x14, 0x00, ++ 0xFD, 0x0C, 0x15, 0x00, 0x1D, 0x0B, 0x15, 0x00, 0x6D, 0x08, 0x15, 0x00, ++ 0x0D, 0x07, 0x15, 0x00, 0x59, 0xC8, 0x13, 0x00, 0xF5, 0xE7, 0x13, 0x00, ++ 0xA1, 0xCE, 0x13, 0x00, 0x3D, 0xD1, 0x13, 0x00, 0x4D, 0xD0, 0x13, 0x00, ++ 0xF9, 0xD0, 0x13, 0x00, 0x05, 0xDD, 0x13, 0x00, 0xF1, 0xDD, 0x13, 0x00, ++ 0x95, 0xDE, 0x13, 0x00, 0x85, 0xE4, 0x13, 0x00, 0xF5, 0xE0, 0x13, 0x00, ++ 0xC1, 0xE3, 0x13, 0x00, 0xED, 0xCE, 0x13, 0x00, 0x59, 0xD6, 0x13, 0x00, ++ 0xF5, 0xD9, 0x13, 0x00, 0x3D, 0xD5, 0x13, 0x00, 0xA9, 0xD4, 0x13, 0x00, ++ 0x91, 0xD8, 0x13, 0x00, 0x31, 0xD9, 0x13, 0x00, 0xC1, 0xD8, 0x13, 0x00, ++ 0x21, 0xD4, 0x13, 0x00, 0x4D, 0xDB, 0x13, 0x00, 0x71, 0xCA, 0x13, 0x00, ++ 0xE5, 0xC9, 0x13, 0x00, 0xAD, 0xC0, 0x13, 0x00, 0xCD, 0xC6, 0x13, 0x00, ++ 0x39, 0xC0, 0x13, 0x00, 0x79, 0xD6, 0x13, 0x00, 0xE5, 0xD7, 0x13, 0x00, ++ 0xF1, 0xC7, 0x13, 0x00, 0xDD, 0xE4, 0x13, 0x00, 0xA1, 0xE6, 0x13, 0x00, ++ 0x21, 0xD2, 0x13, 0x00, 0x6D, 0xD4, 0x13, 0x00, 0x99, 0xEA, 0x13, 0x00, ++ 0x71, 0x50, 0x14, 0x00, 0x71, 0x58, 0x14, 0x00, 0x25, 0x06, 0x12, 0x00, ++ 0x7D, 0x4B, 0x14, 0x00, 0x19, 0x4B, 0x14, 0x00, 0xF9, 0x5E, 0x12, 0x00, ++ 0xD1, 0x5E, 0x12, 0x00, 0xF1, 0x1C, 0x14, 0x00, 0x19, 0x1E, 0x14, 0x00, ++ 0xE9, 0x14, 0x14, 0x00, 0xD9, 0x16, 0x14, 0x00, 0x91, 0x17, 0x14, 0x00, ++ 0xC9, 0x1A, 0x14, 0x00, 0xF1, 0x19, 0x14, 0x00, 0x3D, 0x15, 0x14, 0x00, ++ 0xA5, 0x1B, 0x14, 0x00, 0x25, 0x1B, 0x14, 0x00, 0x1D, 0x90, 0x12, 0x00, ++ 0x7D, 0x93, 0x12, 0x00, 0xD1, 0x9E, 0x12, 0x00, 0x71, 0x8E, 0x12, 0x00, ++ 0xF5, 0xAA, 0x12, 0x00, 0xC5, 0x78, 0x12, 0x00, 0x05, 0x69, 0x12, 0x00, ++ 0x39, 0x69, 0x12, 0x00, 0x8D, 0x52, 0x12, 0x00, 0x7D, 0x50, 0x12, 0x00, ++ 0xD9, 0x55, 0x12, 0x00, 0xC1, 0x51, 0x12, 0x00, 0x79, 0x51, 0x12, 0x00, ++ 0x5D, 0xB2, 0x12, 0x00, 0x8D, 0x0C, 0x15, 0x00, 0x61, 0x4C, 0x14, 0x00, ++ 0xF9, 0x0E, 0x12, 0x00, 0x49, 0x07, 0x12, 0x00, 0x55, 0x59, 0x14, 0x00, ++ 0xD5, 0x58, 0x14, 0x00, 0x49, 0x5A, 0x14, 0x00, 0x05, 0x5A, 0x14, 0x00, ++ 0xD9, 0x80, 0x14, 0x00, 0xD9, 0x5A, 0x14, 0x00, 0x45, 0x79, 0x14, 0x00, ++ 0x7D, 0x7D, 0x13, 0x00, 0xA1, 0x78, 0x13, 0x00, 0xB5, 0x7E, 0x13, 0x00, ++ 0xF1, 0x85, 0x13, 0x00, 0xD5, 0xB6, 0x13, 0x00, 0x91, 0xBC, 0x13, 0x00, ++ 0xF1, 0xB5, 0x13, 0x00, 0x19, 0xBB, 0x13, 0x00, 0x5D, 0xBB, 0x13, 0x00, ++ 0xD5, 0xBC, 0x13, 0x00, 0xDD, 0xB8, 0x13, 0x00, 0x8D, 0xB8, 0x13, 0x00, ++ 0xFD, 0xBD, 0x13, 0x00, 0x21, 0xB8, 0x13, 0x00, 0xC5, 0x8C, 0x13, 0x00, ++ 0x09, 0x8C, 0x13, 0x00, 0xE9, 0x72, 0x13, 0x00, 0x59, 0x87, 0x13, 0x00, ++ 0xCD, 0x73, 0x13, 0x00, 0x31, 0x84, 0x13, 0x00, 0x25, 0x80, 0x13, 0x00, ++ 0x35, 0x83, 0x13, 0x00, 0xFD, 0x80, 0x13, 0x00, 0xE9, 0x8B, 0x13, 0x00, ++ 0x01, 0x8E, 0x13, 0x00, 0x55, 0x89, 0x13, 0x00, 0xD9, 0x89, 0x13, 0x00, ++ 0x91, 0x7D, 0x13, 0x00, 0x4D, 0x75, 0x13, 0x00, 0xA5, 0xB3, 0x13, 0x00, ++ 0x19, 0xB0, 0x13, 0x00, 0x01, 0xAF, 0x13, 0x00, 0x21, 0xAF, 0x13, 0x00, ++ 0x25, 0x05, 0x14, 0x00, 0xA9, 0xFF, 0x13, 0x00, 0xB1, 0xFE, 0x13, 0x00, ++ 0xC5, 0xFF, 0x13, 0x00, 0x81, 0xFF, 0x13, 0x00, 0x69, 0x06, 0x14, 0x00, ++ 0x49, 0x03, 0x14, 0x00, 0x2D, 0x0A, 0x14, 0x00, 0x25, 0x08, 0x14, 0x00, ++ 0x3D, 0x09, 0x14, 0x00, 0xF9, 0x07, 0x14, 0x00, 0x59, 0xFB, 0x13, 0x00, ++ 0x35, 0x04, 0x14, 0x00, 0xF5, 0xF6, 0x13, 0x00, 0x89, 0xF4, 0x13, 0x00, ++ 0xA5, 0x13, 0x12, 0x00, 0x5D, 0x10, 0x12, 0x00, 0xC1, 0x0B, 0x12, 0x00, ++ 0x49, 0x11, 0x12, 0x00, 0x4D, 0x02, 0x12, 0x00, 0xDD, 0xEA, 0x13, 0x00, ++ 0x01, 0xEE, 0x13, 0x00, 0xA9, 0xF0, 0x13, 0x00, 0x79, 0xEF, 0x13, 0x00, ++ 0x49, 0xF1, 0x13, 0x00, 0xE5, 0xF1, 0x13, 0x00, 0x85, 0xEC, 0x13, 0x00, ++ 0x45, 0xED, 0x13, 0x00, 0xA5, 0xED, 0x13, 0x00, 0x3D, 0xEB, 0x13, 0x00, ++ 0x45, 0xEF, 0x13, 0x00, 0xA1, 0xF2, 0x13, 0x00, 0xC5, 0xF3, 0x13, 0x00, ++ 0x85, 0x49, 0x15, 0x00, 0x01, 0x35, 0x15, 0x00, 0xCD, 0x42, 0x12, 0x00, ++ 0x71, 0xCB, 0x12, 0x00, 0x35, 0xCF, 0x12, 0x00, 0xAD, 0xD3, 0x12, 0x00, ++ 0x9D, 0xCB, 0x12, 0x00, 0xFD, 0xD4, 0x12, 0x00, 0xFD, 0x48, 0x13, 0x00, ++ 0x69, 0x4B, 0x13, 0x00, 0x21, 0x4C, 0x13, 0x00, 0x15, 0x46, 0x13, 0x00, ++ 0x99, 0x50, 0x13, 0x00, 0x9D, 0x5C, 0x13, 0x00, 0x79, 0x5C, 0x13, 0x00, ++ 0xED, 0x53, 0x13, 0x00, 0xE5, 0x56, 0x13, 0x00, 0x81, 0x4F, 0x13, 0x00, ++ 0x61, 0x4E, 0x13, 0x00, 0x29, 0x4D, 0x13, 0x00, 0x01, 0x40, 0x13, 0x00, ++ 0xED, 0x4C, 0x13, 0x00, 0x1D, 0x52, 0x13, 0x00, 0xDD, 0xDB, 0x14, 0x00, ++ 0xB5, 0xEB, 0x14, 0x00, 0x19, 0xD9, 0x14, 0x00, 0xA5, 0xDF, 0x14, 0x00, ++ 0xB5, 0xE0, 0x14, 0x00, 0xE9, 0xDE, 0x14, 0x00, 0x15, 0xE3, 0x14, 0x00, ++ 0xD9, 0xE5, 0x14, 0x00, 0x5D, 0xD7, 0x14, 0x00, 0xED, 0xD6, 0x14, 0x00, ++ 0x21, 0x13, 0x14, 0x00, 0x85, 0x14, 0x14, 0x00, 0x05, 0xD1, 0x14, 0x00, ++ 0x8D, 0x85, 0x12, 0x00, 0xD1, 0x80, 0x12, 0x00, 0xCD, 0x7D, 0x12, 0x00, ++ 0xED, 0x7F, 0x12, 0x00, 0x45, 0x7A, 0x12, 0x00, 0x01, 0x7F, 0x12, 0x00, ++ 0xD5, 0x99, 0x14, 0x00, 0xED, 0x9A, 0x14, 0x00, 0x31, 0x62, 0x13, 0x00, ++ 0x29, 0x5F, 0x13, 0x00, 0x65, 0x63, 0x13, 0x00, 0x41, 0x61, 0x13, 0x00, ++ 0x71, 0x5F, 0x12, 0x00, 0xB9, 0x24, 0x12, 0x00, 0xD9, 0x0D, 0x14, 0x00, ++ 0x61, 0x0C, 0x14, 0x00, 0x79, 0x20, 0x14, 0x00, 0x05, 0x20, 0x14, 0x00, ++ 0xC1, 0x20, 0x14, 0x00, 0x55, 0xD6, 0x12, 0x00, 0x4D, 0x1B, 0x13, 0x00, ++ 0x99, 0x0E, 0x13, 0x00, 0x11, 0x0C, 0x13, 0x00, 0x65, 0x0D, 0x13, 0x00, ++ 0xD1, 0x19, 0x13, 0x00, 0x5D, 0x13, 0x13, 0x00, 0x79, 0x0A, 0x13, 0x00, ++ 0x8D, 0x21, 0x13, 0x00, 0x2D, 0x15, 0x13, 0x00, 0x19, 0x21, 0x13, 0x00, ++ 0x79, 0x07, 0x13, 0x00, 0xCD, 0xF3, 0x12, 0x00, 0x31, 0xD7, 0x12, 0x00, ++ 0x41, 0xD8, 0x12, 0x00, 0xA1, 0xD8, 0x12, 0x00, 0x69, 0xFC, 0x12, 0x00, ++ 0x15, 0xFD, 0x12, 0x00, 0xF5, 0xE7, 0x12, 0x00, 0xB5, 0xE2, 0x12, 0x00, ++ 0xE5, 0xEA, 0x12, 0x00, 0xF5, 0xEB, 0x12, 0x00, 0xED, 0xE6, 0x12, 0x00, ++ 0xF9, 0xDD, 0x12, 0x00, 0x89, 0xE2, 0x12, 0x00, 0xD1, 0xFD, 0x12, 0x00, ++ 0xD5, 0xE7, 0x12, 0x00, 0xD5, 0x30, 0x13, 0x00, 0x91, 0x36, 0x13, 0x00, ++ 0xD5, 0x3A, 0x13, 0x00, 0x7D, 0x3C, 0x13, 0x00, 0xDD, 0x26, 0x13, 0x00, ++ 0x49, 0x27, 0x13, 0x00, 0xA9, 0x25, 0x13, 0x00, 0xCD, 0x35, 0x13, 0x00, ++ 0x71, 0x25, 0x13, 0x00, 0x89, 0x2C, 0x13, 0x00, 0x75, 0x30, 0x13, 0x00, ++ 0x81, 0x3A, 0x13, 0x00, 0x05, 0x3A, 0x13, 0x00, 0x49, 0x3D, 0x13, 0x00, ++ 0xB1, 0x2B, 0x13, 0x00, 0x21, 0x2F, 0x13, 0x00, 0xBD, 0x39, 0x13, 0x00, ++ 0x59, 0x28, 0x13, 0x00, 0xCD, 0x2A, 0x13, 0x00, 0x61, 0x37, 0x13, 0x00, ++ 0x01, 0xDB, 0x12, 0x00, 0xF1, 0xE2, 0x12, 0x00, 0x81, 0xD9, 0x12, 0x00, ++ 0x35, 0xEE, 0x12, 0x00, 0xC5, 0xEF, 0x12, 0x00, 0x49, 0xED, 0x12, 0x00, ++ 0x69, 0xFD, 0x14, 0x00, 0x39, 0xF9, 0x14, 0x00, 0x71, 0xF4, 0x14, 0x00, ++ 0x79, 0xF9, 0x14, 0x00, 0x09, 0xFC, 0x14, 0x00, 0xC5, 0xF3, 0x14, 0x00, ++ 0xDD, 0x60, 0x12, 0x00, 0xB1, 0xAD, 0x12, 0x00, 0xBD, 0xAE, 0x12, 0x00, ++ 0x29, 0xAF, 0x12, 0x00, 0xA5, 0xA4, 0x12, 0x00, 0xD1, 0xA5, 0x12, 0x00, ++ 0xD9, 0x6C, 0x13, 0x00, 0xF5, 0x6E, 0x13, 0x00, 0x1D, 0x64, 0x13, 0x00, ++ 0x2D, 0x6E, 0x13, 0x00, 0x51, 0x65, 0x13, 0x00, 0xB5, 0x6E, 0x13, 0x00, ++ 0x2D, 0x6F, 0x13, 0x00, 0xC1, 0x68, 0x13, 0x00, 0x91, 0xBE, 0x12, 0x00, ++ 0x29, 0xC4, 0x12, 0x00, 0x95, 0xBB, 0x12, 0x00, 0xDD, 0x03, 0x12, 0x00, ++ 0x19, 0xC5, 0x12, 0x00, 0xCD, 0xC6, 0x12, 0x00, 0x2D, 0x1E, 0x12, 0x00, ++ 0x61, 0x1B, 0x12, 0x00, 0x69, 0x1D, 0x12, 0x00, 0x7D, 0x9D, 0x12, 0x00, ++ 0xA9, 0x9D, 0x12, 0x00, 0x39, 0x12, 0x14, 0x00, 0x99, 0x71, 0x13, 0x00, ++ 0xC1, 0x21, 0x12, 0x00, 0x51, 0x09, 0x12, 0x00, 0x9D, 0x0A, 0x12, 0x00, ++ 0xA1, 0x0A, 0x12, 0x00, 0xBD, 0x0B, 0x12, 0x00, 0x41, 0x1C, 0x12, 0x00, ++ 0xD5, 0xCF, 0x12, 0x00, 0x21, 0xD1, 0x12, 0x00, 0xD1, 0x3C, 0x12, 0x00, ++ 0xC5, 0x4B, 0x12, 0x00, 0xA1, 0x4D, 0x12, 0x00, 0x6D, 0x4C, 0x12, 0x00, ++ 0xAD, 0x4A, 0x12, 0x00, 0x71, 0xC0, 0x12, 0x00, 0x19, 0xC2, 0x12, 0x00, ++ 0x79, 0xB8, 0x12, 0x00, 0x29, 0x9A, 0x12, 0x00, 0x39, 0x93, 0x12, 0x00, ++ 0xA1, 0x65, 0x12, 0x00, 0xCD, 0xB1, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xC2, 0x03, 0x00, 0x00, ++ 0x02, 0x00, 0x00, 0x00, 0x75, 0x95, 0x13, 0x00, 0x04, 0x00, 0x00, 0x00, ++ 0xFD, 0x8F, 0x13, 0x00, 0x06, 0x00, 0x00, 0x00, 0xF1, 0xA9, 0x13, 0x00, ++ 0x08, 0x00, 0x00, 0x00, 0xF1, 0xA9, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x31, 0x93, 0x13, 0x00, 0x10, 0x00, 0x00, 0x00, 0xF1, 0xA9, 0x13, 0x00, ++ 0x16, 0x00, 0x00, 0x00, 0xF1, 0xA9, 0x13, 0x00, 0x14, 0x00, 0x00, 0x00, ++ 0xF1, 0xA9, 0x13, 0x00, 0x12, 0x00, 0x00, 0x00, 0xF1, 0xA9, 0x13, 0x00, ++ 0x0E, 0x00, 0x00, 0x00, 0xF1, 0xA9, 0x13, 0x00, 0x18, 0x00, 0x00, 0x00, ++ 0xF1, 0xA9, 0x13, 0x00, 0x1A, 0x00, 0x00, 0x00, 0xCD, 0x90, 0x13, 0x00, ++ 0x6B, 0x00, 0x00, 0x00, 0xF5, 0x96, 0x13, 0x00, 0x6D, 0x00, 0x00, 0x00, ++ 0xD1, 0x97, 0x13, 0x00, 0x71, 0x00, 0x00, 0x00, 0x19, 0x93, 0x13, 0x00, ++ 0x6F, 0x00, 0x00, 0x00, 0x79, 0x91, 0x13, 0x00, 0x20, 0x00, 0x00, 0x00, ++ 0xF1, 0xA9, 0x13, 0x00, 0x1C, 0x00, 0x00, 0x00, 0xF1, 0xA9, 0x13, 0x00, ++ 0x1E, 0x00, 0x00, 0x00, 0xF1, 0xA9, 0x13, 0x00, 0x30, 0x00, 0x00, 0x00, ++ 0xF1, 0xA9, 0x13, 0x00, 0x22, 0x00, 0x00, 0x00, 0x09, 0xA0, 0x13, 0x00, ++ 0x84, 0x00, 0x00, 0x00, 0xAD, 0xA0, 0x13, 0x00, 0x2E, 0x00, 0x00, 0x00, ++ 0x4D, 0x8E, 0x13, 0x00, 0x24, 0x00, 0x00, 0x00, 0xA9, 0x93, 0x13, 0x00, ++ 0x26, 0x00, 0x00, 0x00, 0x4D, 0x94, 0x13, 0x00, 0x0A, 0x00, 0x00, 0x00, ++ 0x9D, 0x8E, 0x13, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x9D, 0x91, 0x13, 0x00, ++ 0x28, 0x00, 0x00, 0x00, 0xF1, 0xA9, 0x13, 0x00, 0x2A, 0x00, 0x00, 0x00, ++ 0xF1, 0x97, 0x13, 0x00, 0x39, 0x00, 0x00, 0x00, 0xC5, 0x91, 0x13, 0x00, ++ 0x3B, 0x00, 0x00, 0x00, 0xF1, 0xA9, 0x13, 0x00, 0x46, 0x00, 0x00, 0x00, ++ 0xCD, 0x8E, 0x13, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x21, 0x8E, 0x13, 0x00, ++ 0x41, 0x00, 0x00, 0x00, 0x91, 0x98, 0x13, 0x00, 0x31, 0x00, 0x00, 0x00, ++ 0x35, 0x8E, 0x13, 0x00, 0x4B, 0x00, 0x00, 0x00, 0xA9, 0x94, 0x13, 0x00, ++ 0x51, 0x00, 0x00, 0x00, 0x59, 0x8F, 0x13, 0x00, 0x52, 0x00, 0x00, 0x00, ++ 0xB5, 0x9F, 0x13, 0x00, 0x56, 0x00, 0x00, 0x00, 0x15, 0x95, 0x13, 0x00, ++ 0x87, 0x00, 0x00, 0x00, 0xF1, 0xA9, 0x13, 0x00, 0x61, 0x00, 0x00, 0x00, ++ 0x21, 0x97, 0x13, 0x00, 0x63, 0x00, 0x00, 0x00, 0x9D, 0x98, 0x13, 0x00, ++ 0x65, 0x00, 0x00, 0x00, 0xE9, 0x91, 0x13, 0x00, 0x67, 0x00, 0x00, 0x00, ++ 0x0D, 0x96, 0x13, 0x00, 0x69, 0x00, 0x00, 0x00, 0xF1, 0x9C, 0x13, 0x00, ++ 0x73, 0x00, 0x00, 0x00, 0xE9, 0x98, 0x13, 0x00, 0x75, 0x00, 0x00, 0x00, ++ 0x0D, 0x8F, 0x13, 0x00, 0x77, 0x00, 0x00, 0x00, 0xA5, 0x92, 0x13, 0x00, ++ 0x79, 0x00, 0x00, 0x00, 0xCD, 0x92, 0x13, 0x00, 0x7B, 0x00, 0x00, 0x00, ++ 0xE1, 0x9B, 0x13, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x59, 0x99, 0x13, 0x00, ++ 0x80, 0x00, 0x00, 0x00, 0xBD, 0x96, 0x13, 0x00, 0x82, 0x00, 0x00, 0x00, ++ 0x11, 0x9B, 0x13, 0x00, 0x00, 0x08, 0x00, 0x00, 0xB9, 0x0E, 0x14, 0x00, ++ 0x85, 0x00, 0x00, 0x00, 0x4D, 0x0F, 0x14, 0x00, 0x86, 0x00, 0x00, 0x00, ++ 0xC9, 0x0F, 0x14, 0x00, 0x03, 0x08, 0x00, 0x00, 0x71, 0x10, 0x14, 0x00, ++ 0x0D, 0xCD, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0xB0, 0x13, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0xA1, 0x28, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x2D, 0x4C, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9D, 0x2F, 0x14, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x85, 0x84, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xB5, 0x7F, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB5, 0x7F, 0x13, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x3D, 0x6D, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x85, 0x4A, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0xF2, 0x14, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0xFD, 0x48, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xD1, 0x78, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x13, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0xD1, 0xF4, 0x12, 0x00, 0x04, 0x00, 0x00, 0x00, ++ 0xD1, 0xF4, 0x12, 0x00, 0x03, 0x00, 0x00, 0x00, 0xD1, 0xF4, 0x12, 0x00, ++ 0x02, 0x00, 0x00, 0x00, 0xD1, 0xF4, 0x12, 0x00, 0x01, 0x00, 0x00, 0x00, ++ 0xD1, 0xF4, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF9, 0x4C, 0x14, 0x00, ++ 0x04, 0x00, 0x00, 0x00, 0xD1, 0xF4, 0x12, 0x00, 0x05, 0x00, 0x00, 0x00, ++ 0xF9, 0x4C, 0x14, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF9, 0x4C, 0x14, 0x00, ++ 0x02, 0x00, 0x00, 0x00, 0xF9, 0x4C, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, ++ 0xF9, 0x4C, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0x69, 0x12, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x11, 0x6D, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x69, 0x6D, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x6D, 0x12, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0xBD, 0x6D, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x15, 0x4A, 0x14, 0x00, ++ 0x02, 0x04, 0x00, 0x00, 0xB5, 0x49, 0x14, 0x00, 0x04, 0x04, 0x00, 0x00, ++ 0x2D, 0x48, 0x14, 0x00, 0x06, 0x04, 0x00, 0x00, 0xF9, 0x47, 0x14, 0x00, ++ 0x09, 0x04, 0x00, 0x00, 0x95, 0x49, 0x14, 0x00, 0x11, 0x04, 0x00, 0x00, ++ 0x11, 0x49, 0x14, 0x00, 0x0B, 0x04, 0x00, 0x00, 0xC1, 0x4A, 0x14, 0x00, ++ 0x0D, 0x04, 0x00, 0x00, 0x45, 0x4A, 0x14, 0x00, 0x0F, 0x04, 0x00, 0x00, ++ 0x61, 0x48, 0x14, 0x00, 0x1B, 0x04, 0x00, 0x00, 0x91, 0x47, 0x14, 0x00, ++ 0x1E, 0x04, 0x00, 0x00, 0x75, 0x47, 0x14, 0x00, 0x1F, 0x04, 0x00, 0x00, ++ 0x59, 0x47, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x34, 0x17, 0x00, ++ 0x00, 0x14, 0x00, 0x00, 0xBD, 0x68, 0x14, 0x00, 0x02, 0x14, 0x00, 0x00, ++ 0xED, 0x65, 0x14, 0x00, 0x04, 0x14, 0x00, 0x00, 0x01, 0x67, 0x14, 0x00, ++ 0x07, 0x14, 0x00, 0x00, 0x01, 0x6A, 0x14, 0x00, 0x09, 0x14, 0x00, 0x00, ++ 0x75, 0x67, 0x14, 0x00, 0x17, 0x14, 0x00, 0x00, 0xB1, 0x72, 0x14, 0x00, ++ 0x19, 0x14, 0x00, 0x00, 0xB5, 0x6E, 0x14, 0x00, 0x0C, 0x14, 0x00, 0x00, ++ 0x01, 0x68, 0x14, 0x00, 0x18, 0x14, 0x00, 0x00, 0x89, 0x31, 0x14, 0x00, ++ 0x23, 0x00, 0x00, 0x00, 0x45, 0x6F, 0x14, 0x00, 0x13, 0x14, 0x00, 0x00, ++ 0x45, 0x73, 0x14, 0x00, 0x32, 0x00, 0x00, 0x00, 0x9D, 0x6F, 0x14, 0x00, ++ 0x15, 0x14, 0x00, 0x00, 0x11, 0x66, 0x14, 0x00, 0x0D, 0x00, 0x00, 0x00, ++ 0x89, 0x31, 0x14, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x89, 0x31, 0x14, 0x00, ++ 0x42, 0x00, 0x00, 0x00, 0x89, 0x31, 0x14, 0x00, 0x1B, 0x00, 0x00, 0x00, ++ 0x89, 0x31, 0x14, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x89, 0x31, 0x14, 0x00, ++ 0x6E, 0x00, 0x00, 0x00, 0x89, 0x31, 0x14, 0x00, 0x70, 0x00, 0x00, 0x00, ++ 0x89, 0x31, 0x14, 0x00, 0x72, 0x00, 0x00, 0x00, 0x89, 0x31, 0x14, 0x00, ++ 0x0E, 0x14, 0x00, 0x00, 0xF5, 0x6F, 0x14, 0x00, 0x10, 0x14, 0x00, 0x00, ++ 0xF1, 0x70, 0x14, 0x00, 0x11, 0x14, 0x00, 0x00, 0x91, 0x71, 0x14, 0x00, ++ 0x00, 0x18, 0x00, 0x00, 0x1D, 0x8A, 0x14, 0x00, 0x03, 0x18, 0x00, 0x00, ++ 0x6D, 0x92, 0x14, 0x00, 0x01, 0x10, 0x00, 0x00, 0xA1, 0x8C, 0x14, 0x00, ++ 0x03, 0x10, 0x00, 0x00, 0x09, 0x8D, 0x14, 0x00, 0x08, 0x18, 0x00, 0x00, ++ 0x71, 0x8C, 0x14, 0x00, 0x43, 0x00, 0x00, 0x00, 0x21, 0x8C, 0x14, 0x00, ++ 0x0B, 0x00, 0x00, 0x00, 0x8D, 0x92, 0x14, 0x00, 0x18, 0x14, 0x00, 0x00, ++ 0xA5, 0x90, 0x14, 0x00, 0x19, 0x00, 0x00, 0x00, 0xE5, 0x8F, 0x14, 0x00, ++ 0x17, 0x00, 0x00, 0x00, 0xE5, 0x8F, 0x14, 0x00, 0x15, 0x00, 0x00, 0x00, ++ 0xE5, 0x8F, 0x14, 0x00, 0x72, 0x00, 0x00, 0x00, 0xE5, 0x8F, 0x14, 0x00, ++ 0x1B, 0x00, 0x00, 0x00, 0xE5, 0x8F, 0x14, 0x00, 0x1F, 0x00, 0x00, 0x00, ++ 0xD9, 0x94, 0x14, 0x00, 0x1A, 0x14, 0x00, 0x00, 0x7D, 0x8F, 0x14, 0x00, ++ 0x4C, 0x00, 0x00, 0x00, 0x89, 0x31, 0x14, 0x00, 0x0D, 0x00, 0x00, 0x00, ++ 0x25, 0x90, 0x14, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x65, 0x90, 0x14, 0x00, ++ 0x00, 0x28, 0x00, 0x00, 0x99, 0x91, 0x14, 0x00, 0x07, 0x18, 0x00, 0x00, ++ 0xFD, 0x91, 0x14, 0x00, 0x09, 0x18, 0x00, 0x00, 0x19, 0x92, 0x14, 0x00, ++ 0x00, 0x1C, 0x00, 0x00, 0xF5, 0xB3, 0x14, 0x00, 0x02, 0x1C, 0x00, 0x00, ++ 0xD5, 0xB6, 0x14, 0x00, 0x18, 0x14, 0x00, 0x00, 0xD9, 0xB7, 0x14, 0x00, ++ 0x40, 0x00, 0x00, 0x00, 0xBD, 0xB2, 0x14, 0x00, 0x19, 0x00, 0x00, 0x00, ++ 0x01, 0xB6, 0x14, 0x00, 0x17, 0x00, 0x00, 0x00, 0x01, 0xB6, 0x14, 0x00, ++ 0x15, 0x00, 0x00, 0x00, 0x01, 0xB6, 0x14, 0x00, 0x1A, 0x14, 0x00, 0x00, ++ 0x9D, 0xB5, 0x14, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x81, 0xB6, 0x14, 0x00, ++ 0x3A, 0x00, 0x00, 0x00, 0x41, 0xB6, 0x14, 0x00, 0x04, 0x1C, 0x00, 0x00, ++ 0x01, 0xB3, 0x14, 0x00, 0x06, 0x1C, 0x00, 0x00, 0x39, 0xB7, 0x14, 0x00, ++ 0x08, 0x1C, 0x00, 0x00, 0x59, 0xB5, 0x14, 0x00, 0x00, 0x10, 0x00, 0x00, ++ 0x8D, 0x31, 0x14, 0x00, 0x02, 0x10, 0x00, 0x00, 0x8D, 0x31, 0x14, 0x00, ++ 0x05, 0x10, 0x00, 0x00, 0x8D, 0x31, 0x14, 0x00, 0x00, 0x28, 0x00, 0x00, ++ 0x89, 0x31, 0x14, 0x00, 0x00, 0x10, 0x00, 0x00, 0x95, 0xBF, 0x14, 0x00, ++ 0x02, 0x10, 0x00, 0x00, 0xF5, 0xC0, 0x14, 0x00, 0x05, 0x10, 0x00, 0x00, ++ 0xF5, 0xBF, 0x14, 0x00, 0x07, 0x10, 0x00, 0x00, 0xF1, 0xC1, 0x14, 0x00, ++ 0x0A, 0x10, 0x00, 0x00, 0x7D, 0xC0, 0x14, 0x00, 0x01, 0x08, 0x00, 0x00, ++ 0x39, 0xC2, 0x14, 0x00, 0x02, 0x08, 0x00, 0x00, 0x85, 0xC2, 0x14, 0x00, ++ 0x00, 0x28, 0x00, 0x00, 0xA1, 0xC2, 0x14, 0x00, 0x0A, 0x10, 0x00, 0x00, ++ 0x51, 0xC0, 0x14, 0x00, 0x04, 0x08, 0x00, 0x00, 0x4D, 0xC2, 0x14, 0x00, ++ 0x00, 0x10, 0x00, 0x00, 0xD5, 0xC0, 0x14, 0x00, 0x07, 0x10, 0x00, 0x00, ++ 0xA1, 0xC0, 0x14, 0x00, 0xDC, 0x05, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, ++ 0x45, 0x04, 0x15, 0x00, 0x01, 0x20, 0x00, 0x00, 0x69, 0x04, 0x15, 0x00, ++ 0x2B, 0x00, 0x00, 0x00, 0xC5, 0x00, 0x15, 0x00, 0x29, 0x00, 0x00, 0x00, ++ 0x55, 0xFF, 0x14, 0x00, 0x00, 0x28, 0x00, 0x00, 0x35, 0x01, 0x15, 0x00, ++ 0x0D, 0x26, 0x40, 0x80, 0x80, 0x80, 0x80, 0x80, ++}; ++ ++char fw_adid_u03[1208] = { ++ 0x61, 0xBD, 0x08, 0x00, 0xFD, 0x7D, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x7D, 0x03, 0x08, 0x00, 0x71, 0x02, 0x08, 0x00, ++ 0x21, 0x04, 0x08, 0x00, 0xD9, 0x0A, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x39, 0x0F, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDD, 0x15, 0x08, 0x00, ++ 0x6D, 0x18, 0x08, 0x00, 0xD1, 0x18, 0x08, 0x00, 0x15, 0x19, 0x08, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0xF5, 0x1D, 0x08, 0x00, 0xA1, 0x24, 0x08, 0x00, ++ 0x05, 0x26, 0x08, 0x00, 0x3D, 0x2A, 0x08, 0x00, 0x9D, 0x55, 0x08, 0x00, ++ 0x39, 0x76, 0x08, 0x00, 0x91, 0x76, 0x08, 0x00, 0x9D, 0x7C, 0x08, 0x00, ++ 0xE5, 0x7C, 0x08, 0x00, 0x5D, 0x80, 0x08, 0x00, 0x75, 0xA9, 0x08, 0x00, ++ 0x9D, 0xBE, 0x08, 0x00, 0xD5, 0xBE, 0x08, 0x00, 0x39, 0xC0, 0x08, 0x00, ++ 0x6D, 0xC2, 0x08, 0x00, 0x3D, 0x05, 0x09, 0x00, 0xF1, 0x3B, 0x09, 0x00, ++ 0x31, 0x3E, 0x09, 0x00, 0xFD, 0x40, 0x09, 0x00, 0x65, 0x9D, 0x09, 0x00, ++ 0x25, 0xC0, 0x09, 0x00, 0xF9, 0xBB, 0x09, 0x00, 0x05, 0xA2, 0x09, 0x00, ++ 0x91, 0xD7, 0x09, 0x00, 0x4D, 0xB2, 0x0A, 0x00, 0x25, 0xB6, 0x0A, 0x00, ++ 0x75, 0xB8, 0x0A, 0x00, 0x2D, 0xB9, 0x0A, 0x00, 0x8D, 0xBB, 0x0A, 0x00, ++ 0x99, 0xBC, 0x0A, 0x00, 0xA1, 0xC5, 0x0A, 0x00, 0x31, 0xCD, 0x0A, 0x00, ++ 0x09, 0xDE, 0x0A, 0x00, 0xB9, 0xEE, 0x0A, 0x00, 0x35, 0x58, 0x09, 0x00, ++ 0xB1, 0x58, 0x09, 0x00, 0x15, 0x54, 0x09, 0x00, 0xBD, 0x56, 0x09, 0x00, ++ 0x11, 0x5B, 0x09, 0x00, 0xED, 0x5C, 0x09, 0x00, 0x15, 0x6C, 0x09, 0x00, ++ 0xB9, 0x60, 0x09, 0x00, 0xDD, 0x29, 0x0B, 0x00, 0x05, 0x76, 0x09, 0x00, ++ 0x75, 0x76, 0x09, 0x00, 0x3D, 0x7A, 0x09, 0x00, 0x5D, 0x7E, 0x09, 0x00, ++ 0x69, 0x78, 0x09, 0x00, 0x61, 0x79, 0x09, 0x00, 0xD9, 0x7E, 0x09, 0x00, ++ 0x35, 0x41, 0x0B, 0x00, 0xB5, 0x08, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xCD, 0x0C, 0x0B, 0x00, 0x85, 0x6F, 0x09, 0x00, 0xD5, 0x7B, 0x0B, 0x00, ++ 0x75, 0x7C, 0x0B, 0x00, 0xDD, 0x6C, 0x09, 0x00, 0xA9, 0x6D, 0x09, 0x00, ++ 0x75, 0x6E, 0x09, 0x00, 0xE9, 0x1F, 0x0B, 0x00, 0x35, 0x23, 0x0B, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0xA1, 0x1B, 0x0B, 0x00, 0x45, 0x27, 0x0B, 0x00, ++ 0x85, 0x1A, 0x0B, 0x00, 0x69, 0x17, 0x0B, 0x00, 0xDD, 0x27, 0x0B, 0x00, ++ 0x31, 0x2B, 0x0B, 0x00, 0x25, 0x78, 0x0B, 0x00, 0x15, 0x65, 0x0B, 0x00, ++ 0x3D, 0x6B, 0x0B, 0x00, 0x9D, 0x67, 0x0B, 0x00, 0x99, 0x6B, 0x0B, 0x00, ++ 0xC5, 0x6C, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2D, 0xAF, 0x0B, 0x00, ++ 0x3D, 0x99, 0x0C, 0x00, 0xC5, 0xD9, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x95, 0x0C, 0x00, ++ 0x3D, 0xD5, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF5, 0xA4, 0x08, 0x00, ++ 0xB5, 0xA5, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xFD, 0x50, 0x08, 0x00, 0x9D, 0x7D, 0x08, 0x00, 0xBD, 0x7D, 0x08, 0x00, ++ 0xDD, 0x7D, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xA9, 0x91, 0x08, 0x00, 0xAB, 0x91, 0x08, 0x00, 0xAD, 0x91, 0x08, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x71, 0xD5, 0x09, 0x00, 0x6D, 0x0E, 0x08, 0x00, ++}; ++ ++char fw_patch_table_u03[1256] = { ++ 0x41, 0x49, 0x43, 0x42, 0x54, 0x5F, 0x50, 0x54, 0x5F, 0x54, 0x41, 0x47, ++ 0x00, 0x00, 0x00, 0x00, 0x41, 0x49, 0x43, 0x42, 0x54, 0x5F, 0x54, 0x52, ++ 0x41, 0x50, 0x5F, 0x54, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, ++ 0x21, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x16, 0x00, 0x04, 0x23, 0xA3, 0x55, ++ 0x00, 0x10, 0x08, 0x40, 0x88, 0x48, 0x0C, 0x00, 0x04, 0xF0, 0x16, 0x00, ++ 0x00, 0x2B, 0x05, 0xE0, 0x04, 0x10, 0x08, 0x40, 0x58, 0x58, 0x0B, 0x00, ++ 0x08, 0xF0, 0x16, 0x00, 0x00, 0x2B, 0xB1, 0xE7, 0x08, 0x10, 0x08, 0x40, ++ 0x30, 0x5A, 0x0B, 0x00, 0x14, 0xEA, 0x16, 0x00, 0x02, 0x49, 0x8E, 0x46, ++ 0x18, 0xEA, 0x16, 0x00, 0x00, 0xB5, 0x02, 0x4B, 0x1C, 0xEA, 0x16, 0x00, ++ 0xDB, 0x6E, 0x00, 0xBD, 0x20, 0xEA, 0x16, 0x00, 0xD7, 0xCB, 0x0A, 0x00, ++ 0x24, 0xEA, 0x16, 0x00, 0xAC, 0x2B, 0x16, 0x00, 0x0C, 0xF0, 0x16, 0x00, ++ 0xC1, 0xF0, 0x1F, 0xFF, 0x0C, 0x10, 0x08, 0x40, 0xD2, 0xCB, 0x0A, 0x00, ++ 0x00, 0xEA, 0x16, 0x00, 0x02, 0x49, 0x8E, 0x46, 0x04, 0xEA, 0x16, 0x00, ++ 0x00, 0xB5, 0x02, 0x4B, 0x08, 0xEA, 0x16, 0x00, 0xDA, 0x6E, 0x00, 0xBD, ++ 0x0C, 0xEA, 0x16, 0x00, 0xC1, 0xE6, 0x0A, 0x00, 0x10, 0xEA, 0x16, 0x00, ++ 0xAC, 0x2B, 0x16, 0x00, 0x10, 0xF0, 0x16, 0x00, 0xC0, 0xF0, 0xA0, 0xF9, ++ 0x10, 0x10, 0x08, 0x40, 0xBC, 0xE6, 0x0A, 0x00, 0x14, 0xF0, 0x16, 0x00, ++ 0x43, 0x1C, 0x05, 0xE0, 0x14, 0x10, 0x08, 0x40, 0x1C, 0xFD, 0x0C, 0x00, ++ 0x30, 0xEA, 0x16, 0x00, 0x01, 0x4B, 0x98, 0x47, 0x34, 0xEA, 0x16, 0x00, ++ 0x01, 0x4B, 0x9F, 0x46, 0x38, 0xEA, 0x16, 0x00, 0xD9, 0x97, 0x10, 0x00, ++ 0x3C, 0xEA, 0x16, 0x00, 0x59, 0x1E, 0x0D, 0x00, 0x18, 0xF0, 0x16, 0x00, ++ 0x9C, 0xF0, 0x92, 0xFF, 0x18, 0x10, 0x08, 0x40, 0x08, 0x1B, 0x0D, 0x00, ++ 0x1C, 0xF0, 0x16, 0x00, 0xEC, 0xE1, 0x10, 0x00, 0x1C, 0x10, 0x08, 0x40, ++ 0x30, 0xB8, 0x0B, 0x00, 0x84, 0x10, 0x08, 0x40, 0x00, 0xF0, 0x16, 0x00, ++ 0x80, 0x10, 0x08, 0x40, 0xFF, 0x00, 0x00, 0x00, 0x58, 0x00, 0x10, 0x40, ++ 0x00, 0x00, 0x00, 0x00, 0x41, 0x49, 0x43, 0x42, 0x54, 0x5F, 0x50, 0x41, ++ 0x54, 0x43, 0x48, 0x5F, 0x54, 0x42, 0x34, 0x00, 0x02, 0x00, 0x00, 0x00, ++ 0x2C, 0x00, 0x00, 0x00, 0x38, 0x1B, 0x16, 0x00, 0x99, 0x12, 0x10, 0x00, ++ 0x98, 0x19, 0x16, 0x00, 0xA9, 0x23, 0x10, 0x00, 0x18, 0x1B, 0x16, 0x00, ++ 0x81, 0x07, 0x10, 0x00, 0x20, 0x1B, 0x16, 0x00, 0xCD, 0x09, 0x10, 0x00, ++ 0x28, 0x1B, 0x16, 0x00, 0xF1, 0x0B, 0x10, 0x00, 0xB0, 0x19, 0x16, 0x00, ++ 0x21, 0x25, 0x10, 0x00, 0x70, 0x1A, 0x16, 0x00, 0xB9, 0x30, 0x10, 0x00, ++ 0x6C, 0x1A, 0x16, 0x00, 0x19, 0x64, 0x10, 0x00, 0xE0, 0x1A, 0x16, 0x00, ++ 0xB9, 0x69, 0x10, 0x00, 0xE0, 0x19, 0x16, 0x00, 0xCB, 0x09, 0x10, 0x00, ++ 0xDC, 0x19, 0x16, 0x00, 0xC9, 0x09, 0x10, 0x00, 0x38, 0x19, 0x16, 0x00, ++ 0x89, 0x54, 0x10, 0x00, 0x1C, 0x1B, 0x16, 0x00, 0x69, 0x56, 0x10, 0x00, ++ 0x24, 0x1B, 0x16, 0x00, 0x75, 0x58, 0x10, 0x00, 0x7C, 0x1D, 0x16, 0x00, ++ 0xDD, 0x5B, 0x10, 0x00, 0xB0, 0x1A, 0x16, 0x00, 0xB9, 0x5A, 0x10, 0x00, ++ 0xB0, 0x1D, 0x16, 0x00, 0x31, 0x6D, 0x10, 0x00, 0x8C, 0x1D, 0x16, 0x00, ++ 0x19, 0x6E, 0x10, 0x00, 0x88, 0x1D, 0x16, 0x00, 0x49, 0x6E, 0x10, 0x00, ++ 0x40, 0x19, 0x16, 0x00, 0xF5, 0x6E, 0x10, 0x00, 0x2C, 0x1B, 0x16, 0x00, ++ 0x51, 0x6F, 0x10, 0x00, 0x80, 0x1D, 0x16, 0x00, 0xC1, 0x5F, 0x10, 0x00, ++ 0xF4, 0x19, 0x16, 0x00, 0x89, 0x6F, 0x10, 0x00, 0xEC, 0x19, 0x16, 0x00, ++ 0x0D, 0x70, 0x10, 0x00, 0x54, 0x19, 0x16, 0x00, 0x31, 0x93, 0x10, 0x00, ++ 0x14, 0x1B, 0x16, 0x00, 0x35, 0x94, 0x10, 0x00, 0x8C, 0x19, 0x16, 0x00, ++ 0xE9, 0x71, 0x10, 0x00, 0x88, 0x19, 0x16, 0x00, 0xB9, 0x7A, 0x10, 0x00, ++ 0x04, 0x1B, 0x16, 0x00, 0x35, 0x97, 0x10, 0x00, 0x90, 0x19, 0x16, 0x00, ++ 0xFD, 0x9E, 0x10, 0x00, 0x94, 0x19, 0x16, 0x00, 0x5D, 0x9F, 0x10, 0x00, ++ 0xE8, 0x19, 0x16, 0x00, 0x3D, 0xA2, 0x10, 0x00, 0xE4, 0x1A, 0x16, 0x00, ++ 0x35, 0x02, 0x10, 0x00, 0xD4, 0x1A, 0x16, 0x00, 0x69, 0xA2, 0x10, 0x00, ++ 0x64, 0x1A, 0x16, 0x00, 0x29, 0x33, 0x10, 0x00, 0x08, 0x1B, 0x16, 0x00, ++ 0x55, 0x91, 0x10, 0x00, 0xBC, 0x19, 0x16, 0x00, 0x31, 0x38, 0x10, 0x00, ++ 0x68, 0x1A, 0x16, 0x00, 0x79, 0x61, 0x10, 0x00, 0x40, 0x1A, 0x16, 0x00, ++ 0x8D, 0x40, 0x10, 0x00, 0x3C, 0x1A, 0x16, 0x00, 0x41, 0x07, 0x10, 0x00, ++ 0x4C, 0x1A, 0x16, 0x00, 0x85, 0x54, 0x10, 0x00, 0xB8, 0x19, 0x16, 0x00, ++ 0x9D, 0x3B, 0x10, 0x00, 0x7C, 0x1A, 0x16, 0x00, 0x41, 0x2A, 0x10, 0x00, ++ 0x68, 0xAD, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x49, 0x43, 0x42, ++ 0x54, 0x5F, 0x4D, 0x4F, 0x44, 0x45, 0x5F, 0x54, 0x00, 0x00, 0x00, 0x00, ++ 0x03, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xA4, 0xE5, 0x10, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0xC0, 0xE5, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x54, 0xE0, 0x10, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x50, 0xE0, 0x10, 0x00, ++ 0xFF, 0x00, 0x00, 0x00, 0xA8, 0xE5, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, ++ 0xB8, 0xE5, 0x10, 0x00, 0x60, 0xE3, 0x16, 0x00, 0xBC, 0xE5, 0x10, 0x00, ++ 0x01, 0x00, 0x00, 0x00, 0xAC, 0xE5, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xB0, 0xE5, 0x10, 0x00, 0x20, 0x60, 0x00, 0x00, 0x41, 0x49, 0x43, 0x42, ++ 0x54, 0x5F, 0x50, 0x4F, 0x57, 0x45, 0x52, 0x5F, 0x4F, 0x4E, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x50, 0x40, ++ 0x00, 0x00, 0x08, 0x00, 0x24, 0x01, 0x50, 0x40, 0x40, 0x00, 0x00, 0x00, ++ 0x41, 0x49, 0x43, 0x42, 0x54, 0x5F, 0x50, 0x41, 0x54, 0x43, 0x48, 0x5F, ++ 0x54, 0x41, 0x46, 0x00, 0x05, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, ++ 0x24, 0x0A, 0x16, 0x00, 0x65, 0x7E, 0x10, 0x00, 0xA4, 0x12, 0x16, 0x00, ++ 0x1D, 0x84, 0x10, 0x00, 0xBC, 0x12, 0x16, 0x00, 0xFD, 0xA3, 0x10, 0x00, ++ 0xC4, 0x12, 0x16, 0x00, 0xE9, 0xB2, 0x10, 0x00, 0x0C, 0x08, 0x16, 0x00, ++ 0x1D, 0xA3, 0x10, 0x00, 0x5C, 0x07, 0x16, 0x00, 0x45, 0xA3, 0x10, 0x00, ++ 0x84, 0x15, 0x16, 0x00, 0xB9, 0x89, 0x10, 0x00, 0x4C, 0x18, 0x16, 0x00, ++ 0x65, 0x8B, 0x10, 0x00, 0x6C, 0x18, 0x16, 0x00, 0xE9, 0x8B, 0x10, 0x00, ++ 0xDC, 0x18, 0x16, 0x00, 0x35, 0x8C, 0x10, 0x00, 0xF4, 0x1A, 0x16, 0x00, ++ 0x99, 0x05, 0x10, 0x00, 0xAC, 0x12, 0x16, 0x00, 0x35, 0x76, 0x10, 0x00, ++ 0x04, 0x10, 0x16, 0x00, 0xD1, 0x8E, 0x10, 0x00, 0x0C, 0x10, 0x16, 0x00, ++ 0x25, 0x90, 0x10, 0x00, 0x84, 0x10, 0x16, 0x00, 0x41, 0xAA, 0x10, 0x00, ++ 0x9C, 0x10, 0x16, 0x00, 0xB1, 0xAA, 0x10, 0x00, 0xA4, 0x10, 0x16, 0x00, ++ 0x71, 0xAB, 0x10, 0x00, 0x4C, 0x10, 0x16, 0x00, 0x5D, 0xAC, 0x10, 0x00, ++ 0xE4, 0x0F, 0x16, 0x00, 0x65, 0x90, 0x10, 0x00, 0xEC, 0x13, 0x16, 0x00, ++ 0xC5, 0xA7, 0x10, 0x00, 0x0C, 0x13, 0x16, 0x00, 0x55, 0xB3, 0x10, 0x00, ++ 0xFC, 0x12, 0x16, 0x00, 0x1D, 0x26, 0x10, 0x00, 0x74, 0x0A, 0x16, 0x00, ++ 0xED, 0x27, 0x10, 0x00, 0x74, 0x13, 0x16, 0x00, 0x35, 0xA8, 0x10, 0x00, ++ 0x04, 0x14, 0x16, 0x00, 0xD9, 0xA8, 0x10, 0x00, 0x4C, 0x14, 0x16, 0x00, ++ 0xB1, 0xAE, 0x10, 0x00, 0x3C, 0x0A, 0x16, 0x00, 0x05, 0xAF, 0x10, 0x00, ++ 0x44, 0x0A, 0x16, 0x00, 0xF1, 0xAF, 0x10, 0x00, 0x04, 0x15, 0x16, 0x00, ++ 0x51, 0x91, 0x10, 0x00, 0x2C, 0x13, 0x16, 0x00, 0xA1, 0x42, 0x10, 0x00, ++ 0xD4, 0x0A, 0x16, 0x00, 0xED, 0xAD, 0x10, 0x00, 0x44, 0x11, 0x16, 0x00, ++ 0x51, 0xAD, 0x10, 0x00, 0xE4, 0x12, 0x16, 0x00, 0x09, 0xA7, 0x10, 0x00, ++ 0x7C, 0x09, 0x16, 0x00, 0x15, 0xCD, 0x10, 0x00, 0x8C, 0x09, 0x16, 0x00, ++ 0x4D, 0xCD, 0x10, 0x00, 0x94, 0x09, 0x16, 0x00, 0xC1, 0xCD, 0x10, 0x00, ++ 0x6C, 0x14, 0x16, 0x00, 0x71, 0xCD, 0x10, 0x00, 0x70, 0x30, 0x50, 0x40, ++ 0x00, 0x00, 0x00, 0x00, 0x74, 0x30, 0x50, 0x40, 0x00, 0x00, 0x00, 0x00, ++ 0x78, 0x30, 0x50, 0x40, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x30, 0x50, 0x40, ++ 0x00, 0x00, 0x00, 0x00, 0x41, 0x49, 0x43, 0x42, 0x54, 0x5F, 0x56, 0x45, ++ 0x52, 0x5F, 0x49, 0x4E, 0x46, 0x4F, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, ++ 0x08, 0x00, 0x00, 0x00, 0x2D, 0x20, 0x53, 0x65, 0x70, 0x20, 0x31, 0x33, ++ 0x20, 0x32, 0x30, 0x32, 0x32, 0x20, 0x31, 0x30, 0x3A, 0x33, 0x38, 0x3A, ++ 0x33, 0x39, 0x20, 0x2D, 0x20, 0x67, 0x69, 0x74, 0x20, 0x30, 0x61, 0x61, ++ 0x62, 0x66, 0x62, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++}; ++ ++char fw_patch_u03[59704] = { ++ 0x10, 0xB5, 0x15, 0x4B, 0x1B, 0x68, 0x02, 0x2B, 0x02, 0xD0, 0x14, 0x4B, ++ 0x98, 0x47, 0x10, 0xBD, 0x13, 0x4B, 0x1B, 0x68, 0x3F, 0x22, 0x9A, 0x5C, ++ 0x00, 0x2A, 0xF6, 0xD1, 0x3D, 0x32, 0x9C, 0x5C, 0x10, 0x4B, 0x1A, 0x78, ++ 0x01, 0x32, 0xD2, 0xB2, 0x10, 0x2A, 0x10, 0xD8, 0x1A, 0x70, 0x0D, 0x49, ++ 0x0A, 0x78, 0x12, 0x03, 0x92, 0xB2, 0x62, 0x23, 0x63, 0x43, 0x0B, 0x4C, ++ 0x1C, 0x19, 0x22, 0x80, 0x0A, 0x78, 0x12, 0x09, 0x09, 0x49, 0x8C, 0x46, ++ 0x63, 0x44, 0x1A, 0x80, 0xDD, 0xE7, 0x05, 0x4B, 0x00, 0x22, 0x1A, 0x70, ++ 0xEB, 0xE7, 0xC0, 0x46, 0x50, 0xE0, 0x10, 0x00, 0xC1, 0xE9, 0x0A, 0x00, ++ 0x28, 0x27, 0x16, 0x00, 0xB0, 0xE6, 0x10, 0x00, 0xFA, 0x64, 0x61, 0x40, ++ 0xFC, 0x64, 0x61, 0x40, 0x10, 0xB5, 0x04, 0x00, 0x0B, 0x4B, 0x1B, 0x68, ++ 0x00, 0x2B, 0x03, 0xD0, 0x3A, 0x22, 0x9B, 0x5C, 0x01, 0x2B, 0x06, 0xD0, ++ 0x20, 0x00, 0x08, 0x4B, 0x98, 0x47, 0x62, 0x68, 0x07, 0x4B, 0x1A, 0x60, ++ 0x10, 0xBD, 0x07, 0x49, 0x0B, 0x68, 0x07, 0x4A, 0x1A, 0x40, 0x80, 0x23, ++ 0x9B, 0x03, 0x13, 0x43, 0x0B, 0x60, 0xEF, 0xE7, 0x18, 0x27, 0x16, 0x00, ++ 0x25, 0xC3, 0x0C, 0x00, 0x30, 0xE6, 0x10, 0x00, 0x00, 0x04, 0x60, 0x40, ++ 0xFF, 0xFF, 0xDF, 0xFF, 0x10, 0xB5, 0x18, 0x4A, 0x00, 0x23, 0x00, 0x24, ++ 0x14, 0x57, 0x84, 0x42, 0x04, 0xDA, 0x01, 0x33, 0xDB, 0xB2, 0x01, 0x32, ++ 0x08, 0x2B, 0xF6, 0xD1, 0x12, 0x4A, 0xD2, 0x56, 0x82, 0x42, 0x05, 0xD0, ++ 0x00, 0x29, 0x03, 0xD1, 0x00, 0x2B, 0x01, 0xD0, 0x01, 0x3B, 0xDB, 0xB2, ++ 0x1A, 0x1C, 0x07, 0x2B, 0x00, 0xD9, 0x07, 0x22, 0xD2, 0xB2, 0x0C, 0x4B, ++ 0x99, 0x5C, 0x0C, 0x4A, 0x95, 0x23, 0x9B, 0x00, 0xD3, 0x5C, 0x1A, 0x1C, ++ 0xDB, 0xB2, 0x8B, 0x42, 0x00, 0xD9, 0x0A, 0x1C, 0x07, 0x49, 0x08, 0x4B, ++ 0xCB, 0x5C, 0x18, 0x1C, 0xDB, 0xB2, 0xD1, 0xB2, 0x8B, 0x42, 0x00, 0xD2, ++ 0x10, 0x1C, 0xC0, 0xB2, 0x10, 0xBD, 0xC0, 0x46, 0x28, 0xE0, 0x10, 0x00, ++ 0xBC, 0xDF, 0x10, 0x00, 0x7C, 0x1E, 0x16, 0x00, 0x55, 0x02, 0x00, 0x00, ++ 0x10, 0xB5, 0x62, 0x22, 0x42, 0x43, 0x0F, 0x4B, 0x9C, 0x46, 0x62, 0x44, ++ 0x13, 0x88, 0xDB, 0xB2, 0x1E, 0x2B, 0x13, 0xD0, 0x0C, 0x49, 0x0D, 0x48, ++ 0x0C, 0x5C, 0x0D, 0x48, 0x09, 0x5C, 0x09, 0x19, 0x01, 0x20, 0x8B, 0x42, ++ 0x09, 0xDB, 0x1B, 0x1B, 0xDB, 0xB2, 0x10, 0x2B, 0x08, 0xD0, 0x11, 0x88, ++ 0xFF, 0x20, 0x81, 0x43, 0x0B, 0x43, 0x13, 0x80, 0x00, 0x20, 0x10, 0xBD, ++ 0x0E, 0x3B, 0xE9, 0xE7, 0x0E, 0x33, 0xF4, 0xE7, 0x0C, 0x65, 0x61, 0x40, ++ 0x7C, 0x1E, 0x16, 0x00, 0x57, 0x02, 0x00, 0x00, 0x55, 0x02, 0x00, 0x00, ++ 0x30, 0xB5, 0x62, 0x22, 0x42, 0x43, 0x0F, 0x4B, 0x9C, 0x46, 0x62, 0x44, ++ 0x13, 0x88, 0xDB, 0xB2, 0x1E, 0x2B, 0x12, 0xD0, 0x0C, 0x49, 0x0D, 0x48, ++ 0x0C, 0x5C, 0x1D, 0x19, 0x03, 0x38, 0x09, 0x5C, 0x01, 0x20, 0x8D, 0x42, ++ 0x08, 0xDC, 0xEB, 0xB2, 0x10, 0x2B, 0x08, 0xD0, 0x11, 0x88, 0xFF, 0x20, ++ 0x81, 0x43, 0x0B, 0x43, 0x13, 0x80, 0x00, 0x20, 0x30, 0xBD, 0x0E, 0x3B, ++ 0xEA, 0xE7, 0x0E, 0x33, 0xF4, 0xE7, 0xC0, 0x46, 0x0C, 0x65, 0x61, 0x40, ++ 0x7C, 0x1E, 0x16, 0x00, 0x57, 0x02, 0x00, 0x00, 0x70, 0x47, 0x70, 0x47, ++ 0x70, 0xB5, 0x00, 0x28, 0x1C, 0xD0, 0x12, 0x4B, 0x1D, 0x68, 0x00, 0x2D, ++ 0x18, 0xD0, 0xE9, 0x78, 0x09, 0x02, 0x01, 0x23, 0x19, 0x43, 0x03, 0x33, ++ 0xFF, 0x22, 0x0E, 0x48, 0x81, 0xF7, 0xFA, 0xFE, 0x04, 0x1E, 0x0E, 0xD0, ++ 0x20, 0x00, 0x81, 0xF7, 0x1F, 0xFF, 0xAB, 0xF7, 0x23, 0xFB, 0x03, 0x00, ++ 0x09, 0x48, 0x6A, 0x68, 0x9B, 0x18, 0x1B, 0x01, 0x1B, 0x09, 0x43, 0x60, ++ 0xD6, 0xF7, 0x9E, 0xFE, 0x70, 0xBD, 0x06, 0x4B, 0x9B, 0x6E, 0x00, 0x22, ++ 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0xE9, 0xE7, 0xD8, 0xE5, 0x10, 0x00, ++ 0x3F, 0x06, 0x00, 0x00, 0xFC, 0xE6, 0x10, 0x00, 0x28, 0x19, 0x16, 0x00, ++ 0xF8, 0xB5, 0x05, 0x00, 0x22, 0x4B, 0x23, 0x4A, 0x13, 0x60, 0x02, 0x22, ++ 0xFF, 0x32, 0x9C, 0x5C, 0x21, 0x4B, 0xE2, 0x18, 0x12, 0x01, 0x13, 0x88, ++ 0x9B, 0x06, 0x5B, 0x0F, 0x01, 0x2B, 0x04, 0xD0, 0x13, 0x88, 0x9B, 0x06, ++ 0x5B, 0x0F, 0x02, 0x2B, 0x0F, 0xD1, 0x23, 0x01, 0x18, 0x49, 0x8C, 0x46, ++ 0x63, 0x44, 0x1B, 0x7B, 0x00, 0x2B, 0x05, 0xD1, 0x13, 0x88, 0x38, 0x21, ++ 0x8B, 0x43, 0x20, 0x39, 0x0B, 0x43, 0x13, 0x80, 0x15, 0x48, 0x83, 0xF7, ++ 0xB9, 0xFF, 0x15, 0x4B, 0x2A, 0x68, 0x9A, 0x42, 0x0F, 0xD0, 0x14, 0x4F, ++ 0xDE, 0x26, 0x76, 0x00, 0x00, 0x23, 0xBB, 0x51, 0x28, 0x00, 0xD7, 0xF7, ++ 0x4B, 0xF9, 0x11, 0x4B, 0xBB, 0x51, 0xAB, 0xF7, 0xD5, 0xFA, 0xA4, 0x00, ++ 0x0F, 0x4B, 0x18, 0x51, 0xF8, 0xBD, 0x0F, 0x4B, 0x1B, 0x68, 0x02, 0x2B, ++ 0xEB, 0xD1, 0x2B, 0x7C, 0x9B, 0x00, 0x0D, 0x4A, 0x94, 0x46, 0x63, 0x44, ++ 0x1B, 0x68, 0x0C, 0x4A, 0x12, 0x68, 0x1A, 0x66, 0x1A, 0x61, 0xE0, 0xE7, ++ 0x80, 0x2A, 0x16, 0x00, 0x0C, 0xE7, 0x10, 0x00, 0x00, 0x10, 0x06, 0x04, ++ 0xF8, 0xCD, 0x10, 0x00, 0xD1, 0x1F, 0x0D, 0x00, 0x28, 0x19, 0x16, 0x00, ++ 0x35, 0x02, 0x10, 0x00, 0xE0, 0xE5, 0x10, 0x00, 0x50, 0xE0, 0x10, 0x00, ++ 0xF4, 0x29, 0x16, 0x00, 0xE8, 0xE1, 0x10, 0x00, 0x30, 0xB5, 0x89, 0xB0, ++ 0x04, 0x1E, 0x32, 0xD0, 0x9E, 0x23, 0xC5, 0x5C, 0x1B, 0x4B, 0x00, 0x93, ++ 0x43, 0x68, 0x01, 0x93, 0x83, 0x68, 0x02, 0x93, 0x6B, 0x46, 0x1D, 0x76, ++ 0x04, 0x95, 0x18, 0x4B, 0x03, 0x93, 0x83, 0x7D, 0x6A, 0x46, 0x13, 0x75, ++ 0x01, 0x33, 0x53, 0x75, 0x00, 0x23, 0x93, 0x75, 0xB0, 0x22, 0x82, 0x5C, ++ 0x69, 0x46, 0xCA, 0x75, 0x8B, 0x76, 0xCB, 0x76, 0x01, 0x33, 0x4B, 0x76, ++ 0x68, 0x46, 0xD7, 0xF7, 0xFB, 0xF8, 0xA9, 0x22, 0xA3, 0x5C, 0x01, 0x33, ++ 0xA3, 0x54, 0x47, 0x3A, 0x6A, 0x43, 0x0C, 0x4B, 0x9C, 0x46, 0x62, 0x44, ++ 0x13, 0x88, 0xFF, 0x21, 0x8B, 0x43, 0x01, 0x21, 0x0B, 0x43, 0x9B, 0xB2, ++ 0x13, 0x80, 0xA0, 0x23, 0xE1, 0x54, 0x09, 0xB0, 0x30, 0xBD, 0x06, 0x4B, ++ 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0xF6, 0xE7, ++ 0xD1, 0xBD, 0x10, 0x00, 0xDE, 0x05, 0x00, 0x00, 0x1E, 0x65, 0x61, 0x40, ++ 0x28, 0x19, 0x16, 0x00, 0x30, 0xB5, 0x89, 0xB0, 0x03, 0x00, 0x0D, 0x00, ++ 0x89, 0x00, 0x2B, 0x4A, 0x8C, 0x58, 0x00, 0x2C, 0x36, 0xD0, 0xA6, 0x22, ++ 0xA2, 0x5C, 0x12, 0x1A, 0x03, 0x20, 0x10, 0x40, 0xC0, 0x18, 0x00, 0x01, ++ 0x00, 0x09, 0x63, 0x68, 0xC3, 0x1A, 0x1A, 0x01, 0x12, 0x09, 0x80, 0x21, ++ 0x09, 0x05, 0x8A, 0x42, 0x26, 0xD8, 0x1B, 0x01, 0x20, 0x2B, 0x23, 0xD9, ++ 0x20, 0x4B, 0x00, 0x93, 0x01, 0x90, 0xA3, 0x68, 0x02, 0x93, 0x6B, 0x46, ++ 0x1D, 0x76, 0x04, 0x95, 0x1D, 0x4B, 0x03, 0x93, 0xA3, 0x7D, 0x6A, 0x46, ++ 0x13, 0x75, 0x01, 0x33, 0x53, 0x75, 0x00, 0x23, 0x93, 0x75, 0xB0, 0x22, ++ 0xA2, 0x5C, 0x69, 0x46, 0xCA, 0x75, 0x8B, 0x76, 0xCB, 0x76, 0x01, 0x33, ++ 0x4B, 0x76, 0x68, 0x46, 0xD7, 0xF7, 0xA0, 0xF8, 0xA9, 0x22, 0xA3, 0x5C, ++ 0x01, 0x33, 0xA3, 0x54, 0x9F, 0x23, 0xE3, 0x5C, 0x01, 0x2B, 0x01, 0xD0, ++ 0x09, 0xB0, 0x30, 0xBD, 0xA3, 0x6F, 0x9B, 0xB2, 0x62, 0x21, 0x4D, 0x43, ++ 0x0D, 0x4A, 0xAA, 0x18, 0x13, 0x80, 0xA3, 0x6F, 0x1B, 0x0C, 0x0C, 0x4A, ++ 0xAA, 0x18, 0x13, 0x80, 0x0B, 0x4B, 0x9C, 0x46, 0x65, 0x44, 0x0B, 0x4B, ++ 0x1B, 0x68, 0xDB, 0x03, 0xFF, 0x22, 0xD2, 0x03, 0x1A, 0x40, 0x23, 0x6D, ++ 0x13, 0x43, 0x9B, 0xB2, 0x2B, 0x80, 0xE3, 0xE7, 0x38, 0xE6, 0x10, 0x00, ++ 0x39, 0xCB, 0x10, 0x00, 0xDE, 0x05, 0x00, 0x00, 0xFA, 0x64, 0x61, 0x40, ++ 0xFC, 0x64, 0x61, 0x40, 0x10, 0x65, 0x61, 0x40, 0xC8, 0xE6, 0x10, 0x00, ++ 0x10, 0xB5, 0x00, 0x28, 0x08, 0xD0, 0x08, 0x4B, 0x98, 0x47, 0x08, 0x4B, ++ 0x1B, 0x68, 0xD9, 0x6A, 0x05, 0x20, 0xD7, 0xF7, 0x5B, 0xFF, 0x10, 0xBD, ++ 0x05, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, ++ 0xF7, 0xE7, 0xC0, 0x46, 0x85, 0xC0, 0x0A, 0x00, 0x18, 0x27, 0x16, 0x00, ++ 0x28, 0x19, 0x16, 0x00, 0x10, 0xB5, 0x04, 0x4B, 0x98, 0x47, 0x04, 0x4B, ++ 0x1B, 0x68, 0x59, 0x6B, 0x06, 0x20, 0xD7, 0xF7, 0x43, 0xFF, 0x10, 0xBD, ++ 0xA5, 0xD7, 0x0A, 0x00, 0x24, 0x27, 0x16, 0x00, 0x30, 0xB5, 0x89, 0xB0, ++ 0x04, 0x1E, 0x5A, 0xD0, 0x9F, 0x23, 0xC3, 0x5C, 0x01, 0x2B, 0x04, 0xD0, ++ 0xA0, 0x23, 0x01, 0x22, 0xE2, 0x54, 0x09, 0xB0, 0x30, 0xBD, 0x9D, 0x33, ++ 0xC5, 0x5C, 0x2B, 0x4B, 0x00, 0x93, 0x43, 0x68, 0x01, 0x93, 0x83, 0x68, ++ 0x02, 0x93, 0x6B, 0x46, 0x1D, 0x76, 0x04, 0x95, 0x27, 0x4B, 0x03, 0x93, ++ 0x83, 0x7D, 0x6A, 0x46, 0x13, 0x75, 0x01, 0x33, 0x53, 0x75, 0x00, 0x23, ++ 0x93, 0x75, 0xB0, 0x22, 0x82, 0x5C, 0x69, 0x46, 0xCA, 0x75, 0x8B, 0x76, ++ 0xCB, 0x76, 0x01, 0x33, 0x4B, 0x76, 0x68, 0x46, 0xD7, 0xF7, 0x1A, 0xF8, ++ 0xA9, 0x22, 0xA3, 0x5C, 0x01, 0x33, 0xA3, 0x54, 0x9F, 0x23, 0xE3, 0x5C, ++ 0x01, 0x2B, 0xD3, 0xD1, 0x23, 0x6D, 0x01, 0x33, 0x5B, 0x08, 0xA2, 0x6F, ++ 0x91, 0xB2, 0x62, 0x22, 0x55, 0x43, 0x17, 0x4A, 0xAA, 0x18, 0x11, 0x80, ++ 0xA2, 0x6F, 0x12, 0x0C, 0x15, 0x49, 0x69, 0x18, 0x0A, 0x80, 0x15, 0x4A, ++ 0x94, 0x46, 0x65, 0x44, 0x01, 0x33, 0x5B, 0x08, 0x13, 0x4A, 0x13, 0x43, ++ 0x9B, 0xB2, 0x2B, 0x80, 0x9F, 0x23, 0xE3, 0x5C, 0x01, 0x2B, 0xB7, 0xD1, ++ 0xA5, 0x33, 0xE2, 0x5C, 0x01, 0x32, 0xA3, 0x3B, 0x13, 0x40, 0x9E, 0x22, ++ 0xA1, 0x5C, 0x9C, 0x3A, 0x0C, 0x48, 0xD7, 0xF7, 0x3D, 0xF9, 0xAA, 0x23, ++ 0x01, 0x22, 0xE2, 0x54, 0xA8, 0xE7, 0x0A, 0x4B, 0x9B, 0x6E, 0x00, 0x22, ++ 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0xA4, 0xE7, 0x39, 0xCB, 0x10, 0x00, ++ 0xDE, 0x05, 0x00, 0x00, 0xFA, 0x64, 0x61, 0x40, 0xFC, 0x64, 0x61, 0x40, ++ 0x10, 0x65, 0x61, 0x40, 0x00, 0x80, 0xFF, 0xFF, 0x7D, 0x03, 0x10, 0x00, ++ 0x28, 0x19, 0x16, 0x00, 0x00, 0x09, 0x01, 0x4B, 0x18, 0x56, 0x70, 0x47, ++ 0x28, 0xE0, 0x10, 0x00, 0xF0, 0xB5, 0xD6, 0x46, 0x4F, 0x46, 0x46, 0x46, ++ 0xC0, 0xB5, 0x8A, 0x46, 0x5B, 0x49, 0x09, 0x78, 0x06, 0x29, 0x23, 0xD0, ++ 0x5A, 0x49, 0x0C, 0x78, 0x01, 0x2C, 0x07, 0xD0, 0x20, 0x21, 0x55, 0x46, ++ 0x69, 0x5C, 0x1E, 0x29, 0x08, 0xD8, 0x56, 0x49, 0x01, 0x25, 0x0D, 0x70, ++ 0x20, 0x21, 0x55, 0x46, 0x69, 0x5C, 0x1F, 0x29, 0x00, 0xD9, 0x9B, 0xE0, ++ 0x52, 0x4F, 0xE6, 0x25, 0x6D, 0x00, 0x00, 0x21, 0x79, 0x51, 0x51, 0x46, ++ 0x50, 0x4E, 0xB0, 0x47, 0x50, 0x4B, 0x7B, 0x51, 0x4C, 0x4B, 0x1C, 0x70, ++ 0x00, 0x20, 0x1C, 0xBC, 0x90, 0x46, 0x99, 0x46, 0xA2, 0x46, 0xF0, 0xBD, ++ 0x00, 0x21, 0xE5, 0x20, 0x81, 0xF7, 0xC8, 0xFD, 0x80, 0x46, 0x00, 0x28, ++ 0x14, 0xD0, 0x20, 0x23, 0x52, 0x46, 0xD7, 0x5C, 0x04, 0x33, 0xD1, 0x5C, ++ 0x53, 0x8C, 0xC9, 0x18, 0x89, 0xB2, 0x45, 0x4B, 0x9C, 0x46, 0x61, 0x44, ++ 0x3A, 0x00, 0x40, 0x46, 0xD8, 0xF7, 0xDC, 0xFB, 0x00, 0x2F, 0x64, 0xD0, ++ 0x45, 0x46, 0x41, 0x4B, 0x99, 0x46, 0x14, 0xE0, 0x3B, 0x4B, 0x9B, 0x6E, ++ 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0xE3, 0xE7, 0x05, 0x2C, ++ 0x27, 0xD0, 0x4B, 0x46, 0x1A, 0x88, 0x3B, 0x4B, 0x9A, 0x42, 0x36, 0xD0, ++ 0xE2, 0x43, 0xBF, 0x18, 0xFF, 0xB2, 0x01, 0x34, 0x2D, 0x19, 0x00, 0x2F, ++ 0x4B, 0xD0, 0x2C, 0x78, 0x6E, 0x78, 0x16, 0x2E, 0xED, 0xD0, 0xFF, 0x2E, ++ 0xED, 0xD1, 0x0D, 0x2C, 0xEB, 0xD1, 0xAB, 0x78, 0x5D, 0x2B, 0xE8, 0xD1, ++ 0xEB, 0x78, 0x00, 0x2B, 0xE5, 0xD1, 0x2B, 0x79, 0x03, 0x2B, 0xE2, 0xD1, ++ 0x6B, 0x79, 0x00, 0x2B, 0xDF, 0xD1, 0x2D, 0x48, 0x83, 0xF7, 0xB6, 0xFD, ++ 0x2C, 0x4B, 0x80, 0x22, 0x12, 0x04, 0x1A, 0x60, 0xD7, 0xE7, 0xAB, 0x78, ++ 0x01, 0x2B, 0xD4, 0xD1, 0xEB, 0x78, 0xFD, 0x2B, 0xD1, 0xD1, 0x2B, 0x79, ++ 0x00, 0x2B, 0xCE, 0xD1, 0x6B, 0x79, 0x01, 0x2B, 0xCB, 0xD1, 0x25, 0x48, ++ 0x83, 0xF7, 0xA2, 0xFD, 0x22, 0x4B, 0x80, 0x22, 0x12, 0x04, 0x1A, 0x60, ++ 0xC3, 0xE7, 0x1D, 0x4B, 0x5B, 0x88, 0xB3, 0x42, 0xC4, 0xD1, 0x1B, 0x4B, ++ 0x9B, 0x68, 0x00, 0x2B, 0x0C, 0xD0, 0x19, 0x4B, 0x9A, 0x79, 0xA9, 0x1C, ++ 0x98, 0x68, 0xD8, 0xF7, 0x5F, 0xFB, 0x00, 0x28, 0xB8, 0xD1, 0x18, 0x4B, ++ 0x80, 0x22, 0x12, 0x04, 0x1A, 0x60, 0xB3, 0xE7, 0x0E, 0x4B, 0x9B, 0x6E, ++ 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0xEB, 0xE7, 0x20, 0x23, ++ 0x52, 0x46, 0xD3, 0x5C, 0x00, 0x2B, 0x03, 0xD1, 0x40, 0x46, 0x81, 0xF7, ++ 0xEB, 0xFD, 0x73, 0xE7, 0x50, 0x8C, 0xBA, 0xF7, 0xAD, 0xFD, 0xF7, 0xE7, ++ 0x53, 0x46, 0x58, 0x8C, 0xBA, 0xF7, 0xA8, 0xFD, 0x6A, 0xE7, 0xC0, 0x46, ++ 0xD0, 0xE5, 0x10, 0x00, 0x59, 0xA9, 0x16, 0x00, 0x28, 0x19, 0x16, 0x00, ++ 0x45, 0xF8, 0x0B, 0x00, 0x99, 0x05, 0x10, 0x00, 0x00, 0x00, 0x61, 0x40, ++ 0xC4, 0xE5, 0x10, 0x00, 0x88, 0xAC, 0x00, 0x00, 0x10, 0xCE, 0x10, 0x00, ++ 0x00, 0x41, 0x04, 0x40, 0x00, 0xCE, 0x10, 0x00, 0x70, 0xB5, 0x0C, 0x00, ++ 0x07, 0x4E, 0x8A, 0x25, 0x6D, 0x00, 0x00, 0x21, 0x71, 0x51, 0x21, 0x00, ++ 0xB3, 0xF7, 0xF0, 0xFC, 0xA4, 0x00, 0x04, 0x4B, 0xE3, 0x58, 0x04, 0x4A, ++ 0xDA, 0x61, 0x04, 0x4B, 0x73, 0x51, 0x70, 0xBD, 0x28, 0x19, 0x16, 0x00, ++ 0x54, 0x27, 0x16, 0x00, 0x21, 0x61, 0x10, 0x00, 0x41, 0x07, 0x10, 0x00, ++ 0x10, 0xB5, 0xD2, 0x23, 0x5B, 0x00, 0x1B, 0x68, 0x98, 0x47, 0x10, 0xBD, ++ 0xF0, 0xB5, 0xCE, 0x46, 0x47, 0x46, 0x80, 0xB5, 0xE3, 0xB0, 0x01, 0xAC, ++ 0xC2, 0x25, 0x6D, 0x00, 0x2A, 0x00, 0x00, 0x21, 0x20, 0x00, 0x7F, 0xF7, ++ 0xAB, 0xFC, 0x7A, 0x4E, 0x2A, 0x00, 0x00, 0x21, 0x30, 0x68, 0x7F, 0xF7, ++ 0xA5, 0xFC, 0x31, 0x68, 0x2A, 0x00, 0x01, 0xA8, 0xD8, 0xF7, 0x14, 0xFB, ++ 0x75, 0x48, 0x83, 0xF7, 0x1D, 0xFD, 0x50, 0x22, 0x00, 0x21, 0x4E, 0xA8, ++ 0x7F, 0xF7, 0x98, 0xFC, 0x00, 0x26, 0x9A, 0x23, 0x5B, 0x00, 0xE6, 0x54, ++ 0x4E, 0xA9, 0x00, 0x20, 0x8B, 0xF7, 0x3A, 0xF8, 0x86, 0x3D, 0xC0, 0x23, ++ 0x5B, 0x00, 0xE5, 0x54, 0x80, 0x3B, 0xFF, 0x3B, 0x98, 0x46, 0x82, 0x33, ++ 0xFF, 0x33, 0x42, 0x46, 0xE2, 0x54, 0x03, 0x27, 0x82, 0x23, 0xFF, 0x33, ++ 0xE7, 0x54, 0x0D, 0x3B, 0xE7, 0x54, 0x36, 0x23, 0xFF, 0x33, 0x99, 0x46, ++ 0xE6, 0x54, 0x4E, 0xA9, 0x00, 0x20, 0x87, 0xF7, 0x6B, 0xFE, 0x4B, 0x46, ++ 0xE0, 0x5C, 0x4E, 0xA9, 0x8B, 0xF7, 0x6A, 0xF8, 0x50, 0x22, 0x00, 0x21, ++ 0x3A, 0xA8, 0x7F, 0xF7, 0x6D, 0xFC, 0xE4, 0x23, 0xE6, 0x54, 0x3A, 0xA9, ++ 0x00, 0x20, 0x8B, 0xF7, 0x11, 0xF8, 0x32, 0x23, 0xFF, 0x33, 0xE5, 0x54, ++ 0x30, 0x3B, 0xFF, 0x3B, 0x99, 0x22, 0x52, 0x00, 0xA3, 0x54, 0x02, 0x3A, ++ 0xA3, 0x54, 0x0C, 0x3A, 0xA3, 0x54, 0x19, 0x3D, 0x43, 0x46, 0x63, 0x55, ++ 0x3A, 0xA9, 0x01, 0x20, 0x87, 0xF7, 0x48, 0xFE, 0x60, 0x5D, 0x3A, 0xA9, ++ 0x8B, 0xF7, 0x48, 0xF8, 0x4E, 0x4B, 0x1E, 0x60, 0x4E, 0x4D, 0x2E, 0x60, ++ 0x4E, 0x4B, 0x42, 0x46, 0x1A, 0x60, 0x4E, 0x49, 0x0B, 0x68, 0x4E, 0x4A, ++ 0x1A, 0x40, 0x80, 0x23, 0x5B, 0x00, 0x13, 0x43, 0x0B, 0x60, 0x4C, 0x4C, ++ 0x27, 0x60, 0x4C, 0x4B, 0x19, 0x68, 0x4C, 0x48, 0xD7, 0xF7, 0x60, 0xFE, ++ 0x0F, 0x23, 0x03, 0x40, 0x22, 0x68, 0x80, 0x21, 0x8A, 0x43, 0x0A, 0x43, ++ 0x22, 0x60, 0x06, 0x09, 0xFF, 0x22, 0x16, 0x40, 0x46, 0x4F, 0x3E, 0x60, ++ 0x00, 0x0B, 0x10, 0x40, 0x28, 0x60, 0x5A, 0x08, 0x9B, 0x1A, 0x1B, 0x01, ++ 0x9B, 0x18, 0x43, 0x4A, 0x13, 0x60, 0x23, 0x68, 0x8B, 0x43, 0x23, 0x60, ++ 0x41, 0x4B, 0x1B, 0x6F, 0x1B, 0x07, 0x06, 0xD1, 0x3F, 0x4A, 0x13, 0x6F, ++ 0x71, 0x39, 0x8B, 0x43, 0x0D, 0x39, 0x0B, 0x43, 0x13, 0x67, 0x3C, 0x4B, ++ 0x5B, 0x6F, 0x1B, 0x07, 0x06, 0xD1, 0x3A, 0x4A, 0x53, 0x6F, 0x0F, 0x21, ++ 0x8B, 0x43, 0x0D, 0x39, 0x0B, 0x43, 0x53, 0x67, 0x36, 0x4B, 0x9B, 0x6F, ++ 0x1B, 0x07, 0x06, 0xD1, 0x34, 0x4A, 0x93, 0x6F, 0x0F, 0x21, 0x8B, 0x43, ++ 0x0D, 0x39, 0x0B, 0x43, 0x93, 0x67, 0x31, 0x4B, 0xDB, 0x6F, 0x1B, 0x07, ++ 0x06, 0xD1, 0x2F, 0x4A, 0xD3, 0x6F, 0x0F, 0x21, 0x8B, 0x43, 0x0D, 0x39, ++ 0x0B, 0x43, 0xD3, 0x67, 0x2B, 0x4B, 0x19, 0x69, 0x0F, 0x24, 0xA1, 0x43, ++ 0x03, 0x20, 0x01, 0x43, 0x19, 0x61, 0x59, 0x69, 0xA1, 0x43, 0x01, 0x43, ++ 0x59, 0x61, 0x99, 0x69, 0xA1, 0x43, 0x01, 0x43, 0x99, 0x61, 0xDA, 0x69, ++ 0xA2, 0x43, 0x02, 0x43, 0xDA, 0x61, 0x18, 0x4B, 0x07, 0x22, 0x1A, 0x60, ++ 0x01, 0xAA, 0x00, 0x23, 0x20, 0x21, 0x53, 0x54, 0x06, 0x93, 0x05, 0x93, ++ 0x02, 0x93, 0x01, 0x93, 0x15, 0x4A, 0x13, 0x68, 0x1E, 0x39, 0x0B, 0x43, ++ 0x13, 0x60, 0x1B, 0x4B, 0x1B, 0x68, 0x00, 0x2B, 0x03, 0xD0, 0x13, 0x68, ++ 0x1E, 0x31, 0x0B, 0x43, 0x13, 0x60, 0x18, 0x4B, 0x9A, 0x68, 0x84, 0x23, ++ 0x17, 0x49, 0xD1, 0x50, 0x17, 0x4B, 0x80, 0x22, 0x92, 0x01, 0x1A, 0x60, ++ 0xC2, 0x22, 0x05, 0x4B, 0x18, 0x68, 0x52, 0x00, 0x01, 0xA9, 0xD8, 0xF7, ++ 0x2F, 0xFA, 0x63, 0xB0, 0x0C, 0xBC, 0x90, 0x46, 0x99, 0x46, 0xF0, 0xBD, ++ 0xFC, 0xE1, 0x10, 0x00, 0x20, 0xCE, 0x10, 0x00, 0x08, 0x20, 0x04, 0x40, ++ 0x04, 0x20, 0x04, 0x40, 0x24, 0x20, 0x04, 0x40, 0x10, 0x20, 0x04, 0x40, ++ 0xFF, 0xFE, 0xFF, 0xFF, 0x0C, 0x20, 0x04, 0x40, 0xB8, 0xE5, 0x10, 0x00, ++ 0x00, 0x75, 0x19, 0x03, 0x00, 0x20, 0x04, 0x40, 0x28, 0x20, 0x04, 0x40, ++ 0x00, 0x30, 0x50, 0x40, 0xBC, 0xE5, 0x10, 0x00, 0x00, 0xED, 0x00, 0xE0, ++ 0xC5, 0x88, 0x08, 0x00, 0x00, 0xE1, 0x00, 0xE0, 0x70, 0x47, 0x70, 0x47, ++ 0x3D, 0x4B, 0x3E, 0x4A, 0x1A, 0x60, 0x3E, 0x4B, 0x8D, 0x22, 0x12, 0x03, ++ 0x1A, 0x60, 0x3D, 0x4B, 0x3D, 0x4A, 0x1A, 0x60, 0x3D, 0x4B, 0x3E, 0x4A, ++ 0x1A, 0x60, 0x3E, 0x4B, 0x3E, 0x4A, 0x1A, 0x60, 0x3E, 0x4B, 0x3F, 0x4A, ++ 0x1A, 0x60, 0x3F, 0x4B, 0x3F, 0x4A, 0x1A, 0x60, 0x3F, 0x4B, 0x40, 0x4A, ++ 0x1A, 0x60, 0x40, 0x4B, 0x40, 0x4A, 0x1A, 0x60, 0x40, 0x4B, 0x41, 0x4A, ++ 0x1A, 0x60, 0x41, 0x4B, 0x41, 0x4A, 0x1A, 0x60, 0x41, 0x4B, 0x42, 0x4A, ++ 0x1A, 0x60, 0x42, 0x4B, 0x42, 0x4A, 0x1A, 0x60, 0x42, 0x4B, 0x43, 0x4A, ++ 0x1A, 0x60, 0x43, 0x4B, 0x43, 0x4A, 0x1A, 0x60, 0x43, 0x4B, 0x44, 0x4A, ++ 0x1A, 0x60, 0x44, 0x4B, 0x44, 0x4A, 0x1A, 0x60, 0x44, 0x4B, 0x45, 0x4A, ++ 0x1A, 0x60, 0x45, 0x4B, 0x45, 0x4A, 0x1A, 0x60, 0x45, 0x4B, 0x46, 0x4A, ++ 0x1A, 0x60, 0x46, 0x4B, 0x46, 0x4A, 0x1A, 0x60, 0x46, 0x4B, 0x88, 0x22, ++ 0x52, 0x01, 0x1A, 0x60, 0x45, 0x4B, 0x46, 0x4A, 0x1A, 0x60, 0x46, 0x4B, ++ 0x46, 0x4A, 0x13, 0x60, 0x46, 0x4A, 0x47, 0x49, 0x11, 0x60, 0x47, 0x4A, ++ 0x13, 0x60, 0x47, 0x4A, 0x13, 0x60, 0x47, 0x4A, 0x13, 0x60, 0x47, 0x4B, ++ 0x47, 0x4A, 0x1A, 0x60, 0x47, 0x4B, 0x48, 0x4A, 0x1A, 0x60, 0x48, 0x4B, ++ 0x48, 0x4A, 0x1A, 0x60, 0x48, 0x4B, 0x49, 0x4A, 0x1A, 0x60, 0x49, 0x4B, ++ 0x49, 0x4A, 0x1A, 0x60, 0x49, 0x4B, 0x4A, 0x4A, 0x1A, 0x60, 0x4A, 0x4B, ++ 0x4A, 0x4A, 0x1A, 0x60, 0x4A, 0x4B, 0xFF, 0x22, 0x12, 0x02, 0x1A, 0x60, ++ 0x49, 0x4B, 0x4A, 0x4A, 0x1A, 0x60, 0x4A, 0x4B, 0x4A, 0x4A, 0x1A, 0x60, ++ 0x4A, 0x4B, 0x74, 0x22, 0x1A, 0x60, 0x4A, 0x4B, 0x4A, 0x4A, 0x1A, 0x60, ++ 0x4A, 0x4B, 0x4B, 0x4A, 0x1A, 0x60, 0x70, 0x47, 0x04, 0x01, 0x58, 0x40, ++ 0xFB, 0x33, 0x09, 0x00, 0x1C, 0x20, 0x62, 0x40, 0x28, 0x20, 0x62, 0x40, ++ 0x20, 0x20, 0x91, 0x48, 0x14, 0x20, 0x62, 0x40, 0x83, 0x89, 0x01, 0x00, ++ 0x54, 0x20, 0x62, 0x40, 0x34, 0x8F, 0x00, 0x00, 0x48, 0x07, 0x62, 0x40, ++ 0xA0, 0x01, 0x1A, 0x02, 0x28, 0x07, 0x62, 0x40, 0x20, 0x00, 0x01, 0x00, ++ 0x38, 0x07, 0x62, 0x40, 0xD4, 0x0F, 0x80, 0x04, 0x3C, 0x07, 0x62, 0x40, ++ 0x64, 0x00, 0xC8, 0x00, 0x2C, 0x20, 0x62, 0x40, 0x20, 0xB2, 0x0C, 0x00, ++ 0x0C, 0x20, 0x62, 0x40, 0x45, 0x2B, 0xAD, 0xE9, 0x30, 0x20, 0x62, 0x40, ++ 0xD2, 0x30, 0x0C, 0x14, 0x34, 0x20, 0x62, 0x40, 0x02, 0x16, 0x00, 0x00, ++ 0x54, 0x07, 0x62, 0x40, 0xFD, 0x20, 0x42, 0x21, 0x58, 0x07, 0x62, 0x40, ++ 0x1E, 0xF0, 0x07, 0x00, 0x1C, 0x07, 0x62, 0x40, 0x33, 0x0A, 0x00, 0x00, ++ 0x18, 0x20, 0x62, 0x40, 0x24, 0x41, 0x12, 0x00, 0x0C, 0x00, 0x62, 0x40, ++ 0x00, 0x00, 0x04, 0x04, 0x90, 0x00, 0x62, 0x40, 0x82, 0x90, 0x06, 0x00, ++ 0x34, 0x10, 0x62, 0x40, 0x80, 0x30, 0x00, 0x02, 0x14, 0x10, 0x62, 0x40, ++ 0x7A, 0x11, 0x45, 0x04, 0x24, 0x20, 0x62, 0x40, 0x04, 0x20, 0x62, 0x40, ++ 0xC0, 0xA9, 0x01, 0x00, 0x34, 0x08, 0x50, 0x00, 0x8C, 0x04, 0x60, 0x40, ++ 0x10, 0x01, 0x60, 0x40, 0x58, 0x00, 0x7E, 0x02, 0x80, 0x08, 0x60, 0x40, ++ 0x84, 0x08, 0x60, 0x40, 0x88, 0x08, 0x60, 0x40, 0x8C, 0x08, 0x60, 0x40, ++ 0x34, 0x08, 0x00, 0x00, 0x18, 0x05, 0x62, 0x40, 0x0A, 0x88, 0x92, 0x36, ++ 0x14, 0x05, 0x62, 0x40, 0x10, 0x1A, 0x0C, 0xA8, 0x2C, 0x05, 0x62, 0x40, ++ 0x03, 0x14, 0x0C, 0x9C, 0x0C, 0x05, 0x62, 0x40, 0x13, 0x20, 0x20, 0x20, ++ 0xA0, 0x05, 0x62, 0x40, 0x00, 0x0C, 0x15, 0x14, 0xA4, 0x05, 0x62, 0x40, ++ 0x24, 0x36, 0x2D, 0x36, 0xF0, 0x05, 0x62, 0x40, 0x08, 0x05, 0x62, 0x40, ++ 0x32, 0x31, 0x55, 0x54, 0x30, 0x05, 0x62, 0x40, 0x00, 0x12, 0x17, 0x13, ++ 0x34, 0x05, 0x62, 0x40, 0xB0, 0x05, 0x62, 0x40, 0x55, 0x53, 0x00, 0x00, ++ 0x1C, 0x05, 0x62, 0x40, 0x66, 0x57, 0x4B, 0x96, 0x2A, 0x49, 0x0B, 0x68, ++ 0x2A, 0x4A, 0x1A, 0x40, 0xFC, 0x23, 0x9B, 0x05, 0x13, 0x43, 0x0B, 0x60, ++ 0x28, 0x4B, 0x29, 0x4A, 0x1A, 0x60, 0x29, 0x4B, 0x29, 0x4A, 0x1A, 0x60, ++ 0x29, 0x4B, 0x2A, 0x4A, 0x1A, 0x60, 0x2A, 0x4B, 0x2A, 0x4A, 0x1A, 0x60, ++ 0x2A, 0x4B, 0x2B, 0x4A, 0x1A, 0x60, 0x2B, 0x4B, 0x2B, 0x4A, 0x1A, 0x60, ++ 0x2B, 0x4B, 0x2C, 0x4A, 0x13, 0x60, 0x2C, 0x4A, 0x2C, 0x49, 0x11, 0x60, ++ 0x2C, 0x4A, 0x13, 0x60, 0x2C, 0x4A, 0x13, 0x60, 0x2C, 0x4A, 0x13, 0x60, ++ 0x2C, 0x4B, 0x2D, 0x4A, 0x1A, 0x60, 0x2D, 0x4B, 0x2D, 0x4A, 0x1A, 0x60, ++ 0x2D, 0x4B, 0x2E, 0x4A, 0x1A, 0x60, 0x2E, 0x4B, 0x2E, 0x4A, 0x1A, 0x60, ++ 0x2E, 0x4B, 0x2F, 0x4A, 0x1A, 0x60, 0x2F, 0x4B, 0x2F, 0x4A, 0x1A, 0x60, ++ 0x2F, 0x4B, 0x30, 0x4A, 0x1A, 0x60, 0x30, 0x4B, 0x30, 0x4A, 0x1A, 0x60, ++ 0x30, 0x4B, 0xFF, 0x22, 0x12, 0x02, 0x1A, 0x60, 0x2F, 0x4B, 0x30, 0x4A, ++ 0x1A, 0x60, 0x30, 0x4B, 0x76, 0x22, 0x1A, 0x60, 0x2F, 0x4B, 0x30, 0x4A, ++ 0x1A, 0x60, 0x30, 0x4B, 0x30, 0x4A, 0x1A, 0x60, 0x30, 0x4B, 0x31, 0x4A, ++ 0x1A, 0x60, 0x31, 0x4B, 0x31, 0x4A, 0x1A, 0x60, 0x70, 0x47, 0xC0, 0x46, ++ 0x0C, 0x00, 0x58, 0x40, 0xFF, 0xFF, 0xFF, 0xC0, 0x04, 0x01, 0x58, 0x40, ++ 0xFB, 0x33, 0x09, 0x00, 0x20, 0x40, 0x34, 0x40, 0x77, 0x0B, 0x00, 0x00, ++ 0x24, 0x40, 0x34, 0x40, 0x94, 0xC5, 0x6E, 0x00, 0x28, 0x40, 0x34, 0x40, ++ 0x02, 0x94, 0x00, 0x00, 0x2C, 0x40, 0x34, 0x40, 0x84, 0x18, 0x20, 0x56, ++ 0x30, 0x40, 0x34, 0x40, 0x68, 0x51, 0x2E, 0x1A, 0x34, 0x08, 0x50, 0x00, ++ 0x8C, 0x04, 0x60, 0x40, 0x10, 0x01, 0x60, 0x40, 0x58, 0x00, 0x7E, 0x02, ++ 0x80, 0x08, 0x60, 0x40, 0x84, 0x08, 0x60, 0x40, 0x88, 0x08, 0x60, 0x40, ++ 0x8C, 0x08, 0x60, 0x40, 0x34, 0x08, 0x00, 0x00, 0x18, 0x05, 0x62, 0x40, ++ 0x0A, 0x88, 0x92, 0x36, 0x14, 0x05, 0x62, 0x40, 0x10, 0x1A, 0x0C, 0xA8, ++ 0x2C, 0x05, 0x62, 0x40, 0x03, 0x14, 0x0C, 0x9C, 0x0C, 0x05, 0x62, 0x40, ++ 0x13, 0x20, 0x20, 0x20, 0x08, 0x05, 0x62, 0x40, 0x32, 0x31, 0x55, 0x54, ++ 0xA0, 0x05, 0x62, 0x40, 0x00, 0x16, 0x17, 0x0F, 0xA4, 0x05, 0x62, 0x40, ++ 0x36, 0x36, 0x28, 0x36, 0xF0, 0x05, 0x62, 0x40, 0x30, 0x05, 0x62, 0x40, ++ 0x00, 0x1A, 0x17, 0x13, 0x34, 0x05, 0x62, 0x40, 0xB0, 0x05, 0x62, 0x40, ++ 0x55, 0x53, 0x00, 0x00, 0x1C, 0x05, 0x62, 0x40, 0x66, 0x57, 0x4B, 0x96, ++ 0x90, 0x00, 0x62, 0x40, 0x32, 0x00, 0x05, 0x00, 0x10, 0x10, 0x62, 0x40, ++ 0x43, 0x01, 0x00, 0x12, 0x10, 0xB5, 0x01, 0x28, 0x03, 0xD0, 0x02, 0x38, ++ 0x01, 0x28, 0x05, 0xD9, 0x10, 0xBD, 0x87, 0xF7, 0x99, 0xFF, 0xFF, 0xF7, ++ 0x2B, 0xFE, 0xF9, 0xE7, 0x88, 0xF7, 0x96, 0xF8, 0x0A, 0x4A, 0x11, 0x68, ++ 0x80, 0x23, 0xDB, 0x05, 0x0B, 0x43, 0x13, 0x60, 0xFF, 0xF7, 0x32, 0xFF, ++ 0x07, 0x4B, 0x1B, 0x68, 0x9B, 0x02, 0xEB, 0xD4, 0x05, 0x49, 0x0B, 0x68, ++ 0x05, 0x4A, 0x1A, 0x40, 0x80, 0x23, 0x1B, 0x04, 0x13, 0x43, 0x0B, 0x60, ++ 0xE2, 0xE7, 0xC0, 0x46, 0x1C, 0x20, 0x34, 0x40, 0x58, 0x40, 0x34, 0x40, ++ 0xFF, 0xFF, 0x7F, 0xFF, 0xF0, 0xB5, 0xDE, 0x46, 0x57, 0x46, 0x4E, 0x46, ++ 0x45, 0x46, 0xE0, 0xB5, 0x83, 0xB0, 0x01, 0x90, 0x0D, 0x00, 0x00, 0x24, ++ 0x25, 0x4A, 0x26, 0x4B, 0x9B, 0x46, 0xE0, 0x23, 0xDB, 0x04, 0x9A, 0x46, ++ 0xC0, 0x23, 0x9B, 0x05, 0x99, 0x46, 0x23, 0x4B, 0x98, 0x46, 0x23, 0x4B, ++ 0x00, 0x93, 0x23, 0x4F, 0x23, 0x4E, 0x13, 0x68, 0x58, 0x46, 0x03, 0x40, ++ 0x50, 0x46, 0x20, 0x40, 0x03, 0x43, 0x13, 0x60, 0x13, 0x68, 0x48, 0x46, ++ 0x03, 0x43, 0x13, 0x60, 0x43, 0x46, 0x1B, 0x68, 0x00, 0x98, 0x00, 0x68, ++ 0x1B, 0x04, 0x3B, 0x40, 0x40, 0x04, 0x40, 0x0C, 0x03, 0x43, 0x08, 0xC5, ++ 0x13, 0x68, 0x33, 0x40, 0x13, 0x60, 0x80, 0x23, 0x5B, 0x04, 0x9C, 0x46, ++ 0x64, 0x44, 0x80, 0x23, 0xDB, 0x04, 0x9C, 0x42, 0xDF, 0xD1, 0x04, 0x20, ++ 0x01, 0x9B, 0x01, 0x2B, 0x06, 0xD0, 0x03, 0xB0, 0x3C, 0xBC, 0x90, 0x46, ++ 0x99, 0x46, 0xA2, 0x46, 0xAB, 0x46, 0xF0, 0xBD, 0x0E, 0x4B, 0x1B, 0x68, ++ 0x0B, 0x61, 0x0E, 0x4B, 0x1B, 0x68, 0x4B, 0x61, 0x0D, 0x4B, 0x1B, 0x68, ++ 0x8B, 0x61, 0x0D, 0x4B, 0x1B, 0x68, 0xCB, 0x61, 0x0C, 0x4B, 0x1B, 0x68, ++ 0x0B, 0x62, 0x05, 0x30, 0xE7, 0xE7, 0xC0, 0x46, 0x28, 0x05, 0x62, 0x40, ++ 0xFF, 0xFF, 0xFF, 0xF8, 0x8C, 0x08, 0x62, 0x40, 0x90, 0x08, 0x62, 0x40, ++ 0x00, 0x00, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xCF, 0x30, 0x07, 0x62, 0x40, ++ 0x34, 0x07, 0x62, 0x40, 0x5C, 0x07, 0x62, 0x40, 0x60, 0x07, 0x62, 0x40, ++ 0x20, 0x20, 0x62, 0x40, 0x12, 0x04, 0x12, 0x4B, 0x1A, 0x40, 0x49, 0x04, ++ 0x49, 0x0C, 0x0A, 0x43, 0x10, 0x4B, 0x1A, 0x60, 0x10, 0x4B, 0x1A, 0x68, ++ 0x00, 0x06, 0xE0, 0x21, 0xC9, 0x04, 0x08, 0x40, 0x0E, 0x49, 0x0A, 0x40, ++ 0x10, 0x43, 0x18, 0x60, 0x19, 0x68, 0x80, 0x22, 0x12, 0x06, 0x0A, 0x43, ++ 0x1A, 0x60, 0x19, 0x68, 0x80, 0x22, 0xD2, 0x05, 0x0A, 0x43, 0x1A, 0x60, ++ 0x1A, 0x68, 0x08, 0x49, 0x0A, 0x40, 0x1A, 0x60, 0x1A, 0x68, 0x52, 0x00, ++ 0x52, 0x08, 0x1A, 0x60, 0x70, 0x47, 0xC0, 0x46, 0x00, 0x00, 0xFF, 0x7F, ++ 0x44, 0x05, 0x62, 0x40, 0x28, 0x05, 0x62, 0x40, 0xFF, 0xFF, 0xFF, 0xF8, ++ 0xFF, 0xFF, 0xFF, 0xBF, 0xF0, 0xB5, 0xD6, 0x46, 0x4F, 0x46, 0x46, 0x46, ++ 0xC0, 0xB5, 0x82, 0xB0, 0x1C, 0x49, 0x0B, 0x68, 0x99, 0x46, 0x1C, 0x4A, ++ 0x1A, 0x40, 0x1C, 0x4B, 0x13, 0x43, 0x0B, 0x60, 0x1B, 0x4B, 0x1B, 0x68, ++ 0x98, 0x46, 0x1B, 0x4B, 0x1B, 0x68, 0x9A, 0x46, 0x00, 0x24, 0xF0, 0x23, ++ 0x47, 0x46, 0x9F, 0x43, 0x16, 0x4E, 0xE5, 0xB2, 0x00, 0x22, 0x00, 0x21, ++ 0x28, 0x00, 0xFF, 0xF7, 0xB1, 0xFF, 0x23, 0x01, 0x3B, 0x43, 0x33, 0x60, ++ 0x88, 0xF7, 0x3D, 0xF9, 0x69, 0x46, 0x01, 0xA8, 0x88, 0xF7, 0x4A, 0xF9, ++ 0x00, 0x9A, 0x01, 0x99, 0x28, 0x00, 0xFF, 0xF7, 0xA3, 0xFF, 0x01, 0x34, ++ 0x04, 0x2C, 0xE8, 0xD1, 0x07, 0x4B, 0x4A, 0x46, 0x1A, 0x60, 0x09, 0x4B, ++ 0x42, 0x46, 0x1A, 0x60, 0x08, 0x4B, 0x52, 0x46, 0x1A, 0x60, 0x02, 0xB0, ++ 0x1C, 0xBC, 0x90, 0x46, 0x99, 0x46, 0xA2, 0x46, 0xF0, 0xBD, 0xC0, 0x46, ++ 0x1C, 0x05, 0x62, 0x40, 0xFF, 0xFF, 0x8F, 0x7F, 0x0A, 0x00, 0x20, 0x00, ++ 0x08, 0x05, 0x62, 0x40, 0x04, 0x00, 0x62, 0x40, 0x70, 0xB5, 0x0C, 0x4D, ++ 0x2C, 0x68, 0x2A, 0x68, 0x0B, 0x4E, 0x32, 0x40, 0x80, 0x23, 0x5B, 0x00, ++ 0x13, 0x43, 0x2B, 0x60, 0x26, 0x20, 0x88, 0xF7, 0x3F, 0xFF, 0xFF, 0xF7, ++ 0xA7, 0xFF, 0x88, 0xF7, 0x81, 0xFF, 0x2B, 0x68, 0xE4, 0x05, 0xE4, 0x0F, ++ 0x24, 0x02, 0x33, 0x40, 0x1C, 0x43, 0x2C, 0x60, 0x70, 0xBD, 0xC0, 0x46, ++ 0x00, 0x04, 0x60, 0x40, 0xFF, 0xFE, 0xFF, 0xFF, 0x10, 0xB5, 0x26, 0x20, ++ 0x88, 0xF7, 0x62, 0xF9, 0xFF, 0xF7, 0x92, 0xFF, 0x88, 0xF7, 0xBA, 0xF9, ++ 0x10, 0xBD, 0x00, 0x00, 0xF0, 0xB5, 0xDE, 0x46, 0x57, 0x46, 0x4E, 0x46, ++ 0x45, 0x46, 0xE0, 0xB5, 0x8B, 0xB0, 0x82, 0x46, 0x0C, 0x00, 0x03, 0x68, ++ 0x7F, 0x22, 0x1A, 0x40, 0x93, 0x46, 0x1E, 0x09, 0x0F, 0x25, 0x2E, 0x40, ++ 0x1D, 0x40, 0x01, 0x95, 0x0C, 0x22, 0x13, 0x42, 0x05, 0xD0, 0x35, 0x4B, ++ 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x01, 0x9B, ++ 0x9E, 0x42, 0x05, 0xD9, 0x30, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, ++ 0x00, 0x20, 0x98, 0x47, 0x2E, 0x4B, 0x98, 0x46, 0x1F, 0x68, 0x1A, 0x68, ++ 0x2D, 0x4B, 0x99, 0x46, 0x1A, 0x40, 0x80, 0x23, 0x5B, 0x00, 0x13, 0x43, ++ 0x42, 0x46, 0x13, 0x60, 0x58, 0x46, 0x88, 0xF7, 0xF1, 0xFE, 0x53, 0x46, ++ 0x19, 0x68, 0x03, 0xA8, 0x89, 0xF7, 0x0E, 0xF9, 0x88, 0xF7, 0x30, 0xFF, ++ 0x43, 0x46, 0x1B, 0x68, 0xFF, 0x05, 0xFF, 0x0F, 0x3F, 0x02, 0x4A, 0x46, ++ 0x13, 0x40, 0x1F, 0x43, 0x43, 0x46, 0x1F, 0x60, 0x01, 0x9B, 0x9E, 0x42, ++ 0x30, 0xD8, 0x37, 0x00, 0x20, 0x36, 0x36, 0x01, 0x1D, 0x4B, 0xF6, 0x18, ++ 0x03, 0xA9, 0x1D, 0x4B, 0x98, 0x46, 0xF0, 0x23, 0x1B, 0x05, 0x9C, 0x46, ++ 0x23, 0x1D, 0x99, 0x46, 0x05, 0xE0, 0x01, 0x37, 0x10, 0x36, 0xFB, 0xB2, ++ 0x01, 0x9A, 0x9A, 0x42, 0x1C, 0xD3, 0x7B, 0x18, 0x1A, 0x7D, 0x12, 0x02, ++ 0xDB, 0x7B, 0x1A, 0x43, 0x43, 0x46, 0x1A, 0x43, 0x32, 0x60, 0x7B, 0x5C, ++ 0x18, 0x05, 0x65, 0x46, 0x28, 0x40, 0x1B, 0x07, 0x5B, 0x0F, 0x5B, 0x07, ++ 0x03, 0x43, 0x70, 0x68, 0x00, 0x02, 0x00, 0x0A, 0x03, 0x43, 0x73, 0x60, ++ 0x00, 0x2C, 0xE2, 0xD0, 0xFB, 0x00, 0xE2, 0x50, 0x4A, 0x46, 0x70, 0x68, ++ 0xD0, 0x50, 0xDC, 0xE7, 0x0B, 0xB0, 0x3C, 0xBC, 0x90, 0x46, 0x99, 0x46, ++ 0xA2, 0x46, 0xAB, 0x46, 0xF0, 0xBD, 0xC0, 0x46, 0x28, 0x19, 0x16, 0x00, ++ 0x00, 0x04, 0x60, 0x40, 0xFF, 0xFE, 0xFF, 0xFF, 0xD8, 0x99, 0x16, 0x00, ++ 0x00, 0x00, 0x80, 0x80, 0xF0, 0xB5, 0xDE, 0x46, 0x57, 0x46, 0x4E, 0x46, ++ 0x45, 0x46, 0xE0, 0xB5, 0x87, 0xB0, 0x05, 0x00, 0x01, 0x91, 0x03, 0x68, ++ 0x5A, 0x02, 0x52, 0x0E, 0x90, 0x46, 0x1C, 0x09, 0x0F, 0x26, 0x34, 0x40, ++ 0x1E, 0x40, 0x0C, 0x22, 0x13, 0x42, 0x05, 0xD0, 0x38, 0x4B, 0x9B, 0x6E, ++ 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0xB4, 0x42, 0x2F, 0xD9, ++ 0x34, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, ++ 0x40, 0x46, 0x88, 0xF7, 0xAD, 0xF8, 0x29, 0x68, 0x02, 0xA8, 0x88, 0xF7, ++ 0x09, 0xFB, 0x88, 0xF7, 0x03, 0xF9, 0x80, 0x22, 0x52, 0x00, 0x2D, 0x49, ++ 0x2D, 0x48, 0xD7, 0xF7, 0x49, 0xFE, 0x07, 0xB0, 0x3C, 0xBC, 0x90, 0x46, ++ 0x99, 0x46, 0xA2, 0x46, 0xAB, 0x46, 0xF0, 0xBD, 0x01, 0x35, 0xEB, 0xB2, ++ 0x9E, 0x42, 0xEE, 0xD3, 0x2B, 0x01, 0xA8, 0x00, 0x63, 0x44, 0x1A, 0x68, ++ 0x22, 0x40, 0x02, 0xA9, 0x41, 0x58, 0x00, 0x91, 0xC9, 0x01, 0x0A, 0x43, ++ 0x1A, 0x60, 0x01, 0x9B, 0x00, 0x2B, 0xED, 0xD0, 0x1A, 0x50, 0xEB, 0xE7, ++ 0x40, 0x46, 0x88, 0xF7, 0x83, 0xF8, 0x29, 0x68, 0x02, 0xA8, 0x88, 0xF7, ++ 0xDF, 0xFA, 0x25, 0x00, 0xA2, 0x00, 0x02, 0xAB, 0x9C, 0x46, 0x62, 0x44, ++ 0xFC, 0x23, 0x1B, 0x01, 0x98, 0x46, 0xF8, 0x23, 0x5B, 0x02, 0x9C, 0x46, ++ 0x3F, 0x20, 0xF8, 0x23, 0x9B, 0x03, 0x9B, 0x46, 0x13, 0x68, 0x1F, 0x0A, ++ 0x41, 0x46, 0x0F, 0x40, 0xB9, 0x46, 0xD9, 0x00, 0x0F, 0x00, 0x61, 0x46, ++ 0x0F, 0x40, 0xBA, 0x46, 0x4F, 0x46, 0x51, 0x46, 0x0F, 0x43, 0xB9, 0x46, ++ 0x19, 0x0D, 0x0F, 0x00, 0x07, 0x40, 0xBA, 0x46, 0x4F, 0x46, 0x51, 0x46, ++ 0x0F, 0x43, 0x5B, 0x03, 0x59, 0x46, 0x0B, 0x40, 0x3B, 0x43, 0x08, 0xC2, ++ 0x01, 0x34, 0xE4, 0xB2, 0xA6, 0x42, 0xE1, 0xD2, 0x88, 0xF7, 0xAC, 0xF8, ++ 0x02, 0x4B, 0x9C, 0x46, 0x03, 0x4C, 0xB5, 0xE7, 0x28, 0x19, 0x16, 0x00, ++ 0xD8, 0x97, 0x16, 0x00, 0x00, 0x50, 0x1E, 0x00, 0x7F, 0x00, 0x00, 0xE0, ++ 0x70, 0xB5, 0x8E, 0xB0, 0x87, 0xF7, 0x76, 0xFF, 0x04, 0x00, 0x01, 0x28, ++ 0x05, 0xD0, 0x83, 0x1E, 0xDB, 0xB2, 0x01, 0x2B, 0x24, 0xD9, 0x0E, 0xB0, ++ 0x70, 0xBD, 0x1C, 0x4B, 0x00, 0x93, 0x1C, 0x4C, 0x25, 0x68, 0xF0, 0x23, ++ 0x2A, 0x00, 0x9A, 0x43, 0x13, 0x00, 0x70, 0x22, 0x13, 0x43, 0x23, 0x60, ++ 0x01, 0xA9, 0x68, 0x46, 0xFF, 0xF7, 0x56, 0xFF, 0x25, 0x60, 0x16, 0x4B, ++ 0x00, 0x93, 0x00, 0x21, 0x68, 0x46, 0x88, 0xF7, 0xE9, 0xFC, 0x00, 0x20, ++ 0x88, 0xF7, 0xD0, 0xFB, 0x05, 0xA9, 0x01, 0x20, 0xFF, 0xF7, 0xB0, 0xFD, ++ 0x01, 0x20, 0x89, 0xF7, 0x43, 0xFA, 0xFF, 0xF7, 0xAF, 0xFE, 0xDA, 0xE7, ++ 0x0A, 0x4B, 0x00, 0x93, 0x0A, 0x4D, 0x2E, 0x68, 0xF0, 0x23, 0x32, 0x00, ++ 0x9A, 0x43, 0x13, 0x00, 0x70, 0x22, 0x13, 0x43, 0x2B, 0x60, 0x01, 0xA9, ++ 0x68, 0x46, 0xFF, 0xF7, 0xA9, 0xFE, 0x2E, 0x60, 0x20, 0x00, 0x89, 0xF7, ++ 0x2D, 0xFA, 0xFF, 0xF7, 0x7B, 0xFE, 0xC4, 0xE7, 0x03, 0x42, 0x26, 0x00, ++ 0x08, 0x05, 0x62, 0x40, 0x0F, 0x30, 0x02, 0x00, 0x30, 0xB5, 0x83, 0xB0, ++ 0x41, 0x4B, 0x18, 0x78, 0x87, 0xF7, 0x12, 0xFF, 0x40, 0x4A, 0x80, 0x23, ++ 0x5B, 0x00, 0x06, 0x21, 0xD1, 0x50, 0x3F, 0x4B, 0x5A, 0x68, 0x3F, 0x49, ++ 0x0A, 0x40, 0x5A, 0x60, 0x59, 0x68, 0x80, 0x22, 0x92, 0x02, 0x0A, 0x43, ++ 0x5A, 0x60, 0x19, 0x00, 0x44, 0x22, 0x0B, 0x6B, 0x13, 0x40, 0x04, 0x2B, ++ 0xFB, 0xD1, 0x39, 0x4B, 0x18, 0x68, 0x39, 0x49, 0xD7, 0xF7, 0x32, 0xF9, ++ 0xA0, 0x23, 0x5B, 0x03, 0x03, 0x43, 0x37, 0x4A, 0x13, 0x60, 0x37, 0x49, ++ 0x08, 0x43, 0x10, 0x60, 0x13, 0x60, 0x30, 0x4B, 0x59, 0x68, 0x35, 0x4A, ++ 0x0A, 0x43, 0x5A, 0x60, 0x2C, 0x49, 0x9A, 0x22, 0x52, 0x00, 0x80, 0x20, ++ 0x40, 0x01, 0x88, 0x50, 0x1A, 0x68, 0x40, 0x20, 0x02, 0x43, 0x1A, 0x60, ++ 0x18, 0x68, 0x02, 0x24, 0x20, 0x43, 0x18, 0x60, 0x48, 0x6F, 0x01, 0x22, ++ 0x10, 0x43, 0x48, 0x67, 0x59, 0x6D, 0x2B, 0x4A, 0x11, 0x40, 0x59, 0x65, ++ 0x5A, 0x6D, 0x22, 0x43, 0x5A, 0x65, 0x5A, 0x6D, 0x28, 0x49, 0x0A, 0x40, ++ 0x5A, 0x65, 0x87, 0xF7, 0xE1, 0xFE, 0x04, 0x00, 0x80, 0x22, 0x52, 0x00, ++ 0x25, 0x49, 0x26, 0x48, 0xD7, 0xF7, 0x4C, 0xFD, 0x80, 0x22, 0x25, 0x49, ++ 0x25, 0x48, 0xD7, 0xF7, 0x47, 0xFD, 0x01, 0x2C, 0x05, 0xD1, 0x17, 0x4B, ++ 0xDB, 0x6D, 0x9B, 0x07, 0x0D, 0xD5, 0x03, 0xB0, 0x30, 0xBD, 0xC0, 0x22, ++ 0x92, 0x00, 0x20, 0x49, 0x20, 0x48, 0xD7, 0xF7, 0x39, 0xFD, 0x80, 0x22, ++ 0x1F, 0x49, 0x20, 0x48, 0xD7, 0xF7, 0x34, 0xFD, 0xED, 0xE7, 0x20, 0x00, ++ 0x87, 0xF7, 0xD2, 0xFE, 0x20, 0x00, 0xFF, 0xF7, 0xF1, 0xFC, 0x00, 0x23, ++ 0x01, 0x93, 0x00, 0x93, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0xFF, 0xF7, ++ 0x39, 0xFF, 0x05, 0x4B, 0x1B, 0x78, 0x01, 0x2B, 0xDF, 0xD1, 0x16, 0x4A, ++ 0x13, 0x68, 0x01, 0x21, 0x8B, 0x43, 0x13, 0x60, 0xD9, 0xE7, 0xC0, 0x46, ++ 0xB4, 0xE5, 0x10, 0x00, 0x00, 0x00, 0x50, 0x40, 0x00, 0x60, 0x50, 0x40, ++ 0xFF, 0xFF, 0xFB, 0xFF, 0xB0, 0x06, 0x16, 0x00, 0x40, 0x42, 0x0F, 0x00, ++ 0x08, 0x00, 0x58, 0x40, 0x00, 0x00, 0x14, 0x80, 0x02, 0x88, 0x01, 0x00, ++ 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0x58, 0xE0, 0x10, 0x00, ++ 0xD8, 0x97, 0x16, 0x00, 0x58, 0xE1, 0x10, 0x00, 0xD8, 0x98, 0x16, 0x00, ++ 0x18, 0xE2, 0x10, 0x00, 0xD8, 0x99, 0x16, 0x00, 0x18, 0xE5, 0x10, 0x00, ++ 0x58, 0x99, 0x16, 0x00, 0x04, 0x30, 0x34, 0x40, 0x80, 0x00, 0x01, 0x4B, ++ 0xC0, 0x58, 0x70, 0x47, 0x38, 0x27, 0x16, 0x00, 0x80, 0x00, 0x01, 0x4B, ++ 0xC0, 0x58, 0x70, 0x47, 0x54, 0x27, 0x16, 0x00, 0x80, 0x00, 0x01, 0x4B, ++ 0x19, 0x50, 0x70, 0x47, 0x54, 0x27, 0x16, 0x00, 0x03, 0x23, 0x03, 0x40, ++ 0x8B, 0x42, 0x05, 0xD8, 0x03, 0x23, 0x98, 0x43, 0x40, 0x18, 0x00, 0x01, ++ 0x00, 0x09, 0x70, 0x47, 0x03, 0x30, 0x03, 0x23, 0x98, 0x43, 0x40, 0x18, ++ 0xF7, 0xE7, 0x00, 0x00, 0xF0, 0xB5, 0xC6, 0x46, 0x00, 0xB5, 0x05, 0x00, ++ 0x0F, 0x00, 0x14, 0x00, 0x06, 0xAB, 0x04, 0xCB, 0x90, 0x46, 0x1A, 0x78, ++ 0x1B, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x01, 0xD0, 0x00, 0x2A, 0x06, 0xD0, ++ 0x18, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x00, 0x21, 0x99, 0x70, 0xD9, 0x70, ++ 0x5A, 0x70, 0xAB, 0x68, 0x2A, 0x69, 0x94, 0x46, 0x63, 0x44, 0x18, 0x00, ++ 0x13, 0x49, 0xD7, 0xF7, 0x63, 0xF8, 0x06, 0x00, 0x10, 0x4B, 0x5D, 0x60, ++ 0x9F, 0x60, 0xDC, 0x60, 0x18, 0x61, 0x00, 0x2C, 0x05, 0xD1, 0x0F, 0x4B, ++ 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x0A, 0x4D, ++ 0x21, 0x00, 0x38, 0x00, 0xD7, 0xF7, 0xD6, 0xF8, 0x29, 0x77, 0x43, 0x46, ++ 0x6B, 0x61, 0xA4, 0x1B, 0x62, 0x01, 0x12, 0x1B, 0x92, 0x00, 0x12, 0x19, ++ 0x90, 0x00, 0x12, 0x18, 0x78, 0x3A, 0xAA, 0x61, 0x04, 0xBC, 0x90, 0x46, ++ 0xF0, 0xBD, 0xC0, 0x46, 0x74, 0xE6, 0x10, 0x00, 0x71, 0x02, 0x00, 0x00, ++ 0x28, 0x19, 0x16, 0x00, 0xF0, 0xB5, 0xDE, 0x46, 0x4F, 0x46, 0x46, 0x46, ++ 0xC0, 0xB5, 0x82, 0xB0, 0x80, 0x46, 0x00, 0x91, 0x01, 0x92, 0x99, 0x46, ++ 0x40, 0x4B, 0x1B, 0x78, 0x01, 0x2B, 0x05, 0xD0, 0x02, 0xB0, 0x1C, 0xBC, ++ 0x90, 0x46, 0x99, 0x46, 0xA3, 0x46, 0xF0, 0xBD, 0x3C, 0x4B, 0x1E, 0x68, ++ 0xB4, 0x68, 0x00, 0x2C, 0xF4, 0xD0, 0x00, 0x25, 0x1F, 0x23, 0x9B, 0x46, ++ 0x01, 0x27, 0x03, 0xE0, 0x3B, 0x00, 0x83, 0x40, 0x9C, 0x43, 0x0D, 0xD0, ++ 0x20, 0x00, 0xD7, 0xF7, 0x8B, 0xF9, 0x5B, 0x46, 0x18, 0x1A, 0x43, 0x1C, ++ 0xDB, 0x00, 0xF3, 0x18, 0x5B, 0x68, 0x00, 0x2B, 0xF0, 0xD0, 0x01, 0x35, ++ 0xED, 0xB2, 0xED, 0xE7, 0x01, 0x2D, 0xDB, 0xD1, 0x2C, 0x4B, 0x5C, 0x68, ++ 0xA3, 0x68, 0x22, 0x69, 0x94, 0x46, 0x63, 0x44, 0x1E, 0x00, 0x2B, 0x49, ++ 0x18, 0x00, 0xD6, 0xF7, 0xFD, 0xFF, 0x05, 0x00, 0x64, 0x68, 0x04, 0x19, ++ 0x27, 0x49, 0x30, 0x00, 0xD7, 0xF7, 0x7C, 0xF8, 0x4B, 0x46, 0x9B, 0x68, ++ 0x9C, 0x46, 0x8C, 0x45, 0x89, 0x41, 0x49, 0x42, 0x64, 0x18, 0x4B, 0x46, ++ 0x99, 0x8A, 0x89, 0x04, 0x49, 0x0F, 0x04, 0x29, 0x03, 0xD0, 0x20, 0x00, ++ 0xFF, 0xF7, 0x54, 0xFF, 0x04, 0x00, 0x43, 0x46, 0x1B, 0x68, 0xE1, 0x1A, ++ 0x0A, 0x01, 0x12, 0x09, 0x80, 0x20, 0x00, 0x05, 0x82, 0x42, 0x11, 0xD8, ++ 0x09, 0x01, 0x0F, 0xD0, 0x15, 0x4A, 0xD1, 0x68, 0xCB, 0x18, 0xE2, 0x1A, ++ 0x12, 0x01, 0x12, 0x09, 0x82, 0x42, 0x07, 0xD8, 0x1B, 0x01, 0x1B, 0x09, ++ 0xE3, 0x1A, 0x1B, 0x01, 0x02, 0xD0, 0x64, 0x1A, 0x24, 0x01, 0x24, 0x09, ++ 0x43, 0x46, 0x1C, 0x60, 0x0C, 0x4B, 0xDA, 0x68, 0x55, 0x1B, 0x68, 0x01, ++ 0x40, 0x1B, 0x80, 0x00, 0x40, 0x19, 0x82, 0x00, 0x80, 0x18, 0x0B, 0x4A, ++ 0x94, 0x46, 0x60, 0x44, 0x00, 0x9A, 0x10, 0x60, 0xD8, 0x68, 0x60, 0x28, ++ 0x02, 0xD8, 0x01, 0x9B, 0x18, 0x60, 0x87, 0xE7, 0x24, 0x21, 0xD6, 0xF7, ++ 0xB1, 0xFF, 0x01, 0x9B, 0x18, 0x60, 0x81, 0xE7, 0x74, 0xE6, 0x10, 0x00, ++ 0xF4, 0xE1, 0x10, 0x00, 0x71, 0x02, 0x00, 0x00, 0x1E, 0xFB, 0xFF, 0xFF, ++ 0x03, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x02, 0xD0, 0x01, 0x4B, 0x00, 0x22, ++ 0x1A, 0x70, 0x70, 0x47, 0x74, 0xE6, 0x10, 0x00, 0xF0, 0xB5, 0xDE, 0x46, ++ 0x57, 0x46, 0x4E, 0x46, 0x45, 0x46, 0xE0, 0xB5, 0x83, 0xB0, 0x06, 0x00, ++ 0x01, 0x92, 0x38, 0x4B, 0x38, 0x4A, 0x13, 0x60, 0x9C, 0x68, 0x00, 0x2C, ++ 0x08, 0xD0, 0x43, 0x68, 0x9B, 0x46, 0x36, 0x4B, 0x99, 0x46, 0x36, 0x4B, ++ 0x98, 0x46, 0x33, 0x4B, 0x9A, 0x46, 0x0F, 0xE0, 0xD5, 0xF7, 0x8C, 0xF9, ++ 0x04, 0x1E, 0x5B, 0xD0, 0x73, 0x68, 0x9B, 0x46, 0xF1, 0xE7, 0x75, 0x60, ++ 0x53, 0x46, 0x1B, 0x68, 0x9B, 0x68, 0xA3, 0x42, 0x46, 0xD0, 0x24, 0x68, ++ 0x00, 0x2C, 0x47, 0xD0, 0x21, 0x00, 0x30, 0x00, 0xC8, 0x47, 0x00, 0x28, ++ 0x43, 0xD0, 0x05, 0x28, 0xF0, 0xD0, 0xA3, 0x68, 0x22, 0x69, 0x94, 0x46, ++ 0x63, 0x44, 0x1F, 0x00, 0x41, 0x46, 0x18, 0x00, 0xD6, 0xF7, 0x64, 0xFF, ++ 0x63, 0x68, 0xC5, 0x18, 0x41, 0x46, 0x38, 0x00, 0xD6, 0xF7, 0xE4, 0xFF, ++ 0xB3, 0x68, 0x9C, 0x46, 0x8C, 0x45, 0x89, 0x41, 0x49, 0x42, 0x6D, 0x18, ++ 0xB1, 0x8A, 0x89, 0x04, 0x49, 0x0F, 0x04, 0x29, 0x03, 0xD0, 0x28, 0x00, ++ 0xFF, 0xF7, 0xBE, 0xFE, 0x05, 0x00, 0x5B, 0x46, 0xEB, 0x1A, 0x1B, 0x01, ++ 0x1B, 0x09, 0x80, 0x22, 0x12, 0x05, 0x93, 0x42, 0x04, 0xD9, 0x5B, 0x46, ++ 0x5B, 0x1B, 0x1B, 0x01, 0x1B, 0x09, 0x5B, 0x42, 0x01, 0x9A, 0x93, 0x42, ++ 0xC1, 0xD9, 0x63, 0x7E, 0x0B, 0x2B, 0x03, 0xD8, 0x10, 0x4A, 0xDA, 0x40, ++ 0xD3, 0x07, 0xBA, 0xD4, 0xA3, 0x7D, 0xB2, 0x7D, 0x01, 0x20, 0x9A, 0x42, ++ 0x07, 0xD8, 0x01, 0x33, 0xB3, 0x75, 0x04, 0xE0, 0xD5, 0xF7, 0x38, 0xF9, ++ 0x04, 0x00, 0xB5, 0xE7, 0x00, 0x20, 0x03, 0xB0, 0x3C, 0xBC, 0x90, 0x46, ++ 0x99, 0x46, 0xA2, 0x46, 0xAB, 0x46, 0xF0, 0xBD, 0x00, 0x20, 0xF6, 0xE7, ++ 0x64, 0x2A, 0x16, 0x00, 0x10, 0xE7, 0x10, 0x00, 0x51, 0x62, 0x0D, 0x00, ++ 0x71, 0x02, 0x00, 0x00, 0x6A, 0x0C, 0x00, 0x00, 0x01, 0x4B, 0x18, 0x68, ++ 0x70, 0x47, 0xC0, 0x46, 0x94, 0x40, 0x04, 0x40, 0x02, 0x4B, 0x1B, 0x68, ++ 0x01, 0x20, 0x18, 0x40, 0x70, 0x47, 0xC0, 0x46, 0x94, 0x40, 0x04, 0x40, ++ 0x02, 0x4B, 0x18, 0x68, 0x80, 0x07, 0xC0, 0x0F, 0x70, 0x47, 0xC0, 0x46, ++ 0x94, 0x40, 0x04, 0x40, 0x02, 0x4B, 0x18, 0x68, 0xC0, 0x0F, 0xC0, 0x07, ++ 0x70, 0x47, 0xC0, 0x46, 0x48, 0x30, 0x34, 0x40, 0x01, 0x4B, 0x18, 0x68, ++ 0xC0, 0x0F, 0x70, 0x47, 0x48, 0x30, 0x34, 0x40, 0x02, 0x4B, 0x18, 0x68, ++ 0x40, 0x07, 0xC0, 0x0F, 0x70, 0x47, 0xC0, 0x46, 0x94, 0x40, 0x04, 0x40, ++ 0x03, 0x4B, 0x1B, 0x68, 0x14, 0x20, 0x18, 0x40, 0x43, 0x1E, 0x98, 0x41, ++ 0xC0, 0xB2, 0x70, 0x47, 0x94, 0x40, 0x04, 0x40, 0x02, 0x4B, 0x18, 0x68, ++ 0xC0, 0x06, 0xC0, 0x0F, 0x70, 0x47, 0xC0, 0x46, 0x94, 0x40, 0x04, 0x40, ++ 0x01, 0x4B, 0x18, 0x68, 0xC0, 0x0F, 0x70, 0x47, 0x98, 0x40, 0x04, 0x40, ++ 0x10, 0xB5, 0x10, 0x4B, 0x1A, 0x68, 0x00, 0x23, 0x01, 0x2A, 0x02, 0xD9, ++ 0x01, 0x20, 0x18, 0x40, 0x10, 0xBD, 0xFF, 0xF7, 0xCF, 0xFF, 0x00, 0x23, ++ 0x00, 0x28, 0xF7, 0xD0, 0xFF, 0xF7, 0xE2, 0xFF, 0x00, 0x28, 0x03, 0xD1, ++ 0x08, 0x4B, 0x1B, 0x68, 0x00, 0x2B, 0x05, 0xDA, 0xFF, 0xF7, 0xB2, 0xFF, ++ 0x01, 0x23, 0x43, 0x40, 0xDB, 0xB2, 0xE9, 0xE7, 0xFF, 0xF7, 0xC2, 0xFF, ++ 0x00, 0x23, 0x00, 0x28, 0xE4, 0xD0, 0xF3, 0xE7, 0x50, 0xE0, 0x10, 0x00, ++ 0x98, 0x40, 0x04, 0x40, 0x10, 0xB5, 0xFF, 0xF7, 0xB7, 0xFF, 0x00, 0x23, ++ 0x00, 0x28, 0x02, 0xD1, 0x01, 0x20, 0x18, 0x40, 0x10, 0xBD, 0xFF, 0xF7, ++ 0x99, 0xFF, 0x01, 0x23, 0x43, 0x40, 0xDB, 0xB2, 0xF6, 0xE7, 0x00, 0x00, ++ 0x05, 0x4B, 0x1B, 0x68, 0x00, 0x28, 0x04, 0xD0, 0x08, 0x22, 0x13, 0x43, ++ 0x02, 0x4A, 0x13, 0x60, 0x70, 0x47, 0x08, 0x22, 0x93, 0x43, 0xF9, 0xE7, ++ 0x94, 0x40, 0x04, 0x40, 0x04, 0x4A, 0x13, 0x68, 0x40, 0x01, 0x04, 0x49, ++ 0x0B, 0x40, 0x04, 0x49, 0x08, 0x40, 0x18, 0x43, 0x10, 0x60, 0x70, 0x47, ++ 0x94, 0x40, 0x04, 0x40, 0x1F, 0x00, 0xFE, 0xFF, 0xE0, 0xFF, 0x01, 0x00, ++ 0x03, 0x4B, 0x1B, 0x68, 0x00, 0x20, 0x01, 0x22, 0x9A, 0x42, 0x40, 0x41, ++ 0xC0, 0xB2, 0x70, 0x47, 0x50, 0xE0, 0x10, 0x00, 0x02, 0x4B, 0x18, 0x68, ++ 0x43, 0x42, 0x58, 0x41, 0xC0, 0xB2, 0x70, 0x47, 0x50, 0xE0, 0x10, 0x00, ++ 0x70, 0xB5, 0x01, 0x28, 0x02, 0xD0, 0x02, 0x28, 0x0F, 0xD0, 0x70, 0xBD, ++ 0x0E, 0x4C, 0xEA, 0x25, 0x6D, 0x00, 0x02, 0x22, 0x02, 0x21, 0x20, 0x00, ++ 0x2B, 0x68, 0x98, 0x47, 0x80, 0x22, 0x2B, 0x68, 0x92, 0x01, 0x00, 0x21, ++ 0x20, 0x00, 0x98, 0x47, 0xEF, 0xE7, 0x80, 0x21, 0x89, 0x01, 0x06, 0x4C, ++ 0xEA, 0x25, 0x6D, 0x00, 0x0A, 0x00, 0x20, 0x00, 0x2B, 0x68, 0x98, 0x47, ++ 0x2B, 0x68, 0x02, 0x22, 0x00, 0x21, 0x20, 0x00, 0x98, 0x47, 0xE0, 0xE7, ++ 0x00, 0x10, 0x01, 0x50, 0x70, 0xB5, 0x05, 0x00, 0x0C, 0x00, 0x39, 0x4B, ++ 0x1B, 0x68, 0x01, 0x20, 0x00, 0x2B, 0x45, 0xD1, 0x00, 0x29, 0x43, 0xD0, ++ 0x00, 0x2D, 0x1A, 0xD0, 0xEF, 0xF3, 0x10, 0x83, 0x01, 0x22, 0x16, 0x00, ++ 0x1E, 0x40, 0x1A, 0x42, 0x4E, 0xD1, 0x72, 0xB6, 0x31, 0x4B, 0x1B, 0x68, ++ 0x00, 0x2B, 0x41, 0xD1, 0x00, 0x20, 0x00, 0x2E, 0x4A, 0xD1, 0x62, 0xB6, ++ 0x27, 0xE0, 0x20, 0x00, 0xFF, 0xF7, 0xBA, 0xFF, 0x2B, 0x4B, 0x01, 0x22, ++ 0x1A, 0x60, 0x28, 0x00, 0x00, 0x2E, 0x20, 0xD1, 0xF3, 0xE7, 0xEF, 0xF3, ++ 0x10, 0x83, 0x01, 0x22, 0x16, 0x00, 0x1E, 0x40, 0x1A, 0x42, 0x00, 0xD1, ++ 0x72, 0xB6, 0x24, 0x4B, 0x1B, 0x68, 0x00, 0x2B, 0x1B, 0xD1, 0x01, 0x20, ++ 0x87, 0xF7, 0x51, 0xFC, 0x20, 0x4B, 0x1B, 0x68, 0x00, 0x2B, 0x14, 0xD1, ++ 0x01, 0x20, 0x87, 0xF7, 0x4A, 0xFC, 0x28, 0x00, 0x00, 0x2E, 0x00, 0xD1, ++ 0x62, 0xB6, 0x1C, 0x4A, 0x13, 0x68, 0x01, 0x33, 0x13, 0x60, 0x00, 0x28, ++ 0x1E, 0xD0, 0x00, 0x23, 0x19, 0x4A, 0x13, 0x60, 0x19, 0x4A, 0x13, 0x60, ++ 0x16, 0x4A, 0x13, 0x60, 0x70, 0xBD, 0x20, 0x00, 0xFF, 0xF7, 0x88, 0xFF, ++ 0x12, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0x01, 0x20, 0x87, 0xF7, 0x2F, 0xFC, ++ 0x01, 0x20, 0xE3, 0xE7, 0x08, 0x00, 0xFF, 0xF7, 0x7D, 0xFF, 0x0D, 0x4B, ++ 0x01, 0x22, 0x1A, 0x60, 0x28, 0x00, 0xB8, 0xE7, 0x0A, 0x4B, 0x1B, 0x68, ++ 0x00, 0x2B, 0xB6, 0xD1, 0x09, 0x4B, 0x1B, 0x68, 0x00, 0x20, 0x05, 0x2B, ++ 0xDB, 0xD8, 0x08, 0x4B, 0x1C, 0x60, 0x08, 0x4B, 0x01, 0x22, 0x1A, 0x60, ++ 0x07, 0x48, 0x82, 0xF7, 0x2F, 0xFC, 0x00, 0x20, 0xD8, 0xE7, 0xC0, 0x46, ++ 0x50, 0xE0, 0x10, 0x00, 0x5C, 0x40, 0x04, 0x40, 0x54, 0xE6, 0x10, 0x00, ++ 0x58, 0xE6, 0x10, 0x00, 0x5C, 0xE6, 0x10, 0x00, 0x2C, 0xCE, 0x10, 0x00, ++ 0xF0, 0xB5, 0xCE, 0x46, 0x00, 0xB5, 0x86, 0xB0, 0x2A, 0x4B, 0x1C, 0x68, ++ 0x21, 0x00, 0x2A, 0x48, 0x82, 0xF7, 0x16, 0xFC, 0x03, 0xAA, 0x29, 0x4B, ++ 0x03, 0xCB, 0x03, 0xC2, 0x1B, 0x88, 0x13, 0x80, 0x00, 0x2C, 0x0D, 0xDB, ++ 0x0A, 0x22, 0x03, 0xA9, 0x25, 0x48, 0xD7, 0xF7, 0xFD, 0xF9, 0x0A, 0x22, ++ 0x03, 0xA9, 0x24, 0x48, 0xD7, 0xF7, 0xF8, 0xF9, 0x06, 0xB0, 0x04, 0xBC, ++ 0x91, 0x46, 0xF0, 0xBD, 0xFF, 0x23, 0x1B, 0x04, 0x23, 0x40, 0x80, 0x22, ++ 0x52, 0x02, 0x93, 0x42, 0x11, 0xD0, 0x24, 0x04, 0x24, 0x0C, 0x1D, 0x4B, ++ 0xE7, 0x18, 0x1D, 0x4B, 0x9C, 0x46, 0x64, 0x44, 0xFB, 0x43, 0xDB, 0x17, ++ 0x1F, 0x40, 0x4E, 0x2C, 0x00, 0xDD, 0x4E, 0x24, 0x03, 0xAD, 0x00, 0x26, ++ 0x00, 0x23, 0x01, 0x93, 0x1B, 0xE0, 0x24, 0x04, 0x24, 0x0C, 0x16, 0x4B, ++ 0xE7, 0x18, 0x16, 0x4B, 0x9C, 0x46, 0x64, 0x44, 0xEC, 0xE7, 0x8B, 0x40, ++ 0x1A, 0x43, 0xD2, 0xB2, 0x01, 0x31, 0x08, 0x29, 0x07, 0xD0, 0x88, 0x19, ++ 0x01, 0x23, 0xB8, 0x42, 0xF5, 0xDB, 0xA0, 0x42, 0xF3, 0xDC, 0x01, 0x9B, ++ 0xF1, 0xE7, 0x4B, 0x46, 0x1A, 0x70, 0x01, 0x35, 0x08, 0x36, 0x50, 0x2E, ++ 0xBC, 0xD0, 0xA9, 0x46, 0x00, 0x22, 0x00, 0x21, 0xED, 0xE7, 0xC0, 0x46, ++ 0x98, 0x40, 0x04, 0x40, 0x34, 0xCE, 0x10, 0x00, 0x48, 0xCE, 0x10, 0x00, ++ 0xD8, 0xE1, 0x10, 0x00, 0xC0, 0x9F, 0x16, 0x00, 0x94, 0xF6, 0xFF, 0xFF, ++ 0xA7, 0xF6, 0xFF, 0xFF, 0x8A, 0xF6, 0xFF, 0xFF, 0xB1, 0xF6, 0xFF, 0xFF, ++ 0x10, 0xB5, 0x84, 0xB0, 0x98, 0x4B, 0x1C, 0x68, 0x21, 0x00, 0x98, 0x48, ++ 0x82, 0xF7, 0xAC, 0xFB, 0x01, 0xAA, 0x97, 0x4B, 0x03, 0xCB, 0x03, 0xC2, ++ 0x1B, 0x88, 0x13, 0x80, 0x00, 0x2C, 0x0B, 0xDB, 0x0A, 0x22, 0x01, 0xA9, ++ 0x93, 0x48, 0xD7, 0xF7, 0x93, 0xF9, 0x0A, 0x22, 0x01, 0xA9, 0x92, 0x48, ++ 0xD7, 0xF7, 0x8E, 0xF9, 0x04, 0xB0, 0x10, 0xBD, 0xFF, 0x23, 0x1B, 0x04, ++ 0x23, 0x40, 0x80, 0x22, 0x52, 0x02, 0x93, 0x42, 0x00, 0xD1, 0x02, 0xE1, ++ 0x24, 0x04, 0x24, 0x0C, 0x8B, 0x4B, 0x9C, 0x46, 0x64, 0x44, 0x3C, 0x2C, ++ 0xE4, 0xD8, 0xA4, 0x00, 0x89, 0x4B, 0x1B, 0x59, 0x9F, 0x46, 0x01, 0xAB, ++ 0x00, 0x22, 0x1A, 0x70, 0x5A, 0x70, 0x9A, 0x70, 0xFC, 0x32, 0xDA, 0x70, ++ 0xD8, 0xE7, 0x0A, 0x21, 0x01, 0xAB, 0x3F, 0x22, 0x1A, 0x70, 0x00, 0x22, ++ 0x5A, 0x70, 0x9A, 0x70, 0xFC, 0x32, 0xDA, 0x70, 0x14, 0x29, 0xCD, 0xD1, ++ 0x00, 0x22, 0x1A, 0x70, 0xDA, 0x70, 0x1A, 0x71, 0xC8, 0xE7, 0x14, 0x21, ++ 0xEE, 0xE7, 0x0A, 0x21, 0x01, 0xAB, 0x03, 0x22, 0x5A, 0x70, 0x00, 0x22, ++ 0x9A, 0x70, 0xC0, 0x32, 0xDA, 0x70, 0x14, 0x29, 0xBC, 0xD1, 0x00, 0x22, ++ 0x1A, 0x70, 0x5A, 0x70, 0xDA, 0x70, 0x1A, 0x71, 0xF0, 0x32, 0x5A, 0x71, ++ 0xB4, 0xE7, 0x14, 0x21, 0xEC, 0xE7, 0x0A, 0x21, 0x01, 0xAB, 0x00, 0x22, ++ 0x9A, 0x70, 0xDA, 0x70, 0xF0, 0x32, 0x1A, 0x71, 0x14, 0x29, 0xA9, 0xD1, ++ 0xED, 0x3A, 0x1A, 0x70, 0x00, 0x22, 0x5A, 0x70, 0x1A, 0x71, 0x5A, 0x71, ++ 0xA2, 0xE7, 0x14, 0x21, 0xEE, 0xE7, 0x0A, 0x21, 0x01, 0xAB, 0x3F, 0x22, ++ 0x9A, 0x70, 0x00, 0x22, 0xDA, 0x70, 0x1A, 0x71, 0xFC, 0x32, 0x5A, 0x71, ++ 0x14, 0x29, 0x95, 0xD1, 0x00, 0x22, 0x5A, 0x70, 0x9A, 0x70, 0x5A, 0x71, ++ 0xF0, 0x32, 0x9A, 0x71, 0x8E, 0xE7, 0x14, 0x21, 0xEC, 0xE7, 0x0A, 0x21, ++ 0x01, 0xAB, 0x03, 0x22, 0xDA, 0x70, 0x00, 0x22, 0x1A, 0x71, 0xC0, 0x32, ++ 0x5A, 0x71, 0x14, 0x29, 0x00, 0xD0, 0x81, 0xE7, 0x81, 0x3A, 0x5A, 0x70, ++ 0x00, 0x22, 0x9A, 0x70, 0xDA, 0x70, 0x5A, 0x71, 0xFC, 0x32, 0x9A, 0x71, ++ 0x78, 0xE7, 0x14, 0x21, 0xEA, 0xE7, 0x0A, 0x21, 0x01, 0xAB, 0x3F, 0x22, ++ 0xDA, 0x70, 0x00, 0x22, 0x1A, 0x71, 0x5A, 0x71, 0xFC, 0x32, 0x9A, 0x71, ++ 0x14, 0x29, 0x00, 0xD0, 0x6A, 0xE7, 0xF9, 0x3A, 0x9A, 0x70, 0x00, 0x22, ++ 0xDA, 0x70, 0x9A, 0x71, 0xC0, 0x32, 0xDA, 0x71, 0x62, 0xE7, 0x14, 0x21, ++ 0xEA, 0xE7, 0x0A, 0x21, 0x01, 0xAB, 0x0F, 0x22, 0x1A, 0x71, 0x00, 0x22, ++ 0x5A, 0x71, 0x9A, 0x71, 0x14, 0x29, 0x00, 0xD0, 0x56, 0xE7, 0x3F, 0x32, ++ 0x9A, 0x70, 0x00, 0x22, 0xDA, 0x70, 0x1A, 0x71, 0xDA, 0x71, 0x4F, 0xE7, ++ 0x14, 0x21, 0xED, 0xE7, 0x0A, 0x21, 0x01, 0xAB, 0x00, 0x22, 0x5A, 0x71, ++ 0x9A, 0x71, 0xF0, 0x32, 0xDA, 0x71, 0x14, 0x29, 0x00, 0xD0, 0x43, 0xE7, ++ 0xE1, 0x3A, 0xDA, 0x70, 0x00, 0x22, 0x1A, 0x71, 0xDA, 0x71, 0x1A, 0x72, ++ 0x3C, 0xE7, 0x14, 0x21, 0xED, 0xE7, 0x0A, 0x21, 0x01, 0xAB, 0x3F, 0x22, ++ 0x5A, 0x71, 0x00, 0x22, 0x9A, 0x71, 0xDA, 0x71, 0xFC, 0x32, 0x1A, 0x72, ++ 0x14, 0x29, 0x00, 0xD0, 0x2E, 0xE7, 0xED, 0x3A, 0x1A, 0x71, 0x00, 0x22, ++ 0x5A, 0x71, 0x1A, 0x72, 0x5A, 0x72, 0x27, 0xE7, 0x14, 0x21, 0xEB, 0xE7, ++ 0x0A, 0x21, 0x01, 0xAB, 0x03, 0x22, 0x9A, 0x71, 0x00, 0x22, 0xDA, 0x71, ++ 0xC0, 0x32, 0x1A, 0x72, 0x14, 0x29, 0x00, 0xD0, 0x1A, 0xE7, 0x00, 0x22, ++ 0x5A, 0x71, 0x9A, 0x71, 0x1A, 0x72, 0x5A, 0x72, 0x14, 0xE7, 0x14, 0x21, ++ 0xED, 0xE7, 0x0A, 0x21, 0x01, 0xAB, 0x00, 0x22, 0xDA, 0x71, 0x1A, 0x72, ++ 0xF0, 0x32, 0x5A, 0x72, 0x14, 0x29, 0x00, 0xD0, 0x08, 0xE7, 0x00, 0x22, ++ 0x9A, 0x71, 0x5A, 0x72, 0x04, 0xE7, 0x14, 0x21, 0xF0, 0xE7, 0x0A, 0x21, ++ 0x01, 0xAB, 0x3F, 0x22, 0xDA, 0x71, 0x00, 0x22, 0x1A, 0x72, 0x5A, 0x72, ++ 0x14, 0x29, 0x00, 0xD0, 0xF8, 0xE6, 0x0F, 0x32, 0x9A, 0x71, 0x00, 0x22, ++ 0xDA, 0x71, 0xF3, 0xE6, 0x14, 0x21, 0xEF, 0xE7, 0x01, 0xAB, 0x00, 0x22, ++ 0x1A, 0x70, 0x5A, 0x70, 0x9A, 0x70, 0xDA, 0x70, 0xFC, 0x32, 0x1A, 0x71, ++ 0xE8, 0xE6, 0x24, 0x04, 0x24, 0x0C, 0x0A, 0x4B, 0x9C, 0x46, 0x64, 0x44, ++ 0x3C, 0x2C, 0x00, 0xD9, 0xE0, 0xE6, 0xA4, 0x00, 0x08, 0x4B, 0x1B, 0x59, ++ 0x9F, 0x46, 0xC0, 0x46, 0x98, 0x40, 0x04, 0x40, 0x34, 0xCE, 0x10, 0x00, ++ 0x48, 0xCE, 0x10, 0x00, 0xD8, 0xE1, 0x10, 0x00, 0xC0, 0x9F, 0x16, 0x00, ++ 0x94, 0xF6, 0xFF, 0xFF, 0x54, 0xCE, 0x10, 0x00, 0x48, 0xCF, 0x10, 0x00, ++ 0x10, 0xB5, 0x08, 0x4B, 0x1B, 0x78, 0x01, 0x2B, 0x00, 0xD0, 0x10, 0xBD, ++ 0x06, 0x4B, 0x1A, 0x6B, 0x06, 0x4B, 0x19, 0x68, 0x01, 0x20, 0x81, 0x43, ++ 0x19, 0x60, 0x19, 0x68, 0x04, 0x48, 0x82, 0xF7, 0x5F, 0xFA, 0xF2, 0xE7, ++ 0xB4, 0xE5, 0x10, 0x00, 0x00, 0x60, 0x50, 0x40, 0x04, 0x30, 0x34, 0x40, ++ 0x3C, 0xD0, 0x10, 0x00, 0x70, 0xB5, 0x05, 0x00, 0x0C, 0x00, 0x4C, 0x4B, ++ 0x1B, 0x68, 0x01, 0x2B, 0x02, 0xD0, 0x4B, 0x4B, 0x01, 0x22, 0x1A, 0x70, ++ 0x4A, 0x4A, 0x13, 0x68, 0x04, 0x21, 0x8B, 0x43, 0x13, 0x60, 0xA9, 0xF7, ++ 0x71, 0xFD, 0x48, 0x4B, 0x18, 0x60, 0x5C, 0x60, 0x0C, 0x2D, 0x38, 0xD8, ++ 0xAD, 0x00, 0x46, 0x4B, 0x5B, 0x59, 0x9F, 0x46, 0x80, 0x23, 0xDB, 0x01, ++ 0x00, 0x21, 0x9C, 0x42, 0x1B, 0xD3, 0x43, 0x4A, 0x13, 0x68, 0x43, 0x49, ++ 0x19, 0x40, 0x80, 0x23, 0x9B, 0x02, 0x0B, 0x43, 0x13, 0x60, 0x11, 0x68, ++ 0xE3, 0x08, 0xC0, 0x20, 0x40, 0x01, 0x03, 0x40, 0x76, 0x20, 0x03, 0x43, ++ 0x09, 0x0C, 0x09, 0x04, 0x0B, 0x43, 0x13, 0x60, 0x13, 0x68, 0x3B, 0x49, ++ 0x19, 0x40, 0x80, 0x23, 0x1B, 0x03, 0x0B, 0x43, 0x13, 0x60, 0x80, 0x21, ++ 0xC9, 0x01, 0x35, 0x4B, 0x1A, 0x68, 0x35, 0x48, 0x02, 0x40, 0x1A, 0x60, ++ 0x1A, 0x68, 0xA4, 0x04, 0xA4, 0x0C, 0x0C, 0x43, 0x12, 0x0C, 0x12, 0x04, ++ 0x14, 0x43, 0x1C, 0x60, 0x1A, 0x68, 0x30, 0x49, 0x11, 0x40, 0x80, 0x22, ++ 0x12, 0x03, 0x0A, 0x43, 0x1A, 0x60, 0x70, 0xBD, 0x2D, 0x4B, 0x1B, 0x68, ++ 0x9A, 0x6A, 0x5B, 0x6B, 0xD2, 0x1A, 0xD5, 0x00, 0x55, 0x19, 0x6D, 0x00, ++ 0x55, 0x19, 0xAD, 0xB2, 0x2A, 0x00, 0x21, 0x00, 0x28, 0x48, 0x82, 0xF7, ++ 0xF7, 0xF9, 0x23, 0x4B, 0x19, 0x68, 0x23, 0x4E, 0x31, 0x40, 0x80, 0x22, ++ 0x92, 0x02, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x12, 0x0C, 0x12, 0x04, ++ 0x6D, 0x05, 0x6D, 0x0D, 0x2A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x1D, 0x48, ++ 0x02, 0x40, 0x80, 0x21, 0x09, 0x03, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, ++ 0x16, 0x40, 0x1E, 0x60, 0x1A, 0x68, 0xA4, 0x04, 0xA4, 0x0C, 0x80, 0x25, ++ 0x2D, 0x02, 0x2C, 0x43, 0x12, 0x0C, 0x12, 0x04, 0x14, 0x43, 0x1C, 0x60, ++ 0x1A, 0x68, 0x10, 0x40, 0x01, 0x43, 0x19, 0x60, 0xC7, 0xE7, 0x0F, 0x4A, ++ 0x13, 0x68, 0x0F, 0x49, 0x0B, 0x40, 0x13, 0x60, 0x13, 0x68, 0x1B, 0x0C, ++ 0x1B, 0x04, 0x10, 0x49, 0x0C, 0x43, 0xA4, 0xB2, 0x1C, 0x43, 0x14, 0x60, ++ 0x13, 0x68, 0x0A, 0x49, 0x19, 0x40, 0x80, 0x23, 0x1B, 0x03, 0x0B, 0x43, ++ 0x13, 0x60, 0xB2, 0xE7, 0x50, 0xE0, 0x10, 0x00, 0xB2, 0xE6, 0x10, 0x00, ++ 0xFC, 0x00, 0x60, 0x40, 0x6C, 0xE6, 0x10, 0x00, 0x5C, 0xD0, 0x10, 0x00, ++ 0xF8, 0x00, 0x60, 0x40, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, ++ 0xF8, 0xE6, 0x10, 0x00, 0x50, 0xD0, 0x10, 0x00, 0x00, 0xC0, 0xFF, 0xFF, ++ 0xF0, 0xB5, 0xD6, 0x46, 0x4F, 0x46, 0x46, 0x46, 0xC0, 0xB5, 0x82, 0xB0, ++ 0x07, 0x00, 0xD4, 0xF7, 0x4B, 0xFD, 0x04, 0x00, 0x00, 0x23, 0x01, 0x93, ++ 0x00, 0x93, 0x3B, 0x4A, 0x13, 0x70, 0x01, 0x21, 0x01, 0x20, 0xFF, 0xF7, ++ 0xEF, 0xFC, 0x80, 0x46, 0x38, 0x4B, 0x1E, 0x78, 0x02, 0x3E, 0x73, 0x1E, ++ 0x9E, 0x41, 0x76, 0x42, 0x19, 0x23, 0x1E, 0x40, 0x02, 0x36, 0x00, 0x2C, ++ 0x21, 0xD0, 0x65, 0x68, 0xFB, 0x7D, 0x9A, 0x46, 0xA3, 0x68, 0x99, 0x46, ++ 0x69, 0x46, 0x01, 0xA8, 0xA9, 0xF7, 0xB0, 0xFC, 0x01, 0x9B, 0x53, 0x44, ++ 0xEB, 0x1A, 0x1B, 0x01, 0x1A, 0x09, 0x5B, 0x00, 0x9C, 0x1A, 0xA4, 0x00, ++ 0xA4, 0x18, 0xA3, 0x00, 0xE4, 0x18, 0x4B, 0x46, 0x00, 0x9A, 0x9B, 0x1A, ++ 0xE4, 0x18, 0xA4, 0x09, 0xA6, 0x42, 0x00, 0xD8, 0xA4, 0x1B, 0x80, 0x23, ++ 0x5B, 0x02, 0x9C, 0x42, 0x02, 0xD9, 0x24, 0x4C, 0x00, 0xE0, 0x23, 0x4C, ++ 0xFF, 0xF7, 0xFC, 0xFB, 0x05, 0x00, 0x43, 0x46, 0x00, 0x2B, 0x12, 0xD0, ++ 0x20, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x03, 0xD0, 0x1F, 0x4B, 0x1B, 0x78, ++ 0x01, 0x2B, 0x0F, 0xD0, 0x0A, 0x2C, 0x16, 0xD8, 0x4F, 0x23, 0x00, 0x22, ++ 0xFA, 0x54, 0x02, 0xB0, 0x1C, 0xBC, 0x90, 0x46, 0x99, 0x46, 0xA2, 0x46, ++ 0xF0, 0xBD, 0x01, 0x21, 0x00, 0x20, 0xFF, 0xF7, 0xA3, 0xFC, 0xE7, 0xE7, ++ 0x16, 0x4B, 0x80, 0x22, 0x12, 0x05, 0x1A, 0x60, 0x13, 0x4B, 0x02, 0x22, ++ 0x1A, 0x70, 0x00, 0x25, 0xE6, 0xE7, 0xFF, 0xF7, 0x0B, 0xFC, 0x00, 0x28, ++ 0xE4, 0xD0, 0xB2, 0xF7, 0xC9, 0xFD, 0x06, 0x23, 0x00, 0x28, 0x05, 0xD1, ++ 0x4A, 0x33, 0xFB, 0x5C, 0x01, 0x3B, 0x58, 0x42, 0x43, 0x41, 0x05, 0x33, ++ 0x00, 0x2D, 0xD7, 0xD1, 0xCF, 0x2C, 0x01, 0xD8, 0x06, 0x2B, 0xD3, 0xD1, ++ 0x21, 0x00, 0x18, 0x00, 0xFF, 0xF7, 0xCC, 0xFE, 0xCE, 0xE7, 0xC0, 0x46, ++ 0xB2, 0xE6, 0x10, 0x00, 0xB4, 0xE5, 0x10, 0x00, 0xFF, 0xFF, 0x00, 0x00, ++ 0xB4, 0xE6, 0x10, 0x00, 0xB3, 0xE6, 0x10, 0x00, 0x00, 0x41, 0x04, 0x40, ++ 0x70, 0xB5, 0x4E, 0x23, 0x01, 0x22, 0xC2, 0x54, 0x2A, 0x4B, 0x1D, 0x68, ++ 0x2A, 0x4B, 0x1C, 0x68, 0x2A, 0x4B, 0x19, 0x68, 0x2A, 0x4B, 0x1A, 0x68, ++ 0x2A, 0x4B, 0x00, 0x26, 0x1E, 0x70, 0x00, 0x23, 0x00, 0x2D, 0x05, 0xD0, ++ 0x42, 0x33, 0xEB, 0x5C, 0x01, 0x3B, 0x5D, 0x42, 0x6B, 0x41, 0xDB, 0xB2, ++ 0x00, 0x2C, 0x03, 0xD0, 0x3A, 0x25, 0x64, 0x5D, 0x01, 0x2C, 0x23, 0xD0, ++ 0x00, 0x24, 0x00, 0x29, 0x04, 0xD0, 0x3E, 0x34, 0x0D, 0x5D, 0x00, 0x24, ++ 0x01, 0x2D, 0x1D, 0xD0, 0x00, 0x2A, 0x03, 0xD0, 0x2F, 0x21, 0x51, 0x5C, ++ 0x01, 0x29, 0x1A, 0xD0, 0x00, 0x2B, 0x1D, 0xD0, 0x1A, 0x49, 0x0B, 0x68, ++ 0x1A, 0x4A, 0x1A, 0x40, 0x80, 0x23, 0x9B, 0x03, 0x13, 0x43, 0x0B, 0x60, ++ 0x18, 0x4B, 0x19, 0x4A, 0x13, 0x60, 0x81, 0x22, 0x52, 0x00, 0x9B, 0x5C, ++ 0x00, 0x2B, 0x18, 0xD0, 0x4F, 0x23, 0x01, 0x22, 0xC2, 0x54, 0x70, 0xBD, ++ 0x01, 0x23, 0xD9, 0xE7, 0x8C, 0x62, 0x01, 0x34, 0xDE, 0xE7, 0x00, 0x21, ++ 0x91, 0x62, 0x00, 0x2B, 0xE2, 0xD1, 0x01, 0xE0, 0x00, 0x2C, 0xE7, 0xD0, ++ 0x0A, 0x49, 0x0B, 0x68, 0x0D, 0x4A, 0x1A, 0x40, 0x80, 0x23, 0x1B, 0x04, ++ 0x13, 0x43, 0x0B, 0x60, 0xDE, 0xE7, 0xFF, 0xF7, 0x17, 0xFF, 0xE6, 0xE7, ++ 0x24, 0x27, 0x16, 0x00, 0x18, 0x27, 0x16, 0x00, 0x28, 0x27, 0x16, 0x00, ++ 0x20, 0x27, 0x16, 0x00, 0xB1, 0xE6, 0x10, 0x00, 0x00, 0x04, 0x60, 0x40, ++ 0xFF, 0xFF, 0xDF, 0xFF, 0x80, 0x2A, 0x16, 0x00, 0x0C, 0xE7, 0x10, 0x00, ++ 0xFF, 0xFF, 0x7F, 0xFF, 0x02, 0x4B, 0x1B, 0x68, 0x04, 0x20, 0x18, 0x40, ++ 0x70, 0x47, 0xC0, 0x46, 0x80, 0x40, 0x34, 0x40, 0x10, 0xB5, 0x04, 0x00, ++ 0x01, 0x00, 0x12, 0x48, 0x82, 0xF7, 0x98, 0xF8, 0x00, 0x2C, 0x1E, 0xD0, ++ 0x10, 0x4B, 0x1A, 0x68, 0x10, 0x48, 0x02, 0x40, 0xD0, 0x21, 0x89, 0x03, ++ 0x0A, 0x43, 0x1A, 0x60, 0x1C, 0x68, 0x04, 0x40, 0xA0, 0x22, 0x52, 0x03, ++ 0x22, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x02, 0x40, 0x11, 0x43, 0x19, 0x60, ++ 0x09, 0x49, 0x04, 0x22, 0x0B, 0x68, 0x1A, 0x42, 0xFC, 0xD0, 0x05, 0x49, ++ 0x0B, 0x68, 0x05, 0x4A, 0x1A, 0x40, 0x80, 0x23, 0x9B, 0x03, 0x13, 0x43, ++ 0x0B, 0x60, 0x10, 0xBD, 0x90, 0xD0, 0x10, 0x00, 0x58, 0x40, 0x34, 0x40, ++ 0xFF, 0xFF, 0xC1, 0xFF, 0x80, 0x40, 0x34, 0x40, 0xF8, 0xB5, 0x04, 0x00, ++ 0x83, 0x7D, 0x02, 0x33, 0x83, 0x75, 0x03, 0x6C, 0x03, 0x61, 0xB2, 0xF7, ++ 0xF9, 0xFC, 0x00, 0x28, 0x24, 0xD1, 0x20, 0x4E, 0x4C, 0x25, 0x20, 0x4F, ++ 0x20, 0x00, 0xD4, 0xF7, 0x19, 0xFA, 0x00, 0x28, 0x33, 0xD0, 0x31, 0x00, ++ 0x20, 0x69, 0xD6, 0xF7, 0xFD, 0xF9, 0x63, 0x68, 0x9C, 0x46, 0x60, 0x44, ++ 0x00, 0x01, 0x00, 0x09, 0x60, 0x60, 0x63, 0x5B, 0x5B, 0x00, 0xE2, 0x68, ++ 0x94, 0x46, 0x63, 0x44, 0x1B, 0x01, 0x1B, 0x09, 0xE3, 0x60, 0xA3, 0x7D, ++ 0x14, 0x4A, 0x52, 0x78, 0x9B, 0x18, 0xA3, 0x75, 0x10, 0x4B, 0x9C, 0x46, ++ 0x66, 0x44, 0xBE, 0x42, 0xDE, 0xD1, 0xF8, 0xBD, 0x63, 0x68, 0x18, 0x33, ++ 0x1B, 0x01, 0x1B, 0x09, 0x63, 0x60, 0x18, 0x26, 0x65, 0x68, 0x00, 0x22, ++ 0x21, 0x69, 0x20, 0x00, 0xFF, 0xF7, 0x3C, 0xFA, 0x63, 0x68, 0xAB, 0x42, ++ 0xCB, 0xD0, 0x75, 0x19, 0x2D, 0x01, 0x2D, 0x09, 0x65, 0x60, 0x18, 0x36, ++ 0x90, 0x2E, 0xEF, 0xD1, 0xC3, 0xE7, 0x4E, 0x23, 0x00, 0x22, 0xE2, 0x54, ++ 0xE3, 0xE7, 0xC0, 0x46, 0xE2, 0x04, 0x00, 0x00, 0x6A, 0x18, 0x00, 0x00, ++ 0x7C, 0x91, 0x0D, 0x00, 0x10, 0xB5, 0xFF, 0xF7, 0xAB, 0xFF, 0x10, 0xBD, ++ 0xF8, 0xB5, 0x04, 0x00, 0x4E, 0x23, 0xC3, 0x5C, 0x00, 0x2B, 0x00, 0xD0, ++ 0xF8, 0xBD, 0x00, 0x21, 0xD4, 0xF7, 0x6E, 0xFB, 0xA9, 0xF7, 0x38, 0xFB, ++ 0x23, 0x6C, 0x23, 0x61, 0x60, 0x60, 0x04, 0x26, 0x4C, 0x27, 0x10, 0x4D, ++ 0x20, 0x00, 0xD4, 0xF7, 0xBF, 0xF9, 0x00, 0x28, 0x15, 0xD0, 0x63, 0x68, ++ 0x04, 0x33, 0x1B, 0x01, 0x1B, 0x09, 0x63, 0x60, 0xE3, 0x5B, 0x5B, 0x00, ++ 0xE2, 0x68, 0x94, 0x46, 0x63, 0x44, 0x1B, 0x01, 0x1B, 0x09, 0xE3, 0x60, ++ 0xA3, 0x7D, 0x6A, 0x78, 0x9B, 0x18, 0xA3, 0x75, 0x01, 0x3E, 0xF6, 0xB2, ++ 0x00, 0x2E, 0xE5, 0xD1, 0xD8, 0xE7, 0x4E, 0x23, 0x00, 0x22, 0xE2, 0x54, ++ 0xD4, 0xE7, 0xC0, 0x46, 0x7C, 0x91, 0x0D, 0x00, 0x70, 0xB5, 0xEF, 0xF3, ++ 0x10, 0x83, 0x01, 0x22, 0x14, 0x00, 0x1C, 0x40, 0x1A, 0x42, 0x1C, 0xD1, ++ 0x72, 0xB6, 0x10, 0x4B, 0x18, 0x68, 0x00, 0x28, 0x07, 0xD0, 0x4E, 0x23, ++ 0xC3, 0x5C, 0x00, 0x2B, 0x05, 0xD0, 0x01, 0x2B, 0x0D, 0xD0, 0x00, 0x2C, ++ 0x00, 0xD1, 0x62, 0xB6, 0x70, 0xBD, 0x00, 0x21, 0xD4, 0xF7, 0x2A, 0xFB, ++ 0x07, 0x4D, 0x28, 0x68, 0x80, 0xF7, 0x38, 0xF8, 0x00, 0x23, 0x2B, 0x60, ++ 0xF1, 0xE7, 0x4E, 0x23, 0x02, 0x22, 0xC2, 0x54, 0xED, 0xE7, 0x02, 0x4B, ++ 0x18, 0x68, 0x00, 0x28, 0xE3, 0xD1, 0xEB, 0xE7, 0xF8, 0xE6, 0x10, 0x00, ++ 0xF8, 0xB5, 0x05, 0x00, 0x36, 0x4B, 0x1B, 0x68, 0x0C, 0x20, 0x00, 0x2B, ++ 0x00, 0xD0, 0xF8, 0xBD, 0x00, 0x21, 0x48, 0x30, 0x7F, 0xF7, 0x7A, 0xFF, ++ 0x31, 0x4B, 0x18, 0x60, 0x00, 0x28, 0x56, 0xD0, 0xA9, 0xF7, 0xD2, 0xFA, ++ 0x06, 0x00, 0x00, 0x27, 0x2E, 0x4B, 0x1F, 0x60, 0x2E, 0x4B, 0x1F, 0x60, ++ 0x2B, 0x4B, 0x1C, 0x68, 0x54, 0x22, 0x00, 0x21, 0x20, 0x00, 0x7D, 0xF7, ++ 0x19, 0xFF, 0x2B, 0x68, 0xA3, 0x62, 0x6A, 0x68, 0x22, 0x63, 0xEA, 0x68, ++ 0xE2, 0x63, 0x2A, 0x68, 0xE2, 0x62, 0xAA, 0x68, 0xA2, 0x63, 0x62, 0x63, ++ 0x1B, 0x01, 0x4C, 0x22, 0xA3, 0x52, 0x24, 0x4A, 0x22, 0x64, 0x24, 0x4B, ++ 0x63, 0x62, 0x24, 0x4B, 0xE3, 0x61, 0x24, 0x4B, 0x23, 0x62, 0x03, 0x23, ++ 0x23, 0x76, 0x23, 0x4B, 0x9B, 0x78, 0x02, 0x33, 0xA3, 0x75, 0x22, 0x61, ++ 0xE7, 0x75, 0x05, 0x23, 0x63, 0x76, 0xEF, 0xF3, 0x10, 0x83, 0x01, 0x22, ++ 0x15, 0x00, 0x1D, 0x40, 0x1A, 0x42, 0x00, 0xD1, 0x72, 0xB6, 0x66, 0x60, ++ 0x00, 0x23, 0xA3, 0x60, 0x1A, 0x4B, 0xA3, 0x82, 0x4C, 0x23, 0xE0, 0x5A, ++ 0x40, 0x00, 0x80, 0x19, 0x00, 0x01, 0x00, 0x09, 0xE0, 0x60, 0x20, 0x00, ++ 0xD4, 0xF7, 0x1E, 0xF9, 0x00, 0x28, 0x06, 0xD1, 0x4E, 0x23, 0x00, 0x22, ++ 0xE2, 0x54, 0x00, 0x2D, 0xA9, 0xD1, 0x62, 0xB6, 0xA7, 0xE7, 0x11, 0x4B, ++ 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x0C, 0x20, ++ 0xF3, 0xE7, 0x0D, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, ++ 0x98, 0x47, 0x0C, 0x20, 0x97, 0xE7, 0xC0, 0x46, 0xF8, 0xE6, 0x10, 0x00, ++ 0x58, 0xE6, 0x10, 0x00, 0x5C, 0xE6, 0x10, 0x00, 0xE8, 0xFD, 0x00, 0x00, ++ 0xB9, 0x21, 0x10, 0x00, 0xC9, 0x1F, 0x10, 0x00, 0x05, 0x4B, 0x10, 0x00, ++ 0x7C, 0x91, 0x0D, 0x00, 0x00, 0xA0, 0xFF, 0xFF, 0x28, 0x19, 0x16, 0x00, ++ 0x10, 0xB5, 0x06, 0x4B, 0x18, 0x68, 0x00, 0x28, 0x03, 0xD0, 0x4F, 0x23, ++ 0xC3, 0x5C, 0x01, 0x2B, 0x00, 0xD0, 0x10, 0xBD, 0xFF, 0xF7, 0x84, 0xFD, ++ 0xFB, 0xE7, 0xC0, 0x46, 0xF8, 0xE6, 0x10, 0x00, 0xF0, 0xB5, 0xC6, 0x46, ++ 0x00, 0xB5, 0x85, 0xF7, 0x55, 0xFE, 0x4C, 0x4B, 0x1B, 0x68, 0x01, 0x2B, ++ 0x02, 0xD0, 0x4A, 0x4B, 0x02, 0x22, 0x1A, 0x60, 0x49, 0x4A, 0x48, 0x4B, ++ 0x19, 0x68, 0x49, 0x4B, 0xD1, 0x54, 0x00, 0x21, 0x42, 0x3B, 0xD1, 0x54, ++ 0x0B, 0x23, 0x47, 0x48, 0x13, 0x54, 0x01, 0x30, 0x13, 0x54, 0x46, 0x4B, ++ 0x1B, 0x68, 0x1C, 0x0A, 0x50, 0x38, 0x14, 0x54, 0x44, 0x48, 0x13, 0x54, ++ 0x44, 0x4B, 0x20, 0x20, 0xD0, 0x54, 0x44, 0x4B, 0x10, 0x38, 0xD0, 0x54, ++ 0x43, 0x4B, 0x19, 0x60, 0x00, 0x24, 0x00, 0x23, 0x98, 0x46, 0x00, 0x27, ++ 0x01, 0x34, 0xE4, 0xB2, 0x01, 0x2C, 0x0B, 0xD0, 0x02, 0x2C, 0x3E, 0xD0, ++ 0x03, 0x2C, 0x4C, 0xD0, 0x3D, 0x4A, 0x13, 0x78, 0x20, 0x21, 0x8B, 0x43, ++ 0x13, 0x70, 0x04, 0xBC, 0x90, 0x46, 0xF0, 0xBD, 0x0C, 0x20, 0xFE, 0xF7, ++ 0xA7, 0xF9, 0x06, 0x00, 0x0D, 0x20, 0xFE, 0xF7, 0xA3, 0xF9, 0x05, 0x04, ++ 0x2D, 0x0C, 0x2A, 0x00, 0x31, 0x00, 0x35, 0x48, 0x81, 0xF7, 0xDA, 0xFE, ++ 0x2B, 0x00, 0x33, 0x43, 0xDE, 0xD0, 0x43, 0x46, 0x00, 0x2B, 0x41, 0xD0, ++ 0x27, 0x4B, 0x2A, 0x0A, 0x1A, 0x70, 0x5D, 0x70, 0x32, 0x0E, 0x9A, 0x70, ++ 0x32, 0x0C, 0xDA, 0x70, 0x32, 0x0A, 0x1A, 0x71, 0x5E, 0x71, 0x00, 0x2F, ++ 0x0A, 0xD0, 0x21, 0x4A, 0x11, 0x1D, 0x13, 0x78, 0x01, 0x33, 0xDB, 0xB2, ++ 0x13, 0x70, 0x00, 0x2B, 0x02, 0xD1, 0x01, 0x32, 0x8A, 0x42, 0xF6, 0xD1, ++ 0x1B, 0x4C, 0x20, 0x68, 0x61, 0x68, 0xA9, 0xF7, 0xD1, 0xFC, 0x20, 0x00, ++ 0xB9, 0xF7, 0x0E, 0xFB, 0xC2, 0xE7, 0x07, 0x20, 0xFE, 0xF7, 0x72, 0xF9, ++ 0x06, 0x00, 0x08, 0x20, 0xFE, 0xF7, 0x6E, 0xF9, 0x05, 0x04, 0x2D, 0x0C, ++ 0x2A, 0x00, 0x31, 0x00, 0x1B, 0x48, 0x81, 0xF7, 0xA5, 0xFE, 0x01, 0x27, ++ 0xC8, 0xE7, 0x1A, 0x4B, 0x1E, 0x88, 0x58, 0x88, 0x00, 0x04, 0x06, 0x43, ++ 0x18, 0x4B, 0x1D, 0x88, 0x5B, 0x88, 0x2A, 0x00, 0x31, 0x00, 0x17, 0x48, ++ 0x81, 0xF7, 0x96, 0xFE, 0x01, 0x23, 0x98, 0x46, 0x00, 0x27, 0xB7, 0xE7, ++ 0x06, 0x4B, 0x2A, 0x0A, 0x5A, 0x71, 0x1D, 0x71, 0x32, 0x0E, 0xDA, 0x70, ++ 0x32, 0x0C, 0x9A, 0x70, 0x32, 0x0A, 0x5A, 0x70, 0x1E, 0x70, 0xBC, 0xE7, ++ 0xA8, 0xE5, 0x10, 0x00, 0x7C, 0x1E, 0x16, 0x00, 0x9A, 0x02, 0x00, 0x00, ++ 0xA3, 0x02, 0x00, 0x00, 0xB0, 0xE5, 0x10, 0x00, 0x55, 0x02, 0x00, 0x00, ++ 0x56, 0x02, 0x00, 0x00, 0x57, 0x02, 0x00, 0x00, 0xF8, 0xE6, 0x10, 0x00, ++ 0xEC, 0xE1, 0x10, 0x00, 0xA0, 0xD0, 0x10, 0x00, 0xB0, 0xD0, 0x10, 0x00, ++ 0x12, 0xC0, 0x1F, 0x08, 0x16, 0xC0, 0x1F, 0x08, 0xC4, 0xD0, 0x10, 0x00, ++ 0x30, 0xB5, 0x89, 0xB0, 0x05, 0x00, 0x14, 0x00, 0x00, 0x28, 0x14, 0xD1, ++ 0x1F, 0x4B, 0x20, 0x48, 0x1A, 0x5C, 0x04, 0x35, 0xAA, 0x43, 0x1A, 0x54, ++ 0x02, 0x30, 0x1A, 0x5C, 0x3E, 0x35, 0xAA, 0x43, 0x1A, 0x54, 0x22, 0x00, ++ 0x00, 0x20, 0x8D, 0xF7, 0xF9, 0xFF, 0x1A, 0x4B, 0x1B, 0x68, 0x00, 0x2B, ++ 0x0E, 0xD0, 0x09, 0xB0, 0x30, 0xBD, 0x8D, 0xF7, 0xF1, 0xFF, 0x02, 0x2D, ++ 0xF5, 0xD1, 0x23, 0x78, 0x0C, 0x22, 0x93, 0x43, 0x23, 0x70, 0x63, 0x78, ++ 0x0B, 0x3A, 0x93, 0x43, 0x63, 0x70, 0xEC, 0xE7, 0x11, 0x4B, 0x1B, 0x68, ++ 0x01, 0x2B, 0xEC, 0xD8, 0x00, 0x23, 0x07, 0x93, 0x0F, 0x4B, 0x1B, 0x68, ++ 0x03, 0x93, 0x0F, 0x4B, 0x1B, 0x68, 0x01, 0x93, 0x04, 0x93, 0x0E, 0x4B, ++ 0x18, 0x68, 0x0E, 0x49, 0xD5, 0xF7, 0xD4, 0xFF, 0x05, 0x90, 0x0D, 0x4B, ++ 0x18, 0x68, 0x0B, 0x49, 0xD5, 0xF7, 0xCE, 0xFF, 0x06, 0x90, 0x03, 0xA8, ++ 0xFF, 0xF7, 0x6C, 0xFE, 0xD3, 0xE7, 0xC0, 0x46, 0x7C, 0x1E, 0x16, 0x00, ++ 0x9E, 0x02, 0x00, 0x00, 0xF8, 0xE6, 0x10, 0x00, 0x50, 0xE0, 0x10, 0x00, ++ 0x0C, 0xE2, 0x10, 0x00, 0x10, 0xE2, 0x10, 0x00, 0x04, 0xE2, 0x10, 0x00, ++ 0x71, 0x02, 0x00, 0x00, 0x08, 0xE2, 0x10, 0x00, 0x80, 0x00, 0x08, 0x4B, ++ 0xC3, 0x58, 0x88, 0x22, 0xFF, 0x32, 0x9A, 0x5C, 0x00, 0x20, 0x01, 0x2A, ++ 0x00, 0xD0, 0x70, 0x47, 0x8A, 0x22, 0xFF, 0x32, 0x98, 0x5C, 0x01, 0x38, ++ 0x43, 0x42, 0x58, 0x41, 0xF7, 0xE7, 0xC0, 0x46, 0x64, 0xA2, 0x16, 0x00, ++ 0x00, 0x23, 0x00, 0x20, 0x06, 0x49, 0x02, 0xE0, 0x01, 0x33, 0x07, 0x2B, ++ 0x06, 0xD0, 0x9A, 0x00, 0x52, 0x58, 0x00, 0x2A, 0xF8, 0xD0, 0x01, 0x30, ++ 0xC0, 0xB2, 0xF5, 0xE7, 0x70, 0x47, 0xC0, 0x46, 0x38, 0x27, 0x16, 0x00, ++ 0x70, 0xB5, 0x82, 0xB0, 0x14, 0x00, 0x15, 0x0A, 0xAA, 0x00, 0x30, 0x4B, ++ 0xD6, 0x58, 0x20, 0x00, 0x80, 0xF7, 0xB2, 0xF8, 0x03, 0x00, 0x02, 0x00, ++ 0x01, 0x28, 0x12, 0xD0, 0x00, 0x20, 0x01, 0x2B, 0x05, 0xD9, 0x19, 0x2B, ++ 0x05, 0xD8, 0x15, 0x23, 0x93, 0x42, 0x40, 0x41, 0x40, 0x00, 0x02, 0xB0, ++ 0x70, 0xBD, 0x58, 0x3B, 0xDB, 0xB2, 0x01, 0x20, 0x98, 0x42, 0x80, 0x41, ++ 0x40, 0x42, 0x40, 0x00, 0xF5, 0xE7, 0x4C, 0x23, 0xF3, 0x5C, 0x00, 0x2B, ++ 0x3A, 0xD1, 0x4B, 0x33, 0xF3, 0x5C, 0x00, 0x2B, 0x02, 0xD0, 0x4B, 0x23, ++ 0x00, 0x22, 0xF2, 0x54, 0x4F, 0x23, 0xF3, 0x5C, 0x00, 0x2B, 0x16, 0xD1, ++ 0x36, 0x33, 0xF2, 0x5C, 0x35, 0x3B, 0x13, 0x40, 0x3E, 0x22, 0x13, 0x43, ++ 0x6A, 0x46, 0x13, 0x71, 0x00, 0x23, 0x53, 0x71, 0xE8, 0xB2, 0x01, 0xA9, ++ 0xA7, 0xF7, 0x98, 0xF9, 0x14, 0x48, 0x81, 0xF7, 0xA9, 0xFD, 0x59, 0x21, ++ 0x20, 0x00, 0x80, 0xF7, 0x17, 0xF8, 0x00, 0x20, 0xCF, 0xE7, 0x01, 0xA9, ++ 0x36, 0x23, 0xF2, 0x5C, 0x38, 0x3B, 0x13, 0x43, 0x0B, 0x70, 0x1F, 0x23, ++ 0x4B, 0x70, 0x1E, 0x3B, 0x8B, 0x70, 0xE8, 0xB2, 0xA7, 0xF7, 0x82, 0xF9, ++ 0x0A, 0x48, 0x81, 0xF7, 0x93, 0xFD, 0x20, 0x00, 0x97, 0xF7, 0x72, 0xFD, ++ 0x58, 0x21, 0x20, 0x00, 0x7F, 0xF7, 0xFE, 0xFF, 0x00, 0x20, 0xB6, 0xE7, ++ 0x05, 0x48, 0x81, 0xF7, 0x87, 0xFD, 0x00, 0x20, 0xB1, 0xE7, 0xC0, 0x46, ++ 0x64, 0xA2, 0x16, 0x00, 0xDC, 0xD0, 0x10, 0x00, 0xEC, 0xD0, 0x10, 0x00, ++ 0xFC, 0xD0, 0x10, 0x00, 0xF0, 0xB5, 0x05, 0xAC, 0x24, 0x78, 0x4E, 0x28, ++ 0x3C, 0xD8, 0xFF, 0x2C, 0x08, 0xD0, 0x10, 0x2C, 0x0B, 0xD9, 0x18, 0x2C, ++ 0x37, 0xD9, 0x20, 0x2C, 0x38, 0xD9, 0x03, 0x26, 0x00, 0x25, 0x06, 0xE0, ++ 0x32, 0x4C, 0x24, 0x18, 0xED, 0x34, 0x24, 0x78, 0xF1, 0xE7, 0x00, 0x26, ++ 0x03, 0x25, 0x00, 0x29, 0x36, 0xD0, 0x2E, 0x4F, 0x39, 0x18, 0x0E, 0x00, ++ 0x4F, 0x36, 0x33, 0x70, 0x3E, 0x56, 0xF3, 0x18, 0x5B, 0x10, 0x3B, 0x54, ++ 0x0B, 0x00, 0xED, 0x33, 0x1C, 0x70, 0x0E, 0x00, 0x9E, 0x36, 0x33, 0x78, ++ 0x1C, 0x19, 0x64, 0x10, 0x34, 0x70, 0x8C, 0x31, 0xFF, 0x31, 0x00, 0x23, ++ 0x0B, 0x70, 0x24, 0x4B, 0x1B, 0x18, 0x49, 0x33, 0xFF, 0x33, 0x1B, 0x78, ++ 0xED, 0x18, 0x6D, 0xB2, 0x06, 0x2D, 0x10, 0xDC, 0x1F, 0x4B, 0x1B, 0x18, ++ 0x49, 0x33, 0xFF, 0x33, 0x1D, 0x70, 0x02, 0x30, 0x80, 0x00, 0x1C, 0x4B, ++ 0x18, 0x18, 0x42, 0x60, 0xF0, 0xBD, 0x01, 0x26, 0x02, 0x25, 0xD0, 0xE7, ++ 0x02, 0x26, 0x01, 0x25, 0xCD, 0xE7, 0x17, 0x4B, 0x1B, 0x18, 0x49, 0x33, ++ 0xFF, 0x33, 0x06, 0x21, 0x19, 0x70, 0xEC, 0xE7, 0x12, 0x4B, 0x1B, 0x18, ++ 0x8C, 0x33, 0xFF, 0x33, 0x1B, 0x78, 0x01, 0x2B, 0x14, 0xD0, 0x0F, 0x49, ++ 0x09, 0x18, 0x8C, 0x31, 0xFF, 0x31, 0x01, 0x23, 0x0B, 0x70, 0x0D, 0x49, ++ 0x09, 0x18, 0x49, 0x31, 0xFF, 0x31, 0x0B, 0x78, 0x9B, 0x1B, 0x5B, 0xB2, ++ 0x99, 0x1D, 0x08, 0xDB, 0x08, 0x49, 0x09, 0x18, 0x49, 0x31, 0xFF, 0x31, ++ 0x0B, 0x70, 0xD0, 0xE7, 0x02, 0x36, 0xF6, 0xB2, 0xE7, 0xE7, 0x04, 0x4B, ++ 0x1B, 0x18, 0x49, 0x33, 0xFF, 0x33, 0xFA, 0x21, 0x19, 0x70, 0xC6, 0xE7, ++ 0x1C, 0xE7, 0x10, 0x00, 0x20, 0xA3, 0x16, 0x00, 0xF8, 0xB5, 0xDE, 0x46, ++ 0x57, 0x46, 0x4E, 0x46, 0x45, 0x46, 0xE0, 0xB5, 0x8B, 0x4C, 0x00, 0x25, ++ 0x00, 0x22, 0x01, 0x26, 0xC1, 0x27, 0xFF, 0x00, 0x03, 0xE0, 0x01, 0x35, ++ 0x09, 0x34, 0x07, 0x2D, 0x0E, 0xD0, 0x23, 0x78, 0x03, 0x2B, 0xF8, 0xD1, ++ 0x63, 0x78, 0x00, 0x2B, 0xF5, 0xD1, 0x29, 0x02, 0x31, 0x43, 0x89, 0xB2, ++ 0x00, 0x22, 0x38, 0x00, 0x7F, 0xF7, 0x20, 0xFC, 0x01, 0x22, 0xEC, 0xE7, ++ 0x00, 0x2A, 0x0B, 0xD1, 0x7E, 0x4A, 0xD9, 0x23, 0x5B, 0x00, 0x00, 0x21, ++ 0xD1, 0x54, 0x00, 0x20, 0x3C, 0xBC, 0x90, 0x46, 0x99, 0x46, 0xA2, 0x46, ++ 0xAB, 0x46, 0xF8, 0xBD, 0xA8, 0xF7, 0xFE, 0xFF, 0x82, 0x46, 0x8E, 0xF7, ++ 0x09, 0xF8, 0x80, 0x46, 0xA9, 0xF7, 0x18, 0xFB, 0x81, 0x46, 0x00, 0x24, ++ 0x73, 0x4B, 0x9B, 0x46, 0x63, 0xE0, 0x8D, 0xF7, 0xF3, 0xFF, 0x00, 0x28, ++ 0x19, 0xD0, 0xA3, 0x00, 0x4A, 0x46, 0xD3, 0x58, 0x52, 0x46, 0xD3, 0x1A, ++ 0x1B, 0x01, 0x1B, 0x09, 0xC8, 0x22, 0x92, 0x01, 0x93, 0x42, 0x3D, 0xD2, ++ 0x4B, 0x46, 0x3D, 0x33, 0xFF, 0x33, 0x1B, 0x57, 0x01, 0x33, 0x2D, 0xDB, ++ 0xD4, 0x20, 0x40, 0x00, 0x66, 0x4B, 0x5B, 0x19, 0x01, 0x21, 0xB1, 0x40, ++ 0x1A, 0x5C, 0x0A, 0x43, 0x1A, 0x54, 0x2A, 0x00, 0x63, 0x32, 0xFF, 0x32, ++ 0x5A, 0x44, 0x00, 0x21, 0x06, 0x20, 0x38, 0x40, 0x03, 0x27, 0x13, 0x78, ++ 0x03, 0x41, 0x3B, 0x40, 0x03, 0x2B, 0x27, 0xD0, 0x01, 0x31, 0x0A, 0x32, ++ 0x07, 0x29, 0xF6, 0xD1, 0xB3, 0x1E, 0x01, 0x2B, 0x00, 0xD8, 0x98, 0xE0, ++ 0x73, 0x1F, 0x01, 0x2B, 0x00, 0xD8, 0x94, 0xE0, 0xA3, 0x00, 0x4A, 0x46, ++ 0xD3, 0x58, 0x52, 0x46, 0xD3, 0x1A, 0x1B, 0x01, 0x1B, 0x09, 0xFA, 0x22, ++ 0x12, 0x02, 0x93, 0x42, 0x1E, 0xD9, 0x93, 0xE0, 0xD4, 0x21, 0x49, 0x00, ++ 0x4F, 0x4B, 0x5D, 0x19, 0x01, 0x22, 0xB2, 0x40, 0x6B, 0x5C, 0x93, 0x43, ++ 0x6B, 0x54, 0x13, 0xE0, 0x4B, 0x46, 0x3D, 0x33, 0xFF, 0x33, 0x00, 0x22, ++ 0x1A, 0x55, 0xCA, 0xE7, 0xD4, 0x20, 0x40, 0x00, 0x47, 0x4B, 0x9C, 0x46, ++ 0xAC, 0x44, 0x01, 0x22, 0xB2, 0x40, 0x63, 0x46, 0x1B, 0x5C, 0x93, 0x43, ++ 0x62, 0x46, 0x13, 0x54, 0x07, 0x29, 0xCD, 0xD0, 0x01, 0x34, 0x4F, 0x2C, ++ 0x13, 0xD0, 0xE7, 0xB2, 0x07, 0x26, 0x26, 0x40, 0x65, 0x05, 0x2D, 0x0E, ++ 0x43, 0x46, 0x5B, 0x5D, 0x33, 0x41, 0xDB, 0x07, 0x91, 0xD4, 0xD4, 0x21, ++ 0x49, 0x00, 0x3A, 0x4B, 0x5D, 0x19, 0x01, 0x22, 0xB2, 0x40, 0x6B, 0x5C, ++ 0x93, 0x43, 0x6B, 0x54, 0xE8, 0xE7, 0x37, 0x48, 0x81, 0xF7, 0xB0, 0xFC, ++ 0x13, 0x28, 0x41, 0xD8, 0x14, 0x23, 0x1B, 0x1A, 0xDB, 0xB2, 0x9B, 0x46, ++ 0x14, 0x25, 0x2D, 0x1A, 0x00, 0x23, 0x99, 0x46, 0x00, 0x24, 0x2F, 0x4E, ++ 0x0E, 0xE0, 0x48, 0x46, 0x13, 0x28, 0x09, 0xD9, 0x2C, 0x48, 0x84, 0x46, ++ 0x62, 0x44, 0x01, 0x20, 0x98, 0x40, 0x01, 0x43, 0xD4, 0x23, 0x5B, 0x00, ++ 0xD1, 0x54, 0x01, 0x34, 0xAC, 0x42, 0x27, 0xDA, 0xD6, 0xF7, 0xDA, 0xFA, ++ 0x7F, 0x23, 0x18, 0x40, 0x4E, 0x28, 0x00, 0xD9, 0x4F, 0x38, 0xC2, 0x08, ++ 0xB1, 0x18, 0xD4, 0x23, 0x5B, 0x00, 0xC9, 0x5C, 0xA2, 0x3B, 0xFF, 0x3B, ++ 0x03, 0x40, 0x0F, 0x00, 0x1F, 0x41, 0xFF, 0x07, 0xEA, 0xD4, 0x47, 0x46, ++ 0xBF, 0x5C, 0x1F, 0x41, 0xFF, 0x07, 0xE5, 0xD5, 0x4F, 0x46, 0x01, 0x37, ++ 0xFF, 0xB2, 0xB9, 0x46, 0x1A, 0x4F, 0xBC, 0x46, 0x60, 0x44, 0x9E, 0x30, ++ 0x00, 0x78, 0x18, 0x28, 0xD0, 0xD9, 0xCB, 0x45, 0xCB, 0xD8, 0x20, 0x28, ++ 0xCC, 0xD9, 0xC8, 0xE7, 0x13, 0x48, 0x81, 0xF7, 0x69, 0xFC, 0x01, 0x00, ++ 0x13, 0x48, 0x81, 0xF7, 0x01, 0xFC, 0xC8, 0x22, 0x00, 0x21, 0x12, 0x48, ++ 0x7F, 0xF7, 0x38, 0xFA, 0x1F, 0xE7, 0xA3, 0x00, 0x4A, 0x46, 0xD3, 0x58, ++ 0x52, 0x46, 0xD3, 0x1A, 0x1B, 0x01, 0x1B, 0x09, 0xFA, 0x22, 0xD2, 0x01, ++ 0x93, 0x42, 0x89, 0xD9, 0xD4, 0x21, 0x49, 0x00, 0x05, 0x4B, 0x9C, 0x46, ++ 0x65, 0x44, 0x01, 0x22, 0xB2, 0x40, 0x6B, 0x5C, 0x13, 0x43, 0x6B, 0x54, ++ 0x7E, 0xE7, 0xC0, 0x46, 0xA4, 0x9E, 0x16, 0x00, 0x68, 0x9E, 0x16, 0x00, ++ 0x10, 0xA0, 0x16, 0x00, 0x1C, 0xE7, 0x10, 0x00, 0x0C, 0xD1, 0x10, 0x00, ++ 0x0A, 0x05, 0x00, 0x00, 0xF0, 0xB5, 0xDE, 0x46, 0x57, 0x46, 0x4E, 0x46, ++ 0x45, 0x46, 0xE0, 0xB5, 0x87, 0xB0, 0x07, 0x00, 0x08, 0x00, 0x00, 0x91, ++ 0xBA, 0x00, 0xA4, 0x4B, 0xD5, 0x58, 0xA6, 0x23, 0xEB, 0x5C, 0x9B, 0x46, ++ 0x2B, 0x6D, 0x98, 0x46, 0x62, 0x23, 0x7B, 0x43, 0xA0, 0x4A, 0x9A, 0x18, ++ 0x16, 0x88, 0xA0, 0x4A, 0x9A, 0x18, 0x14, 0x88, 0x36, 0x04, 0x26, 0x43, ++ 0x9E, 0x4A, 0x9A, 0x18, 0x12, 0x88, 0x92, 0x05, 0x92, 0x0D, 0x91, 0x46, ++ 0x9C, 0x4A, 0x9A, 0x18, 0x14, 0x88, 0x9C, 0x4A, 0x94, 0x46, 0x63, 0x44, ++ 0x1B, 0x88, 0x24, 0x04, 0x1C, 0x19, 0x9A, 0x4B, 0x98, 0x45, 0x1A, 0xD8, ++ 0x73, 0x1A, 0x19, 0x01, 0x09, 0x09, 0x80, 0x22, 0x12, 0x05, 0x91, 0x42, ++ 0x4A, 0xD9, 0x83, 0x1B, 0x1B, 0x01, 0x1B, 0x09, 0x5B, 0x42, 0xA1, 0x22, ++ 0xAA, 0x5C, 0x00, 0x2A, 0x49, 0xD0, 0x00, 0x2B, 0x09, 0xDB, 0x89, 0x08, ++ 0x00, 0x29, 0x06, 0xDD, 0x89, 0x00, 0x00, 0x9B, 0x9C, 0x46, 0x61, 0x44, ++ 0x09, 0x01, 0x0B, 0x09, 0x00, 0x93, 0xA4, 0x1B, 0x00, 0x9B, 0x9C, 0x46, ++ 0x64, 0x44, 0x24, 0x01, 0x24, 0x09, 0xF4, 0x26, 0x76, 0x00, 0x4B, 0x46, ++ 0xF6, 0x1A, 0x3B, 0xD4, 0xAC, 0x67, 0x82, 0x23, 0xEE, 0x52, 0x62, 0x42, ++ 0x7F, 0x3B, 0x13, 0x40, 0xA6, 0x22, 0xAB, 0x54, 0x72, 0x3A, 0x2A, 0x65, ++ 0x01, 0x96, 0xAE, 0x60, 0x42, 0x46, 0x34, 0x2A, 0x09, 0xD9, 0xEA, 0x7D, ++ 0x00, 0x2A, 0x06, 0xD0, 0xC8, 0x22, 0x52, 0x00, 0xB2, 0x42, 0x92, 0x41, ++ 0x52, 0x42, 0x05, 0x32, 0xEA, 0x75, 0x5B, 0x45, 0x00, 0xD1, 0x9F, 0xE0, ++ 0xA1, 0x23, 0xEB, 0x5C, 0x03, 0x2B, 0x21, 0xD0, 0x3B, 0x02, 0x01, 0x22, ++ 0x13, 0x43, 0x02, 0x93, 0x01, 0x23, 0x98, 0x46, 0xFE, 0x33, 0x9A, 0x46, ++ 0xA9, 0x46, 0x45, 0x46, 0xA0, 0x46, 0x4D, 0xE0, 0x1B, 0x01, 0x1B, 0x09, ++ 0xA1, 0x22, 0xAA, 0x5C, 0x00, 0x2A, 0xB8, 0xD0, 0xB5, 0xE7, 0x00, 0x2B, ++ 0xB5, 0xDA, 0x6C, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, ++ 0x98, 0x47, 0xB8, 0xE7, 0x69, 0x4E, 0xF6, 0x1A, 0x01, 0x34, 0x24, 0x01, ++ 0x24, 0x09, 0xBD, 0xE7, 0xC1, 0x33, 0x99, 0x46, 0xEB, 0x58, 0x6A, 0x6F, ++ 0x94, 0x46, 0x63, 0x44, 0x1B, 0x1B, 0x1B, 0x01, 0x1B, 0x09, 0x4A, 0x46, ++ 0xAB, 0x50, 0x3B, 0x02, 0x01, 0x21, 0x19, 0x43, 0x02, 0x23, 0x3B, 0x32, ++ 0x5F, 0x48, 0x7F, 0xF7, 0x2B, 0xFA, 0x80, 0x46, 0x4B, 0x46, 0xEB, 0x58, ++ 0x5B, 0x08, 0x99, 0x46, 0xCC, 0x23, 0xEB, 0x5A, 0x9A, 0x46, 0x00, 0x2B, ++ 0x05, 0xD1, 0x57, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, ++ 0x98, 0x47, 0x51, 0x46, 0x48, 0x46, 0xD5, 0xF7, 0x47, 0xFD, 0x43, 0x46, ++ 0x19, 0x80, 0x40, 0x46, 0x7F, 0xF7, 0x3C, 0xFA, 0xB0, 0xE7, 0x21, 0x00, ++ 0x03, 0x98, 0xD5, 0xF7, 0x3D, 0xFD, 0x04, 0x9B, 0x59, 0x80, 0x18, 0x00, ++ 0x7F, 0xF7, 0x32, 0xFA, 0x01, 0x3D, 0x3F, 0xD3, 0x53, 0x46, 0x2B, 0x40, ++ 0x9B, 0x00, 0x4B, 0x4A, 0x9C, 0x58, 0x00, 0x2C, 0xF6, 0xD0, 0x46, 0x23, ++ 0xE3, 0x5C, 0xBB, 0x42, 0xF2, 0xD1, 0x63, 0x6B, 0x42, 0x46, 0x9B, 0x1A, ++ 0x1B, 0x01, 0x1B, 0x09, 0x63, 0x63, 0x4A, 0x46, 0x52, 0x6F, 0x94, 0x46, ++ 0x63, 0x44, 0x1B, 0x01, 0x1B, 0x09, 0x63, 0x63, 0x63, 0x68, 0x42, 0x46, ++ 0x9B, 0x1A, 0x1B, 0x01, 0x1B, 0x09, 0x63, 0x60, 0x4A, 0x46, 0x52, 0x6F, ++ 0x94, 0x46, 0x63, 0x44, 0x1B, 0x01, 0x1B, 0x09, 0x63, 0x60, 0x01, 0x9B, ++ 0xA3, 0x60, 0x04, 0x23, 0x52, 0x46, 0x02, 0x99, 0x38, 0x48, 0x7F, 0xF7, ++ 0xD9, 0xF9, 0x04, 0x90, 0x47, 0x23, 0xE3, 0x5C, 0x03, 0x70, 0x63, 0x6B, ++ 0x5B, 0x08, 0x03, 0x93, 0x42, 0x23, 0xE4, 0x5C, 0x00, 0x2C, 0xBC, 0xD1, ++ 0x2D, 0x4B, 0x9B, 0x6E, 0x05, 0x93, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, ++ 0x98, 0x47, 0xB4, 0xE7, 0x44, 0x46, 0x4D, 0x46, 0x6C, 0x67, 0x84, 0x23, ++ 0xEE, 0x52, 0x1D, 0x33, 0xEB, 0x5C, 0x04, 0x2B, 0x0D, 0xD0, 0xA6, 0x23, ++ 0xE8, 0x5C, 0x5B, 0x46, 0xC0, 0x1A, 0x43, 0x1E, 0x98, 0x41, 0xC0, 0xB2, ++ 0x07, 0xB0, 0x3C, 0xBC, 0x90, 0x46, 0x99, 0x46, 0xA2, 0x46, 0xAB, 0x46, ++ 0xF0, 0xBD, 0x7C, 0x33, 0xEB, 0x5A, 0x9E, 0x1B, 0xF3, 0x17, 0xF6, 0x18, ++ 0x5E, 0x40, 0x33, 0xB2, 0x9D, 0x22, 0x52, 0x00, 0x93, 0x42, 0x02, 0xDB, ++ 0x1D, 0x4B, 0x9B, 0x1B, 0x1B, 0xB2, 0x03, 0x2B, 0xE1, 0xDD, 0xE8, 0x23, ++ 0xEB, 0x58, 0x1A, 0x68, 0x00, 0x9B, 0xA8, 0x6F, 0x84, 0x46, 0x63, 0x44, ++ 0x19, 0x00, 0xD3, 0x1A, 0x1B, 0x01, 0x1B, 0x09, 0x80, 0x20, 0x00, 0x05, ++ 0x83, 0x42, 0xD2, 0xD8, 0x09, 0x01, 0x09, 0x09, 0x51, 0x1A, 0x09, 0x01, ++ 0x09, 0x09, 0x64, 0x29, 0xCB, 0xDD, 0x3F, 0x02, 0x01, 0x21, 0x39, 0x43, ++ 0xFF, 0x22, 0x0F, 0x48, 0x7F, 0xF7, 0xC2, 0xF9, 0xC3, 0xE7, 0xC0, 0x46, ++ 0x38, 0x27, 0x16, 0x00, 0x4C, 0x65, 0x61, 0x40, 0x4A, 0x65, 0x61, 0x40, ++ 0x4E, 0x65, 0x61, 0x40, 0xFC, 0x64, 0x61, 0x40, 0xFA, 0x64, 0x61, 0x40, ++ 0xE1, 0x04, 0x00, 0x00, 0x28, 0x19, 0x16, 0x00, 0x59, 0x04, 0x00, 0x00, ++ 0x33, 0x06, 0x00, 0x00, 0x54, 0x27, 0x16, 0x00, 0x34, 0x06, 0x00, 0x00, ++ 0x71, 0x02, 0x00, 0x00, 0x2E, 0x06, 0x00, 0x00, 0xF0, 0xB5, 0xDE, 0x46, ++ 0x57, 0x46, 0x4E, 0x46, 0x45, 0x46, 0xE0, 0xB5, 0x89, 0xB0, 0x03, 0x90, ++ 0x89, 0x46, 0x81, 0x00, 0xC9, 0x4B, 0xCF, 0x58, 0x53, 0x1E, 0xDB, 0xB2, ++ 0x9B, 0x46, 0x00, 0x2A, 0x00, 0xD1, 0x26, 0xE1, 0x03, 0x02, 0x01, 0x22, ++ 0x13, 0x43, 0x07, 0x93, 0xC4, 0x4B, 0x98, 0x46, 0x9A, 0x46, 0x5C, 0x46, ++ 0x83, 0xE0, 0x6B, 0x46, 0x10, 0x21, 0x5B, 0x5E, 0x00, 0x2B, 0x06, 0xDB, ++ 0xA7, 0x21, 0x79, 0x5C, 0x77, 0x29, 0x02, 0xD8, 0x01, 0x31, 0xA7, 0x20, ++ 0x39, 0x54, 0xE9, 0x06, 0x00, 0xD5, 0xD7, 0xE0, 0xA4, 0x21, 0x29, 0x42, ++ 0x5B, 0xD1, 0x29, 0x07, 0x54, 0xD4, 0x00, 0x2B, 0x00, 0xDA, 0xCF, 0xE0, ++ 0xA7, 0x23, 0xFB, 0x5C, 0x77, 0x2B, 0x02, 0xD8, 0xA7, 0x23, 0x02, 0x21, ++ 0xF9, 0x54, 0x0F, 0x23, 0x1A, 0x40, 0x03, 0x25, 0x05, 0x9B, 0x1D, 0x40, ++ 0x03, 0x2A, 0x01, 0xD0, 0x08, 0x2A, 0x02, 0xD1, 0x03, 0x2D, 0x00, 0xD1, ++ 0xCE, 0xE0, 0xEC, 0x23, 0xFB, 0x58, 0x00, 0x2B, 0x00, 0xD0, 0xB7, 0xE0, ++ 0x6B, 0x1E, 0x01, 0x2B, 0x00, 0xD9, 0xB3, 0xE0, 0x05, 0x9B, 0xDE, 0x04, ++ 0xB6, 0x0D, 0x00, 0xD1, 0xAE, 0xE0, 0x04, 0x23, 0xFF, 0x22, 0x07, 0x99, ++ 0xA5, 0x48, 0x7F, 0xF7, 0x0B, 0xF9, 0xA5, 0x4A, 0xD5, 0x23, 0x5B, 0x00, ++ 0xD2, 0x5C, 0xD3, 0x00, 0x9B, 0x1A, 0x5B, 0x00, 0xA2, 0x4A, 0x94, 0x46, ++ 0x63, 0x44, 0x1B, 0x88, 0x03, 0x80, 0x43, 0x88, 0x9B, 0x0A, 0x9B, 0x02, ++ 0x33, 0x43, 0x9F, 0x4E, 0x33, 0x40, 0x2D, 0x03, 0x1D, 0x43, 0xAA, 0x04, ++ 0x92, 0x0C, 0x06, 0x9B, 0x59, 0x42, 0x4B, 0x41, 0x9B, 0x03, 0x13, 0x43, ++ 0x43, 0x80, 0x7F, 0xF7, 0x17, 0xF9, 0x96, 0x4A, 0xD5, 0x23, 0x5B, 0x00, ++ 0xD2, 0x5C, 0xD3, 0x00, 0x9B, 0x1A, 0x5B, 0x00, 0x93, 0x4A, 0x94, 0x46, ++ 0x63, 0x44, 0x00, 0x22, 0x1A, 0x80, 0x7D, 0xE0, 0xFF, 0x22, 0x07, 0x99, ++ 0x91, 0x48, 0x7F, 0xF7, 0x1B, 0xF9, 0xA8, 0xF7, 0x3F, 0xFA, 0x90, 0x4B, ++ 0x1D, 0x68, 0x58, 0x46, 0x43, 0x46, 0xDB, 0x69, 0x98, 0x47, 0x03, 0x00, ++ 0x2D, 0x0A, 0xED, 0xB2, 0x00, 0x95, 0x4A, 0x46, 0x00, 0x21, 0x02, 0x98, ++ 0xFF, 0xF7, 0x52, 0xFC, 0x01, 0x3C, 0xE4, 0xB2, 0xFF, 0x2C, 0x00, 0xD1, ++ 0x99, 0xE0, 0x03, 0x98, 0xA8, 0xF7, 0x54, 0xFA, 0x00, 0x28, 0x00, 0xD1, ++ 0x93, 0xE0, 0xD5, 0x23, 0x5B, 0x00, 0x7E, 0x4A, 0xD2, 0x5C, 0xD3, 0x00, ++ 0x9B, 0x1A, 0x5B, 0x00, 0x80, 0x4A, 0x9A, 0x18, 0x15, 0x88, 0xAD, 0xB2, ++ 0x7F, 0x4A, 0x9A, 0x18, 0x16, 0x88, 0xB6, 0xB2, 0x7E, 0x4A, 0x9A, 0x18, ++ 0x12, 0x88, 0x92, 0xB2, 0x05, 0x92, 0x7D, 0x4A, 0x94, 0x46, 0x63, 0x44, ++ 0x1B, 0x88, 0x9A, 0xB2, 0x04, 0x92, 0xDA, 0xB2, 0x93, 0x46, 0x5B, 0x04, ++ 0x5B, 0x0E, 0x02, 0x93, 0x4B, 0x46, 0xFA, 0x6E, 0x9B, 0x1A, 0x1B, 0x01, ++ 0x1B, 0x09, 0xC8, 0x2B, 0x0A, 0xD9, 0xA7, 0x23, 0xFB, 0x5C, 0x77, 0x2B, ++ 0x06, 0xD8, 0xA1, 0x22, 0xBA, 0x5C, 0x00, 0x2A, 0x02, 0xD1, 0x01, 0x33, ++ 0xA7, 0x32, 0xBB, 0x54, 0xEB, 0x07, 0xB0, 0xD4, 0x07, 0x23, 0x1A, 0x00, ++ 0x32, 0x40, 0x06, 0x92, 0x4A, 0x46, 0xFA, 0x66, 0x33, 0x42, 0x0B, 0xD0, ++ 0x5F, 0x4B, 0xDB, 0x69, 0x58, 0x46, 0x98, 0x47, 0x98, 0x22, 0xBB, 0x5A, ++ 0x1B, 0x18, 0xBB, 0x52, 0x02, 0x32, 0xBB, 0x5C, 0x01, 0x33, 0xBB, 0x54, ++ 0xAB, 0x07, 0x9A, 0xD4, 0x4B, 0x46, 0x3B, 0x67, 0x6B, 0x06, 0x02, 0xD5, ++ 0x06, 0x9B, 0x00, 0x2B, 0x0C, 0xD1, 0xF6, 0x10, 0xF2, 0xB2, 0x0E, 0x23, ++ 0x1E, 0x42, 0x00, 0xD0, 0x1F, 0xE7, 0x99, 0x33, 0xFB, 0x5C, 0x00, 0x2B, ++ 0x02, 0xD0, 0x01, 0x3B, 0xA7, 0x22, 0xBB, 0x54, 0xA8, 0xF7, 0xC6, 0xF9, ++ 0x53, 0x4B, 0x1D, 0x68, 0x58, 0x46, 0x53, 0x46, 0xDB, 0x69, 0x98, 0x47, ++ 0x03, 0x00, 0x2D, 0x0A, 0xED, 0xB2, 0x00, 0x95, 0x4A, 0x46, 0x01, 0x21, ++ 0x02, 0x98, 0xFF, 0xF7, 0xD9, 0xFB, 0x85, 0xE7, 0x47, 0x4A, 0xD5, 0x23, ++ 0x5B, 0x00, 0xD2, 0x5C, 0xD3, 0x00, 0x9B, 0x1A, 0x5B, 0x00, 0x4D, 0x4A, ++ 0x94, 0x46, 0x63, 0x44, 0x19, 0x88, 0x8B, 0xB2, 0x04, 0x93, 0x05, 0x9A, ++ 0xD5, 0x04, 0xAD, 0x0D, 0x6B, 0x1C, 0xFF, 0x22, 0x07, 0x99, 0x48, 0x48, ++ 0x7F, 0xF7, 0x3A, 0xF8, 0x06, 0x00, 0x05, 0x70, 0x04, 0x9B, 0x46, 0x4A, ++ 0x94, 0x46, 0x63, 0x44, 0x19, 0x00, 0x01, 0x30, 0x2A, 0x00, 0xD5, 0xF7, ++ 0x27, 0xFF, 0x30, 0x00, 0x7F, 0xF7, 0x56, 0xF8, 0xC8, 0xE7, 0x62, 0x24, ++ 0x03, 0x9B, 0x5C, 0x43, 0x3F, 0x4B, 0x9C, 0x46, 0x64, 0x44, 0x23, 0x88, ++ 0x80, 0x22, 0x93, 0x43, 0x23, 0x80, 0x89, 0xF7, 0x59, 0xF9, 0x00, 0x28, ++ 0x18, 0xD0, 0x2F, 0x4B, 0x1B, 0x88, 0x9B, 0xB2, 0x00, 0x2B, 0x13, 0xD1, ++ 0x38, 0x4B, 0x1B, 0x88, 0x9B, 0xB2, 0x00, 0x2B, 0x0E, 0xD1, 0x37, 0x4B, ++ 0x1B, 0x88, 0x9B, 0xB2, 0x00, 0x2B, 0x09, 0xD1, 0x35, 0x4B, 0x1B, 0x88, ++ 0x9B, 0xB2, 0x00, 0x2B, 0x04, 0xD1, 0x23, 0x88, 0x80, 0x22, 0x93, 0x43, ++ 0x13, 0x43, 0x23, 0x80, 0x9A, 0x23, 0xFB, 0x5C, 0x96, 0x2B, 0x03, 0xD9, ++ 0xEC, 0x23, 0xFB, 0x58, 0x00, 0x2B, 0x06, 0xD0, 0x09, 0xB0, 0x3C, 0xBC, ++ 0x90, 0x46, 0x99, 0x46, 0xA2, 0x46, 0xAB, 0x46, 0xF0, 0xBD, 0xAC, 0x33, ++ 0xFB, 0x5C, 0x00, 0x2B, 0xF4, 0xD0, 0x9B, 0x23, 0x00, 0x22, 0xFA, 0x54, ++ 0x26, 0x4A, 0x27, 0x4B, 0xD3, 0x5C, 0x5B, 0x07, 0x03, 0xD5, 0x26, 0x4B, ++ 0x1B, 0x78, 0x00, 0x2B, 0x05, 0xD1, 0x00, 0x23, 0x9A, 0x22, 0xBB, 0x54, ++ 0x02, 0x3A, 0xBB, 0x52, 0xE2, 0xE7, 0x03, 0x9B, 0x19, 0x02, 0x01, 0x23, ++ 0x19, 0x43, 0xFF, 0x22, 0x1F, 0x48, 0x7F, 0xF7, 0x17, 0xF8, 0x98, 0x23, ++ 0xF8, 0x5E, 0x9A, 0x23, 0xF9, 0x5C, 0xD5, 0xF7, 0x05, 0xFB, 0x06, 0x4A, ++ 0x2F, 0x23, 0xD3, 0x5C, 0xC0, 0x1A, 0x9B, 0x23, 0xF8, 0x54, 0x17, 0x4A, ++ 0x13, 0x78, 0x01, 0x3B, 0x13, 0x70, 0xE0, 0xE7, 0x38, 0x27, 0x16, 0x00, ++ 0x60, 0x92, 0x16, 0x00, 0x29, 0x06, 0x00, 0x00, 0x20, 0xA3, 0x16, 0x00, ++ 0x9A, 0x69, 0x61, 0x40, 0xFF, 0xCF, 0xFF, 0xFF, 0x2A, 0x06, 0x00, 0x00, ++ 0x0C, 0x01, 0x60, 0x40, 0x92, 0x69, 0x61, 0x40, 0x94, 0x69, 0x61, 0x40, ++ 0x96, 0x69, 0x61, 0x40, 0x98, 0x69, 0x61, 0x40, 0x9C, 0x69, 0x61, 0x40, ++ 0x27, 0x06, 0x00, 0x00, 0x00, 0x00, 0x61, 0x40, 0x0E, 0x65, 0x61, 0x40, ++ 0xA8, 0x69, 0x61, 0x40, 0xB6, 0x69, 0x61, 0x40, 0xC4, 0x69, 0x61, 0x40, ++ 0x7C, 0x1E, 0x16, 0x00, 0x9D, 0x02, 0x00, 0x00, 0x24, 0xE6, 0x10, 0x00, ++ 0x2F, 0x06, 0x00, 0x00, 0xF0, 0xB5, 0xC6, 0x46, 0x00, 0xB5, 0x04, 0x00, ++ 0x88, 0x46, 0x16, 0x00, 0xFF, 0xF7, 0x84, 0xFA, 0x00, 0x28, 0x3F, 0xD1, ++ 0x22, 0x4D, 0x23, 0x4F, 0xEB, 0x5D, 0x04, 0x22, 0x93, 0x43, 0xEB, 0x55, ++ 0x32, 0x00, 0x41, 0x46, 0x20, 0x00, 0xFF, 0xF7, 0x1F, 0xFE, 0xEB, 0x5D, ++ 0x04, 0x22, 0x13, 0x43, 0xEB, 0x55, 0xA4, 0x00, 0x1C, 0x4B, 0xE4, 0x58, ++ 0xA7, 0x23, 0xE3, 0x5C, 0x04, 0x2B, 0x02, 0xD9, 0xA7, 0x23, 0x04, 0x22, ++ 0xE2, 0x54, 0xFE, 0xF7, 0x49, 0xFB, 0x00, 0x28, 0x02, 0xD1, 0x04, 0xBC, ++ 0x90, 0x46, 0xF0, 0xBD, 0xB1, 0xF7, 0x04, 0xFD, 0x00, 0x28, 0xF8, 0xD1, ++ 0x9F, 0x23, 0xE3, 0x5C, 0x00, 0x2B, 0x0A, 0xD1, 0xA7, 0x33, 0xE3, 0x5C, ++ 0x00, 0x2B, 0x06, 0xD1, 0xAA, 0x33, 0xE3, 0x5C, 0x00, 0x2B, 0x02, 0xD0, ++ 0xA7, 0x23, 0x01, 0x22, 0xE2, 0x54, 0xA8, 0x23, 0xE3, 0x5C, 0x00, 0x2B, ++ 0x03, 0xD1, 0x62, 0x68, 0x09, 0x4B, 0x1A, 0x60, 0xE1, 0xE7, 0xA8, 0xF7, ++ 0x81, 0xFB, 0x08, 0x4B, 0x18, 0x60, 0xF6, 0xE7, 0x32, 0x00, 0x41, 0x46, ++ 0x20, 0x00, 0xFF, 0xF7, 0xE5, 0xFD, 0xC8, 0xE7, 0x7C, 0x1E, 0x16, 0x00, ++ 0x9D, 0x02, 0x00, 0x00, 0x38, 0x27, 0x16, 0x00, 0x28, 0xE6, 0x10, 0x00, ++ 0x2C, 0xE6, 0x10, 0x00, 0x03, 0x4B, 0x04, 0x4A, 0x1A, 0x60, 0x04, 0x4B, ++ 0x04, 0x4A, 0x1A, 0x60, 0x70, 0x47, 0xC0, 0x46, 0x04, 0x30, 0x34, 0x40, ++ 0xC1, 0x00, 0xA0, 0x00, 0x0C, 0x00, 0x58, 0x40, 0x14, 0x00, 0x7F, 0x30, ++ 0x01, 0x4B, 0x02, 0x4A, 0x1A, 0x60, 0x70, 0x47, 0x04, 0x30, 0x34, 0x40, ++ 0xC0, 0x00, 0xA0, 0x00, 0x10, 0xB5, 0x30, 0x4B, 0x1B, 0x78, 0x01, 0x2B, ++ 0x09, 0xD0, 0x01, 0x28, 0x08, 0xD0, 0x02, 0x28, 0x47, 0xD0, 0x2D, 0x4B, ++ 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x10, 0xBD, ++ 0xA8, 0xF7, 0x44, 0xFB, 0x27, 0x4B, 0x5B, 0x78, 0x00, 0x2B, 0x11, 0xD1, ++ 0x25, 0x4B, 0x01, 0x22, 0x5A, 0x70, 0x58, 0x60, 0x9B, 0x78, 0x01, 0x2B, ++ 0xF1, 0xD0, 0xFE, 0xF7, 0xA7, 0xFA, 0x00, 0x28, 0xED, 0xD1, 0xFE, 0xF7, ++ 0xC1, 0xFA, 0x00, 0x28, 0xE9, 0xD1, 0xFF, 0xF7, 0xC1, 0xFF, 0xE6, 0xE7, ++ 0x1C, 0x4A, 0x53, 0x68, 0xC3, 0x1A, 0x1B, 0x01, 0x1B, 0x09, 0x92, 0x78, ++ 0x00, 0x2A, 0x0B, 0xD1, 0x23, 0x2B, 0xDC, 0xD9, 0x17, 0x4B, 0x01, 0x32, ++ 0x9A, 0x70, 0x00, 0x22, 0x5A, 0x70, 0x58, 0x60, 0x16, 0x4B, 0x17, 0x4A, ++ 0x1A, 0x60, 0xD2, 0xE7, 0x01, 0x2A, 0xD0, 0xD1, 0x3B, 0x2B, 0xCE, 0xD9, ++ 0x10, 0x4B, 0x00, 0x22, 0x9A, 0x70, 0x01, 0x32, 0x5A, 0x70, 0x58, 0x60, ++ 0xFE, 0xF7, 0x7E, 0xFA, 0x00, 0x28, 0xC4, 0xD1, 0xFE, 0xF7, 0x98, 0xFA, ++ 0x00, 0x28, 0xC0, 0xD1, 0xFF, 0xF7, 0x98, 0xFF, 0xBD, 0xE7, 0x08, 0x4B, ++ 0x5B, 0x78, 0x01, 0x2B, 0x01, 0xD0, 0x00, 0x29, 0xB7, 0xD0, 0x05, 0x4B, ++ 0x00, 0x22, 0x5A, 0x70, 0x9A, 0x70, 0x01, 0x3A, 0x5A, 0x60, 0x04, 0x4B, ++ 0x04, 0x4A, 0x1A, 0x60, 0xAD, 0xE7, 0xC0, 0x46, 0xDC, 0xE6, 0x10, 0x00, ++ 0x28, 0x19, 0x16, 0x00, 0x04, 0x30, 0x34, 0x40, 0xC0, 0x00, 0xA0, 0x00, ++ 0xF0, 0xB5, 0x80, 0x00, 0x26, 0x4B, 0xC3, 0x58, 0xAB, 0x20, 0x18, 0x5C, ++ 0x00, 0x28, 0x27, 0xD0, 0x0D, 0x1C, 0xAA, 0x20, 0x80, 0x00, 0x81, 0x42, ++ 0x01, 0xD3, 0x22, 0x49, 0x0D, 0x1C, 0xAD, 0xB2, 0x9D, 0x21, 0x5F, 0x5C, ++ 0x00, 0x23, 0x00, 0x24, 0x01, 0x26, 0x02, 0xE0, 0x01, 0x33, 0x07, 0x2B, ++ 0x0C, 0xD0, 0xD8, 0xB2, 0x39, 0x00, 0x19, 0x41, 0x0E, 0x42, 0xF7, 0xD0, ++ 0x59, 0x00, 0x1A, 0x4C, 0x61, 0x5A, 0xA9, 0x42, 0x01, 0xD2, 0x04, 0x00, ++ 0xF0, 0xE7, 0x04, 0x00, 0x17, 0x4B, 0x18, 0x5D, 0x64, 0x00, 0x15, 0x4B, ++ 0xE3, 0x5A, 0xAB, 0x42, 0x00, 0xD9, 0x2B, 0x00, 0x13, 0x80, 0xF0, 0xBD, ++ 0x9C, 0x20, 0x1F, 0x5C, 0x00, 0x23, 0x00, 0x25, 0x01, 0x26, 0x02, 0xE0, ++ 0x01, 0x33, 0x06, 0x2B, 0x0C, 0xD0, 0xDC, 0xB2, 0x38, 0x00, 0x18, 0x41, ++ 0x06, 0x42, 0xF7, 0xD0, 0x58, 0x00, 0x0C, 0x4D, 0x28, 0x5A, 0x88, 0x42, ++ 0x01, 0xD2, 0x25, 0x00, 0xF0, 0xE7, 0x25, 0x00, 0x09, 0x4B, 0x58, 0x5D, ++ 0x6D, 0x00, 0x07, 0x4B, 0xEB, 0x5A, 0x8B, 0x42, 0x00, 0xD9, 0x0B, 0x00, ++ 0x13, 0x80, 0xDE, 0xE7, 0x38, 0x27, 0x16, 0x00, 0xA7, 0x02, 0x00, 0x00, ++ 0x40, 0xC9, 0x0D, 0x00, 0x50, 0xC9, 0x0D, 0x00, 0x2C, 0xC9, 0x0D, 0x00, ++ 0x38, 0xC9, 0x0D, 0x00, 0xF0, 0xB5, 0xDE, 0x46, 0x57, 0x46, 0x4E, 0x46, ++ 0x45, 0x46, 0xE0, 0xB5, 0x85, 0xB0, 0x00, 0x90, 0x88, 0x46, 0x82, 0x00, ++ 0x95, 0x4B, 0xD4, 0x58, 0xAF, 0x23, 0xE3, 0x5C, 0x01, 0x2B, 0x00, 0xD9, ++ 0x0D, 0xE1, 0x03, 0x02, 0x01, 0x27, 0x1F, 0x43, 0x88, 0x23, 0x99, 0x46, ++ 0xBB, 0x46, 0x2A, 0xE0, 0xAB, 0x00, 0x5D, 0x19, 0x6D, 0x00, 0x8E, 0x4B, ++ 0xEA, 0x18, 0x13, 0x88, 0x78, 0x21, 0x8B, 0x43, 0x60, 0x39, 0x0B, 0x43, ++ 0x13, 0x80, 0x8B, 0x4B, 0xEA, 0x18, 0x83, 0x79, 0xDB, 0x00, 0x11, 0x39, ++ 0x0B, 0x43, 0x13, 0x80, 0x82, 0x88, 0x88, 0x4B, 0xEB, 0x18, 0x1A, 0x80, ++ 0x87, 0x4B, 0x9C, 0x46, 0x65, 0x44, 0x2B, 0x88, 0x5B, 0x04, 0x5B, 0x0C, ++ 0x2B, 0x80, 0xAE, 0x22, 0xA3, 0x5C, 0x59, 0x42, 0x4B, 0x41, 0xA3, 0x54, ++ 0x01, 0x32, 0xA3, 0x5C, 0x01, 0x33, 0xA3, 0x54, 0xAF, 0x23, 0xE3, 0x5C, ++ 0x01, 0x2B, 0x00, 0xD9, 0xDB, 0xE0, 0x9E, 0x23, 0xE5, 0x5C, 0x6D, 0x00, ++ 0x10, 0x33, 0xE3, 0x5C, 0xED, 0x18, 0xED, 0xB2, 0x20, 0x00, 0x40, 0x30, ++ 0x81, 0xF7, 0x84, 0xFA, 0x00, 0x28, 0xC7, 0xD1, 0xEC, 0x23, 0xE3, 0x58, ++ 0x00, 0x2B, 0x39, 0xD0, 0x9A, 0x7A, 0x00, 0x2A, 0x36, 0xD1, 0xAC, 0x32, ++ 0xA2, 0x5C, 0x00, 0x2A, 0x00, 0xD1, 0xC2, 0xE0, 0x9A, 0x78, 0x05, 0x3A, ++ 0x03, 0x2A, 0x00, 0xD8, 0xBD, 0xE0, 0x1A, 0x88, 0xA9, 0x00, 0x4D, 0x19, ++ 0x6D, 0x00, 0x69, 0x49, 0x68, 0x18, 0x01, 0x88, 0xDE, 0x79, 0x0F, 0x23, ++ 0x33, 0x40, 0xDB, 0x00, 0x78, 0x26, 0xB1, 0x43, 0x0B, 0x43, 0x03, 0x80, ++ 0x64, 0x4B, 0xE9, 0x18, 0xD3, 0x00, 0x05, 0x22, 0x13, 0x43, 0x9B, 0xB2, ++ 0x0B, 0x80, 0xEC, 0x23, 0xE3, 0x58, 0x1A, 0x89, 0x62, 0x4B, 0xEB, 0x18, ++ 0x1A, 0x80, 0x60, 0x4B, 0x9C, 0x46, 0x65, 0x44, 0x2B, 0x88, 0x5B, 0x04, ++ 0x5B, 0x0C, 0x2B, 0x80, 0xAE, 0x22, 0xA3, 0x5C, 0x59, 0x42, 0x4B, 0x41, ++ 0xA3, 0x54, 0x01, 0x32, 0xA3, 0x5C, 0x01, 0x33, 0xA3, 0x54, 0xAF, 0xE7, ++ 0xAC, 0x23, 0xE3, 0x5C, 0x00, 0x2B, 0x00, 0xD1, 0x8B, 0xE0, 0x96, 0x23, ++ 0xE1, 0x5A, 0x01, 0x27, 0x00, 0x29, 0x39, 0xD0, 0x02, 0xAB, 0x9A, 0x1D, ++ 0x00, 0x98, 0xFF, 0xF7, 0x07, 0xFF, 0xAB, 0x00, 0x5D, 0x19, 0x6D, 0x00, ++ 0x4B, 0x4B, 0xEA, 0x18, 0x13, 0x88, 0x78, 0x21, 0x8B, 0x43, 0xC0, 0x00, ++ 0x03, 0x43, 0x9B, 0xB2, 0x13, 0x80, 0x48, 0x4B, 0xEA, 0x18, 0x02, 0xAB, ++ 0xDB, 0x88, 0xDB, 0x00, 0x1F, 0x43, 0x04, 0x23, 0x1F, 0x43, 0xBF, 0xB2, ++ 0x17, 0x80, 0x94, 0x22, 0xA1, 0x5A, 0x45, 0x4B, 0xEB, 0x18, 0x19, 0x80, ++ 0x42, 0x4B, 0x9C, 0x46, 0x65, 0x44, 0x2B, 0x88, 0x5B, 0x04, 0x5B, 0x0C, ++ 0x2B, 0x80, 0x02, 0xAB, 0xDB, 0x88, 0x96, 0x20, 0x21, 0x5A, 0xC9, 0x1A, ++ 0x21, 0x52, 0xA1, 0x5A, 0x5B, 0x18, 0xA3, 0x52, 0x1A, 0x32, 0xA3, 0x5C, ++ 0x59, 0x42, 0x4B, 0x41, 0xA3, 0x54, 0x01, 0x32, 0xA3, 0x5C, 0x01, 0x33, ++ 0xA3, 0x54, 0x6B, 0xE7, 0x27, 0x00, 0x48, 0x37, 0x80, 0x23, 0x1B, 0x05, ++ 0x9A, 0x46, 0x0F, 0xE0, 0x52, 0x00, 0x8A, 0x42, 0x1E, 0xDA, 0x01, 0x23, ++ 0xFF, 0x22, 0x59, 0x46, 0x31, 0x48, 0x7E, 0xF7, 0x7F, 0xFD, 0x01, 0x23, ++ 0x03, 0x70, 0x7E, 0xF7, 0xA5, 0xFD, 0x30, 0x89, 0x88, 0xF7, 0x98, 0xFE, ++ 0x38, 0x00, 0x81, 0xF7, 0xE7, 0xF9, 0x06, 0x1E, 0x46, 0xD0, 0x4B, 0x46, ++ 0xE2, 0x5A, 0x00, 0x2A, 0x08, 0xD0, 0x43, 0x68, 0x59, 0x1C, 0x05, 0xD0, ++ 0x41, 0x46, 0xCB, 0x1A, 0x19, 0x01, 0x09, 0x09, 0x51, 0x45, 0xDD, 0xD9, ++ 0x73, 0x89, 0x9F, 0x04, 0xBF, 0x0F, 0x9B, 0x05, 0x9B, 0x0D, 0x9A, 0x46, ++ 0x90, 0x23, 0xE3, 0x58, 0x00, 0x2B, 0x2C, 0xD0, 0x8C, 0x23, 0xE3, 0x58, ++ 0x00, 0x2B, 0x06, 0xD0, 0x1D, 0x4B, 0x9B, 0x6E, 0x01, 0x93, 0x00, 0x22, ++ 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x8C, 0x23, 0xE6, 0x50, 0x96, 0x23, ++ 0x52, 0x46, 0xE2, 0x52, 0x32, 0x89, 0x02, 0x3B, 0xE2, 0x52, 0x01, 0x2F, ++ 0x00, 0xD0, 0x02, 0x27, 0x96, 0x23, 0xE1, 0x5A, 0x00, 0x29, 0x00, 0xD0, ++ 0x78, 0xE7, 0xAF, 0x23, 0xE3, 0x5C, 0x00, 0x2B, 0x06, 0xD0, 0xA8, 0x23, ++ 0xE3, 0x5C, 0x00, 0x2B, 0x02, 0xD1, 0xA8, 0x33, 0x01, 0x22, 0xE2, 0x54, ++ 0x05, 0xB0, 0x3C, 0xBC, 0x90, 0x46, 0x99, 0x46, 0xA2, 0x46, 0xAB, 0x46, ++ 0xF0, 0xBD, 0x90, 0x33, 0xE6, 0x50, 0xDC, 0xE7, 0x01, 0x27, 0xE3, 0xE7, ++ 0x38, 0x27, 0x16, 0x00, 0xCA, 0x69, 0x61, 0x40, 0xCC, 0x69, 0x61, 0x40, ++ 0xD0, 0x69, 0x61, 0x40, 0xC8, 0x69, 0x61, 0x40, 0xCE, 0x69, 0x61, 0x40, ++ 0x2B, 0x06, 0x00, 0x00, 0x28, 0x19, 0x16, 0x00, 0xF0, 0xB5, 0xDE, 0x46, ++ 0x57, 0x46, 0x4E, 0x46, 0x45, 0x46, 0xE0, 0xB5, 0x83, 0xB0, 0x82, 0x00, ++ 0x4B, 0x4B, 0xD4, 0x58, 0x90, 0x23, 0xE2, 0x58, 0x00, 0x2A, 0x00, 0xD1, ++ 0x84, 0xE0, 0x49, 0x4B, 0x59, 0x88, 0x49, 0x4B, 0x1B, 0x78, 0x99, 0x42, ++ 0x73, 0xD9, 0x9E, 0x23, 0xE3, 0x5C, 0x5B, 0x00, 0xAD, 0x21, 0x61, 0x5C, ++ 0x5B, 0x18, 0xDB, 0xB2, 0x56, 0x89, 0xB6, 0x05, 0xB2, 0x0D, 0x90, 0x46, ++ 0x02, 0x22, 0x90, 0x26, 0x41, 0x49, 0x01, 0x91, 0xAF, 0x21, 0x8A, 0x46, ++ 0x01, 0x39, 0x89, 0x46, 0x10, 0x39, 0x8C, 0x46, 0x00, 0x90, 0x0C, 0xE0, ++ 0x63, 0x46, 0xE5, 0x5C, 0x6D, 0x00, 0xAD, 0x23, 0xE1, 0x5C, 0x4B, 0x42, ++ 0x4B, 0x41, 0x5B, 0x19, 0xDB, 0xB2, 0x01, 0x3A, 0xD2, 0xB2, 0x00, 0x2A, ++ 0x31, 0xD0, 0x99, 0x00, 0xCB, 0x18, 0x5B, 0x00, 0x35, 0x49, 0x5F, 0x18, ++ 0x39, 0x88, 0x89, 0xB2, 0xA5, 0x59, 0x2D, 0x89, 0x8D, 0x42, 0xE7, 0xD8, ++ 0x45, 0x44, 0xA9, 0x42, 0xE4, 0xDA, 0x31, 0x49, 0x5D, 0x18, 0x29, 0x88, ++ 0x01, 0x98, 0x01, 0x40, 0x29, 0x80, 0x2F, 0x49, 0x5D, 0x18, 0x29, 0x88, ++ 0x49, 0x04, 0x49, 0x0C, 0x2D, 0x48, 0x01, 0x43, 0x89, 0xB2, 0x29, 0x80, ++ 0x2C, 0x49, 0x8B, 0x46, 0x5B, 0x44, 0x19, 0x88, 0x78, 0x20, 0x81, 0x43, ++ 0x19, 0x80, 0x00, 0x23, 0x3B, 0x80, 0x53, 0x46, 0xE3, 0x5C, 0x01, 0x3B, ++ 0x51, 0x46, 0x63, 0x54, 0x4B, 0x46, 0xE3, 0x5C, 0x59, 0x42, 0x4B, 0x41, ++ 0x49, 0x46, 0x63, 0x54, 0xC0, 0xE7, 0x00, 0x98, 0x00, 0x02, 0x01, 0x25, ++ 0x28, 0x43, 0x81, 0xB2, 0x01, 0x23, 0xFF, 0x32, 0x1F, 0x48, 0x7E, 0xF7, ++ 0xA5, 0xFC, 0x05, 0x70, 0x7E, 0xF7, 0xCC, 0xFC, 0x1D, 0x48, 0x80, 0xF7, ++ 0xA3, 0xFD, 0x90, 0x23, 0xE3, 0x58, 0x18, 0x89, 0x88, 0xF7, 0xBA, 0xFD, ++ 0x8C, 0x23, 0xE3, 0x58, 0x00, 0x2B, 0x0B, 0xD0, 0x90, 0x22, 0xA3, 0x50, ++ 0x8C, 0x23, 0x00, 0x22, 0xE2, 0x50, 0x03, 0xB0, 0x3C, 0xBC, 0x90, 0x46, ++ 0x99, 0x46, 0xA2, 0x46, 0xAB, 0x46, 0xF0, 0xBD, 0x96, 0x22, 0x00, 0x21, ++ 0xA1, 0x52, 0xEF, 0xE7, 0x8C, 0x23, 0xE3, 0x58, 0x00, 0x2B, 0xF0, 0xD0, ++ 0x0E, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, ++ 0xE9, 0xE7, 0xC0, 0x46, 0x38, 0x27, 0x16, 0x00, 0x9C, 0xE5, 0x10, 0x00, ++ 0xF8, 0xE1, 0x10, 0x00, 0x07, 0xE0, 0xFF, 0xFF, 0xCE, 0x69, 0x61, 0x40, ++ 0xCC, 0x69, 0x61, 0x40, 0xC8, 0x69, 0x61, 0x40, 0x00, 0x80, 0xFF, 0xFF, ++ 0xCA, 0x69, 0x61, 0x40, 0x2B, 0x06, 0x00, 0x00, 0x18, 0xD1, 0x10, 0x00, ++ 0x28, 0x19, 0x16, 0x00, 0x03, 0x00, 0x00, 0x20, 0x9A, 0x6C, 0x00, 0x2A, ++ 0x00, 0xD0, 0x70, 0x47, 0xA7, 0x32, 0x9A, 0x5C, 0x00, 0x2A, 0xFA, 0xD1, ++ 0xA8, 0x32, 0x98, 0x5C, 0x43, 0x42, 0x58, 0x41, 0xC0, 0xB2, 0xF4, 0xE7, ++ 0x04, 0x4B, 0x18, 0x68, 0x04, 0x4B, 0x1B, 0x68, 0x18, 0x43, 0x43, 0x1E, ++ 0x98, 0x41, 0xC0, 0xB2, 0x70, 0x47, 0xC0, 0x46, 0x24, 0x27, 0x16, 0x00, ++ 0x18, 0x27, 0x16, 0x00, 0x70, 0xB5, 0x84, 0xB0, 0x82, 0x00, 0x12, 0x4B, ++ 0xD5, 0x58, 0x01, 0xA9, 0x11, 0x4C, 0x02, 0x01, 0x13, 0x1A, 0x9B, 0x00, ++ 0xE3, 0x18, 0xDE, 0x88, 0x4E, 0x80, 0x1E, 0x7B, 0x4E, 0x70, 0x1E, 0x89, ++ 0xCE, 0x80, 0x5E, 0x89, 0x0E, 0x81, 0x9B, 0x88, 0x8B, 0x80, 0x12, 0x1A, ++ 0x92, 0x00, 0xA2, 0x18, 0x53, 0x7B, 0x01, 0x22, 0x53, 0x40, 0x36, 0x22, ++ 0xAA, 0x5C, 0x5A, 0x40, 0x01, 0x23, 0x13, 0x40, 0x2E, 0x22, 0x13, 0x43, ++ 0x0B, 0x70, 0xA6, 0xF7, 0x0F, 0xF9, 0x04, 0xB0, 0x70, 0xBD, 0xC0, 0x46, ++ 0x64, 0xA2, 0x16, 0x00, 0xC0, 0xA0, 0x16, 0x00, 0xF8, 0xB5, 0x06, 0x00, ++ 0x0C, 0x00, 0x05, 0x0A, 0xAA, 0x00, 0x18, 0x4B, 0xD7, 0x58, 0x36, 0x23, ++ 0xFB, 0x5C, 0x00, 0x2B, 0x0C, 0xD0, 0x2B, 0x01, 0x5B, 0x1B, 0x9B, 0x00, ++ 0x14, 0x4A, 0xD3, 0x18, 0x5B, 0x7B, 0x00, 0x2B, 0x08, 0xD1, 0x01, 0x21, ++ 0x30, 0x00, 0x7E, 0xF7, 0x77, 0xFF, 0xF8, 0xBD, 0xE8, 0xB2, 0xB2, 0xF7, ++ 0x73, 0xF9, 0xEE, 0xE7, 0x08, 0x23, 0x14, 0x22, 0x00, 0x21, 0x0D, 0x48, ++ 0x7E, 0xF7, 0xF6, 0xFB, 0x04, 0x70, 0x2B, 0x00, 0x80, 0x33, 0x43, 0x80, ++ 0x00, 0x23, 0xC3, 0x80, 0x3C, 0x33, 0xFB, 0x5C, 0x03, 0x71, 0xD0, 0xF7, ++ 0x4B, 0xFA, 0x2B, 0x01, 0x5D, 0x1B, 0xAD, 0x00, 0x03, 0x4B, 0x5D, 0x19, ++ 0x00, 0x23, 0x6B, 0x73, 0xDD, 0xE7, 0xC0, 0x46, 0x64, 0xA2, 0x16, 0x00, ++ 0xC0, 0xA0, 0x16, 0x00, 0x03, 0x11, 0x00, 0x00, 0xF0, 0xB5, 0xDE, 0x46, ++ 0x57, 0x46, 0x4E, 0x46, 0x45, 0x46, 0xE0, 0xB5, 0x93, 0xB0, 0x05, 0x00, ++ 0x03, 0x91, 0x93, 0x46, 0x1E, 0x00, 0x1C, 0xAB, 0x1B, 0x88, 0x99, 0x46, ++ 0x1D, 0xAB, 0x1B, 0x88, 0x9A, 0x46, 0x04, 0x0A, 0xA2, 0x00, 0xCB, 0x4B, ++ 0xD7, 0x58, 0x01, 0x00, 0xCA, 0x48, 0x7E, 0xF7, 0x7B, 0xFB, 0xB3, 0x1F, ++ 0xC9, 0x4A, 0x9B, 0xB2, 0x93, 0x42, 0x03, 0xD8, 0x5B, 0x46, 0x33, 0x43, ++ 0xDB, 0x07, 0x0D, 0xD5, 0x39, 0x23, 0xFB, 0x5C, 0xE0, 0xB2, 0x12, 0x22, ++ 0x17, 0x21, 0xA6, 0xF7, 0xF6, 0xF8, 0x13, 0xB0, 0x3C, 0xBC, 0x90, 0x46, ++ 0x99, 0x46, 0xA2, 0x46, 0xAB, 0x46, 0xF0, 0xBD, 0x5E, 0x45, 0xEF, 0xD9, ++ 0x4B, 0x46, 0x00, 0x2B, 0xEC, 0xD0, 0x73, 0x08, 0x4B, 0x45, 0xE9, 0xD3, ++ 0x53, 0x46, 0x28, 0x2B, 0xE6, 0xD8, 0x4B, 0x44, 0x5B, 0x00, 0xB3, 0x42, ++ 0xE2, 0xD2, 0x28, 0x00, 0x7E, 0xF7, 0x70, 0xFF, 0x01, 0x28, 0x00, 0xD1, ++ 0x85, 0xE0, 0xB5, 0x4B, 0x22, 0x01, 0x11, 0x1B, 0x89, 0x00, 0xCE, 0x52, ++ 0x5B, 0x18, 0x5E, 0x80, 0x4A, 0x46, 0x1A, 0x81, 0x9E, 0x80, 0x5A, 0x46, ++ 0xDA, 0x80, 0x52, 0x46, 0x5A, 0x81, 0x03, 0x9A, 0x1A, 0x73, 0x36, 0x23, ++ 0xFB, 0x5C, 0x00, 0x22, 0x04, 0x92, 0x01, 0x2B, 0x77, 0xD0, 0x0A, 0x96, ++ 0x0B, 0x96, 0x36, 0x23, 0xF8, 0x5C, 0x4A, 0x46, 0x02, 0x2A, 0x00, 0xD9, ++ 0x02, 0x22, 0x90, 0x46, 0x80, 0x44, 0x0A, 0xAB, 0x42, 0x46, 0x0C, 0x92, ++ 0x49, 0x46, 0x49, 0x00, 0x0D, 0x91, 0x00, 0x21, 0x99, 0x74, 0x80, 0x31, ++ 0x8C, 0x46, 0xA4, 0x44, 0x61, 0x46, 0x19, 0x82, 0x01, 0x21, 0x04, 0x9A, ++ 0x11, 0x40, 0xD9, 0x74, 0x06, 0xAB, 0x06, 0x96, 0x42, 0x46, 0x07, 0x92, ++ 0x62, 0x46, 0x9A, 0x81, 0x00, 0x28, 0x5A, 0xD1, 0x58, 0x46, 0x08, 0x90, ++ 0x36, 0x23, 0xFB, 0x5C, 0x01, 0x2B, 0x5A, 0xD0, 0x08, 0x9B, 0x10, 0x93, ++ 0x11, 0x93, 0x06, 0x9B, 0x0F, 0x93, 0x06, 0xA8, 0xD4, 0xF7, 0x5A, 0xFA, ++ 0x80, 0x46, 0x00, 0x28, 0x72, 0xD1, 0x0A, 0xAA, 0x10, 0x98, 0x23, 0x01, ++ 0x1B, 0x1B, 0x9B, 0x00, 0x8D, 0x49, 0xCB, 0x18, 0x98, 0x62, 0x0F, 0x99, ++ 0x8C, 0x46, 0x59, 0x62, 0x0C, 0x99, 0xD9, 0x62, 0x0D, 0x99, 0x19, 0x63, ++ 0x12, 0x8A, 0x9A, 0x86, 0x00, 0x22, 0x9A, 0x63, 0x36, 0x33, 0x1A, 0x70, ++ 0x36, 0x23, 0xFB, 0x5C, 0x00, 0x2B, 0x6B, 0xD1, 0x80, 0xB2, 0x23, 0x01, ++ 0x1B, 0x1B, 0x9B, 0x00, 0x81, 0x4A, 0xD3, 0x18, 0xD8, 0x80, 0x36, 0x23, ++ 0xFB, 0x5C, 0x01, 0x2B, 0x67, 0xD0, 0xD9, 0x23, 0x9B, 0x00, 0xFB, 0x18, ++ 0x1A, 0x88, 0x7D, 0x4B, 0x9A, 0x42, 0x79, 0xD1, 0x43, 0x46, 0x01, 0x2B, ++ 0x00, 0xD1, 0xDF, 0xE0, 0x02, 0x2B, 0x00, 0xD1, 0xBC, 0xE0, 0x00, 0x2B, ++ 0x00, 0xD1, 0xAE, 0xE0, 0x77, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x11, 0x00, ++ 0x10, 0x00, 0x98, 0x47, 0x5D, 0xE7, 0x23, 0x01, 0x1B, 0x1B, 0x9B, 0x00, ++ 0x70, 0x4A, 0xD3, 0x18, 0x00, 0x22, 0x5A, 0x73, 0x71, 0xE7, 0xE0, 0xB2, ++ 0xAF, 0xF7, 0xAE, 0xFE, 0x43, 0x08, 0x04, 0x93, 0x81, 0xE7, 0x04, 0x9A, ++ 0x31, 0x00, 0x58, 0x46, 0xA5, 0xF7, 0x2E, 0xFD, 0x9F, 0xE7, 0x06, 0x9B, ++ 0x9B, 0x46, 0x01, 0x3B, 0x98, 0x46, 0x80, 0x44, 0x5B, 0x46, 0x00, 0x2B, ++ 0x05, 0xD1, 0x66, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x11, 0x00, 0x10, 0x00, ++ 0x98, 0x47, 0x59, 0x46, 0x40, 0x46, 0xD4, 0xF7, 0x1B, 0xFE, 0x08, 0x91, ++ 0x0A, 0xAB, 0xDA, 0x7C, 0x01, 0x21, 0x4A, 0x40, 0xDA, 0x74, 0x0C, 0x9A, ++ 0x03, 0x32, 0x0C, 0x92, 0x0D, 0x9A, 0x03, 0x32, 0x0D, 0x92, 0x07, 0x9B, ++ 0x05, 0x93, 0x03, 0x33, 0x07, 0x93, 0x81, 0xE7, 0x28, 0x00, 0x7E, 0xF7, ++ 0xAD, 0xFE, 0x80, 0x46, 0x01, 0x28, 0x02, 0xD0, 0x01, 0x23, 0x98, 0x46, ++ 0x83, 0xE7, 0x0A, 0xA8, 0xD4, 0xF7, 0x6A, 0xF9, 0x00, 0x28, 0x00, 0xD0, ++ 0x7D, 0xE7, 0x02, 0x23, 0x98, 0x46, 0x7A, 0xE7, 0x63, 0x46, 0x99, 0xB2, ++ 0x80, 0xB2, 0x04, 0x9A, 0xA5, 0xF7, 0x0A, 0xFD, 0x8D, 0xE7, 0x43, 0x1C, ++ 0x04, 0x93, 0x0F, 0x9B, 0x9B, 0x46, 0x00, 0x2B, 0x05, 0xD1, 0x49, 0x4B, ++ 0x9B, 0x6E, 0x00, 0x22, 0x11, 0x00, 0x10, 0x00, 0x98, 0x47, 0x23, 0x01, ++ 0x1B, 0x1B, 0x9B, 0x00, 0x42, 0x4A, 0xD3, 0x18, 0x05, 0x93, 0x59, 0x46, ++ 0x04, 0x98, 0xD4, 0xF7, 0xDB, 0xFD, 0x05, 0x9B, 0xD9, 0x80, 0x7E, 0xE7, ++ 0xE3, 0xB2, 0x9B, 0x46, 0x18, 0x00, 0x95, 0xF7, 0x71, 0xFF, 0x05, 0x90, ++ 0x0F, 0x9B, 0x04, 0x93, 0x00, 0x28, 0x05, 0xD1, 0x3A, 0x4B, 0x9B, 0x6E, ++ 0x00, 0x22, 0x11, 0x00, 0x10, 0x00, 0x98, 0x47, 0x05, 0x99, 0x04, 0x98, ++ 0xD4, 0xF7, 0xC4, 0xFD, 0x00, 0x29, 0x00, 0xD0, 0x6E, 0xE7, 0x3C, 0x22, ++ 0x62, 0x43, 0x31, 0x4B, 0x9B, 0x18, 0xD9, 0x88, 0x11, 0x9B, 0x04, 0x93, ++ 0x10, 0x9B, 0x05, 0x93, 0x04, 0x9B, 0x05, 0x9A, 0x9A, 0x1A, 0x8A, 0x18, ++ 0x92, 0xB2, 0x58, 0x46, 0x95, 0xF7, 0x9C, 0xFF, 0x04, 0x90, 0x0F, 0x9B, ++ 0x9B, 0x46, 0x00, 0x2B, 0x05, 0xD1, 0x29, 0x4B, 0x9B, 0x6E, 0x00, 0x22, ++ 0x11, 0x00, 0x10, 0x00, 0x98, 0x47, 0x3C, 0x23, 0x63, 0x43, 0x23, 0x4A, ++ 0xD3, 0x18, 0x05, 0x93, 0x59, 0x46, 0x04, 0x98, 0xD4, 0xF7, 0x9C, 0xFD, ++ 0x05, 0x9B, 0xD9, 0x80, 0x46, 0xE7, 0x39, 0x33, 0xFA, 0x5C, 0xE0, 0xB2, ++ 0x17, 0x21, 0xA5, 0xF7, 0x87, 0xFF, 0x2F, 0x21, 0x28, 0x00, 0x7E, 0xF7, ++ 0xD5, 0xFD, 0xAA, 0xE6, 0x36, 0x23, 0xFB, 0x5C, 0x00, 0x2B, 0x0A, 0xD0, ++ 0xE0, 0xB2, 0xFF, 0xF7, 0x13, 0xFE, 0x28, 0x00, 0x96, 0xF7, 0x3A, 0xFB, ++ 0x2E, 0x21, 0x28, 0x00, 0x7E, 0xF7, 0xC6, 0xFD, 0x9B, 0xE6, 0x3C, 0x22, ++ 0x62, 0x43, 0x10, 0x4B, 0x9B, 0x18, 0xD9, 0x88, 0xE0, 0xB2, 0x03, 0x9B, ++ 0x9F, 0x07, 0xFF, 0x0F, 0x01, 0x97, 0x53, 0x46, 0x00, 0x93, 0x4B, 0x46, ++ 0x32, 0x00, 0xAF, 0xF7, 0x5F, 0xFC, 0xE3, 0xE7, 0x39, 0x23, 0xFB, 0x5C, ++ 0xE0, 0xB2, 0x20, 0x22, 0x17, 0x21, 0xA5, 0xF7, 0x7A, 0xFF, 0x20, 0x21, ++ 0x28, 0x00, 0xFF, 0xF7, 0x1B, 0xFE, 0x7E, 0xE6, 0x64, 0xA2, 0x16, 0x00, ++ 0x05, 0x06, 0x00, 0x00, 0x3A, 0x05, 0x00, 0x00, 0xC0, 0xA0, 0x16, 0x00, ++ 0xFF, 0xFF, 0x00, 0x00, 0x28, 0x19, 0x16, 0x00, 0xF0, 0xB5, 0xD6, 0x46, ++ 0x4F, 0x46, 0x46, 0x46, 0xC0, 0xB5, 0x8A, 0xB0, 0x06, 0x00, 0x88, 0x46, ++ 0x91, 0x46, 0x1D, 0x00, 0x12, 0xAB, 0x1B, 0x88, 0x9C, 0x46, 0x04, 0x0A, ++ 0xA2, 0x00, 0x9C, 0x4B, 0xD7, 0x58, 0x9C, 0x4B, 0x22, 0x01, 0x11, 0x1B, ++ 0x89, 0x00, 0x40, 0x46, 0xC8, 0x52, 0x5B, 0x18, 0x4A, 0x46, 0x5A, 0x80, ++ 0x1D, 0x81, 0x62, 0x46, 0x5A, 0x81, 0x36, 0x23, 0xFB, 0x5C, 0x00, 0x22, ++ 0x92, 0x46, 0x01, 0x2B, 0x00, 0xD1, 0x87, 0xE0, 0x23, 0x01, 0x1B, 0x1B, ++ 0x9B, 0x00, 0x91, 0x4A, 0xD3, 0x18, 0x00, 0x22, 0x1A, 0x73, 0xA7, 0xF7, ++ 0x29, 0xFE, 0x50, 0x44, 0x03, 0x01, 0x06, 0xD5, 0x23, 0x01, 0x1B, 0x1B, ++ 0x9B, 0x00, 0x8B, 0x4A, 0xD3, 0x18, 0x02, 0x22, 0x1A, 0x73, 0x02, 0xAB, ++ 0x4A, 0x46, 0x02, 0x92, 0x42, 0x46, 0x5A, 0x60, 0x2A, 0x00, 0x02, 0x2D, ++ 0x00, 0xD9, 0x02, 0x22, 0x9A, 0x60, 0x6D, 0x00, 0x05, 0x95, 0x00, 0x23, ++ 0x02, 0xAA, 0x93, 0x74, 0x25, 0x00, 0x80, 0x35, 0x15, 0x82, 0x53, 0x46, ++ 0x5B, 0x08, 0x9A, 0x46, 0x01, 0x23, 0x52, 0x46, 0x13, 0x40, 0x02, 0xAA, ++ 0xD3, 0x74, 0xD9, 0x23, 0x9B, 0x00, 0xFB, 0x18, 0x1A, 0x88, 0x7B, 0x4B, ++ 0x9A, 0x42, 0x58, 0xD1, 0x36, 0x23, 0xFB, 0x5C, 0x01, 0x2B, 0x6A, 0xD0, ++ 0x02, 0xA8, 0xD4, 0xF7, 0x63, 0xF8, 0x00, 0x28, 0x00, 0xD0, 0x72, 0xE0, ++ 0x08, 0x98, 0x22, 0x01, 0x12, 0x1B, 0x92, 0x00, 0x71, 0x4B, 0x9B, 0x18, ++ 0x98, 0x62, 0x07, 0x99, 0x59, 0x62, 0x04, 0x9A, 0xDA, 0x62, 0x05, 0x9A, ++ 0x00, 0x92, 0x1A, 0x63, 0x02, 0xAA, 0x12, 0x8A, 0x9A, 0x86, 0x00, 0x22, ++ 0x9A, 0x63, 0x36, 0x33, 0x1A, 0x70, 0x36, 0x23, 0xFB, 0x5C, 0x00, 0x2B, ++ 0x6A, 0xD1, 0x80, 0xB2, 0x23, 0x01, 0x1B, 0x1B, 0x9B, 0x00, 0x65, 0x4A, ++ 0xD3, 0x18, 0xD8, 0x80, 0x07, 0x9D, 0x9D, 0x80, 0x36, 0x23, 0xFB, 0x5C, ++ 0x01, 0x2B, 0x63, 0xD0, 0xD9, 0x23, 0x9B, 0x00, 0xFB, 0x18, 0x1A, 0x88, ++ 0x5F, 0x4B, 0x9A, 0x42, 0x00, 0xD0, 0x72, 0xE0, 0x23, 0x01, 0x1B, 0x1B, ++ 0x9B, 0x00, 0x5B, 0x4A, 0xD3, 0x18, 0x01, 0x22, 0x5A, 0x73, 0x36, 0x23, ++ 0xFB, 0x5C, 0x00, 0x2B, 0x00, 0xD1, 0xA4, 0xE0, 0xE0, 0xB2, 0xFF, 0xF7, ++ 0x43, 0xFD, 0x30, 0x00, 0x96, 0xF7, 0x6A, 0xFA, 0x2E, 0x21, 0x30, 0x00, ++ 0x7E, 0xF7, 0xF6, 0xFC, 0x0A, 0xB0, 0x1C, 0xBC, 0x90, 0x46, 0x99, 0x46, ++ 0xA2, 0x46, 0xF0, 0xBD, 0xE0, 0xB2, 0xAF, 0xF7, 0x1F, 0xFD, 0x82, 0x46, ++ 0x72, 0xE7, 0xE0, 0xB2, 0x95, 0xF7, 0x40, 0xFE, 0x02, 0x00, 0x03, 0x00, ++ 0x02, 0x98, 0x82, 0x42, 0x07, 0xD2, 0x00, 0x92, 0x11, 0x00, 0xD4, 0xF7, ++ 0x13, 0xFC, 0x43, 0x1C, 0x00, 0x9A, 0x5A, 0x43, 0x93, 0xB2, 0x03, 0x9A, ++ 0x93, 0x42, 0x93, 0xD8, 0x02, 0x93, 0x03, 0x93, 0x90, 0xE7, 0x02, 0xAB, ++ 0xDB, 0x7C, 0x01, 0x22, 0x53, 0x40, 0x02, 0xAA, 0xD3, 0x74, 0x04, 0x9B, ++ 0x03, 0x33, 0x04, 0x93, 0x05, 0x9B, 0x00, 0x93, 0x03, 0x33, 0x05, 0x93, ++ 0x86, 0xE7, 0x08, 0x23, 0x14, 0x22, 0x00, 0x21, 0x3A, 0x48, 0x7E, 0xF7, ++ 0x4B, 0xF9, 0x20, 0x23, 0x03, 0x70, 0x45, 0x80, 0x00, 0x23, 0xC3, 0x80, ++ 0x3C, 0x33, 0xFB, 0x5C, 0x03, 0x71, 0xCF, 0xF7, 0xA1, 0xFF, 0xBF, 0xE7, ++ 0x89, 0xB2, 0x80, 0xB2, 0x52, 0x46, 0xA5, 0xF7, 0x83, 0xFB, 0x8F, 0xE7, ++ 0x43, 0x1C, 0x98, 0x46, 0x00, 0x2D, 0x05, 0xD1, 0x2F, 0x4B, 0x9B, 0x6E, ++ 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x23, 0x01, 0x1B, 0x1B, ++ 0x9B, 0x00, 0x28, 0x4A, 0x91, 0x46, 0x99, 0x44, 0x29, 0x00, 0x40, 0x46, ++ 0xD4, 0xF7, 0x56, 0xFC, 0x4B, 0x46, 0xD9, 0x80, 0x84, 0xE7, 0xE3, 0xB2, ++ 0x98, 0x46, 0x18, 0x00, 0x95, 0xF7, 0xEC, 0xFD, 0x05, 0x1E, 0x07, 0x9B, ++ 0x99, 0x46, 0x05, 0xD1, 0x21, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, ++ 0x00, 0x20, 0x98, 0x47, 0x29, 0x00, 0x48, 0x46, 0xD4, 0xF7, 0x40, 0xFC, ++ 0x00, 0x29, 0x00, 0xD0, 0x76, 0xE7, 0x23, 0x01, 0x1B, 0x1B, 0x9B, 0x00, ++ 0x16, 0x4A, 0xD3, 0x18, 0xD9, 0x88, 0x09, 0x9B, 0x00, 0x93, 0x08, 0x9B, ++ 0x01, 0x93, 0x00, 0x9B, 0x01, 0x9A, 0x9A, 0x1A, 0x8A, 0x18, 0x92, 0xB2, ++ 0x40, 0x46, 0x95, 0xF7, 0x17, 0xFE, 0x81, 0x46, 0x07, 0x9B, 0x98, 0x46, ++ 0x00, 0x2B, 0x05, 0xD1, 0x0F, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, ++ 0x00, 0x20, 0x98, 0x47, 0x23, 0x01, 0x1B, 0x1B, 0x9B, 0x00, 0x08, 0x4D, ++ 0xED, 0x18, 0x41, 0x46, 0x48, 0x46, 0xD4, 0xF7, 0x17, 0xFC, 0xE9, 0x80, ++ 0x4E, 0xE7, 0xE0, 0xB2, 0x01, 0x33, 0x00, 0x22, 0x17, 0x21, 0x95, 0xF7, ++ 0x89, 0xFC, 0x53, 0xE7, 0x64, 0xA2, 0x16, 0x00, 0xC0, 0xA0, 0x16, 0x00, ++ 0xFF, 0xFF, 0x00, 0x00, 0x03, 0x11, 0x00, 0x00, 0x28, 0x19, 0x16, 0x00, ++ 0xF0, 0xB5, 0xC6, 0x46, 0x00, 0xB5, 0x00, 0x24, 0x00, 0x20, 0x0E, 0x4E, ++ 0xA1, 0x27, 0xAF, 0x23, 0x98, 0x46, 0x0C, 0xE0, 0x42, 0x46, 0x9D, 0x5C, ++ 0x45, 0x19, 0xED, 0xB2, 0x48, 0x33, 0x18, 0x00, 0x80, 0xF7, 0x18, 0xFE, ++ 0x28, 0x18, 0xC0, 0xB2, 0x01, 0x34, 0x07, 0x2C, 0x07, 0xD0, 0xA3, 0x00, ++ 0x9B, 0x59, 0x00, 0x2B, 0xF8, 0xD0, 0xDA, 0x5D, 0x00, 0x2A, 0xF5, 0xD1, ++ 0xEA, 0xE7, 0x04, 0xBC, 0x90, 0x46, 0xF0, 0xBD, 0x38, 0x27, 0x16, 0x00, ++ 0xF0, 0xB5, 0x85, 0xB0, 0x40, 0x4B, 0x1A, 0x78, 0x01, 0x2A, 0x01, 0xD0, ++ 0x05, 0xB0, 0xF0, 0xBD, 0x3E, 0x4B, 0x1D, 0x78, 0x3E, 0x4B, 0x1B, 0x68, ++ 0x00, 0x24, 0x5B, 0x05, 0x08, 0xD5, 0x3C, 0x48, 0x03, 0x68, 0x3C, 0x49, ++ 0x19, 0x40, 0x80, 0x23, 0x1B, 0x01, 0x0B, 0x43, 0x03, 0x60, 0x80, 0x34, ++ 0x39, 0x4B, 0x1B, 0x68, 0x9B, 0x05, 0x09, 0xD4, 0x37, 0x48, 0x03, 0x68, ++ 0x37, 0x49, 0x19, 0x40, 0x80, 0x23, 0x9B, 0x00, 0x0B, 0x43, 0x03, 0x60, ++ 0x40, 0x23, 0x1C, 0x43, 0x34, 0x4B, 0x18, 0x68, 0x34, 0x4B, 0x19, 0x68, ++ 0x34, 0x4B, 0x1E, 0x68, 0x8B, 0x07, 0x31, 0xD4, 0xF0, 0x23, 0x03, 0x40, ++ 0x30, 0x2B, 0x0E, 0xD0, 0x20, 0x2B, 0x1F, 0xD0, 0x10, 0x2B, 0x29, 0xD1, ++ 0x2F, 0x4B, 0xDB, 0x69, 0xB3, 0x42, 0x25, 0xD0, 0xF0, 0x23, 0x07, 0x00, ++ 0x9F, 0x43, 0x3B, 0x00, 0x20, 0x27, 0x3B, 0x43, 0x0A, 0xE0, 0x2A, 0x4B, ++ 0xDB, 0x6B, 0xB3, 0x42, 0x1A, 0xD0, 0xF0, 0x23, 0x02, 0x00, 0x9A, 0x43, ++ 0x13, 0x00, 0x20, 0x22, 0x13, 0x43, 0x1D, 0x3A, 0x22, 0x4F, 0x3F, 0x68, ++ 0xBF, 0x07, 0x1F, 0xD4, 0x1F, 0x4F, 0x3B, 0x60, 0x14, 0x43, 0x1D, 0xE0, ++ 0x20, 0x4B, 0xDB, 0x6A, 0xB3, 0x42, 0x07, 0xD0, 0xF0, 0x23, 0x02, 0x00, ++ 0x9A, 0x43, 0x13, 0x00, 0x10, 0x22, 0x13, 0x43, 0x0E, 0x3A, 0xEB, 0xE7, ++ 0x01, 0x2D, 0xA3, 0xD1, 0x17, 0x4B, 0x1B, 0x68, 0x02, 0x93, 0x00, 0x23, ++ 0x01, 0x93, 0x00, 0x90, 0x33, 0x00, 0x00, 0x22, 0x16, 0x48, 0x80, 0xF7, ++ 0x47, 0xF9, 0x00, 0x2C, 0x96, 0xD0, 0x0D, 0xE0, 0x04, 0x27, 0x3C, 0x43, ++ 0x01, 0x2D, 0x00, 0xD0, 0x90, 0xE7, 0x0E, 0x4D, 0x2D, 0x68, 0x02, 0x95, ++ 0x01, 0x93, 0x00, 0x90, 0x33, 0x00, 0x0E, 0x48, 0x80, 0xF7, 0x36, 0xF9, ++ 0x32, 0x00, 0x21, 0x00, 0x0C, 0x48, 0x80, 0xF7, 0x31, 0xF9, 0x81, 0xE7, ++ 0xB4, 0xE5, 0x10, 0x00, 0xBC, 0xE6, 0x10, 0x00, 0x4C, 0x20, 0x62, 0x40, ++ 0xFF, 0xF3, 0xFF, 0xFF, 0x58, 0x20, 0x62, 0x40, 0xFF, 0xFD, 0xFF, 0xFF, ++ 0x08, 0x05, 0x62, 0x40, 0x74, 0x20, 0x62, 0x40, 0x78, 0x20, 0x62, 0x40, ++ 0xD8, 0x97, 0x16, 0x00, 0x24, 0xD1, 0x10, 0x00, 0x3C, 0xD1, 0x10, 0x00, ++ 0x70, 0x47, 0x00, 0x00, 0x03, 0x4B, 0x04, 0x4A, 0x13, 0x60, 0x81, 0x22, ++ 0x52, 0x00, 0x98, 0x5C, 0x70, 0x47, 0xC0, 0x46, 0x80, 0x2A, 0x16, 0x00, ++ 0x0C, 0xE7, 0x10, 0x00, 0xF0, 0xB5, 0xC6, 0x46, 0x00, 0xB5, 0x17, 0x4B, ++ 0x17, 0x4A, 0x1A, 0x60, 0x17, 0x48, 0x80, 0xF7, 0x53, 0xFD, 0x45, 0x1E, ++ 0x6D, 0xB2, 0x40, 0xB2, 0x00, 0x28, 0x1F, 0xDD, 0x11, 0x4F, 0x14, 0x4B, ++ 0x98, 0x46, 0x14, 0x4E, 0x0A, 0xE0, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, ++ 0x43, 0x46, 0x9B, 0x6E, 0x98, 0x47, 0x09, 0xE0, 0x01, 0x3D, 0x6D, 0xB2, ++ 0x6B, 0x1C, 0x0F, 0xD0, 0x38, 0x68, 0x0C, 0x30, 0x80, 0xF7, 0x56, 0xFC, ++ 0x04, 0x1E, 0xEE, 0xD0, 0x61, 0x6A, 0x30, 0x00, 0x80, 0xF7, 0xE2, 0xF8, ++ 0x63, 0x6A, 0x00, 0x2B, 0xEE, 0xD0, 0x20, 0x00, 0x98, 0x47, 0xEB, 0xE7, ++ 0x04, 0xBC, 0x90, 0x46, 0xF0, 0xBD, 0xC0, 0x46, 0x10, 0xE7, 0x10, 0x00, ++ 0x64, 0x2A, 0x16, 0x00, 0x70, 0x2A, 0x16, 0x00, 0x28, 0x19, 0x16, 0x00, ++ 0xC0, 0xD3, 0x10, 0x00, 0x70, 0xB5, 0x04, 0x00, 0x78, 0x21, 0x88, 0xF7, ++ 0xAB, 0xF9, 0x05, 0x00, 0x08, 0x4B, 0xC0, 0x18, 0x78, 0x22, 0x55, 0x21, ++ 0x7C, 0xF7, 0x42, 0xF8, 0x29, 0x00, 0x20, 0x00, 0x88, 0xF7, 0xBA, 0xF9, ++ 0x01, 0x00, 0x20, 0x00, 0xB0, 0xF7, 0x1E, 0xFD, 0x02, 0x48, 0x80, 0xF7, ++ 0xB7, 0xF8, 0x70, 0xBD, 0x00, 0x00, 0x61, 0x40, 0x4C, 0xD1, 0x10, 0x00, ++ 0xF0, 0xB5, 0xDE, 0x46, 0x57, 0x46, 0x4E, 0x46, 0x45, 0x46, 0xE0, 0xB5, ++ 0x83, 0xB0, 0x04, 0x00, 0x83, 0x00, 0x76, 0x4A, 0x94, 0x46, 0x63, 0x44, ++ 0x1D, 0x68, 0x00, 0x2D, 0x00, 0xD1, 0xDE, 0xE0, 0x4B, 0x23, 0xEB, 0x5C, ++ 0x00, 0x2B, 0x05, 0xD0, 0x71, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, ++ 0x00, 0x20, 0x98, 0x47, 0x28, 0x00, 0x50, 0x30, 0x80, 0xF7, 0x02, 0xFC, ++ 0x07, 0x00, 0x00, 0x21, 0x20, 0x00, 0x88, 0xF7, 0xDF, 0xF9, 0x63, 0x01, ++ 0x6A, 0x4A, 0x9A, 0x18, 0x12, 0x68, 0xD2, 0x0F, 0x49, 0x21, 0x69, 0x5C, ++ 0x01, 0x26, 0x71, 0x40, 0x91, 0x42, 0x4F, 0xD0, 0x66, 0x49, 0x8A, 0x46, ++ 0x9A, 0x44, 0x51, 0x46, 0x09, 0x68, 0x89, 0xB2, 0x8B, 0x46, 0x64, 0x4E, ++ 0xB1, 0x46, 0x99, 0x44, 0x4E, 0x46, 0x36, 0x68, 0xB6, 0xB2, 0xB0, 0x46, ++ 0x61, 0x4E, 0x9E, 0x19, 0x36, 0x68, 0xB6, 0x03, 0xB1, 0x0F, 0x01, 0x91, ++ 0x56, 0x46, 0x36, 0x68, 0x36, 0x0C, 0x36, 0x04, 0xB4, 0x46, 0x56, 0x46, ++ 0x61, 0x46, 0x31, 0x60, 0x49, 0x46, 0x09, 0x68, 0x09, 0x0C, 0x09, 0x04, ++ 0x8C, 0x46, 0x49, 0x46, 0x66, 0x46, 0x0E, 0x60, 0x00, 0x2F, 0x67, 0xD0, ++ 0x00, 0x2A, 0x4C, 0xD1, 0x52, 0x4A, 0x94, 0x46, 0x9C, 0x44, 0x62, 0x46, ++ 0x12, 0x68, 0x91, 0x46, 0xBA, 0x88, 0x12, 0x04, 0x49, 0x46, 0x0F, 0x04, ++ 0x3F, 0x0C, 0x3A, 0x43, 0x61, 0x46, 0x0A, 0x60, 0x00, 0x28, 0x0A, 0xD0, ++ 0x4B, 0x4A, 0x94, 0x46, 0x63, 0x44, 0x1F, 0x68, 0x82, 0x88, 0x04, 0x32, ++ 0x12, 0x04, 0x38, 0x04, 0x00, 0x0C, 0x02, 0x43, 0x1A, 0x60, 0x5B, 0x46, ++ 0x00, 0x2B, 0x4C, 0xD1, 0x43, 0x46, 0x00, 0x2B, 0x4E, 0xD1, 0x03, 0xB0, ++ 0x3C, 0xBC, 0x90, 0x46, 0x99, 0x46, 0xA2, 0x46, 0xAB, 0x46, 0xF0, 0xBD, ++ 0x3E, 0x49, 0x8A, 0x46, 0x9A, 0x44, 0x51, 0x46, 0x09, 0x68, 0x09, 0x0C, ++ 0x8B, 0x46, 0x3C, 0x49, 0x89, 0x46, 0x99, 0x44, 0x49, 0x46, 0x0E, 0x68, ++ 0x31, 0x0C, 0x88, 0x46, 0x39, 0x49, 0x5E, 0x18, 0x36, 0x68, 0x36, 0x03, ++ 0xB1, 0x0F, 0x01, 0x91, 0x51, 0x46, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0C, ++ 0x8C, 0x46, 0x51, 0x46, 0x66, 0x46, 0x0E, 0x60, 0x49, 0x46, 0x09, 0x68, ++ 0x09, 0x04, 0x09, 0x0C, 0x8C, 0x46, 0x49, 0x46, 0x66, 0x46, 0x0E, 0x60, ++ 0xAE, 0xE7, 0x2C, 0x4A, 0x94, 0x46, 0x9C, 0x44, 0x62, 0x46, 0x12, 0x68, ++ 0x12, 0x0C, 0x12, 0x04, 0xBF, 0x88, 0x3A, 0x43, 0x61, 0x46, 0x0A, 0x60, ++ 0x00, 0x28, 0xC0, 0xD0, 0x26, 0x4A, 0x94, 0x46, 0x63, 0x44, 0x1F, 0x68, ++ 0x82, 0x88, 0x04, 0x32, 0x92, 0xB2, 0x38, 0x0C, 0x00, 0x04, 0x02, 0x43, ++ 0x1A, 0x60, 0xB4, 0xE7, 0x00, 0x28, 0xB2, 0xD0, 0x00, 0x2A, 0xEF, 0xD1, ++ 0xA4, 0xE7, 0x59, 0x46, 0x20, 0x00, 0x88, 0xF7, 0x17, 0xF9, 0xAD, 0xE7, ++ 0x46, 0x23, 0xE9, 0x5C, 0x09, 0x02, 0x45, 0x3B, 0x19, 0x43, 0x05, 0x33, ++ 0xFF, 0x22, 0x1A, 0x48, 0x7D, 0xF7, 0xDE, 0xFE, 0x07, 0x00, 0x43, 0x46, ++ 0x03, 0x80, 0x58, 0x23, 0xEA, 0x5C, 0x01, 0x32, 0x2B, 0x8F, 0x53, 0x43, ++ 0x83, 0x70, 0x01, 0x99, 0xC1, 0x70, 0x14, 0x4B, 0x1A, 0x68, 0x01, 0x32, ++ 0x1A, 0x60, 0x00, 0x29, 0x04, 0xD1, 0x3C, 0x71, 0x38, 0x00, 0x7D, 0xF7, ++ 0xF3, 0xFE, 0x90, 0xE7, 0x0F, 0x49, 0x0B, 0x68, 0x01, 0x33, 0x0B, 0x60, ++ 0x01, 0x99, 0x0E, 0x48, 0x7F, 0xF7, 0xC4, 0xFF, 0xF1, 0xE7, 0x04, 0x4B, ++ 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x80, 0xE7, ++ 0x54, 0x27, 0x16, 0x00, 0x28, 0x19, 0x16, 0x00, 0xD0, 0x05, 0x60, 0x40, ++ 0xD8, 0x05, 0x60, 0x40, 0xDC, 0x05, 0x60, 0x40, 0xD4, 0x05, 0x60, 0x40, ++ 0x35, 0x06, 0x00, 0x00, 0xC4, 0xE6, 0x10, 0x00, 0xC0, 0xE6, 0x10, 0x00, ++ 0x54, 0xD1, 0x10, 0x00, 0x70, 0xB5, 0x0C, 0x00, 0x15, 0x00, 0x10, 0x00, ++ 0x7E, 0xF7, 0x74, 0xFA, 0x00, 0x28, 0x03, 0xD0, 0x16, 0x38, 0xC0, 0xB2, ++ 0x03, 0x28, 0x07, 0xD8, 0x21, 0x88, 0x04, 0x39, 0x89, 0xB2, 0x20, 0x79, ++ 0x88, 0xF7, 0xFA, 0xF8, 0x00, 0x20, 0x70, 0xBD, 0x2E, 0x0A, 0x06, 0x23, ++ 0x2A, 0x00, 0x31, 0x00, 0x1B, 0x48, 0x7D, 0xF7, 0x89, 0xFE, 0x05, 0x00, ++ 0x23, 0x88, 0x83, 0x80, 0xA3, 0x78, 0x83, 0x70, 0x21, 0x79, 0x01, 0x31, ++ 0x09, 0x02, 0x80, 0x36, 0x89, 0x19, 0x01, 0x80, 0xE1, 0x78, 0x0A, 0x03, ++ 0x14, 0x4B, 0x1A, 0x42, 0x06, 0xD0, 0xC0, 0x20, 0x13, 0x4B, 0xDE, 0x6E, ++ 0x00, 0x23, 0x00, 0x22, 0x80, 0x01, 0xB0, 0x47, 0x2B, 0x88, 0x0F, 0x4A, ++ 0x13, 0x40, 0xE2, 0x78, 0x12, 0x03, 0x13, 0x43, 0x2B, 0x80, 0xE3, 0x78, ++ 0x00, 0x2B, 0x03, 0xD1, 0x28, 0x00, 0xCF, 0xF7, 0xC5, 0xFC, 0xD1, 0xE7, ++ 0xA2, 0x78, 0x20, 0x88, 0x09, 0x4B, 0x9C, 0x46, 0x60, 0x44, 0x00, 0x21, ++ 0x7B, 0xF7, 0xE0, 0xFE, 0xE1, 0x78, 0x00, 0x29, 0xF0, 0xD0, 0x06, 0x48, ++ 0x7F, 0xF7, 0x5A, 0xFF, 0xEC, 0xE7, 0xC0, 0x46, 0x07, 0x11, 0x00, 0x00, ++ 0xFF, 0xCF, 0xFF, 0xFF, 0x28, 0x19, 0x16, 0x00, 0x00, 0x00, 0x61, 0x40, ++ 0x6C, 0xD1, 0x10, 0x00, 0xF0, 0xB5, 0x89, 0xB0, 0x04, 0x1E, 0x00, 0xD1, ++ 0xAB, 0xE0, 0x46, 0x23, 0xC6, 0x5C, 0xB2, 0x00, 0x5A, 0x4B, 0xD5, 0x58, ++ 0x00, 0x2D, 0x00, 0xD1, 0xA9, 0xE0, 0x43, 0x68, 0x02, 0x3B, 0x1B, 0x01, ++ 0x1B, 0x09, 0xC3, 0x62, 0x28, 0x30, 0xD2, 0xF7, 0xE9, 0xFD, 0x62, 0x68, ++ 0x61, 0x6B, 0x8A, 0x42, 0x13, 0xD0, 0x45, 0x23, 0xE3, 0x5C, 0x5B, 0x00, ++ 0x5B, 0x18, 0x1B, 0x01, 0x1B, 0x09, 0x9A, 0x42, 0x0B, 0xD0, 0x4F, 0x4B, ++ 0x9B, 0x7A, 0xA3, 0x75, 0x4A, 0x23, 0xE3, 0x5C, 0x03, 0x2B, 0x00, 0xD0, ++ 0x8D, 0xE0, 0x47, 0x33, 0x00, 0x22, 0xE2, 0x54, 0x89, 0xE0, 0x4A, 0x4B, ++ 0x00, 0x93, 0x01, 0x92, 0xA3, 0x68, 0x02, 0x93, 0x6B, 0x46, 0x1E, 0x76, ++ 0x47, 0x23, 0xE0, 0x5C, 0x03, 0x01, 0x33, 0x43, 0x04, 0x93, 0x00, 0x23, ++ 0x9C, 0x46, 0x03, 0x93, 0xA7, 0x7D, 0x6B, 0x46, 0x1F, 0x75, 0x67, 0x46, ++ 0x5F, 0x75, 0x9F, 0x75, 0x8A, 0x42, 0x00, 0xD1, 0x73, 0xE0, 0x10, 0x23, ++ 0x6A, 0x46, 0xD3, 0x75, 0x0C, 0x3B, 0x6A, 0x46, 0x93, 0x76, 0xD0, 0x76, ++ 0x01, 0x23, 0x53, 0x76, 0x68, 0x46, 0xD3, 0xF7, 0x9B, 0xF8, 0x48, 0x22, ++ 0xA3, 0x5C, 0x01, 0x33, 0xA3, 0x54, 0x01, 0x21, 0x63, 0x68, 0x62, 0x6B, ++ 0x93, 0x42, 0x35, 0xD0, 0x47, 0x23, 0xE3, 0x5C, 0x33, 0x4A, 0x94, 0x46, ++ 0x63, 0x44, 0x5B, 0x01, 0x1A, 0x68, 0x32, 0x48, 0x02, 0x40, 0x09, 0x04, ++ 0x0A, 0x43, 0x1A, 0x60, 0x9F, 0x23, 0xEB, 0x5C, 0x01, 0x2B, 0xB6, 0xD1, ++ 0x2B, 0x6D, 0x5F, 0x1C, 0x7F, 0x08, 0xAB, 0x6F, 0x9B, 0xB2, 0x62, 0x22, ++ 0x56, 0x43, 0x2B, 0x4A, 0xB2, 0x18, 0x13, 0x80, 0xAB, 0x6F, 0x1B, 0x0C, ++ 0x29, 0x4A, 0xB2, 0x18, 0x13, 0x80, 0x80, 0x23, 0x9B, 0x01, 0x9F, 0x42, ++ 0x2B, 0xD3, 0x27, 0x49, 0x38, 0x00, 0xD4, 0xF7, 0xF9, 0xF8, 0x00, 0x29, ++ 0x19, 0xD0, 0x25, 0x4B, 0x9C, 0x46, 0x66, 0x44, 0x22, 0x49, 0x38, 0x00, ++ 0xD4, 0xF7, 0x6A, 0xF8, 0x01, 0x30, 0x22, 0x4B, 0x03, 0x43, 0x9B, 0xB2, ++ 0x33, 0x80, 0x90, 0xE7, 0x20, 0x4B, 0x2A, 0x6D, 0x9A, 0x42, 0xC5, 0xD8, ++ 0x4A, 0x23, 0xE3, 0x5C, 0x00, 0x2B, 0xC1, 0xD1, 0x44, 0x33, 0xE1, 0x5C, ++ 0x01, 0x31, 0xC9, 0xB2, 0xBC, 0xE7, 0x18, 0x4B, 0x9C, 0x46, 0x66, 0x44, ++ 0x15, 0x49, 0x38, 0x00, 0xD4, 0xF7, 0x50, 0xF8, 0x15, 0x4B, 0x03, 0x43, ++ 0x9B, 0xB2, 0x33, 0x80, 0x77, 0xE7, 0x01, 0x37, 0x7F, 0x08, 0xBF, 0xB2, ++ 0x10, 0x4B, 0x9C, 0x46, 0x66, 0x44, 0x37, 0x80, 0x6F, 0xE7, 0x11, 0x4B, ++ 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x09, 0xB0, ++ 0xF0, 0xBD, 0x0F, 0x23, 0x6A, 0x46, 0xD3, 0x75, 0x0D, 0x3B, 0x8A, 0xE7, ++ 0x38, 0x27, 0x16, 0x00, 0x7C, 0x91, 0x0D, 0x00, 0x5D, 0x74, 0x0B, 0x00, ++ 0x2F, 0x00, 0x03, 0x02, 0xFF, 0xFF, 0x00, 0xFF, 0xFA, 0x64, 0x61, 0x40, ++ 0xFC, 0x64, 0x61, 0x40, 0x71, 0x02, 0x00, 0x00, 0x10, 0x65, 0x61, 0x40, ++ 0x00, 0x80, 0xFF, 0xFF, 0xE1, 0x04, 0x00, 0x00, 0x28, 0x19, 0x16, 0x00, ++ 0xF8, 0xB5, 0x06, 0x00, 0x14, 0x4B, 0x1D, 0x68, 0x00, 0x2D, 0x05, 0xD1, ++ 0x5D, 0x68, 0x00, 0x2D, 0x02, 0xD1, 0x00, 0x24, 0x20, 0x00, 0xF8, 0xBD, ++ 0xAB, 0x68, 0x2A, 0x69, 0x94, 0x46, 0x63, 0x44, 0x1F, 0x00, 0x0E, 0x49, ++ 0x18, 0x00, 0xD4, 0xF7, 0x09, 0xF8, 0x6C, 0x6B, 0x04, 0x19, 0x0B, 0x49, ++ 0x38, 0x00, 0xD4, 0xF7, 0x89, 0xF8, 0xB3, 0x68, 0x9C, 0x46, 0x8C, 0x45, ++ 0x89, 0x41, 0x49, 0x42, 0x64, 0x18, 0xB1, 0x8A, 0x89, 0x04, 0x49, 0x0F, ++ 0x04, 0x29, 0xE3, 0xD0, 0x20, 0x00, 0xFC, 0xF7, 0x63, 0xFF, 0x04, 0x00, ++ 0xDE, 0xE7, 0xC0, 0x46, 0x54, 0x27, 0x16, 0x00, 0x71, 0x02, 0x00, 0x00, ++ 0xF0, 0xB5, 0xDE, 0x46, 0x57, 0x46, 0x4E, 0x46, 0x45, 0x46, 0xE0, 0xB5, ++ 0x8B, 0xB0, 0xBD, 0x4B, 0x1C, 0x68, 0xA1, 0x46, 0xBC, 0x4B, 0xA3, 0x82, ++ 0x4C, 0x23, 0xE3, 0x5A, 0x5B, 0x00, 0x62, 0x6C, 0x94, 0x46, 0x63, 0x44, ++ 0x1B, 0x01, 0x1B, 0x09, 0xE3, 0x60, 0xA7, 0xF7, 0x5D, 0xF9, 0x04, 0x90, ++ 0xB6, 0x4B, 0x1B, 0x68, 0x01, 0x93, 0xB6, 0x4B, 0x1B, 0x68, 0x02, 0x93, ++ 0xB5, 0x4B, 0x1B, 0x68, 0x07, 0x93, 0xB5, 0x4B, 0x1B, 0x68, 0x06, 0x93, ++ 0x00, 0x25, 0x00, 0x20, 0x00, 0x27, 0x00, 0x23, 0x03, 0x93, 0x00, 0x26, ++ 0xB1, 0x4B, 0x98, 0x46, 0xA1, 0x23, 0x9A, 0x46, 0x02, 0x3B, 0x9B, 0x46, ++ 0x0F, 0xE0, 0x01, 0x37, 0xFF, 0xB2, 0xAF, 0x22, 0x9E, 0x5C, 0x86, 0x19, ++ 0xF6, 0xB2, 0x48, 0x33, 0x18, 0x00, 0x80, 0xF7, 0x5F, 0xFA, 0x30, 0x18, ++ 0xC0, 0xB2, 0x01, 0x26, 0x01, 0x35, 0x07, 0x2D, 0x0E, 0xD0, 0xAB, 0x00, ++ 0x42, 0x46, 0x9B, 0x58, 0x00, 0x2B, 0xF7, 0xD0, 0x52, 0x46, 0x9A, 0x5C, ++ 0x00, 0x2A, 0xF3, 0xD1, 0x5A, 0x46, 0x9A, 0x5C, 0x01, 0x2A, 0xE2, 0xD1, ++ 0x03, 0x92, 0xE0, 0xE7, 0x9F, 0x4B, 0x00, 0x22, 0x1A, 0x70, 0x00, 0x23, ++ 0x01, 0x32, 0xBA, 0x42, 0x5B, 0x41, 0x02, 0x33, 0x9C, 0x4A, 0x13, 0x70, ++ 0x83, 0x42, 0x08, 0xD8, 0x00, 0x22, 0x03, 0x28, 0x01, 0xD9, 0xC2, 0x1E, ++ 0xD2, 0xB2, 0xC0, 0x1A, 0x10, 0x18, 0x96, 0x4B, 0x18, 0x70, 0x50, 0x23, ++ 0x00, 0x22, 0xE2, 0x54, 0x95, 0x4B, 0x19, 0x00, 0x41, 0x31, 0xFF, 0x31, ++ 0x00, 0x25, 0x04, 0xE0, 0x01, 0x35, 0xED, 0xB2, 0x40, 0x33, 0x8B, 0x42, ++ 0x07, 0xD0, 0x1A, 0x78, 0x09, 0x2A, 0xF9, 0xD1, 0x00, 0x2F, 0xF5, 0xD0, ++ 0x01, 0x37, 0xFF, 0xB2, 0xF2, 0xE7, 0xB0, 0xF7, 0x5F, 0xFA, 0x05, 0x90, ++ 0x80, 0x46, 0x02, 0x9B, 0x01, 0x9A, 0x13, 0x43, 0x5A, 0x1E, 0x93, 0x41, ++ 0xDB, 0xB2, 0x9B, 0x46, 0x87, 0x4B, 0x1B, 0x78, 0x9A, 0x46, 0x00, 0x2B, ++ 0x00, 0xD1, 0x79, 0xE0, 0x85, 0x4B, 0x1B, 0x78, 0x01, 0x2B, 0x28, 0xD9, ++ 0x02, 0x2B, 0x64, 0xD0, 0x8C, 0xF7, 0xDC, 0xF8, 0x82, 0x46, 0x00, 0x28, ++ 0x00, 0xD1, 0x1B, 0xE2, 0x00, 0x23, 0x9A, 0x46, 0x7F, 0x4B, 0x23, 0x64, ++ 0x02, 0x22, 0x62, 0x63, 0xFA, 0x22, 0x92, 0x01, 0xA2, 0x62, 0x19, 0x00, ++ 0x23, 0x61, 0x43, 0x46, 0x00, 0x2B, 0x00, 0xD0, 0x77, 0xE0, 0xA3, 0x6A, ++ 0x62, 0x6B, 0x98, 0x1A, 0x40, 0x00, 0x04, 0x9B, 0x9C, 0x46, 0x60, 0x44, ++ 0x00, 0x01, 0x00, 0x09, 0x60, 0x60, 0x01, 0x2D, 0x00, 0xD1, 0x84, 0xE1, ++ 0x00, 0x22, 0x20, 0x00, 0xFC, 0xF7, 0x9A, 0xFF, 0x11, 0xE0, 0x71, 0x4B, ++ 0x23, 0x64, 0x80, 0x22, 0x62, 0x63, 0xA2, 0x62, 0x6C, 0x4A, 0x01, 0x21, ++ 0x11, 0x70, 0x16, 0x22, 0xA2, 0x75, 0x23, 0x61, 0x04, 0x98, 0x2C, 0x30, ++ 0x00, 0x01, 0x00, 0x09, 0x60, 0x60, 0x00, 0x23, 0x9A, 0x46, 0x69, 0x4E, ++ 0x4C, 0x25, 0x69, 0x4F, 0x48, 0x46, 0xD1, 0xF7, 0x33, 0xFF, 0x00, 0x28, ++ 0x00, 0xD1, 0xB0, 0xE1, 0x31, 0x00, 0x20, 0x69, 0xD3, 0xF7, 0x16, 0xFF, ++ 0x63, 0x68, 0x9C, 0x46, 0x60, 0x44, 0x00, 0x01, 0x00, 0x09, 0x60, 0x60, ++ 0x63, 0x5B, 0x5B, 0x00, 0xE2, 0x68, 0x94, 0x46, 0x63, 0x44, 0x1B, 0x01, ++ 0x1B, 0x09, 0xE3, 0x60, 0xA3, 0x7D, 0x5D, 0x4A, 0xD2, 0x78, 0x9B, 0x18, ++ 0xA3, 0x75, 0x59, 0x4B, 0x9C, 0x46, 0x66, 0x44, 0xBE, 0x42, 0xDD, 0xD1, ++ 0x0B, 0xB0, 0x3C, 0xBC, 0x90, 0x46, 0x99, 0x46, 0xA2, 0x46, 0xAB, 0x46, ++ 0xF0, 0xBD, 0x56, 0x4B, 0x1B, 0x68, 0x5B, 0x00, 0x23, 0x64, 0x02, 0x23, ++ 0x63, 0x63, 0x4E, 0x33, 0xA3, 0x62, 0x4C, 0x4B, 0x03, 0x22, 0x1A, 0x70, ++ 0x49, 0x4B, 0x00, 0x22, 0x1A, 0x70, 0x8B, 0xE7, 0xFD, 0xF7, 0x12, 0xF8, ++ 0x00, 0x28, 0x04, 0xD1, 0x4D, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x00, 0xD1, ++ 0x11, 0xE1, 0x43, 0x46, 0x00, 0x2B, 0x2C, 0xD0, 0x4A, 0x4B, 0x23, 0x64, ++ 0x04, 0x23, 0x63, 0x63, 0x08, 0x33, 0xA3, 0x62, 0x8C, 0xF7, 0x56, 0xF8, ++ 0x00, 0x28, 0x00, 0xD0, 0x7C, 0xE7, 0x23, 0x6C, 0x23, 0x61, 0x20, 0x00, ++ 0xFF, 0xF7, 0xAE, 0xFE, 0x53, 0x46, 0x00, 0x2B, 0x00, 0xD1, 0x95, 0xE1, ++ 0xC0, 0x30, 0x00, 0x01, 0x00, 0x09, 0x60, 0x60, 0x18, 0x26, 0x4F, 0x46, ++ 0x65, 0x68, 0x00, 0x22, 0x21, 0x69, 0x38, 0x00, 0xFC, 0xF7, 0x20, 0xFF, ++ 0x63, 0x68, 0xAB, 0x42, 0x00, 0xD1, 0x4A, 0xE1, 0x75, 0x19, 0x2D, 0x01, ++ 0x2D, 0x09, 0x65, 0x60, 0x18, 0x36, 0x90, 0x2E, 0xEE, 0xD1, 0xB9, 0x46, ++ 0x8B, 0xE7, 0x5B, 0x46, 0x00, 0x2B, 0x21, 0xD0, 0x33, 0x4B, 0x1B, 0x68, ++ 0x5B, 0x00, 0x23, 0x64, 0xE3, 0x6B, 0x63, 0x63, 0x23, 0x6B, 0xA3, 0x62, ++ 0x03, 0x9B, 0x00, 0x2B, 0x05, 0xD0, 0x2F, 0x4B, 0x23, 0x64, 0x1A, 0x23, ++ 0x63, 0x63, 0x46, 0x33, 0xA3, 0x62, 0xB2, 0x46, 0x00, 0x2E, 0x00, 0xD1, ++ 0xD4, 0xE0, 0x05, 0x9A, 0x92, 0x46, 0x01, 0x9B, 0x00, 0x2B, 0x00, 0xD1, ++ 0xCE, 0xE0, 0x28, 0x4B, 0x1B, 0x68, 0xA1, 0x6A, 0x8C, 0x46, 0x63, 0x44, ++ 0xA3, 0x62, 0xC7, 0xE0, 0x15, 0x4B, 0x1B, 0x78, 0x5A, 0x00, 0x9B, 0x18, ++ 0x5B, 0x00, 0xDB, 0xB2, 0x01, 0x2F, 0x49, 0xD9, 0x21, 0x4A, 0x22, 0x64, ++ 0x1A, 0x22, 0x62, 0x63, 0x2C, 0x32, 0xA2, 0x62, 0x00, 0x2B, 0x03, 0xD0, ++ 0x1E, 0x4B, 0x23, 0x64, 0x14, 0x23, 0x63, 0x63, 0x00, 0x2D, 0x03, 0xD0, ++ 0x1C, 0x4B, 0x23, 0x64, 0x10, 0x23, 0x63, 0x63, 0x63, 0x6B, 0xA3, 0x62, ++ 0xDA, 0x46, 0xA9, 0xE0, 0xF8, 0xE6, 0x10, 0x00, 0x00, 0xA0, 0xFF, 0xFF, ++ 0x24, 0x27, 0x16, 0x00, 0x18, 0x27, 0x16, 0x00, 0x28, 0x27, 0x16, 0x00, ++ 0x20, 0x27, 0x16, 0x00, 0x38, 0x27, 0x16, 0x00, 0xB1, 0xE6, 0x10, 0x00, ++ 0xD1, 0xE6, 0x10, 0x00, 0x70, 0xA6, 0x16, 0x00, 0xB4, 0xE6, 0x10, 0x00, ++ 0xB3, 0xE6, 0x10, 0x00, 0xC4, 0x09, 0x00, 0x00, 0x00, 0x71, 0x02, 0x00, ++ 0xE2, 0x04, 0x00, 0x00, 0x6A, 0x18, 0x00, 0x00, 0x7C, 0x91, 0x0D, 0x00, ++ 0x04, 0xE2, 0x10, 0x00, 0xB2, 0xE6, 0x10, 0x00, 0xF9, 0x15, 0x00, 0x00, ++ 0x08, 0xE2, 0x10, 0x00, 0xDC, 0x82, 0x00, 0x00, 0x14, 0xE2, 0x10, 0x00, ++ 0xE8, 0x80, 0x00, 0x00, 0xF6, 0x54, 0x00, 0x00, 0xF2, 0x2B, 0x00, 0x00, ++ 0x85, 0x4A, 0x5A, 0x43, 0x03, 0x99, 0x00, 0x29, 0x33, 0xD0, 0x84, 0x49, ++ 0x09, 0x68, 0x49, 0x00, 0x8A, 0x42, 0x29, 0xD8, 0x8A, 0x1A, 0x22, 0x64, ++ 0x28, 0x22, 0xD3, 0x1A, 0x63, 0x63, 0xE3, 0x6A, 0xA3, 0x62, 0x7F, 0x4B, ++ 0x22, 0x6C, 0x9A, 0x42, 0x4B, 0xD9, 0xDA, 0x46, 0x00, 0x2F, 0x5D, 0xD0, ++ 0x07, 0x9B, 0x00, 0x2B, 0x00, 0xD1, 0xC4, 0xE0, 0x59, 0x68, 0x06, 0x9A, ++ 0x00, 0x2A, 0x00, 0xD1, 0xC4, 0xE0, 0x78, 0x4B, 0x99, 0x42, 0x00, 0xD1, ++ 0xBE, 0xE0, 0x52, 0x68, 0x53, 0x1A, 0x1B, 0x01, 0x1B, 0x09, 0x80, 0x20, ++ 0x00, 0x05, 0x83, 0x42, 0x00, 0xD8, 0xBA, 0xE0, 0x8B, 0x1A, 0x1B, 0x01, ++ 0x00, 0xD1, 0xB6, 0xE0, 0x11, 0x00, 0xB1, 0xE0, 0x6F, 0x4B, 0x23, 0x64, ++ 0x1A, 0x23, 0x63, 0x63, 0xD5, 0xE7, 0x00, 0x2D, 0x0D, 0xD0, 0x6D, 0x4B, ++ 0x23, 0x64, 0x10, 0x23, 0x63, 0x63, 0xA3, 0x62, 0x01, 0x2D, 0x02, 0xD0, ++ 0x01, 0x23, 0x9A, 0x46, 0xD0, 0xE7, 0x40, 0x33, 0x01, 0x22, 0xE2, 0x54, ++ 0xF8, 0xE7, 0x67, 0x49, 0x09, 0x68, 0x49, 0x00, 0x8A, 0x42, 0x0D, 0xD8, ++ 0x8A, 0x1A, 0x22, 0x64, 0xA2, 0x6B, 0xD3, 0x1A, 0x63, 0x63, 0xE3, 0x6A, ++ 0xA3, 0x62, 0x5D, 0x4B, 0x22, 0x6C, 0x9A, 0x42, 0x09, 0xD9, 0x03, 0x9B, ++ 0x9A, 0x46, 0xB9, 0xE7, 0x5B, 0x4B, 0x23, 0x64, 0x1A, 0x23, 0x63, 0x63, ++ 0xF1, 0xE7, 0x00, 0x2D, 0x05, 0xD1, 0x58, 0x4B, 0x23, 0x64, 0x1A, 0x23, ++ 0x63, 0x63, 0xDA, 0x46, 0xAC, 0xE7, 0xDA, 0x46, 0xAA, 0xE7, 0x50, 0x4B, ++ 0x23, 0x64, 0x02, 0x23, 0x63, 0x63, 0x43, 0x46, 0x00, 0x2B, 0x0B, 0xD1, ++ 0x30, 0x33, 0xA3, 0x62, 0x2F, 0x3B, 0x9A, 0x46, 0x8B, 0xF7, 0x42, 0xFF, ++ 0x00, 0x28, 0x00, 0xD0, 0x68, 0xE6, 0x21, 0x6C, 0x21, 0x61, 0x72, 0xE6, ++ 0xC0, 0x23, 0xA3, 0x62, 0x05, 0x9B, 0x9A, 0x46, 0xDE, 0xE6, 0x00, 0x23, ++ 0x08, 0x93, 0x09, 0x93, 0x20, 0x1D, 0x23, 0x00, 0x08, 0xAA, 0x09, 0xA9, ++ 0xFC, 0xF7, 0x72, 0xFD, 0x09, 0x9B, 0x00, 0x2B, 0x04, 0xD0, 0x22, 0x69, ++ 0x9A, 0x42, 0x00, 0xD9, 0x1A, 0x00, 0x22, 0x61, 0x00, 0x2F, 0x07, 0xD0, ++ 0x08, 0x9B, 0x5B, 0x00, 0x62, 0x68, 0x94, 0x46, 0x63, 0x44, 0x1B, 0x01, ++ 0x1B, 0x09, 0x63, 0x60, 0x63, 0x6B, 0x02, 0x2B, 0x1E, 0xD0, 0x53, 0x46, ++ 0x00, 0x2B, 0x04, 0xD1, 0x3A, 0x4B, 0x08, 0x9A, 0x53, 0x43, 0x23, 0x61, ++ 0x23, 0x64, 0x03, 0x26, 0x4F, 0x46, 0x65, 0x68, 0x00, 0x22, 0x21, 0x69, ++ 0x38, 0x00, 0xFC, 0xF7, 0xEB, 0xFD, 0x63, 0x68, 0xAB, 0x42, 0x18, 0xD0, ++ 0x08, 0x9B, 0x9C, 0x46, 0x65, 0x44, 0x2D, 0x01, 0x2D, 0x09, 0x65, 0x60, ++ 0x01, 0x3E, 0xF6, 0xB2, 0x00, 0x2E, 0xEC, 0xD1, 0xB9, 0x46, 0x54, 0xE6, ++ 0x08, 0x9A, 0x53, 0x00, 0x9B, 0x18, 0x5B, 0x00, 0x62, 0x68, 0x94, 0x46, ++ 0x63, 0x44, 0x1B, 0x01, 0x1B, 0x09, 0x63, 0x60, 0xD5, 0xE7, 0xB9, 0x46, ++ 0x47, 0xE6, 0xB9, 0x46, 0x45, 0xE6, 0x4E, 0x23, 0x00, 0x22, 0xE2, 0x54, ++ 0xA3, 0x7D, 0x10, 0x2B, 0x00, 0xD9, 0x63, 0xE6, 0x43, 0x46, 0x00, 0x2B, ++ 0x00, 0xD0, 0x5F, 0xE6, 0x53, 0x46, 0x00, 0x2B, 0x00, 0xD0, 0x5B, 0xE6, ++ 0x11, 0x33, 0xA3, 0x75, 0x58, 0xE6, 0x06, 0x9B, 0x00, 0x2B, 0x91, 0xD0, ++ 0x06, 0x9B, 0x59, 0x68, 0x15, 0x4B, 0x99, 0x42, 0x8C, 0xD0, 0x63, 0x6B, ++ 0x1A, 0x00, 0x28, 0x32, 0x52, 0x00, 0xA0, 0x6A, 0xC3, 0x1A, 0x5B, 0x00, ++ 0x04, 0x98, 0x84, 0x46, 0x63, 0x44, 0x1B, 0x01, 0x1B, 0x09, 0x5B, 0x1A, ++ 0x1B, 0x01, 0x1B, 0x09, 0x9A, 0x42, 0x00, 0xD2, 0x7A, 0xE7, 0x0C, 0x4B, ++ 0x23, 0x64, 0x77, 0xE7, 0x21, 0x6C, 0x21, 0x61, 0x43, 0x46, 0x00, 0x2B, ++ 0x04, 0xD0, 0x20, 0x00, 0xFF, 0xF7, 0x14, 0xFD, 0x60, 0x60, 0x6B, 0xE6, ++ 0x05, 0x9B, 0x9A, 0x46, 0xE5, 0xE5, 0xC0, 0x46, 0xE2, 0x04, 0x00, 0x00, ++ 0x00, 0xE2, 0x10, 0x00, 0xE7, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F, ++ 0xE8, 0x80, 0x00, 0x00, 0xF2, 0x2B, 0x00, 0x00, 0x04, 0xE2, 0x10, 0x00, ++ 0xA9, 0x03, 0x00, 0x00, 0x70, 0xB5, 0x04, 0x00, 0x1A, 0x4A, 0x13, 0x68, ++ 0x04, 0x21, 0x0B, 0x43, 0x13, 0x60, 0x19, 0x4B, 0x9B, 0x78, 0x83, 0x75, ++ 0xFC, 0xF7, 0x06, 0xFE, 0x05, 0x00, 0x02, 0x21, 0x01, 0x20, 0xFC, 0xF7, ++ 0xC3, 0xFE, 0x06, 0x00, 0x00, 0x2D, 0x04, 0xD0, 0x11, 0x4A, 0x13, 0x68, ++ 0x04, 0x21, 0x8B, 0x43, 0x13, 0x60, 0x4E, 0x23, 0xE3, 0x5C, 0x02, 0x2B, ++ 0x0E, 0xD0, 0xA6, 0xF7, 0x83, 0xFE, 0x60, 0x64, 0xFF, 0xF7, 0x0C, 0xFD, ++ 0x00, 0x2E, 0x0E, 0xD0, 0x00, 0x2D, 0x04, 0xD0, 0x08, 0x4A, 0x13, 0x68, ++ 0x04, 0x21, 0x0B, 0x43, 0x13, 0x60, 0x70, 0xBD, 0x07, 0x4C, 0x20, 0x68, ++ 0x7D, 0xF7, 0xB8, 0xFB, 0x00, 0x23, 0x23, 0x60, 0xEE, 0xE7, 0x02, 0x21, ++ 0x00, 0x20, 0xFC, 0xF7, 0x9D, 0xFE, 0xEB, 0xE7, 0xFC, 0x00, 0x60, 0x40, ++ 0x7C, 0x91, 0x0D, 0x00, 0xF8, 0xE6, 0x10, 0x00, 0x10, 0xB5, 0x4E, 0x23, ++ 0xC3, 0x5C, 0x00, 0x2B, 0x00, 0xD0, 0x10, 0xBD, 0x00, 0x21, 0xD1, 0xF7, ++ 0x8F, 0xFE, 0xFF, 0xF7, 0xE5, 0xFC, 0xF8, 0xE7, 0x10, 0xB5, 0xA6, 0xF7, ++ 0x55, 0xFE, 0x22, 0x4B, 0x5A, 0x68, 0x92, 0x01, 0x1B, 0x68, 0xC0, 0x1A, ++ 0x00, 0x01, 0x01, 0x09, 0x40, 0x00, 0x43, 0x1A, 0x9B, 0x00, 0x5B, 0x18, ++ 0x99, 0x00, 0x5B, 0x18, 0x9A, 0x42, 0x20, 0xD3, 0xD3, 0x1A, 0x1B, 0x4C, ++ 0x9C, 0x42, 0xA4, 0x41, 0x64, 0x42, 0x1A, 0x4B, 0x1A, 0x4A, 0x1A, 0x60, ++ 0xD1, 0xF7, 0xC0, 0xFE, 0x00, 0x28, 0x0A, 0xD0, 0x00, 0x2C, 0x19, 0xD0, ++ 0x17, 0x4B, 0x80, 0x22, 0x12, 0x05, 0x1A, 0x60, 0x16, 0x48, 0x7F, 0xF7, ++ 0x05, 0xFB, 0x10, 0xBD, 0x00, 0x24, 0x11, 0x4B, 0x1B, 0x68, 0x9B, 0x68, ++ 0x00, 0x2B, 0xF1, 0xD0, 0x12, 0x4A, 0xDB, 0x69, 0x93, 0x42, 0xEB, 0xD1, ++ 0xEC, 0xE7, 0x0C, 0x4B, 0x0C, 0x4A, 0x1A, 0x60, 0xD1, 0xF7, 0xA4, 0xFE, ++ 0x00, 0x28, 0xED, 0xD0, 0x0D, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x0D, 0x4B, ++ 0x00, 0x22, 0x1A, 0x70, 0x0C, 0x4B, 0x18, 0x68, 0x00, 0x28, 0xE2, 0xD0, ++ 0xFF, 0xF7, 0xAE, 0xFF, 0xDF, 0xE7, 0xC0, 0x46, 0x6C, 0xE6, 0x10, 0x00, ++ 0xFF, 0x70, 0x02, 0x00, 0x10, 0xE7, 0x10, 0x00, 0x64, 0x2A, 0x16, 0x00, ++ 0x00, 0x41, 0x04, 0x40, 0x74, 0xD1, 0x10, 0x00, 0xC9, 0x1F, 0x10, 0x00, ++ 0xB4, 0xE6, 0x10, 0x00, 0xB3, 0xE6, 0x10, 0x00, 0xF8, 0xE6, 0x10, 0x00, ++ 0xF8, 0xB5, 0xDE, 0x46, 0x57, 0x46, 0x4E, 0x46, 0x45, 0x46, 0xE0, 0xB5, ++ 0x06, 0x00, 0x0D, 0x00, 0x17, 0x00, 0x49, 0x4B, 0x1C, 0x68, 0xA4, 0x04, ++ 0xA4, 0x0E, 0x20, 0x00, 0x50, 0x43, 0x43, 0x01, 0x1B, 0x1A, 0x9B, 0x00, ++ 0x1B, 0x18, 0x98, 0x00, 0x18, 0x18, 0x00, 0x02, 0xD3, 0xF7, 0x5E, 0xFC, ++ 0x81, 0x46, 0x03, 0x0A, 0x9B, 0x46, 0x29, 0x00, 0x80, 0x20, 0xC0, 0x00, ++ 0xD3, 0xF7, 0x56, 0xFC, 0x03, 0x00, 0x6B, 0x43, 0x9A, 0x46, 0xFF, 0x21, ++ 0x4B, 0x46, 0x19, 0x40, 0x69, 0x43, 0x09, 0x0A, 0x48, 0x43, 0x53, 0x46, ++ 0x1B, 0x1A, 0x98, 0x46, 0x23, 0x01, 0x1B, 0x19, 0x9B, 0x00, 0x99, 0x46, ++ 0xA1, 0x44, 0x53, 0x46, 0x00, 0x2B, 0x05, 0xD1, 0x34, 0x4B, 0x9B, 0x6E, ++ 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x78, 0x01, 0xC0, 0x1B, ++ 0x80, 0x00, 0xC7, 0x19, 0xB8, 0x00, 0x38, 0x18, 0x29, 0x00, 0xD3, 0xF7, ++ 0x33, 0xFC, 0x44, 0x43, 0x27, 0x00, 0x65, 0x09, 0x73, 0x01, 0x2C, 0x4A, ++ 0x9A, 0x18, 0x11, 0x68, 0x2B, 0x4A, 0x11, 0x60, 0x2B, 0x4A, 0x94, 0x46, ++ 0x63, 0x44, 0x1A, 0x68, 0x2A, 0x4B, 0x1A, 0x60, 0x2A, 0x4B, 0x5A, 0x46, ++ 0x1A, 0x60, 0x51, 0x46, 0x48, 0x46, 0xD3, 0xF7, 0xA3, 0xFC, 0x09, 0x05, ++ 0x43, 0x46, 0x19, 0x43, 0x26, 0x4B, 0x19, 0x60, 0x26, 0x4B, 0x52, 0x46, ++ 0x1A, 0x60, 0x26, 0x4B, 0x00, 0x22, 0x1A, 0x60, 0x25, 0x4B, 0x9E, 0x22, ++ 0xFF, 0x32, 0x99, 0x5C, 0x09, 0x02, 0x01, 0x3A, 0x9A, 0x5C, 0x0A, 0x43, ++ 0x12, 0x04, 0x9C, 0x21, 0xFF, 0x31, 0x58, 0x5C, 0x00, 0x02, 0x01, 0x39, ++ 0x59, 0x5C, 0x01, 0x43, 0x0A, 0x43, 0x1E, 0x49, 0x0A, 0x60, 0xA0, 0x22, ++ 0xFF, 0x32, 0x98, 0x5C, 0x00, 0x02, 0x01, 0x3A, 0x9C, 0x5C, 0x04, 0x43, ++ 0x24, 0x04, 0x20, 0x00, 0x28, 0x43, 0x01, 0x35, 0x6D, 0x01, 0xEC, 0x1B, ++ 0x24, 0x04, 0x04, 0x43, 0x16, 0x4A, 0x14, 0x60, 0x9A, 0x22, 0xFF, 0x32, ++ 0x98, 0x5C, 0x00, 0x02, 0x01, 0x3A, 0x9B, 0x5C, 0x03, 0x43, 0x36, 0x02, ++ 0x1E, 0x43, 0x01, 0x20, 0x06, 0x43, 0x11, 0x4B, 0x1E, 0x60, 0x3C, 0xBC, ++ 0x90, 0x46, 0x99, 0x46, 0xA2, 0x46, 0xAB, 0x46, 0xF8, 0xBD, 0xC0, 0x46, ++ 0x08, 0x04, 0x60, 0x40, 0x28, 0x19, 0x16, 0x00, 0xDC, 0x05, 0x60, 0x40, ++ 0x5C, 0x06, 0x60, 0x40, 0xD8, 0x05, 0x60, 0x40, 0x60, 0x06, 0x60, 0x40, ++ 0x50, 0x06, 0x60, 0x40, 0x54, 0x06, 0x60, 0x40, 0x58, 0x06, 0x60, 0x40, ++ 0x4C, 0x06, 0x60, 0x40, 0x20, 0xA3, 0x16, 0x00, 0x44, 0x06, 0x60, 0x40, ++ 0x48, 0x06, 0x60, 0x40, 0x40, 0x06, 0x60, 0x40, 0xF0, 0xB5, 0xDE, 0x46, ++ 0x57, 0x46, 0x4E, 0x46, 0x45, 0x46, 0xE0, 0xB5, 0x8F, 0xB0, 0x80, 0x46, ++ 0x0E, 0x00, 0x15, 0x00, 0x03, 0x93, 0xEF, 0xF3, 0x10, 0x83, 0x01, 0x22, ++ 0x17, 0x00, 0x1F, 0x40, 0x1A, 0x42, 0x00, 0xD0, 0xF6, 0xE2, 0x72, 0xB6, ++ 0x00, 0x21, 0x5C, 0x20, 0x7D, 0xF7, 0xCE, 0xF9, 0x04, 0x1E, 0x00, 0xD1, ++ 0x25, 0xE3, 0x00, 0x20, 0x00, 0x2F, 0x00, 0xD0, 0xF1, 0xE2, 0x62, 0xB6, ++ 0x00, 0x28, 0x00, 0xD1, 0xED, 0xE2, 0x0F, 0xB0, 0x3C, 0xBC, 0x90, 0x46, ++ 0x99, 0x46, 0xA2, 0x46, 0xAB, 0x46, 0xF0, 0xBD, 0xDE, 0x4B, 0x9B, 0x6E, ++ 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x0C, 0x20, 0x00, 0x2F, ++ 0xEF, 0xD1, 0xEA, 0xE7, 0x00, 0x23, 0x06, 0x93, 0xEC, 0xE2, 0x01, 0x23, ++ 0x06, 0x93, 0xE9, 0xE2, 0x00, 0x23, 0x5B, 0x00, 0xD6, 0x4A, 0xD3, 0x18, ++ 0x5F, 0x78, 0xBA, 0x46, 0xBF, 0xE0, 0x2F, 0x7B, 0xD4, 0x4B, 0x19, 0x00, ++ 0x00, 0x22, 0x08, 0x78, 0xB8, 0x42, 0x00, 0xD1, 0xAD, 0xE0, 0x01, 0x32, ++ 0x02, 0x31, 0x08, 0x2A, 0xF7, 0xD1, 0x02, 0x27, 0x68, 0x7B, 0x00, 0x22, ++ 0x19, 0x78, 0x81, 0x42, 0x00, 0xD1, 0xA7, 0xE0, 0x01, 0x32, 0x02, 0x33, ++ 0x08, 0x2A, 0xF7, 0xD1, 0x02, 0x23, 0x9A, 0x46, 0x09, 0x2F, 0x05, 0xD9, ++ 0xC5, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, ++ 0x07, 0x97, 0xD3, 0x46, 0xC4, 0x4A, 0x7B, 0x00, 0xDF, 0x19, 0xD7, 0x19, ++ 0x53, 0x46, 0x5B, 0x00, 0x53, 0x44, 0xD2, 0x18, 0xBF, 0x78, 0x93, 0x78, ++ 0xFF, 0x18, 0xFB, 0xB2, 0x1F, 0x00, 0x05, 0x93, 0x28, 0x7C, 0x19, 0x00, ++ 0xD3, 0xF7, 0x48, 0xFB, 0xC0, 0xB2, 0xBC, 0x4B, 0x63, 0x62, 0xBC, 0x4B, ++ 0xE3, 0x61, 0xBC, 0x4B, 0x23, 0x62, 0x03, 0x23, 0x23, 0x76, 0xBB, 0x4B, ++ 0x9B, 0x7A, 0xA3, 0x75, 0xBA, 0x4A, 0x9F, 0x23, 0x9B, 0x00, 0xD2, 0x5C, ++ 0x00, 0x23, 0x00, 0x2A, 0x02, 0xD1, 0x7B, 0x00, 0x03, 0x33, 0xDB, 0xB2, ++ 0xE3, 0x75, 0x00, 0x23, 0xA3, 0x82, 0x06, 0x33, 0x63, 0x76, 0x40, 0x33, ++ 0x42, 0x46, 0xE2, 0x54, 0x01, 0x33, 0xE6, 0x54, 0xEB, 0x88, 0x23, 0x87, ++ 0x2B, 0x89, 0x63, 0x87, 0xAA, 0x7A, 0x3D, 0x23, 0xE2, 0x54, 0xEA, 0x7A, ++ 0x01, 0x33, 0xE2, 0x54, 0x2A, 0x7B, 0x01, 0x33, 0xE2, 0x54, 0x6A, 0x7B, ++ 0x01, 0x33, 0xE2, 0x54, 0xAA, 0x7B, 0x01, 0x33, 0xE2, 0x54, 0xEA, 0x7B, ++ 0x01, 0x33, 0xE2, 0x54, 0x6A, 0x7C, 0x01, 0x33, 0xE2, 0x54, 0x01, 0x33, ++ 0xE0, 0x54, 0x9B, 0x4A, 0xB0, 0x33, 0xD3, 0x58, 0x23, 0x63, 0xAA, 0x78, ++ 0x4B, 0x23, 0xE2, 0x54, 0x2B, 0x7C, 0x05, 0x99, 0x8C, 0x46, 0x63, 0x44, ++ 0xEA, 0x7B, 0x9B, 0x1A, 0x5A, 0x42, 0x53, 0x41, 0x49, 0x22, 0xA3, 0x54, ++ 0x45, 0x23, 0xE1, 0x54, 0x13, 0x33, 0x08, 0x9A, 0xE2, 0x54, 0x01, 0x22, ++ 0x31, 0x00, 0x01, 0x20, 0xA6, 0xF7, 0xF8, 0xF9, 0x03, 0x9B, 0x00, 0x2B, ++ 0x00, 0xD0, 0x98, 0xE1, 0x06, 0x99, 0x01, 0x31, 0x2A, 0x89, 0x4A, 0x43, ++ 0xD3, 0xB2, 0x0C, 0x93, 0xEB, 0x88, 0x4B, 0x43, 0xDB, 0xB2, 0x0D, 0x93, ++ 0x2B, 0x79, 0x00, 0x22, 0x92, 0x46, 0x00, 0x2B, 0x02, 0xD0, 0xEA, 0x78, ++ 0x04, 0x2A, 0x26, 0xD0, 0x68, 0x78, 0x03, 0x28, 0x33, 0xD8, 0x2B, 0x78, ++ 0x04, 0x2B, 0x30, 0xD8, 0x9B, 0x00, 0x88, 0x4A, 0xD3, 0x18, 0x1A, 0x5C, ++ 0x0F, 0x23, 0x13, 0x40, 0x0A, 0x93, 0x53, 0x11, 0x01, 0x21, 0x0B, 0x40, ++ 0x03, 0x93, 0x12, 0x11, 0x11, 0x40, 0x0B, 0x91, 0x2C, 0xE0, 0x52, 0x00, ++ 0x79, 0x49, 0x8A, 0x18, 0x57, 0x78, 0x51, 0xE7, 0x52, 0x00, 0x77, 0x4B, ++ 0x9A, 0x18, 0x53, 0x78, 0x9A, 0x46, 0x09, 0x2F, 0x00, 0xD9, 0x57, 0xE7, ++ 0x53, 0x46, 0x09, 0x2B, 0x00, 0xD9, 0x53, 0xE7, 0x58, 0xE7, 0x01, 0x2B, ++ 0x0A, 0xD0, 0x02, 0x3B, 0x5A, 0x42, 0x53, 0x41, 0x5B, 0x42, 0x76, 0x4A, ++ 0x13, 0x40, 0x9A, 0x46, 0x75, 0x4B, 0x9C, 0x46, 0xE2, 0x44, 0xCB, 0xE7, ++ 0x74, 0x4B, 0x9A, 0x46, 0xC8, 0xE7, 0x29, 0x78, 0x66, 0x4B, 0xDB, 0x6E, ++ 0x98, 0x46, 0x00, 0x23, 0x00, 0x22, 0xC0, 0x47, 0x03, 0x9B, 0x0B, 0x93, ++ 0x00, 0x23, 0x0A, 0x93, 0x2B, 0x79, 0x0E, 0x2B, 0x00, 0xD1, 0xBC, 0xE0, ++ 0x00, 0xD9, 0xAC, 0xE0, 0x00, 0x22, 0x06, 0x92, 0x08, 0x2B, 0x04, 0xD0, ++ 0x01, 0x32, 0x06, 0x92, 0x0D, 0x2B, 0x00, 0xD0, 0xA8, 0xE0, 0xEB, 0x78, ++ 0x5A, 0x1E, 0x03, 0x2A, 0x00, 0xD9, 0xE3, 0xE0, 0xD3, 0xB2, 0x08, 0x93, ++ 0x63, 0x4A, 0x13, 0x68, 0x63, 0x49, 0x19, 0x40, 0x80, 0x23, 0x9B, 0x02, ++ 0x0B, 0x43, 0x13, 0x60, 0x13, 0x68, 0x61, 0x49, 0x0B, 0x40, 0x80, 0x21, ++ 0x49, 0x02, 0x8C, 0x46, 0x0B, 0x43, 0x13, 0x60, 0x73, 0x01, 0x98, 0x46, ++ 0x5D, 0x4A, 0x42, 0x44, 0x85, 0x23, 0x1B, 0x04, 0x51, 0x46, 0x0B, 0x43, ++ 0x13, 0x60, 0x5B, 0x4B, 0x43, 0x44, 0x9A, 0x46, 0x4B, 0x4A, 0x5B, 0x46, ++ 0x59, 0x00, 0x59, 0x44, 0x53, 0x18, 0x5B, 0x78, 0x1B, 0x01, 0xA8, 0x7A, ++ 0x03, 0x43, 0xE8, 0x7A, 0x02, 0x38, 0x07, 0x00, 0x78, 0x42, 0x78, 0x41, ++ 0xC0, 0x00, 0x03, 0x43, 0x07, 0x9F, 0x78, 0x00, 0xBB, 0x46, 0x58, 0x44, ++ 0x17, 0x18, 0x7F, 0x78, 0x7F, 0x01, 0x3B, 0x43, 0x67, 0x46, 0x3B, 0x43, ++ 0x57, 0x46, 0x3B, 0x60, 0x4C, 0x4B, 0x43, 0x44, 0x9A, 0x46, 0x2B, 0x89, ++ 0x1B, 0x05, 0x9C, 0x46, 0xEB, 0x88, 0x1B, 0x01, 0x67, 0x46, 0x3B, 0x43, ++ 0x80, 0x5C, 0x03, 0x43, 0x88, 0x5C, 0x00, 0x04, 0x03, 0x43, 0x52, 0x46, ++ 0x13, 0x60, 0x03, 0x9B, 0xDB, 0x03, 0x0A, 0x9A, 0x12, 0x02, 0x13, 0x43, ++ 0x0B, 0x9A, 0xD2, 0x01, 0x13, 0x43, 0x06, 0x9A, 0x12, 0x05, 0x13, 0x43, ++ 0x08, 0x9A, 0x12, 0x04, 0x13, 0x43, 0x3E, 0x4A, 0xB2, 0x18, 0x92, 0x00, ++ 0x13, 0x60, 0xB3, 0x00, 0x3C, 0x4A, 0x9C, 0x50, 0x4B, 0x23, 0xE3, 0x5C, ++ 0x00, 0x2B, 0x00, 0xD1, 0x87, 0xE0, 0x32, 0x01, 0xB2, 0x18, 0xD3, 0x01, ++ 0x9B, 0x1A, 0xF3, 0x18, 0x37, 0x4A, 0x94, 0x46, 0x63, 0x44, 0x9B, 0xB2, ++ 0x36, 0x49, 0x41, 0x44, 0x0C, 0x98, 0xC2, 0x18, 0x12, 0x04, 0x13, 0x43, ++ 0x0B, 0x60, 0x87, 0x23, 0xDB, 0x00, 0x73, 0x43, 0x84, 0x46, 0x63, 0x44, ++ 0x31, 0x4A, 0x94, 0x46, 0x63, 0x44, 0x5B, 0x00, 0x9B, 0xB2, 0x30, 0x49, ++ 0x41, 0x44, 0x0D, 0x9A, 0x9A, 0x18, 0x92, 0xB2, 0x1B, 0x04, 0x13, 0x43, ++ 0x0B, 0x60, 0x2D, 0x4B, 0x43, 0x44, 0xE9, 0x7B, 0x80, 0x22, 0xD2, 0x01, ++ 0x0A, 0x43, 0x1A, 0x60, 0x29, 0x89, 0x00, 0x29, 0x04, 0xD1, 0xEB, 0x88, ++ 0x01, 0x31, 0x00, 0x2B, 0x00, 0xD0, 0x19, 0x00, 0x00, 0x2E, 0x00, 0xD0, ++ 0xDA, 0xE0, 0xEA, 0x7B, 0x89, 0xB2, 0x00, 0x20, 0xFF, 0xF7, 0x72, 0xFD, ++ 0xD4, 0xE0, 0x03, 0x22, 0x06, 0x92, 0x10, 0x2B, 0x00, 0xD1, 0x56, 0xE7, ++ 0x05, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, ++ 0x00, 0x23, 0x06, 0x93, 0x4D, 0xE7, 0x02, 0x23, 0x06, 0x93, 0x4A, 0xE7, ++ 0x28, 0x19, 0x16, 0x00, 0xE4, 0xDF, 0x10, 0x00, 0xD4, 0xDF, 0x10, 0x00, ++ 0xE8, 0xDF, 0x10, 0x00, 0x69, 0xF5, 0x0A, 0x00, 0x21, 0x61, 0x10, 0x00, ++ 0x4D, 0xF3, 0x0A, 0x00, 0x7C, 0x91, 0x0D, 0x00, 0x7C, 0x1E, 0x16, 0x00, ++ 0x08, 0xE0, 0x10, 0x00, 0x00, 0xA0, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, ++ 0xFF, 0x0F, 0x00, 0x00, 0xD0, 0x04, 0x60, 0x40, 0xFF, 0xFF, 0xFD, 0xFF, ++ 0xFF, 0xFF, 0xFE, 0xFF, 0xD4, 0x05, 0x60, 0x40, 0xE0, 0x05, 0x60, 0x40, ++ 0xE4, 0x05, 0x60, 0x40, 0x8C, 0x01, 0x18, 0x10, 0x54, 0x27, 0x16, 0x00, ++ 0x5C, 0xAB, 0xFF, 0xFF, 0xD8, 0x05, 0x60, 0x40, 0xAE, 0x55, 0x00, 0x00, ++ 0xDC, 0x05, 0x60, 0x40, 0xD0, 0x05, 0x60, 0x40, 0x96, 0x4B, 0x9B, 0x6E, ++ 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x00, 0x23, 0x08, 0x93, ++ 0x14, 0xE7, 0x42, 0x33, 0xE3, 0x5C, 0x5F, 0x1E, 0x20, 0x00, 0x50, 0x30, ++ 0x7F, 0xF7, 0xF0, 0xFA, 0x49, 0x23, 0xE1, 0x5C, 0xCB, 0x1C, 0xDB, 0xB2, ++ 0x04, 0x31, 0xC9, 0xB2, 0x8B, 0x4A, 0x92, 0x46, 0x0D, 0x9A, 0x04, 0x32, ++ 0xD2, 0xB2, 0x00, 0x92, 0x84, 0x22, 0x50, 0x46, 0x82, 0x58, 0x93, 0x46, ++ 0x0C, 0x9A, 0x30, 0x00, 0xD8, 0x47, 0x86, 0x4A, 0x42, 0x44, 0x00, 0x23, ++ 0x13, 0x60, 0x85, 0x4A, 0x42, 0x44, 0x13, 0x60, 0x19, 0x33, 0xFF, 0x33, ++ 0x52, 0x46, 0xD0, 0x58, 0x31, 0x00, 0xD2, 0xF7, 0x47, 0xFB, 0x81, 0x4A, ++ 0x11, 0x68, 0x80, 0x23, 0x9B, 0x01, 0xB3, 0x40, 0x0B, 0x43, 0x13, 0x60, ++ 0x7E, 0x4A, 0x42, 0x44, 0xFF, 0x23, 0x3B, 0x40, 0x1F, 0x2B, 0x00, 0xD9, ++ 0x1F, 0x23, 0x1B, 0x02, 0xE9, 0x7B, 0x0B, 0x43, 0x09, 0x99, 0x03, 0x39, ++ 0x48, 0x42, 0x41, 0x41, 0xC9, 0x03, 0x0B, 0x43, 0xC0, 0x21, 0xC9, 0x01, ++ 0x0B, 0x43, 0x13, 0x60, 0x42, 0xE0, 0x75, 0x4B, 0xF2, 0x18, 0x52, 0x01, ++ 0x74, 0x49, 0x5B, 0x46, 0x58, 0x00, 0x58, 0x44, 0x0B, 0x18, 0x5B, 0x78, ++ 0x1B, 0x01, 0xAF, 0x7A, 0x1F, 0x43, 0xBC, 0x46, 0xEB, 0x7A, 0x02, 0x3B, ++ 0x1F, 0x00, 0x7B, 0x42, 0x7B, 0x41, 0xDB, 0x00, 0x67, 0x46, 0x3B, 0x43, ++ 0x9A, 0x46, 0x07, 0x9F, 0x7B, 0x00, 0x98, 0x46, 0xBC, 0x46, 0xE0, 0x44, ++ 0x8C, 0x46, 0xC4, 0x44, 0x63, 0x46, 0x5B, 0x78, 0x5B, 0x01, 0x1F, 0x00, ++ 0x53, 0x46, 0x1F, 0x43, 0x80, 0x23, 0x5B, 0x02, 0x3B, 0x43, 0x13, 0x60, ++ 0x2B, 0x89, 0x1B, 0x05, 0xED, 0x88, 0x2D, 0x01, 0x2B, 0x43, 0x45, 0x46, ++ 0x6D, 0x5C, 0x2B, 0x43, 0x41, 0x5C, 0x09, 0x04, 0x0B, 0x43, 0x53, 0x60, ++ 0x31, 0x01, 0x71, 0x18, 0xCB, 0x01, 0x5B, 0x1A, 0xF3, 0x18, 0x5B, 0x49, ++ 0x8C, 0x46, 0x63, 0x44, 0x98, 0xB2, 0x11, 0x00, 0x08, 0x39, 0x1B, 0x04, ++ 0x03, 0x43, 0x0B, 0x60, 0x04, 0x3A, 0x13, 0x60, 0xEF, 0xF3, 0x10, 0x83, ++ 0x01, 0x22, 0x11, 0x00, 0x19, 0x40, 0x88, 0x46, 0x1A, 0x42, 0x00, 0xD1, ++ 0x72, 0xB6, 0x52, 0x4B, 0x05, 0x9A, 0x53, 0x43, 0x9B, 0xB2, 0x42, 0x22, ++ 0xA2, 0x5C, 0x52, 0x00, 0x44, 0x21, 0x61, 0x5C, 0x48, 0x1E, 0x81, 0x41, ++ 0x00, 0x91, 0x31, 0x00, 0x0B, 0x20, 0xD3, 0xF7, 0x41, 0xF8, 0x4B, 0x46, ++ 0xDB, 0x07, 0x33, 0xD4, 0x4B, 0x46, 0x1F, 0x01, 0x3F, 0x09, 0x41, 0x23, ++ 0xE5, 0x5C, 0x02, 0x33, 0xE3, 0x5C, 0x9B, 0x06, 0x7F, 0x08, 0x5F, 0x40, ++ 0x42, 0x23, 0xE3, 0x5C, 0x99, 0x46, 0x00, 0x2B, 0x05, 0xD1, 0x39, 0x4B, ++ 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x49, 0x46, ++ 0x38, 0x00, 0xD3, 0xF7, 0x63, 0xF9, 0x69, 0x1A, 0x00, 0x29, 0x21, 0xDD, ++ 0x42, 0x23, 0xE3, 0x5C, 0xC9, 0x1A, 0x49, 0x00, 0x58, 0x00, 0x04, 0x9A, ++ 0x94, 0x46, 0x60, 0x44, 0x09, 0x18, 0x09, 0x01, 0x09, 0x09, 0x61, 0x63, ++ 0x02, 0x2B, 0x02, 0xD9, 0x30, 0x00, 0x34, 0x4B, 0x98, 0x47, 0x00, 0x20, ++ 0x43, 0x46, 0x00, 0x2B, 0x00, 0xD0, 0x28, 0xE5, 0x62, 0xB6, 0x26, 0xE5, ++ 0x30, 0x4F, 0x4B, 0x46, 0x3B, 0x40, 0x1F, 0x00, 0x04, 0x98, 0x01, 0x38, ++ 0x00, 0x01, 0x03, 0x09, 0x04, 0x93, 0xC4, 0xE7, 0x42, 0x23, 0xE3, 0x5C, ++ 0xC9, 0x18, 0xD9, 0xE7, 0x00, 0x21, 0x5C, 0x20, 0x7C, 0xF7, 0xD8, 0xFE, ++ 0x04, 0x1E, 0x00, 0xD1, 0x18, 0xE5, 0x43, 0x46, 0x9B, 0x00, 0x26, 0x4A, ++ 0x9F, 0x58, 0x6B, 0x78, 0x09, 0x93, 0x03, 0x2B, 0x00, 0xD1, 0x19, 0xE5, ++ 0xAB, 0x78, 0x01, 0x2B, 0x00, 0xD1, 0x18, 0xE5, 0x2A, 0x79, 0x08, 0x23, ++ 0x93, 0x42, 0x9B, 0x41, 0x5B, 0x42, 0x06, 0x93, 0x06, 0x9B, 0x08, 0x93, ++ 0xA6, 0xF7, 0x1C, 0xFA, 0x04, 0x90, 0xBB, 0x6F, 0x81, 0x46, 0x99, 0x44, ++ 0x5C, 0x22, 0x00, 0x21, 0x20, 0x00, 0x7A, 0xF7, 0x67, 0xFE, 0xEB, 0x7A, ++ 0x00, 0x2B, 0x00, 0xD0, 0x0B, 0xE5, 0x2B, 0x7B, 0x00, 0x2B, 0x00, 0xD1, ++ 0x00, 0xE5, 0x02, 0x22, 0x92, 0x46, 0x02, 0x27, 0x02, 0x2B, 0x00, 0xD0, ++ 0x22, 0xE5, 0x01, 0x3B, 0xF9, 0xE4, 0x04, 0x4B, 0x9B, 0x6E, 0x00, 0x22, ++ 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x0C, 0x20, 0xD5, 0xE4, 0xC0, 0x46, ++ 0x28, 0x19, 0x16, 0x00, 0xD8, 0x05, 0x60, 0x40, 0xDC, 0x05, 0x60, 0x40, ++ 0x0C, 0x04, 0x60, 0x40, 0xD0, 0x05, 0x60, 0x40, 0x2F, 0x00, 0x03, 0x02, ++ 0xE8, 0xDF, 0x10, 0x00, 0x5C, 0xAB, 0xFF, 0xFF, 0xE2, 0x04, 0x00, 0x00, ++ 0x3D, 0xF4, 0x0A, 0x00, 0xFE, 0xFF, 0xFF, 0x0F, 0x38, 0x27, 0x16, 0x00, ++ 0x00, 0x20, 0x70, 0x47, 0x10, 0xB5, 0xEF, 0xF3, 0x10, 0x83, 0x01, 0x22, ++ 0x14, 0x00, 0x1C, 0x40, 0x1A, 0x42, 0x00, 0xD1, 0x72, 0xB6, 0x5A, 0x4B, ++ 0x1B, 0x68, 0xDB, 0x05, 0x0B, 0xD5, 0x58, 0x49, 0x0B, 0x68, 0x5B, 0x00, ++ 0x5B, 0x08, 0x80, 0x22, 0x12, 0x06, 0x13, 0x43, 0x0B, 0x60, 0x0A, 0x00, ++ 0x13, 0x68, 0x00, 0x2B, 0xFC, 0xDB, 0x53, 0x4B, 0x1B, 0x68, 0xDB, 0x05, ++ 0x0B, 0xD5, 0x51, 0x49, 0x0B, 0x68, 0x5B, 0x00, 0x5B, 0x08, 0x80, 0x22, ++ 0x12, 0x06, 0x13, 0x43, 0x0B, 0x60, 0x0A, 0x00, 0x13, 0x68, 0x00, 0x2B, ++ 0xFC, 0xDB, 0x7A, 0xF7, 0x4F, 0xFF, 0x4B, 0x4B, 0x18, 0x68, 0x00, 0x28, ++ 0x09, 0xD0, 0x7C, 0xF7, 0xF5, 0xFE, 0x48, 0x4B, 0x00, 0x22, 0x1A, 0x60, ++ 0x47, 0x4A, 0x13, 0x68, 0x04, 0x21, 0x8B, 0x43, 0x13, 0x60, 0x46, 0x4B, ++ 0x11, 0x22, 0x44, 0x21, 0x5A, 0x54, 0x40, 0x31, 0x5A, 0x54, 0x40, 0x31, ++ 0x5A, 0x54, 0x40, 0x31, 0x5A, 0x54, 0x40, 0x31, 0x5A, 0x54, 0x10, 0x3A, ++ 0x40, 0x49, 0x5A, 0x54, 0x40, 0x49, 0x5A, 0x54, 0x40, 0x4A, 0x00, 0x21, ++ 0x99, 0x54, 0x40, 0x4B, 0x1B, 0x68, 0x01, 0x2B, 0x47, 0xD9, 0x39, 0x4B, ++ 0x1A, 0x68, 0x08, 0x21, 0x8A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x01, 0x20, ++ 0x82, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x06, 0x39, 0x8A, 0x43, 0x1A, 0x60, ++ 0x1A, 0x68, 0x38, 0x49, 0x0A, 0x40, 0x1A, 0x60, 0x1A, 0x68, 0x12, 0x04, ++ 0x12, 0x0C, 0xB0, 0x21, 0x49, 0x03, 0x0A, 0x43, 0x1A, 0x60, 0x34, 0x4A, ++ 0xA0, 0x23, 0x9B, 0x00, 0xD0, 0x54, 0x29, 0x4A, 0x13, 0x68, 0x0F, 0x21, ++ 0x0B, 0x43, 0x13, 0x60, 0x30, 0x4A, 0x13, 0x68, 0x30, 0x49, 0x19, 0x40, ++ 0xA0, 0x23, 0xDB, 0x03, 0x0B, 0x43, 0x13, 0x60, 0x13, 0x68, 0xFF, 0x21, ++ 0x8B, 0x43, 0xAF, 0x39, 0x0B, 0x43, 0x13, 0x60, 0x2B, 0x4B, 0x2C, 0x4A, ++ 0x9A, 0x60, 0x2C, 0x4A, 0xDA, 0x60, 0x2C, 0x4A, 0x5A, 0x61, 0x2C, 0x4A, ++ 0x9A, 0x61, 0x00, 0x2C, 0x00, 0xD1, 0x62, 0xB6, 0x00, 0x23, 0x2A, 0x4A, ++ 0x13, 0x60, 0x2A, 0x4A, 0x13, 0x60, 0x2A, 0x4A, 0x13, 0x60, 0x0A, 0x22, ++ 0x29, 0x49, 0x2A, 0x48, 0xD3, 0xF7, 0x10, 0xFC, 0x10, 0xBD, 0x15, 0x4B, ++ 0x1A, 0x68, 0x08, 0x31, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x07, 0x39, ++ 0x8A, 0x43, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x02, 0x20, 0x02, 0x43, ++ 0x1A, 0x60, 0x1A, 0x68, 0x13, 0x48, 0x10, 0x40, 0x80, 0x22, 0x92, 0x01, ++ 0x02, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x12, 0x04, 0x12, 0x0C, 0xB0, 0x20, ++ 0x40, 0x03, 0x02, 0x43, 0x1A, 0x60, 0x0E, 0x4A, 0xA0, 0x23, 0x9B, 0x00, ++ 0xD1, 0x54, 0x19, 0x4B, 0x19, 0x4A, 0x1A, 0x60, 0xAF, 0xE7, 0xC0, 0x46, ++ 0x00, 0x04, 0x60, 0x40, 0x00, 0x08, 0x60, 0x40, 0xF8, 0xE6, 0x10, 0x00, ++ 0xFC, 0x00, 0x60, 0x40, 0xEC, 0xA4, 0x16, 0x00, 0x1E, 0x03, 0x00, 0x00, ++ 0x6F, 0x04, 0x00, 0x00, 0x6D, 0x04, 0x00, 0x00, 0x50, 0xE0, 0x10, 0x00, ++ 0xFF, 0xDF, 0xFF, 0xFF, 0x7C, 0x1E, 0x16, 0x00, 0x8C, 0x04, 0x60, 0x40, ++ 0xFF, 0xFF, 0x00, 0xFF, 0x60, 0x92, 0x16, 0x00, 0x2D, 0x01, 0x10, 0x00, ++ 0x81, 0x01, 0x10, 0x00, 0x8D, 0x05, 0x10, 0x00, 0xB9, 0x00, 0x10, 0x00, ++ 0x58, 0xE6, 0x10, 0x00, 0x5C, 0xE6, 0x10, 0x00, 0x54, 0xE6, 0x10, 0x00, ++ 0xD8, 0xE1, 0x10, 0x00, 0xC0, 0x9F, 0x16, 0x00, 0x30, 0x10, 0x62, 0x40, ++ 0x15, 0x1C, 0x20, 0x00, 0xF8, 0xB5, 0xDE, 0x46, 0x57, 0x46, 0x4E, 0x46, ++ 0x45, 0x46, 0xE0, 0xB5, 0x70, 0x4B, 0x1B, 0x68, 0x1B, 0x07, 0x0B, 0xD5, ++ 0x6F, 0x4A, 0x13, 0x68, 0x00, 0x2B, 0xFC, 0xD0, 0x6C, 0x4A, 0x13, 0x68, ++ 0x08, 0x21, 0x8B, 0x43, 0x13, 0x60, 0x6B, 0x4B, 0x01, 0x22, 0x1A, 0x60, ++ 0x6A, 0x4C, 0x23, 0x68, 0x6A, 0x4E, 0x33, 0x40, 0x23, 0x60, 0x6A, 0x4D, ++ 0x2B, 0x68, 0x6A, 0x4F, 0x3B, 0x40, 0x2B, 0x60, 0x83, 0xF7, 0xEE, 0xFA, ++ 0x23, 0x68, 0x68, 0x4A, 0x13, 0x40, 0x23, 0x60, 0x2B, 0x68, 0x33, 0x40, ++ 0x2B, 0x60, 0x23, 0x68, 0x1F, 0x40, 0x80, 0x23, 0x5B, 0x00, 0x3B, 0x43, ++ 0x23, 0x60, 0x23, 0x68, 0x1E, 0x40, 0x80, 0x23, 0x9B, 0x00, 0x33, 0x43, ++ 0x23, 0x60, 0x60, 0x4B, 0x99, 0x46, 0xFF, 0x23, 0x9B, 0x46, 0x22, 0x00, ++ 0xC0, 0x3B, 0x98, 0x46, 0x5D, 0x4B, 0x9C, 0x46, 0x40, 0x25, 0x80, 0x21, ++ 0x09, 0x01, 0x5F, 0x46, 0x5E, 0x46, 0x04, 0x36, 0xF3, 0xB2, 0x9B, 0x46, ++ 0x4C, 0x46, 0x18, 0x00, 0x13, 0x68, 0x46, 0x46, 0xB3, 0x43, 0x03, 0x43, ++ 0x13, 0x60, 0x63, 0x46, 0x26, 0x68, 0x1E, 0x60, 0x13, 0x68, 0xAB, 0x43, ++ 0x2B, 0x43, 0x13, 0x60, 0xC0, 0x46, 0xC0, 0x46, 0xC0, 0x46, 0xC0, 0x46, ++ 0x13, 0x68, 0x0B, 0x42, 0xFC, 0xD0, 0x01, 0x38, 0xC0, 0xB2, 0x04, 0x34, ++ 0xB8, 0x42, 0xE7, 0xD1, 0x10, 0x23, 0x9A, 0x46, 0xD1, 0x44, 0x5B, 0x46, ++ 0x0F, 0x2B, 0xDA, 0xD1, 0x42, 0x4C, 0x23, 0x68, 0x44, 0x4D, 0x2B, 0x40, ++ 0x23, 0x60, 0x83, 0xF7, 0xAA, 0xFA, 0x23, 0x68, 0x3F, 0x4A, 0x13, 0x40, ++ 0x23, 0x60, 0x3F, 0x4B, 0x1A, 0x68, 0x80, 0x21, 0x0A, 0x43, 0x1A, 0x60, ++ 0x1A, 0x68, 0x15, 0x40, 0x80, 0x22, 0x52, 0x00, 0x2A, 0x43, 0x1A, 0x60, ++ 0x3E, 0x4B, 0x9A, 0x46, 0xFF, 0x24, 0x38, 0x4A, 0x1F, 0x23, 0x99, 0x46, ++ 0x3C, 0x4B, 0x98, 0x46, 0x20, 0x26, 0x80, 0x21, 0xC9, 0x00, 0x04, 0xE0, ++ 0x08, 0x23, 0x9C, 0x46, 0xE2, 0x44, 0x1F, 0x2C, 0x1D, 0xD0, 0xA4, 0x46, ++ 0x02, 0x34, 0xE4, 0xB2, 0x55, 0x46, 0x20, 0x00, 0x13, 0x68, 0x4F, 0x46, ++ 0xBB, 0x43, 0x03, 0x43, 0x13, 0x60, 0x43, 0x46, 0x2F, 0x68, 0x1F, 0x60, ++ 0x13, 0x68, 0xB3, 0x43, 0x33, 0x43, 0x13, 0x60, 0xC0, 0x46, 0xC0, 0x46, ++ 0xC0, 0x46, 0xC0, 0x46, 0x13, 0x68, 0x0B, 0x42, 0xFC, 0xD0, 0x01, 0x38, ++ 0xC0, 0xB2, 0x04, 0x35, 0x60, 0x45, 0xE7, 0xD1, 0xDC, 0xE7, 0x22, 0x4C, ++ 0x23, 0x68, 0x80, 0x22, 0x93, 0x43, 0x23, 0x60, 0x83, 0xF7, 0x65, 0xFA, ++ 0x23, 0x68, 0x1F, 0x4D, 0x2B, 0x40, 0x23, 0x60, 0x23, 0x49, 0x0B, 0x68, ++ 0x23, 0x4A, 0x1A, 0x40, 0x80, 0x23, 0x5B, 0x02, 0x13, 0x43, 0x0B, 0x60, ++ 0x83, 0xF7, 0x50, 0xFA, 0x15, 0x49, 0x0B, 0x68, 0x18, 0x4A, 0x1A, 0x40, ++ 0x80, 0x23, 0xDB, 0x00, 0x13, 0x43, 0x0B, 0x60, 0x0B, 0x68, 0x12, 0x48, ++ 0x03, 0x40, 0x80, 0x22, 0x92, 0x00, 0x13, 0x43, 0x0B, 0x60, 0x23, 0x68, ++ 0x03, 0x40, 0x1A, 0x43, 0x22, 0x60, 0x23, 0x68, 0x1D, 0x40, 0x80, 0x23, ++ 0x5B, 0x00, 0x2B, 0x43, 0x23, 0x60, 0x14, 0x49, 0x0B, 0x68, 0x14, 0x4A, ++ 0x1A, 0x40, 0x80, 0x23, 0x5B, 0x03, 0x13, 0x43, 0x0B, 0x60, 0x3C, 0xBC, ++ 0x90, 0x46, 0x99, 0x46, 0xA2, 0x46, 0xAB, 0x46, 0xF8, 0xBD, 0xC0, 0x46, ++ 0x18, 0x00, 0x58, 0x40, 0x40, 0x42, 0x04, 0x40, 0x58, 0x20, 0x62, 0x40, ++ 0xFF, 0xFD, 0xFF, 0xFF, 0x64, 0x20, 0x62, 0x40, 0xFF, 0xFE, 0xFF, 0xFF, ++ 0xFF, 0xFB, 0xFF, 0xFF, 0xD8, 0x97, 0x16, 0x00, 0x5C, 0x20, 0x62, 0x40, ++ 0xD8, 0x98, 0x16, 0x00, 0x68, 0x20, 0x62, 0x40, 0x4C, 0x20, 0x62, 0x40, ++ 0xFF, 0xFF, 0xFE, 0xFF, 0x30, 0x20, 0x62, 0x40, 0xFF, 0xFF, 0xEF, 0xFF, ++ 0xF8, 0xB5, 0xDE, 0x46, 0x57, 0x46, 0x4E, 0x46, 0x45, 0x46, 0xE0, 0xB5, ++ 0x6E, 0x4C, 0x23, 0x68, 0x6E, 0x4E, 0x33, 0x40, 0x23, 0x60, 0x6E, 0x4D, ++ 0x2B, 0x68, 0x6E, 0x4A, 0x13, 0x40, 0x2B, 0x60, 0x83, 0xF7, 0xF8, 0xF9, ++ 0x23, 0x68, 0x6C, 0x4A, 0x13, 0x40, 0x23, 0x60, 0x2B, 0x68, 0x6B, 0x4A, ++ 0x13, 0x40, 0x2B, 0x60, 0x23, 0x68, 0x6A, 0x4A, 0x1A, 0x40, 0x80, 0x23, ++ 0xDB, 0x00, 0x13, 0x43, 0x23, 0x60, 0x23, 0x68, 0x1E, 0x40, 0x80, 0x23, ++ 0x1B, 0x01, 0x33, 0x43, 0x23, 0x60, 0x65, 0x4B, 0x9A, 0x46, 0x7F, 0x25, ++ 0x22, 0x00, 0xFF, 0x23, 0x99, 0x46, 0x63, 0x4B, 0x98, 0x46, 0x5D, 0x4B, ++ 0x9C, 0x46, 0x80, 0x21, 0x89, 0x01, 0x2E, 0x00, 0x04, 0x35, 0xED, 0xB2, ++ 0x54, 0x46, 0x28, 0x00, 0x13, 0x68, 0x4F, 0x46, 0xBB, 0x43, 0x03, 0x43, ++ 0x13, 0x60, 0x43, 0x46, 0x27, 0x68, 0x1F, 0x60, 0x13, 0x68, 0x67, 0x46, ++ 0x3B, 0x40, 0x80, 0x27, 0x7F, 0x00, 0x3B, 0x43, 0x13, 0x60, 0xC0, 0x46, ++ 0xC0, 0x46, 0xC0, 0x46, 0xC0, 0x46, 0x13, 0x68, 0x0B, 0x42, 0xFC, 0xD0, ++ 0x01, 0x38, 0xC0, 0xB2, 0x04, 0x34, 0x86, 0x42, 0xE4, 0xD1, 0x10, 0x23, ++ 0x9B, 0x46, 0xDA, 0x44, 0x8F, 0x2D, 0xDA, 0xD1, 0x45, 0x4C, 0x23, 0x68, ++ 0x4A, 0x4A, 0x13, 0x40, 0x23, 0x60, 0x83, 0xF7, 0xB2, 0xF9, 0x23, 0x68, ++ 0x42, 0x4A, 0x13, 0x40, 0x23, 0x60, 0x42, 0x4B, 0x1A, 0x68, 0x80, 0x21, ++ 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x40, 0x49, 0x11, 0x40, 0x80, 0x22, ++ 0x52, 0x00, 0x0A, 0x43, 0x1A, 0x60, 0x10, 0x20, 0x1A, 0x00, 0x1F, 0x27, ++ 0x41, 0x4E, 0x42, 0x4D, 0x20, 0x24, 0x80, 0x21, 0xC9, 0x00, 0x13, 0x68, ++ 0xBB, 0x43, 0x03, 0x43, 0x13, 0x60, 0x83, 0x00, 0xF3, 0x58, 0x2B, 0x60, ++ 0x13, 0x68, 0xA3, 0x43, 0x23, 0x43, 0x13, 0x60, 0xC0, 0x46, 0xC0, 0x46, ++ 0xC0, 0x46, 0xC0, 0x46, 0x13, 0x68, 0x0B, 0x42, 0xFC, 0xD0, 0x01, 0x30, ++ 0x20, 0x28, 0xEA, 0xD1, 0x2D, 0x4C, 0x23, 0x68, 0x80, 0x22, 0x93, 0x43, ++ 0x23, 0x60, 0x83, 0xF7, 0x7E, 0xF9, 0x23, 0x68, 0x2A, 0x4A, 0x13, 0x40, ++ 0x23, 0x60, 0x31, 0x4A, 0x13, 0x68, 0x00, 0x2B, 0xFC, 0xD0, 0x30, 0x4A, ++ 0x13, 0x68, 0x02, 0x21, 0x8B, 0x43, 0x13, 0x60, 0x2C, 0x4B, 0x01, 0x22, ++ 0x1A, 0x60, 0x2D, 0x4A, 0x13, 0x68, 0x2D, 0x49, 0x0B, 0x40, 0x13, 0x60, ++ 0x2C, 0x4B, 0x00, 0x22, 0x1A, 0x60, 0x83, 0xF7, 0x5D, 0xF9, 0x1B, 0x49, ++ 0x0B, 0x68, 0x1E, 0x4A, 0x13, 0x40, 0x80, 0x22, 0x52, 0x01, 0x13, 0x43, ++ 0x0B, 0x60, 0x0B, 0x68, 0x17, 0x48, 0x18, 0x40, 0x80, 0x23, 0x1B, 0x01, ++ 0x03, 0x43, 0x0B, 0x60, 0x15, 0x4B, 0x19, 0x68, 0x17, 0x48, 0x08, 0x40, ++ 0x80, 0x21, 0x89, 0x00, 0x01, 0x43, 0x19, 0x60, 0x19, 0x68, 0x12, 0x48, ++ 0x08, 0x40, 0x80, 0x21, 0x49, 0x00, 0x01, 0x43, 0x19, 0x60, 0x1C, 0x4B, ++ 0x19, 0x68, 0x0A, 0x43, 0x1A, 0x60, 0x1B, 0x4A, 0x13, 0x68, 0x1B, 0x49, ++ 0x0B, 0x40, 0x13, 0x60, 0x1A, 0x4B, 0x1A, 0x68, 0x1A, 0x49, 0x0A, 0x40, ++ 0x1A, 0x60, 0x19, 0x68, 0x80, 0x22, 0xD2, 0x05, 0x0A, 0x43, 0x1A, 0x60, ++ 0x3C, 0xBC, 0x90, 0x46, 0x99, 0x46, 0xA2, 0x46, 0xAB, 0x46, 0xF8, 0xBD, ++ 0x60, 0x40, 0x34, 0x40, 0xFF, 0xF7, 0xFF, 0xFF, 0x6C, 0x40, 0x34, 0x40, ++ 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, ++ 0xFF, 0xFB, 0xFF, 0xFF, 0xD8, 0x9B, 0x16, 0x00, 0x64, 0x40, 0x34, 0x40, ++ 0x58, 0x99, 0x16, 0x00, 0x70, 0x40, 0x34, 0x40, 0x40, 0x42, 0x04, 0x40, ++ 0x18, 0x00, 0x58, 0x40, 0x58, 0x40, 0x34, 0x40, 0xFF, 0xFF, 0xFF, 0xFB, ++ 0x08, 0x40, 0x34, 0x40, 0x14, 0x20, 0x34, 0x40, 0x18, 0x20, 0x34, 0x40, ++ 0xFF, 0xFF, 0xFB, 0xFF, 0x1C, 0x20, 0x34, 0x40, 0xFF, 0xFF, 0xFF, 0xDF, ++ 0x10, 0xB5, 0x07, 0x49, 0x0A, 0x69, 0x0F, 0x24, 0xA2, 0x43, 0x03, 0x20, ++ 0x02, 0x43, 0x0A, 0x61, 0xCB, 0x69, 0xA3, 0x43, 0x03, 0x43, 0xCB, 0x61, ++ 0x02, 0x48, 0x7E, 0xF7, 0xA1, 0xFB, 0x10, 0xBD, 0x00, 0x30, 0x50, 0x40, ++ 0x94, 0xD1, 0x10, 0x00, 0x70, 0xB5, 0x1B, 0x4B, 0x9B, 0x69, 0xDB, 0x05, ++ 0x1F, 0xD4, 0x0C, 0x38, 0xEF, 0xF3, 0x10, 0x83, 0x01, 0x22, 0x14, 0x00, ++ 0x1C, 0x40, 0x1A, 0x42, 0x00, 0xD1, 0x72, 0xB6, 0x15, 0x4B, 0x1B, 0x7F, ++ 0x01, 0x2B, 0x1C, 0xD0, 0xCF, 0xF7, 0x62, 0xF8, 0x12, 0x4B, 0x1B, 0x7F, ++ 0xFF, 0x2B, 0x1A, 0xD0, 0x02, 0x20, 0x7B, 0xF7, 0xCB, 0xF9, 0xFF, 0xF7, ++ 0xCF, 0xFF, 0x0F, 0x4B, 0x80, 0x22, 0x12, 0x04, 0x1A, 0x60, 0x00, 0x2C, ++ 0x00, 0xD1, 0x62, 0xB6, 0x70, 0xBD, 0x0C, 0x4D, 0xC4, 0x24, 0x64, 0x00, ++ 0x00, 0x23, 0x2B, 0x51, 0xCE, 0xF7, 0xCC, 0xF8, 0x09, 0x4B, 0x2B, 0x51, ++ 0xF4, 0xE7, 0x05, 0x4B, 0xFF, 0x22, 0x1A, 0x77, 0xDE, 0xE7, 0x03, 0x4B, ++ 0x01, 0x22, 0x1A, 0x77, 0xE0, 0xE7, 0xC0, 0x46, 0x3C, 0x95, 0x16, 0x00, ++ 0x24, 0x2A, 0x16, 0x00, 0x00, 0x41, 0x04, 0x40, 0x28, 0x19, 0x16, 0x00, ++ 0xB9, 0x5A, 0x10, 0x00, 0x01, 0x28, 0x02, 0xD0, 0x02, 0x28, 0x05, 0xD0, ++ 0x70, 0x47, 0x05, 0x4B, 0x80, 0x22, 0x92, 0x04, 0x1A, 0x60, 0xF9, 0xE7, ++ 0x02, 0x4B, 0x80, 0x22, 0x52, 0x04, 0x1A, 0x60, 0xF4, 0xE7, 0xC0, 0x46, ++ 0x00, 0x41, 0x04, 0x40, 0x15, 0x4B, 0x16, 0x4A, 0x13, 0x60, 0x16, 0x4A, ++ 0x13, 0x60, 0x16, 0x4B, 0x1A, 0x68, 0x30, 0x21, 0x8A, 0x43, 0x1A, 0x60, ++ 0x1A, 0x68, 0x90, 0x31, 0x8A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x12, 0x49, ++ 0x0A, 0x40, 0x1A, 0x60, 0x1A, 0x68, 0x11, 0x49, 0x0A, 0x40, 0x1A, 0x60, ++ 0x1A, 0x68, 0x10, 0x49, 0x0A, 0x40, 0x1A, 0x60, 0x1A, 0x68, 0x0F, 0x49, ++ 0x0A, 0x40, 0x1A, 0x60, 0x0E, 0x4A, 0xC4, 0x20, 0x80, 0x00, 0x13, 0x58, ++ 0x1B, 0x02, 0x1B, 0x0A, 0xC0, 0x21, 0x09, 0x06, 0x0B, 0x43, 0x13, 0x50, ++ 0x80, 0x23, 0x1B, 0x03, 0x13, 0x60, 0x70, 0x47, 0x00, 0x00, 0x7C, 0x07, ++ 0x08, 0x41, 0x04, 0x40, 0x0C, 0x41, 0x04, 0x40, 0x18, 0x41, 0x04, 0x40, ++ 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, ++ 0xFF, 0xFF, 0xFC, 0xFF, 0x00, 0xE1, 0x00, 0xE0, 0x70, 0xB5, 0x82, 0xB0, ++ 0x04, 0x00, 0x64, 0x4B, 0x18, 0x68, 0x04, 0x28, 0x04, 0xD8, 0x49, 0xD8, ++ 0x80, 0x00, 0x62, 0x4B, 0x1B, 0x58, 0x9F, 0x46, 0xFF, 0x28, 0x43, 0xD1, ++ 0x60, 0x4B, 0x80, 0x22, 0xD2, 0x00, 0x1A, 0x60, 0x5F, 0x4B, 0x00, 0x22, ++ 0x1A, 0x70, 0x5F, 0x4B, 0x1B, 0x68, 0x00, 0x2B, 0x40, 0xD1, 0x5E, 0x4B, ++ 0x19, 0x68, 0x41, 0x29, 0x57, 0xD0, 0x43, 0xD8, 0x01, 0x29, 0x49, 0xD0, ++ 0x21, 0x29, 0x00, 0xD0, 0x81, 0xE0, 0x5A, 0x4B, 0x01, 0x22, 0x1A, 0x70, ++ 0x52, 0x4B, 0x00, 0x22, 0x1A, 0x60, 0x58, 0x4B, 0x1B, 0x68, 0x01, 0x2B, ++ 0x54, 0xD1, 0x50, 0xE0, 0x54, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x4F, 0x4B, ++ 0x80, 0x22, 0xD2, 0x00, 0x1A, 0x60, 0x4E, 0x4B, 0x00, 0x22, 0x1A, 0x70, ++ 0x50, 0x4B, 0x1B, 0x68, 0x01, 0x2B, 0x00, 0xD1, 0x7D, 0xE0, 0x47, 0x4B, ++ 0x1B, 0x68, 0x02, 0x2B, 0x40, 0xD1, 0x00, 0x25, 0x4C, 0x4B, 0x1D, 0x70, ++ 0x01, 0x20, 0xFB, 0xF7, 0xCB, 0xFD, 0x4B, 0x4B, 0x1D, 0x70, 0x3D, 0xE0, ++ 0x46, 0x4B, 0x02, 0x22, 0x1A, 0x70, 0xE2, 0xE7, 0x44, 0x4B, 0x01, 0x22, ++ 0x1A, 0x70, 0xDE, 0xE7, 0x42, 0x4B, 0x19, 0x78, 0x45, 0x4B, 0xDD, 0x6E, ++ 0x00, 0x23, 0x00, 0x22, 0xA8, 0x47, 0xD6, 0xE7, 0x0F, 0x20, 0xFA, 0xF7, ++ 0x6F, 0xFD, 0xFF, 0x23, 0x03, 0x40, 0x3B, 0x4A, 0x13, 0x60, 0xB6, 0xE7, ++ 0x61, 0x29, 0x10, 0xD0, 0xFF, 0x29, 0x3E, 0xD1, 0x3D, 0x48, 0x7E, 0xF7, ++ 0xA1, 0xFA, 0xCD, 0xE7, 0x36, 0x4B, 0x02, 0x22, 0x1A, 0x70, 0x2F, 0x4B, ++ 0x01, 0x3A, 0x1A, 0x60, 0x34, 0x4B, 0x1B, 0x68, 0x01, 0x2B, 0x0D, 0xD1, ++ 0x4C, 0xE0, 0x31, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x29, 0x4B, 0x01, 0x32, ++ 0x1A, 0x60, 0x2F, 0x4B, 0x1B, 0x68, 0x01, 0x2B, 0xC1, 0xD1, 0x26, 0x4B, ++ 0x03, 0x22, 0x1A, 0x60, 0x2D, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x00, 0x20, ++ 0xFB, 0xF7, 0x8A, 0xFD, 0x2D, 0x4B, 0x03, 0x22, 0x1A, 0x70, 0xFF, 0xF7, ++ 0x35, 0xFF, 0x2C, 0x4B, 0x1B, 0x68, 0x24, 0x4A, 0x12, 0x78, 0x1D, 0x49, ++ 0x09, 0x68, 0x2A, 0x48, 0x00, 0x68, 0x01, 0x90, 0x1E, 0x48, 0x00, 0x68, ++ 0x00, 0x90, 0x28, 0x48, 0x7E, 0xF7, 0x6E, 0xFA, 0x00, 0x2C, 0x27, 0xD0, ++ 0x26, 0x4A, 0x13, 0x68, 0x20, 0x21, 0x0B, 0x43, 0x13, 0x60, 0x02, 0xB0, ++ 0x70, 0xBD, 0x24, 0x48, 0x7E, 0xF7, 0x62, 0xFA, 0x17, 0x4E, 0x31, 0x78, ++ 0x10, 0x4D, 0x00, 0x23, 0x00, 0x22, 0x28, 0x68, 0x81, 0xF7, 0xFE, 0xFF, ++ 0x02, 0x23, 0x33, 0x70, 0x01, 0x3B, 0x2B, 0x60, 0x12, 0x4B, 0x1B, 0x68, ++ 0x01, 0x2B, 0xC9, 0xD1, 0x0F, 0x4B, 0x1B, 0x78, 0x03, 0xE0, 0x0E, 0x4B, ++ 0x1B, 0x78, 0x01, 0x2B, 0xBF, 0xD0, 0x02, 0x2B, 0x00, 0xD0, 0x7A, 0xE7, ++ 0x04, 0x4B, 0x04, 0x22, 0x1A, 0x60, 0xBB, 0xE7, 0x12, 0x4A, 0x13, 0x68, ++ 0x20, 0x21, 0x8B, 0x43, 0x13, 0x60, 0xD6, 0xE7, 0x50, 0xE0, 0x10, 0x00, ++ 0xE0, 0xD1, 0x10, 0x00, 0xE4, 0xE1, 0x10, 0x00, 0xB2, 0xE6, 0x10, 0x00, ++ 0xA4, 0xE5, 0x10, 0x00, 0xC0, 0xE5, 0x10, 0x00, 0xB4, 0xE5, 0x10, 0x00, ++ 0x54, 0xE0, 0x10, 0x00, 0x60, 0xE6, 0x10, 0x00, 0xDC, 0xE6, 0x10, 0x00, ++ 0x28, 0x19, 0x16, 0x00, 0x9C, 0xD1, 0x10, 0x00, 0xD1, 0xE6, 0x10, 0x00, ++ 0xA8, 0xE5, 0x10, 0x00, 0xBC, 0xE5, 0x10, 0x00, 0xC8, 0xD1, 0x10, 0x00, ++ 0x84, 0x40, 0x04, 0x40, 0xB0, 0xD1, 0x10, 0x00, 0xF0, 0xB5, 0xC6, 0x46, ++ 0x00, 0xB5, 0x38, 0x4B, 0x38, 0x4A, 0x1A, 0x60, 0x38, 0x4B, 0x39, 0x4A, ++ 0x1A, 0x60, 0x40, 0x23, 0x38, 0x4A, 0x13, 0x60, 0x28, 0x22, 0x38, 0x49, ++ 0x0A, 0x80, 0xC8, 0x21, 0x49, 0x00, 0x37, 0x48, 0x01, 0x80, 0x37, 0x48, ++ 0x01, 0x80, 0x03, 0x20, 0x36, 0x49, 0x08, 0x80, 0x02, 0x21, 0x36, 0x4C, ++ 0x21, 0x80, 0x36, 0x4C, 0x20, 0x80, 0x36, 0x48, 0x01, 0x80, 0x36, 0x49, ++ 0x0A, 0x80, 0x80, 0x25, 0xAD, 0x00, 0x35, 0x49, 0x0D, 0x80, 0x14, 0x21, ++ 0x34, 0x48, 0x01, 0x80, 0x34, 0x48, 0x15, 0x24, 0x04, 0x80, 0x34, 0x48, ++ 0x01, 0x80, 0x20, 0x26, 0x33, 0x49, 0x0E, 0x60, 0x0D, 0x3C, 0x33, 0x49, ++ 0x0C, 0x60, 0x33, 0x49, 0x01, 0x20, 0x40, 0x42, 0x08, 0x60, 0x00, 0x20, ++ 0x31, 0x49, 0x08, 0x60, 0x31, 0x49, 0x88, 0x46, 0x31, 0x4F, 0x39, 0x60, ++ 0x31, 0x4F, 0x14, 0x21, 0xFF, 0x31, 0x39, 0x60, 0x30, 0x4F, 0x31, 0x49, ++ 0x39, 0x60, 0x31, 0x4F, 0x07, 0x21, 0x39, 0x80, 0x30, 0x4F, 0x3B, 0x80, ++ 0x30, 0x4F, 0x41, 0x31, 0x39, 0x80, 0x30, 0x4F, 0x01, 0x39, 0x39, 0x80, ++ 0x2F, 0x4F, 0x3E, 0x80, 0x2F, 0x4E, 0x35, 0x80, 0x2F, 0x4D, 0xD2, 0x26, ++ 0x76, 0x00, 0x2E, 0x80, 0x64, 0x25, 0x2E, 0x4E, 0x35, 0x80, 0x2E, 0x4E, ++ 0x35, 0x80, 0x2E, 0x4D, 0x2C, 0x80, 0x2E, 0x4C, 0x18, 0x25, 0x25, 0x80, ++ 0x2D, 0x4C, 0x22, 0x80, 0x2D, 0x4A, 0x8C, 0x24, 0x14, 0x80, 0x2D, 0x4A, ++ 0x10, 0x80, 0x2D, 0x4A, 0x13, 0x60, 0x2D, 0x4B, 0x42, 0x46, 0x1A, 0x60, ++ 0x2C, 0x4B, 0x32, 0x22, 0x1A, 0x80, 0x04, 0xBC, 0x90, 0x46, 0xF0, 0xBD, ++ 0xA0, 0x06, 0x16, 0x00, 0x00, 0xD7, 0x18, 0x00, 0x9C, 0x06, 0x16, 0x00, ++ 0x00, 0xF7, 0x18, 0x00, 0x78, 0x06, 0x16, 0x00, 0x5C, 0x06, 0x16, 0x00, ++ 0x8E, 0x06, 0x16, 0x00, 0x8C, 0x06, 0x16, 0x00, 0x5A, 0x06, 0x16, 0x00, ++ 0x4A, 0x06, 0x16, 0x00, 0x56, 0x06, 0x16, 0x00, 0x54, 0x06, 0x16, 0x00, ++ 0x5E, 0x06, 0x16, 0x00, 0x58, 0x06, 0x16, 0x00, 0x64, 0x06, 0x16, 0x00, ++ 0x66, 0x06, 0x16, 0x00, 0x62, 0x06, 0x16, 0x00, 0x68, 0x06, 0x16, 0x00, ++ 0x6C, 0x06, 0x16, 0x00, 0x44, 0x1E, 0x16, 0x00, 0x40, 0x1E, 0x16, 0x00, ++ 0x20, 0x4E, 0x00, 0x00, 0x7C, 0x06, 0x16, 0x00, 0x38, 0x1E, 0x16, 0x00, ++ 0x3C, 0x1E, 0x16, 0x00, 0x02, 0x73, 0x06, 0x20, 0x4C, 0x06, 0x16, 0x00, ++ 0x4E, 0x06, 0x16, 0x00, 0x50, 0x06, 0x16, 0x00, 0x52, 0x06, 0x16, 0x00, ++ 0x90, 0x06, 0x16, 0x00, 0x94, 0x06, 0x16, 0x00, 0x92, 0x06, 0x16, 0x00, ++ 0x8A, 0x06, 0x16, 0x00, 0x88, 0x06, 0x16, 0x00, 0x82, 0x06, 0x16, 0x00, ++ 0x80, 0x06, 0x16, 0x00, 0x86, 0x06, 0x16, 0x00, 0x84, 0x06, 0x16, 0x00, ++ 0x48, 0x1E, 0x16, 0x00, 0x70, 0x06, 0x16, 0x00, 0x74, 0x06, 0x16, 0x00, ++ 0x60, 0x06, 0x16, 0x00, 0x0F, 0x4B, 0x02, 0x22, 0x9A, 0x77, 0x0F, 0x4A, ++ 0x11, 0x6D, 0x80, 0x23, 0xDB, 0x01, 0x0B, 0x43, 0x13, 0x65, 0x0D, 0x4B, ++ 0x1B, 0x78, 0x02, 0x2B, 0x0B, 0xD0, 0x0A, 0x4B, 0x19, 0x6D, 0x80, 0x22, ++ 0x12, 0x02, 0x0A, 0x43, 0x1A, 0x65, 0x19, 0x6D, 0x80, 0x22, 0x92, 0x02, ++ 0x0A, 0x43, 0x1A, 0x65, 0x70, 0x47, 0x11, 0x6D, 0x80, 0x23, 0xDB, 0x02, ++ 0x0B, 0x43, 0x13, 0x65, 0xED, 0xE7, 0xC0, 0x46, 0x3C, 0x95, 0x16, 0x00, ++ 0x00, 0x60, 0x50, 0x40, 0xB4, 0xE5, 0x10, 0x00, 0x01, 0x4B, 0x01, 0x22, ++ 0xDA, 0x77, 0x70, 0x47, 0x3C, 0x95, 0x16, 0x00, 0x10, 0xB5, 0x01, 0x20, ++ 0x7F, 0xF7, 0x48, 0xF9, 0x10, 0xBD, 0x10, 0xB5, 0x80, 0x20, 0x40, 0x00, ++ 0x7B, 0xF7, 0x3A, 0xFC, 0x10, 0xBD, 0x00, 0x00, 0x10, 0xB5, 0x04, 0x00, ++ 0x20, 0x4B, 0x1B, 0x68, 0x01, 0x2B, 0x03, 0xD0, 0x1F, 0x4B, 0x1B, 0x68, ++ 0x00, 0x2B, 0x22, 0xD1, 0x00, 0x2C, 0x2C, 0xD0, 0x1D, 0x4A, 0x13, 0x68, ++ 0x08, 0x21, 0x0B, 0x43, 0x13, 0x60, 0x00, 0x23, 0x1B, 0x4A, 0x13, 0x60, ++ 0x1B, 0x4A, 0x13, 0x60, 0x1B, 0x4A, 0x13, 0x60, 0x1B, 0x4B, 0x1B, 0x68, ++ 0x01, 0x2B, 0x22, 0xD9, 0x1A, 0x4A, 0x0F, 0x21, 0x11, 0x70, 0x03, 0x3B, ++ 0x01, 0x2B, 0x05, 0xD8, 0x18, 0x4A, 0x80, 0x23, 0x1B, 0x02, 0x91, 0x69, ++ 0x0B, 0x43, 0x93, 0x61, 0x16, 0x49, 0x17, 0x48, 0x7E, 0xF7, 0xEC, 0xF8, ++ 0x10, 0xBD, 0xFF, 0xF7, 0xCF, 0xFE, 0xFF, 0xF7, 0x97, 0xFF, 0x11, 0x4B, ++ 0x01, 0x22, 0xDA, 0x77, 0xFF, 0xF7, 0xBE, 0xFF, 0xFF, 0xF7, 0xC1, 0xFF, ++ 0xD0, 0xE7, 0x07, 0x4A, 0x13, 0x68, 0x08, 0x21, 0x8B, 0x43, 0x13, 0x60, ++ 0xD1, 0xE7, 0x09, 0x4B, 0x0B, 0x22, 0x1A, 0x70, 0xE4, 0xE7, 0xC0, 0x46, ++ 0xA8, 0xE5, 0x10, 0x00, 0xAC, 0xE5, 0x10, 0x00, 0x84, 0x40, 0x04, 0x40, ++ 0x58, 0xE6, 0x10, 0x00, 0x5C, 0xE6, 0x10, 0x00, 0x54, 0xE6, 0x10, 0x00, ++ 0x50, 0xE0, 0x10, 0x00, 0xE2, 0xE1, 0x10, 0x00, 0x3C, 0x95, 0x16, 0x00, ++ 0xF8, 0xE8, 0x10, 0x00, 0xF4, 0xD1, 0x10, 0x00, 0x02, 0x4B, 0x80, 0x22, ++ 0x12, 0x04, 0x1A, 0x60, 0x70, 0x47, 0xC0, 0x46, 0x00, 0x41, 0x04, 0x40, ++ 0x02, 0x4B, 0x80, 0x22, 0x12, 0x05, 0x1A, 0x60, 0x70, 0x47, 0xC0, 0x46, ++ 0x00, 0x41, 0x04, 0x40, 0x02, 0x4B, 0x80, 0x22, 0xD2, 0x05, 0x1A, 0x60, ++ 0x70, 0x47, 0xC0, 0x46, 0x00, 0x41, 0x04, 0x40, 0x04, 0x4B, 0x1B, 0x78, ++ 0x00, 0x2B, 0x03, 0xD0, 0x03, 0x4B, 0x80, 0x22, 0x52, 0x05, 0x1A, 0x60, ++ 0x70, 0x47, 0xC0, 0x46, 0xD0, 0xE6, 0x10, 0x00, 0x00, 0x41, 0x04, 0x40, ++ 0x10, 0xB5, 0x04, 0x00, 0x13, 0x4B, 0x1B, 0x68, 0x02, 0x2B, 0x07, 0xD0, ++ 0x11, 0x4B, 0x1B, 0x68, 0x01, 0x2B, 0x16, 0xD9, 0x20, 0x00, 0x10, 0x4B, ++ 0x98, 0x47, 0x10, 0xBD, 0xAD, 0x33, 0xC3, 0x5C, 0x00, 0x2B, 0xF7, 0xD0, ++ 0x0D, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x04, 0xD0, 0x00, 0x21, 0x01, 0x20, ++ 0xFD, 0xF7, 0x54, 0xF8, 0xEA, 0xE7, 0xFF, 0xF7, 0xD5, 0xFF, 0x08, 0x4B, ++ 0x01, 0x22, 0x1A, 0x70, 0xF4, 0xE7, 0xAE, 0xF7, 0x09, 0xFD, 0x00, 0x28, ++ 0xE4, 0xD1, 0xA7, 0x23, 0x04, 0x22, 0xE2, 0x54, 0xE0, 0xE7, 0xC0, 0x46, ++ 0x50, 0xE0, 0x10, 0x00, 0xD5, 0x0D, 0x0B, 0x00, 0xD8, 0xE6, 0x10, 0x00, ++ 0x10, 0xB5, 0x04, 0x00, 0x0B, 0x4B, 0x1B, 0x68, 0x02, 0x2B, 0x03, 0xD0, ++ 0x20, 0x00, 0xFE, 0xF7, 0x11, 0xF9, 0x10, 0xBD, 0x08, 0x4B, 0x1B, 0x78, ++ 0x00, 0x2B, 0x04, 0xD0, 0x00, 0x21, 0x01, 0x20, 0xFD, 0xF7, 0x2C, 0xF8, ++ 0xF2, 0xE7, 0xFF, 0xF7, 0xAD, 0xFF, 0x03, 0x4B, 0x01, 0x22, 0x1A, 0x70, ++ 0xF4, 0xE7, 0xC0, 0x46, 0x50, 0xE0, 0x10, 0x00, 0xD8, 0xE6, 0x10, 0x00, ++ 0x04, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x03, 0xD0, 0x03, 0x4B, 0x80, 0x22, ++ 0x92, 0x05, 0x1A, 0x60, 0x70, 0x47, 0xC0, 0x46, 0xD2, 0xE6, 0x10, 0x00, ++ 0x00, 0x41, 0x04, 0x40, 0xF0, 0xB5, 0xDE, 0x46, 0x57, 0x46, 0x4E, 0x46, ++ 0x45, 0x46, 0xE0, 0xB5, 0x83, 0xB0, 0x80, 0x46, 0x00, 0x91, 0x82, 0x00, ++ 0x93, 0x4B, 0xD5, 0x58, 0x9E, 0x23, 0xEC, 0x5C, 0x64, 0x00, 0x0F, 0x33, ++ 0xEB, 0x5C, 0xE4, 0x18, 0xE4, 0xB2, 0xAF, 0x23, 0xEB, 0x5C, 0x00, 0x2B, ++ 0x00, 0xD1, 0xAF, 0xE0, 0xA8, 0x23, 0xEB, 0x5C, 0x77, 0x2B, 0x02, 0xD8, ++ 0x01, 0x33, 0xA8, 0x22, 0xAB, 0x54, 0x43, 0x46, 0x1B, 0x02, 0x01, 0x27, ++ 0x3B, 0x43, 0x9B, 0x46, 0x87, 0x4B, 0x99, 0x46, 0x47, 0xE0, 0xC5, 0x20, ++ 0x02, 0x23, 0xFF, 0x22, 0x59, 0x46, 0xC0, 0x00, 0x7B, 0xF7, 0x0A, 0xFF, ++ 0x06, 0x00, 0x3B, 0x88, 0x03, 0x80, 0x7B, 0xF7, 0x2F, 0xFF, 0x30, 0x88, ++ 0x43, 0x1C, 0x9B, 0xB2, 0x7F, 0x49, 0x5A, 0x5C, 0x41, 0x5C, 0x49, 0x10, ++ 0x7E, 0x48, 0x7D, 0xF7, 0xFF, 0xFF, 0x00, 0x23, 0x3B, 0x80, 0x7D, 0x4B, ++ 0xE2, 0x18, 0x13, 0x88, 0x78, 0x21, 0x8B, 0x43, 0x13, 0x80, 0x7B, 0x4B, ++ 0x9C, 0x46, 0x64, 0x44, 0x23, 0x88, 0x7A, 0x4A, 0x13, 0x40, 0x23, 0x80, ++ 0xAF, 0x22, 0xAB, 0x5C, 0x01, 0x3B, 0xDB, 0xB2, 0xAB, 0x54, 0x35, 0x31, ++ 0x6A, 0x5C, 0x50, 0x42, 0x42, 0x41, 0x6A, 0x54, 0x5A, 0x1E, 0x93, 0x41, ++ 0xA8, 0x22, 0xAB, 0x54, 0x8C, 0x23, 0xEB, 0x58, 0x00, 0x2B, 0x05, 0xD0, ++ 0x6A, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, ++ 0x9E, 0x23, 0xEC, 0x5C, 0x64, 0x00, 0x0F, 0x33, 0xEB, 0x5C, 0xE4, 0x18, ++ 0xE4, 0xB2, 0xAF, 0x23, 0xEB, 0x5C, 0x00, 0x2B, 0x58, 0xD0, 0xA3, 0x00, ++ 0x1C, 0x19, 0x64, 0x00, 0x66, 0x4B, 0xE3, 0x18, 0x1B, 0x88, 0xDB, 0x0B, ++ 0x50, 0xD0, 0x65, 0x4B, 0xE7, 0x18, 0x3B, 0x88, 0x9B, 0xB2, 0x00, 0x2B, ++ 0xA9, 0xD1, 0x63, 0x4B, 0xE7, 0x18, 0x3B, 0x88, 0x9B, 0xB2, 0x00, 0x2B, ++ 0x38, 0xD0, 0xEC, 0x23, 0xEB, 0x58, 0x00, 0x2B, 0xB7, 0xD1, 0x5A, 0x4B, ++ 0xE3, 0x18, 0x1B, 0x88, 0xDB, 0x04, 0x9B, 0x0D, 0x0A, 0xD0, 0x3A, 0x88, ++ 0x90, 0x21, 0x69, 0x58, 0xD3, 0x18, 0x4A, 0x89, 0x92, 0x05, 0x92, 0x0D, ++ 0x09, 0x89, 0x52, 0x18, 0x93, 0x42, 0x0D, 0xDA, 0x8C, 0x23, 0xEB, 0x58, ++ 0x00, 0x2B, 0x06, 0xD0, 0x4B, 0x4B, 0x9B, 0x6E, 0x01, 0x93, 0x00, 0x22, ++ 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x00, 0x23, 0x3B, 0x80, 0x98, 0xE7, ++ 0x01, 0x23, 0xFF, 0x22, 0x59, 0x46, 0x4E, 0x48, 0x7B, 0xF7, 0x8C, 0xFE, ++ 0x00, 0x23, 0x9A, 0x46, 0x03, 0x70, 0x7B, 0xF7, 0xB1, 0xFE, 0x90, 0x26, ++ 0xAB, 0x59, 0x18, 0x89, 0x85, 0xF7, 0xA2, 0xFF, 0x8C, 0x23, 0xEA, 0x58, ++ 0xAA, 0x51, 0x52, 0x46, 0xEA, 0x50, 0xE6, 0xE7, 0xEC, 0x23, 0xEB, 0x58, ++ 0x00, 0x2B, 0x00, 0xD0, 0x7D, 0xE7, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, ++ 0x4B, 0x46, 0x9B, 0x6E, 0x98, 0x47, 0x76, 0xE7, 0x00, 0x99, 0x40, 0x46, ++ 0xFD, 0xF7, 0x0C, 0xF8, 0x3D, 0x4B, 0x1B, 0x68, 0x02, 0x2B, 0x0A, 0xD0, ++ 0xFC, 0xF7, 0x6E, 0xF9, 0x01, 0x28, 0x28, 0xD0, 0x03, 0xB0, 0x3C, 0xBC, ++ 0x90, 0x46, 0x99, 0x46, 0xA2, 0x46, 0xAB, 0x46, 0xF0, 0xBD, 0xAD, 0x33, ++ 0xEB, 0x5C, 0x00, 0x2B, 0x0E, 0xD1, 0x35, 0x4B, 0x1B, 0x78, 0x01, 0x2B, ++ 0x04, 0xD0, 0x00, 0x21, 0x02, 0x20, 0xFC, 0xF7, 0x2B, 0xFF, 0xE7, 0xE7, ++ 0xFF, 0xF7, 0x08, 0xFF, 0x2F, 0x4B, 0x00, 0x22, 0x1A, 0x70, 0xF4, 0xE7, ++ 0x2D, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x04, 0xD0, 0x00, 0x21, 0x01, 0x20, ++ 0xFC, 0xF7, 0x1C, 0xFF, 0xD8, 0xE7, 0xFF, 0xF7, 0x9D, 0xFE, 0x28, 0x4B, ++ 0x01, 0x22, 0x1A, 0x70, 0xF4, 0xE7, 0xFB, 0xF7, 0x0F, 0xFA, 0x00, 0x28, ++ 0xD2, 0xD0, 0xAE, 0xF7, 0xCD, 0xFB, 0x00, 0x28, 0xCE, 0xD1, 0x8A, 0xF7, ++ 0x5D, 0xFA, 0x00, 0x28, 0xCA, 0xD1, 0xAF, 0x23, 0xEB, 0x5C, 0x00, 0x2B, ++ 0xC6, 0xD1, 0xA7, 0x33, 0xEB, 0x5C, 0x01, 0x2B, 0xC2, 0xD8, 0xD0, 0xF7, ++ 0xD9, 0xFA, 0x04, 0x1E, 0xBE, 0xD0, 0x1B, 0x4B, 0xC2, 0x69, 0x9A, 0x42, ++ 0xBA, 0xD1, 0xA5, 0xF7, 0x4D, 0xFA, 0x63, 0x68, 0x05, 0x3B, 0x1B, 0x1A, ++ 0x1B, 0x01, 0x1B, 0x09, 0xAA, 0x22, 0xAA, 0x5C, 0x00, 0x2A, 0xAF, 0xD0, ++ 0x0B, 0x2B, 0xAD, 0xD9, 0x13, 0x4B, 0x01, 0x22, 0x1A, 0x70, 0x9E, 0x23, ++ 0xE8, 0x5C, 0xD1, 0xF7, 0x35, 0xFA, 0xAA, 0x23, 0x00, 0x22, 0xEA, 0x54, ++ 0xA2, 0xE7, 0xC0, 0x46, 0x38, 0x27, 0x16, 0x00, 0x28, 0x19, 0x16, 0x00, ++ 0x00, 0x00, 0x61, 0x40, 0xFC, 0xD1, 0x10, 0x00, 0xCA, 0x69, 0x61, 0x40, ++ 0xCC, 0x69, 0x61, 0x40, 0x07, 0xE0, 0xFF, 0xFF, 0xC8, 0x69, 0x61, 0x40, ++ 0xD0, 0x69, 0x61, 0x40, 0xCE, 0x69, 0x61, 0x40, 0x2B, 0x06, 0x00, 0x00, ++ 0x50, 0xE0, 0x10, 0x00, 0xD8, 0xE6, 0x10, 0x00, 0xC9, 0x1F, 0x10, 0x00, ++ 0x98, 0xE5, 0x10, 0x00, 0xF0, 0xB5, 0xDE, 0x46, 0x57, 0x46, 0x4E, 0x46, ++ 0x45, 0x46, 0xE0, 0xB5, 0x87, 0xB0, 0x81, 0x46, 0x82, 0x00, 0xBA, 0x4B, ++ 0xD4, 0x58, 0x01, 0x94, 0xB0, 0x23, 0x15, 0x22, 0xE2, 0x54, 0x2A, 0x3B, ++ 0xFA, 0x22, 0x52, 0x01, 0xE2, 0x52, 0xB6, 0x4B, 0x1B, 0x68, 0x02, 0x2B, ++ 0x15, 0xD0, 0xB4, 0x4B, 0x1B, 0x68, 0x01, 0x2B, 0x26, 0xD9, 0xB3, 0x4B, ++ 0x00, 0x22, 0x1A, 0x70, 0xA1, 0x23, 0xE3, 0x5C, 0x04, 0x2B, 0x2C, 0xD0, ++ 0x86, 0x23, 0xE3, 0x5A, 0x00, 0x2B, 0x6B, 0xD0, 0x5B, 0x00, 0x22, 0x6F, ++ 0x94, 0x46, 0x63, 0x44, 0x1B, 0x01, 0x1F, 0x09, 0x29, 0xE0, 0xAB, 0x4B, ++ 0xE3, 0x61, 0xAF, 0x23, 0xE3, 0x5C, 0x00, 0x2B, 0x03, 0xD1, 0xA9, 0x4B, ++ 0x1B, 0x78, 0x01, 0x2B, 0x04, 0xD0, 0x01, 0x21, 0x02, 0x20, 0xFC, 0xF7, ++ 0x87, 0xFE, 0xDA, 0xE7, 0xFF, 0xF7, 0x64, 0xFE, 0xA3, 0x4B, 0x00, 0x22, ++ 0x1A, 0x70, 0xF4, 0xE7, 0xA0, 0x4B, 0xE3, 0x61, 0x9E, 0x4B, 0x1B, 0x78, ++ 0x00, 0x2B, 0xD2, 0xD0, 0x9F, 0x4B, 0x18, 0x68, 0x00, 0x28, 0xCE, 0xD0, ++ 0xFB, 0xF7, 0x86, 0xFE, 0xCB, 0xE7, 0xE4, 0x33, 0xE3, 0x58, 0x19, 0x68, ++ 0xA3, 0x6F, 0xC9, 0x1A, 0x14, 0x39, 0x09, 0x01, 0x0F, 0x09, 0xA6, 0x23, ++ 0xE3, 0x5C, 0xDB, 0x02, 0xE0, 0x22, 0x92, 0x01, 0x1A, 0x40, 0x96, 0x4B, ++ 0x59, 0x78, 0x0F, 0x23, 0x0B, 0x40, 0x13, 0x43, 0x94, 0x4A, 0x13, 0x43, ++ 0xA3, 0x82, 0xE7, 0x60, 0xFB, 0xF7, 0x56, 0xF9, 0x02, 0x90, 0xFD, 0xF7, ++ 0x2B, 0xF9, 0x03, 0x90, 0xAE, 0xF7, 0x12, 0xFB, 0x06, 0x00, 0xA1, 0x23, ++ 0xE3, 0x5C, 0x04, 0x2B, 0x00, 0xD1, 0x38, 0xE2, 0x00, 0x25, 0x00, 0x28, ++ 0x2B, 0xD0, 0x8B, 0x4B, 0xA2, 0x6F, 0x1A, 0x60, 0x9F, 0x23, 0xE3, 0x5C, ++ 0x00, 0x2B, 0x00, 0xD1, 0x5C, 0xE1, 0x88, 0x4A, 0xD2, 0x88, 0x22, 0x61, ++ 0x01, 0x2B, 0x00, 0xD0, 0xDA, 0xE1, 0xA7, 0x33, 0xE3, 0x5C, 0xA7, 0x21, ++ 0x61, 0x5C, 0x5B, 0x18, 0x1B, 0x11, 0x83, 0x49, 0x4B, 0x43, 0x93, 0x42, ++ 0x00, 0xD2, 0x13, 0x00, 0x23, 0x61, 0xCD, 0xE1, 0xA6, 0x23, 0xE3, 0x5C, ++ 0xDB, 0x02, 0xE0, 0x22, 0x92, 0x01, 0x1A, 0x40, 0x78, 0x4B, 0x59, 0x78, ++ 0x0F, 0x23, 0x0B, 0x40, 0x13, 0x43, 0x7B, 0x4A, 0x13, 0x43, 0xA3, 0x82, ++ 0x01, 0x27, 0x7F, 0x42, 0xC2, 0xE7, 0xA5, 0xF7, 0x73, 0xF9, 0x60, 0x60, ++ 0x03, 0x9B, 0x00, 0x2B, 0x52, 0xD0, 0x76, 0x4B, 0x23, 0x61, 0x11, 0x23, ++ 0xA3, 0x75, 0x8E, 0x33, 0xE3, 0x5C, 0x01, 0x2B, 0x47, 0xD0, 0x00, 0x25, ++ 0x48, 0x23, 0x9B, 0x46, 0xAF, 0x23, 0xE3, 0x5C, 0x98, 0x46, 0x20, 0x00, ++ 0x48, 0x30, 0x7E, 0xF7, 0x83, 0xFA, 0x6E, 0x4A, 0x12, 0x68, 0x92, 0x68, ++ 0x00, 0x2A, 0x00, 0xD0, 0xE0, 0xE0, 0x9F, 0x23, 0xE3, 0x5C, 0x00, 0x2B, ++ 0x01, 0xD1, 0x6A, 0x4B, 0x23, 0x61, 0x40, 0x44, 0xC3, 0xB2, 0xA7, 0x22, ++ 0xA2, 0x5C, 0x11, 0x00, 0x19, 0x43, 0x06, 0xD0, 0xD3, 0x18, 0x65, 0x4A, ++ 0x53, 0x43, 0x22, 0x69, 0x94, 0x46, 0x63, 0x44, 0x23, 0x61, 0x23, 0x69, ++ 0x62, 0x4A, 0x93, 0x42, 0x00, 0xD9, 0x13, 0x00, 0x23, 0x61, 0x5A, 0x46, ++ 0x21, 0x69, 0x20, 0x00, 0xFB, 0xF7, 0x16, 0xF8, 0x9F, 0x23, 0xE3, 0x5C, ++ 0x00, 0x2B, 0x04, 0xD1, 0x63, 0x68, 0x03, 0x33, 0x03, 0x22, 0x93, 0x43, ++ 0x63, 0x60, 0xA7, 0x23, 0x01, 0x22, 0xE2, 0x54, 0x50, 0x4B, 0xA2, 0x6F, ++ 0x1A, 0x60, 0x20, 0x00, 0xCF, 0xF7, 0xB6, 0xFF, 0x00, 0x28, 0x00, 0xD0, ++ 0xAE, 0xE1, 0xA0, 0x23, 0x00, 0x22, 0xE2, 0x54, 0x49, 0xE1, 0x37, 0x33, ++ 0x9B, 0x46, 0xB7, 0xE7, 0x02, 0x9B, 0x00, 0x2B, 0x6B, 0xD0, 0x00, 0x23, ++ 0x00, 0x25, 0x3E, 0x4A, 0x90, 0x46, 0xA1, 0x22, 0x94, 0x46, 0x02, 0xE0, ++ 0x01, 0x33, 0x07, 0x2B, 0x0B, 0xD0, 0x9A, 0x00, 0x41, 0x46, 0x52, 0x58, ++ 0x00, 0x2A, 0xF7, 0xD0, 0x61, 0x46, 0x52, 0x5C, 0x00, 0x2A, 0xF3, 0xD1, ++ 0x01, 0x35, 0xED, 0xB2, 0xF0, 0xE7, 0x01, 0x2D, 0x08, 0xD9, 0xA0, 0x33, ++ 0x00, 0x22, 0xE2, 0x54, 0x41, 0x4B, 0x1B, 0x68, 0x23, 0x61, 0x28, 0x23, ++ 0x9B, 0x46, 0x93, 0xE7, 0x9F, 0x23, 0xE3, 0x5C, 0x00, 0x2B, 0x23, 0xD1, ++ 0xA7, 0x33, 0x00, 0x22, 0xE2, 0x54, 0x01, 0x33, 0xE2, 0x5C, 0x53, 0x42, ++ 0x5A, 0x41, 0x53, 0x42, 0x08, 0x22, 0x1A, 0x40, 0x68, 0x32, 0x38, 0x4B, ++ 0x1B, 0x68, 0x98, 0x46, 0xC3, 0x1A, 0x1B, 0x01, 0x1B, 0x09, 0x80, 0x21, ++ 0x09, 0x05, 0x8B, 0x42, 0x04, 0xD9, 0x43, 0x46, 0x1B, 0x1A, 0x1B, 0x01, ++ 0x1B, 0x09, 0x5B, 0x42, 0x00, 0x21, 0x8B, 0x46, 0x9A, 0x42, 0x01, 0xD3, ++ 0xD3, 0x1A, 0x9B, 0x46, 0x2C, 0x4B, 0x1B, 0x68, 0x23, 0x61, 0x6B, 0xE7, ++ 0x01, 0x2B, 0x00, 0xD0, 0x65, 0xE1, 0xA7, 0x33, 0xE2, 0x5C, 0x53, 0x42, ++ 0x5A, 0x41, 0x53, 0x42, 0x0C, 0x22, 0x1A, 0x40, 0x44, 0x32, 0xE3, 0x6E, ++ 0x98, 0x46, 0xC3, 0x1A, 0x1B, 0x01, 0x1B, 0x09, 0x80, 0x21, 0x09, 0x05, ++ 0x8B, 0x42, 0x04, 0xD9, 0x43, 0x46, 0x1B, 0x1A, 0x1B, 0x01, 0x1B, 0x09, ++ 0x5B, 0x42, 0x00, 0x21, 0x8B, 0x46, 0x9A, 0x42, 0x01, 0xD3, 0xD3, 0x1A, ++ 0x9B, 0x46, 0x1B, 0x4B, 0x1B, 0x68, 0x23, 0x61, 0x48, 0xE7, 0x0A, 0x4B, ++ 0x1B, 0x68, 0x00, 0x25, 0x01, 0x2B, 0x00, 0xD9, 0x05, 0xE7, 0x13, 0x4B, ++ 0x1B, 0x68, 0x9B, 0x68, 0x00, 0x2B, 0x00, 0xD1, 0x37, 0xE1, 0x13, 0x4B, ++ 0x1B, 0x68, 0x23, 0x61, 0x00, 0x23, 0x9B, 0x46, 0x36, 0xE7, 0xC0, 0x46, ++ 0x38, 0x27, 0x16, 0x00, 0x50, 0xE0, 0x10, 0x00, 0x98, 0xE5, 0x10, 0x00, ++ 0xC1, 0x60, 0x10, 0x00, 0xD8, 0xE6, 0x10, 0x00, 0xF8, 0xE6, 0x10, 0x00, ++ 0x7C, 0x91, 0x0D, 0x00, 0x40, 0x80, 0xFF, 0xFF, 0xCC, 0xE6, 0x10, 0x00, ++ 0x5C, 0xAB, 0x16, 0x00, 0xE2, 0x04, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, ++ 0xE4, 0x57, 0x00, 0x00, 0xF4, 0xE1, 0x10, 0x00, 0x5C, 0x1C, 0x00, 0x00, ++ 0x70, 0x71, 0x00, 0x00, 0x40, 0xE0, 0x10, 0x00, 0x2C, 0xE6, 0x10, 0x00, ++ 0x00, 0x23, 0x04, 0x93, 0x05, 0x93, 0x20, 0x1D, 0x23, 0x00, 0x05, 0xAA, ++ 0x04, 0xA9, 0xFA, 0xF7, 0xAD, 0xFE, 0x04, 0x9B, 0x00, 0x2B, 0x28, 0xD0, ++ 0x22, 0x69, 0x9A, 0x42, 0x00, 0xD9, 0x1A, 0x00, 0x22, 0x61, 0x03, 0x26, ++ 0x63, 0x68, 0x9A, 0x46, 0x5A, 0x46, 0x21, 0x69, 0x01, 0x98, 0xFA, 0xF7, ++ 0x3B, 0xFF, 0x63, 0x68, 0x53, 0x45, 0x08, 0xD0, 0x05, 0x9B, 0x53, 0x44, ++ 0x1B, 0x01, 0x1B, 0x09, 0x63, 0x60, 0x01, 0x3E, 0xF6, 0xB2, 0x00, 0x2E, ++ 0xEC, 0xD1, 0x9F, 0x23, 0xE3, 0x5C, 0x00, 0x2B, 0x00, 0xD0, 0x0E, 0xE7, ++ 0x63, 0x68, 0x03, 0x33, 0x03, 0x22, 0x93, 0x43, 0x63, 0x60, 0x23, 0x69, ++ 0x70, 0x4A, 0x94, 0x46, 0x63, 0x44, 0x23, 0x61, 0x03, 0xE7, 0x02, 0x9B, ++ 0x00, 0x2B, 0x00, 0xD1, 0x9B, 0xE6, 0xEA, 0xE7, 0xA7, 0x23, 0xE3, 0x5C, ++ 0x00, 0x2B, 0x00, 0xD0, 0x7B, 0xE0, 0xA8, 0x33, 0xE3, 0x5C, 0x00, 0x2B, ++ 0x00, 0xD0, 0x76, 0xE0, 0xB3, 0x33, 0xE3, 0x5C, 0x00, 0x2B, 0x00, 0xD0, ++ 0x71, 0xE0, 0x65, 0x4B, 0x23, 0x61, 0x73, 0x42, 0x73, 0x41, 0x5B, 0x42, ++ 0x4B, 0x22, 0x93, 0x43, 0x60, 0x33, 0x5B, 0x00, 0x62, 0x68, 0x94, 0x46, ++ 0x63, 0x44, 0x60, 0x4A, 0x13, 0x40, 0x63, 0x60, 0xB0, 0x23, 0x09, 0x22, ++ 0xE2, 0x54, 0x20, 0x00, 0xCF, 0xF7, 0xA8, 0xFE, 0x00, 0x28, 0x00, 0xD0, ++ 0xA0, 0xE0, 0xA0, 0x23, 0x00, 0x22, 0xE2, 0x54, 0x00, 0x2E, 0x3A, 0xD0, ++ 0xA5, 0xF7, 0x0E, 0xF8, 0x57, 0x4B, 0x18, 0x60, 0x07, 0xB0, 0x3C, 0xBC, ++ 0x90, 0x46, 0x99, 0x46, 0xA2, 0x46, 0xAB, 0x46, 0xF0, 0xBD, 0x66, 0x60, ++ 0x80, 0xE0, 0x00, 0x2E, 0x00, 0xD1, 0x86, 0xE0, 0x51, 0x4B, 0x23, 0x61, ++ 0x20, 0x00, 0xFD, 0xF7, 0x57, 0xFE, 0x60, 0x60, 0x18, 0x26, 0x65, 0x68, ++ 0x00, 0x22, 0x21, 0x69, 0x01, 0x98, 0xFA, 0xF7, 0xD1, 0xFE, 0x63, 0x68, ++ 0xAB, 0x42, 0x06, 0xD0, 0x75, 0x19, 0x2D, 0x01, 0x2D, 0x09, 0x65, 0x60, ++ 0x18, 0x36, 0x60, 0x2E, 0xEF, 0xD1, 0x20, 0x00, 0xCF, 0xF7, 0x76, 0xFE, ++ 0x00, 0x28, 0x6F, 0xD1, 0xA0, 0x23, 0x00, 0x22, 0xE2, 0x54, 0xCF, 0xE7, ++ 0x39, 0x00, 0x14, 0x31, 0x09, 0x01, 0x09, 0x09, 0x48, 0x46, 0x40, 0x4B, ++ 0x98, 0x47, 0xCB, 0xE7, 0xA0, 0x23, 0x00, 0x22, 0xE2, 0x54, 0xA3, 0x7D, ++ 0x10, 0x2B, 0x01, 0xD8, 0x11, 0x23, 0xA3, 0x75, 0x02, 0x9B, 0x00, 0x2B, ++ 0xBC, 0xD0, 0x01, 0x2D, 0xBA, 0xD1, 0x39, 0x4B, 0x1B, 0x68, 0x9B, 0x68, ++ 0x00, 0x2B, 0xB5, 0xD1, 0x37, 0x4B, 0x1B, 0x68, 0x23, 0x61, 0x9F, 0x23, ++ 0xE3, 0x5C, 0x01, 0x2B, 0xAE, 0xD1, 0x35, 0x4B, 0x1B, 0x68, 0x23, 0x61, ++ 0xAA, 0xE7, 0x34, 0x4B, 0xDB, 0x88, 0x23, 0x61, 0xA1, 0x23, 0xE3, 0x5C, ++ 0x04, 0x2B, 0xB0, 0xD0, 0x00, 0x2E, 0xB1, 0xD1, 0x30, 0x4B, 0x23, 0x61, ++ 0xA7, 0x23, 0xE3, 0x5C, 0x00, 0x2B, 0x03, 0xD1, 0xA8, 0x22, 0xA2, 0x5C, ++ 0x00, 0x2A, 0x2E, 0xD0, 0xA8, 0x22, 0xA1, 0x5C, 0xCB, 0x18, 0x2A, 0x49, ++ 0x59, 0x43, 0x29, 0x4B, 0x9C, 0x46, 0x61, 0x44, 0x21, 0x61, 0x23, 0x4B, ++ 0x1A, 0x68, 0x53, 0x6F, 0x58, 0x42, 0x43, 0x41, 0x5B, 0x42, 0x1B, 0x48, ++ 0x03, 0x40, 0x24, 0x48, 0x84, 0x46, 0x63, 0x44, 0x92, 0x68, 0x00, 0x2A, ++ 0x02, 0xD0, 0x22, 0x4A, 0x12, 0x68, 0x9B, 0x1A, 0x99, 0x42, 0x00, 0xD9, ++ 0x19, 0x00, 0x21, 0x61, 0x66, 0x68, 0x28, 0x22, 0x20, 0x00, 0xFA, 0xF7, ++ 0x63, 0xFE, 0x01, 0x28, 0x00, 0xD1, 0x7C, 0xE7, 0x9F, 0x23, 0xE3, 0x5C, ++ 0x00, 0x2B, 0x04, 0xD1, 0x63, 0x68, 0x03, 0x33, 0x03, 0x22, 0x93, 0x43, ++ 0x63, 0x60, 0x20, 0x00, 0xCF, 0xF7, 0x06, 0xFE, 0x00, 0x28, 0x9B, 0xD0, ++ 0xA1, 0x23, 0xE3, 0x5C, 0x04, 0x2B, 0x8F, 0xD0, 0x08, 0x21, 0x48, 0x46, ++ 0x11, 0x4B, 0x98, 0x47, 0x5E, 0xE7, 0x00, 0x25, 0xC7, 0xE5, 0x00, 0x25, ++ 0xC5, 0xE5, 0x00, 0x23, 0x9B, 0x46, 0xFF, 0xE5, 0xAA, 0xF8, 0xFF, 0xFF, ++ 0x98, 0x12, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x0F, 0x34, 0xE6, 0x10, 0x00, ++ 0x88, 0x13, 0x00, 0x00, 0xB9, 0x4C, 0x0B, 0x00, 0xF4, 0xE1, 0x10, 0x00, ++ 0x40, 0xE0, 0x10, 0x00, 0x44, 0xE0, 0x10, 0x00, 0x5C, 0xAB, 0x16, 0x00, ++ 0x5C, 0x1C, 0x00, 0x00, 0x7C, 0x42, 0x00, 0x00, 0xE8, 0xE1, 0x10, 0x00, ++ 0x95, 0x0F, 0x0B, 0x00, 0xF0, 0xB5, 0xD6, 0x46, 0x4F, 0x46, 0x46, 0x46, ++ 0xC0, 0xB5, 0x82, 0xB0, 0xB7, 0x4B, 0xB8, 0x4A, 0x13, 0x60, 0x80, 0x22, ++ 0x52, 0x00, 0x9C, 0x5C, 0xFD, 0xF7, 0x5A, 0xFA, 0xB5, 0x4B, 0x1B, 0x68, ++ 0x9B, 0x68, 0x00, 0x2B, 0x09, 0xD0, 0xB2, 0x4B, 0x1D, 0x68, 0x02, 0x23, ++ 0xFF, 0x33, 0xEB, 0x5C, 0xA3, 0x42, 0x00, 0xD1, 0x42, 0xE1, 0xB0, 0x4F, ++ 0x84, 0xE0, 0xFA, 0xF7, 0xFD, 0xFD, 0xF2, 0xE7, 0xAE, 0x4A, 0x93, 0x42, ++ 0x46, 0xD1, 0xAE, 0x4B, 0x4B, 0x60, 0x43, 0xE0, 0xAD, 0x49, 0x8B, 0x42, ++ 0x00, 0xD1, 0xE5, 0xE0, 0xAC, 0x49, 0x8B, 0x42, 0x16, 0xD1, 0xAC, 0x4B, ++ 0x1A, 0x68, 0x00, 0x2A, 0x38, 0xD0, 0x23, 0x01, 0xED, 0x18, 0xA9, 0x68, ++ 0x8B, 0x00, 0x9B, 0x58, 0x00, 0x9A, 0x48, 0x46, 0x02, 0x43, 0xD2, 0xB2, ++ 0x00, 0x2A, 0x04, 0xD0, 0x00, 0x29, 0x00, 0xD0, 0xCC, 0xE0, 0xD8, 0x22, ++ 0x1A, 0x86, 0x00, 0x22, 0x9A, 0x62, 0x25, 0xE0, 0xA1, 0x49, 0x8B, 0x42, ++ 0x22, 0xD1, 0x02, 0x2A, 0x20, 0xD1, 0x00, 0x21, 0x02, 0x20, 0xFC, 0xF7, ++ 0xA5, 0xFB, 0x1B, 0xE0, 0x9D, 0x4B, 0x1D, 0x68, 0x00, 0x9B, 0x4A, 0x46, ++ 0x13, 0x43, 0xDB, 0xB2, 0x00, 0x2B, 0x04, 0xD0, 0x00, 0x23, 0xAB, 0x62, ++ 0x34, 0x33, 0x01, 0x22, 0xEA, 0x54, 0xAE, 0xF7, 0x53, 0xF8, 0x43, 0x1E, ++ 0x98, 0x41, 0x43, 0x42, 0xC0, 0x22, 0x92, 0x01, 0x13, 0x40, 0x80, 0x22, ++ 0x52, 0x01, 0x94, 0x46, 0x63, 0x44, 0x2B, 0x86, 0x12, 0x23, 0x6B, 0x86, ++ 0x86, 0x4B, 0x1B, 0x68, 0x52, 0x46, 0x98, 0x18, 0x45, 0x68, 0x00, 0x2D, ++ 0x00, 0xD1, 0xD1, 0xE0, 0x42, 0x46, 0x04, 0x3A, 0x51, 0x42, 0x4A, 0x41, ++ 0xD2, 0xB2, 0x31, 0x01, 0x5B, 0x18, 0x99, 0x68, 0x00, 0x68, 0xA8, 0x47, ++ 0x7D, 0x4B, 0x1D, 0x68, 0x33, 0x01, 0xEB, 0x18, 0x85, 0x4A, 0x5B, 0x68, ++ 0x93, 0x42, 0x00, 0xD1, 0xC5, 0xE0, 0x33, 0x01, 0xEB, 0x18, 0x00, 0x22, ++ 0x1A, 0x73, 0x03, 0x32, 0xFF, 0x32, 0xAB, 0x5C, 0x01, 0x3B, 0xAB, 0x54, ++ 0x02, 0x23, 0xFF, 0x33, 0xEA, 0x5C, 0x0F, 0x21, 0xA2, 0x42, 0x00, 0xD1, ++ 0xC5, 0xE0, 0x01, 0x34, 0x0C, 0x40, 0x23, 0x01, 0xEB, 0x18, 0x1B, 0x7B, ++ 0x00, 0x2B, 0xF5, 0xD0, 0x80, 0x23, 0x5B, 0x00, 0xEC, 0x54, 0xA2, 0x42, ++ 0x00, 0xD1, 0xBB, 0xE0, 0x26, 0x00, 0x75, 0x4B, 0xE3, 0x18, 0x1B, 0x01, ++ 0x1B, 0x88, 0x9B, 0x06, 0x5B, 0x0F, 0x98, 0x46, 0x03, 0x3B, 0x02, 0x2B, ++ 0x00, 0xD9, 0xAF, 0xE0, 0xFB, 0xF7, 0x70, 0xFD, 0x00, 0x90, 0x01, 0x90, ++ 0x3A, 0x68, 0x00, 0x23, 0x01, 0x21, 0x91, 0x42, 0x5B, 0x41, 0xDB, 0xB2, ++ 0x99, 0x46, 0x23, 0x01, 0x9A, 0x46, 0xE9, 0x18, 0x4B, 0x68, 0x69, 0x48, ++ 0x83, 0x42, 0x62, 0xD0, 0x00, 0xD9, 0x63, 0xE7, 0x67, 0x4A, 0x93, 0x42, ++ 0x88, 0xD0, 0x63, 0x4A, 0x93, 0x42, 0x00, 0xD0, 0x56, 0xE7, 0x65, 0x4B, ++ 0x1D, 0x68, 0x00, 0x23, 0xAB, 0x62, 0x51, 0x33, 0x01, 0x22, 0xEA, 0x54, ++ 0xAD, 0xF7, 0xDE, 0xFF, 0x00, 0x28, 0x05, 0xD0, 0x80, 0x23, 0x9B, 0x01, ++ 0xAB, 0x85, 0x06, 0x23, 0xEB, 0x85, 0x8F, 0xE7, 0x50, 0x4B, 0x1B, 0x68, ++ 0x02, 0x2B, 0x0B, 0xD0, 0x00, 0x9B, 0x4A, 0x46, 0x13, 0x43, 0xDB, 0xB2, ++ 0x00, 0x2B, 0x1C, 0xD1, 0x80, 0x23, 0x1B, 0x01, 0xAB, 0x85, 0x12, 0x23, ++ 0xEB, 0x85, 0x7F, 0xE7, 0x55, 0x4B, 0xEB, 0x61, 0x01, 0x9B, 0x00, 0x2B, ++ 0x03, 0xD1, 0xFD, 0xF7, 0x13, 0xFA, 0x01, 0x28, 0x07, 0xD9, 0x00, 0x9A, ++ 0xD3, 0x02, 0xAB, 0x85, 0x09, 0x23, 0x9B, 0x1A, 0x5B, 0x00, 0xEB, 0x85, ++ 0x6E, 0xE7, 0x80, 0x23, 0x5B, 0x00, 0xAB, 0x85, 0xEE, 0x3B, 0xEB, 0x85, ++ 0x68, 0xE7, 0xFD, 0xF7, 0x41, 0xF9, 0x01, 0x28, 0x00, 0xD8, 0x63, 0xE7, ++ 0x80, 0x23, 0xDB, 0x01, 0xAB, 0x85, 0x08, 0x23, 0xEB, 0x85, 0x5D, 0xE7, ++ 0xC8, 0x22, 0x92, 0x00, 0x1A, 0x86, 0x30, 0xE7, 0x01, 0x2A, 0x00, 0xD9, ++ 0x56, 0xE7, 0x01, 0x9B, 0x00, 0x2B, 0x00, 0xD1, 0x52, 0xE7, 0x23, 0x01, ++ 0xED, 0x18, 0xAB, 0x68, 0x9B, 0x00, 0x3E, 0x4A, 0x94, 0x46, 0x63, 0x44, ++ 0x1B, 0x68, 0xC0, 0x22, 0x12, 0x01, 0xDA, 0x66, 0x46, 0xE7, 0x02, 0x2A, ++ 0x00, 0xD0, 0x43, 0xE7, 0x23, 0x01, 0xED, 0x18, 0x2B, 0x7A, 0x9B, 0x00, ++ 0x37, 0x4A, 0x9D, 0x58, 0xAF, 0x23, 0xEB, 0x5C, 0x00, 0x2B, 0x03, 0xD1, ++ 0x35, 0x4B, 0x1B, 0x78, 0x01, 0x2B, 0x09, 0xD0, 0xA0, 0x23, 0xEB, 0x5C, ++ 0x02, 0x2B, 0x00, 0xD0, 0x30, 0xE7, 0x01, 0x21, 0x02, 0x20, 0xFC, 0xF7, ++ 0xB5, 0xFA, 0x2B, 0xE7, 0xFF, 0xF7, 0x92, 0xFA, 0x00, 0x23, 0x2D, 0x4A, ++ 0x13, 0x70, 0xEF, 0xE7, 0x2C, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, ++ 0x00, 0x20, 0x98, 0x47, 0x30, 0xE7, 0x24, 0x4B, 0x1B, 0x68, 0x00, 0x2B, ++ 0x00, 0xD1, 0x34, 0xE7, 0x11, 0x22, 0x9A, 0x75, 0x31, 0xE7, 0xFB, 0xF7, ++ 0x93, 0xFB, 0x11, 0xE0, 0x80, 0x20, 0x80, 0x00, 0x7A, 0xF7, 0xE2, 0xFD, ++ 0x13, 0xE0, 0x80, 0x23, 0x5B, 0x00, 0xEC, 0x54, 0x81, 0x23, 0x5B, 0x00, ++ 0xEB, 0x5C, 0x00, 0x2B, 0x04, 0xD1, 0x05, 0x33, 0xFF, 0x33, 0xEB, 0x58, ++ 0x00, 0x2B, 0xEA, 0xD0, 0x07, 0x4B, 0x1A, 0x68, 0x81, 0x23, 0x5B, 0x00, ++ 0xD3, 0x5C, 0x00, 0x2B, 0xE6, 0xD0, 0x02, 0xB0, 0x1C, 0xBC, 0x90, 0x46, ++ 0x99, 0x46, 0xA2, 0x46, 0xF0, 0xBD, 0xC0, 0x46, 0x80, 0x2A, 0x16, 0x00, ++ 0x0C, 0xE7, 0x10, 0x00, 0xF4, 0xE1, 0x10, 0x00, 0x50, 0xE0, 0x10, 0x00, ++ 0x31, 0xC3, 0x0A, 0x00, 0xE1, 0xA1, 0x10, 0x00, 0xE9, 0x8F, 0x0C, 0x00, ++ 0xCD, 0x05, 0x0D, 0x00, 0xF0, 0x29, 0x16, 0x00, 0x5D, 0x74, 0x0B, 0x00, ++ 0x20, 0x27, 0x16, 0x00, 0xD9, 0xEA, 0x0A, 0x00, 0x00, 0x10, 0x06, 0x04, ++ 0x11, 0x6F, 0x0B, 0x00, 0x99, 0xCA, 0x0A, 0x00, 0x28, 0x27, 0x16, 0x00, ++ 0x01, 0x00, 0x10, 0x00, 0x84, 0x29, 0x16, 0x00, 0x38, 0x27, 0x16, 0x00, ++ 0xD8, 0xE6, 0x10, 0x00, 0x28, 0x19, 0x16, 0x00, 0x10, 0xB5, 0x04, 0x4B, ++ 0x1B, 0x7F, 0x01, 0x2B, 0x00, 0xD0, 0x10, 0xBD, 0x02, 0x4B, 0x98, 0x47, ++ 0xFB, 0xE7, 0xC0, 0x46, 0x24, 0x2A, 0x16, 0x00, 0x69, 0x44, 0x0D, 0x00, ++ 0x10, 0xB5, 0x05, 0x4B, 0x80, 0x22, 0xD2, 0x03, 0x1A, 0x60, 0x80, 0x20, ++ 0x40, 0x00, 0x7A, 0xF7, 0xAF, 0xF8, 0xFF, 0xF7, 0xE7, 0xFF, 0x10, 0xBD, ++ 0x08, 0x41, 0x04, 0x40, 0x70, 0xB5, 0x2D, 0x4B, 0x1B, 0x68, 0xC0, 0x22, ++ 0x92, 0x02, 0x13, 0x42, 0x16, 0xD1, 0x5A, 0x03, 0x1E, 0xD4, 0x1A, 0x03, ++ 0x2D, 0xD4, 0xDA, 0x02, 0x34, 0xD4, 0x9A, 0x02, 0x36, 0xD4, 0x5A, 0x02, ++ 0x38, 0xD4, 0xDA, 0x01, 0x39, 0xD4, 0x9A, 0x01, 0x3E, 0xD4, 0x5B, 0x01, ++ 0x0F, 0xD5, 0xFD, 0xF7, 0x1B, 0xFF, 0x22, 0x4B, 0x80, 0x22, 0xD2, 0x04, ++ 0x1A, 0x60, 0x08, 0xE0, 0x20, 0x4D, 0x91, 0x24, 0xE4, 0x00, 0x00, 0x23, ++ 0x2B, 0x51, 0x84, 0xF7, 0x7F, 0xFB, 0x1E, 0x4B, 0x2B, 0x51, 0x70, 0xBD, ++ 0x1D, 0x4B, 0x1C, 0x78, 0xFE, 0xF7, 0x84, 0xFE, 0x02, 0x2C, 0x04, 0xD0, ++ 0x17, 0x4B, 0x80, 0x22, 0xD2, 0x02, 0x1A, 0x60, 0xF3, 0xE7, 0x19, 0x4B, ++ 0x01, 0x22, 0x1A, 0x70, 0x84, 0xF7, 0x32, 0xFB, 0xED, 0xE7, 0x12, 0x4B, ++ 0x80, 0x22, 0x12, 0x03, 0x1A, 0x60, 0x80, 0x20, 0x40, 0x00, 0x7A, 0xF7, ++ 0x3F, 0xFD, 0xE4, 0xE7, 0x01, 0x20, 0x84, 0xF7, 0x3D, 0xFB, 0xE0, 0xE7, ++ 0x02, 0x20, 0x84, 0xF7, 0x39, 0xFB, 0xDC, 0xE7, 0xFF, 0xF7, 0xA6, 0xFF, ++ 0xD9, 0xE7, 0xFA, 0xF7, 0xF1, 0xFD, 0x07, 0x4B, 0x80, 0x22, 0x52, 0x04, ++ 0x1A, 0x60, 0xD2, 0xE7, 0xFA, 0xF7, 0x9A, 0xFF, 0x03, 0x4B, 0x80, 0x22, ++ 0x92, 0x04, 0x1A, 0x60, 0xCB, 0xE7, 0xC0, 0x46, 0x1C, 0x41, 0x04, 0x40, ++ 0x08, 0x41, 0x04, 0x40, 0x28, 0x19, 0x16, 0x00, 0x31, 0x6D, 0x10, 0x00, ++ 0xE0, 0x1D, 0x16, 0x00, 0xE1, 0x1D, 0x16, 0x00, 0x10, 0xB5, 0x04, 0x4B, ++ 0x80, 0x22, 0x12, 0x03, 0x1A, 0x60, 0x80, 0x20, 0x40, 0x00, 0x7A, 0xF7, ++ 0x0F, 0xFD, 0x10, 0xBD, 0x08, 0x41, 0x04, 0x40, 0x10, 0xB5, 0x09, 0x4B, ++ 0xDB, 0x7F, 0x00, 0x2B, 0x08, 0xD0, 0x00, 0x28, 0x01, 0xD1, 0x00, 0x29, ++ 0x04, 0xD0, 0x01, 0x20, 0x80, 0xF7, 0xD6, 0xFF, 0x84, 0xF7, 0x00, 0xFD, ++ 0x03, 0x49, 0x40, 0x22, 0x0B, 0x6B, 0x1A, 0x42, 0xFC, 0xD0, 0x10, 0xBD, ++ 0x3C, 0x95, 0x16, 0x00, 0x00, 0x60, 0x50, 0x40, 0x70, 0xB5, 0x82, 0xB0, ++ 0x27, 0x4A, 0xD3, 0x69, 0x0F, 0x24, 0xA3, 0x43, 0xD3, 0x61, 0x26, 0x4B, ++ 0x99, 0x68, 0x80, 0x20, 0x01, 0x43, 0x99, 0x60, 0x59, 0x68, 0x01, 0x43, ++ 0x59, 0x60, 0x19, 0x68, 0x01, 0x43, 0x19, 0x60, 0x13, 0x69, 0xA3, 0x43, ++ 0x13, 0x61, 0x69, 0x46, 0x01, 0xA8, 0xA4, 0xF7, 0xEF, 0xFC, 0x01, 0x9C, ++ 0x00, 0x9B, 0x1E, 0x00, 0x7A, 0x36, 0x9C, 0x22, 0x92, 0x00, 0x96, 0x42, ++ 0x19, 0xD9, 0xF8, 0x3B, 0xFF, 0x3B, 0x1E, 0x00, 0x01, 0x34, 0x24, 0x01, ++ 0x24, 0x09, 0x80, 0x25, 0x2D, 0x05, 0x69, 0x46, 0x01, 0xA8, 0xA4, 0xF7, ++ 0xDB, 0xFC, 0x01, 0x9A, 0xA3, 0x1A, 0x1B, 0x01, 0x1B, 0x09, 0xAB, 0x42, ++ 0xF5, 0xD9, 0x12, 0x1B, 0x12, 0x01, 0xF2, 0xD0, 0x00, 0x9B, 0xB3, 0x42, ++ 0xEF, 0xD3, 0x02, 0xB0, 0x70, 0xBD, 0xB3, 0x42, 0xE9, 0xD2, 0x80, 0x25, ++ 0x2D, 0x05, 0x02, 0xE0, 0x00, 0x9B, 0xB3, 0x42, 0xF5, 0xD2, 0x69, 0x46, ++ 0x01, 0xA8, 0xA4, 0xF7, 0xC1, 0xFC, 0x01, 0x9A, 0xA3, 0x1A, 0x1B, 0x01, ++ 0x1B, 0x09, 0xAB, 0x42, 0xF2, 0xD9, 0x12, 0x1B, 0x12, 0x01, 0xEF, 0xD0, ++ 0xE7, 0xE7, 0xC0, 0x46, 0x00, 0x30, 0x50, 0x40, 0x00, 0x40, 0x50, 0x40, ++ 0x70, 0xB5, 0x10, 0x4B, 0x9A, 0x69, 0x10, 0x4B, 0x1A, 0x42, 0x0A, 0xD1, ++ 0x0F, 0x4D, 0x10, 0x4C, 0x29, 0x68, 0x00, 0x20, 0xFA, 0xF7, 0xD0, 0xFC, ++ 0x7B, 0xF7, 0x96, 0xFD, 0x23, 0x68, 0x01, 0x2B, 0xF6, 0xD0, 0x0C, 0x4A, ++ 0x13, 0x68, 0x01, 0x33, 0x13, 0x60, 0x0B, 0x4B, 0x1B, 0x68, 0x03, 0x3B, ++ 0x01, 0x2B, 0x00, 0xD9, 0x70, 0xBD, 0x03, 0x4A, 0x80, 0x23, 0x1B, 0x02, ++ 0x91, 0x69, 0x0B, 0x43, 0x93, 0x61, 0xF7, 0xE7, 0x3C, 0x95, 0x16, 0x00, ++ 0x01, 0x20, 0x00, 0x00, 0x58, 0xE6, 0x10, 0x00, 0x5C, 0xE6, 0x10, 0x00, ++ 0x20, 0xE6, 0x10, 0x00, 0x50, 0xE0, 0x10, 0x00, 0x02, 0x38, 0x01, 0x28, ++ 0x11, 0xD8, 0x09, 0x4A, 0x80, 0x23, 0x5B, 0x00, 0x08, 0x21, 0xD1, 0x50, ++ 0x07, 0x49, 0x8B, 0x68, 0x07, 0x4A, 0x1A, 0x40, 0x80, 0x23, 0x9B, 0x02, ++ 0x13, 0x43, 0x8B, 0x60, 0x22, 0x22, 0x0B, 0x6B, 0x13, 0x40, 0x02, 0x2B, ++ 0xFB, 0xD1, 0x70, 0x47, 0x00, 0x00, 0x50, 0x40, 0x00, 0x60, 0x50, 0x40, ++ 0xFF, 0xFF, 0xFB, 0xFF, 0x70, 0xB5, 0xA6, 0xF7, 0x3D, 0xFF, 0x04, 0x1E, ++ 0x0D, 0xD1, 0x1A, 0x4B, 0x18, 0x68, 0x00, 0x28, 0x09, 0xD0, 0xEF, 0xF3, ++ 0x10, 0x83, 0xDB, 0x07, 0x17, 0xD4, 0x72, 0xB6, 0x3E, 0x23, 0xC3, 0x5C, ++ 0x00, 0x2B, 0x02, 0xD0, 0x62, 0xB6, 0x20, 0x00, 0x70, 0xBD, 0x13, 0x4B, ++ 0x1D, 0x68, 0x00, 0x21, 0xCF, 0xF7, 0x7A, 0xFC, 0x2B, 0x6B, 0x5B, 0x00, ++ 0x6A, 0x68, 0x9B, 0x18, 0x1B, 0x01, 0x1B, 0x09, 0x0E, 0x4A, 0x13, 0x60, ++ 0x0E, 0x4B, 0x98, 0x47, 0xEC, 0xE7, 0x3E, 0x23, 0xC3, 0x5C, 0x00, 0x2B, ++ 0xE9, 0xD1, 0x09, 0x4B, 0x1D, 0x68, 0x00, 0x21, 0xCF, 0xF7, 0x66, 0xFC, ++ 0x2B, 0x6B, 0x5B, 0x00, 0x6A, 0x68, 0x9B, 0x18, 0x1B, 0x01, 0x1B, 0x09, ++ 0x04, 0x4A, 0x13, 0x60, 0x04, 0x4B, 0x98, 0x47, 0xD9, 0xE7, 0xC0, 0x46, ++ 0x28, 0x27, 0x16, 0x00, 0x24, 0x27, 0x16, 0x00, 0x18, 0x2C, 0x16, 0x00, ++ 0x15, 0xE6, 0x0A, 0x00, 0x10, 0xB5, 0xA5, 0xF7, 0xC7, 0xFA, 0x00, 0x28, ++ 0x0F, 0xD1, 0x0B, 0x4B, 0x19, 0x68, 0x00, 0x29, 0x0B, 0xD0, 0x0A, 0x4B, ++ 0xCB, 0x61, 0x0A, 0x4B, 0x1C, 0x00, 0x41, 0x34, 0xFF, 0x34, 0x1A, 0x78, ++ 0x09, 0x2A, 0x03, 0xD0, 0x40, 0x33, 0xA3, 0x42, 0xF9, 0xD1, 0x10, 0xBD, ++ 0x0B, 0x69, 0x05, 0x4A, 0x94, 0x46, 0x63, 0x44, 0x0B, 0x61, 0xF8, 0xE7, ++ 0x18, 0x27, 0x16, 0x00, 0x51, 0x04, 0x10, 0x00, 0x70, 0xA6, 0x16, 0x00, ++ 0x78, 0xEC, 0xFF, 0xFF, 0x10, 0xB5, 0x02, 0x00, 0x0C, 0x00, 0x01, 0x23, ++ 0x00, 0x21, 0x03, 0x48, 0x7A, 0xF7, 0xC2, 0xFF, 0x04, 0x70, 0xCC, 0xF7, ++ 0x1F, 0xFE, 0x10, 0xBD, 0x01, 0x11, 0x00, 0x00, 0x10, 0xB5, 0x02, 0x00, ++ 0x0C, 0x00, 0x01, 0x23, 0x00, 0x21, 0x03, 0x48, 0x7A, 0xF7, 0xB4, 0xFF, ++ 0x04, 0x70, 0xCC, 0xF7, 0x11, 0xFE, 0x10, 0xBD, 0x02, 0x11, 0x00, 0x00, ++ 0x10, 0xB5, 0x06, 0x23, 0x13, 0x4A, 0x00, 0x21, 0x13, 0x48, 0x7A, 0xF7, ++ 0xA7, 0xFF, 0x13, 0x4A, 0x2D, 0x23, 0xD3, 0x5C, 0x1B, 0x09, 0x12, 0x4A, ++ 0x12, 0x78, 0x02, 0x2A, 0x0B, 0xD0, 0x01, 0x2A, 0x10, 0xD0, 0x0E, 0x4A, ++ 0x2D, 0x23, 0xD3, 0x5C, 0x03, 0x71, 0x00, 0x23, 0x03, 0x70, 0xCC, 0xF7, ++ 0xF5, 0xFD, 0x00, 0x20, 0x10, 0xBD, 0x0B, 0x4A, 0xD2, 0x5C, 0x80, 0x23, ++ 0x9B, 0x00, 0x13, 0x43, 0x43, 0x80, 0xEE, 0xE7, 0x08, 0x4A, 0xD2, 0x5C, ++ 0x80, 0x23, 0x5B, 0x00, 0x13, 0x43, 0x43, 0x80, 0xE7, 0xE7, 0xC0, 0x46, ++ 0x2D, 0x0C, 0x00, 0x00, 0x01, 0x11, 0x00, 0x00, 0x60, 0x92, 0x16, 0x00, ++ 0xB4, 0xE5, 0x10, 0x00, 0x30, 0xE0, 0x10, 0x00, 0x28, 0xE0, 0x10, 0x00, ++ 0x10, 0xB5, 0x03, 0x00, 0x08, 0x00, 0x19, 0x78, 0x03, 0x4A, 0x2D, 0x23, ++ 0xD1, 0x54, 0x00, 0x21, 0xFF, 0xF7, 0xB2, 0xFF, 0x00, 0x20, 0x10, 0xBD, ++ 0x60, 0x92, 0x16, 0x00, 0x70, 0xB5, 0x82, 0xB0, 0x04, 0x00, 0x0D, 0x00, ++ 0xD1, 0xF7, 0x96, 0xFF, 0x06, 0x00, 0x2C, 0x4B, 0x99, 0x6F, 0x00, 0x29, ++ 0x15, 0xD0, 0xF8, 0x22, 0x20, 0x00, 0xD1, 0xF7, 0xBB, 0xFF, 0x00, 0x21, ++ 0x00, 0x28, 0x0A, 0xD1, 0x26, 0x4A, 0x30, 0x23, 0xD3, 0x5C, 0x01, 0x2B, ++ 0x21, 0xD0, 0x28, 0x00, 0xFF, 0xF7, 0x86, 0xFF, 0x00, 0x20, 0x02, 0xB0, ++ 0x70, 0xBD, 0x21, 0x4B, 0x98, 0x6F, 0x7B, 0xF7, 0xBF, 0xF8, 0xFF, 0x20, ++ 0x06, 0x40, 0xF8, 0x2E, 0x00, 0xD9, 0xF8, 0x26, 0x70, 0x1C, 0x00, 0x21, ++ 0x7B, 0xF7, 0x12, 0xF8, 0x1A, 0x4B, 0x98, 0x67, 0x07, 0x21, 0x00, 0x28, ++ 0xE2, 0xD0, 0x32, 0x00, 0x21, 0x00, 0xD1, 0xF7, 0x2F, 0xFE, 0x16, 0x4B, ++ 0x9B, 0x6F, 0x00, 0x22, 0x9A, 0x55, 0x00, 0x21, 0xD8, 0xE7, 0x7F, 0x33, ++ 0x5B, 0x00, 0x2F, 0x22, 0x00, 0x21, 0x12, 0x48, 0x7A, 0xF7, 0x2A, 0xFF, ++ 0x06, 0x00, 0x01, 0xA9, 0x0D, 0x70, 0x2D, 0x0A, 0x4D, 0x70, 0xF8, 0x23, ++ 0x8B, 0x70, 0x03, 0x22, 0xD1, 0xF7, 0x18, 0xFE, 0xF0, 0x1C, 0xF8, 0x22, ++ 0x21, 0x00, 0xD1, 0xF7, 0x13, 0xFE, 0x0A, 0x4B, 0x01, 0x22, 0x1A, 0x70, ++ 0x30, 0x00, 0x0C, 0x38, 0x08, 0x4B, 0x98, 0x47, 0x08, 0x4B, 0x5B, 0x7F, ++ 0x5B, 0xB2, 0x04, 0x2B, 0xBE, 0xDC, 0x01, 0x33, 0x05, 0x4A, 0x53, 0x77, ++ 0xBA, 0xE7, 0xC0, 0x46, 0x68, 0x9E, 0x16, 0x00, 0x03, 0x11, 0x00, 0x00, ++ 0x68, 0xE6, 0x10, 0x00, 0xA5, 0x4B, 0x0D, 0x00, 0x24, 0x2A, 0x16, 0x00, ++ 0xF8, 0xB5, 0x04, 0x00, 0x0D, 0x00, 0x16, 0x00, 0x1F, 0x00, 0x02, 0x20, ++ 0x79, 0xF7, 0x46, 0xFE, 0x6B, 0x1E, 0x1C, 0x70, 0x63, 0x1E, 0x03, 0x2B, ++ 0x22, 0xD8, 0x04, 0x2C, 0x10, 0xD0, 0x68, 0x1E, 0x16, 0x4B, 0x18, 0x61, ++ 0x1E, 0x83, 0x5F, 0x61, 0x1B, 0x7F, 0xFF, 0x2B, 0x25, 0xD1, 0x13, 0x4B, ++ 0x00, 0x22, 0x1A, 0x77, 0x71, 0x1C, 0x1A, 0x68, 0x54, 0x68, 0x11, 0x4A, ++ 0xA0, 0x47, 0x1C, 0xE0, 0x2B, 0x78, 0x2F, 0x2B, 0xEB, 0xD1, 0x0F, 0x4B, ++ 0x1B, 0x78, 0x00, 0x2B, 0xE7, 0xD0, 0x19, 0x23, 0x2B, 0x70, 0xE2, 0x33, ++ 0x6B, 0x70, 0x0B, 0x4B, 0x00, 0x22, 0x1A, 0x70, 0xFD, 0x26, 0xDE, 0xE7, ++ 0x09, 0x4D, 0x00, 0x23, 0x00, 0x22, 0x01, 0x21, 0x20, 0x00, 0xEE, 0x6E, ++ 0xB0, 0x47, 0xED, 0x6E, 0x00, 0x23, 0x00, 0x22, 0x01, 0x21, 0x20, 0x00, ++ 0xA8, 0x47, 0xF8, 0xBD, 0x58, 0x1E, 0x16, 0x00, 0x19, 0x74, 0x08, 0x00, ++ 0x68, 0xE6, 0x10, 0x00, 0x28, 0x19, 0x16, 0x00, 0xF0, 0xB5, 0xDE, 0x46, ++ 0x57, 0x46, 0x4E, 0x46, 0xC0, 0xB5, 0x86, 0xB0, 0x04, 0x00, 0x0E, 0x00, ++ 0x03, 0x92, 0xCE, 0xF7, 0x93, 0xFE, 0x07, 0x00, 0xB8, 0x4B, 0x1D, 0x25, ++ 0x5D, 0x57, 0x2B, 0x00, 0x80, 0x33, 0x00, 0xD1, 0x61, 0xE1, 0x01, 0x3D, ++ 0x6D, 0xB2, 0xB4, 0x4B, 0x5D, 0x77, 0x00, 0x28, 0x00, 0xD1, 0x18, 0xE1, ++ 0x00, 0x2D, 0x00, 0xDA, 0x59, 0xE1, 0x80, 0x78, 0x0F, 0x23, 0x18, 0x40, ++ 0x08, 0x28, 0x5F, 0xD8, 0x83, 0x00, 0xAE, 0x4A, 0xD3, 0x58, 0x9F, 0x46, ++ 0x05, 0x23, 0x99, 0x46, 0x67, 0xE0, 0x06, 0x28, 0x1E, 0xD0, 0x01, 0x2E, ++ 0x00, 0xD8, 0x3B, 0xE1, 0x03, 0x9A, 0x53, 0x78, 0x1B, 0x02, 0x12, 0x78, ++ 0x13, 0x43, 0x0B, 0x2B, 0x00, 0xD9, 0x22, 0xE1, 0xA5, 0x4A, 0xD2, 0x18, ++ 0x12, 0x7E, 0x00, 0x2A, 0x00, 0xD1, 0x2D, 0xE1, 0xA2, 0x04, 0x37, 0xD4, ++ 0xA2, 0x4A, 0x94, 0x42, 0x34, 0xD0, 0x27, 0xD8, 0xA1, 0x4A, 0x94, 0x42, ++ 0x30, 0xD0, 0xA1, 0x4A, 0x94, 0x42, 0x00, 0xD0, 0x20, 0xE1, 0x2B, 0xE0, ++ 0x05, 0x2E, 0x00, 0xD8, 0x1C, 0xE1, 0x9E, 0x4D, 0x00, 0x23, 0x99, 0x46, ++ 0x07, 0xE0, 0x01, 0x23, 0x9C, 0x46, 0xE1, 0x44, 0x07, 0x35, 0x4B, 0x46, ++ 0x07, 0x2B, 0x00, 0xD1, 0x10, 0xE1, 0x2B, 0x78, 0x00, 0x2B, 0xF4, 0xD0, ++ 0x69, 0x1C, 0x06, 0x22, 0x03, 0x98, 0xD1, 0xF7, 0x2D, 0xFD, 0x00, 0x28, ++ 0xED, 0xD1, 0x4B, 0x46, 0x1B, 0x02, 0x01, 0x22, 0x13, 0x43, 0x9B, 0xB2, ++ 0x99, 0x46, 0x26, 0xE0, 0x90, 0x4A, 0x94, 0x42, 0x04, 0xD8, 0x90, 0x4A, ++ 0x94, 0x42, 0x00, 0xD8, 0xF8, 0xE0, 0x03, 0xE0, 0x8E, 0x4A, 0x94, 0x42, ++ 0x00, 0xD0, 0xF3, 0xE0, 0x1B, 0x02, 0x04, 0x22, 0x13, 0x43, 0x9B, 0xB2, ++ 0x99, 0x46, 0x14, 0xE0, 0x1B, 0x02, 0x01, 0x22, 0x13, 0x43, 0x9B, 0xB2, ++ 0x99, 0x46, 0x0E, 0xE0, 0x87, 0x4B, 0xDD, 0x6E, 0x00, 0x23, 0x00, 0x22, ++ 0x21, 0x00, 0xA8, 0x47, 0xAF, 0xE0, 0x03, 0x23, 0x99, 0x46, 0x04, 0xE0, ++ 0x02, 0x23, 0x99, 0x46, 0x01, 0xE0, 0x00, 0x23, 0x99, 0x46, 0x0E, 0x23, ++ 0x02, 0xAA, 0x94, 0x46, 0x63, 0x44, 0x00, 0x22, 0x1A, 0x80, 0x7E, 0x4B, ++ 0x92, 0x46, 0x9C, 0x42, 0x59, 0xD0, 0x00, 0x2E, 0x00, 0xD1, 0xAD, 0xE0, ++ 0x7D, 0x68, 0x00, 0x2D, 0x00, 0xD1, 0x9C, 0xE0, 0xBB, 0x78, 0x5B, 0x06, ++ 0x65, 0xD5, 0xB3, 0xB2, 0x0E, 0x22, 0x02, 0xA9, 0x8C, 0x46, 0x62, 0x44, ++ 0x03, 0x99, 0x00, 0x20, 0xA8, 0x47, 0xC5, 0xB2, 0x01, 0x2D, 0x66, 0xD0, ++ 0x0E, 0x23, 0x02, 0xAA, 0x94, 0x46, 0x63, 0x44, 0x1B, 0x88, 0x22, 0x00, ++ 0x49, 0x46, 0x6F, 0x48, 0x7A, 0xF7, 0x00, 0xFE, 0x81, 0x46, 0x00, 0x2D, ++ 0x07, 0xD0, 0x6A, 0x4B, 0xDB, 0x6E, 0x9B, 0x46, 0x00, 0x23, 0x00, 0x22, ++ 0x21, 0x00, 0x28, 0x00, 0xD8, 0x47, 0x4B, 0x46, 0x00, 0x2B, 0x59, 0xD0, ++ 0x0E, 0x23, 0x02, 0xAA, 0x94, 0x46, 0x63, 0x44, 0x1B, 0x88, 0x00, 0x2B, ++ 0x0F, 0xD0, 0x7B, 0x68, 0x9B, 0x46, 0x00, 0x2B, 0x0B, 0xD0, 0xBB, 0x78, ++ 0x5B, 0x06, 0x51, 0xD5, 0xB3, 0xB2, 0x0E, 0x22, 0x02, 0xA9, 0x8C, 0x46, ++ 0x62, 0x44, 0x03, 0x99, 0x48, 0x46, 0xD8, 0x47, 0xC5, 0xB2, 0x00, 0x2D, ++ 0x06, 0xD0, 0x58, 0x4B, 0xDE, 0x6E, 0x00, 0x23, 0x00, 0x22, 0x21, 0x00, ++ 0x28, 0x00, 0xB0, 0x47, 0x48, 0x46, 0x7A, 0xF7, 0xF9, 0xFD, 0x54, 0x4B, ++ 0x9C, 0x42, 0x4A, 0xD1, 0x53, 0x46, 0x00, 0x2B, 0x47, 0xD0, 0x50, 0x46, ++ 0x7A, 0xF7, 0x3C, 0xFF, 0x43, 0xE0, 0x75, 0x1C, 0x01, 0x21, 0x28, 0x00, ++ 0x7A, 0xF7, 0x92, 0xFE, 0x82, 0x46, 0x03, 0x99, 0x0B, 0x78, 0x03, 0x70, ++ 0x72, 0x1E, 0x42, 0x70, 0x01, 0x31, 0x02, 0x30, 0xD1, 0xF7, 0xAE, 0xFC, ++ 0xEE, 0xB2, 0x49, 0x48, 0x7C, 0xF7, 0xB6, 0xFE, 0x53, 0x46, 0x03, 0x93, ++ 0x8F, 0xE7, 0xB3, 0xB2, 0x00, 0x95, 0x0E, 0x22, 0x02, 0xA9, 0x8C, 0x46, ++ 0x62, 0x44, 0x03, 0x99, 0x00, 0x20, 0x7D, 0xF7, 0x57, 0xF8, 0x05, 0x00, ++ 0x96, 0xE7, 0x21, 0x00, 0x40, 0x48, 0x7C, 0xF7, 0xA3, 0xFE, 0x00, 0x23, ++ 0x12, 0x22, 0x21, 0x00, 0x38, 0x00, 0x3E, 0x4D, 0xA8, 0x47, 0xC8, 0xE7, ++ 0x07, 0x22, 0x21, 0x00, 0x38, 0x00, 0x3B, 0x4D, 0xA8, 0x47, 0xC2, 0xE7, ++ 0xB3, 0xB2, 0x5A, 0x46, 0x00, 0x92, 0x0E, 0x22, 0x62, 0x44, 0x03, 0x99, ++ 0x48, 0x46, 0x7D, 0xF7, 0x3B, 0xF8, 0x05, 0x00, 0xAB, 0xE7, 0x00, 0x23, ++ 0x01, 0x22, 0x21, 0x00, 0x00, 0x20, 0x32, 0x4C, 0xA0, 0x47, 0x06, 0xB0, ++ 0x1C, 0xBC, 0x91, 0x46, 0x9A, 0x46, 0xA3, 0x46, 0xF0, 0xBD, 0x0E, 0x23, ++ 0x02, 0xAA, 0x94, 0x46, 0x63, 0x44, 0x1B, 0x88, 0x22, 0x00, 0x49, 0x46, ++ 0x27, 0x48, 0x7A, 0xF7, 0x71, 0xFD, 0x81, 0x46, 0x04, 0x25, 0x70, 0xE7, ++ 0x0E, 0x23, 0x02, 0xAA, 0x94, 0x46, 0x63, 0x44, 0x1B, 0x88, 0x22, 0x00, ++ 0x49, 0x46, 0x21, 0x48, 0x7A, 0xF7, 0x64, 0xFD, 0x81, 0x46, 0x35, 0x00, ++ 0x6B, 0xE7, 0x22, 0x4A, 0x13, 0x40, 0x1A, 0x00, 0x80, 0x3A, 0x92, 0xB2, ++ 0x06, 0x2A, 0x09, 0xD8, 0x80, 0x3B, 0xD9, 0x00, 0xC9, 0x1A, 0x0F, 0x4A, ++ 0x52, 0x18, 0x24, 0x32, 0x12, 0x78, 0x02, 0x2A, 0x00, 0xD1, 0x11, 0xE7, ++ 0x21, 0x00, 0x1A, 0x48, 0x7C, 0xF7, 0x50, 0xFE, 0x03, 0x9B, 0x02, 0x22, ++ 0x21, 0x00, 0x38, 0x00, 0x14, 0x4C, 0xA0, 0x47, 0xC3, 0xE7, 0x00, 0x28, ++ 0xBB, 0xD0, 0x00, 0x23, 0x07, 0x22, 0x21, 0x00, 0x38, 0x00, 0x10, 0x4C, ++ 0xA0, 0x47, 0xBA, 0xE7, 0x24, 0x2A, 0x16, 0x00, 0x2C, 0xD2, 0x10, 0x00, ++ 0xCC, 0xAA, 0x16, 0x00, 0x2D, 0x0C, 0x00, 0x00, 0x06, 0x04, 0x00, 0x00, ++ 0x1D, 0x04, 0x00, 0x00, 0xF0, 0xAA, 0x16, 0x00, 0x7C, 0x0C, 0x00, 0x00, ++ 0x7A, 0x0C, 0x00, 0x00, 0x05, 0x14, 0x00, 0x00, 0x28, 0x19, 0x16, 0x00, ++ 0x57, 0xFD, 0x00, 0x00, 0x05, 0x11, 0x00, 0x00, 0x14, 0xD2, 0x10, 0x00, ++ 0x20, 0xD2, 0x10, 0x00, 0x7D, 0x4A, 0x0D, 0x00, 0xFF, 0xFC, 0xFF, 0xFF, ++ 0x08, 0xD2, 0x10, 0x00, 0x10, 0xB5, 0x07, 0x20, 0x7B, 0xF7, 0x10, 0xFA, ++ 0x08, 0x4C, 0xA1, 0x7A, 0x20, 0x89, 0x62, 0x68, 0xFF, 0xF7, 0x54, 0xFE, ++ 0x60, 0x68, 0x00, 0x28, 0x03, 0xD0, 0x7A, 0xF7, 0x7F, 0xFE, 0x00, 0x22, ++ 0x62, 0x60, 0x02, 0x48, 0x02, 0x4B, 0x98, 0x47, 0x10, 0xBD, 0xC0, 0x46, ++ 0x58, 0x1E, 0x16, 0x00, 0xA5, 0x73, 0x08, 0x00, 0x30, 0xB5, 0x0C, 0x4C, ++ 0x25, 0x68, 0x29, 0x60, 0x24, 0x68, 0x60, 0x60, 0xA2, 0x60, 0xE3, 0x60, ++ 0x09, 0x4B, 0x0A, 0x4A, 0x98, 0x50, 0x0A, 0x48, 0x1A, 0x58, 0x0A, 0x43, ++ 0x1A, 0x50, 0x04, 0x30, 0x1A, 0x58, 0x11, 0x43, 0x19, 0x50, 0x07, 0x49, ++ 0x5A, 0x58, 0x01, 0x20, 0x02, 0x43, 0x5A, 0x50, 0x30, 0xBD, 0xC0, 0x46, ++ 0xFC, 0xE1, 0x10, 0x00, 0x00, 0x00, 0x07, 0x40, 0x10, 0x10, 0x00, 0x00, ++ 0x1C, 0x10, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x70, 0xB5, 0x0D, 0x00, ++ 0x1A, 0x4C, 0x30, 0x21, 0x61, 0x5C, 0x01, 0x29, 0x04, 0xD0, 0x29, 0x00, ++ 0x18, 0x4C, 0xA0, 0x47, 0x00, 0x20, 0x70, 0xBD, 0x14, 0x0A, 0x84, 0xF7, ++ 0x99, 0xFD, 0x06, 0x1E, 0x1F, 0xD0, 0x6A, 0x88, 0xA9, 0x88, 0x14, 0x4B, ++ 0x9C, 0x46, 0x61, 0x44, 0x00, 0x89, 0x60, 0x44, 0xD1, 0xF7, 0xB8, 0xFB, ++ 0x08, 0x23, 0x00, 0x22, 0x21, 0x00, 0x10, 0x48, 0x7A, 0xF7, 0xBA, 0xFC, ++ 0x33, 0x89, 0x43, 0x60, 0x2B, 0x88, 0x03, 0x80, 0x6B, 0x88, 0x43, 0x80, ++ 0xCC, 0xF7, 0x12, 0xFB, 0x20, 0x00, 0x80, 0x30, 0x01, 0x21, 0x0A, 0x4B, ++ 0x98, 0x47, 0xA8, 0x88, 0x84, 0xF7, 0xCA, 0xFD, 0xD8, 0xE7, 0x08, 0x4B, ++ 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0xEF, 0xE7, ++ 0x68, 0x9E, 0x16, 0x00, 0x49, 0x86, 0x0A, 0x00, 0x00, 0x00, 0x61, 0x40, ++ 0x06, 0x11, 0x00, 0x00, 0xC1, 0xDC, 0x09, 0x00, 0x28, 0x19, 0x16, 0x00, ++ 0x42, 0x7A, 0x12, 0x02, 0x03, 0x7A, 0x13, 0x43, 0x0B, 0x80, 0x83, 0x7A, ++ 0x8B, 0x70, 0x70, 0x47, 0xC2, 0x7A, 0x12, 0x02, 0x83, 0x7A, 0x13, 0x43, ++ 0x4B, 0x80, 0x42, 0x7A, 0x12, 0x02, 0x03, 0x7A, 0x13, 0x43, 0x0B, 0x80, ++ 0x70, 0x47, 0x83, 0x7A, 0x8B, 0x70, 0x42, 0x7A, 0x12, 0x02, 0x03, 0x7A, ++ 0x13, 0x43, 0x0B, 0x80, 0x70, 0x47, 0x00, 0x00, 0x10, 0xB5, 0x03, 0x00, ++ 0x00, 0x22, 0x02, 0x73, 0x0B, 0x30, 0x1A, 0x68, 0x14, 0x68, 0x03, 0x4A, ++ 0x01, 0x21, 0xA0, 0x47, 0x04, 0x20, 0x7A, 0xF7, 0x91, 0xF8, 0x10, 0xBD, ++ 0x59, 0x78, 0x10, 0x00, 0x10, 0xB5, 0x03, 0x00, 0x01, 0x22, 0x02, 0x73, ++ 0x08, 0x30, 0x1A, 0x68, 0x14, 0x68, 0x03, 0x4A, 0xA0, 0x47, 0x04, 0x20, ++ 0x79, 0xF7, 0xAC, 0xFB, 0x10, 0xBD, 0xC0, 0x46, 0x59, 0x78, 0x10, 0x00, ++ 0x10, 0xB5, 0x03, 0x00, 0x02, 0x22, 0x02, 0x73, 0x40, 0x68, 0x1A, 0x68, ++ 0x14, 0x68, 0x01, 0x4A, 0xA0, 0x47, 0x10, 0xBD, 0x59, 0x78, 0x10, 0x00, ++ 0x10, 0xB5, 0x03, 0x00, 0x03, 0x22, 0x02, 0x73, 0x0B, 0x30, 0x1A, 0x68, ++ 0x14, 0x68, 0x02, 0x4A, 0x01, 0x21, 0xA0, 0x47, 0x10, 0xBD, 0xC0, 0x46, ++ 0x59, 0x78, 0x10, 0x00, 0x10, 0xB5, 0x04, 0x00, 0x01, 0x23, 0x10, 0x22, ++ 0x00, 0x21, 0x0B, 0x48, 0x7A, 0xF7, 0x38, 0xFC, 0x00, 0x23, 0x03, 0x70, ++ 0xCC, 0xF7, 0x94, 0xFA, 0x20, 0x00, 0x08, 0x30, 0x02, 0x22, 0x00, 0x21, ++ 0x78, 0xF7, 0xB2, 0xFC, 0xE3, 0x7A, 0xA3, 0x72, 0x20, 0x00, 0xFF, 0xF7, ++ 0xDB, 0xFF, 0x04, 0x20, 0x7A, 0xF7, 0x4A, 0xF8, 0x10, 0xBD, 0xC0, 0x46, ++ 0x03, 0x11, 0x00, 0x00, 0x10, 0xB5, 0x06, 0x20, 0x7B, 0xF7, 0x1A, 0xF9, ++ 0x16, 0x4C, 0x17, 0x49, 0x20, 0x00, 0xFF, 0xF7, 0x83, 0xFF, 0xA4, 0x7A, ++ 0x00, 0x2C, 0x09, 0xD1, 0x12, 0x4C, 0x20, 0x89, 0x00, 0x22, 0x00, 0x21, ++ 0xFF, 0xF7, 0x56, 0xFD, 0x20, 0x00, 0xFF, 0xF7, 0x93, 0xFF, 0x10, 0xBD, ++ 0x0D, 0x4B, 0x18, 0x89, 0xCD, 0xF7, 0x9C, 0xFA, 0x84, 0x42, 0x03, 0xD9, ++ 0x0A, 0x48, 0xFF, 0xF7, 0xC3, 0xFF, 0xF4, 0xE7, 0x08, 0x4C, 0xA0, 0x7A, ++ 0x01, 0x21, 0x7A, 0xF7, 0xCF, 0xFC, 0x60, 0x60, 0x00, 0x28, 0x04, 0xD0, ++ 0x20, 0x00, 0xA1, 0x7A, 0xFF, 0xF7, 0x9C, 0xFF, 0xE7, 0xE7, 0x02, 0x48, ++ 0xFF, 0xF7, 0xB2, 0xFF, 0xE3, 0xE7, 0xC0, 0x46, 0x58, 0x1E, 0x16, 0x00, ++ 0x60, 0x1E, 0x16, 0x00, 0x10, 0xB5, 0x82, 0xB0, 0x04, 0x00, 0x0E, 0x4B, ++ 0x01, 0x93, 0x01, 0x00, 0x08, 0x31, 0x04, 0x22, 0x01, 0xA8, 0xD1, 0xF7, ++ 0xB5, 0xFA, 0x00, 0x28, 0x0B, 0xD0, 0x04, 0x20, 0x79, 0xF7, 0x2A, 0xFB, ++ 0x63, 0x7A, 0x23, 0x72, 0xA3, 0x7A, 0x63, 0x72, 0xE3, 0x7A, 0xA3, 0x72, ++ 0x00, 0x20, 0x02, 0xB0, 0x10, 0xBD, 0x00, 0x22, 0x00, 0x21, 0x03, 0x48, ++ 0xCD, 0xF7, 0x6C, 0xFA, 0x01, 0x20, 0xF6, 0xE7, 0x01, 0x03, 0x0C, 0x00, ++ 0x03, 0x0C, 0x00, 0x00, 0x10, 0xB5, 0x04, 0x00, 0x00, 0x29, 0x0B, 0xD0, ++ 0x01, 0x29, 0x02, 0xD0, 0x03, 0x7B, 0x00, 0x2B, 0x03, 0xD0, 0x20, 0x00, ++ 0xFF, 0xF7, 0x7C, 0xFF, 0x10, 0xBD, 0xFF, 0xF7, 0x3F, 0xFF, 0xFB, 0xE7, ++ 0x03, 0x7B, 0x02, 0x2B, 0x44, 0xD0, 0x0F, 0xD8, 0x00, 0x2B, 0x17, 0xD0, ++ 0x40, 0x7B, 0x02, 0x28, 0x25, 0xD0, 0x03, 0x28, 0x27, 0xD0, 0x01, 0x28, ++ 0x1D, 0xD0, 0xA1, 0x7B, 0x34, 0x4B, 0xDC, 0x6E, 0x00, 0x23, 0x00, 0x22, ++ 0xA0, 0x47, 0xE7, 0xE7, 0x03, 0x2B, 0x59, 0xD1, 0xFF, 0xF7, 0xB4, 0xFF, ++ 0x00, 0x28, 0x51, 0xD0, 0x20, 0x00, 0xFF, 0xF7, 0x21, 0xFF, 0xDD, 0xE7, ++ 0xC3, 0x7A, 0x43, 0x73, 0x5A, 0x1E, 0x02, 0x2A, 0x04, 0xD8, 0x2B, 0x4A, ++ 0xD1, 0x5C, 0xFF, 0xF7, 0x27, 0xFF, 0xD3, 0xE7, 0xFF, 0xF7, 0x4E, 0xFF, ++ 0xD0, 0xE7, 0x05, 0x30, 0x7B, 0xF7, 0x5E, 0xF8, 0xCC, 0xE7, 0x08, 0x20, ++ 0x7B, 0xF7, 0x5A, 0xF8, 0xC8, 0xE7, 0x21, 0x00, 0x08, 0x31, 0x20, 0x00, ++ 0xFF, 0xF7, 0xFD, 0xFE, 0xA1, 0x7A, 0x20, 0x89, 0xCD, 0xF7, 0x2E, 0xFC, ++ 0x60, 0x60, 0x00, 0x28, 0x04, 0xD0, 0xA1, 0x7A, 0x20, 0x00, 0xFF, 0xF7, ++ 0x1B, 0xFF, 0xB7, 0xE7, 0x20, 0x00, 0xFF, 0xF7, 0x31, 0xFF, 0xB3, 0xE7, ++ 0x40, 0x7B, 0x02, 0x28, 0x0E, 0xD0, 0x03, 0x28, 0x15, 0xD0, 0x01, 0x28, ++ 0x06, 0xD0, 0xA1, 0x7B, 0x13, 0x4B, 0xDC, 0x6E, 0x00, 0x23, 0x00, 0x22, ++ 0xA0, 0x47, 0xA5, 0xE7, 0x06, 0x30, 0x7B, 0xF7, 0x33, 0xF8, 0xA1, 0xE7, ++ 0x61, 0x89, 0x20, 0x89, 0x62, 0x68, 0xCD, 0xF7, 0xB9, 0xFB, 0x20, 0x00, ++ 0xFF, 0xF7, 0xDC, 0xFE, 0x98, 0xE7, 0xA1, 0x7A, 0x20, 0x89, 0x62, 0x68, ++ 0xCD, 0xF7, 0x2E, 0xFC, 0x20, 0x00, 0xFF, 0xF7, 0xD3, 0xFE, 0x8F, 0xE7, ++ 0x20, 0x00, 0xFF, 0xF7, 0xFB, 0xFE, 0x8B, 0xE7, 0x03, 0x4B, 0x9B, 0x6E, ++ 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x84, 0xE7, 0xC0, 0x46, ++ 0x28, 0x19, 0x16, 0x00, 0xC8, 0xDF, 0x10, 0x00, 0x70, 0xB5, 0x0C, 0x00, ++ 0x03, 0x05, 0x1B, 0x0D, 0x82, 0x0B, 0x0B, 0x2B, 0x1C, 0xD8, 0x00, 0x2A, ++ 0x4C, 0xD1, 0x19, 0x02, 0x04, 0x22, 0x0A, 0x43, 0x92, 0xB2, 0xF8, 0x21, ++ 0x09, 0x01, 0x08, 0x42, 0x1F, 0xD1, 0xFB, 0x21, 0xFF, 0x2A, 0x46, 0xD0, ++ 0x8C, 0x42, 0x44, 0xD8, 0xFF, 0x23, 0x13, 0x40, 0x02, 0x2B, 0x26, 0xD9, ++ 0x04, 0x2B, 0x26, 0xD1, 0xB3, 0xF7, 0x8A, 0xFC, 0x00, 0x28, 0x3A, 0xD0, ++ 0x25, 0x4B, 0x9C, 0x46, 0x60, 0x44, 0x46, 0xE0, 0x01, 0x2A, 0x31, 0xD0, ++ 0x00, 0x2A, 0x32, 0xD1, 0xF8, 0x22, 0x12, 0x01, 0x10, 0x42, 0x2E, 0xD0, ++ 0x00, 0x21, 0xFF, 0x22, 0x86, 0x2B, 0xE1, 0xD8, 0x00, 0xE0, 0xFB, 0x21, ++ 0x80, 0x3B, 0xDD, 0x00, 0xED, 0x1A, 0x1C, 0x48, 0x40, 0x19, 0x24, 0x30, ++ 0x00, 0x78, 0x02, 0x28, 0xD6, 0xD1, 0x1B, 0x02, 0x01, 0x22, 0x1A, 0x43, ++ 0x92, 0xB2, 0x18, 0x49, 0xD2, 0xE7, 0x00, 0x2B, 0x06, 0xD1, 0x17, 0x4B, ++ 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x10, 0xE0, ++ 0x84, 0xF7, 0xE0, 0xFB, 0x00, 0x28, 0x03, 0xD0, 0x0E, 0x4B, 0x9C, 0x46, ++ 0x60, 0x44, 0x18, 0xE0, 0x10, 0x48, 0x7C, 0xF7, 0xEB, 0xFB, 0x04, 0xE0, ++ 0x01, 0x2A, 0x02, 0xD1, 0x0B, 0x4B, 0x9C, 0x42, 0xEE, 0xD9, 0x01, 0x23, ++ 0x1A, 0x22, 0x00, 0x21, 0x0B, 0x48, 0x7A, 0xF7, 0xDB, 0xFA, 0x01, 0x25, ++ 0x05, 0x70, 0xCC, 0xF7, 0x37, 0xF9, 0x01, 0x21, 0x20, 0x00, 0x7A, 0xF7, ++ 0xA5, 0xFB, 0x07, 0x4B, 0x9D, 0x77, 0x70, 0xBD, 0x00, 0x00, 0x61, 0x40, ++ 0xCC, 0xAA, 0x16, 0x00, 0xFD, 0x03, 0x00, 0x00, 0x28, 0x19, 0x16, 0x00, ++ 0x50, 0xD2, 0x10, 0x00, 0x03, 0x11, 0x00, 0x00, 0x24, 0x2A, 0x16, 0x00, ++ 0x10, 0xB5, 0x08, 0x20, 0x7A, 0xF7, 0xBA, 0xFF, 0x10, 0x4C, 0x11, 0x49, ++ 0x20, 0x00, 0xFF, 0xF7, 0x2B, 0xFE, 0x61, 0x89, 0x00, 0x29, 0x0E, 0xD0, ++ 0x20, 0x89, 0xFF, 0xF7, 0x77, 0xFF, 0x60, 0x60, 0x00, 0x28, 0x04, 0xD0, ++ 0x09, 0x48, 0x41, 0x89, 0xFF, 0xF7, 0x52, 0xFE, 0x0C, 0xE0, 0x20, 0x00, ++ 0xFF, 0xF7, 0x68, 0xFE, 0x08, 0xE0, 0x05, 0x4C, 0x20, 0x89, 0x00, 0x22, ++ 0x00, 0x21, 0xCD, 0xF7, 0x01, 0xFB, 0x20, 0x00, 0xFF, 0xF7, 0x24, 0xFE, ++ 0x10, 0xBD, 0xC0, 0x46, 0x58, 0x1E, 0x16, 0x00, 0x60, 0x1E, 0x16, 0x00, ++ 0x10, 0xB5, 0x7F, 0xF7, 0xBD, 0xFD, 0x06, 0x49, 0x06, 0x20, 0x7A, 0xF7, ++ 0x47, 0xFF, 0x05, 0x49, 0x07, 0x20, 0x7A, 0xF7, 0x43, 0xFF, 0x04, 0x49, ++ 0x08, 0x20, 0x7A, 0xF7, 0x3F, 0xFF, 0x10, 0xBD, 0xA5, 0x77, 0x10, 0x00, ++ 0xB9, 0x75, 0x10, 0x00, 0x65, 0x7A, 0x10, 0x00, 0x10, 0xB5, 0x0A, 0x00, ++ 0x41, 0x23, 0x00, 0x21, 0x0C, 0x48, 0x7A, 0xF7, 0x7B, 0xFA, 0x04, 0x00, ++ 0x01, 0x30, 0x28, 0x22, 0x0A, 0x49, 0xD1, 0xF7, 0x6D, 0xF9, 0xE2, 0x79, ++ 0x2F, 0x23, 0x13, 0x40, 0xE3, 0x71, 0x20, 0x00, 0x29, 0x30, 0x18, 0x22, ++ 0x00, 0x21, 0x78, 0xF7, 0xEF, 0xFA, 0x00, 0x23, 0x23, 0x70, 0x20, 0x00, ++ 0xCC, 0xF7, 0xC6, 0xF8, 0x00, 0x20, 0x10, 0xBD, 0x01, 0x11, 0x00, 0x00, ++ 0xA4, 0xB5, 0x0D, 0x00, 0xF0, 0xB5, 0xC6, 0x46, 0x00, 0xB5, 0x0D, 0x00, ++ 0x90, 0x46, 0x06, 0x0A, 0xB2, 0x00, 0x11, 0x4B, 0xD7, 0x58, 0x0C, 0x23, ++ 0x03, 0x22, 0x00, 0x21, 0x0F, 0x48, 0x7A, 0xF7, 0x51, 0xFA, 0x04, 0x00, ++ 0x43, 0x46, 0x03, 0x70, 0x2D, 0x02, 0x81, 0x35, 0xFF, 0x35, 0x75, 0x19, ++ 0x45, 0x80, 0x00, 0x23, 0x83, 0x72, 0x88, 0x23, 0xFF, 0x33, 0xFB, 0x5C, ++ 0xC3, 0x72, 0x39, 0x00, 0x72, 0x31, 0x04, 0x30, 0x06, 0x22, 0xD1, 0xF7, ++ 0x35, 0xF9, 0x20, 0x00, 0xCC, 0xF7, 0x9A, 0xF8, 0x04, 0xBC, 0x90, 0x46, ++ 0xF0, 0xBD, 0xC0, 0x46, 0x64, 0xA2, 0x16, 0x00, 0x03, 0x11, 0x00, 0x00, ++ 0x70, 0xB5, 0x05, 0x00, 0x0E, 0x00, 0x04, 0x78, 0x02, 0x2C, 0x21, 0xD8, ++ 0x00, 0x2C, 0x04, 0xD1, 0x14, 0x4A, 0x30, 0x23, 0x00, 0x21, 0xD1, 0x54, ++ 0x1B, 0xE0, 0x03, 0x20, 0x88, 0xF7, 0x2E, 0xFC, 0x04, 0x1E, 0x1C, 0xD1, ++ 0x2B, 0x78, 0x0F, 0x49, 0x30, 0x22, 0x8B, 0x54, 0x01, 0x2B, 0x10, 0xD1, ++ 0xDF, 0x20, 0x00, 0x21, 0x80, 0x00, 0x7A, 0xF7, 0xE7, 0xFA, 0x0B, 0x4B, ++ 0x18, 0x60, 0x0B, 0x4A, 0x24, 0x23, 0x01, 0x21, 0xD1, 0x54, 0x00, 0x21, ++ 0x00, 0x20, 0x92, 0xF7, 0xA1, 0xF8, 0x00, 0xE0, 0x12, 0x24, 0x21, 0x00, ++ 0x30, 0x00, 0xFF, 0xF7, 0x3B, 0xFA, 0x00, 0x20, 0x70, 0xBD, 0x0C, 0x24, ++ 0xF7, 0xE7, 0xC0, 0x46, 0x68, 0x9E, 0x16, 0x00, 0x64, 0xA2, 0x16, 0x00, ++ 0xCC, 0xAA, 0x16, 0x00, 0x70, 0xB5, 0x04, 0x00, 0x0D, 0x00, 0x0F, 0x4B, ++ 0x5B, 0x68, 0x02, 0x00, 0x06, 0x21, 0x01, 0x20, 0x98, 0x47, 0x20, 0x78, ++ 0x63, 0x78, 0x1B, 0x02, 0x03, 0x43, 0xA0, 0x78, 0x00, 0x04, 0x03, 0x43, ++ 0xE0, 0x78, 0x00, 0x06, 0x18, 0x43, 0x23, 0x79, 0x61, 0x79, 0x09, 0x02, ++ 0x19, 0x43, 0xA4, 0xF7, 0xFF, 0xF8, 0x20, 0x00, 0xB3, 0xF7, 0x3C, 0xFF, ++ 0x00, 0x21, 0x28, 0x00, 0xFF, 0xF7, 0x10, 0xFA, 0x00, 0x20, 0x70, 0xBD, ++ 0x94, 0x92, 0x16, 0x00, 0x10, 0x4A, 0xFF, 0x21, 0x13, 0x68, 0x8B, 0x43, ++ 0x0F, 0x48, 0x00, 0x78, 0x03, 0x43, 0x80, 0x20, 0x03, 0x43, 0x0E, 0x48, ++ 0x03, 0x60, 0x0E, 0x4B, 0x1B, 0x78, 0x1B, 0x01, 0x0B, 0x40, 0xD0, 0x68, ++ 0x88, 0x43, 0x03, 0x43, 0x0B, 0x49, 0x0B, 0x60, 0x0B, 0x4B, 0x00, 0x21, ++ 0x19, 0x60, 0x13, 0x69, 0x0A, 0x4A, 0x13, 0x40, 0x0A, 0x4A, 0x13, 0x60, ++ 0x0A, 0x4B, 0x0B, 0x4A, 0x1A, 0x60, 0x0B, 0x4A, 0x1A, 0x60, 0x70, 0x47, ++ 0xE4, 0xE6, 0x10, 0x00, 0x14, 0xE7, 0x10, 0x00, 0x08, 0x01, 0x60, 0x40, ++ 0xF7, 0xE8, 0x10, 0x00, 0x28, 0x10, 0x62, 0x40, 0x1C, 0x10, 0x62, 0x40, ++ 0xFF, 0x0F, 0xF0, 0xFF, 0x34, 0x08, 0x62, 0x40, 0x00, 0x00, 0x62, 0x40, ++ 0x00, 0x01, 0x0A, 0x01, 0x00, 0x01, 0x0F, 0x01, 0x0B, 0x4B, 0x1B, 0x78, ++ 0x00, 0x2B, 0x11, 0xD1, 0x0A, 0x4B, 0x1B, 0x68, 0x03, 0x60, 0x0A, 0x4B, ++ 0x1B, 0x68, 0x43, 0x60, 0x09, 0x4B, 0x1B, 0x68, 0x83, 0x60, 0x09, 0x4B, ++ 0x1B, 0x68, 0xC3, 0x60, 0x08, 0x4B, 0x1B, 0x68, 0x03, 0x61, 0x02, 0x4B, ++ 0x01, 0x22, 0x1A, 0x70, 0x70, 0x47, 0xC0, 0x46, 0xD3, 0xE6, 0x10, 0x00, ++ 0x08, 0x01, 0x60, 0x40, 0x00, 0x00, 0x62, 0x40, 0x1C, 0x10, 0x62, 0x40, ++ 0x28, 0x10, 0x62, 0x40, 0x34, 0x08, 0x62, 0x40, 0x09, 0x4B, 0x02, 0x68, ++ 0x1A, 0x60, 0x09, 0x4B, 0x42, 0x68, 0x1A, 0x60, 0x08, 0x4B, 0x82, 0x68, ++ 0x1A, 0x60, 0x08, 0x4B, 0xC2, 0x68, 0x1A, 0x60, 0x02, 0x69, 0x07, 0x4B, ++ 0x1A, 0x60, 0x07, 0x4B, 0x00, 0x22, 0x1A, 0x70, 0x70, 0x47, 0xC0, 0x46, ++ 0x08, 0x01, 0x60, 0x40, 0x00, 0x00, 0x62, 0x40, 0x1C, 0x10, 0x62, 0x40, ++ 0x28, 0x10, 0x62, 0x40, 0x34, 0x08, 0x62, 0x40, 0xD3, 0xE6, 0x10, 0x00, ++ 0x70, 0xB5, 0x04, 0x00, 0x0D, 0x00, 0x03, 0x78, 0x00, 0x2B, 0x17, 0xD0, ++ 0x02, 0x20, 0xF9, 0xF7, 0x8D, 0xFD, 0x0E, 0x48, 0xFF, 0xF7, 0xB0, 0xFF, ++ 0x62, 0x78, 0x0D, 0x4B, 0x1A, 0x70, 0xA2, 0x78, 0x0C, 0x4B, 0x1A, 0x70, ++ 0xFF, 0xF7, 0x70, 0xFF, 0x21, 0x78, 0x0B, 0x48, 0x7C, 0xF7, 0x46, 0xFA, ++ 0x00, 0x21, 0x28, 0x00, 0xFF, 0xF7, 0x82, 0xF9, 0x00, 0x20, 0x70, 0xBD, ++ 0x03, 0x48, 0xFF, 0xF7, 0xBF, 0xFF, 0x01, 0x20, 0xF9, 0xF7, 0x72, 0xFD, ++ 0xEE, 0xE7, 0xC0, 0x46, 0xE4, 0xE6, 0x10, 0x00, 0x14, 0xE7, 0x10, 0x00, ++ 0xF7, 0xE8, 0x10, 0x00, 0x5C, 0xD2, 0x10, 0x00, 0x00, 0x23, 0x03, 0x73, ++ 0x00, 0x20, 0x70, 0x47, 0x10, 0xB5, 0x03, 0x00, 0x08, 0x00, 0x1B, 0x88, ++ 0x12, 0x21, 0x15, 0x2B, 0x04, 0xD9, 0x04, 0x4B, 0x80, 0x22, 0xD2, 0x01, ++ 0x9A, 0x82, 0x00, 0x21, 0xFF, 0xF7, 0x50, 0xF9, 0x00, 0x20, 0x10, 0xBD, ++ 0x68, 0x9E, 0x16, 0x00, 0x70, 0xB5, 0x04, 0x00, 0x0D, 0x00, 0x0F, 0x4B, ++ 0x1B, 0x68, 0x02, 0x2B, 0x0B, 0xD0, 0x29, 0x00, 0x20, 0x00, 0x0D, 0x4B, ++ 0x98, 0x47, 0x0D, 0x4B, 0x80, 0x22, 0x12, 0x01, 0x1A, 0x83, 0x12, 0x22, ++ 0x5A, 0x83, 0x00, 0x20, 0x70, 0xBD, 0xFA, 0xF7, 0x09, 0xFC, 0x00, 0x28, ++ 0xEF, 0xD1, 0x23, 0x78, 0x9B, 0x07, 0xEC, 0xD5, 0x05, 0x4B, 0x80, 0x22, ++ 0x92, 0x00, 0x1A, 0x83, 0xEF, 0x3A, 0xFF, 0x3A, 0x5A, 0x83, 0xE4, 0xE7, ++ 0x50, 0xE0, 0x10, 0x00, 0x15, 0x28, 0x09, 0x00, 0x68, 0x9E, 0x16, 0x00, ++ 0x70, 0xB5, 0x0C, 0x00, 0x0B, 0x4A, 0x8C, 0x23, 0xD3, 0x5C, 0x0C, 0x25, ++ 0x01, 0x2B, 0x05, 0xD0, 0x29, 0x00, 0x20, 0x00, 0xFF, 0xF7, 0x18, 0xF9, ++ 0x00, 0x20, 0x70, 0xBD, 0xA4, 0xF7, 0xB8, 0xFC, 0x05, 0x1E, 0xF5, 0xD0, ++ 0x04, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, ++ 0xEE, 0xE7, 0xC0, 0x46, 0x68, 0x9E, 0x16, 0x00, 0x28, 0x19, 0x16, 0x00, ++ 0x10, 0xB5, 0x03, 0x00, 0x08, 0x00, 0x1B, 0x78, 0x01, 0x21, 0x99, 0x42, ++ 0x9B, 0x41, 0x11, 0x31, 0x19, 0x40, 0xFF, 0xF7, 0xFB, 0xF8, 0x00, 0x20, ++ 0x10, 0xBD, 0x00, 0x00, 0x70, 0xB5, 0x05, 0x00, 0x08, 0x00, 0x1C, 0x00, ++ 0x47, 0x4B, 0x9C, 0x42, 0x43, 0xD0, 0x23, 0xD8, 0x46, 0x4B, 0x9C, 0x42, ++ 0x51, 0xD0, 0x13, 0xD8, 0x45, 0x4B, 0x9C, 0x42, 0x45, 0xD0, 0x45, 0x4B, ++ 0x9C, 0x42, 0x04, 0xD1, 0x43, 0x49, 0xFF, 0xF7, 0x43, 0xF9, 0x00, 0x25, ++ 0x6A, 0xE0, 0x42, 0x4B, 0x9C, 0x42, 0x00, 0xD0, 0x70, 0xE0, 0x40, 0x49, ++ 0xFF, 0xF7, 0xB6, 0xFF, 0x00, 0x25, 0x61, 0xE0, 0x3E, 0x4B, 0x9C, 0x42, ++ 0x3E, 0xD0, 0x3E, 0x4B, 0x9C, 0x42, 0x65, 0xD1, 0x3C, 0x49, 0x00, 0x20, ++ 0xFF, 0xF7, 0x16, 0xFE, 0x00, 0x25, 0x55, 0xE0, 0x3A, 0x4B, 0x9C, 0x42, ++ 0x20, 0xD0, 0x0A, 0xD9, 0x39, 0x4B, 0x9C, 0x42, 0x12, 0xD0, 0x39, 0x4B, ++ 0x9C, 0x42, 0x55, 0xD1, 0x19, 0x00, 0xFF, 0xF7, 0xDB, 0xF8, 0x00, 0x25, ++ 0x46, 0xE0, 0x36, 0x4B, 0x9C, 0x42, 0x28, 0xD0, 0x35, 0x4B, 0x9C, 0x42, ++ 0x2A, 0xD1, 0x34, 0x49, 0xFF, 0xF7, 0x84, 0xFE, 0x00, 0x25, 0x3B, 0xE0, ++ 0x2E, 0x49, 0xFF, 0xF7, 0x01, 0xF9, 0x00, 0x25, 0x36, 0xE0, 0x24, 0x49, ++ 0xFF, 0xF7, 0x42, 0xFE, 0x00, 0x25, 0x31, 0xE0, 0x28, 0x49, 0xFF, 0xF7, ++ 0x15, 0xFF, 0x00, 0x25, 0x2C, 0xE0, 0x00, 0x23, 0x0B, 0x73, 0x20, 0x4B, ++ 0x28, 0x00, 0x29, 0x4D, 0xA8, 0x47, 0x05, 0x00, 0x24, 0xE0, 0x1C, 0x49, ++ 0xFF, 0xF7, 0x3A, 0xFF, 0x00, 0x25, 0x1F, 0xE0, 0x1D, 0x49, 0xFF, 0xF7, ++ 0x47, 0xFF, 0x00, 0x25, 0x1A, 0xE0, 0x20, 0x49, 0xFF, 0xF7, 0x88, 0xFF, ++ 0x00, 0x25, 0x15, 0xE0, 0x23, 0x00, 0x28, 0x00, 0x1E, 0x4D, 0xA8, 0x47, ++ 0x05, 0x00, 0x1E, 0x4B, 0x9C, 0x42, 0x05, 0xD0, 0x1D, 0x4B, 0x08, 0x22, ++ 0x21, 0x00, 0x91, 0x43, 0x99, 0x42, 0x04, 0xD1, 0x02, 0x20, 0xF9, 0xF7, ++ 0x81, 0xFC, 0xFA, 0xF7, 0x63, 0xF9, 0x19, 0x4B, 0x9C, 0x42, 0x05, 0xD0, ++ 0x21, 0x00, 0x18, 0x48, 0x7C, 0xF7, 0x40, 0xF9, 0x28, 0x00, 0x70, 0xBD, ++ 0x01, 0x20, 0xF9, 0xF7, 0x73, 0xFC, 0xF5, 0xE7, 0x23, 0x00, 0x01, 0x00, ++ 0x28, 0x00, 0x0E, 0x4D, 0xA8, 0x47, 0x05, 0x00, 0xE0, 0xE7, 0xC0, 0x46, ++ 0x02, 0x18, 0x00, 0x00, 0x18, 0x0C, 0x00, 0x00, 0x05, 0x04, 0x00, 0x00, ++ 0x13, 0x0C, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x1A, 0x0C, 0x00, 0x00, ++ 0x02, 0x10, 0x00, 0x00, 0xC6, 0xFC, 0x00, 0x00, 0xC7, 0xFC, 0x00, 0x00, ++ 0xC9, 0xFC, 0x00, 0x00, 0x04, 0x18, 0x00, 0x00, 0x70, 0xFC, 0x00, 0x00, ++ 0x1D, 0x0C, 0x09, 0x00, 0x06, 0x18, 0x00, 0x00, 0x03, 0x18, 0x00, 0x00, ++ 0x0C, 0x18, 0x00, 0x00, 0x6C, 0xD2, 0x10, 0x00, 0x70, 0xB5, 0x0D, 0x00, ++ 0x14, 0x00, 0x04, 0x23, 0x02, 0x00, 0x00, 0x21, 0x03, 0x48, 0x7A, 0xF7, ++ 0x03, 0xF8, 0x05, 0x70, 0x44, 0x80, 0xCB, 0xF7, 0x5F, 0xFE, 0x70, 0xBD, ++ 0x01, 0x11, 0x00, 0x00, 0x10, 0xB5, 0x03, 0x00, 0x10, 0x00, 0x1A, 0x88, ++ 0x0C, 0x21, 0xFF, 0xF7, 0xE9, 0xFF, 0x00, 0x20, 0x10, 0xBD, 0x00, 0x00, ++ 0xF0, 0xB5, 0xDE, 0x46, 0x57, 0x46, 0x4E, 0x46, 0x45, 0x46, 0xE0, 0xB5, ++ 0x83, 0xB0, 0x80, 0x46, 0x0C, 0x00, 0x91, 0x46, 0x0F, 0x0A, 0xBA, 0x00, ++ 0x2E, 0x4B, 0xD5, 0x58, 0x08, 0x00, 0x7A, 0xF7, 0xB7, 0xFB, 0x02, 0x26, ++ 0x00, 0x28, 0x19, 0xD0, 0x36, 0x23, 0xEB, 0x5C, 0x01, 0x2B, 0x4F, 0xD0, ++ 0x3C, 0x23, 0xEE, 0x5C, 0x02, 0x2E, 0x03, 0xD1, 0x43, 0x46, 0x5B, 0x88, ++ 0x00, 0x2B, 0x1B, 0xD1, 0xFA, 0x21, 0x49, 0x01, 0xA9, 0x83, 0xFF, 0xB2, ++ 0x36, 0x23, 0xEA, 0x5C, 0x38, 0x00, 0xA1, 0xF7, 0x6D, 0xFE, 0xA9, 0x8B, ++ 0x38, 0x00, 0xAB, 0xF7, 0x31, 0xFC, 0x00, 0x26, 0x43, 0x46, 0x1A, 0x88, ++ 0x31, 0x00, 0x48, 0x46, 0xFF, 0xF7, 0xB2, 0xFF, 0x00, 0x20, 0x03, 0xB0, ++ 0x3C, 0xBC, 0x90, 0x46, 0x99, 0x46, 0xA2, 0x46, 0xAB, 0x46, 0xF0, 0xBD, ++ 0xFB, 0xB2, 0x9B, 0x46, 0x06, 0x23, 0x6B, 0x44, 0x9A, 0x46, 0x6B, 0x46, ++ 0x5A, 0x1D, 0x51, 0x46, 0x58, 0x46, 0x8B, 0xF7, 0x65, 0xFE, 0x43, 0x46, ++ 0x5A, 0x88, 0x53, 0x46, 0x19, 0x88, 0x8A, 0x42, 0x13, 0xD9, 0x6B, 0x46, ++ 0x05, 0x33, 0x1B, 0x78, 0x00, 0x2B, 0xCD, 0xD0, 0x4B, 0x43, 0x9A, 0x42, ++ 0xCA, 0xD8, 0x00, 0x23, 0x00, 0x22, 0x00, 0x21, 0x58, 0x46, 0xAB, 0xF7, ++ 0x73, 0xFA, 0x22, 0x00, 0x21, 0x00, 0x07, 0x48, 0x79, 0xF7, 0xD2, 0xFF, ++ 0xBE, 0xE7, 0x43, 0x46, 0x1A, 0x88, 0x12, 0x21, 0x48, 0x46, 0xFF, 0xF7, ++ 0x7F, 0xFF, 0xC5, 0xE7, 0x0C, 0x26, 0xC3, 0xE7, 0x64, 0xA2, 0x16, 0x00, ++ 0x22, 0x06, 0x00, 0x00, 0xF0, 0xB5, 0x93, 0xB0, 0x01, 0x90, 0x0C, 0x00, ++ 0x16, 0x00, 0x0F, 0x0A, 0xBA, 0x00, 0x37, 0x4B, 0xD5, 0x58, 0x08, 0x00, ++ 0x7A, 0xF7, 0x4E, 0xFB, 0x04, 0x28, 0x06, 0xD0, 0x09, 0x28, 0x18, 0xD0, ++ 0x0C, 0x21, 0x30, 0x00, 0x91, 0xF7, 0x42, 0xFB, 0x10, 0xE0, 0x3C, 0x22, ++ 0x30, 0x49, 0x03, 0xA8, 0xD0, 0xF7, 0x62, 0xFE, 0x00, 0x21, 0x30, 0x00, ++ 0x91, 0xF7, 0x38, 0xFB, 0x2D, 0x4A, 0xE8, 0x23, 0xD5, 0x58, 0x03, 0xAB, ++ 0x01, 0x22, 0x01, 0x21, 0x20, 0x00, 0xA8, 0x47, 0x00, 0x20, 0x13, 0xB0, ++ 0xF0, 0xBD, 0x21, 0x00, 0x28, 0x48, 0x79, 0xF7, 0x0F, 0xFF, 0x01, 0x21, ++ 0x20, 0x00, 0x7A, 0xF7, 0xC9, 0xFA, 0x00, 0x21, 0x30, 0x00, 0x91, 0xF7, ++ 0x21, 0xFB, 0xBC, 0x23, 0x5B, 0x00, 0xEB, 0x5C, 0xDB, 0x43, 0x9B, 0x07, ++ 0x21, 0xD1, 0x00, 0x23, 0x01, 0x9A, 0x93, 0x71, 0xFF, 0xB2, 0x29, 0x00, ++ 0x38, 0x31, 0x38, 0x00, 0x88, 0xF7, 0x70, 0xF9, 0x00, 0x28, 0x1C, 0xD0, ++ 0x1B, 0x48, 0x7C, 0xF7, 0x3F, 0xF8, 0x01, 0x23, 0xAF, 0x22, 0x92, 0x00, ++ 0xAB, 0x54, 0x43, 0x22, 0xAB, 0x54, 0x20, 0x00, 0x93, 0xF7, 0xA0, 0xF9, ++ 0x88, 0xF7, 0x64, 0xFA, 0x00, 0x28, 0x19, 0xD1, 0xC4, 0x20, 0x22, 0x00, ++ 0x21, 0x00, 0xC0, 0x00, 0x79, 0xF7, 0x68, 0xFF, 0xC8, 0xE7, 0x22, 0x00, ++ 0x21, 0x00, 0x10, 0x48, 0x79, 0xF7, 0x62, 0xFF, 0xD7, 0xE7, 0x0F, 0x48, ++ 0x7C, 0xF7, 0x22, 0xF8, 0x44, 0x23, 0x01, 0x22, 0xEA, 0x54, 0x0B, 0x3B, ++ 0xEA, 0x5C, 0x33, 0x21, 0x38, 0x00, 0xA1, 0xF7, 0x39, 0xFC, 0xE1, 0xE7, ++ 0x22, 0x00, 0x21, 0x00, 0x08, 0x48, 0x79, 0xF7, 0x4F, 0xFF, 0xDF, 0xE7, ++ 0x64, 0xA2, 0x16, 0x00, 0x80, 0xD6, 0x10, 0x00, 0x28, 0x19, 0x16, 0x00, ++ 0x06, 0x06, 0x00, 0x00, 0x74, 0xD2, 0x10, 0x00, 0x14, 0x06, 0x00, 0x00, ++ 0x7C, 0xD2, 0x10, 0x00, 0x1D, 0x06, 0x00, 0x00, 0x70, 0xB5, 0x04, 0x00, ++ 0x0E, 0x00, 0x15, 0x00, 0x41, 0x88, 0x80, 0x23, 0x1B, 0x01, 0x99, 0x42, ++ 0x06, 0xD3, 0x22, 0x88, 0x0C, 0x21, 0x28, 0x00, 0xFF, 0xF7, 0xE4, 0xFE, ++ 0x00, 0x20, 0x70, 0xBD, 0x03, 0x48, 0x7B, 0xF7, 0xEF, 0xFF, 0x30, 0x0A, ++ 0x00, 0x21, 0xAB, 0xF7, 0xA7, 0xF8, 0xF0, 0xE7, 0x84, 0xD2, 0x10, 0x00, ++ 0x70, 0xB5, 0x0E, 0x00, 0x15, 0x00, 0x07, 0x23, 0x02, 0x00, 0x00, 0x21, ++ 0x06, 0x48, 0x79, 0xF7, 0xDB, 0xFE, 0x04, 0x00, 0x06, 0x70, 0x01, 0x30, ++ 0x06, 0x22, 0x29, 0x00, 0xD0, 0xF7, 0xCC, 0xFD, 0x20, 0x00, 0xCB, 0xF7, ++ 0x31, 0xFD, 0x70, 0xBD, 0x01, 0x11, 0x00, 0x00, 0xF0, 0xB5, 0x83, 0xB0, ++ 0x01, 0x90, 0x0D, 0x00, 0x16, 0x00, 0x0F, 0x0A, 0xBA, 0x00, 0x22, 0x4B, ++ 0xD4, 0x58, 0x08, 0x00, 0x7A, 0xF7, 0x98, 0xFA, 0x00, 0x28, 0x1A, 0xD0, ++ 0x16, 0x38, 0xC0, 0xB2, 0x03, 0x28, 0x16, 0xD9, 0x88, 0x23, 0xFF, 0x33, ++ 0xE3, 0x5C, 0x00, 0x2B, 0x03, 0xD1, 0x36, 0x33, 0xE3, 0x5C, 0x00, 0x2B, ++ 0x14, 0xD0, 0x00, 0x21, 0x30, 0x00, 0x91, 0xF7, 0x81, 0xFA, 0x36, 0x23, ++ 0xE3, 0x5C, 0x00, 0x2B, 0x11, 0xD1, 0x2A, 0x00, 0x29, 0x00, 0x14, 0x48, ++ 0x79, 0xF7, 0xE6, 0xFE, 0x03, 0xE0, 0x02, 0x21, 0x30, 0x00, 0x91, 0xF7, ++ 0x73, 0xFA, 0x00, 0x20, 0x03, 0xB0, 0xF0, 0xBD, 0x0C, 0x21, 0x30, 0x00, ++ 0x91, 0xF7, 0x6C, 0xFA, 0xF7, 0xE7, 0x06, 0x23, 0x1C, 0x22, 0x00, 0x21, ++ 0x0B, 0x48, 0x79, 0xF7, 0x93, 0xFE, 0x05, 0x00, 0x00, 0x23, 0x03, 0x70, ++ 0x01, 0x9B, 0x1B, 0x88, 0x43, 0x80, 0xF8, 0xB2, 0xAB, 0xF7, 0x32, 0xFA, ++ 0xC0, 0x03, 0x40, 0x0C, 0xA8, 0x80, 0x28, 0x00, 0xCB, 0xF7, 0xE4, 0xFC, ++ 0xE1, 0xE7, 0xC0, 0x46, 0x64, 0xA2, 0x16, 0x00, 0x16, 0x06, 0x00, 0x00, ++ 0x03, 0x11, 0x00, 0x00, 0xF0, 0xB5, 0x83, 0xB0, 0x01, 0x90, 0x0D, 0x00, ++ 0x16, 0x00, 0x0B, 0x0A, 0x9B, 0x00, 0x31, 0x4A, 0x9F, 0x58, 0x08, 0x00, ++ 0x7A, 0xF7, 0x46, 0xFA, 0x00, 0x28, 0x53, 0xD0, 0x16, 0x38, 0xC0, 0xB2, ++ 0x02, 0x24, 0x03, 0x28, 0x4F, 0xD9, 0x01, 0x99, 0x4B, 0x88, 0xA8, 0x22, ++ 0xD2, 0x00, 0x10, 0x34, 0x93, 0x42, 0x48, 0xD8, 0xDA, 0x07, 0x46, 0xD4, ++ 0x8A, 0x88, 0x05, 0x2A, 0x43, 0xD9, 0xD0, 0x07, 0x41, 0xD4, 0x08, 0x00, ++ 0xC9, 0x88, 0x00, 0x29, 0x3D, 0xD0, 0x00, 0x89, 0x84, 0x46, 0x28, 0x28, ++ 0x39, 0xD8, 0x58, 0x08, 0x81, 0x42, 0x36, 0xD8, 0x93, 0x42, 0x34, 0xD3, ++ 0x61, 0x44, 0x49, 0x00, 0x99, 0x42, 0x30, 0xD2, 0x7B, 0x8C, 0x06, 0x3C, ++ 0x5B, 0x07, 0x2C, 0xD5, 0x3C, 0x23, 0xFC, 0x5C, 0x00, 0x2C, 0x01, 0xD0, ++ 0x0C, 0x24, 0x26, 0xE0, 0x38, 0x00, 0x54, 0x30, 0x07, 0x21, 0xA1, 0xF7, ++ 0x47, 0xFA, 0x00, 0x28, 0x01, 0xD1, 0x1A, 0x24, 0x1D, 0xE0, 0x08, 0x23, ++ 0x2A, 0x00, 0x29, 0x00, 0x11, 0x48, 0x79, 0xF7, 0x31, 0xFE, 0x01, 0x9B, ++ 0x5A, 0x88, 0x02, 0x80, 0x9B, 0x88, 0x43, 0x80, 0xC0, 0x21, 0x49, 0x00, ++ 0x8A, 0x42, 0x00, 0xD9, 0x01, 0x80, 0xC0, 0x22, 0x52, 0x00, 0x93, 0x42, ++ 0x00, 0xD9, 0x42, 0x80, 0x01, 0x9A, 0xD3, 0x88, 0x83, 0x80, 0x13, 0x89, ++ 0xC3, 0x80, 0x79, 0xF7, 0x45, 0xFE, 0x00, 0xE0, 0x02, 0x24, 0x21, 0x00, ++ 0x30, 0x00, 0x91, 0xF7, 0xE7, 0xF9, 0x00, 0x20, 0x03, 0xB0, 0xF0, 0xBD, ++ 0x64, 0xA2, 0x16, 0x00, 0x0D, 0x06, 0x00, 0x00, 0x70, 0xB5, 0x04, 0x00, ++ 0x08, 0x00, 0x15, 0x00, 0x0B, 0x0A, 0x9B, 0x00, 0x0F, 0x4A, 0x9E, 0x58, ++ 0x7A, 0xF7, 0xDA, 0xF9, 0x02, 0x21, 0x00, 0x28, 0x10, 0xD0, 0x63, 0x88, ++ 0xF0, 0x22, 0x10, 0x31, 0x1A, 0x42, 0x0B, 0xD1, 0xE6, 0x3A, 0x01, 0x39, ++ 0x1A, 0x42, 0x07, 0xD1, 0x73, 0x84, 0x2C, 0x32, 0xB1, 0x5C, 0x00, 0x29, ++ 0x08, 0xD1, 0x35, 0x3A, 0x93, 0x43, 0x73, 0x84, 0x22, 0x88, 0x28, 0x00, ++ 0xFF, 0xF7, 0xE0, 0xFD, 0x00, 0x20, 0x70, 0xBD, 0x00, 0x21, 0xF7, 0xE7, ++ 0x64, 0xA2, 0x16, 0x00, 0xF0, 0xB5, 0xD6, 0x46, 0x4F, 0x46, 0x80, 0xB5, ++ 0x83, 0xB0, 0x01, 0x90, 0x0E, 0x00, 0x17, 0x00, 0x1C, 0x00, 0x4B, 0x4B, ++ 0x9C, 0x42, 0x5D, 0xD0, 0x0E, 0xD9, 0x4A, 0x4B, 0x9C, 0x42, 0x67, 0xD0, ++ 0x42, 0xD9, 0x49, 0x4B, 0x9C, 0x42, 0x00, 0xD0, 0x81, 0xE0, 0x47, 0x4A, ++ 0x39, 0x00, 0x30, 0x00, 0xFF, 0xF7, 0xDA, 0xFD, 0x00, 0x25, 0x43, 0xE0, ++ 0x44, 0x4B, 0x9C, 0x42, 0x69, 0xD0, 0x01, 0x33, 0x9C, 0x42, 0x13, 0xD3, ++ 0x42, 0x4B, 0xE3, 0x18, 0x9B, 0xB2, 0x03, 0x2B, 0x00, 0xD9, 0x6E, 0xE0, ++ 0x10, 0x00, 0x7A, 0xF7, 0x91, 0xF9, 0x43, 0x28, 0x51, 0xD8, 0x41, 0x28, ++ 0x51, 0xD8, 0x32, 0x00, 0x0C, 0x21, 0x20, 0x00, 0xFF, 0xF7, 0xCE, 0xFE, ++ 0x00, 0x25, 0x29, 0xE0, 0x39, 0x4B, 0x9C, 0x42, 0x37, 0xD0, 0x39, 0x4B, ++ 0x9C, 0x42, 0x5A, 0xD1, 0x38, 0x48, 0x7B, 0xF7, 0xAB, 0xFE, 0xB5, 0x1D, ++ 0x16, 0x23, 0x9A, 0x46, 0xB2, 0x44, 0x36, 0x4B, 0x99, 0x46, 0x29, 0x78, ++ 0x48, 0x46, 0x7B, 0xF7, 0xA1, 0xFE, 0x01, 0x35, 0x55, 0x45, 0xF8, 0xD1, ++ 0x2F, 0x4B, 0x3A, 0x00, 0x31, 0x00, 0x01, 0x98, 0x30, 0x4D, 0xA8, 0x47, ++ 0x05, 0x00, 0x0B, 0xE0, 0x2F, 0x4B, 0x9C, 0x42, 0x38, 0xD0, 0x2F, 0x4B, ++ 0x9C, 0x42, 0x3C, 0xD1, 0x2D, 0x4A, 0x39, 0x00, 0x30, 0x00, 0xFF, 0xF7, ++ 0x8B, 0xFD, 0x00, 0x25, 0x21, 0x00, 0x2B, 0x48, 0x7B, 0xF7, 0x86, 0xFE, ++ 0x28, 0x00, 0x03, 0xB0, 0x0C, 0xBC, 0x91, 0x46, 0x9A, 0x46, 0xF0, 0xBD, ++ 0x1A, 0x4A, 0x39, 0x00, 0x30, 0x00, 0xFF, 0xF7, 0xFB, 0xFE, 0x00, 0x25, ++ 0xEE, 0xE7, 0x1C, 0x4A, 0x39, 0x00, 0x30, 0x00, 0xFF, 0xF7, 0xEC, 0xFD, ++ 0x05, 0x00, 0xE7, 0xE7, 0x14, 0x4A, 0x39, 0x00, 0x30, 0x00, 0xFF, 0xF7, ++ 0x6B, 0xFE, 0x05, 0x00, 0xE0, 0xE7, 0x4A, 0x28, 0xAD, 0xD1, 0x23, 0x00, ++ 0x3A, 0x00, 0x31, 0x00, 0x01, 0x98, 0x16, 0x4D, 0xA8, 0x47, 0x05, 0x00, ++ 0xD6, 0xE7, 0x0E, 0x4A, 0x39, 0x00, 0x30, 0x00, 0xFF, 0xF7, 0x8A, 0xFE, ++ 0x05, 0x00, 0xCF, 0xE7, 0x11, 0x4A, 0x39, 0x00, 0x30, 0x00, 0xFF, 0xF7, ++ 0x43, 0xFF, 0x05, 0x00, 0xC8, 0xE7, 0x23, 0x00, 0x3A, 0x00, 0x31, 0x00, ++ 0x01, 0x98, 0x0B, 0x4D, 0xA8, 0x47, 0x05, 0x00, 0xC0, 0xE7, 0xC0, 0x46, ++ 0x03, 0x08, 0x00, 0x00, 0x28, 0x0C, 0x00, 0x00, 0x37, 0x0C, 0x00, 0x00, ++ 0x1F, 0x04, 0x00, 0x00, 0xD4, 0xFB, 0xFF, 0xFF, 0x09, 0x04, 0x00, 0x00, ++ 0x0B, 0x04, 0x00, 0x00, 0x90, 0xD2, 0x10, 0x00, 0x98, 0xD2, 0x10, 0x00, ++ 0xC1, 0xDB, 0x09, 0x00, 0x0D, 0x08, 0x00, 0x00, 0x11, 0x08, 0x00, 0x00, ++ 0x9C, 0xD2, 0x10, 0x00, 0x10, 0xB5, 0x03, 0x00, 0x08, 0x00, 0x1B, 0x78, ++ 0x00, 0x21, 0x01, 0x2B, 0x00, 0xD9, 0x12, 0x31, 0xB2, 0xF7, 0x7C, 0xFF, ++ 0x00, 0x20, 0x10, 0xBD, 0x10, 0xB5, 0x08, 0x00, 0x00, 0x21, 0xB2, 0xF7, ++ 0x75, 0xFF, 0x00, 0x20, 0x10, 0xBD, 0x00, 0x00, 0xF0, 0xB5, 0xDE, 0x46, ++ 0x57, 0x46, 0x4E, 0x46, 0x45, 0x46, 0xE0, 0xB5, 0xAD, 0xB0, 0x04, 0x00, ++ 0x0D, 0x00, 0x02, 0xAB, 0x00, 0x22, 0xDA, 0x71, 0x60, 0x32, 0x00, 0x21, ++ 0x14, 0xA8, 0x77, 0xF7, 0x8B, 0xFD, 0x9B, 0x4A, 0x9B, 0x4B, 0xD3, 0x5C, ++ 0x01, 0x2B, 0x00, 0xD1, 0xC8, 0xE1, 0x99, 0x4B, 0x02, 0x21, 0xD1, 0x54, ++ 0x02, 0xAB, 0x00, 0x21, 0xD9, 0x71, 0x44, 0x32, 0x00, 0x20, 0x00, 0x23, ++ 0x01, 0x26, 0x11, 0x78, 0x05, 0x29, 0x26, 0xD0, 0x01, 0x33, 0xDB, 0xB2, ++ 0x40, 0x32, 0x30, 0x00, 0x0C, 0x2B, 0xF6, 0xD1, 0x02, 0xAB, 0x0C, 0x22, ++ 0xDA, 0x71, 0x27, 0x78, 0x00, 0x2F, 0x24, 0xD0, 0x60, 0x7A, 0x07, 0x23, ++ 0x07, 0x00, 0x9F, 0x43, 0x00, 0x97, 0x00, 0xD0, 0xB5, 0xE1, 0x8A, 0x49, ++ 0x0F, 0x22, 0x02, 0x40, 0x03, 0x09, 0x8E, 0x5C, 0xCB, 0x5C, 0xF6, 0x18, ++ 0xF6, 0xB2, 0x00, 0x2E, 0x61, 0xDD, 0x23, 0x00, 0x0A, 0x33, 0x3A, 0x00, ++ 0x02, 0x37, 0x07, 0x40, 0x01, 0x21, 0x01, 0x40, 0xA4, 0x46, 0x0C, 0x00, ++ 0x1E, 0xE0, 0x00, 0x28, 0x01, 0xD0, 0x02, 0xAA, 0xD3, 0x71, 0x0C, 0x21, ++ 0x00, 0x27, 0x0B, 0x2B, 0x00, 0xD8, 0x8D, 0xE1, 0xD7, 0xE7, 0xA1, 0x78, ++ 0xE0, 0x1C, 0xB2, 0xF7, 0x35, 0xFF, 0x0B, 0x21, 0x00, 0x28, 0x00, 0xD0, ++ 0x84, 0xE1, 0xD1, 0xE7, 0x59, 0x88, 0x18, 0x88, 0x81, 0x42, 0x46, 0xD8, ++ 0x03, 0x29, 0x44, 0xD9, 0x03, 0x28, 0x42, 0xD9, 0x01, 0x32, 0x10, 0x33, ++ 0xB2, 0x42, 0x04, 0xDA, 0x00, 0x2F, 0xF1, 0xD0, 0x94, 0x42, 0xEF, 0xD1, ++ 0xF6, 0xE7, 0x64, 0x46, 0x23, 0x00, 0x0E, 0x33, 0x00, 0x98, 0xC8, 0x22, ++ 0x12, 0x01, 0x91, 0x46, 0x6B, 0x4A, 0x92, 0x46, 0xFA, 0x22, 0x52, 0x00, ++ 0x93, 0x46, 0xA4, 0x46, 0xA8, 0x46, 0x1F, 0x88, 0x5A, 0x88, 0x97, 0x42, ++ 0x2D, 0xD8, 0x1D, 0x89, 0x59, 0x89, 0x8D, 0x42, 0x29, 0xD8, 0xD9, 0x88, ++ 0x05, 0x2F, 0x26, 0xD9, 0x4A, 0x45, 0x24, 0xD8, 0x0F, 0x00, 0x0A, 0x3F, ++ 0xBF, 0xB2, 0x57, 0x45, 0x1F, 0xD8, 0x9F, 0x88, 0x5F, 0x45, 0x1C, 0xD2, ++ 0x8C, 0x00, 0x61, 0x18, 0x49, 0x00, 0x01, 0x37, 0x57, 0x43, 0xBA, 0x00, ++ 0xD2, 0x19, 0x01, 0x32, 0x52, 0x10, 0x91, 0x42, 0x11, 0xDB, 0x01, 0x30, ++ 0x10, 0x33, 0xB0, 0x42, 0xDB, 0xDB, 0x64, 0x46, 0x45, 0x46, 0xA3, 0x78, ++ 0x01, 0x2B, 0x0F, 0xD9, 0x12, 0x21, 0x00, 0x27, 0x38, 0xE1, 0x64, 0x46, ++ 0x96, 0x42, 0xC3, 0xDD, 0x12, 0x21, 0x00, 0x27, 0x32, 0xE1, 0x64, 0x46, ++ 0x45, 0x46, 0x86, 0x42, 0xEF, 0xDD, 0x12, 0x21, 0x00, 0x27, 0x2B, 0xE1, ++ 0x63, 0x78, 0x03, 0x2B, 0x00, 0xD9, 0x35, 0xE1, 0xDB, 0x07, 0x06, 0xD5, ++ 0x49, 0x49, 0x4A, 0x48, 0x7B, 0xF7, 0x98, 0xFD, 0x00, 0x28, 0x00, 0xD0, ++ 0x2F, 0xE1, 0x02, 0xAB, 0xD8, 0x1D, 0xB3, 0xF7, 0x71, 0xF9, 0x01, 0x00, ++ 0x01, 0x90, 0x00, 0x27, 0x00, 0x28, 0x00, 0xD0, 0x14, 0xE1, 0x00, 0x2E, ++ 0x00, 0xDC, 0x25, 0xE1, 0x0E, 0x23, 0x99, 0x46, 0xA1, 0x44, 0x14, 0xAF, ++ 0x00, 0x9B, 0x9A, 0x46, 0x00, 0x23, 0x9B, 0x46, 0xA0, 0x46, 0x4C, 0x46, ++ 0xA9, 0x46, 0x55, 0x46, 0x13, 0xE0, 0x78, 0x60, 0x39, 0x60, 0xBA, 0x60, ++ 0xFB, 0x60, 0x5B, 0x46, 0xBB, 0x74, 0xFB, 0x74, 0x02, 0xAB, 0xDB, 0x79, ++ 0x3B, 0x82, 0x38, 0x00, 0xCF, 0xF7, 0xCA, 0xFA, 0x00, 0x28, 0x18, 0xD1, ++ 0x01, 0x35, 0x10, 0x34, 0x20, 0x37, 0xB5, 0x42, 0x24, 0xDA, 0x23, 0x00, ++ 0x21, 0x88, 0x49, 0x00, 0x22, 0x89, 0x8A, 0x42, 0x00, 0xD9, 0x0A, 0x00, ++ 0x02, 0x2A, 0x00, 0xD2, 0x02, 0x22, 0x58, 0x88, 0x40, 0x00, 0x5B, 0x89, ++ 0x83, 0x42, 0x00, 0xD9, 0x03, 0x00, 0x93, 0x42, 0xD9, 0xD2, 0x13, 0x00, ++ 0xD7, 0xE7, 0xAA, 0x46, 0x44, 0x46, 0x4D, 0x46, 0x51, 0x46, 0x25, 0x48, ++ 0x7B, 0xF7, 0x10, 0xFD, 0x51, 0x46, 0x24, 0x48, 0x7B, 0xF7, 0x0C, 0xFD, ++ 0x01, 0x9F, 0x3B, 0x21, 0x56, 0x45, 0x00, 0xDD, 0xCC, 0xE0, 0x06, 0xE0, ++ 0xAA, 0x46, 0x44, 0x46, 0x4D, 0x46, 0x51, 0x46, 0x1D, 0x48, 0x7B, 0xF7, ++ 0xFF, 0xFC, 0x02, 0xAB, 0xDA, 0x79, 0x92, 0x01, 0x13, 0x4B, 0x9B, 0x18, ++ 0x9B, 0x68, 0x00, 0x2B, 0x05, 0xD0, 0x19, 0x4B, 0x9B, 0x6E, 0x00, 0x22, ++ 0x11, 0x00, 0x10, 0x00, 0x98, 0x47, 0x60, 0x78, 0x02, 0x28, 0x2D, 0xD0, ++ 0x0E, 0xD8, 0x00, 0x28, 0x2A, 0xD0, 0x0B, 0x49, 0x02, 0xAB, 0xD8, 0x79, ++ 0x80, 0x01, 0x08, 0x18, 0x0C, 0x30, 0x11, 0x4B, 0x9C, 0x46, 0x61, 0x44, ++ 0x06, 0x22, 0xD0, 0xF7, 0xD3, 0xFA, 0x2B, 0xE0, 0x03, 0x28, 0xF0, 0xD0, ++ 0x0B, 0x4B, 0xDF, 0x6E, 0x00, 0x23, 0x1A, 0x00, 0x19, 0x00, 0xB8, 0x47, ++ 0x22, 0xE0, 0xC0, 0x46, 0xEC, 0xA4, 0x16, 0x00, 0x6D, 0x04, 0x00, 0x00, ++ 0xE4, 0x98, 0x0D, 0x00, 0x76, 0x0C, 0x00, 0x00, 0xB4, 0x98, 0x0D, 0x00, ++ 0xFA, 0xA7, 0x16, 0x00, 0xA4, 0xD2, 0x10, 0x00, 0xB0, 0xD2, 0x10, 0x00, ++ 0x28, 0x19, 0x16, 0x00, 0x0E, 0x03, 0x00, 0x00, 0x4E, 0x4A, 0x02, 0xAB, ++ 0x07, 0x33, 0x1B, 0x78, 0x9B, 0x01, 0xD3, 0x18, 0xC2, 0x21, 0x89, 0x00, ++ 0x8C, 0x46, 0x62, 0x44, 0x11, 0x68, 0xD9, 0x60, 0x92, 0x88, 0x1A, 0x82, ++ 0x02, 0xAB, 0x07, 0x33, 0x1B, 0x78, 0x46, 0x4F, 0x9A, 0x01, 0xBA, 0x18, ++ 0x94, 0x60, 0x01, 0x33, 0x9B, 0x01, 0xFB, 0x18, 0x05, 0x22, 0x1A, 0x71, ++ 0xE1, 0x1C, 0x01, 0x32, 0x0E, 0x20, 0x02, 0xAB, 0x9C, 0x46, 0x60, 0x44, ++ 0xD0, 0xF7, 0x92, 0xFA, 0x3E, 0x4B, 0xF9, 0x18, 0x05, 0x22, 0x07, 0xA8, ++ 0xD0, 0xF7, 0x8C, 0xFA, 0x67, 0x7A, 0x04, 0xAB, 0x9F, 0x74, 0x00, 0x2E, ++ 0x17, 0xDD, 0x22, 0x00, 0x0A, 0x32, 0x14, 0xA9, 0x10, 0x88, 0x18, 0x83, ++ 0x50, 0x88, 0x58, 0x83, 0x48, 0x69, 0x40, 0x08, 0x98, 0x83, 0x88, 0x69, ++ 0xD8, 0x83, 0x10, 0x89, 0x18, 0x84, 0x50, 0x89, 0x58, 0x84, 0x00, 0x98, ++ 0x01, 0x30, 0x00, 0x90, 0x10, 0x32, 0x0C, 0x33, 0x20, 0x31, 0xB0, 0x42, ++ 0xEA, 0xDB, 0x05, 0x23, 0x3B, 0x40, 0x05, 0x2B, 0x20, 0xD0, 0x02, 0xAB, ++ 0x07, 0x33, 0x1B, 0x78, 0x04, 0xA8, 0xC3, 0x74, 0x62, 0x78, 0x02, 0x75, ++ 0xA2, 0x78, 0x42, 0x75, 0x22, 0x78, 0x82, 0x75, 0x24, 0x4A, 0x9B, 0x01, ++ 0xD3, 0x18, 0xD9, 0x68, 0x04, 0x91, 0x1B, 0x8A, 0x83, 0x80, 0x01, 0x23, ++ 0x43, 0x74, 0x22, 0x4B, 0xD2, 0x5C, 0x3C, 0x23, 0xC2, 0x54, 0xC7, 0xF7, ++ 0x29, 0xFF, 0x01, 0x00, 0x01, 0x27, 0x00, 0x28, 0x1E, 0xD0, 0x03, 0x21, ++ 0x01, 0x27, 0x1B, 0xE0, 0x01, 0x3E, 0x04, 0xA8, 0x43, 0x8B, 0x0C, 0x22, ++ 0x72, 0x43, 0x82, 0x18, 0x51, 0x8B, 0x5F, 0x18, 0x02, 0x8B, 0xBA, 0x42, ++ 0x00, 0xD2, 0x07, 0x83, 0x0C, 0x22, 0x72, 0x43, 0x04, 0xA8, 0x84, 0x46, ++ 0x62, 0x44, 0x12, 0x8B, 0xBA, 0x42, 0xCA, 0xD2, 0x0C, 0x22, 0x72, 0x43, ++ 0x62, 0x44, 0x5B, 0x18, 0x13, 0x83, 0xC4, 0xE7, 0x0C, 0x21, 0x00, 0x27, ++ 0x28, 0x00, 0xB2, 0xF7, 0x9B, 0xFD, 0x38, 0x00, 0x2D, 0xB0, 0x3C, 0xBC, ++ 0x90, 0x46, 0x99, 0x46, 0xA2, 0x46, 0xAB, 0x46, 0xF0, 0xBD, 0x12, 0x21, ++ 0x00, 0x27, 0xF1, 0xE7, 0x12, 0x21, 0x00, 0x27, 0xEE, 0xE7, 0x12, 0x21, ++ 0x00, 0x27, 0xEB, 0xE7, 0x00, 0x9B, 0x9A, 0x46, 0x1F, 0xE7, 0xC0, 0x46, ++ 0xEC, 0xA4, 0x16, 0x00, 0x19, 0x03, 0x00, 0x00, 0xD6, 0x03, 0x00, 0x00, ++ 0xF0, 0xB5, 0xC6, 0x46, 0x00, 0xB5, 0x80, 0x46, 0x0D, 0x00, 0x17, 0x00, ++ 0x1C, 0x00, 0x58, 0x4B, 0xE3, 0x18, 0x9A, 0xB2, 0x39, 0x2A, 0x00, 0xD9, ++ 0x90, 0xE0, 0x93, 0x00, 0x55, 0x4A, 0xD3, 0x58, 0x9F, 0x46, 0x02, 0x20, ++ 0xF8, 0xF7, 0x40, 0xFF, 0x53, 0x4B, 0x00, 0x22, 0x44, 0x21, 0x5A, 0x54, ++ 0x40, 0x31, 0x5A, 0x54, 0x40, 0x31, 0x5A, 0x54, 0x40, 0x31, 0x5A, 0x54, ++ 0x40, 0x31, 0x5A, 0x54, 0x00, 0x26, 0x7C, 0xE0, 0x01, 0x20, 0xF8, 0xF7, ++ 0x2F, 0xFF, 0x4B, 0x4B, 0x11, 0x22, 0x44, 0x21, 0x5A, 0x54, 0x40, 0x31, ++ 0x5A, 0x54, 0x40, 0x31, 0x5A, 0x54, 0x40, 0x31, 0x5A, 0x54, 0x40, 0x31, ++ 0x5A, 0x54, 0x00, 0x26, 0x6B, 0xE0, 0x45, 0x4B, 0x1B, 0x78, 0x00, 0x26, ++ 0x00, 0x2B, 0x66, 0xD0, 0x43, 0x49, 0x28, 0x00, 0xFF, 0xF7, 0xB0, 0xFD, ++ 0x05, 0x00, 0x21, 0x00, 0x41, 0x48, 0x7B, 0xF7, 0xDB, 0xFB, 0x41, 0x4B, ++ 0x9C, 0x42, 0x6E, 0xD1, 0x00, 0x26, 0x3B, 0x4A, 0x3F, 0x4B, 0x00, 0x21, ++ 0xD1, 0x54, 0x62, 0xE0, 0x39, 0x4B, 0x1B, 0x78, 0x00, 0x26, 0x00, 0x2B, ++ 0x4F, 0xD0, 0x00, 0x21, 0x3B, 0x48, 0xB2, 0xF7, 0x1F, 0xFD, 0x00, 0x25, ++ 0xE7, 0xE7, 0x4B, 0x78, 0x02, 0x2B, 0x27, 0xD0, 0x38, 0x4E, 0x05, 0x22, ++ 0xFF, 0x21, 0x30, 0x00, 0x77, 0xF7, 0x3E, 0xFB, 0x36, 0x4B, 0xF3, 0x18, ++ 0x36, 0x49, 0x58, 0x5C, 0x1F, 0x22, 0x02, 0x40, 0x5A, 0x54, 0x35, 0x4B, ++ 0x1B, 0x78, 0xEB, 0x81, 0x2B, 0x82, 0x12, 0x23, 0xAB, 0x81, 0x6B, 0x7A, ++ 0x9A, 0x07, 0x07, 0xD5, 0x02, 0x22, 0x93, 0x43, 0x6B, 0x72, 0x12, 0x23, ++ 0xAB, 0x83, 0x6B, 0x8B, 0x9B, 0x00, 0x6B, 0x83, 0x6B, 0x7A, 0x00, 0x26, ++ 0x5B, 0x07, 0x24, 0xD5, 0x12, 0x23, 0xAB, 0x85, 0x6B, 0x8D, 0x5B, 0x00, ++ 0x6B, 0x85, 0x1E, 0xE0, 0x00, 0x23, 0x4B, 0x70, 0xD4, 0xE7, 0x23, 0x4E, ++ 0x05, 0x22, 0xFF, 0x21, 0x30, 0x00, 0x77, 0xF7, 0x13, 0xFB, 0x21, 0x4B, ++ 0xF0, 0x18, 0x21, 0x4A, 0x81, 0x5C, 0x1F, 0x23, 0x0B, 0x40, 0x83, 0x54, ++ 0x20, 0x4B, 0xC6, 0x5C, 0x00, 0x2E, 0x0A, 0xD0, 0x13, 0x4A, 0x00, 0x21, ++ 0xD1, 0x54, 0x06, 0xE0, 0x11, 0x4A, 0x16, 0x4B, 0x00, 0x21, 0xD1, 0x54, ++ 0x00, 0x26, 0x00, 0xE0, 0x00, 0x26, 0x23, 0x00, 0x3A, 0x00, 0x29, 0x00, ++ 0x40, 0x46, 0x18, 0x4D, 0xA8, 0x47, 0x05, 0x00, 0x21, 0x00, 0x0D, 0x48, ++ 0x7B, 0xF7, 0x72, 0xFB, 0x0C, 0x4B, 0x9C, 0x42, 0x97, 0xD0, 0x00, 0x2E, ++ 0x03, 0xD0, 0x06, 0x4A, 0x10, 0x4B, 0x01, 0x21, 0xD1, 0x54, 0x28, 0x00, ++ 0x04, 0xBC, 0x90, 0x46, 0xF0, 0xBD, 0xC0, 0x46, 0xF6, 0xDF, 0xFF, 0xFF, ++ 0xC4, 0xD2, 0x10, 0x00, 0xEC, 0xA4, 0x16, 0x00, 0x60, 0xE6, 0x10, 0x00, ++ 0x0A, 0x20, 0x00, 0x00, 0xB8, 0xD2, 0x10, 0x00, 0x3B, 0x20, 0x00, 0x00, ++ 0x6D, 0x04, 0x00, 0x00, 0x39, 0x20, 0x00, 0x00, 0x05, 0xA8, 0x16, 0x00, ++ 0xE7, 0xFC, 0xFF, 0xFF, 0x1D, 0x03, 0x00, 0x00, 0xE2, 0xE1, 0x10, 0x00, ++ 0xD6, 0x03, 0x00, 0x00, 0x15, 0xC9, 0x0B, 0x00, 0xF0, 0xB5, 0x83, 0xB0, ++ 0x06, 0x00, 0x0D, 0x00, 0x17, 0x00, 0x1C, 0x00, 0x17, 0x4B, 0x9C, 0x42, ++ 0x24, 0xD0, 0x17, 0x4B, 0x9C, 0x42, 0x13, 0xD1, 0xCB, 0x88, 0x10, 0x2B, ++ 0x01, 0xD9, 0x10, 0x23, 0xCB, 0x80, 0x14, 0x4B, 0x1B, 0x78, 0x6A, 0x88, ++ 0x9A, 0x42, 0x01, 0xD8, 0x6B, 0x80, 0xAB, 0x80, 0xEB, 0x88, 0xAA, 0x88, ++ 0x69, 0x88, 0x28, 0x89, 0x00, 0x90, 0x0F, 0x48, 0x7B, 0xF7, 0x26, 0xFB, ++ 0x23, 0x00, 0x3A, 0x00, 0x29, 0x00, 0x30, 0x00, 0x0C, 0x4D, 0xA8, 0x47, ++ 0x05, 0x00, 0x21, 0x00, 0x0B, 0x48, 0x7B, 0xF7, 0x1B, 0xFB, 0x28, 0x00, ++ 0x03, 0xB0, 0xF0, 0xBD, 0x0A, 0x88, 0x00, 0x21, 0x02, 0x48, 0xFF, 0xF7, ++ 0x03, 0xFA, 0x00, 0x25, 0xF1, 0xE7, 0xC0, 0x46, 0x0D, 0x08, 0x00, 0x00, ++ 0x13, 0x20, 0x00, 0x00, 0xE2, 0xE1, 0x10, 0x00, 0xAC, 0xD3, 0x10, 0x00, ++ 0x09, 0x1C, 0x0C, 0x00, 0xBC, 0xD3, 0x10, 0x00, 0xF8, 0xB5, 0xCE, 0x46, ++ 0x47, 0x46, 0x80, 0xB5, 0x14, 0x0A, 0xA4, 0x00, 0x0E, 0x4D, 0x65, 0x59, ++ 0x44, 0x24, 0x2C, 0x5D, 0x03, 0x27, 0x3E, 0x00, 0x26, 0x40, 0x27, 0x42, ++ 0x11, 0xD0, 0xB9, 0x46, 0xBC, 0x43, 0xA4, 0x46, 0x44, 0x24, 0x67, 0x46, ++ 0x2F, 0x55, 0xB9, 0xF7, 0x7F, 0xF8, 0x2B, 0x5D, 0x4A, 0x46, 0x93, 0x43, ++ 0x1E, 0x43, 0x2E, 0x55, 0x00, 0x20, 0x0C, 0xBC, 0x90, 0x46, 0x99, 0x46, ++ 0xF8, 0xBD, 0xB9, 0xF7, 0x73, 0xF8, 0xF7, 0xE7, 0x5C, 0xA9, 0x16, 0x00, ++ 0x70, 0xB5, 0x0D, 0x00, 0x14, 0x0A, 0xA2, 0x00, 0x29, 0x4B, 0xD6, 0x58, ++ 0x0B, 0x2C, 0x06, 0xD8, 0x00, 0x2E, 0x04, 0xD0, 0x44, 0x23, 0xF3, 0x5C, ++ 0xDB, 0x43, 0x9B, 0x07, 0x11, 0xD1, 0x2D, 0x23, 0xEB, 0x5C, 0x00, 0x2B, ++ 0x06, 0xD0, 0x2A, 0x00, 0x16, 0x21, 0x20, 0x00, 0x21, 0x4B, 0x98, 0x47, ++ 0x00, 0x20, 0x70, 0xBD, 0x45, 0x22, 0xB1, 0x5C, 0x7F, 0x23, 0x0B, 0x40, ++ 0xB3, 0x54, 0x00, 0x20, 0xF7, 0xE7, 0x00, 0x21, 0x20, 0x00, 0xB8, 0xF7, ++ 0x83, 0xFC, 0x00, 0x28, 0x2C, 0xD1, 0x42, 0x23, 0xF3, 0x5A, 0xDB, 0x06, ++ 0x04, 0xD5, 0x28, 0x00, 0xB8, 0xF7, 0x92, 0xFC, 0x00, 0x28, 0x25, 0xD0, ++ 0x28, 0x00, 0xB8, 0xF7, 0x8D, 0xFC, 0x00, 0x28, 0x0E, 0xD1, 0x2A, 0x00, ++ 0x00, 0x21, 0x20, 0x00, 0xB8, 0xF7, 0x20, 0xFC, 0x28, 0x00, 0xB8, 0xF7, ++ 0x83, 0xFC, 0x01, 0x00, 0x00, 0x22, 0x20, 0x00, 0x0D, 0x4B, 0x98, 0x47, ++ 0x01, 0x20, 0xD4, 0xE7, 0x28, 0x00, 0xB8, 0xF7, 0x79, 0xFC, 0x01, 0x28, ++ 0xEB, 0xD0, 0x0A, 0x4B, 0xDE, 0x6E, 0x28, 0x00, 0xB8, 0xF7, 0x72, 0xFC, ++ 0x01, 0x00, 0x00, 0x23, 0x00, 0x22, 0x20, 0x00, 0xB0, 0x47, 0xE0, 0xE7, ++ 0x02, 0x20, 0xC2, 0xE7, 0x02, 0x20, 0xC0, 0xE7, 0x5C, 0xA9, 0x16, 0x00, ++ 0x81, 0x45, 0x0C, 0x00, 0xF5, 0x46, 0x0C, 0x00, 0x28, 0x19, 0x16, 0x00, ++ 0xF0, 0xB5, 0xC6, 0x46, 0x00, 0xB5, 0x82, 0xB0, 0x06, 0x00, 0x0D, 0x00, ++ 0x14, 0x00, 0x1F, 0x00, 0x13, 0x0A, 0x9B, 0x00, 0x0E, 0x4A, 0x9B, 0x58, ++ 0x00, 0x2B, 0x0E, 0xD0, 0x89, 0x88, 0x0D, 0x4B, 0x9C, 0x46, 0x61, 0x44, ++ 0x01, 0xAB, 0x98, 0x46, 0x01, 0x22, 0x18, 0x00, 0xD0, 0xF7, 0x5A, 0xF8, ++ 0x43, 0x46, 0x19, 0x78, 0x08, 0x48, 0x7B, 0xF7, 0x61, 0xFA, 0x3B, 0x00, ++ 0x22, 0x00, 0x29, 0x00, 0x30, 0x00, 0xB9, 0xF7, 0x91, 0xF9, 0x02, 0xB0, ++ 0x04, 0xBC, 0x90, 0x46, 0xF0, 0xBD, 0xC0, 0x46, 0x5C, 0xA9, 0x16, 0x00, ++ 0x00, 0x00, 0x61, 0x40, 0xC8, 0xD3, 0x10, 0x00, 0xF8, 0xB5, 0x05, 0x00, ++ 0x0E, 0x00, 0x14, 0x00, 0x1F, 0x00, 0x13, 0x0A, 0x9B, 0x00, 0x08, 0x4A, ++ 0x9B, 0x58, 0x9B, 0x6A, 0x00, 0x2B, 0x03, 0xD0, 0x59, 0x7A, 0x06, 0x48, ++ 0x7B, 0xF7, 0x40, 0xFA, 0x3B, 0x00, 0x22, 0x00, 0x31, 0x00, 0x28, 0x00, ++ 0xB9, 0xF7, 0x50, 0xFA, 0xF8, 0xBD, 0xC0, 0x46, 0x5C, 0xA9, 0x16, 0x00, ++ 0xD4, 0xD3, 0x10, 0x00, 0xF8, 0xB5, 0x04, 0x00, 0x06, 0x0A, 0xB2, 0x00, ++ 0x28, 0x4B, 0xD5, 0x58, 0x28, 0x00, 0x54, 0x30, 0x2A, 0x21, 0xA0, 0xF7, ++ 0x31, 0xFD, 0x00, 0x28, 0x3C, 0xD0, 0xF6, 0xB2, 0x30, 0x00, 0xAA, 0xF7, ++ 0xB5, 0xF8, 0x20, 0x00, 0x91, 0xF7, 0x02, 0xFA, 0x43, 0x23, 0xEB, 0x5C, ++ 0x00, 0x2B, 0x23, 0xD0, 0x1F, 0x4B, 0xEB, 0x5C, 0x00, 0x2B, 0x14, 0xD0, ++ 0x95, 0x23, 0x9B, 0x00, 0xEF, 0x18, 0x38, 0x00, 0x86, 0xF7, 0x80, 0xFA, ++ 0x36, 0x23, 0xE9, 0x5C, 0x3A, 0x00, 0x30, 0x00, 0xA1, 0xF7, 0x42, 0xF8, ++ 0x36, 0x23, 0xEB, 0x5C, 0x01, 0x2B, 0x0A, 0xD0, 0x2D, 0x21, 0x20, 0x00, ++ 0x79, 0xF7, 0x76, 0xFC, 0x22, 0xE0, 0x36, 0x23, 0xE9, 0x5C, 0x30, 0x00, ++ 0xA1, 0xF7, 0x4B, 0xF8, 0xF0, 0xE7, 0x2B, 0x21, 0x20, 0x00, 0x79, 0xF7, ++ 0x6B, 0xFC, 0x17, 0xE0, 0x36, 0x23, 0xEB, 0x5C, 0x01, 0x2B, 0x04, 0xD0, ++ 0x60, 0x21, 0x20, 0x00, 0x79, 0xF7, 0x62, 0xFC, 0x0E, 0xE0, 0x61, 0x21, ++ 0x20, 0x00, 0x79, 0xF7, 0x5D, 0xFC, 0x09, 0xE0, 0x00, 0x23, 0xAC, 0x22, ++ 0x92, 0x00, 0xAB, 0x54, 0x05, 0x4A, 0xAB, 0x54, 0x00, 0x21, 0x20, 0x00, ++ 0x93, 0xF7, 0xA6, 0xFB, 0xF8, 0xBD, 0xC0, 0x46, 0x64, 0xA2, 0x16, 0x00, ++ 0xAF, 0x02, 0x00, 0x00, 0xB3, 0x02, 0x00, 0x00, 0xF8, 0xB5, 0x05, 0x00, ++ 0x0E, 0x00, 0x07, 0x0A, 0xBA, 0x00, 0x1D, 0x4B, 0xD4, 0x58, 0x1D, 0x4B, ++ 0xE3, 0x5C, 0x00, 0x2B, 0x0A, 0xD1, 0x1B, 0x4B, 0x00, 0x22, 0xE2, 0x54, ++ 0x09, 0x3B, 0xE3, 0x5C, 0x00, 0x2B, 0x27, 0xD0, 0x28, 0x00, 0xFF, 0xF7, ++ 0x8F, 0xFF, 0xF8, 0xBD, 0x93, 0xF7, 0xCC, 0xF8, 0x00, 0x28, 0x03, 0xD0, ++ 0x14, 0x4B, 0xE3, 0x5C, 0x00, 0x2B, 0x0C, 0xD0, 0x11, 0x4B, 0xE3, 0x5C, ++ 0x00, 0x2B, 0xE8, 0xD0, 0x88, 0x23, 0xFF, 0x33, 0xE3, 0x5C, 0x00, 0x2B, ++ 0xE3, 0xD0, 0x43, 0x23, 0x01, 0x22, 0xE2, 0x54, 0xDF, 0xE7, 0x04, 0x33, ++ 0x06, 0x22, 0x00, 0x21, 0x0B, 0x48, 0x79, 0xF7, 0xA3, 0xF8, 0x06, 0x70, ++ 0x80, 0x37, 0x47, 0x80, 0xCA, 0xF7, 0xFE, 0xFE, 0x43, 0x23, 0x00, 0x22, ++ 0xE2, 0x54, 0xE3, 0xE7, 0x31, 0x00, 0x28, 0x00, 0x93, 0xF7, 0x60, 0xFB, ++ 0xD5, 0xE7, 0xC0, 0x46, 0x64, 0xA2, 0x16, 0x00, 0xB9, 0x02, 0x00, 0x00, ++ 0xC5, 0x02, 0x00, 0x00, 0x03, 0x11, 0x00, 0x00, 0xF0, 0xB5, 0xC6, 0x46, ++ 0x00, 0xB5, 0x8C, 0xB0, 0x05, 0x00, 0x0C, 0x00, 0x0F, 0x0A, 0xBA, 0x00, ++ 0x4A, 0x4B, 0xD6, 0x58, 0x08, 0x00, 0x79, 0xF7, 0x55, 0xFC, 0x20, 0x28, ++ 0x07, 0xD0, 0x21, 0x00, 0x28, 0x00, 0x47, 0x4B, 0x98, 0x47, 0x0C, 0xB0, ++ 0x04, 0xBC, 0x90, 0x46, 0xF0, 0xBD, 0x2A, 0x78, 0x01, 0x23, 0x13, 0x40, ++ 0x39, 0x22, 0xB3, 0x54, 0x69, 0x1C, 0x29, 0x3A, 0x30, 0x00, 0xCB, 0x30, ++ 0xFF, 0x30, 0xCF, 0xF7, 0x61, 0xFF, 0xFD, 0x23, 0x5B, 0x00, 0x98, 0x46, ++ 0xB0, 0x44, 0x09, 0xAB, 0x07, 0x93, 0x43, 0x46, 0x06, 0x93, 0x02, 0xA8, ++ 0x10, 0x22, 0x31, 0x00, 0xCB, 0x31, 0xFF, 0x31, 0xCF, 0xF7, 0x52, 0xFF, ++ 0x6A, 0x46, 0x33, 0x00, 0x6C, 0x33, 0xF1, 0x6E, 0x00, 0x91, 0x9B, 0x88, ++ 0x93, 0x80, 0xCD, 0x23, 0x5B, 0x00, 0xF3, 0x5A, 0x35, 0x00, 0x9B, 0x35, ++ 0xFF, 0x35, 0x68, 0x88, 0x00, 0x04, 0x18, 0x43, 0xAB, 0x88, 0xE9, 0x88, ++ 0x09, 0x04, 0x19, 0x43, 0x2B, 0x89, 0x6A, 0x89, 0x12, 0x04, 0x1A, 0x43, ++ 0xAB, 0x89, 0x9C, 0x46, 0xEB, 0x89, 0x1B, 0x04, 0x65, 0x46, 0x2B, 0x43, ++ 0x83, 0xF7, 0xDA, 0xFD, 0x27, 0x4B, 0xF3, 0x5C, 0x00, 0x2B, 0x1F, 0xD0, ++ 0x39, 0x23, 0xF2, 0x5C, 0xF8, 0xB2, 0x41, 0x46, 0xA0, 0xF7, 0x93, 0xFE, ++ 0xBE, 0x23, 0x5B, 0x00, 0xF3, 0x5C, 0x00, 0x2B, 0x1B, 0xD0, 0x88, 0x23, ++ 0xFF, 0x33, 0xF3, 0x5C, 0x00, 0x2B, 0x05, 0xD0, 0x01, 0x23, 0xAC, 0x22, ++ 0x92, 0x00, 0xB3, 0x54, 0x1C, 0x4A, 0xB3, 0x54, 0x37, 0x23, 0xF3, 0x5C, ++ 0x05, 0x2B, 0x27, 0xD0, 0x00, 0x21, 0x20, 0x00, 0xFF, 0xF7, 0x44, 0xFF, ++ 0x00, 0x20, 0x9C, 0xE7, 0x0C, 0x22, 0x09, 0xA9, 0x16, 0x4B, 0xF0, 0x18, ++ 0xCF, 0xF7, 0x08, 0xFF, 0xD8, 0xE7, 0x17, 0x33, 0x18, 0x22, 0x00, 0x21, ++ 0x13, 0x48, 0x79, 0xF7, 0x09, 0xF8, 0x05, 0x00, 0xC0, 0x23, 0x5B, 0x00, ++ 0xF3, 0x5C, 0x83, 0x75, 0x06, 0x22, 0x31, 0x00, 0x72, 0x31, 0xCF, 0xF7, ++ 0xF7, 0xFE, 0xA8, 0x1D, 0x10, 0x22, 0x31, 0x00, 0x9B, 0x31, 0xFF, 0x31, ++ 0xCF, 0xF7, 0xF0, 0xFE, 0x28, 0x00, 0xCA, 0xF7, 0x55, 0xFE, 0xC8, 0xE7, ++ 0x05, 0x21, 0x20, 0x00, 0x93, 0xF7, 0x2E, 0xFB, 0x00, 0x20, 0x74, 0xE7, ++ 0x64, 0xA2, 0x16, 0x00, 0x01, 0x4A, 0x0A, 0x00, 0xC5, 0x02, 0x00, 0x00, ++ 0xB3, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x03, 0x11, 0x00, 0x00, ++ 0x70, 0xB5, 0x05, 0x00, 0x0C, 0x00, 0x0B, 0x0A, 0x9B, 0x00, 0x0B, 0x4A, ++ 0x9E, 0x58, 0x08, 0x00, 0x79, 0xF7, 0xAE, 0xFB, 0x24, 0x28, 0x04, 0xD0, ++ 0x21, 0x00, 0x28, 0x00, 0x07, 0x4B, 0x98, 0x47, 0x70, 0xBD, 0xBE, 0x23, ++ 0x5B, 0x00, 0xF3, 0x5C, 0x00, 0x2B, 0xF5, 0xD1, 0x7D, 0x33, 0xFF, 0x33, ++ 0x01, 0x22, 0xF2, 0x54, 0xF0, 0xE7, 0xC0, 0x46, 0x64, 0xA2, 0x16, 0x00, ++ 0x55, 0x45, 0x0A, 0x00, 0xF8, 0xB5, 0xCE, 0x46, 0x47, 0x46, 0x80, 0xB5, ++ 0x05, 0x00, 0x0C, 0x00, 0x0F, 0x0A, 0xBA, 0x00, 0x2F, 0x4B, 0xD6, 0x58, ++ 0x02, 0x78, 0x01, 0x23, 0x13, 0x40, 0x39, 0x22, 0xB3, 0x54, 0x42, 0x78, ++ 0x37, 0x23, 0xF2, 0x54, 0x08, 0x00, 0x79, 0xF7, 0x83, 0xFB, 0x18, 0x28, ++ 0x04, 0xD8, 0x01, 0x23, 0x83, 0x40, 0x28, 0x4A, 0x13, 0x42, 0x2B, 0xD1, ++ 0xFB, 0xB2, 0x99, 0x46, 0x18, 0x00, 0xAA, 0xF7, 0x81, 0xF9, 0x80, 0x46, ++ 0x24, 0x4B, 0x01, 0x22, 0xF2, 0x54, 0x21, 0x00, 0x23, 0x48, 0x78, 0xF7, ++ 0x51, 0xFF, 0x23, 0x4B, 0xF3, 0x5C, 0x00, 0x2B, 0x1F, 0xD1, 0x3C, 0x23, ++ 0xF3, 0x5C, 0x02, 0x2B, 0x2D, 0xD0, 0x48, 0x46, 0xA9, 0xF7, 0x24, 0xFF, ++ 0x36, 0x23, 0xF3, 0x5C, 0x00, 0x2B, 0x2A, 0xD1, 0x43, 0x46, 0x58, 0x00, ++ 0x40, 0x44, 0x40, 0x00, 0x80, 0xB2, 0x7B, 0xF7, 0xE7, 0xF8, 0x02, 0x00, ++ 0x21, 0x00, 0x16, 0x48, 0x78, 0xF7, 0xBE, 0xFE, 0x19, 0x21, 0x20, 0x00, ++ 0x79, 0xF7, 0xF0, 0xFA, 0x00, 0x20, 0x0C, 0xBC, 0x90, 0x46, 0x99, 0x46, ++ 0xF8, 0xBD, 0x04, 0x23, 0x06, 0x22, 0x00, 0x21, 0x10, 0x48, 0x78, 0xF7, ++ 0x6F, 0xFF, 0x6B, 0x78, 0x03, 0x70, 0x80, 0x37, 0x47, 0x80, 0xCA, 0xF7, ++ 0xC9, 0xFD, 0x00, 0x23, 0x0A, 0x4A, 0xB3, 0x54, 0x43, 0x22, 0xB3, 0x54, ++ 0xCD, 0xE7, 0x20, 0x00, 0x09, 0x4B, 0x98, 0x47, 0xCD, 0xE7, 0x43, 0x46, ++ 0x58, 0x00, 0x40, 0x44, 0x80, 0xB2, 0xD4, 0xE7, 0x64, 0xA2, 0x16, 0x00, ++ 0x01, 0x00, 0x40, 0x01, 0xC2, 0x02, 0x00, 0x00, 0x05, 0x06, 0x00, 0x00, ++ 0xB9, 0x02, 0x00, 0x00, 0x03, 0x11, 0x00, 0x00, 0xF5, 0x3A, 0x09, 0x00, ++ 0x00, 0x20, 0x70, 0x47, 0xF0, 0xB5, 0x83, 0xB0, 0x0C, 0x00, 0x04, 0x23, ++ 0x5B, 0x4A, 0x00, 0x21, 0x5B, 0x48, 0x78, 0xF7, 0x41, 0xFF, 0x05, 0x00, ++ 0x21, 0x78, 0x5A, 0x48, 0x7B, 0xF7, 0x40, 0xF8, 0x23, 0x78, 0x01, 0x2B, ++ 0x65, 0xD0, 0x06, 0x2B, 0x00, 0xD1, 0x80, 0xE0, 0x00, 0x2B, 0x05, 0xD0, ++ 0x28, 0x00, 0xCA, 0xF7, 0x91, 0xFD, 0x00, 0x20, 0x03, 0xB0, 0xF0, 0xBD, ++ 0xA2, 0x78, 0x52, 0x4B, 0x1A, 0x70, 0x00, 0x23, 0x2B, 0x70, 0x6B, 0x70, ++ 0xA3, 0x78, 0xAB, 0x70, 0x4F, 0x4B, 0x1B, 0x78, 0xEB, 0x70, 0x63, 0x78, ++ 0x01, 0x2B, 0xEB, 0xD1, 0x4D, 0x4B, 0x1B, 0x68, 0x02, 0x2B, 0xE7, 0xD1, ++ 0x49, 0x4B, 0x1B, 0x78, 0x06, 0x2B, 0xE3, 0xD1, 0xFC, 0xF7, 0x66, 0xF9, ++ 0x49, 0x4C, 0x4A, 0x4B, 0x02, 0x22, 0xE2, 0x54, 0x6B, 0x46, 0xDF, 0x1D, ++ 0x38, 0x00, 0xB2, 0xF7, 0x2D, 0xFC, 0x3E, 0x78, 0x10, 0x23, 0x00, 0x22, ++ 0x00, 0x21, 0x00, 0x20, 0x78, 0xF7, 0x06, 0xFF, 0xB6, 0x01, 0xA6, 0x19, ++ 0xB0, 0x60, 0x3B, 0x78, 0x9B, 0x01, 0xE3, 0x18, 0x9B, 0x68, 0x01, 0x22, ++ 0x9A, 0x70, 0x00, 0x26, 0x1E, 0x71, 0x80, 0x22, 0x92, 0x01, 0xDA, 0x80, ++ 0x1A, 0x81, 0x1E, 0x70, 0x5E, 0x70, 0x38, 0x78, 0x43, 0x1C, 0x9B, 0x01, ++ 0xE3, 0x18, 0x06, 0x22, 0x1A, 0x71, 0x38, 0x4A, 0xA3, 0x5C, 0x03, 0x21, ++ 0x8B, 0x43, 0xA3, 0x54, 0x83, 0x01, 0xE3, 0x18, 0x1E, 0x86, 0x5E, 0x86, ++ 0x34, 0x4B, 0x98, 0x47, 0x3B, 0x78, 0x5A, 0x1C, 0x92, 0x01, 0xA2, 0x18, ++ 0x07, 0x21, 0x11, 0x71, 0x9B, 0x01, 0xE3, 0x18, 0x98, 0x68, 0x0C, 0x38, ++ 0x78, 0xF7, 0x27, 0xFF, 0x3B, 0x78, 0x9B, 0x01, 0xE4, 0x18, 0xA6, 0x60, ++ 0x9E, 0xE7, 0xA3, 0x78, 0x00, 0x2B, 0x0C, 0xD1, 0x24, 0x4B, 0x1B, 0x78, ++ 0x01, 0x33, 0xDB, 0xB2, 0x10, 0x2B, 0x02, 0xD8, 0x21, 0x4A, 0x13, 0x70, ++ 0x07, 0xE0, 0x20, 0x4B, 0x10, 0x22, 0x1A, 0x70, 0x03, 0xE0, 0x1E, 0x4A, ++ 0x13, 0x78, 0x01, 0x3B, 0x13, 0x70, 0x00, 0x23, 0x2B, 0x70, 0x01, 0x33, ++ 0x6B, 0x70, 0xA3, 0x78, 0xAB, 0x70, 0x19, 0x4B, 0x1B, 0x78, 0xEB, 0x70, ++ 0x80, 0xE7, 0xE2, 0x78, 0x12, 0x02, 0xA3, 0x78, 0x13, 0x43, 0x1B, 0x4A, ++ 0x1B, 0xB2, 0x93, 0x42, 0x00, 0xD0, 0x77, 0xE7, 0x19, 0x4B, 0x1A, 0x80, ++ 0x61, 0x79, 0x09, 0x02, 0x22, 0x79, 0x0A, 0x43, 0x5A, 0x80, 0xE1, 0x79, ++ 0x09, 0x02, 0xA2, 0x79, 0x0A, 0x43, 0x9A, 0x80, 0x98, 0x68, 0x00, 0x28, ++ 0x01, 0xD0, 0x79, 0xF7, 0x11, 0xF8, 0x20, 0x7A, 0x10, 0x4E, 0xB0, 0x71, ++ 0x01, 0x21, 0x78, 0xF7, 0x67, 0xFF, 0xB0, 0x60, 0xB2, 0x79, 0x21, 0x00, ++ 0x09, 0x31, 0xCF, 0xF7, 0x87, 0xFD, 0x59, 0xE7, 0x57, 0xFD, 0x00, 0x00, ++ 0x01, 0x11, 0x00, 0x00, 0xE0, 0xD3, 0x10, 0x00, 0xD0, 0xE5, 0x10, 0x00, ++ 0x48, 0x06, 0x16, 0x00, 0xA8, 0xE5, 0x10, 0x00, 0xEC, 0xA4, 0x16, 0x00, ++ 0x6D, 0x04, 0x00, 0x00, 0x6A, 0x04, 0x00, 0x00, 0xE1, 0xEA, 0x0B, 0x00, ++ 0x88, 0xAC, 0xFF, 0xFF, 0xC4, 0xE5, 0x10, 0x00, 0x09, 0x4B, 0x1B, 0x68, ++ 0xDA, 0x6E, 0x53, 0x1C, 0x0C, 0xD0, 0x08, 0x4B, 0x19, 0x68, 0x4B, 0x68, ++ 0x9B, 0x1A, 0x1B, 0x01, 0x1B, 0x09, 0x06, 0x48, 0x83, 0x42, 0x03, 0xD9, ++ 0x04, 0x32, 0x12, 0x01, 0x12, 0x09, 0x4A, 0x60, 0x70, 0x47, 0xC0, 0x46, ++ 0xF4, 0xE1, 0x10, 0x00, 0x28, 0x27, 0x16, 0x00, 0xFE, 0xFF, 0xFF, 0x07, ++ 0x30, 0xB5, 0x83, 0xB0, 0x68, 0x46, 0x77, 0xF7, 0xE5, 0xFC, 0x00, 0x9D, ++ 0x34, 0x4C, 0x23, 0x68, 0x01, 0x22, 0x93, 0x43, 0x23, 0x60, 0x82, 0xF7, ++ 0x51, 0xFE, 0xB1, 0xF7, 0x69, 0xFE, 0x22, 0x68, 0x8C, 0x23, 0x5B, 0x01, ++ 0x13, 0x43, 0x23, 0x60, 0x2E, 0x4B, 0x1B, 0x68, 0x5A, 0x1C, 0x09, 0xD0, ++ 0xAB, 0x42, 0x41, 0xD0, 0x2A, 0x49, 0x0B, 0x68, 0x2B, 0x4A, 0x1A, 0x40, ++ 0x80, 0x23, 0xDB, 0x00, 0x13, 0x43, 0x0B, 0x60, 0x27, 0x4B, 0x5B, 0x68, ++ 0x5A, 0x1C, 0x09, 0xD0, 0xAB, 0x42, 0x36, 0xD0, 0x23, 0x49, 0x0B, 0x68, ++ 0x25, 0x4A, 0x1A, 0x40, 0x80, 0x23, 0x1B, 0x01, 0x13, 0x43, 0x0B, 0x60, ++ 0x20, 0x4B, 0x9B, 0x68, 0x5A, 0x1C, 0x09, 0xD0, 0xAB, 0x42, 0x2B, 0xD0, ++ 0x1C, 0x49, 0x0B, 0x68, 0x1F, 0x4A, 0x1A, 0x40, 0x80, 0x23, 0x9B, 0x00, ++ 0x13, 0x43, 0x0B, 0x60, 0x1D, 0x48, 0x78, 0xF7, 0x3F, 0xFA, 0x18, 0x4B, ++ 0x5B, 0x7F, 0x00, 0x2B, 0x1F, 0xD1, 0x7F, 0xF7, 0x9B, 0xFE, 0x02, 0x28, ++ 0x21, 0xD1, 0x19, 0x49, 0x0B, 0x68, 0x19, 0x4A, 0x1A, 0x40, 0x80, 0x23, ++ 0x9B, 0x03, 0x13, 0x43, 0x0B, 0x60, 0x17, 0x4B, 0x1A, 0x68, 0x01, 0x21, ++ 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, 0x01, 0x31, 0x8A, 0x43, 0x1A, 0x60, ++ 0x03, 0xB0, 0x30, 0xBD, 0x77, 0xF7, 0x4E, 0xFB, 0xC2, 0xE7, 0x77, 0xF7, ++ 0x5F, 0xFB, 0xCD, 0xE7, 0x77, 0xF7, 0x70, 0xFB, 0xD8, 0xE7, 0xFC, 0xF7, ++ 0x49, 0xFB, 0x05, 0x4B, 0x00, 0x22, 0x5A, 0x77, 0xD9, 0xE7, 0x7F, 0xF7, ++ 0x75, 0xFE, 0x03, 0x28, 0xEA, 0xD1, 0xD8, 0xE7, 0x0C, 0x00, 0x60, 0x40, ++ 0x3C, 0x95, 0x16, 0x00, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, ++ 0xFF, 0xFD, 0xFF, 0xFF, 0x01, 0x20, 0x00, 0x00, 0x58, 0x40, 0x34, 0x40, ++ 0xFF, 0xFF, 0xDF, 0xFF, 0x18, 0x00, 0x58, 0x40, 0xF0, 0xB5, 0xCE, 0x46, ++ 0x47, 0x46, 0x80, 0xB5, 0x83, 0xB0, 0x91, 0x46, 0x9C, 0x4B, 0x1E, 0x68, ++ 0x80, 0x00, 0x84, 0x59, 0x3C, 0x23, 0xE3, 0x5C, 0x98, 0x46, 0x9A, 0x4B, ++ 0xE3, 0x61, 0xBD, 0xF7, 0x4D, 0xFA, 0x01, 0x90, 0x00, 0x23, 0xA3, 0x62, ++ 0x00, 0x20, 0xCE, 0xF7, 0x51, 0xFF, 0x96, 0x4B, 0x1D, 0x68, 0xEB, 0x6E, ++ 0x5A, 0x1C, 0x16, 0xD0, 0x63, 0x60, 0x00, 0x23, 0xA3, 0x60, 0xE7, 0x8E, ++ 0xA7, 0x62, 0x92, 0x49, 0x9A, 0x00, 0x52, 0x58, 0x00, 0x2A, 0x25, 0xD1, ++ 0x01, 0x33, 0x07, 0x2B, 0xF8, 0xD1, 0x00, 0x23, 0x9C, 0x46, 0x8E, 0x4B, ++ 0x18, 0x00, 0x41, 0x30, 0xFF, 0x30, 0x00, 0x22, 0x00, 0x21, 0x00, 0x91, ++ 0x1E, 0xE0, 0x8B, 0x4B, 0x1B, 0x68, 0x01, 0x33, 0x09, 0xD0, 0x8A, 0x4B, ++ 0x1B, 0x68, 0x5B, 0x00, 0x01, 0x9A, 0x94, 0x46, 0x63, 0x44, 0x88, 0x4A, ++ 0x13, 0x40, 0x63, 0x60, 0xDB, 0xE7, 0xA3, 0x8E, 0xE2, 0x8E, 0x9B, 0x1A, ++ 0x5B, 0x00, 0x01, 0x9A, 0x94, 0x46, 0x63, 0x44, 0x82, 0x4A, 0x13, 0x40, ++ 0x63, 0x60, 0xD0, 0xE7, 0x01, 0x23, 0x9C, 0x46, 0xDB, 0xE7, 0x40, 0x33, ++ 0x83, 0x42, 0x07, 0xD0, 0x19, 0x78, 0x09, 0x29, 0xF9, 0xD1, 0x01, 0x32, ++ 0xD2, 0xB2, 0x08, 0x39, 0x00, 0x91, 0xF4, 0xE7, 0xEB, 0x6E, 0x59, 0x1C, ++ 0x21, 0xD0, 0x63, 0x60, 0x75, 0x4B, 0x9A, 0x88, 0x77, 0x4B, 0x9A, 0x42, ++ 0x02, 0xD9, 0x77, 0x4B, 0x9C, 0x46, 0x62, 0x44, 0x76, 0x4B, 0x7B, 0x43, ++ 0x93, 0x42, 0x00, 0xD9, 0x13, 0x00, 0x75, 0x4A, 0x93, 0x42, 0x00, 0xD2, ++ 0x13, 0x00, 0x23, 0x61, 0xB3, 0x68, 0x80, 0x22, 0x52, 0x05, 0x93, 0x42, ++ 0x3B, 0xD2, 0x62, 0x68, 0xD3, 0x1A, 0x1B, 0x01, 0x1B, 0x09, 0x6F, 0x4A, ++ 0x93, 0x42, 0x34, 0xD8, 0x6E, 0x4B, 0x98, 0x47, 0xAF, 0xE0, 0x65, 0x4B, ++ 0x1B, 0x68, 0x01, 0x33, 0x07, 0xD0, 0x64, 0x4B, 0x18, 0x68, 0x01, 0x9B, ++ 0x1D, 0x18, 0x63, 0x48, 0x05, 0x40, 0x65, 0x60, 0xD2, 0xE7, 0x63, 0x46, ++ 0x00, 0x2B, 0x03, 0xD1, 0x66, 0x4B, 0x1B, 0x68, 0x00, 0x2B, 0x08, 0xD0, ++ 0x5C, 0x4B, 0x18, 0x68, 0x80, 0x00, 0x01, 0x9B, 0xC5, 0x18, 0x5B, 0x4B, ++ 0x1D, 0x40, 0x65, 0x60, 0xC2, 0xE7, 0x00, 0x9B, 0x00, 0x2B, 0xBF, 0xD0, ++ 0x5F, 0x4B, 0x1B, 0x68, 0x01, 0x2B, 0x06, 0xD9, 0xD3, 0x01, 0x01, 0x9A, ++ 0x9D, 0x18, 0x54, 0x4B, 0x1D, 0x40, 0x65, 0x60, 0xB4, 0xE7, 0x51, 0x4B, ++ 0x1B, 0x68, 0x01, 0x9A, 0xD5, 0x18, 0x50, 0x4B, 0x1D, 0x40, 0x65, 0x60, ++ 0xAC, 0xE7, 0x4B, 0x46, 0x00, 0x2B, 0x05, 0xD1, 0x55, 0x4A, 0x26, 0x33, ++ 0xD3, 0x5C, 0xA3, 0x75, 0x63, 0x68, 0xE3, 0x62, 0x52, 0x4A, 0x27, 0x23, ++ 0xD2, 0x5C, 0x18, 0x3B, 0x1A, 0x40, 0xC0, 0x23, 0xDB, 0x01, 0x13, 0x43, ++ 0xA3, 0x82, 0x3F, 0x23, 0xE1, 0x5C, 0x1B, 0x33, 0x42, 0x46, 0x53, 0x43, ++ 0x4C, 0x4A, 0x98, 0x18, 0x8A, 0x00, 0x11, 0x43, 0x80, 0x22, 0x52, 0x01, ++ 0x0A, 0x43, 0x02, 0x80, 0x21, 0x8D, 0x49, 0x4A, 0x9A, 0x18, 0x11, 0x80, ++ 0x3E, 0x22, 0xA2, 0x5C, 0x0A, 0x3A, 0x01, 0x2A, 0x5A, 0xD9, 0x46, 0x4A, ++ 0x98, 0x18, 0xA1, 0x6A, 0x80, 0x22, 0xD2, 0x01, 0x91, 0x42, 0x00, 0xD3, ++ 0x43, 0x49, 0x44, 0x4A, 0x0A, 0x43, 0x92, 0xB2, 0x02, 0x80, 0x00, 0x21, ++ 0x42, 0x4A, 0x9A, 0x18, 0x11, 0x80, 0x32, 0x7D, 0x92, 0x07, 0x14, 0xD5, ++ 0xF1, 0x7B, 0x09, 0x02, 0xB2, 0x7B, 0x0A, 0x43, 0x3E, 0x49, 0x59, 0x18, ++ 0x0A, 0x80, 0x71, 0x7C, 0x09, 0x02, 0x32, 0x7C, 0x0A, 0x43, 0x3C, 0x49, ++ 0x59, 0x18, 0x0A, 0x80, 0xF1, 0x7C, 0x09, 0x02, 0xB2, 0x7C, 0x0A, 0x43, ++ 0x39, 0x49, 0x59, 0x18, 0x0A, 0x80, 0x71, 0x7D, 0xB5, 0x7D, 0x38, 0x4A, ++ 0x97, 0x78, 0x7A, 0x1E, 0x97, 0x41, 0x30, 0x7D, 0x80, 0x07, 0xC0, 0x0F, ++ 0x01, 0x22, 0x94, 0x46, 0x00, 0x2D, 0x00, 0xD1, 0x84, 0x46, 0x33, 0x4A, ++ 0x9E, 0x18, 0x09, 0x02, 0xAA, 0x01, 0x0A, 0x43, 0xFF, 0x00, 0x3A, 0x43, ++ 0x80, 0x00, 0x02, 0x43, 0x61, 0x46, 0x0A, 0x43, 0x32, 0x80, 0x2E, 0x4A, ++ 0x94, 0x46, 0x63, 0x44, 0x1A, 0x88, 0x1F, 0x21, 0x8A, 0x43, 0x11, 0x00, ++ 0x3E, 0x22, 0xA2, 0x5C, 0x0A, 0x43, 0x1A, 0x80, 0x20, 0x00, 0xCC, 0xF7, ++ 0x71, 0xFF, 0x00, 0x28, 0x0D, 0xD1, 0x00, 0x23, 0x47, 0x22, 0xA3, 0x54, ++ 0x63, 0x87, 0x03, 0xB0, 0x0C, 0xBC, 0x90, 0x46, 0x99, 0x46, 0xF0, 0xBD, ++ 0x22, 0x49, 0x23, 0x4A, 0x9A, 0x18, 0x11, 0x80, 0x9F, 0xE7, 0x22, 0x4B, ++ 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0xEE, 0xE7, ++ 0xE4, 0x29, 0x16, 0x00, 0x71, 0x00, 0x10, 0x00, 0xF4, 0xE1, 0x10, 0x00, ++ 0x38, 0x27, 0x16, 0x00, 0x70, 0xA6, 0x16, 0x00, 0x5C, 0xAB, 0x16, 0x00, ++ 0xE4, 0xE1, 0x10, 0x00, 0xFE, 0xFF, 0xFF, 0x0F, 0xC4, 0x09, 0x00, 0x00, ++ 0x3C, 0xF6, 0xFF, 0xFF, 0xE2, 0x04, 0x00, 0x00, 0xA6, 0x0E, 0x00, 0x00, ++ 0xFE, 0xFF, 0xFF, 0x07, 0x39, 0xC2, 0x0C, 0x00, 0xF0, 0x29, 0x16, 0x00, ++ 0x50, 0xE0, 0x10, 0x00, 0x7C, 0x91, 0x0D, 0x00, 0x7A, 0x01, 0x61, 0x40, ++ 0x96, 0x01, 0x61, 0x40, 0x90, 0x01, 0x61, 0x40, 0xFF, 0x3F, 0x00, 0x00, ++ 0x00, 0x80, 0xFF, 0xFF, 0xBC, 0x01, 0x61, 0x40, 0x7C, 0x01, 0x61, 0x40, ++ 0x7E, 0x01, 0x61, 0x40, 0x80, 0x01, 0x61, 0x40, 0xE8, 0x29, 0x16, 0x00, ++ 0x8A, 0x01, 0x61, 0x40, 0x76, 0x01, 0x61, 0x40, 0x72, 0x3E, 0x00, 0x00, ++ 0x9E, 0x01, 0x61, 0x40, 0x28, 0x19, 0x16, 0x00, 0x10, 0xB5, 0x10, 0x23, ++ 0x0F, 0x4A, 0x00, 0x21, 0x0F, 0x48, 0x78, 0xF7, 0x53, 0xFC, 0x00, 0x22, ++ 0x02, 0x70, 0x05, 0x23, 0x43, 0x70, 0x04, 0x3B, 0x83, 0x70, 0x80, 0x21, ++ 0x89, 0x00, 0x81, 0x80, 0xFE, 0x39, 0xFF, 0x39, 0x81, 0x71, 0xC3, 0x71, ++ 0x0B, 0x31, 0x01, 0x72, 0x43, 0x72, 0x53, 0x31, 0x41, 0x81, 0x57, 0x39, ++ 0x81, 0x81, 0x83, 0x73, 0xC2, 0x73, 0xCA, 0xF7, 0x9B, 0xFA, 0x00, 0x20, ++ 0x10, 0xBD, 0xC0, 0x46, 0x53, 0xFD, 0x00, 0x00, 0x01, 0x11, 0x00, 0x00, ++ 0x10, 0xB5, 0x10, 0x4A, 0x11, 0x68, 0xA0, 0x23, 0x5B, 0x03, 0x0B, 0x43, ++ 0x13, 0x60, 0x0E, 0x4C, 0x01, 0x23, 0x23, 0x60, 0x05, 0x20, 0x7F, 0xF7, ++ 0x10, 0xFD, 0x00, 0x23, 0x23, 0x60, 0x0B, 0x49, 0x04, 0x22, 0x0B, 0x68, ++ 0x1A, 0x42, 0xFC, 0xD0, 0x06, 0x4A, 0x13, 0x68, 0x08, 0x49, 0x0B, 0x40, ++ 0x13, 0x60, 0x08, 0x4C, 0x01, 0x23, 0x23, 0x60, 0x05, 0x20, 0x7F, 0xF7, ++ 0xFE, 0xFC, 0x00, 0x23, 0x23, 0x60, 0x10, 0xBD, 0x58, 0x40, 0x34, 0x40, ++ 0x54, 0x40, 0x34, 0x40, 0x80, 0x40, 0x34, 0x40, 0xFF, 0xFF, 0xEB, 0xFF, ++ 0x48, 0x20, 0x62, 0x40, 0xF0, 0xB5, 0xDE, 0x46, 0x57, 0x46, 0x4E, 0x46, ++ 0x45, 0x46, 0xE0, 0xB5, 0x87, 0xB0, 0x04, 0x90, 0x0F, 0x00, 0x16, 0x00, ++ 0xEF, 0xF3, 0x10, 0x83, 0x01, 0x22, 0x11, 0x00, 0x19, 0x40, 0x05, 0x91, ++ 0x1A, 0x42, 0x00, 0xD1, 0x72, 0xB6, 0x04, 0x9A, 0x93, 0x00, 0xA3, 0x49, ++ 0x8C, 0x46, 0x63, 0x44, 0x1C, 0x68, 0xA2, 0x46, 0xA1, 0x4B, 0x63, 0x62, ++ 0xE5, 0x6C, 0x84, 0x23, 0xE3, 0x5A, 0xDB, 0x07, 0x00, 0xD5, 0x4F, 0xE2, ++ 0x93, 0x00, 0x9E, 0x4A, 0x9B, 0x58, 0x1A, 0x8A, 0x00, 0x2A, 0x0E, 0xD0, ++ 0x84, 0x23, 0xE3, 0x5A, 0x5B, 0x07, 0x00, 0xD5, 0x36, 0xE2, 0x9A, 0x4B, ++ 0x23, 0x61, 0xA2, 0x6E, 0x99, 0x4B, 0x1B, 0x68, 0x9A, 0x42, 0x00, 0xD1, ++ 0x3C, 0xE2, 0x96, 0x4B, 0x2F, 0xE2, 0x06, 0x32, 0x1A, 0x82, 0x96, 0x48, ++ 0x7A, 0xF7, 0xD0, 0xFC, 0xEA, 0xE7, 0x96, 0x23, 0x00, 0x22, 0xE2, 0x54, ++ 0x00, 0x2E, 0x00, 0xD1, 0x34, 0xE2, 0x20, 0x3B, 0xE3, 0x5A, 0x00, 0x2B, ++ 0x00, 0xD1, 0x2F, 0xE2, 0x80, 0x21, 0xC9, 0x00, 0x8E, 0x4A, 0x02, 0x40, ++ 0x8A, 0x42, 0x00, 0xD0, 0x28, 0xE2, 0x02, 0x07, 0x00, 0xD5, 0x25, 0xE2, ++ 0x4A, 0x22, 0xA2, 0x5C, 0x00, 0x2A, 0x00, 0xD0, 0x20, 0xE2, 0xA2, 0x6E, ++ 0x5A, 0x43, 0x55, 0x19, 0x2D, 0x01, 0x2D, 0x09, 0x7E, 0x22, 0xA1, 0x5A, ++ 0x5B, 0x18, 0xA3, 0x52, 0x96, 0x23, 0x7D, 0x3A, 0xE2, 0x54, 0x7B, 0x1B, ++ 0x1B, 0x01, 0x1B, 0x09, 0x81, 0x4A, 0x93, 0x42, 0x00, 0xD8, 0x13, 0xE2, ++ 0xE7, 0x6D, 0x2B, 0xE2, 0x46, 0x33, 0xE3, 0x5C, 0x00, 0x2B, 0x00, 0xD0, ++ 0x26, 0xE2, 0x7C, 0x33, 0xE3, 0x5A, 0x7E, 0x22, 0xA2, 0x5A, 0x9B, 0x18, ++ 0x48, 0x22, 0xA2, 0x5A, 0x9B, 0x1A, 0x79, 0x4A, 0x9B, 0xB2, 0x93, 0x42, ++ 0x00, 0xD9, 0x19, 0xE2, 0x46, 0x23, 0xE3, 0x5C, 0x00, 0x2B, 0x21, 0xD1, ++ 0x40, 0x33, 0xE3, 0x5A, 0x5D, 0x19, 0x2D, 0x01, 0x2D, 0x09, 0xC3, 0x07, ++ 0x00, 0xD4, 0xCA, 0xE1, 0x44, 0x23, 0xE3, 0x5A, 0x5B, 0x08, 0x5D, 0x19, ++ 0x2D, 0x01, 0x2D, 0x09, 0xA3, 0x6B, 0xA3, 0x66, 0x42, 0x23, 0xE2, 0x5A, ++ 0x34, 0x33, 0xE2, 0x52, 0xE3, 0x6B, 0xE3, 0x66, 0x46, 0x23, 0x01, 0x22, ++ 0xE2, 0x54, 0x48, 0x33, 0xE0, 0x5C, 0x68, 0x4B, 0x98, 0x47, 0x84, 0x23, ++ 0xE3, 0x5A, 0xDB, 0x07, 0x00, 0xD4, 0xBB, 0xE1, 0x7C, 0x23, 0xE2, 0x5A, ++ 0x02, 0x33, 0xE3, 0x5A, 0xD2, 0x18, 0x48, 0x23, 0xE3, 0x5A, 0xD2, 0x1A, ++ 0x92, 0xB2, 0x53, 0x1E, 0x9B, 0xB2, 0x00, 0x2A, 0x0A, 0xD0, 0xA1, 0x6E, ++ 0x2F, 0x00, 0x5E, 0x4A, 0x7F, 0x1A, 0x3F, 0x01, 0x3F, 0x09, 0x01, 0x3B, ++ 0x9B, 0xB2, 0x93, 0x42, 0xF8, 0xD1, 0xDB, 0xE1, 0x2F, 0x00, 0xD9, 0xE1, ++ 0x00, 0x2B, 0x00, 0xD1, 0x5F, 0xE1, 0x68, 0xE1, 0x01, 0x3B, 0x1B, 0x01, ++ 0x1B, 0x09, 0x56, 0x4A, 0x94, 0x46, 0xE0, 0x44, 0x78, 0xE1, 0x2B, 0x00, ++ 0x63, 0x60, 0x50, 0x46, 0xCC, 0xF7, 0xFA, 0xFD, 0x00, 0x28, 0x00, 0xD1, ++ 0x2E, 0xE1, 0xA3, 0x7D, 0x50, 0x49, 0x2F, 0x22, 0x8A, 0x5C, 0x9B, 0x18, ++ 0xA3, 0x75, 0x84, 0x23, 0xE3, 0x5A, 0x9B, 0x07, 0x02, 0xD5, 0x03, 0x9B, ++ 0x00, 0x2B, 0x4C, 0xD0, 0xA3, 0x6E, 0x9C, 0x46, 0x65, 0x44, 0x2D, 0x01, ++ 0x2D, 0x09, 0x7E, 0x22, 0xA3, 0x5A, 0x01, 0x33, 0xA3, 0x52, 0xA3, 0x7D, ++ 0x01, 0x33, 0xA3, 0x75, 0x4A, 0x23, 0xE3, 0x5C, 0x01, 0x2B, 0x00, 0xD1, ++ 0x8C, 0xE0, 0xEB, 0x1B, 0x1B, 0x01, 0x1B, 0x09, 0x99, 0x45, 0x00, 0xD8, ++ 0xF5, 0xE0, 0x84, 0x23, 0xE3, 0x5A, 0xDB, 0x07, 0xCF, 0xD5, 0x72, 0x23, ++ 0xE3, 0x5E, 0x98, 0x46, 0x63, 0x6D, 0xEE, 0x1A, 0x36, 0x01, 0x36, 0x09, ++ 0x77, 0xF7, 0x3C, 0xFF, 0x14, 0x23, 0x00, 0x28, 0x02, 0xD1, 0xC4, 0x33, ++ 0x37, 0x4A, 0xD3, 0x5A, 0x7A, 0x22, 0xA0, 0x5A, 0xC0, 0x18, 0x70, 0x43, ++ 0xC8, 0x21, 0xC9, 0x00, 0xCE, 0xF7, 0xA2, 0xFD, 0x20, 0x30, 0x46, 0x00, ++ 0x84, 0x23, 0xE3, 0x5A, 0x9B, 0x07, 0x00, 0xD5, 0x04, 0xE1, 0x74, 0x23, ++ 0xE2, 0x5A, 0x53, 0x01, 0x9B, 0x1A, 0x9B, 0x00, 0x9B, 0x18, 0x9A, 0x00, ++ 0x9B, 0x18, 0xF6, 0x18, 0x4A, 0x23, 0xE3, 0x5C, 0x01, 0x2B, 0x00, 0xD0, ++ 0x05, 0xE1, 0x46, 0x23, 0xE3, 0x5C, 0x00, 0x2B, 0x00, 0xD0, 0x8E, 0xE1, ++ 0xFF, 0xE0, 0xF7, 0xF7, 0xB1, 0xFE, 0x00, 0x28, 0xAE, 0xD0, 0x24, 0x4B, ++ 0x1A, 0x78, 0x01, 0x23, 0x00, 0x2A, 0x08, 0xD0, 0x22, 0x4B, 0x1B, 0x78, ++ 0x01, 0x3B, 0x5A, 0x1E, 0x93, 0x41, 0x5B, 0x42, 0x06, 0x22, 0x93, 0x43, ++ 0x08, 0x33, 0xA0, 0x6E, 0x02, 0x00, 0x5A, 0x43, 0x80, 0x21, 0x49, 0x00, ++ 0x8A, 0x42, 0x0C, 0xD9, 0x5A, 0x1E, 0xD2, 0xB2, 0x42, 0x43, 0x8C, 0x46, ++ 0x00, 0xE0, 0x0A, 0x00, 0x01, 0x3B, 0xDB, 0xB2, 0x62, 0x45, 0x02, 0xD9, ++ 0x11, 0x1A, 0x00, 0x2B, 0xF7, 0xD1, 0x55, 0x19, 0x2D, 0x01, 0x2D, 0x09, ++ 0x7E, 0x21, 0x62, 0x5A, 0xD3, 0x18, 0x63, 0x52, 0x01, 0x23, 0x03, 0x93, ++ 0x8B, 0xE7, 0xC0, 0x46, 0xF4, 0x29, 0x16, 0x00, 0x95, 0x9D, 0x10, 0x00, ++ 0x5C, 0xA9, 0x16, 0x00, 0xDE, 0x0D, 0x00, 0x00, 0x64, 0xE6, 0x10, 0x00, ++ 0xEC, 0xD3, 0x10, 0x00, 0x04, 0x04, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x07, ++ 0xFE, 0x7F, 0x00, 0x00, 0xF1, 0x12, 0x0D, 0x00, 0xFF, 0xFF, 0x00, 0x00, ++ 0x71, 0x02, 0x00, 0x00, 0x7C, 0x91, 0x0D, 0x00, 0x8C, 0xA9, 0x16, 0x00, ++ 0xB4, 0xE6, 0x10, 0x00, 0xB3, 0xE6, 0x10, 0x00, 0x46, 0x33, 0xE3, 0x5C, ++ 0x00, 0x2B, 0x00, 0xD0, 0x6D, 0xE7, 0x7C, 0x33, 0xE3, 0x5A, 0x7E, 0x22, ++ 0xA2, 0x5A, 0x9B, 0x18, 0x48, 0x22, 0xA2, 0x5A, 0x9B, 0x1A, 0x9F, 0x4A, ++ 0x9B, 0xB2, 0x93, 0x42, 0x00, 0xD9, 0x60, 0xE7, 0x46, 0x23, 0xE3, 0x5C, ++ 0x00, 0x2B, 0x26, 0xD1, 0x40, 0x33, 0xE3, 0x5A, 0x5D, 0x19, 0x2D, 0x01, ++ 0x2D, 0x09, 0x84, 0x23, 0xE3, 0x5A, 0xDB, 0x07, 0x00, 0xD4, 0x76, 0xE0, ++ 0x44, 0x23, 0xE3, 0x5A, 0x5B, 0x08, 0x5D, 0x19, 0x2D, 0x01, 0x2D, 0x09, ++ 0xA3, 0x6B, 0xA3, 0x66, 0x42, 0x23, 0xE2, 0x5A, 0x34, 0x33, 0xE2, 0x52, ++ 0xE3, 0x6B, 0xE3, 0x66, 0x8E, 0x23, 0xE0, 0x5C, 0x8E, 0x4B, 0x98, 0x47, ++ 0x46, 0x23, 0x01, 0x22, 0xE2, 0x54, 0xE3, 0x6E, 0x99, 0x46, 0x84, 0x23, ++ 0xE3, 0x5A, 0xDB, 0x07, 0x01, 0xD4, 0x47, 0x23, 0xE2, 0x54, 0x7C, 0x23, ++ 0xE2, 0x5A, 0x02, 0x33, 0xE3, 0x5A, 0xD2, 0x18, 0x48, 0x23, 0xE3, 0x5A, ++ 0xD2, 0x1A, 0x92, 0xB2, 0x53, 0x1E, 0x9B, 0xB2, 0x00, 0x2A, 0x0A, 0xD0, ++ 0xA1, 0x6E, 0x2F, 0x00, 0x81, 0x4A, 0x7F, 0x1A, 0x3F, 0x01, 0x3F, 0x09, ++ 0x01, 0x3B, 0x9B, 0xB2, 0x93, 0x42, 0xF8, 0xD1, 0x1D, 0xE7, 0x2F, 0x00, ++ 0x1B, 0xE7, 0x7D, 0x4B, 0x00, 0x22, 0x1A, 0x70, 0x7C, 0x4B, 0x1B, 0x68, ++ 0x00, 0x21, 0x1B, 0x02, 0x0A, 0xD5, 0x7B, 0x48, 0x7A, 0xF7, 0x2E, 0xFB, ++ 0x84, 0x23, 0xE2, 0x5A, 0x92, 0x07, 0xD2, 0x17, 0x4F, 0x3B, 0x9A, 0x43, ++ 0x3E, 0x32, 0x0A, 0xE0, 0x01, 0x20, 0xF8, 0xF7, 0x85, 0xFA, 0x01, 0x21, ++ 0xEF, 0xE7, 0x84, 0x23, 0xE3, 0x5A, 0x08, 0x22, 0x9B, 0x07, 0x00, 0xD4, ++ 0xB6, 0xE0, 0x01, 0x21, 0x04, 0x98, 0x70, 0x4B, 0x98, 0x47, 0x05, 0x9B, ++ 0x00, 0x2B, 0x00, 0xD1, 0x62, 0xB6, 0x07, 0xB0, 0x3C, 0xBC, 0x90, 0x46, ++ 0x99, 0x46, 0xA2, 0x46, 0xAB, 0x46, 0xF0, 0xBD, 0x8F, 0x23, 0x00, 0x22, ++ 0xE2, 0x54, 0xE5, 0x64, 0x0B, 0x3B, 0xE3, 0x5A, 0x9A, 0x07, 0x02, 0xD5, ++ 0x62, 0x4A, 0x00, 0x21, 0x11, 0x70, 0xDB, 0x07, 0xE7, 0xD5, 0x70, 0x23, ++ 0x42, 0x46, 0xE2, 0x52, 0x1C, 0x36, 0x26, 0x65, 0xE1, 0xE7, 0xA3, 0x6B, ++ 0xA3, 0x66, 0x42, 0x23, 0xE2, 0x5A, 0x34, 0x33, 0xE2, 0x52, 0xE3, 0x6B, ++ 0xE3, 0x66, 0x91, 0xE7, 0x4A, 0x23, 0xE3, 0x5C, 0x01, 0x2B, 0x00, 0xD1, ++ 0x91, 0xE0, 0xA2, 0x6E, 0x53, 0x01, 0x9B, 0x1A, 0x9B, 0x00, 0x9B, 0x18, ++ 0x9A, 0x00, 0x9B, 0x18, 0x5B, 0x08, 0xB3, 0x42, 0xBF, 0xD9, 0x73, 0x08, ++ 0x9B, 0x46, 0x54, 0x49, 0x18, 0x00, 0xCE, 0xF7, 0x81, 0xFC, 0x01, 0x00, ++ 0x2B, 0x1A, 0x1B, 0x01, 0x1B, 0x09, 0x40, 0x01, 0x40, 0x1A, 0x80, 0x00, ++ 0x40, 0x18, 0x82, 0x00, 0x80, 0x18, 0x42, 0x46, 0x59, 0x46, 0x52, 0x1A, ++ 0x82, 0x18, 0x90, 0x46, 0x00, 0xD5, 0x7F, 0xE6, 0x42, 0x46, 0xA2, 0x60, ++ 0x22, 0x6E, 0x92, 0x19, 0x22, 0x61, 0x81, 0xE6, 0xE3, 0x6E, 0x99, 0x46, ++ 0xEB, 0x1B, 0x1B, 0x01, 0x1B, 0x09, 0x08, 0x22, 0x99, 0x45, 0xA0, 0xD9, ++ 0x00, 0x23, 0x03, 0x93, 0x1C, 0x26, 0x98, 0x46, 0x9F, 0xE6, 0xA3, 0x6B, ++ 0xA3, 0x66, 0x42, 0x23, 0xE2, 0x5A, 0x34, 0x33, 0xE2, 0x52, 0xE3, 0x6B, ++ 0xE3, 0x66, 0x46, 0x23, 0x01, 0x22, 0xE2, 0x54, 0x47, 0x23, 0x01, 0x22, ++ 0xE2, 0x54, 0x3F, 0xE6, 0x39, 0x4B, 0x23, 0x61, 0xA2, 0x6E, 0xA1, 0x6D, ++ 0x00, 0x20, 0x01, 0x90, 0x00, 0x93, 0x00, 0x23, 0x20, 0x00, 0xF7, 0xF7, ++ 0xC1, 0xFB, 0x35, 0x4B, 0xA2, 0x6E, 0x1A, 0x60, 0x84, 0x23, 0xE0, 0x5A, ++ 0xC3, 0x43, 0x9B, 0x07, 0x00, 0xD1, 0xC4, 0xE5, 0x7B, 0x1B, 0x1B, 0x01, ++ 0x1B, 0x09, 0x30, 0x4A, 0x93, 0x42, 0x13, 0xD8, 0xA1, 0x6E, 0x7E, 0x23, ++ 0xE2, 0x5A, 0x01, 0x32, 0x92, 0xB2, 0x2C, 0x4E, 0x4D, 0x19, 0x2D, 0x01, ++ 0x2D, 0x09, 0x03, 0x92, 0x01, 0x32, 0x92, 0xB2, 0x7B, 0x1B, 0x1B, 0x01, ++ 0x1B, 0x09, 0xB3, 0x42, 0xF4, 0xD9, 0x7E, 0x23, 0x03, 0x9A, 0xE2, 0x52, ++ 0xE7, 0x6D, 0x4A, 0x23, 0xE3, 0x5C, 0x01, 0x2B, 0x00, 0xD1, 0xD3, 0xE5, ++ 0x84, 0x23, 0xE3, 0x5A, 0x9B, 0x07, 0xAB, 0xD4, 0x14, 0x23, 0xA3, 0x75, ++ 0xA2, 0x6E, 0x53, 0x00, 0x9B, 0x18, 0x5B, 0x00, 0x99, 0x46, 0xEB, 0x1B, ++ 0x1B, 0x01, 0x1B, 0x09, 0x4B, 0x45, 0xA7, 0xD3, 0x12, 0x4B, 0x1B, 0x78, ++ 0x01, 0x33, 0xDB, 0xB2, 0x03, 0x2B, 0x00, 0xD9, 0x23, 0xE7, 0x0F, 0x4A, ++ 0x13, 0x70, 0x3E, 0x22, 0x3D, 0xE7, 0x46, 0x23, 0xE3, 0x5C, 0x00, 0x2B, ++ 0x00, 0xD1, 0x68, 0xE7, 0x00, 0x23, 0x47, 0x22, 0xA2, 0x5C, 0x00, 0x2A, ++ 0x00, 0xD0, 0xFF, 0xE5, 0x44, 0x23, 0xE2, 0x5A, 0x53, 0x01, 0x9B, 0x1A, ++ 0x9B, 0x00, 0x9B, 0x18, 0x9A, 0x00, 0x9B, 0x18, 0xF6, 0x18, 0x62, 0xE7, ++ 0xFE, 0x7F, 0x00, 0x00, 0xF1, 0x12, 0x0D, 0x00, 0xFF, 0xFF, 0x00, 0x00, ++ 0x61, 0xE6, 0x10, 0x00, 0x58, 0x40, 0x34, 0x40, 0xF8, 0xD3, 0x10, 0x00, ++ 0x65, 0x17, 0x0D, 0x00, 0x71, 0x02, 0x00, 0x00, 0x42, 0x0E, 0x00, 0x00, ++ 0x64, 0xE6, 0x10, 0x00, 0xFE, 0xFF, 0xFF, 0x07, 0xF8, 0xB5, 0x04, 0x1E, ++ 0x32, 0xD0, 0xA1, 0xF7, 0x55, 0xFD, 0x05, 0x00, 0x8F, 0x23, 0xE6, 0x5C, ++ 0x00, 0x2E, 0x17, 0xD1, 0xE3, 0x6C, 0xA2, 0x6E, 0x94, 0x46, 0x63, 0x44, ++ 0x1B, 0x01, 0x1B, 0x09, 0xE3, 0x64, 0x7E, 0x22, 0xA3, 0x5A, 0x01, 0x33, ++ 0xA3, 0x52, 0xA3, 0x7D, 0x13, 0x49, 0x4F, 0x3A, 0x8A, 0x5C, 0x9B, 0x18, ++ 0xA3, 0x75, 0x8E, 0x23, 0xE0, 0x5C, 0x00, 0x22, 0x29, 0x00, 0xFF, 0xF7, ++ 0x01, 0xFD, 0xF8, 0xBD, 0x67, 0x68, 0xA1, 0xF7, 0x35, 0xFD, 0x03, 0x00, ++ 0x3A, 0x00, 0x31, 0x00, 0x0B, 0x48, 0x7A, 0xF7, 0x03, 0xFA, 0x8F, 0x23, ++ 0xE3, 0x5C, 0x00, 0x2B, 0xDA, 0xD0, 0x09, 0x4B, 0x9B, 0x6E, 0x00, 0x22, ++ 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0xD3, 0xE7, 0x05, 0x4B, 0x9B, 0x6E, ++ 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0xE3, 0xE7, 0xC0, 0x46, ++ 0x7C, 0x91, 0x0D, 0x00, 0x08, 0xD4, 0x10, 0x00, 0x28, 0x19, 0x16, 0x00, ++ 0xF0, 0xB5, 0xC6, 0x46, 0x00, 0xB5, 0x80, 0x46, 0x0F, 0x00, 0x16, 0x00, ++ 0x1D, 0x00, 0x02, 0x21, 0x10, 0x20, 0x78, 0xF7, 0xAD, 0xF9, 0x04, 0x00, ++ 0x04, 0x23, 0x03, 0x70, 0xFB, 0x33, 0x43, 0x70, 0xF2, 0x3B, 0x83, 0x70, ++ 0x43, 0x46, 0xC3, 0x70, 0x47, 0x60, 0x86, 0x60, 0xC5, 0x60, 0x1F, 0x4B, ++ 0x1B, 0x68, 0x02, 0x2B, 0x1A, 0xD0, 0x01, 0x2B, 0x30, 0xD1, 0x1D, 0x4B, ++ 0x1B, 0x68, 0x00, 0x2B, 0x0D, 0xD0, 0x0A, 0x25, 0x1B, 0x4F, 0x80, 0x26, ++ 0xB6, 0x02, 0xE8, 0x20, 0x7F, 0xF7, 0xA7, 0xF9, 0x3B, 0x68, 0x33, 0x42, ++ 0x25, 0xD1, 0x01, 0x3D, 0xED, 0xB2, 0x00, 0x2D, 0xF5, 0xD1, 0x00, 0x23, ++ 0x15, 0x4A, 0x10, 0x21, 0x20, 0x00, 0x81, 0xF7, 0x6D, 0xFC, 0x17, 0xE0, ++ 0x13, 0x48, 0x14, 0x49, 0x01, 0x22, 0x43, 0x58, 0x1A, 0x42, 0xFC, 0xD1, ++ 0x10, 0x4B, 0x12, 0x4A, 0x9C, 0x50, 0x12, 0x4A, 0x99, 0x58, 0x10, 0x20, ++ 0x01, 0x43, 0x99, 0x50, 0x81, 0x21, 0x49, 0x01, 0x5A, 0x58, 0x02, 0x43, ++ 0x5A, 0x50, 0x0B, 0x49, 0x5A, 0x58, 0x0F, 0x38, 0x02, 0x43, 0x5A, 0x50, ++ 0x04, 0xBC, 0x90, 0x46, 0xF0, 0xBD, 0x0A, 0x4B, 0x80, 0x22, 0x92, 0x02, ++ 0x1A, 0x60, 0xD8, 0xE7, 0xA8, 0xE5, 0x10, 0x00, 0x28, 0x25, 0x16, 0x00, ++ 0x1C, 0x41, 0x04, 0x40, 0x19, 0x74, 0x08, 0x00, 0x00, 0x00, 0x07, 0x40, ++ 0x08, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x1C, 0x10, 0x00, 0x00, ++ 0x08, 0x41, 0x04, 0x40, 0x02, 0x4B, 0x80, 0x22, 0xD2, 0x04, 0x1A, 0x60, ++ 0x70, 0x47, 0xC0, 0x46, 0x00, 0x41, 0x04, 0x40, 0x10, 0xB5, 0x01, 0x00, ++ 0x13, 0x00, 0xEF, 0xF3, 0x10, 0x82, 0xD2, 0x07, 0x00, 0xD4, 0x72, 0xB6, ++ 0x74, 0x46, 0x0E, 0x4A, 0x94, 0x42, 0x0F, 0xD0, 0x22, 0x00, 0x0D, 0x48, ++ 0x7A, 0xF7, 0x6A, 0xF9, 0x23, 0x00, 0x00, 0x22, 0x00, 0x21, 0x57, 0x20, ++ 0xFF, 0xF7, 0x7A, 0xFF, 0x09, 0x4B, 0x1B, 0x68, 0x01, 0x2B, 0x05, 0xD0, ++ 0x72, 0xB6, 0xFE, 0xE7, 0x07, 0x48, 0x7A, 0xF7, 0x5B, 0xF9, 0x10, 0xBD, ++ 0x06, 0x4B, 0x80, 0x22, 0xD2, 0x04, 0x1A, 0x60, 0xF4, 0xE7, 0xC0, 0x46, ++ 0xB9, 0x25, 0x0D, 0x00, 0x40, 0xD4, 0x10, 0x00, 0xA8, 0xE5, 0x10, 0x00, ++ 0x18, 0xD4, 0x10, 0x00, 0x00, 0x41, 0x04, 0x40, 0x70, 0xB5, 0x82, 0xB0, ++ 0x04, 0x00, 0x0D, 0x00, 0xEF, 0xF3, 0x10, 0x82, 0xD2, 0x07, 0x00, 0xD4, ++ 0x72, 0xB6, 0x76, 0x46, 0x00, 0x93, 0x33, 0x00, 0x2A, 0x00, 0x21, 0x00, ++ 0x09, 0x48, 0x7A, 0xF7, 0x39, 0xF9, 0x33, 0x00, 0x2A, 0x00, 0x21, 0x00, ++ 0x57, 0x20, 0xFF, 0xF7, 0x49, 0xFF, 0x06, 0x4B, 0x1B, 0x68, 0x01, 0x2B, ++ 0x01, 0xD0, 0x72, 0xB6, 0xFE, 0xE7, 0x04, 0x4B, 0x80, 0x22, 0xD2, 0x04, ++ 0x1A, 0x60, 0xF8, 0xE7, 0x64, 0xD4, 0x10, 0x00, 0xA8, 0xE5, 0x10, 0x00, ++ 0x00, 0x41, 0x04, 0x40, 0xF0, 0xB5, 0xDE, 0x46, 0x57, 0x46, 0x4E, 0x46, ++ 0x45, 0x46, 0xE0, 0xB5, 0x87, 0xB0, 0x65, 0x4B, 0x1E, 0x68, 0x07, 0x20, ++ 0xA1, 0xF7, 0xA4, 0xF9, 0x00, 0x28, 0x06, 0xD1, 0x07, 0xB0, 0x3C, 0xBC, ++ 0x90, 0x46, 0x99, 0x46, 0xA2, 0x46, 0xAB, 0x46, 0xF0, 0xBD, 0x5F, 0x4A, ++ 0xD5, 0x23, 0x5B, 0x00, 0xD3, 0x5C, 0xDC, 0x00, 0xE4, 0x1A, 0x64, 0x00, ++ 0x5C, 0x4B, 0xE3, 0x18, 0x1D, 0x88, 0xAD, 0xB2, 0xA1, 0xF7, 0x62, 0xF9, ++ 0x6B, 0x07, 0xE9, 0xD1, 0x3A, 0x23, 0xF3, 0x5C, 0x02, 0x2B, 0x52, 0xD0, ++ 0x57, 0x4B, 0xE3, 0x18, 0x1B, 0x88, 0x9B, 0xB2, 0x98, 0x46, 0x56, 0x4B, ++ 0xE2, 0x18, 0x13, 0x88, 0x5B, 0x06, 0x1B, 0x0F, 0x02, 0x2B, 0x08, 0xD0, ++ 0x10, 0x88, 0x40, 0x06, 0x00, 0x0F, 0x52, 0x4B, 0xDF, 0x6E, 0x00, 0x23, ++ 0x00, 0x22, 0x00, 0x21, 0xB8, 0x47, 0x39, 0x23, 0xF3, 0x5C, 0x00, 0x2B, ++ 0x01, 0xD0, 0xEB, 0x05, 0x53, 0xD4, 0x10, 0x23, 0xFF, 0x22, 0x00, 0x21, ++ 0x4B, 0x48, 0x77, 0xF7, 0xD5, 0xFF, 0x07, 0x00, 0x00, 0x23, 0x83, 0x73, ++ 0xFB, 0x1D, 0xBA, 0x1D, 0x02, 0x92, 0x05, 0xAA, 0x01, 0x92, 0x00, 0x22, ++ 0x00, 0x92, 0x3A, 0x00, 0x00, 0x21, 0x40, 0x46, 0xB0, 0xF7, 0x7C, 0xFC, ++ 0x43, 0x4B, 0x19, 0x88, 0x43, 0x4B, 0x1B, 0x88, 0x05, 0x9A, 0x92, 0x00, ++ 0x09, 0x04, 0x0B, 0x43, 0xD3, 0x1A, 0x6A, 0xD4, 0xDB, 0x03, 0x5B, 0x0C, ++ 0x7B, 0x81, 0x3F, 0x4B, 0x9C, 0x46, 0x64, 0x44, 0x23, 0x88, 0x3B, 0x73, ++ 0xED, 0x05, 0xED, 0x0F, 0x7D, 0x73, 0x38, 0x00, 0x77, 0xF7, 0xD8, 0xFF, ++ 0x3C, 0x23, 0xF3, 0x5C, 0x3B, 0x22, 0xB2, 0x5C, 0x9A, 0x42, 0x00, 0xD8, ++ 0x96, 0xE7, 0x01, 0x33, 0x3C, 0x22, 0xB3, 0x54, 0x92, 0xE7, 0x37, 0x33, ++ 0xF3, 0x5C, 0x00, 0x2B, 0x00, 0xD1, 0x8D, 0xE7, 0xEB, 0x05, 0x00, 0xD4, ++ 0x8A, 0xE7, 0x07, 0x20, 0xA1, 0xF7, 0x2A, 0xF9, 0x00, 0x28, 0x00, 0xD1, ++ 0x84, 0xE7, 0x25, 0x4A, 0xD5, 0x23, 0x5B, 0x00, 0xD2, 0x5C, 0xD3, 0x00, ++ 0x9B, 0x1A, 0x5B, 0x00, 0x22, 0x4A, 0x94, 0x46, 0x63, 0x44, 0x1B, 0x88, ++ 0xA1, 0xF7, 0xEE, 0xF8, 0x76, 0xE7, 0x07, 0x20, 0xA1, 0xF7, 0x16, 0xF9, ++ 0x00, 0x28, 0xA6, 0xD0, 0x1B, 0x4A, 0xD5, 0x23, 0x5B, 0x00, 0xD2, 0x5C, ++ 0xD3, 0x00, 0x9B, 0x1A, 0x5B, 0x00, 0x19, 0x4A, 0x9A, 0x18, 0x12, 0x88, ++ 0x52, 0x07, 0x02, 0xD0, 0xA1, 0xF7, 0xDA, 0xF8, 0x97, 0xE7, 0x1D, 0x4A, ++ 0x9A, 0x18, 0x11, 0x88, 0x8A, 0xB2, 0x91, 0x46, 0x1B, 0x4A, 0x94, 0x46, ++ 0x63, 0x44, 0x1B, 0x88, 0xDB, 0x08, 0x9B, 0x46, 0xFF, 0x23, 0x5A, 0x46, ++ 0x1A, 0x40, 0x92, 0x46, 0x13, 0x00, 0x10, 0x33, 0xFF, 0x22, 0x00, 0x21, ++ 0x0F, 0x48, 0x77, 0xF7, 0x5D, 0xFF, 0x07, 0x00, 0x5B, 0x46, 0x83, 0x73, ++ 0x12, 0x49, 0x49, 0x44, 0x0F, 0x30, 0x52, 0x46, 0xCE, 0xF7, 0x4C, 0xFE, ++ 0xA1, 0xF7, 0xB8, 0xF8, 0x7E, 0xE7, 0x80, 0x22, 0x52, 0x05, 0x94, 0x46, ++ 0x63, 0x44, 0x8F, 0xE7, 0x18, 0x27, 0x16, 0x00, 0x20, 0xA3, 0x16, 0x00, ++ 0x92, 0x69, 0x61, 0x40, 0x9C, 0x69, 0x61, 0x40, 0x94, 0x69, 0x61, 0x40, ++ 0x28, 0x19, 0x16, 0x00, 0x01, 0x05, 0x00, 0x00, 0xFA, 0x67, 0x61, 0x40, ++ 0xF8, 0x67, 0x61, 0x40, 0x98, 0x69, 0x61, 0x40, 0x9A, 0x69, 0x61, 0x40, ++ 0x96, 0x69, 0x61, 0x40, 0x00, 0x00, 0x61, 0x40, 0x70, 0xB5, 0xA1, 0xF7, ++ 0x5F, 0xFB, 0x05, 0x00, 0x0F, 0x4B, 0x1C, 0x68, 0x00, 0x2C, 0x06, 0xD1, ++ 0x0E, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, ++ 0x70, 0xBD, 0xFF, 0xF7, 0x03, 0xFF, 0x01, 0x21, 0x20, 0x00, 0xCC, 0xF7, ++ 0x81, 0xFB, 0x3A, 0x23, 0xE3, 0x5C, 0x02, 0x2B, 0x06, 0xD0, 0x07, 0x4B, ++ 0x1B, 0x7D, 0xA3, 0x75, 0x65, 0x60, 0x06, 0x4B, 0x98, 0x47, 0xED, 0xE7, ++ 0x05, 0x4B, 0x98, 0x47, 0xEA, 0xE7, 0xC0, 0x46, 0x18, 0x27, 0x16, 0x00, ++ 0x28, 0x19, 0x16, 0x00, 0x7C, 0x91, 0x0D, 0x00, 0xE5, 0xC1, 0x0A, 0x00, ++ 0x99, 0xC1, 0x0A, 0x00, 0x70, 0xB5, 0x0D, 0x00, 0x14, 0x00, 0x07, 0x29, ++ 0x06, 0xD0, 0x11, 0x4B, 0xDE, 0x6E, 0x00, 0x23, 0x00, 0x22, 0x21, 0x00, ++ 0x28, 0x00, 0xB0, 0x47, 0x01, 0x2C, 0x0E, 0xD9, 0x04, 0x2C, 0x0F, 0xD1, ++ 0x0C, 0x4B, 0x1C, 0x68, 0x01, 0x21, 0x20, 0x00, 0xCC, 0xF7, 0x52, 0xFB, ++ 0x3A, 0x23, 0x00, 0x22, 0xE2, 0x54, 0x20, 0x00, 0x08, 0x4B, 0x98, 0x47, ++ 0x01, 0xE0, 0xFF, 0xF7, 0xB3, 0xFF, 0x70, 0xBD, 0x03, 0x4B, 0xDE, 0x6E, ++ 0x00, 0x23, 0x00, 0x22, 0x21, 0x00, 0x28, 0x00, 0xB0, 0x47, 0xF6, 0xE7, ++ 0x28, 0x19, 0x16, 0x00, 0x18, 0x27, 0x16, 0x00, 0xD1, 0xC2, 0x0A, 0x00, ++ 0x10, 0xB5, 0x01, 0x28, 0x00, 0xD0, 0x10, 0xBD, 0x00, 0x29, 0xFC, 0xD0, ++ 0x04, 0x4B, 0x1B, 0x68, 0x00, 0x2B, 0xF8, 0xD0, 0x03, 0x4A, 0xDA, 0x61, ++ 0x03, 0x48, 0x79, 0xF7, 0xCB, 0xFF, 0xF2, 0xE7, 0x24, 0x27, 0x16, 0x00, ++ 0x85, 0x04, 0x10, 0x00, 0x94, 0xD4, 0x10, 0x00, 0x70, 0xB5, 0x1E, 0x4B, ++ 0x1E, 0x4A, 0x13, 0x60, 0x80, 0x22, 0x52, 0x00, 0x9C, 0x5C, 0x1D, 0x4B, ++ 0xE3, 0x18, 0x1B, 0x01, 0x1A, 0x88, 0xD2, 0x08, 0x06, 0x21, 0x11, 0x42, ++ 0x08, 0xD1, 0x19, 0x88, 0x89, 0x06, 0x49, 0x0F, 0x18, 0x4B, 0xDD, 0x6E, ++ 0x00, 0x23, 0x00, 0x22, 0x20, 0x00, 0xA8, 0x47, 0x13, 0x4B, 0x1A, 0x68, ++ 0x81, 0x23, 0x5B, 0x00, 0xD3, 0x5C, 0x00, 0x2B, 0x05, 0xD1, 0x12, 0x4B, ++ 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x0D, 0x4B, ++ 0x1B, 0x68, 0x22, 0x01, 0x9B, 0x18, 0x1B, 0x7B, 0x00, 0x2B, 0x05, 0xD1, ++ 0x0B, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, ++ 0x06, 0x4B, 0x1A, 0x68, 0x23, 0x01, 0xD3, 0x18, 0x5D, 0x68, 0x00, 0x2D, ++ 0x03, 0xD0, 0x99, 0x68, 0x18, 0x68, 0x02, 0x22, 0xA8, 0x47, 0x70, 0xBD, ++ 0x80, 0x2A, 0x16, 0x00, 0x0C, 0xE7, 0x10, 0x00, 0x00, 0x10, 0x06, 0x04, ++ 0x28, 0x19, 0x16, 0x00, 0x10, 0xB5, 0xFF, 0x23, 0x9B, 0x00, 0x98, 0x42, ++ 0x08, 0xD9, 0x05, 0x4B, 0x59, 0x80, 0x00, 0x24, 0x21, 0x00, 0x04, 0x48, ++ 0x79, 0xF7, 0x72, 0xFF, 0x20, 0x00, 0x10, 0xBD, 0x11, 0x24, 0xF7, 0xE7, ++ 0x54, 0x2A, 0x16, 0x00, 0xA0, 0xD4, 0x10, 0x00, 0x70, 0xB5, 0x04, 0x00, ++ 0x0D, 0x00, 0x81, 0x88, 0x00, 0x88, 0xFF, 0xF7, 0xE5, 0xFF, 0x01, 0x1E, ++ 0x04, 0xD0, 0x28, 0x00, 0xFC, 0xF7, 0x90, 0xFE, 0x00, 0x20, 0x70, 0xBD, ++ 0xE1, 0x88, 0xA0, 0x78, 0xCB, 0xF7, 0xB6, 0xFE, 0x01, 0x00, 0xF4, 0xE7, ++ 0xF0, 0xB5, 0xCE, 0x46, 0x47, 0x46, 0x80, 0xB5, 0x89, 0xB0, 0x06, 0x00, ++ 0x0A, 0x00, 0x04, 0x23, 0x00, 0x21, 0x26, 0x48, 0x77, 0xF7, 0x46, 0xFE, ++ 0x80, 0x46, 0x00, 0x23, 0x43, 0x80, 0xB1, 0x79, 0x23, 0x48, 0x79, 0xF7, ++ 0x43, 0xFF, 0xB3, 0x79, 0x00, 0x2B, 0x2A, 0xD1, 0x60, 0x24, 0x6B, 0x46, ++ 0xDD, 0x1D, 0x16, 0x23, 0x99, 0x46, 0x1F, 0x4F, 0x07, 0xE0, 0x03, 0x23, ++ 0x42, 0x46, 0x13, 0x70, 0x24, 0xE0, 0x01, 0x34, 0xE4, 0xB2, 0x68, 0x2C, ++ 0x20, 0xD0, 0x4B, 0x46, 0x2B, 0x70, 0x02, 0xAA, 0x29, 0x00, 0x20, 0x00, ++ 0x3B, 0x68, 0x98, 0x47, 0x00, 0x28, 0xF2, 0xD1, 0x06, 0x22, 0x02, 0xA9, ++ 0x30, 0x00, 0xCE, 0xF7, 0xF3, 0xFC, 0x00, 0x28, 0xEB, 0xD1, 0x12, 0x4B, ++ 0x9B, 0x68, 0x20, 0x00, 0x98, 0x47, 0x00, 0x28, 0xE1, 0xD1, 0x43, 0x46, ++ 0x5B, 0x88, 0x01, 0x33, 0x42, 0x46, 0x53, 0x80, 0x04, 0xE0, 0x01, 0x2B, ++ 0x0B, 0xD0, 0x12, 0x23, 0x42, 0x46, 0x13, 0x70, 0x40, 0x46, 0xC9, 0xF7, ++ 0x69, 0xFC, 0x00, 0x20, 0x09, 0xB0, 0x0C, 0xBC, 0x90, 0x46, 0x99, 0x46, ++ 0xF0, 0xBD, 0x43, 0x46, 0x5B, 0x88, 0x08, 0x33, 0x42, 0x46, 0x53, 0x80, ++ 0xF0, 0xE7, 0xC0, 0x46, 0x01, 0x11, 0x00, 0x00, 0xAC, 0xD4, 0x10, 0x00, ++ 0x94, 0x92, 0x16, 0x00, 0xF0, 0xB5, 0xDE, 0x46, 0x57, 0x46, 0x4E, 0x46, ++ 0x45, 0x46, 0xE0, 0xB5, 0x85, 0xB0, 0x0C, 0x00, 0x16, 0x00, 0x17, 0x0A, ++ 0xBA, 0x00, 0x91, 0x4B, 0xD5, 0x58, 0x50, 0x23, 0xEB, 0x5C, 0x00, 0x2B, ++ 0x00, 0xD0, 0xD6, 0xE0, 0x4B, 0x78, 0x5B, 0x08, 0x98, 0x46, 0x7F, 0x2B, ++ 0x11, 0xD0, 0x01, 0x93, 0x00, 0x22, 0x19, 0x00, 0x8A, 0x48, 0x79, 0xF7, ++ 0xDD, 0xFE, 0x43, 0x46, 0x7E, 0x2B, 0x56, 0xD1, 0x36, 0x3B, 0xEB, 0x5C, ++ 0x00, 0x2B, 0x43, 0xD0, 0x00, 0x23, 0x9B, 0x46, 0x7E, 0x33, 0x01, 0x93, ++ 0x0C, 0xE0, 0x8B, 0x78, 0x9B, 0x46, 0x1A, 0x00, 0x7F, 0x21, 0x81, 0x48, ++ 0x79, 0xF7, 0xCA, 0xFE, 0x7F, 0x23, 0x01, 0x93, 0x48, 0x23, 0xEB, 0x5C, ++ 0x00, 0x2B, 0x43, 0xD0, 0xFB, 0xB2, 0x99, 0x46, 0x61, 0x78, 0x4F, 0x08, ++ 0x59, 0x29, 0x00, 0xD8, 0xE0, 0xE0, 0x7F, 0x2F, 0x05, 0xD1, 0xA3, 0x78, ++ 0x9A, 0x46, 0x0D, 0x2B, 0x55, 0xD8, 0x0B, 0x2B, 0x55, 0xD8, 0x07, 0x23, ++ 0x02, 0xAA, 0x94, 0x46, 0x63, 0x44, 0x9A, 0x46, 0x23, 0x78, 0x52, 0x46, ++ 0x13, 0x70, 0x14, 0x23, 0x32, 0x00, 0x31, 0x00, 0x70, 0x48, 0x77, 0xF7, ++ 0xA3, 0xFD, 0x07, 0x00, 0x61, 0x1C, 0x52, 0x46, 0x82, 0xF7, 0x30, 0xF9, ++ 0x02, 0x28, 0x75, 0xD0, 0x00, 0x28, 0x00, 0xD1, 0xA9, 0xE0, 0x04, 0x28, ++ 0x00, 0xD0, 0x99, 0xE0, 0xFB, 0x22, 0x43, 0x46, 0x15, 0x3B, 0x13, 0x42, ++ 0x00, 0xD1, 0xB1, 0xE0, 0x19, 0x24, 0x6F, 0xE0, 0x36, 0x33, 0xEB, 0x5C, ++ 0x5A, 0x42, 0x53, 0x41, 0xDB, 0xB2, 0xF8, 0xB2, 0x0C, 0x22, 0x7E, 0x21, ++ 0x9F, 0xF7, 0xC7, 0xFA, 0x00, 0x23, 0x9B, 0x46, 0x7E, 0x33, 0x01, 0x93, ++ 0xBE, 0xE7, 0x00, 0x23, 0x9B, 0x46, 0xB7, 0xE7, 0x59, 0x46, 0x40, 0x46, ++ 0x82, 0xF7, 0x96, 0xF8, 0x00, 0x28, 0xB5, 0xD1, 0x43, 0x46, 0x7F, 0x2B, ++ 0x0A, 0xD0, 0x36, 0x23, 0xEB, 0x5C, 0x5A, 0x42, 0x53, 0x41, 0xDB, 0xB2, ++ 0xF8, 0xB2, 0x0C, 0x22, 0x41, 0x46, 0x9F, 0xF7, 0xAC, 0xFA, 0x5A, 0xE0, ++ 0x49, 0x3B, 0xEB, 0x5C, 0x5A, 0x42, 0x53, 0x41, 0xDB, 0xB2, 0xF8, 0xB2, ++ 0x0C, 0x22, 0x59, 0x46, 0x9F, 0xF7, 0xB0, 0xFA, 0x4F, 0xE0, 0x15, 0x2B, ++ 0xA9, 0xD1, 0x4B, 0x46, 0x9B, 0x00, 0x48, 0x4A, 0x9B, 0x58, 0xB2, 0x22, ++ 0x92, 0x00, 0x9A, 0x5C, 0x00, 0x2A, 0xA0, 0xD0, 0xCA, 0x07, 0x9E, 0xD5, ++ 0x46, 0x4A, 0x9A, 0x5C, 0xBA, 0x42, 0x14, 0xD1, 0x7F, 0x2F, 0x98, 0xD1, ++ 0x44, 0x4A, 0x9B, 0x5C, 0x53, 0x45, 0x94, 0xD0, 0x4B, 0x46, 0x1B, 0x02, ++ 0x01, 0x20, 0x18, 0x43, 0x78, 0xF7, 0x16, 0xF9, 0x00, 0x28, 0x30, 0xD0, ++ 0x01, 0x23, 0x2A, 0x22, 0x51, 0x46, 0x48, 0x46, 0x9F, 0xF7, 0x8A, 0xFA, ++ 0x29, 0xE0, 0x4B, 0x46, 0x1B, 0x02, 0x01, 0x20, 0x18, 0x43, 0x78, 0xF7, ++ 0x07, 0xF9, 0x00, 0x28, 0x21, 0xD0, 0x7F, 0x2F, 0xEE, 0xD0, 0x01, 0x23, ++ 0x2A, 0x22, 0x39, 0x00, 0x48, 0x46, 0x9F, 0xF7, 0x6A, 0xFA, 0x18, 0xE0, ++ 0x33, 0x4B, 0xDC, 0x6E, 0x00, 0x23, 0x00, 0x22, 0x01, 0x99, 0x08, 0x00, ++ 0xA0, 0x47, 0x1E, 0x24, 0x38, 0x00, 0x0C, 0x38, 0x77, 0xF7, 0x69, 0xFD, ++ 0x43, 0x46, 0x7F, 0x2B, 0x1C, 0xD0, 0x36, 0x23, 0xEB, 0x5C, 0x5A, 0x42, ++ 0x53, 0x41, 0xDB, 0xB2, 0x22, 0x00, 0x41, 0x46, 0x48, 0x46, 0x9F, 0xF7, ++ 0x50, 0xFA, 0x8A, 0x23, 0xFF, 0x33, 0xEB, 0x5C, 0x00, 0x2B, 0x03, 0xD0, ++ 0x25, 0x4B, 0xEB, 0x5C, 0x00, 0x2B, 0x18, 0xD1, 0x00, 0x20, 0x05, 0xB0, ++ 0x3C, 0xBC, 0x90, 0x46, 0x99, 0x46, 0xA2, 0x46, 0xAB, 0x46, 0xF0, 0xBD, ++ 0x1E, 0x24, 0xDB, 0xE7, 0x49, 0x3B, 0xEB, 0x5C, 0x5A, 0x42, 0x53, 0x41, ++ 0xDB, 0xB2, 0x22, 0x00, 0x59, 0x46, 0x48, 0x46, 0x9F, 0xF7, 0x42, 0xFA, ++ 0xE1, 0xE7, 0x38, 0x00, 0x77, 0xF7, 0x16, 0xFD, 0xDD, 0xE7, 0xAA, 0x8D, ++ 0xEB, 0x8D, 0xD2, 0x1A, 0x31, 0x00, 0x16, 0x48, 0x77, 0xF7, 0x24, 0xFC, ++ 0xAA, 0x8D, 0x31, 0x00, 0x14, 0x48, 0x77, 0xF7, 0x1F, 0xFC, 0xD9, 0xE7, ++ 0x38, 0x00, 0x0C, 0x38, 0x77, 0xF7, 0x29, 0xFD, 0x1A, 0x24, 0xC0, 0xE7, ++ 0x12, 0x2F, 0x00, 0xD8, 0x23, 0xE7, 0x3A, 0x00, 0x13, 0x3A, 0xD2, 0xB2, ++ 0x01, 0x23, 0x93, 0x40, 0x0C, 0x4A, 0x13, 0x42, 0x00, 0xD1, 0x1A, 0xE7, ++ 0x00, 0x23, 0x9A, 0x46, 0x6D, 0xE7, 0xC0, 0x46, 0x64, 0xA2, 0x16, 0x00, ++ 0xBC, 0xD4, 0x10, 0x00, 0x01, 0x06, 0x00, 0x00, 0xC6, 0x02, 0x00, 0x00, ++ 0xC7, 0x02, 0x00, 0x00, 0x28, 0x19, 0x16, 0x00, 0xAF, 0x02, 0x00, 0x00, ++ 0x09, 0x06, 0x00, 0x00, 0x0A, 0x06, 0x00, 0x00, 0x31, 0x00, 0x00, 0x03, ++ 0x30, 0xB5, 0x87, 0xB0, 0x1E, 0x4C, 0x23, 0x7B, 0x03, 0x22, 0x13, 0x43, ++ 0x23, 0x73, 0x03, 0xAD, 0x21, 0x00, 0x27, 0x31, 0x03, 0x22, 0x28, 0x00, ++ 0xCE, 0xF7, 0x9E, 0xFB, 0xE3, 0x89, 0xAB, 0x80, 0x23, 0x8A, 0xEB, 0x80, ++ 0xA3, 0x7C, 0x2B, 0x72, 0x23, 0x7F, 0x6B, 0x72, 0x28, 0x00, 0xA2, 0xF7, ++ 0x3F, 0xFB, 0x23, 0x00, 0x3C, 0x33, 0x00, 0x24, 0x1A, 0x78, 0x00, 0x2A, ++ 0x06, 0xD0, 0x01, 0x34, 0xE4, 0xB2, 0x09, 0x33, 0x07, 0x2C, 0xF7, 0xD1, ++ 0x07, 0xB0, 0x30, 0xBD, 0x06, 0x2C, 0xFB, 0xD8, 0x01, 0xA8, 0x0B, 0x4B, ++ 0x1A, 0x8B, 0x02, 0x80, 0x5A, 0x8B, 0x42, 0x80, 0x5B, 0x7F, 0x03, 0x71, ++ 0x44, 0x71, 0x08, 0x4A, 0xD0, 0x23, 0xD3, 0x58, 0x98, 0x47, 0x00, 0x28, ++ 0xEC, 0xD1, 0xE3, 0x00, 0x1B, 0x19, 0x03, 0x4C, 0xE4, 0x18, 0x3C, 0x34, ++ 0x02, 0x23, 0x23, 0x70, 0xE4, 0xE7, 0xC0, 0x46, 0x68, 0x9E, 0x16, 0x00, ++ 0x28, 0x19, 0x16, 0x00, 0x10, 0xB5, 0x07, 0x4C, 0xA0, 0x47, 0x86, 0xF7, ++ 0x97, 0xF8, 0x00, 0x28, 0x01, 0xD1, 0x00, 0x20, 0x10, 0xBD, 0xFF, 0xF7, ++ 0xB1, 0xFF, 0x03, 0x48, 0x79, 0xF7, 0x66, 0xFD, 0xF7, 0xE7, 0xC0, 0x46, ++ 0xDD, 0x90, 0x0A, 0x00, 0xCC, 0xD4, 0x10, 0x00, 0x00, 0xB5, 0x83, 0xB0, ++ 0x01, 0xAA, 0x01, 0x23, 0x0B, 0x40, 0x30, 0x21, 0x0B, 0x43, 0x13, 0x70, ++ 0x11, 0x00, 0x9F, 0xF7, 0x41, 0xF9, 0x03, 0xB0, 0x00, 0xBD, 0x00, 0x00, ++ 0x30, 0xB5, 0x83, 0xB0, 0x04, 0x00, 0x00, 0x0A, 0x82, 0x00, 0x0E, 0x4B, ++ 0xD2, 0x58, 0x3C, 0x23, 0xD3, 0x5C, 0x02, 0x2B, 0x07, 0xD0, 0x96, 0x22, ++ 0x52, 0x00, 0x21, 0x00, 0x0A, 0x48, 0x77, 0xF7, 0x7D, 0xFB, 0x03, 0xB0, ++ 0x30, 0xBD, 0x6B, 0x46, 0x9D, 0x1D, 0xC0, 0xB2, 0x00, 0x22, 0x29, 0x00, ++ 0x89, 0xF7, 0xEE, 0xFA, 0x28, 0x88, 0x79, 0xF7, 0x95, 0xFD, 0x40, 0x00, ++ 0x02, 0x00, 0x2D, 0x32, 0xFF, 0x32, 0xEA, 0xE7, 0x64, 0xA2, 0x16, 0x00, ++ 0x05, 0x06, 0x00, 0x00, 0x10, 0xB5, 0x04, 0x00, 0x00, 0x0A, 0x82, 0x00, ++ 0x07, 0x4B, 0xD2, 0x58, 0x36, 0x23, 0xD1, 0x5C, 0xC0, 0xB2, 0xFF, 0xF7, ++ 0xC1, 0xFF, 0x20, 0x00, 0xFF, 0xF7, 0xCC, 0xFF, 0x32, 0x21, 0x20, 0x00, ++ 0x77, 0xF7, 0x8C, 0xFF, 0x10, 0xBD, 0xC0, 0x46, 0x64, 0xA2, 0x16, 0x00, ++ 0x70, 0xB5, 0x14, 0x00, 0x15, 0x0A, 0xAA, 0x00, 0x17, 0x4B, 0xD6, 0x58, ++ 0x20, 0x00, 0x77, 0xF7, 0xDF, 0xFF, 0x03, 0x00, 0x19, 0x28, 0x1D, 0xD8, ++ 0x01, 0x38, 0xC0, 0xB2, 0x14, 0x28, 0x06, 0xD8, 0x02, 0x20, 0x01, 0x2B, ++ 0x15, 0xD1, 0x3C, 0x23, 0xF3, 0x5C, 0x02, 0x2B, 0x16, 0xD0, 0x08, 0x23, ++ 0x14, 0x22, 0x00, 0x21, 0x0D, 0x48, 0x77, 0xF7, 0xF5, 0xFB, 0x0C, 0x23, ++ 0x03, 0x70, 0x80, 0x35, 0x45, 0x80, 0x00, 0x23, 0xC3, 0x80, 0x3C, 0x33, ++ 0xF3, 0x5C, 0x03, 0x71, 0xC9, 0xF7, 0x4A, 0xFA, 0x00, 0x20, 0x70, 0xBD, ++ 0x02, 0x20, 0x66, 0x2B, 0xFB, 0xD1, 0xE4, 0xE7, 0x20, 0x00, 0xFF, 0xF7, ++ 0xB9, 0xFF, 0x00, 0x20, 0xF5, 0xE7, 0xC0, 0x46, 0x64, 0xA2, 0x16, 0x00, ++ 0x03, 0x11, 0x00, 0x00, 0x70, 0xB5, 0x82, 0xB0, 0x14, 0x00, 0x15, 0x0A, ++ 0xAA, 0x00, 0x24, 0x4B, 0xD6, 0x58, 0x20, 0x00, 0x77, 0xF7, 0xA6, 0xFF, ++ 0x01, 0x28, 0x16, 0xD0, 0x04, 0xD9, 0x16, 0x38, 0xC3, 0xB2, 0x02, 0x20, ++ 0x03, 0x2B, 0x0E, 0xD8, 0x06, 0x23, 0x1C, 0x22, 0x00, 0x21, 0x1D, 0x48, ++ 0x77, 0xF7, 0xC2, 0xFB, 0x02, 0x23, 0x03, 0x70, 0x80, 0x35, 0x45, 0x80, ++ 0x00, 0x23, 0x83, 0x80, 0xC9, 0xF7, 0x1A, 0xFA, 0x00, 0x20, 0x02, 0xB0, ++ 0x70, 0xBD, 0x36, 0x23, 0xF3, 0x5C, 0x00, 0x2B, 0x0E, 0xD1, 0x01, 0xA9, ++ 0x0A, 0x33, 0x0B, 0x70, 0xE8, 0xB2, 0x9F, 0xF7, 0x9D, 0xF8, 0x20, 0x00, ++ 0xFF, 0xF7, 0x5C, 0xFF, 0x06, 0x21, 0x20, 0x00, 0x77, 0xF7, 0x1C, 0xFF, ++ 0x00, 0x20, 0xEA, 0xE7, 0x06, 0x23, 0x1C, 0x22, 0x00, 0x21, 0x0B, 0x48, ++ 0x77, 0xF7, 0x9E, 0xFB, 0x04, 0x00, 0x00, 0x23, 0x03, 0x70, 0x2B, 0x00, ++ 0x80, 0x33, 0x43, 0x80, 0xE8, 0xB2, 0xA8, 0xF7, 0x3D, 0xFF, 0x00, 0x04, ++ 0x40, 0x0C, 0xA0, 0x80, 0x20, 0x00, 0xC9, 0xF7, 0xEF, 0xF9, 0x00, 0x20, ++ 0xD3, 0xE7, 0xC0, 0x46, 0x64, 0xA2, 0x16, 0x00, 0x03, 0x11, 0x00, 0x00, ++ 0x70, 0xB5, 0x14, 0x00, 0x13, 0x0A, 0x9B, 0x00, 0x14, 0x4A, 0x9D, 0x58, ++ 0x20, 0x00, 0x77, 0xF7, 0x55, 0xFF, 0x00, 0x28, 0x1E, 0xD0, 0x16, 0x38, ++ 0xC3, 0xB2, 0x00, 0x20, 0x03, 0x2B, 0x13, 0xD9, 0x43, 0x23, 0x01, 0x22, ++ 0xEA, 0x54, 0x07, 0x3B, 0xEB, 0x5C, 0x02, 0x2B, 0x0D, 0xD0, 0x37, 0x23, ++ 0xE9, 0x5C, 0x20, 0x00, 0x8B, 0xF7, 0x32, 0xF8, 0x00, 0x28, 0x0D, 0xD0, ++ 0x37, 0x23, 0xE9, 0x5C, 0x20, 0x00, 0x90, 0xF7, 0x57, 0xFF, 0x00, 0x20, ++ 0x70, 0xBD, 0x20, 0x00, 0x89, 0xF7, 0xFE, 0xFD, 0x02, 0x20, 0xF9, 0xE7, ++ 0x00, 0x20, 0xF7, 0xE7, 0x02, 0x20, 0xF5, 0xE7, 0x64, 0xA2, 0x16, 0x00, ++ 0x10, 0xB5, 0x80, 0x00, 0x0F, 0x4B, 0xC4, 0x58, 0x8E, 0xF7, 0xD4, 0xFC, ++ 0x03, 0x00, 0x01, 0x20, 0x0B, 0x2B, 0x13, 0xD9, 0x11, 0x2B, 0x06, 0xD8, ++ 0x20, 0x00, 0x54, 0x30, 0x00, 0x21, 0x9E, 0xF7, 0x53, 0xFF, 0x00, 0x28, ++ 0x0B, 0xD1, 0x20, 0x00, 0x54, 0x30, 0x01, 0x21, 0x9E, 0xF7, 0x4C, 0xFF, ++ 0x43, 0x42, 0x58, 0x41, 0x40, 0x42, 0x03, 0x23, 0x98, 0x43, 0x05, 0x30, ++ 0x10, 0xBD, 0x03, 0x20, 0xFC, 0xE7, 0xC0, 0x46, 0x64, 0xA2, 0x16, 0x00, ++ 0x02, 0x00, 0x00, 0x29, 0x16, 0xD1, 0x01, 0x23, 0x03, 0x40, 0x58, 0x42, ++ 0x43, 0x41, 0x58, 0x42, 0x20, 0x4B, 0x18, 0x40, 0x20, 0x4B, 0x9C, 0x46, ++ 0x60, 0x44, 0x06, 0x23, 0x1A, 0x40, 0x04, 0x2A, 0x02, 0xD0, 0x02, 0x2A, ++ 0x03, 0xD0, 0x70, 0x47, 0x80, 0x04, 0x80, 0x0C, 0xFB, 0xE7, 0x1B, 0x4B, ++ 0x18, 0x40, 0xF8, 0xE7, 0x18, 0x23, 0x19, 0x00, 0x01, 0x40, 0x03, 0x42, ++ 0x21, 0xD0, 0x08, 0x29, 0x0E, 0xD0, 0x60, 0x23, 0x03, 0x40, 0x40, 0x2B, ++ 0x21, 0xD0, 0x20, 0x3B, 0x18, 0x00, 0x43, 0x1E, 0x98, 0x41, 0x40, 0x42, ++ 0x12, 0x4B, 0x18, 0x40, 0x12, 0x4B, 0x9C, 0x46, 0x60, 0x44, 0xE2, 0xE7, ++ 0x48, 0x33, 0x03, 0x40, 0x60, 0x2B, 0x0E, 0xD0, 0x40, 0x2B, 0x0E, 0xD0, ++ 0x20, 0x3B, 0x18, 0x00, 0x43, 0x1E, 0x98, 0x41, 0x40, 0x42, 0x0C, 0x4B, ++ 0x18, 0x40, 0x0C, 0x4B, 0x9C, 0x46, 0x60, 0x44, 0xD1, 0xE7, 0x0B, 0x48, ++ 0xCF, 0xE7, 0x0B, 0x48, 0xCD, 0xE7, 0x0B, 0x48, 0xCB, 0xE7, 0x0B, 0x48, ++ 0xC9, 0xE7, 0xC0, 0x46, 0xF0, 0x77, 0xFF, 0xFF, 0x1E, 0xFF, 0x00, 0x00, ++ 0xFF, 0x33, 0x00, 0x00, 0x00, 0xCD, 0xFF, 0xFF, 0x08, 0x33, 0x00, 0x00, ++ 0x00, 0xEF, 0xFF, 0xFF, 0x0C, 0x33, 0x00, 0x00, 0x0E, 0x33, 0x00, 0x00, ++ 0x0C, 0x22, 0x00, 0x00, 0x0C, 0x32, 0x00, 0x00, 0x08, 0x30, 0x00, 0x00, ++ 0x70, 0xB5, 0x05, 0x00, 0x0C, 0x00, 0x08, 0x00, 0x77, 0xF7, 0xA4, 0xFE, ++ 0x03, 0x00, 0x01, 0x28, 0x0A, 0xD0, 0x00, 0x20, 0x01, 0x2B, 0x06, 0xD9, ++ 0x16, 0x3B, 0xDB, 0xB2, 0x03, 0x30, 0x98, 0x42, 0x80, 0x41, 0x40, 0x42, ++ 0x40, 0x00, 0x70, 0xBD, 0x24, 0x0A, 0xA2, 0x00, 0x0F, 0x4B, 0xD6, 0x58, ++ 0x3F, 0x23, 0xF1, 0x5C, 0x68, 0x78, 0xFF, 0xF7, 0x83, 0xFF, 0x70, 0x85, ++ 0xE4, 0xB2, 0x20, 0x00, 0xFF, 0xF7, 0x5A, 0xFF, 0x9E, 0xF7, 0x5C, 0xFF, ++ 0x71, 0x8D, 0x01, 0x22, 0x9E, 0xF7, 0x08, 0xFD, 0x31, 0x8C, 0x01, 0x22, ++ 0x9E, 0xF7, 0x04, 0xFD, 0x01, 0x00, 0x33, 0x8C, 0x00, 0x20, 0x8B, 0x42, ++ 0xE1, 0xD0, 0x20, 0x00, 0xA8, 0xF7, 0xA2, 0xFF, 0x00, 0x20, 0xDC, 0xE7, ++ 0x64, 0xA2, 0x16, 0x00, 0xF0, 0xB5, 0xC6, 0x46, 0x00, 0xB5, 0x05, 0x00, ++ 0x08, 0x00, 0x0E, 0x0A, 0xB2, 0x00, 0x29, 0x4B, 0xD4, 0x58, 0x77, 0xF7, ++ 0x67, 0xFE, 0x00, 0x28, 0x03, 0xD0, 0x16, 0x38, 0xC0, 0xB2, 0x03, 0x28, ++ 0x03, 0xD8, 0x00, 0x20, 0x04, 0xBC, 0x90, 0x46, 0xF0, 0xBD, 0x2B, 0x78, ++ 0x01, 0x27, 0x3B, 0x40, 0x39, 0x22, 0xA3, 0x54, 0x54, 0x23, 0x98, 0x46, ++ 0xA0, 0x44, 0x69, 0x1C, 0x31, 0x3A, 0x40, 0x46, 0xCE, 0xF7, 0x72, 0xF9, ++ 0x57, 0x22, 0xA3, 0x5C, 0x04, 0x21, 0x8B, 0x43, 0xA3, 0x54, 0x02, 0x32, ++ 0xA3, 0x5C, 0x3E, 0x31, 0x8B, 0x43, 0xA3, 0x54, 0x29, 0x78, 0x39, 0x40, ++ 0xF0, 0xB2, 0x9F, 0xF7, 0x2D, 0xF9, 0x09, 0x21, 0x40, 0x46, 0x9E, 0xF7, ++ 0x73, 0xFE, 0x00, 0x28, 0x0D, 0xD1, 0x85, 0xF7, 0x8F, 0xFE, 0x00, 0x28, ++ 0x02, 0xD0, 0x4F, 0x23, 0x01, 0x22, 0xE2, 0x54, 0xBC, 0x22, 0x52, 0x00, ++ 0xA3, 0x5C, 0x01, 0x21, 0x0B, 0x43, 0xA3, 0x54, 0xCB, 0xE7, 0x3A, 0x21, ++ 0x40, 0x46, 0x9E, 0xF7, 0x5F, 0xFE, 0x02, 0x00, 0x53, 0x1E, 0x9A, 0x41, ++ 0x4F, 0x23, 0xE2, 0x54, 0x00, 0x23, 0x00, 0x28, 0x04, 0xD0, 0x05, 0x4A, ++ 0x05, 0x4B, 0xD3, 0x5C, 0x5B, 0x07, 0xDB, 0x0F, 0x4F, 0x22, 0xA3, 0x54, ++ 0xDD, 0xE7, 0xC0, 0x46, 0x64, 0xA2, 0x16, 0x00, 0x7C, 0x1E, 0x16, 0x00, ++ 0xA2, 0x02, 0x00, 0x00, 0xF0, 0xB5, 0xC6, 0x46, 0x00, 0xB5, 0x06, 0x00, ++ 0x0D, 0x00, 0x0B, 0x0A, 0x98, 0x46, 0x9A, 0x00, 0x32, 0x4B, 0xD4, 0x58, ++ 0x27, 0x00, 0x54, 0x37, 0x41, 0x1C, 0x08, 0x22, 0x38, 0x00, 0xCE, 0xF7, ++ 0x23, 0xF9, 0x57, 0x22, 0xA3, 0x5C, 0x04, 0x21, 0x8B, 0x43, 0xA3, 0x54, ++ 0x02, 0x32, 0xA3, 0x5C, 0x3E, 0x31, 0x8B, 0x43, 0xA3, 0x54, 0x28, 0x00, ++ 0x77, 0xF7, 0xF4, 0xFD, 0x14, 0x28, 0x13, 0xD0, 0x07, 0xD9, 0x16, 0x38, ++ 0xC0, 0xB2, 0x03, 0x28, 0x05, 0xD8, 0x00, 0x20, 0x04, 0xBC, 0x90, 0x46, ++ 0xF0, 0xBD, 0x00, 0x28, 0xF9, 0xD0, 0x28, 0x00, 0x77, 0xF7, 0xE4, 0xFD, ++ 0x00, 0x23, 0x00, 0x22, 0x00, 0x21, 0x7D, 0xF7, 0xB1, 0xF8, 0xF0, 0xE7, ++ 0x29, 0x00, 0x1D, 0x48, 0x77, 0xF7, 0xBC, 0xF9, 0x32, 0x78, 0x01, 0x23, ++ 0x13, 0x40, 0x3A, 0x22, 0xA3, 0x54, 0x09, 0x21, 0x38, 0x00, 0x9E, 0xF7, ++ 0x07, 0xFE, 0x00, 0x28, 0x11, 0xD1, 0xBC, 0x22, 0x52, 0x00, 0xA3, 0x5C, ++ 0x01, 0x21, 0x0B, 0x43, 0xA3, 0x54, 0x3F, 0x21, 0x38, 0x00, 0x9E, 0xF7, ++ 0xFB, 0xFD, 0x00, 0x28, 0x19, 0xD0, 0x01, 0x22, 0x41, 0x46, 0x28, 0x00, ++ 0x91, 0xF7, 0xE6, 0xF8, 0xCF, 0xE7, 0x3A, 0x21, 0x38, 0x00, 0x9E, 0xF7, ++ 0xEF, 0xFD, 0x02, 0x00, 0x53, 0x1E, 0x9A, 0x41, 0x4F, 0x23, 0xE2, 0x54, ++ 0x00, 0x23, 0x00, 0x28, 0x04, 0xD0, 0x08, 0x4A, 0x08, 0x4B, 0xD3, 0x5C, ++ 0x5B, 0x07, 0xDB, 0x0F, 0x4F, 0x22, 0xA3, 0x54, 0xD9, 0xE7, 0x01, 0x21, ++ 0x28, 0x00, 0x77, 0xF7, 0x45, 0xFD, 0xB6, 0xE7, 0x64, 0xA2, 0x16, 0x00, ++ 0x05, 0x06, 0x00, 0x00, 0x7C, 0x1E, 0x16, 0x00, 0xA2, 0x02, 0x00, 0x00, ++ 0xF0, 0xB5, 0xCE, 0x46, 0x47, 0x46, 0x80, 0xB5, 0x83, 0xB0, 0x04, 0x00, ++ 0x0D, 0x00, 0x0E, 0x0A, 0xB2, 0x00, 0x35, 0x4B, 0xD7, 0x58, 0x02, 0x78, ++ 0x01, 0x23, 0x13, 0x40, 0x39, 0x22, 0xBB, 0x54, 0x36, 0x23, 0xFB, 0x5C, ++ 0x98, 0x46, 0x33, 0x01, 0x9B, 0x1B, 0x9B, 0x00, 0x2F, 0x4A, 0xD3, 0x18, ++ 0x5B, 0x7B, 0x99, 0x46, 0x08, 0x00, 0x77, 0xF7, 0x7F, 0xFD, 0x02, 0x00, ++ 0x19, 0x28, 0x1B, 0xD8, 0x01, 0x38, 0xC0, 0xB2, 0x14, 0x28, 0x47, 0xD8, ++ 0x02, 0x20, 0x01, 0x2A, 0x47, 0xD1, 0x3C, 0x23, 0xFB, 0x5C, 0x00, 0x2B, ++ 0x36, 0xD1, 0x7B, 0x8C, 0x5B, 0x07, 0x33, 0xD5, 0xA3, 0x88, 0x62, 0x88, ++ 0x61, 0x78, 0x20, 0x89, 0x01, 0x90, 0xE0, 0x88, 0x00, 0x90, 0x21, 0x4C, ++ 0x94, 0x20, 0x24, 0x58, 0x28, 0x00, 0xA0, 0x47, 0x00, 0x20, 0x32, 0xE0, ++ 0x2E, 0x28, 0x2F, 0xD1, 0x01, 0x23, 0x4A, 0x46, 0x5A, 0x40, 0x13, 0x00, ++ 0x42, 0x46, 0x5A, 0x40, 0x13, 0x00, 0x39, 0x22, 0xBA, 0x5C, 0xDB, 0xB2, ++ 0x9A, 0x42, 0x0D, 0xD1, 0xA3, 0x88, 0x62, 0x88, 0x61, 0x78, 0x20, 0x89, ++ 0x01, 0x90, 0xE0, 0x88, 0x00, 0x90, 0x13, 0x4C, 0x94, 0x20, 0x24, 0x58, ++ 0x28, 0x00, 0xA0, 0x47, 0x00, 0x20, 0x16, 0xE0, 0x22, 0x78, 0x01, 0x23, ++ 0x13, 0x40, 0xF0, 0xB2, 0x23, 0x22, 0x17, 0x21, 0x9E, 0xF7, 0xA9, 0xFE, ++ 0x00, 0x20, 0x0C, 0xE0, 0x22, 0x78, 0x01, 0x23, 0x13, 0x40, 0xF0, 0xB2, ++ 0x24, 0x22, 0x17, 0x21, 0x9E, 0xF7, 0x9F, 0xFE, 0x00, 0x20, 0x02, 0xE0, ++ 0x00, 0x20, 0x00, 0xE0, 0x02, 0x20, 0x03, 0xB0, 0x0C, 0xBC, 0x90, 0x46, ++ 0x99, 0x46, 0xF0, 0xBD, 0x64, 0xA2, 0x16, 0x00, 0xC0, 0xA0, 0x16, 0x00, ++ 0x28, 0x19, 0x16, 0x00, 0xF8, 0xB5, 0x04, 0x00, 0x08, 0x00, 0x0D, 0x0A, ++ 0xAA, 0x00, 0x22, 0x4B, 0xD6, 0x58, 0x77, 0xF7, 0x19, 0xFD, 0x00, 0x28, ++ 0x3B, 0xD0, 0x16, 0x38, 0xC0, 0xB2, 0x03, 0x28, 0x37, 0xD9, 0x22, 0x78, ++ 0x01, 0x23, 0x13, 0x40, 0x39, 0x22, 0xB3, 0x54, 0x36, 0x23, 0xF3, 0x5C, ++ 0x01, 0x2B, 0x27, 0xD1, 0x23, 0x7A, 0x1B, 0x3A, 0x01, 0x2B, 0x24, 0xD8, ++ 0x27, 0x00, 0x09, 0x37, 0x38, 0x00, 0x79, 0xF7, 0x93, 0xFA, 0x01, 0x00, ++ 0x13, 0x28, 0x16, 0xD9, 0x8B, 0x23, 0x9B, 0x00, 0xF0, 0x18, 0x0A, 0x22, ++ 0x39, 0x00, 0xCE, 0xF7, 0x19, 0xF8, 0x22, 0x7A, 0x53, 0x1E, 0x9A, 0x41, ++ 0xD2, 0xB2, 0xE8, 0xB2, 0x3B, 0x00, 0x61, 0x68, 0xA9, 0xF7, 0x2E, 0xF8, ++ 0x23, 0x7A, 0x5A, 0x1E, 0x93, 0x41, 0x91, 0x22, 0x92, 0x00, 0xB3, 0x54, ++ 0x0B, 0xE0, 0x08, 0x48, 0x79, 0xF7, 0x12, 0xFA, 0x1E, 0x22, 0x00, 0xE0, ++ 0x24, 0x22, 0x39, 0x23, 0xF3, 0x5C, 0xE8, 0xB2, 0x3C, 0x21, 0x9E, 0xF7, ++ 0x48, 0xFE, 0x00, 0x20, 0xF8, 0xBD, 0xC0, 0x46, 0x64, 0xA2, 0x16, 0x00, ++ 0xD8, 0xD4, 0x10, 0x00, 0x70, 0xB5, 0x82, 0xB0, 0x04, 0x00, 0x08, 0x00, ++ 0x0D, 0x0A, 0xAA, 0x00, 0x2B, 0x4B, 0xD6, 0x58, 0x77, 0xF7, 0xCA, 0xFC, ++ 0x00, 0x28, 0x20, 0xD0, 0x16, 0x38, 0xC0, 0xB2, 0x03, 0x28, 0x1C, 0xD9, ++ 0x22, 0x78, 0x01, 0x23, 0x13, 0x40, 0x39, 0x22, 0xB3, 0x54, 0x4F, 0x23, ++ 0xF3, 0x5C, 0x00, 0x2B, 0x16, 0xD0, 0xA3, 0x78, 0x01, 0x2B, 0x31, 0xD0, ++ 0x02, 0x2B, 0x39, 0xD0, 0x00, 0x20, 0x00, 0x2B, 0x22, 0xD0, 0x01, 0xA9, ++ 0x39, 0x23, 0xF2, 0x5C, 0x3B, 0x3B, 0x13, 0x43, 0x0B, 0x70, 0x20, 0x23, ++ 0x4B, 0x70, 0x88, 0x70, 0xE8, 0xB2, 0x9E, 0xF7, 0xC1, 0xFD, 0x00, 0x20, ++ 0x02, 0xB0, 0x70, 0xBD, 0x85, 0xF7, 0xF8, 0xFC, 0x00, 0x28, 0x03, 0xD0, ++ 0x4F, 0x23, 0x01, 0x22, 0xF2, 0x54, 0xE0, 0xE7, 0x4F, 0x23, 0xF3, 0x5C, ++ 0x00, 0x2B, 0xDC, 0xD1, 0x39, 0x23, 0xF3, 0x5C, 0xE8, 0xB2, 0x1A, 0x22, ++ 0x1F, 0x21, 0x9E, 0xF7, 0x0D, 0xFE, 0xE8, 0xE7, 0xE8, 0xB2, 0xF5, 0xF7, ++ 0x59, 0xF9, 0x43, 0x1E, 0x98, 0x41, 0x43, 0x42, 0x2A, 0x20, 0x18, 0x40, ++ 0x15, 0x30, 0xD2, 0xE7, 0xE8, 0xB2, 0xF5, 0xF7, 0x79, 0xF9, 0x43, 0x1E, ++ 0x98, 0x41, 0x43, 0x42, 0x15, 0x20, 0x18, 0x40, 0x15, 0x30, 0xC8, 0xE7, ++ 0xE8, 0xB2, 0x03, 0x4B, 0x1B, 0x69, 0x98, 0x47, 0x2A, 0x20, 0xC2, 0xE7, ++ 0x64, 0xA2, 0x16, 0x00, 0x60, 0x92, 0x16, 0x00, 0x70, 0xB5, 0x14, 0x00, ++ 0x13, 0x0A, 0x9B, 0x00, 0x11, 0x4A, 0x9D, 0x58, 0x20, 0x00, 0x77, 0xF7, ++ 0x69, 0xFC, 0x03, 0x00, 0x01, 0x28, 0x0A, 0xD0, 0x00, 0x20, 0x01, 0x2B, ++ 0x06, 0xD9, 0x16, 0x3B, 0xDB, 0xB2, 0x03, 0x30, 0x98, 0x42, 0x80, 0x41, ++ 0x40, 0x42, 0x40, 0x00, 0x70, 0xBD, 0x36, 0x23, 0xEB, 0x5C, 0x00, 0x20, ++ 0x00, 0x2B, 0xF9, 0xD1, 0x91, 0x23, 0x9B, 0x00, 0xEB, 0x5C, 0x00, 0x2B, ++ 0xF4, 0xD0, 0x00, 0x21, 0x20, 0x00, 0x8E, 0xF7, 0xDB, 0xFC, 0x00, 0x20, ++ 0xEE, 0xE7, 0xC0, 0x46, 0x64, 0xA2, 0x16, 0x00, 0xF0, 0xB5, 0x83, 0xB0, ++ 0x00, 0x90, 0x0F, 0x00, 0x16, 0x00, 0x01, 0x93, 0x0B, 0x78, 0xDC, 0x00, ++ 0xE3, 0x18, 0x32, 0x4C, 0xE4, 0x18, 0x3C, 0x34, 0x23, 0x78, 0x01, 0x2B, ++ 0x02, 0xD0, 0x00, 0x20, 0x03, 0xB0, 0xF0, 0xBD, 0x4B, 0x78, 0x00, 0x2B, ++ 0x4B, 0xD1, 0x2C, 0x4B, 0x1B, 0x68, 0x00, 0x2B, 0x4D, 0xD0, 0x2B, 0x4D, ++ 0x2C, 0x00, 0x3F, 0x34, 0x02, 0xE0, 0x09, 0x35, 0xA5, 0x42, 0x43, 0xD0, ++ 0xAB, 0x79, 0x02, 0x2B, 0xF9, 0xD9, 0x3B, 0x78, 0xD9, 0x00, 0xC9, 0x18, ++ 0x36, 0x31, 0x23, 0x4B, 0x9C, 0x46, 0x61, 0x44, 0x06, 0x22, 0x28, 0x00, ++ 0xCD, 0xF7, 0x18, 0xFF, 0x00, 0x28, 0xEC, 0xD1, 0x0C, 0x23, 0x03, 0x22, ++ 0x00, 0x21, 0x1F, 0x48, 0x77, 0xF7, 0x3C, 0xF8, 0x04, 0x00, 0x0B, 0x23, ++ 0x03, 0x70, 0x3B, 0x78, 0xD9, 0x00, 0xC9, 0x18, 0x36, 0x31, 0x18, 0x4D, ++ 0x49, 0x19, 0x04, 0x30, 0x06, 0x22, 0xCD, 0xF7, 0x27, 0xFF, 0x01, 0x23, ++ 0x5B, 0x42, 0x63, 0x80, 0x02, 0x33, 0xA3, 0x72, 0x00, 0x26, 0xE6, 0x72, ++ 0x20, 0x00, 0xC8, 0xF7, 0x85, 0xFE, 0x3A, 0x78, 0xD3, 0x00, 0x9B, 0x18, ++ 0xEB, 0x18, 0x3E, 0x33, 0x18, 0x78, 0x85, 0xF7, 0x0F, 0xFA, 0x3A, 0x78, ++ 0xD3, 0x00, 0x9B, 0x18, 0xEB, 0x18, 0x3C, 0x33, 0x1E, 0x70, 0x28, 0x68, ++ 0x0C, 0x38, 0x77, 0xF7, 0x62, 0xF8, 0x2E, 0x60, 0xAD, 0xE7, 0x16, 0x2B, ++ 0xAB, 0xD0, 0x02, 0xE0, 0x7B, 0x78, 0x16, 0x2B, 0xA7, 0xD0, 0x01, 0x9B, ++ 0x32, 0x00, 0x39, 0x00, 0x00, 0x98, 0x04, 0x4C, 0xA0, 0x47, 0xA0, 0xE7, ++ 0x68, 0x9E, 0x16, 0x00, 0x9E, 0x9E, 0x16, 0x00, 0x03, 0x11, 0x00, 0x00, ++ 0xED, 0x33, 0x09, 0x00, 0xF0, 0xB5, 0x87, 0xB0, 0x01, 0x90, 0x0D, 0x00, ++ 0x02, 0x92, 0x03, 0x93, 0x0A, 0x78, 0xD3, 0x00, 0x9A, 0x18, 0x29, 0x4B, ++ 0x9B, 0x18, 0x3C, 0x33, 0x1B, 0x78, 0x02, 0x2B, 0x02, 0xD0, 0x00, 0x20, ++ 0x07, 0xB0, 0xF0, 0xBD, 0x25, 0x4C, 0x27, 0x00, 0x3F, 0x37, 0x4E, 0x1C, ++ 0x02, 0xE0, 0x09, 0x34, 0xBC, 0x42, 0x39, 0xD0, 0xA3, 0x79, 0x02, 0x2B, ++ 0xF9, 0xD9, 0x06, 0x22, 0x31, 0x00, 0x20, 0x00, 0xCD, 0xF7, 0xAE, 0xFE, ++ 0x00, 0x28, 0xF2, 0xD1, 0x1B, 0x4A, 0x29, 0x78, 0xCB, 0x00, 0x5B, 0x18, ++ 0xD3, 0x18, 0x3C, 0x33, 0x00, 0x21, 0x19, 0x70, 0x13, 0x7B, 0x9B, 0x07, ++ 0xDF, 0xD5, 0x18, 0x4B, 0x00, 0x24, 0x1A, 0x78, 0x00, 0x2A, 0x05, 0xD0, ++ 0x01, 0x34, 0xE4, 0xB2, 0x09, 0x33, 0x07, 0x2C, 0xF7, 0xD1, 0xD4, 0xE7, ++ 0x06, 0x2C, 0xD2, 0xD8, 0x0F, 0x4B, 0x1A, 0x8B, 0x04, 0xA9, 0x0A, 0x80, ++ 0x5A, 0x8B, 0x4A, 0x80, 0x5B, 0x7F, 0x0B, 0x71, 0x4C, 0x71, 0x0E, 0x4A, ++ 0xD0, 0x23, 0xD3, 0x58, 0x08, 0x00, 0x98, 0x47, 0x00, 0x28, 0xC2, 0xD1, ++ 0xE3, 0x00, 0x1C, 0x19, 0x06, 0x4B, 0x1C, 0x19, 0x3C, 0x34, 0x02, 0x22, ++ 0x22, 0x70, 0xBA, 0xE7, 0x03, 0x9B, 0x02, 0x9A, 0x29, 0x00, 0x01, 0x98, ++ 0x05, 0x4C, 0xA0, 0x47, 0xB3, 0xE7, 0xC0, 0x46, 0x68, 0x9E, 0x16, 0x00, ++ 0x9E, 0x9E, 0x16, 0x00, 0xA4, 0x9E, 0x16, 0x00, 0x28, 0x19, 0x16, 0x00, ++ 0xDD, 0x32, 0x09, 0x00, 0x00, 0x09, 0x70, 0x47, 0x00, 0x28, 0x14, 0xD0, ++ 0x0E, 0x4B, 0x1B, 0x68, 0x00, 0x2B, 0x03, 0xD0, 0x0D, 0x4B, 0x1B, 0x68, ++ 0x00, 0x2B, 0x06, 0xD1, 0x0C, 0x4B, 0x0A, 0x4A, 0x99, 0x68, 0x11, 0x60, ++ 0xDA, 0x68, 0x09, 0x4B, 0x1A, 0x60, 0x09, 0x4B, 0x09, 0x4A, 0x9A, 0x60, ++ 0x09, 0x4A, 0xDA, 0x60, 0x70, 0x47, 0x06, 0x4B, 0x03, 0x4A, 0x12, 0x68, ++ 0x9A, 0x60, 0x03, 0x4A, 0x12, 0x68, 0xDA, 0x60, 0xF6, 0xE7, 0xC0, 0x46, ++ 0xB8, 0xE6, 0x10, 0x00, 0xD4, 0xE6, 0x10, 0x00, 0x60, 0x92, 0x16, 0x00, ++ 0x2D, 0x01, 0x10, 0x00, 0x81, 0x01, 0x10, 0x00, 0x70, 0xB5, 0x04, 0x00, ++ 0x01, 0x00, 0x2F, 0x48, 0x79, 0xF7, 0x68, 0xF8, 0x7D, 0xF7, 0xE8, 0xFF, ++ 0x01, 0x28, 0x00, 0xD0, 0x70, 0xBD, 0xFF, 0xF7, 0xC9, 0xFF, 0x2B, 0x4A, ++ 0x95, 0x23, 0x9B, 0x00, 0xD2, 0x5C, 0x2A, 0x4B, 0x1A, 0x70, 0x2A, 0x4B, ++ 0x1A, 0x68, 0x2A, 0x4B, 0x1A, 0x60, 0xE6, 0x23, 0x5B, 0x00, 0x1B, 0x68, ++ 0x28, 0x48, 0x98, 0x47, 0x28, 0x4B, 0x18, 0x60, 0x01, 0x2C, 0x27, 0xD0, ++ 0x02, 0x23, 0x22, 0x00, 0x9A, 0x43, 0x05, 0xD0, 0x25, 0x4B, 0x9B, 0x6E, ++ 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x1C, 0x4E, 0x95, 0x25, ++ 0xAD, 0x00, 0x40, 0x23, 0x73, 0x55, 0x1C, 0x4B, 0x20, 0x4A, 0x1A, 0x60, ++ 0x8C, 0x21, 0xE8, 0x23, 0x5B, 0x00, 0x1B, 0x68, 0x49, 0x00, 0x1A, 0x48, ++ 0x98, 0x47, 0x73, 0x5D, 0x1C, 0x49, 0x2D, 0x22, 0x8B, 0x54, 0x01, 0x2C, ++ 0x1B, 0xD9, 0x02, 0x2C, 0xC8, 0xD1, 0x1A, 0x49, 0x0A, 0x88, 0xFF, 0x20, ++ 0x82, 0x43, 0x13, 0x43, 0x0B, 0x80, 0xC1, 0xE7, 0x0D, 0x4D, 0x95, 0x24, ++ 0xA4, 0x00, 0x30, 0x23, 0x2B, 0x55, 0x0D, 0x4B, 0x11, 0x4A, 0x1A, 0x60, ++ 0x8C, 0x21, 0xE8, 0x23, 0x5B, 0x00, 0x1B, 0x68, 0x49, 0x00, 0x0B, 0x48, ++ 0x98, 0x47, 0x2B, 0x5D, 0x0D, 0x49, 0x2D, 0x22, 0x8B, 0x54, 0x0E, 0x49, ++ 0x0A, 0x88, 0xFF, 0x20, 0x82, 0x43, 0x13, 0x43, 0x0B, 0x80, 0xA7, 0xE7, ++ 0xE4, 0xD4, 0x10, 0x00, 0x7C, 0x1E, 0x16, 0x00, 0xF6, 0xE8, 0x10, 0x00, ++ 0x54, 0x07, 0x62, 0x40, 0x08, 0xE7, 0x10, 0x00, 0x58, 0x00, 0x01, 0x50, ++ 0x18, 0xE7, 0x10, 0x00, 0x28, 0x19, 0x16, 0x00, 0xFD, 0x20, 0x22, 0x21, ++ 0x60, 0x92, 0x16, 0x00, 0x8E, 0x01, 0x61, 0x40, 0x0C, 0x65, 0x61, 0x40, ++ 0x70, 0xB5, 0x04, 0x00, 0x01, 0x00, 0x1A, 0x48, 0x78, 0xF7, 0xEE, 0xFF, ++ 0x7D, 0xF7, 0x6E, 0xFF, 0x01, 0x28, 0x00, 0xD0, 0x70, 0xBD, 0x00, 0x20, ++ 0xFF, 0xF7, 0x4E, 0xFF, 0x15, 0x4E, 0x95, 0x25, 0xAD, 0x00, 0x15, 0x4B, ++ 0x1B, 0x78, 0x73, 0x55, 0x14, 0x4B, 0x1A, 0x68, 0x14, 0x4B, 0x1A, 0x60, ++ 0x14, 0x4B, 0x1B, 0x68, 0x80, 0x21, 0x49, 0x00, 0x19, 0x43, 0xE8, 0x23, ++ 0x5B, 0x00, 0x1B, 0x68, 0x11, 0x48, 0x98, 0x47, 0x73, 0x5D, 0x11, 0x49, ++ 0x2D, 0x22, 0x8B, 0x54, 0x01, 0x2C, 0x08, 0xD9, 0x02, 0x2C, 0xDF, 0xD1, ++ 0x0E, 0x49, 0x0A, 0x88, 0xFF, 0x20, 0x82, 0x43, 0x13, 0x43, 0x0B, 0x80, ++ 0xD8, 0xE7, 0x0C, 0x49, 0x0A, 0x88, 0xFF, 0x20, 0x82, 0x43, 0x13, 0x43, ++ 0x0B, 0x80, 0xD1, 0xE7, 0xF8, 0xD4, 0x10, 0x00, 0x7C, 0x1E, 0x16, 0x00, ++ 0xF6, 0xE8, 0x10, 0x00, 0x08, 0xE7, 0x10, 0x00, 0x54, 0x07, 0x62, 0x40, ++ 0x18, 0xE7, 0x10, 0x00, 0x58, 0x00, 0x01, 0x50, 0x60, 0x92, 0x16, 0x00, ++ 0x8E, 0x01, 0x61, 0x40, 0x0C, 0x65, 0x61, 0x40, 0x10, 0xB5, 0x09, 0x28, ++ 0x0B, 0xD9, 0xFF, 0x28, 0x0B, 0xD1, 0x0B, 0x09, 0x1F, 0x29, 0x0D, 0xD9, ++ 0x02, 0x3B, 0x01, 0x2B, 0x05, 0xD8, 0x01, 0x20, 0xFF, 0xF7, 0xA6, 0xFF, ++ 0x01, 0xE0, 0x00, 0x28, 0x08, 0xD1, 0x10, 0xBD, 0x00, 0x20, 0xFF, 0xF7, ++ 0x25, 0xFF, 0xFA, 0xE7, 0x00, 0x20, 0xFF, 0xF7, 0x9B, 0xFF, 0xF6, 0xE7, ++ 0x0B, 0x09, 0x1F, 0x29, 0xF4, 0xD9, 0x02, 0x3B, 0x01, 0x2B, 0xF0, 0xD8, ++ 0x01, 0x20, 0xFF, 0xF7, 0x17, 0xFF, 0xEC, 0xE7, 0xF8, 0xB5, 0xCE, 0x46, ++ 0x47, 0x46, 0x80, 0xB5, 0x06, 0x00, 0x0D, 0x00, 0x14, 0x00, 0x1F, 0x00, ++ 0x13, 0x0A, 0x9B, 0x00, 0x11, 0x4A, 0x9B, 0x58, 0x99, 0x46, 0x0A, 0x88, ++ 0x10, 0x4B, 0xD3, 0x5C, 0x98, 0x46, 0x20, 0x00, 0x77, 0xF7, 0x42, 0xFA, ++ 0x0A, 0x28, 0x0A, 0xD0, 0x3B, 0x00, 0x22, 0x00, 0x29, 0x00, 0x30, 0x00, ++ 0x0B, 0x4C, 0xA0, 0x47, 0x00, 0x20, 0x0C, 0xBC, 0x90, 0x46, 0x99, 0x46, ++ 0xF8, 0xBD, 0x43, 0x46, 0x5B, 0x08, 0x03, 0x2B, 0xF0, 0xD1, 0x07, 0x4B, ++ 0x4A, 0x46, 0xD1, 0x5C, 0x06, 0x3B, 0xD0, 0x5C, 0xFF, 0xF7, 0xB0, 0xFF, ++ 0xE8, 0xE7, 0xC0, 0x46, 0x64, 0xA2, 0x16, 0x00, 0x00, 0x00, 0x61, 0x40, ++ 0x05, 0x87, 0x0A, 0x00, 0x2A, 0x02, 0x00, 0x00, 0x70, 0xB5, 0x82, 0xB0, ++ 0x14, 0x00, 0x15, 0x0A, 0xAA, 0x00, 0x20, 0x4B, 0xD6, 0x58, 0x20, 0x00, ++ 0x77, 0xF7, 0x16, 0xFA, 0x03, 0x00, 0x01, 0x28, 0x10, 0xD0, 0x00, 0x20, ++ 0x01, 0x2B, 0x05, 0xD9, 0x19, 0x2B, 0x05, 0xD8, 0x15, 0x22, 0x9A, 0x42, ++ 0x40, 0x41, 0x40, 0x00, 0x02, 0xB0, 0x70, 0xBD, 0x58, 0x3B, 0x18, 0x00, ++ 0x43, 0x1E, 0x98, 0x41, 0x40, 0x00, 0xF7, 0xE7, 0x4C, 0x23, 0xF3, 0x5C, ++ 0x00, 0x20, 0x00, 0x2B, 0xF2, 0xD1, 0x4B, 0x33, 0xF3, 0x5C, 0x00, 0x2B, ++ 0x02, 0xD0, 0x4B, 0x23, 0x00, 0x22, 0xF2, 0x54, 0x4F, 0x23, 0xF3, 0x5C, ++ 0x00, 0x20, 0x00, 0x2B, 0xE6, 0xD0, 0x01, 0xA9, 0x36, 0x23, 0xF2, 0x5C, ++ 0x38, 0x3B, 0x13, 0x43, 0x0B, 0x70, 0x1F, 0x23, 0x4B, 0x70, 0x1D, 0x3B, ++ 0x8B, 0x70, 0xE8, 0xB2, 0x9E, 0xF7, 0xFE, 0xFA, 0x20, 0x00, 0x8E, 0xF7, ++ 0xF1, 0xFE, 0x58, 0x21, 0x20, 0x00, 0x77, 0xF7, 0x7D, 0xF9, 0x00, 0x20, ++ 0xD0, 0xE7, 0xC0, 0x46, 0x64, 0xA2, 0x16, 0x00, 0x05, 0x4B, 0x00, 0x20, ++ 0x1A, 0x78, 0x00, 0x2A, 0x04, 0xD0, 0x01, 0x30, 0xC0, 0xB2, 0x09, 0x33, ++ 0x07, 0x28, 0xF7, 0xD1, 0x70, 0x47, 0xC0, 0x46, 0xA4, 0x9E, 0x16, 0x00, ++ 0x70, 0xB5, 0x80, 0x00, 0x28, 0x4B, 0xC2, 0x58, 0x28, 0x49, 0xD5, 0x23, ++ 0x5B, 0x00, 0xC9, 0x5C, 0xCB, 0x00, 0x5B, 0x1A, 0x5B, 0x00, 0x26, 0x49, ++ 0x8C, 0x46, 0x63, 0x44, 0x19, 0x88, 0xC9, 0x0B, 0x0B, 0xD0, 0x19, 0x88, ++ 0x49, 0x04, 0x49, 0x0C, 0x19, 0x80, 0x20, 0x4C, 0xD5, 0x20, 0x40, 0x00, ++ 0x21, 0x5C, 0x01, 0x31, 0x03, 0x23, 0x0B, 0x40, 0x23, 0x54, 0x9E, 0x23, ++ 0xD3, 0x5C, 0x5B, 0x00, 0xAE, 0x21, 0x51, 0x5C, 0x5B, 0x18, 0xDB, 0xB2, ++ 0x99, 0x00, 0xCB, 0x18, 0x5B, 0x00, 0x19, 0x49, 0x5C, 0x18, 0x21, 0x88, ++ 0x89, 0xB2, 0x00, 0x29, 0x19, 0xD1, 0x9C, 0x31, 0x50, 0x5C, 0x00, 0x28, ++ 0x01, 0xD1, 0x01, 0x31, 0x50, 0x5C, 0x14, 0x49, 0x5D, 0x18, 0x29, 0x88, ++ 0x78, 0x26, 0xB1, 0x43, 0xC0, 0x00, 0x01, 0x43, 0x29, 0x80, 0x96, 0x21, ++ 0x51, 0x5A, 0xC9, 0x00, 0x06, 0x20, 0x01, 0x43, 0x89, 0xB2, 0x0E, 0x48, ++ 0x18, 0x18, 0x01, 0x80, 0x94, 0x21, 0x51, 0x5A, 0x21, 0x80, 0x0C, 0x49, ++ 0x8C, 0x46, 0x63, 0x44, 0x19, 0x88, 0x49, 0x04, 0x49, 0x0C, 0x19, 0x80, ++ 0xAE, 0x21, 0x53, 0x5C, 0x58, 0x42, 0x43, 0x41, 0x53, 0x54, 0x70, 0xBD, ++ 0x38, 0xE6, 0x10, 0x00, 0x20, 0xA3, 0x16, 0x00, 0x90, 0x69, 0x61, 0x40, ++ 0xCE, 0x69, 0x61, 0x40, 0xCA, 0x69, 0x61, 0x40, 0xCC, 0x69, 0x61, 0x40, ++ 0xC8, 0x69, 0x61, 0x40, 0x70, 0xB5, 0x35, 0x4B, 0x1C, 0x68, 0x00, 0x2C, ++ 0x14, 0xD0, 0xE3, 0x78, 0x9B, 0x00, 0x33, 0x4A, 0x9D, 0x58, 0xA0, 0x23, ++ 0xEB, 0x5C, 0x02, 0x2B, 0x0E, 0xD0, 0x31, 0x4B, 0x1B, 0x78, 0x00, 0x2B, ++ 0x05, 0xD0, 0x30, 0x4A, 0x11, 0x68, 0x80, 0x23, 0xDB, 0x03, 0x0B, 0x43, ++ 0x13, 0x60, 0xA0, 0x23, 0x02, 0x22, 0xEA, 0x54, 0x00, 0x20, 0x70, 0xBD, ++ 0x94, 0x23, 0xE8, 0x5A, 0x00, 0x28, 0x07, 0xD0, 0x63, 0x78, 0x00, 0x2B, ++ 0x42, 0xD0, 0x01, 0x2B, 0x43, 0xD0, 0x94, 0x23, 0x00, 0x22, 0xEA, 0x52, ++ 0xE2, 0x78, 0x62, 0x23, 0x53, 0x43, 0x24, 0x4A, 0x94, 0x46, 0x63, 0x44, ++ 0x18, 0x88, 0x40, 0x05, 0x40, 0x0F, 0x84, 0xF7, 0x51, 0xFF, 0x1D, 0x4D, ++ 0xE3, 0x78, 0x9B, 0x00, 0x58, 0x59, 0x76, 0xF7, 0xCF, 0xFE, 0xE3, 0x78, ++ 0x9B, 0x00, 0x00, 0x24, 0x5C, 0x51, 0x1C, 0x48, 0xCB, 0xF7, 0x56, 0xFD, ++ 0x1B, 0x48, 0x78, 0xF7, 0x53, 0xFE, 0x14, 0x4D, 0x2B, 0x68, 0xD8, 0x68, ++ 0x76, 0xF7, 0xC0, 0xFE, 0x2B, 0x68, 0xDC, 0x60, 0x98, 0x68, 0x00, 0x28, ++ 0x05, 0xD0, 0x76, 0xF7, 0xB9, 0xFE, 0x0E, 0x4B, 0x1B, 0x68, 0x00, 0x22, ++ 0x9A, 0x60, 0x0C, 0x4C, 0x20, 0x68, 0x76, 0xF7, 0xB1, 0xFE, 0x00, 0x23, ++ 0x23, 0x60, 0x0B, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0xBC, 0xD0, 0x0E, 0x4A, ++ 0x13, 0x68, 0x0E, 0x49, 0x0B, 0x40, 0x13, 0x60, 0x06, 0x4B, 0x00, 0x22, ++ 0x1A, 0x70, 0xB3, 0xE7, 0x80, 0xF7, 0x4A, 0xFE, 0xBB, 0xE7, 0x80, 0xF7, ++ 0xFD, 0xFD, 0xB8, 0xE7, 0xD8, 0xE5, 0x10, 0x00, 0x38, 0xE6, 0x10, 0x00, ++ 0xDC, 0xE5, 0x10, 0x00, 0x00, 0x04, 0x60, 0x40, 0xFE, 0x64, 0x61, 0x40, ++ 0xFC, 0xE6, 0x10, 0x00, 0x0C, 0xD5, 0x10, 0x00, 0xD0, 0x04, 0x60, 0x40, ++ 0xFF, 0x7F, 0xFF, 0xFF, 0x70, 0xB5, 0x13, 0x4B, 0x1C, 0x68, 0xA5, 0x78, ++ 0x00, 0x2D, 0x1D, 0xD1, 0x23, 0x78, 0x03, 0x2B, 0x1C, 0xD0, 0x63, 0x78, ++ 0x00, 0x2B, 0x08, 0xD0, 0x01, 0x2B, 0x0F, 0xD0, 0x0D, 0x4B, 0x9B, 0x6E, ++ 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x04, 0xE0, 0x0E, 0x22, ++ 0x01, 0x00, 0xE0, 0x68, 0xCD, 0xF7, 0xF2, 0xFB, 0x01, 0x23, 0xA3, 0x70, ++ 0x28, 0x00, 0x70, 0xBD, 0x0E, 0x22, 0x01, 0x00, 0xE0, 0x68, 0xCD, 0xF7, ++ 0xE9, 0xFB, 0xF5, 0xE7, 0x0C, 0x25, 0xF5, 0xE7, 0x0C, 0x25, 0xF3, 0xE7, ++ 0xD8, 0xE5, 0x10, 0x00, 0x28, 0x19, 0x16, 0x00, 0xF0, 0xB5, 0xDE, 0x46, ++ 0x57, 0x46, 0x4E, 0x46, 0x45, 0x46, 0xE0, 0xB5, 0x8B, 0xB0, 0x05, 0x00, ++ 0x0E, 0x00, 0x14, 0x00, 0x01, 0x93, 0x00, 0x23, 0x08, 0x93, 0x09, 0x93, ++ 0x06, 0x93, 0x06, 0xAA, 0x93, 0x80, 0x82, 0x00, 0xBB, 0x4B, 0xD3, 0x58, ++ 0x00, 0x2B, 0x00, 0xD1, 0x10, 0xE1, 0xAB, 0x00, 0xB8, 0x4A, 0x9F, 0x58, ++ 0x21, 0x00, 0xB8, 0x48, 0x78, 0xF7, 0xCE, 0xFD, 0x00, 0x2C, 0x00, 0xD1, ++ 0x0D, 0xE1, 0x01, 0x2C, 0x00, 0xD1, 0x6D, 0xE2, 0xB4, 0x4B, 0x9B, 0x6E, ++ 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x00, 0x23, 0x00, 0x93, ++ 0x98, 0x46, 0x99, 0x46, 0x02, 0x93, 0x00, 0x21, 0x00, 0x26, 0x01, 0x9B, ++ 0x00, 0x2B, 0x63, 0xD0, 0x62, 0x23, 0x6B, 0x43, 0xAC, 0x4A, 0x98, 0x18, ++ 0x02, 0x88, 0x1F, 0x24, 0xA2, 0x43, 0x32, 0x43, 0x02, 0x80, 0xAA, 0x4A, ++ 0x9A, 0x18, 0x10, 0x88, 0xA9, 0x4E, 0x06, 0x40, 0x80, 0x20, 0x40, 0x00, ++ 0x30, 0x43, 0x10, 0x80, 0x10, 0x88, 0x40, 0x04, 0x40, 0x0C, 0x10, 0x80, ++ 0x10, 0x88, 0xA5, 0x4E, 0x30, 0x40, 0x10, 0x80, 0xA4, 0x4A, 0x94, 0x46, ++ 0x9C, 0x44, 0x62, 0x46, 0x16, 0x88, 0xFF, 0x20, 0x86, 0x43, 0xA2, 0x4A, ++ 0x93, 0x46, 0x2D, 0x22, 0x5C, 0x46, 0xA2, 0x5C, 0x32, 0x43, 0x64, 0x46, ++ 0x22, 0x80, 0x9F, 0x4A, 0x9E, 0x18, 0x00, 0x22, 0x94, 0x46, 0x32, 0x80, ++ 0x9D, 0x4A, 0x93, 0x46, 0x9B, 0x44, 0x5A, 0x46, 0x12, 0x88, 0x52, 0x04, ++ 0x52, 0x0C, 0x5C, 0x46, 0x22, 0x80, 0x9A, 0x4A, 0x9A, 0x18, 0x11, 0x80, ++ 0x99, 0x4A, 0x9A, 0x18, 0x61, 0x46, 0x11, 0x80, 0x98, 0x4A, 0x9A, 0x18, ++ 0x11, 0x80, 0x98, 0x4A, 0x99, 0x18, 0x02, 0x22, 0xFF, 0x32, 0x0A, 0x80, ++ 0x32, 0x88, 0x40, 0x24, 0xA2, 0x43, 0x22, 0x43, 0x32, 0x80, 0x0A, 0x88, ++ 0x82, 0x43, 0xFE, 0x38, 0x02, 0x43, 0x0A, 0x80, 0x9E, 0x22, 0xBA, 0x5C, ++ 0x14, 0x21, 0x4A, 0x43, 0x8F, 0x49, 0x8C, 0x46, 0x62, 0x44, 0x92, 0xB2, ++ 0x8E, 0x49, 0x59, 0x18, 0x0A, 0x80, 0x8E, 0x4A, 0x94, 0x46, 0x63, 0x44, ++ 0x1A, 0x88, 0x3F, 0x21, 0x0A, 0x40, 0x8C, 0x49, 0x0A, 0x43, 0x1A, 0x80, ++ 0x08, 0xAE, 0x31, 0x00, 0x06, 0xA8, 0xAF, 0xF7, 0x9D, 0xF9, 0x06, 0xAB, ++ 0x5A, 0x78, 0x12, 0x02, 0x1B, 0x78, 0x13, 0x43, 0x62, 0x27, 0x6F, 0x43, ++ 0x85, 0x4A, 0xBA, 0x18, 0x13, 0x80, 0x06, 0xAB, 0xDA, 0x78, 0x12, 0x02, ++ 0x9B, 0x78, 0x13, 0x43, 0x82, 0x4A, 0xBA, 0x18, 0x13, 0x80, 0x06, 0xAB, ++ 0x5A, 0x79, 0x12, 0x02, 0x1B, 0x79, 0x13, 0x43, 0x7F, 0x4A, 0xBA, 0x18, ++ 0x13, 0x80, 0x72, 0x78, 0x12, 0x02, 0x33, 0x78, 0x13, 0x43, 0x7D, 0x4A, ++ 0xBA, 0x18, 0x13, 0x80, 0xF2, 0x78, 0x12, 0x02, 0xB3, 0x78, 0x13, 0x43, ++ 0x7A, 0x4A, 0xBA, 0x18, 0x13, 0x80, 0x00, 0x22, 0x06, 0x2D, 0x01, 0xD8, ++ 0x6A, 0x1C, 0xD2, 0xB2, 0x08, 0xAB, 0x19, 0x79, 0x03, 0x23, 0x0B, 0x40, ++ 0x92, 0x00, 0x13, 0x43, 0x6E, 0x4A, 0x13, 0x43, 0x6C, 0x4A, 0xBA, 0x18, ++ 0x13, 0x80, 0x72, 0x48, 0x03, 0x68, 0x72, 0x49, 0x0B, 0x40, 0x80, 0x22, ++ 0x52, 0x01, 0x1A, 0x43, 0x02, 0x60, 0x5A, 0x4B, 0xFE, 0x18, 0x33, 0x88, ++ 0x02, 0x9A, 0x14, 0x03, 0x24, 0xB2, 0x0B, 0x40, 0x23, 0x43, 0x9B, 0xB2, ++ 0x33, 0x80, 0x4B, 0x46, 0x00, 0x2B, 0x00, 0xD1, 0xDE, 0xE1, 0x56, 0x4B, ++ 0xFA, 0x18, 0x13, 0x88, 0x5B, 0x04, 0x5B, 0x0C, 0x80, 0x21, 0x09, 0x02, ++ 0x0B, 0x43, 0x13, 0x80, 0x33, 0x88, 0x64, 0x4A, 0x13, 0x40, 0x00, 0x9A, ++ 0xD2, 0x02, 0x13, 0x43, 0x9B, 0xB2, 0x33, 0x80, 0x61, 0x49, 0x0B, 0x68, ++ 0x61, 0x4A, 0x1A, 0x40, 0x80, 0x23, 0x1B, 0x02, 0x13, 0x43, 0x0B, 0x60, ++ 0x4C, 0x4B, 0xFB, 0x18, 0x00, 0x22, 0x1A, 0x80, 0x49, 0x4B, 0xFB, 0x18, ++ 0x1A, 0x88, 0x08, 0x21, 0x8A, 0x43, 0x1A, 0x80, 0x30, 0x88, 0x31, 0x88, ++ 0x33, 0x88, 0x80, 0x0B, 0x01, 0x22, 0x10, 0x40, 0x80, 0x03, 0xC9, 0x0A, ++ 0x0A, 0x40, 0xD2, 0x02, 0x10, 0x43, 0x05, 0x43, 0x58, 0x05, 0x40, 0x0F, ++ 0x00, 0x02, 0x05, 0x43, 0x25, 0x43, 0xAD, 0xB2, 0x35, 0x80, 0x0B, 0xB0, ++ 0x3C, 0xBC, 0x90, 0x46, 0x99, 0x46, 0xA2, 0x46, 0xAB, 0x46, 0xF0, 0xBD, ++ 0x32, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, ++ 0xE7, 0xE6, 0xB3, 0x78, 0x99, 0x46, 0xF3, 0x78, 0x98, 0x46, 0x33, 0x79, ++ 0x00, 0x93, 0x72, 0x79, 0x02, 0x92, 0x00, 0x2B, 0x10, 0xD1, 0x9D, 0x23, ++ 0x00, 0x22, 0xFA, 0x54, 0x32, 0x78, 0x01, 0x3B, 0xFA, 0x54, 0xF2, 0x88, ++ 0x96, 0x23, 0xFA, 0x52, 0x73, 0x78, 0x07, 0x2B, 0x00, 0xD9, 0x3D, 0xE1, ++ 0x9B, 0x00, 0x3E, 0x49, 0xCB, 0x58, 0x9F, 0x46, 0x31, 0x78, 0x9D, 0x23, ++ 0xF9, 0x54, 0x3C, 0x48, 0x78, 0xF7, 0x9C, 0xFC, 0x9C, 0x23, 0x00, 0x22, ++ 0xFA, 0x54, 0xEA, 0xE7, 0x39, 0x4B, 0x1A, 0x68, 0x39, 0x49, 0x0A, 0x40, ++ 0x1A, 0x60, 0x1A, 0x68, 0x30, 0x49, 0x11, 0x40, 0x80, 0x22, 0x52, 0x01, ++ 0x0A, 0x43, 0x1A, 0x60, 0x35, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x76, 0xD0, ++ 0x31, 0x49, 0x0B, 0x68, 0x2D, 0x4A, 0x1A, 0x40, 0x80, 0x23, 0x1B, 0x02, ++ 0x13, 0x43, 0x0B, 0x60, 0x6D, 0xE0, 0x2D, 0x4B, 0x1A, 0x68, 0x2D, 0x49, ++ 0x11, 0x40, 0x80, 0x22, 0x92, 0x01, 0x0A, 0x43, 0x1A, 0x60, 0x1A, 0x68, ++ 0x22, 0x49, 0x11, 0x40, 0x80, 0x22, 0x52, 0x01, 0x0A, 0x43, 0x1A, 0x60, ++ 0x27, 0x4B, 0x1B, 0x78, 0x00, 0x2B, 0x5A, 0xD0, 0x23, 0x49, 0x0B, 0x68, ++ 0x1F, 0x4A, 0x1A, 0x40, 0x80, 0x23, 0x1B, 0x02, 0x13, 0x43, 0x0B, 0x60, ++ 0x51, 0xE0, 0xC0, 0x46, 0x38, 0xE6, 0x10, 0x00, 0x18, 0xD5, 0x10, 0x00, ++ 0x28, 0x19, 0x16, 0x00, 0xF8, 0x64, 0x61, 0x40, 0xFE, 0x64, 0x61, 0x40, ++ 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0x0C, 0x65, 0x61, 0x40, ++ 0x60, 0x92, 0x16, 0x00, 0x0E, 0x65, 0x61, 0x40, 0x56, 0x65, 0x61, 0x40, ++ 0x10, 0x65, 0x61, 0x40, 0xFA, 0x64, 0x61, 0x40, 0xFC, 0x64, 0x61, 0x40, ++ 0x1E, 0x65, 0x61, 0x40, 0xC8, 0x69, 0x00, 0x00, 0x12, 0x65, 0x61, 0x40, ++ 0x0A, 0x65, 0x61, 0x40, 0x40, 0xFF, 0x00, 0x00, 0x00, 0x65, 0x61, 0x40, ++ 0x02, 0x65, 0x61, 0x40, 0x04, 0x65, 0x61, 0x40, 0x06, 0x65, 0x61, 0x40, ++ 0x08, 0x65, 0x61, 0x40, 0x00, 0x04, 0x60, 0x40, 0xFF, 0xEF, 0xFF, 0xFF, ++ 0xFF, 0xF7, 0xFF, 0xFF, 0x28, 0x04, 0x60, 0x40, 0xFF, 0x7F, 0xFF, 0xFF, ++ 0x48, 0xD5, 0x10, 0x00, 0x30, 0xD5, 0x10, 0x00, 0xD0, 0x04, 0x60, 0x40, ++ 0xFF, 0xDF, 0xFF, 0xFF, 0xDC, 0xE5, 0x10, 0x00, 0x94, 0x23, 0xF8, 0x5A, ++ 0x8E, 0x4B, 0x9C, 0x46, 0x60, 0x44, 0xF0, 0x21, 0x74, 0xF7, 0x96, 0xFB, ++ 0x8C, 0x4A, 0x13, 0x68, 0x8C, 0x49, 0x0B, 0x40, 0x13, 0x60, 0x9E, 0x23, ++ 0xFA, 0x5C, 0x52, 0x00, 0x10, 0x33, 0xFB, 0x5C, 0xD2, 0x18, 0xD2, 0xB2, ++ 0x62, 0x23, 0x6B, 0x43, 0x87, 0x49, 0x8C, 0x46, 0x63, 0x44, 0x03, 0x93, ++ 0x02, 0x20, 0x07, 0x23, 0x9A, 0x46, 0x04, 0x95, 0x05, 0x96, 0x91, 0x00, ++ 0x89, 0x18, 0x49, 0x00, 0x82, 0x4B, 0xCC, 0x18, 0x23, 0x88, 0x78, 0x25, ++ 0xAB, 0x43, 0x70, 0x3D, 0x2B, 0x43, 0x9B, 0xB2, 0x23, 0x80, 0x03, 0x9B, ++ 0x1B, 0x88, 0x25, 0x88, 0xAB, 0x46, 0x1B, 0x0A, 0x55, 0x46, 0x2B, 0x40, ++ 0x5D, 0x46, 0x56, 0x46, 0xB5, 0x43, 0x2B, 0x43, 0x23, 0x80, 0x79, 0x4B, ++ 0x9C, 0x46, 0x8C, 0x44, 0x63, 0x46, 0x1B, 0x88, 0x77, 0x4C, 0x23, 0x40, ++ 0x64, 0x46, 0x23, 0x80, 0x76, 0x4B, 0xCB, 0x18, 0x00, 0x24, 0x1C, 0x80, ++ 0x75, 0x4B, 0x9C, 0x46, 0x61, 0x44, 0x9E, 0x23, 0xFB, 0x5C, 0x5B, 0x00, ++ 0x01, 0x34, 0x54, 0x40, 0xE4, 0xB2, 0xA4, 0x46, 0x63, 0x44, 0x9C, 0x00, ++ 0xA4, 0x46, 0x63, 0x44, 0x5B, 0x00, 0x6F, 0x4C, 0xA4, 0x46, 0x63, 0x44, ++ 0x6E, 0x4C, 0x23, 0x43, 0x9B, 0xB2, 0x0B, 0x80, 0x0B, 0x88, 0x5B, 0x04, ++ 0x5B, 0x0C, 0x0B, 0x80, 0x53, 0x42, 0x5A, 0x41, 0xD2, 0xB2, 0x01, 0x38, ++ 0xC0, 0xB2, 0x00, 0x28, 0xB9, 0xD1, 0x04, 0x9D, 0x05, 0x9E, 0x31, 0x00, ++ 0x08, 0x31, 0x06, 0x22, 0x06, 0xA8, 0xCD, 0xF7, 0xA5, 0xF9, 0x00, 0x21, ++ 0x02, 0x26, 0xF2, 0xE5, 0x94, 0x23, 0xF8, 0x5A, 0x56, 0x4B, 0x9C, 0x46, ++ 0x60, 0x44, 0xAA, 0x21, 0x74, 0xF7, 0x26, 0xFB, 0x54, 0x4A, 0x13, 0x68, ++ 0x54, 0x49, 0x0B, 0x40, 0x13, 0x60, 0x8E, 0xE7, 0x94, 0x23, 0xF8, 0x5A, ++ 0x4F, 0x4B, 0x9C, 0x46, 0x60, 0x44, 0xFF, 0x21, 0x74, 0xF7, 0x18, 0xFB, ++ 0x4D, 0x4A, 0x13, 0x68, 0x4D, 0x49, 0x0B, 0x40, 0x13, 0x60, 0x80, 0xE7, ++ 0x94, 0x23, 0xF8, 0x5A, 0x48, 0x4B, 0x9C, 0x46, 0x60, 0x44, 0x00, 0x21, ++ 0x74, 0xF7, 0x0A, 0xFB, 0x46, 0x4A, 0x13, 0x68, 0x46, 0x49, 0x0B, 0x40, ++ 0x13, 0x60, 0x72, 0xE7, 0x94, 0x23, 0xF8, 0x5A, 0x41, 0x4B, 0x9C, 0x46, ++ 0x60, 0x44, 0x0F, 0x21, 0x74, 0xF7, 0xFC, 0xFA, 0x3F, 0x4A, 0x13, 0x68, ++ 0x3F, 0x49, 0x0B, 0x40, 0x13, 0x60, 0x64, 0xE7, 0x94, 0x23, 0xF8, 0x5A, ++ 0x3A, 0x4B, 0x9C, 0x46, 0x60, 0x44, 0x55, 0x21, 0x74, 0xF7, 0xEE, 0xFA, ++ 0x38, 0x4A, 0x13, 0x68, 0x38, 0x49, 0x0B, 0x40, 0x13, 0x60, 0x56, 0xE7, ++ 0x94, 0x23, 0xF8, 0x5A, 0x33, 0x4B, 0x9C, 0x46, 0x60, 0x44, 0x00, 0x21, ++ 0x74, 0xF7, 0xE0, 0xFA, 0x31, 0x4A, 0x13, 0x68, 0x31, 0x49, 0x0B, 0x40, ++ 0x13, 0x60, 0x48, 0xE7, 0xB3, 0x78, 0x98, 0x46, 0xF3, 0x78, 0x00, 0x93, ++ 0xB4, 0x79, 0xF1, 0x1D, 0x06, 0x22, 0x06, 0xA8, 0xCD, 0xF7, 0x44, 0xF9, ++ 0x00, 0x22, 0x33, 0x4B, 0x99, 0x46, 0xD5, 0x23, 0x5B, 0x00, 0x9C, 0x46, ++ 0x03, 0x26, 0x17, 0x3B, 0xFF, 0x3B, 0x9B, 0x46, 0x0A, 0xE0, 0x2F, 0x49, ++ 0x8A, 0x46, 0x53, 0x44, 0x19, 0x88, 0x49, 0x04, 0x49, 0x0C, 0x19, 0x80, ++ 0x01, 0x32, 0xD2, 0xB2, 0x04, 0x2A, 0x11, 0xD0, 0x4B, 0x46, 0x61, 0x46, ++ 0x5B, 0x5C, 0xD3, 0x18, 0x33, 0x40, 0xD9, 0x00, 0xCB, 0x1A, 0x5B, 0x00, ++ 0x26, 0x49, 0x58, 0x18, 0x01, 0x88, 0x89, 0xB2, 0x00, 0x29, 0xE6, 0xD1, ++ 0x59, 0x46, 0x79, 0x5A, 0x01, 0x80, 0xE2, 0xE7, 0x02, 0x94, 0x00, 0x23, ++ 0x99, 0x46, 0x21, 0x49, 0x03, 0x26, 0x66, 0xE5, 0x20, 0x4B, 0xFA, 0x18, ++ 0x13, 0x88, 0x5B, 0x04, 0x5B, 0x0C, 0x13, 0x80, 0x43, 0x46, 0xDB, 0x07, ++ 0x0F, 0xD4, 0x11, 0x88, 0x43, 0x46, 0x5B, 0x08, 0x1B, 0x02, 0x1B, 0x48, ++ 0x01, 0x40, 0x0B, 0x43, 0x13, 0x80, 0x43, 0x46, 0x5B, 0x08, 0x28, 0x33, ++ 0x19, 0x00, 0x18, 0x48, 0x78, 0xF7, 0x0A, 0xFB, 0x10, 0xE6, 0x10, 0x88, ++ 0x43, 0x46, 0x5B, 0x08, 0x28, 0x33, 0x1B, 0x02, 0x12, 0x49, 0x01, 0x40, ++ 0x0B, 0x43, 0x9B, 0xB2, 0x13, 0x80, 0xEC, 0xE7, 0x00, 0x00, 0x61, 0x40, ++ 0xD0, 0x04, 0x60, 0x40, 0xFF, 0xEF, 0xFF, 0xFF, 0xFE, 0x64, 0x61, 0x40, ++ 0xCA, 0x69, 0x61, 0x40, 0xCC, 0x69, 0x61, 0x40, 0x07, 0xE0, 0xFF, 0xFF, ++ 0xCE, 0x69, 0x61, 0x40, 0xC8, 0x69, 0x61, 0x40, 0xC8, 0x69, 0x00, 0x00, ++ 0x00, 0x80, 0xFF, 0xFF, 0x20, 0xA3, 0x16, 0x00, 0x90, 0x69, 0x61, 0x40, ++ 0x9A, 0x69, 0x61, 0x40, 0xFF, 0x1F, 0x00, 0x00, 0x0C, 0x65, 0x61, 0x40, ++ 0xFF, 0x80, 0xFF, 0xFF, 0x3C, 0xD5, 0x10, 0x00, 0x10, 0xB5, 0x07, 0x4B, ++ 0x1C, 0x68, 0xA3, 0x78, 0x00, 0x2B, 0x00, 0xD1, 0x10, 0xBD, 0x00, 0x23, ++ 0x0A, 0x00, 0xE1, 0x68, 0xFF, 0xF7, 0xE2, 0xFC, 0x00, 0x23, 0xA3, 0x70, ++ 0xF6, 0xE7, 0xC0, 0x46, 0xD8, 0xE5, 0x10, 0x00, 0xF0, 0xB5, 0xC6, 0x46, ++ 0x00, 0xB5, 0x05, 0x00, 0x82, 0x00, 0x52, 0x4B, 0xD4, 0x58, 0x00, 0x2C, ++ 0x00, 0xD1, 0x98, 0xE0, 0xA9, 0x23, 0xE3, 0x5C, 0x00, 0x2B, 0x05, 0xD1, ++ 0x4E, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, ++ 0xA9, 0x22, 0xA3, 0x5C, 0x01, 0x3B, 0xDB, 0xB2, 0xA3, 0x54, 0x09, 0x3A, ++ 0xA2, 0x5C, 0x02, 0x3A, 0x01, 0x2A, 0x01, 0xD8, 0x00, 0x2B, 0x14, 0xD0, ++ 0x9F, 0xF7, 0xD2, 0xFD, 0x06, 0x00, 0x01, 0x00, 0x28, 0x00, 0xFF, 0xF7, ++ 0xA9, 0xFB, 0xA9, 0x23, 0xE3, 0x5C, 0x00, 0x2B, 0x00, 0xD1, 0x68, 0xE0, ++ 0x3F, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, ++ 0x04, 0xBC, 0x90, 0x46, 0xF0, 0xBD, 0x01, 0x21, 0x20, 0x00, 0xCA, 0xF7, ++ 0xEF, 0xFD, 0xA0, 0x23, 0x02, 0x22, 0xE2, 0x54, 0xFF, 0xF7, 0xF4, 0xFB, ++ 0x37, 0x4A, 0xD5, 0x23, 0x5B, 0x00, 0xD2, 0x5C, 0xD3, 0x00, 0x9B, 0x1A, ++ 0x5B, 0x00, 0x35, 0x4A, 0x9A, 0x18, 0x12, 0x88, 0xD2, 0x0B, 0xE7, 0xD0, ++ 0x33, 0x4A, 0x94, 0x46, 0x63, 0x44, 0x1A, 0x88, 0xD2, 0x0A, 0xAA, 0x42, ++ 0x07, 0xD0, 0x19, 0x88, 0xC9, 0x0A, 0x2C, 0x4B, 0xDC, 0x6E, 0x00, 0x23, ++ 0x00, 0x22, 0x28, 0x00, 0xA0, 0x47, 0x2A, 0x4C, 0xD5, 0x20, 0x40, 0x00, ++ 0x22, 0x5C, 0xD3, 0x00, 0x9B, 0x1A, 0x5B, 0x00, 0x27, 0x4A, 0x94, 0x46, ++ 0x63, 0x44, 0x1A, 0x88, 0x52, 0x04, 0x52, 0x0C, 0x1A, 0x80, 0x21, 0x5C, ++ 0x01, 0x31, 0x03, 0x23, 0x19, 0x40, 0x21, 0x54, 0x23, 0x4B, 0x1A, 0x68, ++ 0xCB, 0x00, 0x5B, 0x1A, 0x5B, 0x00, 0x22, 0x49, 0x8C, 0x46, 0x63, 0x44, ++ 0x52, 0x04, 0x52, 0x0C, 0x93, 0x42, 0x05, 0xD0, 0x19, 0x4B, 0x9B, 0x6E, ++ 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x18, 0x4E, 0x00, 0x24, ++ 0xD5, 0x23, 0x5B, 0x00, 0x98, 0x46, 0x14, 0x4F, 0x03, 0xE0, 0x01, 0x34, ++ 0x0E, 0x36, 0x04, 0x2C, 0xA8, 0xD0, 0x33, 0x88, 0xDB, 0x0B, 0xF8, 0xD0, ++ 0x10, 0x4B, 0x42, 0x46, 0x98, 0x5C, 0x00, 0x23, 0x00, 0x22, 0x21, 0x00, ++ 0xFD, 0x6E, 0xA8, 0x47, 0xEF, 0xE7, 0x01, 0x21, 0x20, 0x00, 0xCA, 0xF7, ++ 0x8F, 0xFD, 0x02, 0x36, 0x66, 0x60, 0x00, 0x21, 0x28, 0x00, 0xFF, 0xF7, ++ 0x4F, 0xFF, 0x20, 0x00, 0xF4, 0xF7, 0xA6, 0xFA, 0x8E, 0xE7, 0x04, 0x4B, ++ 0xDC, 0x6E, 0x00, 0x23, 0x00, 0x22, 0x00, 0x21, 0xA0, 0x47, 0x87, 0xE7, ++ 0x38, 0xE6, 0x10, 0x00, 0x28, 0x19, 0x16, 0x00, 0x20, 0xA3, 0x16, 0x00, ++ 0x90, 0x69, 0x61, 0x40, 0x92, 0x69, 0x61, 0x40, 0x2C, 0x04, 0x60, 0x40, ++ 0x90, 0x69, 0x00, 0x00, 0xF0, 0xB5, 0x83, 0xB0, 0x01, 0x90, 0x0D, 0x00, ++ 0x14, 0x00, 0xCF, 0xB2, 0x06, 0x2F, 0x07, 0xD9, 0xFF, 0x20, 0x08, 0x40, ++ 0x0B, 0x4B, 0xDE, 0x6E, 0x00, 0x23, 0x00, 0x22, 0x21, 0x00, 0xB0, 0x47, ++ 0x00, 0x2C, 0x09, 0xD0, 0xFF, 0x20, 0x28, 0x40, 0x06, 0x4B, 0xDD, 0x6E, ++ 0x00, 0x23, 0x00, 0x22, 0x21, 0x00, 0xA8, 0x47, 0x03, 0xB0, 0xF0, 0xBD, ++ 0x01, 0x99, 0x38, 0x00, 0xFF, 0xF7, 0x28, 0xFF, 0xF8, 0xE7, 0xC0, 0x46, ++ 0x28, 0x19, 0x16, 0x00, 0xF0, 0xB5, 0xC6, 0x46, 0x00, 0xB5, 0x96, 0xB0, ++ 0x2F, 0x4B, 0x1B, 0x68, 0xD9, 0x68, 0xEF, 0xF3, 0x10, 0x83, 0xDB, 0x07, ++ 0x51, 0xD4, 0x72, 0xB6, 0x10, 0x31, 0x24, 0x22, 0x0D, 0xA8, 0xCC, 0xF7, ++ 0xCF, 0xFF, 0x62, 0xB6, 0x0D, 0x9C, 0x00, 0x26, 0x00, 0x2C, 0x07, 0xD0, ++ 0x0E, 0x9B, 0xE3, 0x1A, 0x64, 0x20, 0x58, 0x43, 0x21, 0x00, 0xCC, 0xF7, ++ 0x75, 0xFB, 0x06, 0x00, 0x13, 0x9D, 0x00, 0x20, 0x00, 0x2D, 0x05, 0xD0, ++ 0x21, 0x48, 0x14, 0x9B, 0x58, 0x43, 0x29, 0x00, 0xCC, 0xF7, 0x6A, 0xFB, ++ 0x11, 0x9A, 0x12, 0x9F, 0x15, 0x99, 0x13, 0x00, 0x3B, 0x43, 0x0B, 0x43, ++ 0x1B, 0xD0, 0x0F, 0x9B, 0x98, 0x46, 0x0E, 0x9B, 0x9C, 0x46, 0x00, 0x23, ++ 0x09, 0x93, 0x08, 0x90, 0x07, 0x93, 0x06, 0x96, 0x14, 0x9B, 0x0B, 0x93, ++ 0x05, 0x93, 0x04, 0x95, 0x03, 0x91, 0x02, 0x97, 0x01, 0x92, 0x10, 0x9B, ++ 0x00, 0x93, 0x43, 0x46, 0x22, 0x00, 0x61, 0x46, 0x11, 0x48, 0x78, 0xF7, ++ 0xA5, 0xF9, 0x16, 0xB0, 0x04, 0xBC, 0x90, 0x46, 0xF0, 0xBD, 0x0F, 0x9B, ++ 0x0E, 0x99, 0x00, 0x22, 0x06, 0x92, 0x05, 0x90, 0x04, 0x92, 0x03, 0x96, ++ 0x14, 0x9A, 0x0B, 0x92, 0x02, 0x92, 0x01, 0x95, 0x10, 0x9A, 0x00, 0x92, ++ 0x22, 0x00, 0x08, 0x48, 0x78, 0xF7, 0x90, 0xF9, 0xE9, 0xE7, 0x10, 0x31, ++ 0x24, 0x22, 0x0D, 0xA8, 0xCC, 0xF7, 0x7E, 0xFF, 0xAE, 0xE7, 0xC0, 0x46, ++ 0xD8, 0xE5, 0x10, 0x00, 0x10, 0x27, 0x00, 0x00, 0x68, 0xD5, 0x10, 0x00, ++ 0xC8, 0xD5, 0x10, 0x00, 0x70, 0x47, 0x00, 0x00, 0xF0, 0xB5, 0xC6, 0x46, ++ 0x00, 0xB5, 0x05, 0x00, 0x0F, 0x00, 0x16, 0x00, 0x1C, 0x00, 0x4B, 0x4B, ++ 0x1B, 0x68, 0x00, 0x2B, 0x05, 0xD0, 0x4A, 0x4B, 0x9B, 0x6E, 0x00, 0x22, ++ 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x00, 0x21, 0x10, 0x20, 0x76, 0xF7, ++ 0x37, 0xF9, 0x44, 0x4B, 0x18, 0x60, 0x00, 0x28, 0x10, 0xD0, 0x42, 0x4B, ++ 0x18, 0x68, 0x10, 0x22, 0x00, 0x21, 0x74, 0xF7, 0xDF, 0xF8, 0x00, 0x2D, ++ 0x0E, 0xD0, 0x01, 0x2D, 0x2C, 0xD0, 0x3E, 0x4B, 0x9B, 0x6E, 0x00, 0x22, ++ 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x1B, 0xE0, 0x3A, 0x4B, 0x9B, 0x6E, ++ 0x00, 0x22, 0x00, 0x21, 0x98, 0x47, 0xE8, 0xE7, 0x36, 0x4C, 0x25, 0x68, ++ 0x00, 0x21, 0x0E, 0x20, 0x76, 0xF7, 0x16, 0xF9, 0xE8, 0x60, 0x23, 0x68, ++ 0xDB, 0x68, 0x00, 0x2B, 0x0D, 0xD0, 0x31, 0x4C, 0x23, 0x68, 0xD8, 0x68, ++ 0x0E, 0x22, 0x00, 0x21, 0x74, 0xF7, 0xBC, 0xF8, 0x23, 0x68, 0x00, 0x22, ++ 0x5A, 0x70, 0xDE, 0x70, 0x04, 0xBC, 0x90, 0x46, 0xF0, 0xBD, 0x2B, 0x4B, ++ 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0xEA, 0xE7, ++ 0x26, 0x4D, 0x2B, 0x68, 0x98, 0x46, 0x00, 0x21, 0x38, 0x20, 0x76, 0xF7, ++ 0xF5, 0xF8, 0x43, 0x46, 0xD8, 0x60, 0x2B, 0x68, 0xDB, 0x68, 0x00, 0x2B, ++ 0x31, 0xD0, 0x20, 0x4D, 0x2B, 0x68, 0xD8, 0x68, 0x38, 0x22, 0x00, 0x21, ++ 0x74, 0xF7, 0x9A, 0xF8, 0x2B, 0x68, 0x98, 0x46, 0x00, 0x21, 0x28, 0x20, ++ 0x76, 0xF7, 0xE2, 0xF8, 0x43, 0x46, 0x98, 0x60, 0x2B, 0x68, 0x9B, 0x68, ++ 0x00, 0x2B, 0x25, 0xD0, 0x16, 0x4D, 0x2B, 0x68, 0x98, 0x68, 0x28, 0x22, ++ 0x00, 0x21, 0x74, 0xF7, 0x87, 0xF8, 0x2B, 0x68, 0xD8, 0x68, 0x0E, 0x22, ++ 0x39, 0x00, 0xCC, 0xF7, 0xF5, 0xFE, 0x2B, 0x68, 0x01, 0x22, 0x5A, 0x70, ++ 0xC8, 0x22, 0x52, 0x01, 0x5A, 0x60, 0xDE, 0x70, 0x0E, 0x48, 0x0F, 0x4A, ++ 0x82, 0x60, 0x5B, 0x68, 0xE4, 0x18, 0x24, 0x01, 0x24, 0x09, 0x44, 0x60, ++ 0xCA, 0xF7, 0xA0, 0xFF, 0xB6, 0xE7, 0x08, 0x4B, 0x9B, 0x6E, 0x00, 0x22, ++ 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0xC6, 0xE7, 0x04, 0x4B, 0x9B, 0x6E, ++ 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0xD2, 0xE7, 0xC0, 0x46, ++ 0xD8, 0xE5, 0x10, 0x00, 0x28, 0x19, 0x16, 0x00, 0xFC, 0xE6, 0x10, 0x00, ++ 0xD5, 0x01, 0x10, 0x00, 0xF8, 0xB5, 0x04, 0x00, 0x4E, 0x4B, 0x1B, 0x68, ++ 0x00, 0x2B, 0x04, 0xD0, 0xFF, 0xF7, 0xB8, 0xFA, 0x05, 0x00, 0x28, 0x00, ++ 0xF8, 0xBD, 0x4B, 0x48, 0x78, 0xF7, 0xCA, 0xF8, 0x4A, 0x4B, 0x1B, 0x68, ++ 0x00, 0x2B, 0x07, 0xD0, 0x49, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, ++ 0x00, 0x20, 0x98, 0x47, 0x12, 0x25, 0xEE, 0xE7, 0x00, 0x21, 0xF8, 0x20, ++ 0x76, 0xF7, 0x88, 0xF8, 0x42, 0x4B, 0x18, 0x60, 0x00, 0x28, 0x75, 0xD0, ++ 0x9F, 0xF7, 0xE0, 0xFB, 0x07, 0x00, 0x84, 0xF7, 0x81, 0xF9, 0x40, 0x4A, ++ 0x13, 0x88, 0x40, 0x49, 0x0B, 0x40, 0x00, 0x02, 0x03, 0x43, 0x9B, 0xB2, ++ 0x13, 0x80, 0x3A, 0x4B, 0x1E, 0x68, 0xF8, 0x22, 0x00, 0x21, 0x30, 0x00, ++ 0x74, 0xF7, 0x22, 0xF8, 0x00, 0x23, 0x73, 0x62, 0x39, 0x4A, 0xF2, 0x61, ++ 0x39, 0x4A, 0x32, 0x62, 0x03, 0x22, 0x32, 0x76, 0x38, 0x4A, 0x12, 0x78, ++ 0xB2, 0x75, 0x38, 0x4A, 0x32, 0x61, 0x05, 0x22, 0xF2, 0x75, 0x99, 0x32, ++ 0xB3, 0x54, 0x01, 0x32, 0xB3, 0x54, 0x02, 0x32, 0xB3, 0x54, 0x03, 0x32, ++ 0x28, 0x21, 0xB1, 0x52, 0x1C, 0x3A, 0xB3, 0x52, 0x80, 0xF7, 0x72, 0xF8, ++ 0x05, 0x1E, 0x05, 0xD1, 0x28, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, ++ 0x00, 0x20, 0x98, 0x47, 0x94, 0x23, 0xF5, 0x52, 0x93, 0x3B, 0x00, 0x22, ++ 0x21, 0x00, 0x00, 0x20, 0xFF, 0xF7, 0x8A, 0xFA, 0x28, 0x4A, 0x13, 0x88, ++ 0x1F, 0x21, 0x0B, 0x40, 0x13, 0x80, 0x77, 0x60, 0x00, 0x23, 0x82, 0x22, ++ 0xB3, 0x52, 0xB3, 0x60, 0x00, 0x22, 0xA6, 0x33, 0xF2, 0x54, 0x20, 0x3B, ++ 0xFA, 0x22, 0xD2, 0x01, 0xF2, 0x52, 0x37, 0x67, 0x20, 0x4B, 0xB3, 0x82, ++ 0xFA, 0x23, 0x1B, 0x02, 0xFB, 0x18, 0x1B, 0x01, 0x1B, 0x09, 0xF3, 0x60, ++ 0x30, 0x00, 0xCA, 0xF7, 0x15, 0xFA, 0x05, 0x1E, 0x07, 0xD0, 0x12, 0x4B, ++ 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x12, 0x25, ++ 0x7F, 0xE7, 0xA0, 0x23, 0x00, 0x22, 0xF2, 0x54, 0x01, 0x32, 0x00, 0x21, ++ 0x00, 0x20, 0x9F, 0xF7, 0xF3, 0xF8, 0x3B, 0x00, 0x00, 0x22, 0x21, 0x00, ++ 0x00, 0x20, 0xFF, 0xF7, 0xC3, 0xFE, 0x70, 0xE7, 0x06, 0x4B, 0x9B, 0x6E, ++ 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x12, 0x25, 0x68, 0xE7, ++ 0xD8, 0xE5, 0x10, 0x00, 0x10, 0xD6, 0x10, 0x00, 0x38, 0xE6, 0x10, 0x00, ++ 0x28, 0x19, 0x16, 0x00, 0xFE, 0x64, 0x61, 0x40, 0xFF, 0xF8, 0xFF, 0xFF, ++ 0xF1, 0x02, 0x10, 0x00, 0xD1, 0x01, 0x10, 0x00, 0x7C, 0x91, 0x0D, 0x00, ++ 0x6A, 0x04, 0x00, 0x00, 0xF8, 0x64, 0x61, 0x40, 0x00, 0x80, 0xFF, 0xFF, ++ 0x10, 0xB5, 0x00, 0x29, 0x12, 0xD1, 0x03, 0x78, 0xFF, 0x2B, 0x0A, 0xD1, ++ 0x43, 0x78, 0xC1, 0x2B, 0x2F, 0xD1, 0x83, 0x78, 0xFB, 0x2B, 0x2E, 0xD1, ++ 0xC1, 0x78, 0xE8, 0x39, 0x4B, 0x42, 0x59, 0x41, 0x03, 0x31, 0x04, 0x39, ++ 0x48, 0x42, 0x48, 0x41, 0xC0, 0xB2, 0x10, 0xBD, 0x03, 0x29, 0x0C, 0xD0, ++ 0x12, 0x4B, 0x5C, 0x5C, 0x00, 0x23, 0xD9, 0xB2, 0xC2, 0x5C, 0xA2, 0x42, ++ 0xF1, 0xD1, 0x01, 0x31, 0xC9, 0xB2, 0x01, 0x33, 0x04, 0x2B, 0xF6, 0xD1, ++ 0xEB, 0xE7, 0x03, 0x78, 0xFF, 0x2B, 0x0A, 0xD1, 0x43, 0x78, 0xC1, 0x2B, ++ 0x09, 0xD1, 0x83, 0x78, 0xFB, 0x2B, 0x08, 0xD1, 0xC3, 0x78, 0xE8, 0x2B, ++ 0xDF, 0xD1, 0x04, 0x21, 0xDD, 0xE7, 0x00, 0x21, 0xDB, 0xE7, 0x01, 0x21, ++ 0xD9, 0xE7, 0x02, 0x21, 0xD7, 0xE7, 0x01, 0x21, 0xD5, 0xE7, 0x02, 0x21, ++ 0xD3, 0xE7, 0xC0, 0x46, 0x1C, 0xE0, 0x10, 0x00, 0xF8, 0xB5, 0x23, 0x4B, ++ 0x1B, 0x68, 0x00, 0x2B, 0x3A, 0xD0, 0xDA, 0x68, 0x53, 0x78, 0x00, 0x2B, ++ 0x10, 0xD1, 0x95, 0x88, 0x00, 0x2D, 0x0C, 0xD0, 0x1E, 0x4F, 0x1F, 0x4E, ++ 0xF1, 0x5C, 0xC4, 0x5C, 0x61, 0x40, 0x79, 0x5C, 0xD4, 0x6A, 0xA4, 0x46, ++ 0x61, 0x44, 0xD1, 0x62, 0x01, 0x33, 0xAB, 0x42, 0xF4, 0xD3, 0xF8, 0xBD, ++ 0x03, 0x2B, 0x11, 0xD0, 0x18, 0x49, 0xCD, 0x5C, 0x94, 0x88, 0x00, 0x2C, ++ 0xF7, 0xD0, 0x00, 0x23, 0x13, 0x4E, 0xC1, 0x5C, 0x69, 0x40, 0x71, 0x5C, ++ 0xD7, 0x6A, 0xBC, 0x46, 0x61, 0x44, 0xD1, 0x62, 0x01, 0x33, 0xA3, 0x42, ++ 0xF5, 0xD3, 0xEA, 0xE7, 0x95, 0x88, 0x00, 0x2D, 0xE7, 0xD0, 0x00, 0x23, ++ 0x0B, 0x4F, 0x0E, 0x4E, 0xF1, 0x5C, 0xC4, 0x5C, 0x61, 0x40, 0x79, 0x5C, ++ 0xD4, 0x6A, 0xA4, 0x46, 0x61, 0x44, 0xD1, 0x62, 0x01, 0x33, 0xAB, 0x42, ++ 0xF4, 0xD3, 0xD8, 0xE7, 0x08, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, ++ 0x00, 0x20, 0x98, 0x47, 0xD1, 0xE7, 0xC0, 0x46, 0xD8, 0xE5, 0x10, 0x00, ++ 0xBC, 0xDE, 0x10, 0x00, 0xBC, 0xDA, 0x10, 0x00, 0x1C, 0xE0, 0x10, 0x00, ++ 0xBC, 0xD6, 0x10, 0x00, 0x28, 0x19, 0x16, 0x00, 0xF0, 0xB5, 0xD6, 0x46, ++ 0x4F, 0x46, 0x46, 0x46, 0xC0, 0xB5, 0x82, 0xB0, 0x06, 0x00, 0x74, 0x4B, ++ 0x1B, 0x68, 0xDD, 0x68, 0x54, 0x1E, 0xE4, 0xB2, 0x00, 0x2A, 0x00, 0xD1, ++ 0xDA, 0xE0, 0x71, 0x4F, 0xAB, 0xE0, 0x04, 0x21, 0x08, 0x00, 0x10, 0x40, ++ 0x11, 0x42, 0x2F, 0xD0, 0xE9, 0x69, 0x01, 0x31, 0xE9, 0x61, 0xDB, 0x04, ++ 0x9B, 0x0D, 0x99, 0x46, 0xB8, 0x23, 0x13, 0x42, 0x5B, 0xD1, 0xAB, 0x88, ++ 0xDB, 0x00, 0xAA, 0x6A, 0x94, 0x46, 0x63, 0x44, 0xAB, 0x62, 0xD5, 0x23, ++ 0x5B, 0x00, 0x65, 0x4A, 0xD2, 0x5C, 0xD3, 0x00, 0x9B, 0x1A, 0x5B, 0x00, ++ 0x63, 0x4A, 0x94, 0x46, 0x63, 0x44, 0x18, 0x88, 0x83, 0xB2, 0x9A, 0x46, ++ 0x00, 0x2B, 0x06, 0xD1, 0x60, 0x4B, 0x9B, 0x6E, 0x01, 0x93, 0x00, 0x22, ++ 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x4B, 0x46, 0x00, 0x2B, 0x53, 0xD0, ++ 0x43, 0x46, 0x59, 0x06, 0x09, 0x0F, 0x5B, 0x48, 0x50, 0x44, 0xFF, 0xF7, ++ 0x67, 0xFF, 0x4B, 0xE0, 0x69, 0x69, 0x01, 0x31, 0x69, 0x61, 0xDB, 0x04, ++ 0x9B, 0x0D, 0x99, 0x46, 0xB8, 0x23, 0x13, 0x42, 0x00, 0xD0, 0x95, 0xE0, ++ 0x00, 0x28, 0xCC, 0xD1, 0xAB, 0x88, 0x4B, 0x45, 0x2B, 0xD0, 0x6B, 0x6A, ++ 0x01, 0x33, 0x6B, 0x62, 0x4C, 0x4A, 0xD5, 0x23, 0x5B, 0x00, 0xD2, 0x5C, ++ 0xD3, 0x00, 0x9B, 0x1A, 0x5B, 0x00, 0x4A, 0x4A, 0x94, 0x46, 0x63, 0x44, ++ 0x18, 0x88, 0x83, 0xB2, 0x98, 0x46, 0x00, 0x2B, 0x05, 0xD1, 0x47, 0x4B, ++ 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x4B, 0x46, ++ 0x00, 0x2B, 0x21, 0xD0, 0x69, 0x78, 0x43, 0x48, 0x40, 0x44, 0xFF, 0xF7, ++ 0xF7, 0xFE, 0x00, 0x28, 0x1A, 0xD1, 0x2B, 0x6B, 0x01, 0x33, 0x2B, 0x63, ++ 0x16, 0xE0, 0x2B, 0x6A, 0x01, 0x33, 0x2B, 0x62, 0x00, 0x28, 0x11, 0xD1, ++ 0xD0, 0xE7, 0xDB, 0x00, 0xAA, 0x6A, 0x94, 0x46, 0x63, 0x44, 0xAB, 0x62, ++ 0xD0, 0xE7, 0x35, 0x23, 0xEB, 0x5C, 0x01, 0x33, 0xDB, 0xB2, 0x64, 0x2B, ++ 0x54, 0xD8, 0x35, 0x22, 0xAB, 0x54, 0x34, 0x23, 0x00, 0x22, 0xEA, 0x54, ++ 0x2F, 0x4A, 0xD5, 0x23, 0x5B, 0x00, 0xD2, 0x5C, 0xD3, 0x00, 0x9B, 0x1A, ++ 0x5B, 0x00, 0x2D, 0x4A, 0x94, 0x46, 0x63, 0x44, 0x1B, 0x88, 0x9B, 0xB2, ++ 0x00, 0x2B, 0x05, 0xD1, 0x2A, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, ++ 0x00, 0x20, 0x98, 0x47, 0x25, 0x48, 0xD5, 0x21, 0x49, 0x00, 0x42, 0x5C, ++ 0xD3, 0x00, 0x9B, 0x1A, 0x5B, 0x00, 0x26, 0x4A, 0x94, 0x46, 0x63, 0x44, ++ 0x1A, 0x88, 0x52, 0x04, 0x52, 0x0C, 0x1A, 0x80, 0x42, 0x5C, 0x01, 0x32, ++ 0x03, 0x23, 0x13, 0x40, 0x43, 0x54, 0x01, 0x3C, 0xE4, 0xB2, 0xFF, 0x2C, ++ 0x2C, 0xD0, 0x30, 0x00, 0x9E, 0xF7, 0x5A, 0xFF, 0x00, 0x28, 0x27, 0xD0, ++ 0xD5, 0x23, 0x5B, 0x00, 0xFA, 0x5C, 0xD3, 0x00, 0x9B, 0x1A, 0x5B, 0x00, ++ 0x19, 0x4A, 0x9A, 0x18, 0x10, 0x88, 0x82, 0xB2, 0x18, 0x49, 0x59, 0x18, ++ 0x09, 0x88, 0x89, 0xB2, 0x88, 0x46, 0x17, 0x49, 0x8C, 0x46, 0x63, 0x44, ++ 0x1B, 0x88, 0x9B, 0xB2, 0xC1, 0x07, 0xAE, 0xD4, 0x29, 0x69, 0x01, 0x31, ++ 0x29, 0x61, 0x91, 0x07, 0x00, 0xD4, 0x32, 0xE7, 0xAB, 0x69, 0x01, 0x33, ++ 0xAB, 0x61, 0xAF, 0xE7, 0x35, 0x23, 0x64, 0x22, 0xEA, 0x54, 0xA8, 0xE7, ++ 0x2B, 0x6A, 0x01, 0x33, 0x2B, 0x62, 0x67, 0xE7, 0x02, 0xB0, 0x1C, 0xBC, ++ 0x90, 0x46, 0x99, 0x46, 0xA2, 0x46, 0xF0, 0xBD, 0xD8, 0xE5, 0x10, 0x00, ++ 0x20, 0xA3, 0x16, 0x00, 0x9A, 0x69, 0x61, 0x40, 0x28, 0x19, 0x16, 0x00, ++ 0x00, 0x00, 0x61, 0x40, 0x90, 0x69, 0x61, 0x40, 0x92, 0x69, 0x61, 0x40, ++ 0x94, 0x69, 0x61, 0x40, 0x96, 0x69, 0x61, 0x40, 0xF0, 0xB5, 0xD6, 0x46, ++ 0x4F, 0x46, 0x46, 0x46, 0xC0, 0xB5, 0x89, 0x46, 0x82, 0x00, 0x41, 0x4B, ++ 0xD5, 0x58, 0xA6, 0x23, 0xEF, 0x5C, 0x2E, 0x6D, 0x44, 0x3B, 0x58, 0x43, ++ 0x3E, 0x4B, 0xC3, 0x18, 0x1B, 0x88, 0x3E, 0x4A, 0x82, 0x18, 0x14, 0x88, ++ 0x1B, 0x04, 0x1C, 0x43, 0xA2, 0x46, 0x3C, 0x4B, 0xC3, 0x18, 0x1B, 0x88, ++ 0x9B, 0x05, 0x9B, 0x0D, 0x98, 0x46, 0x3A, 0x4B, 0xC3, 0x18, 0x1C, 0x88, ++ 0x39, 0x4B, 0x9C, 0x46, 0x60, 0x44, 0x01, 0x88, 0x24, 0x04, 0x0C, 0x19, ++ 0x37, 0x4B, 0x9E, 0x42, 0x1C, 0xD8, 0x53, 0x46, 0x4A, 0x46, 0x9B, 0x1A, ++ 0x19, 0x01, 0x09, 0x09, 0x80, 0x22, 0x12, 0x05, 0x91, 0x42, 0x40, 0xD9, ++ 0x4B, 0x46, 0x52, 0x46, 0x9B, 0x1A, 0x1B, 0x01, 0x1B, 0x09, 0x5B, 0x42, ++ 0xA1, 0x22, 0xAA, 0x5C, 0x00, 0x2A, 0x3D, 0xD0, 0x00, 0x2B, 0x07, 0xDB, ++ 0x89, 0x08, 0x00, 0x29, 0x04, 0xDD, 0x89, 0x00, 0x49, 0x44, 0x09, 0x01, ++ 0x0B, 0x09, 0x99, 0x46, 0x53, 0x46, 0xE1, 0x1A, 0x49, 0x44, 0x09, 0x01, ++ 0x09, 0x09, 0xF4, 0x23, 0x5B, 0x00, 0x42, 0x46, 0x9B, 0x1A, 0x32, 0xD4, ++ 0xA9, 0x67, 0x82, 0x22, 0xAB, 0x52, 0x4A, 0x42, 0x03, 0x20, 0x10, 0x40, ++ 0xA6, 0x22, 0xA8, 0x54, 0x72, 0x3A, 0x2A, 0x65, 0xAB, 0x60, 0x34, 0x2E, ++ 0x09, 0xD9, 0xEA, 0x7D, 0x00, 0x2A, 0x06, 0xD0, 0xC8, 0x22, 0x52, 0x00, ++ 0x9A, 0x42, 0x92, 0x41, 0x52, 0x42, 0x05, 0x32, 0xEA, 0x75, 0x69, 0x67, ++ 0x84, 0x22, 0xAB, 0x52, 0xC0, 0x1B, 0x43, 0x1E, 0x98, 0x41, 0xC0, 0xB2, ++ 0x1C, 0xBC, 0x90, 0x46, 0x99, 0x46, 0xA2, 0x46, 0xF0, 0xBD, 0x1B, 0x01, ++ 0x1B, 0x09, 0xA1, 0x22, 0xAA, 0x5C, 0x00, 0x2A, 0xC4, 0xD0, 0xC1, 0xE7, ++ 0x00, 0x2B, 0xC1, 0xDA, 0x0D, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, ++ 0x00, 0x20, 0x98, 0x47, 0xC2, 0xE7, 0x0B, 0x4B, 0x9B, 0x1A, 0x01, 0x31, ++ 0x09, 0x01, 0x09, 0x09, 0xC6, 0xE7, 0xC0, 0x46, 0x38, 0xE6, 0x10, 0x00, ++ 0x4C, 0x65, 0x61, 0x40, 0x4A, 0x65, 0x61, 0x40, 0x4E, 0x65, 0x61, 0x40, ++ 0xFC, 0x64, 0x61, 0x40, 0xFA, 0x64, 0x61, 0x40, 0xE1, 0x04, 0x00, 0x00, ++ 0x28, 0x19, 0x16, 0x00, 0x59, 0x04, 0x00, 0x00, 0xF8, 0xB5, 0x80, 0x00, ++ 0x25, 0x4B, 0xC5, 0x58, 0xA6, 0x23, 0xEE, 0x5C, 0x6C, 0x6F, 0xEB, 0x6E, ++ 0xC8, 0x1A, 0x00, 0x01, 0x00, 0x09, 0x22, 0x49, 0x48, 0x43, 0x22, 0x49, ++ 0xCB, 0xF7, 0x84, 0xFF, 0x1A, 0x30, 0x40, 0x00, 0x02, 0x00, 0x34, 0x3A, ++ 0x52, 0x08, 0x84, 0x23, 0xEB, 0x5A, 0x9B, 0x1A, 0x19, 0xB2, 0x1B, 0x04, ++ 0x27, 0xD5, 0x00, 0x23, 0x1B, 0x4A, 0x8A, 0x18, 0x11, 0xB2, 0x01, 0x34, ++ 0x24, 0x01, 0x24, 0x09, 0x1F, 0x00, 0x01, 0x33, 0xDB, 0xB2, 0x12, 0x04, ++ 0xF4, 0xD4, 0xAC, 0x67, 0x82, 0x22, 0xA9, 0x52, 0x64, 0x42, 0x7F, 0x3A, ++ 0x14, 0x40, 0xA3, 0x32, 0xAC, 0x54, 0x28, 0x65, 0xA9, 0x60, 0x00, 0x2B, ++ 0x0A, 0xD0, 0xEB, 0x7D, 0x00, 0x2B, 0x07, 0xD0, 0xC8, 0x23, 0x5B, 0x00, ++ 0x8B, 0x42, 0x9B, 0x41, 0x5B, 0x42, 0x06, 0x37, 0xDF, 0x19, 0xEF, 0x75, ++ 0x34, 0x1B, 0x66, 0x1E, 0xB4, 0x41, 0xE0, 0xB2, 0xF8, 0xBD, 0xAC, 0x67, ++ 0x82, 0x23, 0xE9, 0x52, 0x64, 0x42, 0x7F, 0x3B, 0x1C, 0x40, 0xA3, 0x33, ++ 0xEC, 0x54, 0x28, 0x65, 0xA9, 0x60, 0xEF, 0xE7, 0x38, 0xE6, 0x10, 0x00, ++ 0xA8, 0x61, 0x00, 0x00, 0x40, 0x42, 0x0F, 0x00, 0x71, 0x02, 0x00, 0x00, ++ 0xF0, 0xB5, 0xC6, 0x46, 0x00, 0xB5, 0x8A, 0xB0, 0x0E, 0x00, 0x8A, 0x00, ++ 0x52, 0x4B, 0xD5, 0x58, 0x00, 0x2D, 0x00, 0xD1, 0x9B, 0xE0, 0xA6, 0x23, ++ 0x98, 0x46, 0xEB, 0x5C, 0x01, 0x33, 0x03, 0x24, 0x23, 0x40, 0x1F, 0x00, ++ 0x9F, 0xF7, 0xB0, 0xF8, 0x00, 0x90, 0x03, 0x00, 0xA3, 0x43, 0x3B, 0x43, ++ 0x42, 0x46, 0xAA, 0x5C, 0xD2, 0x1A, 0x14, 0x40, 0x04, 0x3B, 0xE4, 0x18, ++ 0x24, 0x01, 0x24, 0x09, 0x23, 0x1A, 0x1B, 0x01, 0x1B, 0x09, 0x80, 0x22, ++ 0x12, 0x05, 0x93, 0x42, 0x02, 0xD9, 0x03, 0x1B, 0x1B, 0x01, 0x59, 0xD1, ++ 0x00, 0x23, 0x01, 0x93, 0x01, 0xA9, 0x68, 0x46, 0x9F, 0xF7, 0x9C, 0xF8, ++ 0x01, 0x9B, 0x1A, 0x00, 0x0F, 0x32, 0xFF, 0x32, 0x9C, 0x21, 0x89, 0x00, ++ 0x8A, 0x42, 0x57, 0xD8, 0x01, 0x92, 0x00, 0x9A, 0x13, 0x1B, 0x1B, 0x01, ++ 0x1B, 0x09, 0x38, 0x49, 0x8B, 0x42, 0x05, 0xD8, 0xA2, 0x42, 0x61, 0xD1, ++ 0xAB, 0x68, 0x01, 0x9A, 0x93, 0x42, 0x5D, 0xD9, 0x02, 0xA8, 0x34, 0x4B, ++ 0x02, 0x93, 0x44, 0x60, 0xAB, 0x68, 0x83, 0x60, 0x06, 0x76, 0x06, 0x61, ++ 0x31, 0x4B, 0xC3, 0x60, 0xAB, 0x7D, 0x03, 0x75, 0x01, 0x33, 0x43, 0x75, ++ 0x00, 0x23, 0x83, 0x75, 0xB0, 0x22, 0xAA, 0x5C, 0xC2, 0x75, 0x83, 0x76, ++ 0xC3, 0x76, 0x01, 0x33, 0x43, 0x76, 0xCA, 0xF7, 0xD7, 0xFE, 0xA9, 0x22, ++ 0xAB, 0x5C, 0x01, 0x33, 0xAB, 0x54, 0xAA, 0x23, 0xEB, 0x5C, 0x00, 0x2B, ++ 0x31, 0xD1, 0x9F, 0x23, 0xEB, 0x5C, 0x01, 0x2B, 0x3B, 0xD1, 0xAB, 0x6F, ++ 0x9B, 0xB2, 0x62, 0x21, 0x4E, 0x43, 0x22, 0x4A, 0xB2, 0x18, 0x13, 0x80, ++ 0xAB, 0x6F, 0x1B, 0x0C, 0x20, 0x4A, 0xB2, 0x18, 0x13, 0x80, 0x20, 0x4B, ++ 0x9C, 0x46, 0x66, 0x44, 0x2B, 0x6D, 0x01, 0x33, 0x5B, 0x08, 0x01, 0x33, ++ 0x5B, 0x08, 0x1D, 0x4A, 0x13, 0x43, 0x9B, 0xB2, 0x33, 0x80, 0x22, 0xE0, ++ 0x04, 0x34, 0x24, 0x01, 0x24, 0x09, 0x23, 0x1A, 0x1B, 0x01, 0x1B, 0x09, ++ 0x93, 0x42, 0x9D, 0xD9, 0x03, 0x1B, 0x1B, 0x01, 0x9A, 0xD0, 0xF3, 0xE7, ++ 0x64, 0x3B, 0xFF, 0x3B, 0x01, 0x93, 0x00, 0x9B, 0x01, 0x33, 0x1B, 0x01, ++ 0x1B, 0x09, 0x00, 0x93, 0x9F, 0xE7, 0x9E, 0x23, 0xE8, 0x5C, 0xCB, 0xF7, ++ 0x21, 0xF8, 0x0F, 0x4B, 0x01, 0x22, 0x1A, 0x60, 0xAA, 0x23, 0x00, 0x22, ++ 0xEA, 0x54, 0xC2, 0xE7, 0x0C, 0x48, 0x77, 0xF7, 0xF1, 0xFC, 0x0A, 0xB0, ++ 0x04, 0xBC, 0x90, 0x46, 0xF0, 0xBD, 0xC0, 0x46, 0x38, 0xE6, 0x10, 0x00, ++ 0xFE, 0xFF, 0xFF, 0x07, 0x39, 0xCB, 0x10, 0x00, 0xDE, 0x05, 0x00, 0x00, ++ 0xFA, 0x64, 0x61, 0x40, 0xFC, 0x64, 0x61, 0x40, 0x10, 0x65, 0x61, 0x40, ++ 0x00, 0x80, 0xFF, 0xFF, 0x18, 0x00, 0x60, 0x40, 0x28, 0xD6, 0x10, 0x00, ++ 0xF0, 0xB5, 0xC6, 0x46, 0x00, 0xB5, 0x82, 0xB0, 0x05, 0x00, 0x0E, 0x00, ++ 0x82, 0x00, 0x9D, 0x4B, 0xD4, 0x58, 0x00, 0x2C, 0x00, 0xD1, 0x2B, 0xE1, ++ 0x9B, 0x4B, 0x1B, 0x68, 0xDF, 0x68, 0xA9, 0x23, 0xE3, 0x5C, 0x00, 0x2B, ++ 0x05, 0xD1, 0x99, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, ++ 0x98, 0x47, 0xA9, 0x22, 0xA3, 0x5C, 0x01, 0x3B, 0xDB, 0xB2, 0xA3, 0x54, ++ 0x09, 0x3A, 0xA2, 0x5C, 0x02, 0x2A, 0x01, 0xD1, 0x00, 0x2B, 0x51, 0xD0, ++ 0x9E, 0xF7, 0xDE, 0xFF, 0x01, 0x90, 0x01, 0x22, 0x31, 0x00, 0x28, 0x00, ++ 0xFF, 0xF7, 0x20, 0xFD, 0x62, 0x23, 0x6B, 0x43, 0x8C, 0x4A, 0x94, 0x46, ++ 0x63, 0x44, 0x1B, 0x88, 0xDB, 0x0B, 0x00, 0xD1, 0xAC, 0xE0, 0x31, 0x00, ++ 0x28, 0x00, 0xFF, 0xF7, 0x15, 0xFE, 0xB4, 0x23, 0xE0, 0x54, 0xA0, 0x23, ++ 0xE3, 0x5C, 0x02, 0x2B, 0x00, 0xD1, 0xEA, 0xE0, 0x01, 0x21, 0x28, 0x00, ++ 0xFF, 0xF7, 0xBA, 0xF9, 0x82, 0x23, 0xE3, 0x5E, 0xA3, 0x60, 0x81, 0x4B, ++ 0x1B, 0x68, 0x00, 0x2B, 0x0C, 0xD0, 0x34, 0x23, 0xFB, 0x5C, 0x00, 0x2B, ++ 0x00, 0xD1, 0x9D, 0xE0, 0xA9, 0x23, 0xE3, 0x5C, 0x00, 0x2B, 0x00, 0xD1, ++ 0x93, 0xE0, 0x7A, 0x4B, 0x00, 0x22, 0x1A, 0x60, 0x34, 0x23, 0xFB, 0x5C, ++ 0x00, 0x2B, 0x00, 0xD1, 0x90, 0xE0, 0xB4, 0x23, 0xE3, 0x5C, 0x00, 0x2B, ++ 0x00, 0xD0, 0xBE, 0xE0, 0xAA, 0x33, 0xE3, 0x5C, 0x00, 0x2B, 0x00, 0xD0, ++ 0xD6, 0xE0, 0xA6, 0x33, 0xE2, 0x5C, 0x01, 0x32, 0xA3, 0x3B, 0x13, 0x40, ++ 0x9E, 0x22, 0xA1, 0x5C, 0x9C, 0x3A, 0x6E, 0x48, 0xCA, 0xF7, 0x56, 0xFF, ++ 0xAA, 0x23, 0x01, 0x22, 0xE2, 0x54, 0xC7, 0xE0, 0x01, 0x21, 0x20, 0x00, ++ 0xC9, 0xF7, 0xBE, 0xFF, 0xA0, 0x23, 0x02, 0x22, 0xE2, 0x54, 0x0A, 0x33, ++ 0xE3, 0x5C, 0x00, 0x2B, 0x49, 0xD1, 0xFE, 0xF7, 0xBF, 0xFD, 0x65, 0x4A, ++ 0xD5, 0x23, 0x5B, 0x00, 0xD2, 0x5C, 0xD3, 0x00, 0x9B, 0x1A, 0x5B, 0x00, ++ 0x62, 0x4A, 0x9A, 0x18, 0x12, 0x88, 0xD2, 0x0B, 0x00, 0xD1, 0xAD, 0xE0, ++ 0x60, 0x4A, 0x94, 0x46, 0x63, 0x44, 0x1A, 0x88, 0xD2, 0x0A, 0xAA, 0x42, ++ 0x07, 0xD0, 0x19, 0x88, 0xC9, 0x0A, 0x56, 0x4B, 0xDC, 0x6E, 0x00, 0x23, ++ 0x00, 0x22, 0x28, 0x00, 0xA0, 0x47, 0x57, 0x4C, 0xD5, 0x20, 0x40, 0x00, ++ 0x22, 0x5C, 0xD3, 0x00, 0x9B, 0x1A, 0x5B, 0x00, 0x54, 0x4A, 0x94, 0x46, ++ 0x63, 0x44, 0x1A, 0x88, 0x52, 0x04, 0x52, 0x0C, 0x1A, 0x80, 0x21, 0x5C, ++ 0x01, 0x31, 0x03, 0x23, 0x19, 0x40, 0x21, 0x54, 0x50, 0x4B, 0x1A, 0x68, ++ 0xCB, 0x00, 0x5B, 0x1A, 0x5B, 0x00, 0x4F, 0x49, 0x8C, 0x46, 0x63, 0x44, ++ 0x52, 0x04, 0x52, 0x0C, 0x93, 0x42, 0x05, 0xD0, 0x43, 0x4B, 0x9B, 0x6E, ++ 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x45, 0x4E, 0x00, 0x24, ++ 0xD5, 0x23, 0x5B, 0x00, 0x98, 0x46, 0x3E, 0x4F, 0x0A, 0xE0, 0x28, 0x00, ++ 0xCA, 0xF7, 0x30, 0xFF, 0xAA, 0x23, 0x00, 0x22, 0xE2, 0x54, 0xAE, 0xE7, ++ 0x01, 0x34, 0x0E, 0x36, 0x04, 0x2C, 0x67, 0xD0, 0x33, 0x88, 0xDB, 0x0B, ++ 0xF8, 0xD0, 0x3A, 0x4B, 0x42, 0x46, 0x98, 0x5C, 0x00, 0x23, 0x00, 0x22, ++ 0x21, 0x00, 0xFD, 0x6E, 0xA8, 0x47, 0xEF, 0xE7, 0x31, 0x00, 0x28, 0x00, ++ 0xFF, 0xF7, 0x04, 0xFE, 0xB4, 0x23, 0xE0, 0x54, 0x51, 0xE7, 0x29, 0x00, ++ 0x01, 0x98, 0xFF, 0xF7, 0x53, 0xFE, 0x66, 0xE7, 0xB4, 0x23, 0xE3, 0x5C, ++ 0x00, 0x2B, 0x2E, 0xD1, 0xAA, 0x23, 0xE3, 0x5C, 0x00, 0x2B, 0x47, 0xD1, ++ 0xA9, 0x33, 0xE3, 0x5C, 0x00, 0x2B, 0x43, 0xD1, 0x01, 0x21, 0x20, 0x00, ++ 0xC9, 0xF7, 0x3A, 0xFF, 0x01, 0x99, 0x61, 0x60, 0x86, 0x23, 0xFA, 0x22, ++ 0xD2, 0x01, 0xE2, 0x52, 0x21, 0x67, 0x20, 0x33, 0xE3, 0x5C, 0xDB, 0x02, ++ 0xE0, 0x22, 0x92, 0x01, 0x13, 0x40, 0x26, 0x4A, 0x13, 0x43, 0xA3, 0x82, ++ 0xFA, 0x23, 0x1B, 0x02, 0x9C, 0x46, 0x61, 0x44, 0x0F, 0x01, 0x3F, 0x09, ++ 0xE7, 0x60, 0x20, 0x00, 0xC9, 0xF7, 0x7C, 0xFD, 0x00, 0x28, 0x23, 0xD0, ++ 0x15, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, ++ 0x1C, 0xE0, 0x9E, 0x23, 0xE0, 0x5C, 0xCA, 0xF7, 0xD9, 0xFE, 0x00, 0x23, ++ 0xAA, 0x22, 0xA3, 0x54, 0x75, 0x3A, 0xBB, 0x54, 0xC6, 0xE7, 0x9E, 0x23, ++ 0xE0, 0x5C, 0xCA, 0xF7, 0xCF, 0xFE, 0xAA, 0x23, 0x00, 0x22, 0xE2, 0x54, ++ 0x01, 0x3B, 0xE1, 0x5C, 0x12, 0x48, 0x77, 0xF7, 0xA1, 0xFB, 0x05, 0xE0, ++ 0x06, 0x4B, 0xDC, 0x6E, 0x00, 0x23, 0x00, 0x22, 0x00, 0x21, 0xA0, 0x47, ++ 0x02, 0xB0, 0x04, 0xBC, 0x90, 0x46, 0xF0, 0xBD, 0x38, 0xE6, 0x10, 0x00, ++ 0xD8, 0xE5, 0x10, 0x00, 0x28, 0x19, 0x16, 0x00, 0x4E, 0x65, 0x61, 0x40, ++ 0xC8, 0xE6, 0x10, 0x00, 0x7D, 0x03, 0x10, 0x00, 0x20, 0xA3, 0x16, 0x00, ++ 0x90, 0x69, 0x61, 0x40, 0x92, 0x69, 0x61, 0x40, 0x2C, 0x04, 0x60, 0x40, ++ 0x90, 0x69, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x34, 0xD6, 0x10, 0x00, ++ 0x10, 0xB5, 0x82, 0x00, 0x0C, 0x4B, 0xD4, 0x58, 0x00, 0x2C, 0x0E, 0xD0, ++ 0xA9, 0x23, 0xE3, 0x5C, 0x00, 0x2B, 0x05, 0xD1, 0x09, 0x4B, 0x9B, 0x6E, ++ 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0xA9, 0x22, 0xA3, 0x5C, ++ 0x01, 0x3B, 0xA3, 0x54, 0x10, 0xBD, 0x04, 0x4B, 0xDC, 0x6E, 0x00, 0x23, ++ 0x00, 0x22, 0x00, 0x21, 0xA0, 0x47, 0xF7, 0xE7, 0x38, 0xE6, 0x10, 0x00, ++ 0x28, 0x19, 0x16, 0x00, 0xF0, 0xB5, 0xC6, 0x46, 0x00, 0xB5, 0x06, 0x00, ++ 0x0D, 0x00, 0x14, 0x00, 0xCF, 0xB2, 0x06, 0x2F, 0x08, 0xD9, 0xFF, 0x20, ++ 0x08, 0x40, 0x10, 0x4B, 0xDB, 0x6E, 0x98, 0x46, 0x00, 0x23, 0x00, 0x22, ++ 0x21, 0x00, 0xC0, 0x47, 0x00, 0x2C, 0x0A, 0xD0, 0x04, 0x2C, 0x0F, 0xD0, ++ 0xFF, 0x20, 0x28, 0x40, 0x09, 0x4B, 0xDD, 0x6E, 0x00, 0x23, 0x00, 0x22, ++ 0x21, 0x00, 0xA8, 0x47, 0x03, 0xE0, 0x31, 0x00, 0x38, 0x00, 0xFF, 0xF7, ++ 0x61, 0xFE, 0x04, 0xBC, 0x90, 0x46, 0xF0, 0xBD, 0x31, 0x00, 0x38, 0x00, ++ 0xFF, 0xF7, 0xB6, 0xFF, 0xF7, 0xE7, 0xC0, 0x46, 0x28, 0x19, 0x16, 0x00, ++ 0xF8, 0xB5, 0x05, 0x00, 0x51, 0x4B, 0x1B, 0x68, 0x00, 0x2B, 0x02, 0xD0, ++ 0xFE, 0xF7, 0x0E, 0xFD, 0xF8, 0xBD, 0x4F, 0x48, 0x77, 0xF7, 0x22, 0xFB, ++ 0x4E, 0x4B, 0x1B, 0x68, 0x00, 0x2B, 0x07, 0xD0, 0x4D, 0x4B, 0x9B, 0x6E, ++ 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0x12, 0x20, 0xEF, 0xE7, ++ 0x00, 0x21, 0xF8, 0x20, 0x75, 0xF7, 0xE0, 0xFA, 0x46, 0x4B, 0x18, 0x60, ++ 0x00, 0x28, 0x00, 0xD1, 0x7C, 0xE0, 0x9E, 0xF7, 0x37, 0xFE, 0x06, 0x00, ++ 0x83, 0xF7, 0xD8, 0xFB, 0x43, 0x4A, 0x13, 0x88, 0x43, 0x49, 0x0B, 0x40, ++ 0x00, 0x02, 0x03, 0x43, 0x9B, 0xB2, 0x13, 0x80, 0x3D, 0x4B, 0x1C, 0x68, ++ 0xF8, 0x22, 0x00, 0x21, 0x20, 0x00, 0x73, 0xF7, 0x79, 0xFA, 0x00, 0x23, ++ 0x63, 0x62, 0x3D, 0x4A, 0xE2, 0x61, 0x3D, 0x4A, 0x22, 0x62, 0x03, 0x22, ++ 0x22, 0x76, 0x3C, 0x4A, 0x12, 0x78, 0xA2, 0x75, 0x3B, 0x4A, 0x22, 0x61, ++ 0x05, 0x22, 0xE2, 0x75, 0x99, 0x32, 0xA3, 0x54, 0x01, 0x32, 0x01, 0x21, ++ 0xA1, 0x54, 0x6B, 0x3A, 0x22, 0x65, 0x6D, 0x32, 0xA3, 0x54, 0x7F, 0xF7, ++ 0xA9, 0xFA, 0x07, 0x1E, 0x3D, 0xD0, 0x3A, 0x89, 0x94, 0x23, 0xE2, 0x52, ++ 0x93, 0x3B, 0x01, 0x22, 0x29, 0x00, 0x00, 0x20, 0xFE, 0xF7, 0xE8, 0xFC, ++ 0x33, 0x00, 0x00, 0x22, 0x29, 0x00, 0x01, 0x20, 0xFF, 0xF7, 0x50, 0xF9, ++ 0x9E, 0xF7, 0xF8, 0xFD, 0x60, 0x60, 0x00, 0x23, 0x82, 0x22, 0xA3, 0x52, ++ 0xA3, 0x60, 0x04, 0x32, 0xFA, 0x21, 0xC9, 0x01, 0xA1, 0x52, 0xE6, 0x66, ++ 0x26, 0x67, 0x63, 0x67, 0xA3, 0x67, 0x00, 0x22, 0xA6, 0x33, 0xE2, 0x54, ++ 0x23, 0x4B, 0xA3, 0x82, 0xFA, 0x23, 0x1B, 0x02, 0x9C, 0x46, 0x66, 0x44, ++ 0x36, 0x01, 0x36, 0x09, 0xE6, 0x60, 0x20, 0x00, 0xC9, 0xF7, 0x6C, 0xFC, ++ 0x00, 0x28, 0x15, 0xD1, 0xA0, 0x23, 0x00, 0x22, 0xE2, 0x54, 0x1C, 0x49, ++ 0xA1, 0x32, 0xFF, 0x32, 0x8B, 0x5A, 0x01, 0x24, 0x23, 0x43, 0x8B, 0x52, ++ 0xA0, 0x3A, 0xFF, 0x3A, 0x18, 0x4B, 0x1A, 0x60, 0x78, 0xE7, 0x0E, 0x4B, ++ 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, 0xBA, 0xE7, ++ 0x0A, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0x98, 0x47, ++ 0x12, 0x20, 0x69, 0xE7, 0x06, 0x4B, 0x9B, 0x6E, 0x00, 0x22, 0x00, 0x21, ++ 0x00, 0x20, 0x98, 0x47, 0x12, 0x20, 0x61, 0xE7, 0xD8, 0xE5, 0x10, 0x00, ++ 0x4C, 0xD6, 0x10, 0x00, 0x38, 0xE6, 0x10, 0x00, 0x28, 0x19, 0x16, 0x00, ++ 0xFE, 0x64, 0x61, 0x40, 0xFF, 0xF8, 0xFF, 0xFF, 0xA1, 0x04, 0x10, 0x00, ++ 0xD3, 0x01, 0x10, 0x00, 0x7C, 0x91, 0x0D, 0x00, 0x6A, 0x04, 0x00, 0x00, ++ 0x00, 0x80, 0xFF, 0xFF, 0x20, 0xA3, 0x16, 0x00, 0xC8, 0xE6, 0x10, 0x00, ++ 0x70, 0xB5, 0x04, 0x00, 0x0D, 0x00, 0x0A, 0x48, 0x77, 0xF7, 0x68, 0xFA, ++ 0xA1, 0x78, 0x4A, 0x10, 0x01, 0x23, 0x1A, 0x40, 0x07, 0x48, 0x02, 0x70, ++ 0x0B, 0x40, 0xA3, 0x70, 0x20, 0x00, 0xFF, 0xF7, 0x85, 0xF9, 0x01, 0x00, ++ 0x28, 0x00, 0xFA, 0xF7, 0x8B, 0xF9, 0x00, 0x20, 0x70, 0xBD, 0xC0, 0x46, ++ 0x60, 0xD6, 0x10, 0x00, 0xDC, 0xE5, 0x10, 0x00, 0x70, 0xB5, 0x05, 0x00, ++ 0x0C, 0x00, 0x06, 0x48, 0x77, 0xF7, 0x4C, 0xFA, 0x28, 0x00, 0xFF, 0xF7, ++ 0x1B, 0xFF, 0x01, 0x00, 0x20, 0x00, 0xFA, 0xF7, 0x77, 0xF9, 0x00, 0x20, ++ 0x70, 0xBD, 0xC0, 0x46, 0x68, 0xD6, 0x10, 0x00, 0x10, 0xB5, 0xFF, 0xF7, ++ 0x51, 0xF8, 0x00, 0x20, 0x10, 0xBD, 0x00, 0x00, 0x10, 0xB5, 0x0E, 0x4B, ++ 0x1B, 0x68, 0x00, 0x2B, 0x17, 0xD0, 0xDC, 0x68, 0x18, 0x23, 0x0D, 0x22, ++ 0x00, 0x21, 0x0B, 0x48, 0x75, 0xF7, 0x2A, 0xF9, 0xFF, 0x23, 0x03, 0x70, ++ 0xA3, 0x88, 0x43, 0x80, 0x00, 0x23, 0x03, 0x71, 0x43, 0x71, 0x23, 0x69, ++ 0x83, 0x60, 0x63, 0x69, 0xC3, 0x60, 0xE3, 0x69, 0x03, 0x61, 0xE3, 0x6A, ++ 0x43, 0x61, 0xC6, 0xF7, 0x79, 0xFF, 0x10, 0xBD, 0xD8, 0xE5, 0x10, 0x00, ++ 0x03, 0x11, 0x00, 0x00, 0x70, 0xB5, 0x04, 0x00, 0x0D, 0x00, 0x01, 0x78, ++ 0x0A, 0x48, 0x77, 0xF7, 0x11, 0xFA, 0x23, 0x78, 0x00, 0x2B, 0x07, 0xD0, ++ 0x01, 0x2B, 0x08, 0xD0, 0x00, 0x21, 0x28, 0x00, 0xFA, 0xF7, 0x3A, 0xF9, ++ 0x00, 0x20, 0x70, 0xBD, 0xFE, 0xF7, 0x6E, 0xFB, 0xF6, 0xE7, 0xFF, 0xF7, ++ 0xC7, 0xFF, 0xFE, 0xF7, 0x69, 0xFB, 0xF1, 0xE7, 0x70, 0xD6, 0x10, 0x00, ++ 0x45, 0x54, 0x45, 0x52, 0x52, 0x3A, 0x0A, 0x00, 0x77, 0x61, 0x6B, 0x65, ++ 0x75, 0x70, 0x5F, 0x68, 0x6F, 0x73, 0x74, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x70, 0x6F, 0x77, 0x65, 0x72, 0x5F, 0x75, 0x70, 0x5F, 0x68, 0x6F, 0x73, ++ 0x74, 0x0A, 0x00, 0x00, 0x75, 0x61, 0x72, 0x74, 0x5F, 0x69, 0x6E, 0x69, ++ 0x74, 0x0A, 0x00, 0x00, 0x70, 0x5F, 0x73, 0x5F, 0x70, 0x00, 0x00, 0x00, ++ 0x77, 0x69, 0x66, 0x69, 0x5F, 0x63, 0x68, 0x5F, 0x75, 0x70, 0x64, 0x61, ++ 0x74, 0x65, 0x3A, 0x25, 0x78, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, ++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xE6, 0x1A, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xF6, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0x1A, 0x1B, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0x42, 0x1B, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0x66, 0x1B, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0x8E, 0x1B, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0xBA, 0x1B, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xE6, 0x1B, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0x0C, 0x1C, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0x32, 0x1C, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0x5C, 0x1C, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0x82, 0x1C, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0xA2, 0x1C, 0x10, 0x00, ++ 0xC4, 0x1C, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0x16, 0x1B, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0x3E, 0x1B, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0x62, 0x1B, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0x8A, 0x1B, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xB6, 0x1B, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0xE2, 0x1B, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0x08, 0x1C, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0x2E, 0x1C, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0x58, 0x1C, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0x7E, 0x1C, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0x9E, 0x1C, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, 0xA8, 0x1A, 0x10, 0x00, ++ 0xC0, 0x1C, 0x10, 0x00, 0x30, 0x78, 0x34, 0x30, 0x33, 0x34, 0x33, 0x30, ++ 0x30, 0x34, 0x3A, 0x25, 0x78, 0x2C, 0x25, 0x78, 0x00, 0x00, 0x00, 0x00, ++ 0x43, 0x54, 0x53, 0x3A, 0x25, 0x78, 0x2C, 0x25, 0x78, 0x20, 0x0A, 0x00, ++ 0xE2, 0x1D, 0x10, 0x00, 0x78, 0x1D, 0x10, 0x00, 0x78, 0x1D, 0x10, 0x00, ++ 0x78, 0x1D, 0x10, 0x00, 0x78, 0x1D, 0x10, 0x00, 0x78, 0x1D, 0x10, 0x00, ++ 0x52, 0x1E, 0x10, 0x00, 0xE4, 0x1D, 0x10, 0x00, 0x78, 0x1D, 0x10, 0x00, ++ 0x78, 0x1D, 0x10, 0x00, 0xE2, 0x1D, 0x10, 0x00, 0x78, 0x1D, 0x10, 0x00, ++ 0x78, 0x1D, 0x10, 0x00, 0x6D, 0x64, 0x6C, 0x6C, 0x5F, 0x72, 0x65, 0x63, ++ 0x3A, 0x25, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x62, 0x64, 0x5F, 0x61, ++ 0x64, 0x64, 0x72, 0x3A, 0x25, 0x78, 0x2C, 0x25, 0x78, 0x0A, 0x00, 0x00, ++ 0x77, 0x69, 0x66, 0x69, 0x6D, 0x61, 0x63, 0x5F, 0x61, 0x64, 0x64, 0x72, ++ 0x3A, 0x25, 0x78, 0x2C, 0x25, 0x78, 0x0A, 0x00, 0x66, 0x6C, 0x61, 0x73, ++ 0x68, 0x6D, 0x61, 0x63, 0x5F, 0x61, 0x64, 0x64, 0x72, 0x3A, 0x25, 0x78, ++ 0x2C, 0x25, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x49, 0x4E, 0x43, 0x52, ++ 0x5F, 0x50, 0x57, 0x52, 0x5F, 0x52, 0x45, 0x51, 0x0A, 0x00, 0x00, 0x00, ++ 0x50, 0x57, 0x52, 0x5F, 0x43, 0x54, 0x52, 0x4C, 0x5F, 0x52, 0x45, 0x51, ++ 0x0A, 0x00, 0x00, 0x00, 0x72, 0x65, 0x6D, 0x6F, 0x74, 0x65, 0x5F, 0x6D, ++ 0x61, 0x78, 0x5F, 0x70, 0x77, 0x72, 0x0A, 0x00, 0x61, 0x66, 0x68, 0x74, ++ 0x6F, 0x3A, 0x25, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x74, 0x78, 0x5F, 0x61, ++ 0x62, 0x6F, 0x72, 0x74, 0x0A, 0x00, 0x00, 0x00, 0x72, 0x3A, 0x25, 0x78, ++ 0x2C, 0x25, 0x78, 0x2C, 0x25, 0x78, 0x2C, 0x25, 0x78, 0x2C, 0x25, 0x78, ++ 0x2C, 0x25, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x72, 0x73, 0x73, 0x69, ++ 0x3A, 0x20, 0x25, 0x78, 0x2C, 0x20, 0x25, 0x78, 0x0A, 0x00, 0x00, 0x00, ++ 0x73, 0x6D, 0x75, 0x74, 0x65, 0x0A, 0x00, 0x00, 0x72, 0x78, 0x5F, 0x69, ++ 0x6E, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x3A, 0x25, 0x78, 0x2C, 0x25, 0x78, ++ 0x2C, 0x25, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x65, 0x72, 0x72, 0x3A, ++ 0x25, 0x78, 0x0A, 0x00, 0x64, 0x75, 0x20, 0x65, 0x6E, 0x6F, 0x75, 0x67, ++ 0x68, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x77, 0x69, 0x66, 0x69, 0x20, 0x63, ++ 0x6F, 0x6E, 0x6E, 0x65, 0x63, 0x69, 0x6F, 0x6E, 0x0A, 0x00, 0x00, 0x00, ++ 0x75, 0x6D, 0x72, 0x65, 0x0A, 0x00, 0x00, 0x00, 0x55, 0x4E, 0x44, 0x45, ++ 0x46, 0x20, 0x56, 0x45, 0x4E, 0x44, 0x4F, 0x52, 0x5F, 0x49, 0x4E, 0x46, ++ 0x4F, 0x0A, 0x00, 0x00, 0x55, 0x4E, 0x4B, 0x4E, 0x4F, 0x57, 0x20, 0x56, ++ 0x45, 0x4E, 0x44, 0x4F, 0x52, 0x5F, 0x49, 0x4E, 0x46, 0x4F, 0x3A, 0x25, ++ 0x78, 0x0A, 0x00, 0x00, 0x69, 0x6E, 0x69, 0x74, 0x3A, 0x25, 0x78, 0x2C, ++ 0x25, 0x78, 0x2C, 0x25, 0x78, 0x2C, 0x25, 0x78, 0x2C, 0x25, 0x78, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x38, 0x5C, 0x10, 0x00, 0x70, 0x5C, 0x10, 0x00, ++ 0x78, 0x5C, 0x10, 0x00, 0x38, 0x5C, 0x10, 0x00, 0x70, 0x5C, 0x10, 0x00, ++ 0x76, 0x65, 0x72, 0x3A, 0x25, 0x73, 0x0A, 0x00, 0x6C, 0x6D, 0x74, 0x3A, ++ 0x25, 0x78, 0x2C, 0x25, 0x78, 0x0A, 0x00, 0x00, 0x72, 0x65, 0x6A, 0x65, ++ 0x63, 0x74, 0x3A, 0x25, 0x78, 0x00, 0x00, 0x00, 0x76, 0x73, 0x5F, 0x61, ++ 0x70, 0x63, 0x66, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x72, 0x65, 0x6A, 0x65, ++ 0x63, 0x74, 0x32, 0x3A, 0x25, 0x78, 0x00, 0x00, 0x92, 0x73, 0x10, 0x00, ++ 0xC6, 0x72, 0x10, 0x00, 0x86, 0x73, 0x10, 0x00, 0xC6, 0x72, 0x10, 0x00, ++ 0x92, 0x73, 0x10, 0x00, 0xC6, 0x72, 0x10, 0x00, 0xC6, 0x72, 0x10, 0x00, ++ 0x8C, 0x73, 0x10, 0x00, 0xC0, 0x72, 0x10, 0x00, 0x6E, 0x6F, 0x61, 0x6C, ++ 0x63, 0x62, 0x75, 0x66, 0x0A, 0x00, 0x00, 0x00, 0x62, 0x62, 0x5F, 0x74, ++ 0x78, 0x5F, 0x74, 0x6F, 0x6E, 0x65, 0x3A, 0x25, 0x78, 0x0A, 0x00, 0x00, ++ 0x6F, 0x70, 0x6D, 0x3A, 0x25, 0x78, 0x0A, 0x00, 0x6D, 0x73, 0x73, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x6D, 0x73, 0x73, 0x65, 0x72, 0x72, 0x0A, 0x00, ++ 0x46, 0x4C, 0x55, 0x53, 0x48, 0x3A, 0x25, 0x78, 0x0A, 0x00, 0x00, 0x00, ++ 0x4C, 0x54, 0x4B, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x25, 0x78, 0x20, 0x00, ++ 0x6F, 0x70, 0x63, 0x3A, 0x25, 0x78, 0x0A, 0x00, 0x69, 0x20, 0x3D, 0x20, ++ 0x3A, 0x25, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x69, 0x3A, 0x25, 0x78, ++ 0x0A, 0x00, 0x00, 0x00, 0x6F, 0x70, 0x6C, 0x6C, 0x6D, 0x3A, 0x25, 0x78, ++ 0x0A, 0x00, 0x00, 0x00, 0x1E, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, ++ 0xF4, 0x8A, 0x10, 0x00, 0xBE, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, ++ 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, ++ 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, ++ 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, ++ 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, ++ 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, 0xDA, 0x89, 0x10, 0x00, ++ 0xDA, 0x89, 0x10, 0x00, 0xFC, 0x89, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, ++ 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, ++ 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, ++ 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, ++ 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, ++ 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, ++ 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, ++ 0xDA, 0x89, 0x10, 0x00, 0xDA, 0x89, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, ++ 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, ++ 0x4C, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, 0xE8, 0x8A, 0x10, 0x00, ++ 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, ++ 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, 0xF4, 0x8A, 0x10, 0x00, ++ 0xF4, 0x8A, 0x10, 0x00, 0x62, 0x8A, 0x10, 0x00, 0x55, 0x50, 0x3A, 0x25, ++ 0x78, 0x2C, 0x25, 0x78, 0x2C, 0x25, 0x78, 0x2C, 0x25, 0x78, 0x0A, 0x00, ++ 0x6F, 0x70, 0x6C, 0x6C, 0x63, 0x3A, 0x25, 0x78, 0x0A, 0x00, 0x00, 0x00, ++ 0x6C, 0x6C, 0x63, 0x72, 0x78, 0x3A, 0x25, 0x78, 0x0A, 0x00, 0x00, 0x00, ++ 0x6C, 0x6C, 0x63, 0x74, 0x6D, 0x3A, 0x25, 0x78, 0x0A, 0x00, 0x00, 0x00, ++ 0x61, 0x70, 0x63, 0x66, 0x3A, 0x25, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x6C, 0x61, 0x74, 0x65, 0x6E, 0x63, 0x79, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x72, 0x66, 0x5F, 0x72, 0x65, 0x73, 0x65, 0x74, 0x3A, 0x25, 0x78, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x45, 0x52, 0x52, 0x3A, 0x25, 0x78, 0x2C, 0x25, ++ 0x78, 0x2C, 0x25, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x41, 0x53, 0x53, 0x45, ++ 0x52, 0x54, 0x5F, 0x57, 0x41, 0x52, 0x4E, 0x49, 0x4E, 0x47, 0x28, 0x25, ++ 0x73, 0x29, 0x2C, 0x20, 0x69, 0x6E, 0x20, 0x25, 0x78, 0x20, 0x61, 0x74, ++ 0x20, 0x6C, 0x69, 0x6E, 0x65, 0x20, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, ++ 0x41, 0x53, 0x53, 0x45, 0x52, 0x54, 0x5F, 0x45, 0x52, 0x52, 0x7A, 0x28, ++ 0x25, 0x73, 0x29, 0x2C, 0x20, 0x69, 0x6E, 0x20, 0x25, 0x78, 0x20, 0x61, ++ 0x74, 0x20, 0x6C, 0x69, 0x6E, 0x65, 0x20, 0x25, 0x64, 0x0D, 0x0A, 0x00, ++ 0x41, 0x53, 0x53, 0x45, 0x52, 0x54, 0x5F, 0x50, 0x41, 0x52, 0x41, 0x4D, ++ 0x7A, 0x28, 0x30, 0x78, 0x25, 0x58, 0x2C, 0x20, 0x30, 0x78, 0x25, 0x58, ++ 0x29, 0x2C, 0x20, 0x69, 0x6E, 0x20, 0x25, 0x78, 0x20, 0x61, 0x74, 0x20, ++ 0x6C, 0x69, 0x6E, 0x65, 0x20, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x00, ++ 0x70, 0x61, 0x67, 0x65, 0x5F, 0x73, 0x74, 0x61, 0x72, 0x74, 0x0A, 0x00, ++ 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x25, 0x78, 0x0D, 0x0A, 0x00, ++ 0x64, 0x65, 0x6C, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x25, 0x64, 0x0D, 0x0A, ++ 0x00, 0x00, 0x00, 0x00, 0x6F, 0x70, 0x3A, 0x30, 0x78, 0x25, 0x78, 0x20, ++ 0x30, 0x78, 0x25, 0x78, 0x0D, 0x0A, 0x00, 0x00, 0x73, 0x63, 0x61, 0x6E, ++ 0x5F, 0x65, 0x6E, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x63, 0x68, 0x65, 0x72, ++ 0x72, 0x3A, 0x25, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, ++ 0x5F, 0x6D, 0x6F, 0x64, 0x65, 0x5F, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x3A, ++ 0x25, 0x78, 0x0A, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5F, 0x6D, 0x6F, 0x64, ++ 0x65, 0x5F, 0x65, 0x78, 0x69, 0x74, 0x3A, 0x25, 0x78, 0x0A, 0x00, 0x00, ++ 0x74, 0x73, 0x74, 0x5F, 0x65, 0x6E, 0x64, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x6C, 0x64, 0x5F, 0x62, 0x62, 0x5F, 0x74, 0x73, 0x74, 0x5F, 0x75, 0x70, ++ 0x64, 0x61, 0x74, 0x65, 0x3A, 0x25, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0x65, 0x64, 0x72, 0x5F, 0x70, 0x6B, 0x74, 0x3D, 0x25, 0x78, 0x00, 0x00, ++ 0x66, 0x72, 0x65, 0x71, 0x25, 0x78, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, ++ 0xC0, 0xB8, 0x10, 0x00, 0xB4, 0xB9, 0x10, 0x00, 0x94, 0xBA, 0x10, 0x00, ++ 0xF2, 0xB8, 0x10, 0x00, 0xB0, 0xBA, 0x10, 0x00, 0xCC, 0xBA, 0x10, 0x00, ++ 0xE8, 0xBA, 0x10, 0x00, 0x04, 0xBB, 0x10, 0x00, 0x70, 0x6F, 0x3A, 0x25, ++ 0x34, 0x64, 0x2C, 0x20, 0x73, 0x6F, 0x3A, 0x25, 0x34, 0x64, 0x2C, 0x20, ++ 0x68, 0x65, 0x3A, 0x25, 0x34, 0x64, 0x2C, 0x20, 0x63, 0x65, 0x3A, 0x25, ++ 0x34, 0x64, 0x2C, 0x20, 0x6F, 0x65, 0x3A, 0x25, 0x34, 0x64, 0x2C, 0x20, ++ 0x63, 0x6F, 0x6C, 0x65, 0x3A, 0x25, 0x34, 0x64, 0x2C, 0x20, 0x70, 0x6E, ++ 0x3A, 0x25, 0x34, 0x64, 0x20, 0x62, 0x63, 0x3A, 0x25, 0x37, 0x64, 0x2C, ++ 0x20, 0x62, 0x65, 0x3A, 0x25, 0x37, 0x64, 0x2C, 0x20, 0x70, 0x65, 0x72, ++ 0x3A, 0x25, 0x64, 0x2E, 0x25, 0x64, 0x2C, 0x20, 0x62, 0x65, 0x72, 0x3A, ++ 0x25, 0x64, 0x2E, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x70, 0x6F, 0x3A, 0x25, ++ 0x34, 0x64, 0x2C, 0x20, 0x73, 0x6F, 0x3A, 0x25, 0x34, 0x64, 0x2C, 0x20, ++ 0x68, 0x65, 0x3A, 0x25, 0x34, 0x64, 0x2C, 0x20, 0x63, 0x65, 0x3A, 0x25, ++ 0x34, 0x64, 0x2C, 0x20, 0x62, 0x63, 0x3A, 0x25, 0x37, 0x64, 0x2C, 0x20, ++ 0x62, 0x65, 0x3A, 0x25, 0x37, 0x64, 0x2C, 0x20, 0x70, 0x65, 0x72, 0x3A, ++ 0x25, 0x64, 0x2E, 0x25, 0x64, 0x2C, 0x20, 0x62, 0x65, 0x72, 0x3A, 0x25, ++ 0x64, 0x2E, 0x25, 0x64, 0x0D, 0x0A, 0x00, 0x00, 0x6C, 0x64, 0x5F, 0x62, ++ 0x62, 0x5F, 0x62, 0x75, 0x72, 0x73, 0x74, 0x5F, 0x74, 0x78, 0x5F, 0x73, ++ 0x74, 0x61, 0x72, 0x74, 0x0A, 0x00, 0x00, 0x00, 0x72, 0x78, 0x61, 0x62, ++ 0x6F, 0x72, 0x74, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x73, 0x63, 0x68, 0x5F, ++ 0x70, 0x72, 0x6F, 0x67, 0x5F, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6C, 0x65, ++ 0x3A, 0x25, 0x78, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x64, 0x5F, 0x62, ++ 0x62, 0x5F, 0x72, 0x78, 0x5F, 0x74, 0x73, 0x74, 0x5F, 0x73, 0x74, 0x61, ++ 0x72, 0x74, 0x0A, 0x00, 0x74, 0x78, 0x5F, 0x74, 0x73, 0x74, 0x0A, 0x00, ++ 0x72, 0x78, 0x5F, 0x74, 0x73, 0x74, 0x0A, 0x00, 0x62, 0x62, 0x5F, 0x74, ++ 0x73, 0x74, 0x5F, 0x73, 0x74, 0x6F, 0x70, 0x3A, 0x25, 0x78, 0x0A, 0x00, ++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00, ++ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0x00, 0x00, ++ 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x02, 0x02, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC7, 0x03, 0x00, 0x00, ++ 0xFF, 0xC1, 0xFB, 0xE8, 0x4C, 0x90, 0x72, 0x8B, 0xE7, 0xB3, 0x51, 0x89, ++ 0x63, 0xAB, 0x23, 0x23, 0x02, 0x84, 0x18, 0x72, 0xAA, 0x61, 0x2F, 0x3B, ++ 0x51, 0xA8, 0xE5, 0x37, 0x49, 0xFB, 0xC9, 0xCA, 0x0C, 0x18, 0x53, 0x2C, ++ 0xFD, 0x45, 0xE3, 0x9A, 0xE6, 0xF1, 0x5D, 0xB0, 0xB6, 0x1B, 0xB4, 0xBE, ++ 0x2A, 0x50, 0xEA, 0xE9, 0x0E, 0x9C, 0x4B, 0x5E, 0x57, 0x24, 0xCC, 0xA1, ++ 0xB7, 0x59, 0xB8, 0x87, 0xFF, 0xE0, 0x7D, 0x74, 0x26, 0x48, 0xB9, 0xC5, ++ 0xF3, 0xD9, 0xA8, 0xC4, 0xB1, 0xD5, 0x91, 0x11, 0x01, 0x42, 0x0C, 0x39, ++ 0xD5, 0xB0, 0x97, 0x9D, 0x28, 0xD4, 0xF2, 0x9B, 0xA4, 0xFD, 0x64, 0x65, ++ 0x06, 0x8C, 0x29, 0x96, 0xFE, 0xA2, 0x71, 0x4D, 0xF3, 0xF8, 0x2E, 0x58, ++ 0xDB, 0x0D, 0x5A, 0x5F, 0x15, 0x28, 0xF5, 0x74, 0x07, 0xCE, 0x25, 0xAF, ++ 0x2B, 0x12, 0xE6, 0xD0, 0xDB, 0x2C, 0xDC, 0xC3, 0x7F, 0xF0, 0x3E, 0x3A, ++ 0x13, 0xA4, 0xDC, 0xE2, 0xF9, 0x6C, 0x54, 0xE2, 0xD8, 0xEA, 0xC8, 0x88, ++ 0x00, 0x21, 0x86, 0x9C, 0x6A, 0xD8, 0xCB, 0x4E, 0x14, 0x6A, 0xF9, 0x4D, ++ 0xD2, 0x7E, 0xB2, 0x32, 0x03, 0xC6, 0x14, 0x4B, 0x7F, 0xD1, 0xB8, 0xA6, ++ 0x79, 0x7C, 0x17, 0xAC, 0xED, 0x06, 0xAD, 0xAF, 0x0A, 0x94, 0x7A, 0xBA, ++ 0x03, 0xE7, 0x92, 0xD7, 0x15, 0x09, 0x73, 0xE8, 0x6D, 0x16, 0xEE, 0xE1, ++ 0x3F, 0x78, 0x1F, 0x9D, 0x09, 0x52, 0x6E, 0xF1, 0x7C, 0x36, 0x2A, 0x71, ++ 0x6C, 0x75, 0x64, 0x44, 0x80, 0x10, 0x43, 0x4E, 0x35, 0xEC, 0x65, 0x27, ++ 0x0A, 0xB5, 0xFC, 0x26, 0x69, 0x3F, 0x59, 0x99, 0x01, 0x63, 0x8A, 0xA5, ++ 0xBF, 0x68, 0x5C, 0xD3, 0x3C, 0xBE, 0x0B, 0xD6, 0x76, 0x83, 0xD6, 0x57, ++ 0x05, 0x4A, 0x3D, 0xDD, 0x81, 0x73, 0xC9, 0xEB, 0x8A, 0x84, 0x39, 0xF4, ++ 0x36, 0x0B, 0xF7, 0xF0, 0x1F, 0xBC, 0x8F, 0xCE, 0x04, 0x29, 0xB7, 0x78, ++ 0x3E, 0x1B, 0x95, 0x38, 0xB6, 0x3A, 0x32, 0x22, 0x40, 0x88, 0x21, 0xA7, ++ 0x1A, 0xF6, 0xB2, 0x13, 0x85, 0x5A, 0x7E, 0x93, 0xB4, 0x9F, 0xAC, 0xCC, ++ 0x80, 0x31, 0xC5, 0xD2, 0x5F, 0x34, 0xAE, 0x69, 0x1E, 0xDF, 0x05, 0x6B, ++ 0xBB, 0x41, 0xEB, 0xAB, 0x02, 0xA5, 0x9E, 0xEE, 0xC0, 0xB9, 0xE4, 0x75, ++ 0x45, 0xC2, 0x1C, 0x7A, 0x9B, 0x85, 0x7B, 0xF8, 0x0F, 0xDE, 0x47, 0x67, ++ 0x82, 0x94, 0x5B, 0x3C, 0x9F, 0x8D, 0x4A, 0x1C, 0x5B, 0x1D, 0x19, 0x11, ++ 0x20, 0xC4, 0x90, 0x53, 0x0D, 0x7B, 0xD9, 0x89, 0x42, 0x2D, 0xBF, 0x49, ++ 0xDA, 0x4F, 0x56, 0x66, 0xC0, 0x98, 0x62, 0xE9, 0x2F, 0x1A, 0xD7, 0x34, ++ 0x8F, 0xEF, 0x82, 0xB5, 0xDD, 0xA0, 0xF5, 0x55, 0x81, 0x52, 0x4F, 0x77, ++ 0xE0, 0x5C, 0xF2, 0xBA, 0x22, 0x61, 0x0E, 0xBD, 0xCD, 0xC2, 0x3D, 0xFC, ++ 0x07, 0xEF, 0xA3, 0x33, 0x41, 0xCA, 0x2D, 0x9E, 0xCF, 0x46, 0x25, 0x8E, ++ 0xAD, 0x8E, 0x8C, 0x08, 0x10, 0x62, 0xC8, 0xA9, 0x86, 0xBD, 0xEC, 0x44, ++ 0xA1, 0x96, 0xDF, 0x24, 0xED, 0x27, 0x2B, 0x33, 0x60, 0x4C, 0xB1, 0xF4, ++ 0x17, 0x8D, 0x6B, 0x9A, 0xC7, 0x77, 0xC1, 0xDA, 0x6E, 0xD0, 0xFA, 0xAA, ++ 0x40, 0xA9, 0xA7, 0x3B, 0x70, 0x2E, 0x79, 0x5D, 0x91, 0x30, 0x87, 0xDE, ++ 0x66, 0xE1, 0x1E, 0xFE, 0x83, 0xF7, 0xD1, 0x99, 0x20, 0xE5, 0x16, 0xCF, ++ 0x67, 0xA3, 0x12, 0xC7, 0x56, 0x47, 0x46, 0x04, 0x08, 0x31, 0xE4, 0x54, ++ 0xC3, 0x5E, 0x76, 0xA2, 0x50, 0xCB, 0x6F, 0x92, 0xF6, 0x93, 0x95, 0x19, ++ 0x30, 0xA6, 0x58, 0xFA, 0x8B, 0xC6, 0x35, 0xCD, 0xE3, 0xBB, 0x60, 0x6D, ++ 0x37, 0x68, 0x7D, 0x55, 0xA0, 0xD4, 0xD3, 0x1D, 0x38, 0x97, 0xBC, 0xAE, ++ 0x48, 0x98, 0x43, 0x6F, 0xB3, 0x70, 0x0F, 0xFF, 0xC1, 0xFB, 0xE8, 0x4C, ++ 0x90, 0x72, 0x8B, 0xE7, 0xB3, 0x51, 0x89, 0x63, 0xAB, 0x23, 0x23, 0x02, ++ 0x84, 0x18, 0x72, 0xAA, 0x61, 0x2F, 0x3B, 0x51, 0xA8, 0xE5, 0x37, 0x49, ++ 0xFB, 0xC9, 0xCA, 0x0C, 0x18, 0x53, 0x2C, 0xFD, 0x45, 0xE3, 0x9A, 0xE6, ++ 0xF1, 0x5D, 0xB0, 0xB6, 0x1B, 0xB4, 0xBE, 0x2A, 0x50, 0xEA, 0xE9, 0x0E, ++ 0x9C, 0x4B, 0x5E, 0x57, 0x24, 0xCC, 0xA1, 0xB7, 0x59, 0xB8, 0x87, 0xFF, ++ 0xE0, 0x7D, 0x74, 0x26, 0x48, 0xB9, 0xC5, 0xF3, 0xD9, 0xA8, 0xC4, 0xB1, ++ 0xD5, 0x91, 0x11, 0x01, 0x42, 0x0C, 0x39, 0xD5, 0xB0, 0x97, 0x9D, 0x28, ++ 0xD4, 0xF2, 0x9B, 0xA4, 0xFD, 0x64, 0x65, 0x06, 0x8C, 0x29, 0x96, 0xFE, ++ 0xA2, 0x71, 0x4D, 0xF3, 0xF8, 0x2E, 0x58, 0xDB, 0x0D, 0x5A, 0x5F, 0x15, ++ 0x28, 0xF5, 0x74, 0x07, 0xCE, 0x25, 0xAF, 0x2B, 0x12, 0xE6, 0xD0, 0xDB, ++ 0x2C, 0xDC, 0xC3, 0x7F, 0xF0, 0x3E, 0x3A, 0x13, 0xA4, 0xDC, 0xE2, 0xF9, ++ 0x6C, 0x54, 0xE2, 0xD8, 0xEA, 0xC8, 0x88, 0x00, 0x21, 0x86, 0x9C, 0x6A, ++ 0xD8, 0xCB, 0x4E, 0x14, 0x6A, 0xF9, 0x4D, 0xD2, 0x7E, 0xB2, 0x32, 0x03, ++ 0xC6, 0x14, 0x4B, 0x7F, 0xD1, 0xB8, 0xA6, 0x79, 0x7C, 0x17, 0xAC, 0xED, ++ 0x06, 0xAD, 0xAF, 0x0A, 0x94, 0x7A, 0xBA, 0x03, 0xE7, 0x92, 0xD7, 0x15, ++ 0x09, 0x73, 0xE8, 0x6D, 0x16, 0xEE, 0xE1, 0x3F, 0x78, 0x1F, 0x9D, 0x09, ++ 0x52, 0x6E, 0xF1, 0x7C, 0x36, 0x2A, 0x71, 0x6C, 0x75, 0x64, 0x44, 0x80, ++ 0x10, 0x43, 0x4E, 0x35, 0xEC, 0x65, 0x27, 0x0A, 0xB5, 0xFC, 0x26, 0x69, ++ 0x3F, 0x59, 0x99, 0x01, 0x63, 0x8A, 0xA5, 0xBF, 0x68, 0x5C, 0xD3, 0x3C, ++ 0xBE, 0x0B, 0xD6, 0x76, 0x83, 0xD6, 0x57, 0x05, 0x4A, 0x3D, 0xDD, 0x81, ++ 0x73, 0xC9, 0xEB, 0x8A, 0x84, 0x39, 0xF4, 0x36, 0x0B, 0xF7, 0xF0, 0x1F, ++ 0xBC, 0x8F, 0xCE, 0x04, 0x29, 0xB7, 0x78, 0x3E, 0x1B, 0x95, 0x38, 0xB6, ++ 0x3A, 0x32, 0x22, 0x40, 0x88, 0x21, 0xA7, 0x1A, 0xF6, 0xB2, 0x13, 0x85, ++ 0x5A, 0x7E, 0x93, 0xB4, 0x9F, 0xAC, 0xCC, 0x80, 0x31, 0xC5, 0xD2, 0x5F, ++ 0x34, 0xAE, 0x69, 0x1E, 0xDF, 0x05, 0x6B, 0xBB, 0x41, 0xEB, 0xAB, 0x02, ++ 0xA5, 0x9E, 0xEE, 0xC0, 0xB9, 0xE4, 0x75, 0x45, 0xC2, 0x1C, 0x7A, 0x9B, ++ 0x85, 0x7B, 0xF8, 0x0F, 0xDE, 0x47, 0x67, 0x82, 0x94, 0x5B, 0x3C, 0x9F, ++ 0x8D, 0x4A, 0x1C, 0x5B, 0x1D, 0x19, 0x11, 0x20, 0xC4, 0x90, 0x53, 0x0D, ++ 0x7B, 0xD9, 0x89, 0x42, 0x2D, 0xBF, 0x49, 0xDA, 0x4F, 0x56, 0x66, 0xC0, ++ 0x98, 0x62, 0xE9, 0x2F, 0x1A, 0xD7, 0x34, 0x8F, 0xEF, 0x82, 0xB5, 0xDD, ++ 0xA0, 0xF5, 0x55, 0x81, 0x52, 0x4F, 0x77, 0xE0, 0x5C, 0xF2, 0xBA, 0x22, ++ 0x61, 0x0E, 0xBD, 0xCD, 0xC2, 0x3D, 0xFC, 0x07, 0xEF, 0xA3, 0x33, 0x41, ++ 0xCA, 0x2D, 0x9E, 0xCF, 0x46, 0x25, 0x8E, 0xAD, 0x8E, 0x8C, 0x08, 0x10, ++ 0x62, 0xC8, 0xA9, 0x86, 0xBD, 0xEC, 0x44, 0xA1, 0x96, 0xDF, 0x24, 0xED, ++ 0x27, 0x2B, 0x33, 0x60, 0x4C, 0xB1, 0xF4, 0x17, 0x8D, 0x6B, 0x9A, 0xC7, ++ 0x77, 0xC1, 0xDA, 0x6E, 0xD0, 0xFA, 0xAA, 0x40, 0xA9, 0xA7, 0x3B, 0x70, ++ 0x2E, 0x79, 0x5D, 0x91, 0x30, 0x87, 0xDE, 0x66, 0xE1, 0x1E, 0xFE, 0x83, ++ 0xF7, 0xD1, 0x99, 0x20, 0xE5, 0x16, 0xCF, 0x67, 0xA3, 0x12, 0xC7, 0x56, ++ 0x47, 0x46, 0x04, 0x08, 0x31, 0xE4, 0x54, 0xC3, 0x5E, 0x76, 0xA2, 0x50, ++ 0xCB, 0x6F, 0x92, 0xF6, 0x93, 0x95, 0x19, 0x30, 0xA6, 0x58, 0xFA, 0x8B, ++ 0xC6, 0x35, 0xCD, 0xE3, 0xBB, 0x60, 0x6D, 0x37, 0x68, 0x7D, 0x55, 0xA0, ++ 0xD4, 0xD3, 0x1D, 0x38, 0x97, 0xBC, 0xAE, 0x48, 0x98, 0x43, 0x6F, 0xB3, ++ 0x70, 0x0F, 0xFF, 0xC1, 0xFF, 0xC1, 0xFB, 0xE8, 0x4C, 0x90, 0x72, 0x8B, ++ 0xE7, 0xB3, 0x51, 0x89, 0x63, 0xAB, 0x23, 0x23, 0x02, 0x84, 0x18, 0x72, ++ 0xAA, 0x61, 0x2F, 0x3B, 0x51, 0xA8, 0xE5, 0x37, 0x49, 0xFB, 0xC9, 0xCA, ++ 0x0C, 0x18, 0x53, 0x2C, 0xFD, 0x45, 0xE3, 0x9A, 0xE6, 0xF1, 0x5D, 0xB0, ++ 0xB6, 0x1B, 0xB4, 0xBE, 0x2A, 0x50, 0xEA, 0xE9, 0x0E, 0x9C, 0x4B, 0x5E, ++ 0x57, 0x24, 0xCC, 0xA1, 0xB7, 0x59, 0xB8, 0x87, 0xFF, 0xE0, 0x7D, 0x74, ++ 0x26, 0x48, 0xB9, 0xC5, 0xF3, 0xD9, 0xA8, 0xC4, 0xB1, 0xD5, 0x91, 0x11, ++ 0x01, 0x42, 0x0C, 0x39, 0xD5, 0xB0, 0x97, 0x9D, 0x28, 0xD4, 0xF2, 0x9B, ++ 0xA4, 0xFD, 0x64, 0x65, 0x06, 0x8C, 0x29, 0x96, 0xFE, 0xA2, 0x71, 0x4D, ++ 0xF3, 0xF8, 0x2E, 0x58, 0xDB, 0x0D, 0x5A, 0x5F, 0x15, 0x28, 0xF5, 0x74, ++ 0x07, 0xCE, 0x25, 0xAF, 0x2B, 0x12, 0xE6, 0xD0, 0xDB, 0x2C, 0xDC, 0xC3, ++ 0x7F, 0xF0, 0x3E, 0x3A, 0x13, 0xA4, 0xDC, 0xE2, 0xF9, 0x6C, 0x54, 0xE2, ++ 0xD8, 0xEA, 0xC8, 0x88, 0x00, 0x21, 0x86, 0x9C, 0x6A, 0xD8, 0xCB, 0x4E, ++ 0x14, 0x6A, 0xF9, 0x4D, 0xD2, 0x7E, 0xB2, 0x32, 0x03, 0xC6, 0x14, 0x4B, ++ 0x7F, 0xD1, 0xB8, 0xA6, 0x79, 0x7C, 0x17, 0xAC, 0xED, 0x06, 0xAD, 0xAF, ++ 0x0A, 0x94, 0x7A, 0xBA, 0x03, 0xE7, 0x92, 0xD7, 0x15, 0x09, 0x73, 0xE8, ++ 0x6D, 0x16, 0xEE, 0xE1, 0x3F, 0x78, 0x1F, 0x9D, 0x09, 0x52, 0x6E, 0xF1, ++ 0x7C, 0x36, 0x2A, 0x71, 0x6C, 0x75, 0x64, 0x44, 0x80, 0x10, 0x43, 0x4E, ++ 0x35, 0xEC, 0x65, 0x27, 0x0A, 0xB5, 0xFC, 0x26, 0x69, 0x3F, 0x59, 0x99, ++ 0x01, 0x63, 0x8A, 0xA5, 0xBF, 0x68, 0x5C, 0xD3, 0x3C, 0xBE, 0x0B, 0xD6, ++ 0x76, 0x83, 0xD6, 0x57, 0x05, 0x4A, 0x3D, 0xDD, 0x81, 0x73, 0xC9, 0xEB, ++ 0x8A, 0x84, 0x39, 0xF4, 0x36, 0x0B, 0xF7, 0xF0, 0x1F, 0xBC, 0x8F, 0xCE, ++ 0x04, 0x29, 0xB7, 0x78, 0x3E, 0x1B, 0x95, 0x38, 0xB6, 0x3A, 0x32, 0x22, ++ 0x40, 0x88, 0x21, 0xA7, 0x1A, 0xF6, 0xB2, 0x13, 0x85, 0x5A, 0x7E, 0x93, ++ 0xB4, 0x9F, 0xAC, 0xCC, 0x80, 0x31, 0xC5, 0xD2, 0x5F, 0x34, 0xAE, 0x69, ++ 0x1E, 0xDF, 0x05, 0x6B, 0xBB, 0x41, 0xEB, 0xAB, 0x02, 0xA5, 0x9E, 0xEE, ++ 0xC0, 0xB9, 0xE4, 0x75, 0x45, 0xC2, 0x1C, 0x7A, 0x9B, 0x85, 0x7B, 0xF8, ++ 0x0F, 0xDE, 0x47, 0x67, 0x82, 0x94, 0x5B, 0x3C, 0x9F, 0x8D, 0x4A, 0x1C, ++ 0x5B, 0x1D, 0x19, 0x11, 0x20, 0xC4, 0x90, 0x53, 0x0D, 0x7B, 0xD9, 0x89, ++ 0x42, 0x2D, 0xBF, 0x49, 0xDA, 0x4F, 0x56, 0x66, 0xC0, 0x98, 0x62, 0xE9, ++ 0x2F, 0x1A, 0xD7, 0x34, 0x8F, 0xEF, 0x82, 0xB5, 0xDD, 0xA0, 0xF5, 0x55, ++ 0x81, 0x52, 0x4F, 0x77, 0xE0, 0x5C, 0xF2, 0xBA, 0x22, 0x61, 0x0E, 0xBD, ++ 0xCD, 0xC2, 0x3D, 0xFC, 0x07, 0xEF, 0xA3, 0x33, 0x41, 0xCA, 0x2D, 0x9E, ++ 0xCF, 0x46, 0x25, 0x8E, 0xAD, 0x8E, 0x8C, 0x08, 0x10, 0x62, 0xC8, 0xA9, ++ 0x86, 0xBD, 0xEC, 0x44, 0xA1, 0x96, 0xDF, 0x24, 0xED, 0x27, 0x2B, 0x33, ++ 0x60, 0x4C, 0xB1, 0xF4, 0x17, 0x8D, 0x6B, 0x9A, 0xC7, 0x77, 0xC1, 0xDA, ++ 0x6E, 0xD0, 0xFA, 0xAA, 0x40, 0xA9, 0xA7, 0x3B, 0x70, 0x2E, 0x79, 0x5D, ++ 0x91, 0x30, 0x87, 0xDE, 0x66, 0xE1, 0x1E, 0xFE, 0x83, 0xF7, 0xD1, 0x99, ++ 0x20, 0xE5, 0x16, 0xCF, 0x67, 0xA3, 0x12, 0xC7, 0x56, 0x47, 0x46, 0x04, ++ 0x08, 0x31, 0xE4, 0x54, 0xC3, 0x5E, 0x76, 0xA2, 0x50, 0xCB, 0x6F, 0x92, ++ 0xF6, 0x93, 0x95, 0x19, 0x30, 0xA6, 0x58, 0xFA, 0x8B, 0xC6, 0x35, 0xCD, ++ 0xE3, 0xBB, 0x60, 0x6D, 0x37, 0x68, 0x7D, 0x55, 0xA0, 0xD4, 0xD3, 0x1D, ++ 0x38, 0x97, 0xBC, 0xAE, 0x48, 0x98, 0x43, 0x6F, 0xB3, 0x70, 0x0F, 0xFF, ++ 0xC1, 0xFB, 0xE8, 0x4C, 0x90, 0x72, 0x8B, 0xE7, 0xB3, 0x51, 0x89, 0x63, ++ 0xAB, 0x23, 0x23, 0x02, 0x84, 0x18, 0x72, 0xAA, 0x61, 0x2F, 0x3B, 0x51, ++ 0xA8, 0xE5, 0x37, 0x49, 0xFB, 0xC9, 0xCA, 0x0C, 0x18, 0x53, 0x2C, 0xFD, ++ 0x45, 0xE3, 0x9A, 0xE6, 0xF1, 0x5D, 0xB0, 0xB6, 0x1B, 0xB4, 0xBE, 0x2A, ++ 0x50, 0xEA, 0xE9, 0x0E, 0x9C, 0x4B, 0x5E, 0x57, 0x24, 0xCC, 0xA1, 0xB7, ++ 0x59, 0xB8, 0x87, 0xFF, 0xE0, 0x7D, 0x74, 0x26, 0x48, 0xB9, 0xC5, 0xF3, ++ 0xD9, 0xA8, 0xC4, 0xB1, 0xD5, 0x91, 0x11, 0x01, 0x42, 0x0C, 0x39, 0xD5, ++ 0xB0, 0x97, 0x9D, 0x28, 0xD4, 0xF2, 0x9B, 0xA4, 0xFD, 0x64, 0x65, 0x06, ++ 0x8C, 0x29, 0x96, 0xFE, 0xA2, 0x71, 0x4D, 0xF3, 0xF8, 0x2E, 0x58, 0xDB, ++ 0x0D, 0x5A, 0x5F, 0x15, 0x28, 0xF5, 0x74, 0x07, 0xCE, 0x25, 0xAF, 0x2B, ++ 0x12, 0xE6, 0xD0, 0xDB, 0x2C, 0xDC, 0xC3, 0x7F, 0xF0, 0x3E, 0x3A, 0x13, ++ 0xA4, 0xDC, 0xE2, 0xF9, 0x6C, 0x54, 0xE2, 0xD8, 0xEA, 0xC8, 0x88, 0x00, ++ 0x21, 0x86, 0x9C, 0x6A, 0xD8, 0xCB, 0x4E, 0x14, 0x6A, 0xF9, 0x4D, 0xD2, ++ 0x7E, 0xB2, 0x32, 0x03, 0xC6, 0x14, 0x4B, 0x7F, 0xD1, 0xB8, 0xA6, 0x79, ++ 0x7C, 0x17, 0xAC, 0xED, 0x06, 0xAD, 0xAF, 0x0A, 0x94, 0x7A, 0xBA, 0x03, ++ 0xE7, 0x92, 0xD7, 0x15, 0x09, 0x73, 0xE8, 0x6D, 0x16, 0xEE, 0xE1, 0x3F, ++ 0x78, 0x1F, 0x9D, 0x09, 0x52, 0x6E, 0xF1, 0x7C, 0x36, 0x2A, 0x71, 0x6C, ++ 0x75, 0x64, 0x44, 0x80, 0x10, 0x43, 0x4E, 0x35, 0xEC, 0x65, 0x27, 0x0A, ++ 0xB5, 0xFC, 0x26, 0x69, 0x3F, 0x59, 0x99, 0x01, 0x63, 0x8A, 0xA5, 0xBF, ++ 0x68, 0x5C, 0xD3, 0x3C, 0xBE, 0x0B, 0xD6, 0x76, 0x83, 0xD6, 0x57, 0x05, ++ 0x4A, 0x3D, 0xDD, 0x81, 0x73, 0xC9, 0xEB, 0x8A, 0x84, 0x39, 0xF4, 0x36, ++ 0x0B, 0xF7, 0xF0, 0x1F, 0xBC, 0x8F, 0xCE, 0x04, 0x29, 0xB7, 0x78, 0x3E, ++ 0x1B, 0x95, 0x38, 0xB6, 0x3A, 0x32, 0x22, 0x40, 0x88, 0x21, 0xA7, 0x1A, ++ 0xF6, 0xB2, 0x13, 0x85, 0x5A, 0x7E, 0x93, 0xB4, 0x9F, 0xAC, 0xCC, 0x80, ++ 0x31, 0xC5, 0xD2, 0x5F, 0x34, 0xAE, 0x69, 0x1E, 0xDF, 0x05, 0x6B, 0xBB, ++ 0x41, 0xEB, 0xAB, 0x02, 0xA5, 0x9E, 0xEE, 0xC0, 0xB9, 0xE4, 0x75, 0x45, ++ 0xC2, 0x1C, 0x7A, 0x9B, 0x85, 0x7B, 0xF8, 0x0F, 0xDE, 0x47, 0x67, 0x82, ++ 0x94, 0x5B, 0x3C, 0x9F, 0x8D, 0x4A, 0x1C, 0x5B, 0x1D, 0x19, 0x11, 0x20, ++ 0xC4, 0x90, 0x53, 0x0D, 0x7B, 0xD9, 0x89, 0x42, 0x2D, 0xBF, 0x49, 0xDA, ++ 0x4F, 0x56, 0x66, 0xC0, 0x98, 0x62, 0xE9, 0x2F, 0x1A, 0xD7, 0x34, 0x8F, ++ 0xEF, 0x82, 0xB5, 0xDD, 0xA0, 0xF5, 0x55, 0x81, 0x52, 0x4F, 0x77, 0xE0, ++ 0x5C, 0xF2, 0xBA, 0x22, 0x61, 0x0E, 0xBD, 0xCD, 0xC2, 0x3D, 0xFC, 0x07, ++ 0xEF, 0xA3, 0x33, 0x41, 0xCA, 0x2D, 0x9E, 0xCF, 0x46, 0x25, 0x8E, 0xAD, ++ 0x8E, 0x8C, 0x08, 0x10, 0x62, 0xC8, 0xA9, 0x86, 0xBD, 0xEC, 0x44, 0xA1, ++ 0x96, 0xDF, 0x24, 0xED, 0x27, 0x2B, 0x33, 0x60, 0x4C, 0xB1, 0xF4, 0x17, ++ 0x8D, 0x6B, 0x9A, 0xC7, 0x77, 0xC1, 0xDA, 0x6E, 0xD0, 0xFA, 0xAA, 0x40, ++ 0xA9, 0xA7, 0x3B, 0x70, 0x2E, 0x79, 0x5D, 0x91, 0x30, 0x87, 0xDE, 0x66, ++ 0xE1, 0x1E, 0xFE, 0x83, 0xF7, 0xD1, 0x99, 0x20, 0xE5, 0x16, 0xCF, 0x67, ++ 0xA3, 0x12, 0xC7, 0x56, 0x47, 0x46, 0x04, 0x08, 0x31, 0xE4, 0x54, 0xC3, ++ 0x5E, 0x76, 0xA2, 0x50, 0xCB, 0x6F, 0x92, 0xF6, 0x93, 0x95, 0x19, 0x30, ++ 0xA6, 0x58, 0xFA, 0x8B, 0xC6, 0x35, 0xCD, 0xE3, 0xBB, 0x60, 0x6D, 0x37, ++ 0x68, 0x7D, 0x55, 0xA0, 0xD4, 0xD3, 0x1D, 0x38, 0x97, 0xBC, 0xAE, 0x48, ++ 0x98, 0x43, 0x6F, 0xB3, 0x70, 0x0F, 0xFF, 0xC1, 0x00, 0x01, 0x01, 0x02, ++ 0x01, 0x02, 0x02, 0x03, 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, ++ 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, 0x02, 0x03, 0x03, 0x04, ++ 0x03, 0x04, 0x04, 0x05, 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, ++ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, 0x02, 0x03, 0x03, 0x04, ++ 0x03, 0x04, 0x04, 0x05, 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, ++ 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, 0x02, 0x03, 0x03, 0x04, ++ 0x03, 0x04, 0x04, 0x05, 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, ++ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, 0x02, 0x03, 0x03, 0x04, ++ 0x03, 0x04, 0x04, 0x05, 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, ++ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, 0x04, 0x05, 0x05, 0x06, ++ 0x05, 0x06, 0x06, 0x07, 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, ++ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, 0x02, 0x03, 0x03, 0x04, ++ 0x03, 0x04, 0x04, 0x05, 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, ++ 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, 0x03, 0x04, 0x04, 0x05, ++ 0x04, 0x05, 0x05, 0x06, 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, ++ 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, 0x02, 0x03, 0x03, 0x04, ++ 0x03, 0x04, 0x04, 0x05, 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, ++ 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, 0x04, 0x05, 0x05, 0x06, ++ 0x05, 0x06, 0x06, 0x07, 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, ++ 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, 0x04, 0x05, 0x05, 0x06, ++ 0x05, 0x06, 0x06, 0x07, 0x05, 0x06, 0x06, 0x07, 0x06, 0x07, 0x07, 0x08, ++ 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x00, 0x00, 0x01, 0x50, ++ 0x00, 0x03, 0x04, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x50, ++ 0x00, 0x02, 0x07, 0x03, 0x0C, 0x04, 0x0D, 0x05, 0x26, 0x06, 0x37, 0x07, ++ 0x2C, 0x08, 0x3D, 0x09, 0x00, 0x00, 0x02, 0x01, 0x05, 0x00, 0x01, 0x07, ++ 0x00, 0x01, 0x00, 0x00, 0x01, 0x07, 0x00, 0x01, 0x0C, 0x00, 0x03, 0x0D, ++ 0x00, 0x03, 0x06, 0x01, 0x01, 0x07, 0x01, 0x01, 0x0C, 0x01, 0x03, 0x0D, ++ 0x01, 0x03, 0x00, 0x00, 0x00, 0x27, 0x35, 0x00, 0x2B, 0x00, 0x31, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x22, 0x10, 0x00, ++ 0xFF, 0xF0, 0xAA, 0xFF, 0xFF, 0x00, 0x0F, 0x55, 0x80, 0x01, 0x00, 0x00, ++ 0xF6, 0xFC, 0xFE, 0x00, 0x03, 0x06, 0x09, 0x0A, 0xF9, 0xFC, 0xFF, 0x02, ++ 0x05, 0x07, 0x09, 0x0C, 0x0F, 0x11, 0x15, 0x17, 0x50, 0x00, 0x00, 0x00, ++ 0xE4, 0x57, 0x00, 0x00, 0x50, 0xC3, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, ++ 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, ++ 0x24, 0x10, 0x04, 0x00, 0x0C, 0x21, 0x04, 0x25, 0x00, 0x80, 0xDE, 0xA9, ++ 0x91, 0x06, 0x7B, 0x00, 0x04, 0x10, 0x04, 0x00, 0x04, 0x00, 0x00, 0x26, ++ 0x00, 0x80, 0xDE, 0xA9, 0x65, 0x06, 0x7C, 0x00, 0x04, 0xF0, 0x03, 0x00, ++ 0x3C, 0xE7, 0x1C, 0x24, 0x09, 0x80, 0xDE, 0xA9, 0x69, 0x06, 0x7C, 0x48, ++ 0x04, 0x10, 0x04, 0x00, 0xF8, 0xFF, 0x7F, 0x24, 0x17, 0x42, 0x40, 0x40, ++ 0x8D, 0x08, 0x7B, 0xB0, 0x14, 0x10, 0x04, 0x00, 0x0C, 0x21, 0x84, 0x27, ++ 0x00, 0x80, 0xDE, 0xA9, 0x91, 0x46, 0x7B, 0x03, 0x04, 0x10, 0x04, 0x00, ++ 0x0C, 0x21, 0x04, 0x26, 0x00, 0x80, 0xDE, 0xA9, 0x81, 0x06, 0x7B, 0x03, ++ 0x04, 0xF0, 0x03, 0x00, 0x3C, 0xE7, 0x1C, 0x24, 0x09, 0x80, 0xDE, 0xA9, ++ 0x69, 0x06, 0x7C, 0x4B, 0x04, 0x10, 0x04, 0x00, 0xF8, 0xFF, 0xFF, 0x27, ++ 0x17, 0x42, 0x40, 0x40, 0xFD, 0x08, 0x7A, 0xB0, 0x14, 0x10, 0x04, 0x00, ++ 0x0C, 0x21, 0x84, 0x27, 0x00, 0x80, 0xDE, 0xA9, 0x91, 0x46, 0x7B, 0x03, ++ 0x04, 0x10, 0x04, 0x00, 0x0C, 0x21, 0x04, 0x26, 0x00, 0x80, 0xDE, 0xA9, ++ 0x81, 0x06, 0x7B, 0x03, 0x04, 0xF0, 0x03, 0x00, 0x3C, 0xE7, 0x1C, 0x24, ++ 0x09, 0x80, 0xDE, 0xA9, 0x69, 0x06, 0x7C, 0x4B, 0x04, 0x10, 0x04, 0x00, ++ 0xF8, 0xFF, 0xFF, 0x27, 0x17, 0x42, 0x40, 0x40, 0xFD, 0x08, 0x7A, 0xB0, ++ 0x14, 0x10, 0x04, 0x00, 0x0C, 0x21, 0x84, 0x27, 0x00, 0x80, 0xDE, 0xA9, ++ 0x91, 0x46, 0x7B, 0x03, 0x04, 0x10, 0x04, 0x00, 0x0C, 0x21, 0x04, 0x26, ++ 0x00, 0x80, 0xDE, 0xA9, 0x81, 0x06, 0x7B, 0x03, 0x04, 0xF0, 0x03, 0x00, ++ 0x3C, 0xE7, 0x1C, 0x24, 0x09, 0x80, 0xDE, 0xA9, 0x69, 0x06, 0x7C, 0x4B, ++ 0x04, 0x10, 0x04, 0x00, 0xF8, 0xFF, 0xFF, 0x27, 0x17, 0x42, 0x40, 0x40, ++ 0xFD, 0x08, 0x7A, 0xB0, 0xD0, 0x9E, 0x21, 0x00, 0x1C, 0x1C, 0xFB, 0x41, ++ 0xD4, 0x9E, 0x21, 0x00, 0x1C, 0x1C, 0xFB, 0x41, 0xD4, 0x9E, 0x21, 0x00, ++ 0x70, 0x70, 0xFB, 0x41, 0xD4, 0x9E, 0x21, 0x00, 0x70, 0x70, 0xFB, 0x61, ++ 0xD6, 0x9E, 0x21, 0x00, 0x70, 0x70, 0xFB, 0x65, 0xD7, 0x9E, 0x21, 0x00, ++ 0x70, 0x70, 0xFB, 0x75, 0xD7, 0x9E, 0x21, 0x00, 0x70, 0x70, 0xFB, 0xFD, ++ 0xD7, 0x9E, 0x21, 0x00, 0xF0, 0xF0, 0xFB, 0xFD, 0xD7, 0x9D, 0x21, 0x00, ++ 0xF0, 0xF0, 0x87, 0xFD, 0xD7, 0x9D, 0x21, 0x00, 0xF0, 0xF0, 0x87, 0xFD, ++ 0xD7, 0x9D, 0x21, 0x00, 0xF0, 0xF0, 0x87, 0xFD, 0xD7, 0x9D, 0x21, 0x00, ++ 0xF0, 0xF0, 0x87, 0xFD, 0xD7, 0x9D, 0x21, 0x00, 0xF0, 0xF0, 0x87, 0xFD, ++ 0xD7, 0x9D, 0x21, 0x00, 0xF0, 0xF0, 0x87, 0xFD, 0xD7, 0x9D, 0x21, 0x00, ++ 0xF0, 0xF0, 0x87, 0xFD, 0xD7, 0x9D, 0x21, 0x00, 0xF0, 0xF0, 0x87, 0xFD, ++ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0B, 0x00, ++ 0x00, 0x04, 0x00, 0x00, 0xB8, 0x0B, 0x00, 0x00, 0xFF, 0xF9, 0x01, 0x08, ++ 0x00, 0x00, 0x00, 0x00, 0xAC, 0x2B, 0x16, 0x00, 0x04, 0x00, 0x00, 0x00, ++ 0x28, 0x21, 0x16, 0x00, 0xA8, 0x61, 0x00, 0x00, 0xB8, 0x88, 0x00, 0x00, ++ 0x74, 0x40, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, ++ 0x30, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x22, 0x3E, 0x55, 0x00, ++ 0x6C, 0x00, 0x0F, 0x1B, 0x60, 0x07, 0xED, 0x79, 0x80, 0x80, 0x80, 0x80, ++ 0x34, 0x3E, 0x55, 0x00, 0x6C, 0x00, 0x0F, 0x5B, 0x60, 0x07, 0xCD, 0x79, ++ 0x80, 0x80, 0x80, 0x80, 0x34, 0x3E, 0x55, 0x00, 0x6C, 0x00, 0x0F, 0x5B, ++ 0x60, 0x07, 0xAD, 0x79, 0x80, 0x80, 0x80, 0x80, 0x34, 0x3E, 0x55, 0x00, ++ 0x6C, 0x00, 0x0F, 0x5B, 0x60, 0x07, 0x8D, 0x79, 0x80, 0x80, 0x80, 0x80, ++ 0x34, 0x3E, 0x55, 0x00, 0x6C, 0x00, 0x0F, 0x5B, 0x60, 0x07, 0x0D, 0x79, ++ 0x80, 0x80, 0x80, 0x80, 0x34, 0x3E, 0x55, 0x00, 0x6C, 0x00, 0x0F, 0x5B, ++ 0x60, 0x07, 0x8D, 0x78, 0x80, 0x80, 0x80, 0x80, 0x6B, 0x3E, 0x55, 0x00, ++ 0x6C, 0x00, 0x0F, 0x1B, 0x60, 0x07, 0x8D, 0x78, 0x80, 0x80, 0x80, 0x80, ++ 0x58, 0x3E, 0x55, 0x00, 0x6C, 0x00, 0x0F, 0xDB, 0x60, 0x07, 0x0D, 0x78, ++ 0x80, 0x80, 0x80, 0x80, 0x22, 0x3E, 0x55, 0x00, 0x6C, 0x00, 0x0F, 0x1B, ++ 0x60, 0xD7, 0x0C, 0x78, 0x80, 0x80, 0x80, 0x80, 0x22, 0x3E, 0x55, 0x00, ++ 0x6C, 0x00, 0x0F, 0x1B, 0x60, 0x1F, 0x0D, 0x78, 0x80, 0x80, 0x80, 0x80, ++ 0x22, 0x3E, 0x55, 0x00, 0x6D, 0x0C, 0x2F, 0x1B, 0x60, 0x1F, 0x0D, 0x78, ++ 0x80, 0x80, 0x80, 0x80, 0x58, 0x3E, 0x55, 0x00, 0x6D, 0x0C, 0x2F, 0xDB, ++ 0x60, 0x1F, 0x0D, 0x78, 0x80, 0x80, 0x80, 0x80, 0xD8, 0x3E, 0x55, 0x00, ++ 0x6D, 0x0C, 0x2F, 0xDB, 0x60, 0x1F, 0x0D, 0x78, 0x80, 0x80, 0x80, 0x80, ++ 0xEB, 0x3E, 0x55, 0x00, 0x6D, 0x0C, 0x2F, 0x1B, 0x60, 0x9F, 0x0D, 0x68, ++ 0x80, 0x80, 0x80, 0x80, 0x6B, 0x3F, 0x55, 0x00, 0x6D, 0x0C, 0x2F, 0x1B, ++ 0x60, 0x9F, 0x0D, 0x68, 0x80, 0x80, 0x80, 0x80, 0xEB, 0x3F, 0x55, 0x00, ++ 0x6D, 0x0C, 0x2F, 0x1B, 0x60, 0x9F, 0x0D, 0x68, 0x80, 0x80, 0x80, 0x80, ++ 0x22, 0x3E, 0x55, 0x00, 0x6C, 0x00, 0x0F, 0x1B, 0x60, 0x07, 0xED, 0x79, ++ 0x80, 0x80, 0x80, 0x80, 0x34, 0x3E, 0x55, 0x00, 0x6C, 0x00, 0x0F, 0x5B, ++ 0x60, 0x07, 0xCD, 0x79, 0x80, 0x80, 0x80, 0x80, 0x34, 0x3E, 0x55, 0x00, ++ 0x6C, 0x00, 0x0F, 0x5B, 0x60, 0x07, 0xAD, 0x79, 0x80, 0x80, 0x80, 0x80, ++ 0x34, 0x3E, 0x55, 0x00, 0x6C, 0x00, 0x0F, 0x5B, 0x60, 0x07, 0x8D, 0x79, ++ 0x80, 0x80, 0x80, 0x80, 0x34, 0x3E, 0x55, 0x00, 0x6C, 0x00, 0x0F, 0x5B, ++ 0x60, 0x07, 0x0D, 0x79, 0x80, 0x80, 0x80, 0x80, 0x34, 0x3E, 0x55, 0x00, ++ 0x6C, 0x00, 0x0F, 0x5B, 0x60, 0x07, 0x8D, 0x78, 0x80, 0x80, 0x80, 0x80, ++ 0x6B, 0x3E, 0x55, 0x00, 0x6C, 0x00, 0x0F, 0x1B, 0x60, 0x07, 0x8D, 0x78, ++ 0x80, 0x80, 0x80, 0x80, 0x58, 0x3E, 0x55, 0x00, 0x6C, 0x00, 0x0F, 0xDB, ++ 0x60, 0x07, 0x0D, 0x78, 0x80, 0x80, 0x80, 0x80, 0x22, 0x3E, 0x55, 0x00, ++ 0x6C, 0x00, 0x0F, 0x1B, 0x60, 0xD7, 0x0C, 0x78, 0x80, 0x80, 0x80, 0x80, ++ 0x22, 0x3E, 0x55, 0x00, 0x6C, 0x00, 0x0F, 0x1B, 0x60, 0x1F, 0x0D, 0x78, ++ 0x80, 0x80, 0x80, 0x80, 0x22, 0x3E, 0x55, 0x00, 0x6D, 0x0C, 0x2F, 0x1B, ++ 0x60, 0x1F, 0x0D, 0x78, 0x80, 0x80, 0x80, 0x80, 0x58, 0x3E, 0x55, 0x00, ++ 0x6D, 0x0C, 0x2F, 0xDB, 0x60, 0x1F, 0x0D, 0x78, 0x80, 0x80, 0x80, 0x80, ++ 0xD8, 0x3E, 0x55, 0x00, 0x6D, 0x0C, 0x2F, 0xDB, 0x60, 0x1F, 0x0D, 0x78, ++ 0x80, 0x80, 0x80, 0x80, 0xEB, 0x3E, 0x55, 0x00, 0x6D, 0x0C, 0x2F, 0x1B, ++ 0x60, 0x9F, 0x0D, 0x68, 0x80, 0x80, 0x80, 0x80, 0x6B, 0x3F, 0x55, 0x00, ++ 0x6D, 0x0C, 0x2F, 0x1B, 0x60, 0x9F, 0x0D, 0x68, 0x80, 0x80, 0x80, 0x80, ++ 0xEB, 0x3F, 0x55, 0x00, 0x6D, 0x0C, 0x2F, 0x1B, 0x60, 0x9F, 0x0D, 0x68, ++ 0x80, 0x80, 0x80, 0x80, 0x00, 0x94, 0x7F, 0x00, 0x6C, 0x00, 0x00, 0x03, ++ 0x60, 0x07, 0xAC, 0xE9, 0x80, 0x80, 0x80, 0x80, 0x00, 0x94, 0x7F, 0x00, ++ 0x6C, 0x00, 0x00, 0x03, 0x60, 0x07, 0x0C, 0xE8, 0x80, 0x80, 0x80, 0x80, ++ 0x00, 0x94, 0x7F, 0x00, 0x6C, 0x00, 0x20, 0x03, 0x60, 0xD7, 0x0C, 0xE8, ++ 0x80, 0x80, 0x80, 0x80, 0x00, 0x94, 0x7F, 0x00, 0x6C, 0x00, 0xE0, 0x03, ++ 0x60, 0x9F, 0x0D, 0xE8, 0x80, 0x80, 0x80, 0x80, 0x00, 0xBE, 0x7F, 0x00, ++ 0x6C, 0x00, 0x0F, 0x1B, 0x60, 0xE7, 0x8C, 0x69, 0x80, 0x80, 0x80, 0x80, ++ 0x00, 0x3E, 0x55, 0x00, 0xFC, 0x00, 0x6F, 0x1B, 0x60, 0x1F, 0x0D, 0x78, ++ 0x80, 0x80, 0x80, 0x80, 0x12, 0x3E, 0x55, 0x00, 0xFC, 0x00, 0xEF, 0x5B, ++ 0x60, 0x1F, 0x0D, 0x78, 0x80, 0x80, 0x80, 0x80, 0x6D, 0x3E, 0x55, 0x00, ++ 0xFC, 0x00, 0xEF, 0x9B, 0x60, 0x9F, 0x0D, 0x68, 0x80, 0x80, 0x80, 0x80, ++ 0x00, 0x3E, 0x55, 0x00, 0xFC, 0x00, 0x2F, 0x1B, 0x60, 0x87, 0xEC, 0x79, ++ 0x80, 0x80, 0x80, 0x80, 0x00, 0x3E, 0x55, 0x00, 0xFC, 0x00, 0x6F, 0x1B, ++ 0x60, 0x87, 0xEC, 0x79, 0x80, 0x80, 0x80, 0x80, 0x00, 0x3E, 0x55, 0x00, ++ 0xFC, 0x00, 0x6F, 0x1B, 0x60, 0x07, 0xAD, 0x79, 0x80, 0x80, 0x80, 0x80, ++ 0x00, 0x3E, 0x55, 0x00, 0xFC, 0x00, 0x6F, 0x1B, 0x60, 0x07, 0x0D, 0x79, ++ 0x80, 0x80, 0x80, 0x80, 0x00, 0x3E, 0x55, 0x00, 0xFC, 0x00, 0x6F, 0x1B, ++ 0x60, 0x07, 0x0D, 0x78, 0x80, 0x80, 0x80, 0x80, 0x00, 0x3E, 0x55, 0x00, ++ 0xFC, 0x00, 0x6F, 0x1B, 0x60, 0x17, 0x0D, 0x78, 0x80, 0x80, 0x80, 0x80, ++ 0x12, 0x3E, 0x55, 0x00, 0xFC, 0x00, 0xEF, 0x5B, 0x60, 0x1F, 0x0D, 0x78, ++ 0x80, 0x80, 0x80, 0x80, 0x6D, 0x3E, 0x55, 0x00, 0xFC, 0x00, 0xEF, 0x9B, ++ 0x60, 0x9F, 0x0D, 0x68, 0x03, 0xC7, 0x8E, 0x00, 0x07, 0xC7, 0x8E, 0x00, ++ 0x0B, 0xC7, 0x8E, 0x00, 0x0F, 0xC7, 0x8E, 0x00, 0x13, 0xC7, 0x8E, 0x00, ++ 0x17, 0xC7, 0x8E, 0x00, 0x1B, 0xC7, 0x8E, 0x00, 0x1F, 0xC7, 0x8E, 0x00, ++ 0x23, 0xC7, 0x8E, 0x00, 0x27, 0xC7, 0x8E, 0x00, 0x2B, 0xC7, 0x8E, 0x00, ++ 0x2F, 0xC7, 0x8E, 0x00, 0x33, 0xC7, 0x8E, 0x00, 0x37, 0xC7, 0x8E, 0x00, ++ 0x3B, 0xC7, 0x8E, 0x00, 0x3F, 0xC7, 0x8E, 0x00, 0x06, 0x81, 0x88, 0x00, ++ 0x0A, 0x81, 0x88, 0x00, 0x0C, 0xC1, 0x88, 0x00, 0x14, 0xC1, 0x90, 0x00, ++ 0x14, 0x41, 0x91, 0x00, 0x15, 0xC1, 0x91, 0x00, 0x23, 0xC1, 0x91, 0x00, ++ 0x3F, 0xC1, 0x91, 0x00, 0x3F, 0xC1, 0x92, 0x00, 0x3F, 0x01, 0x94, 0x00, ++ 0x3F, 0xC1, 0x96, 0x00, 0x3F, 0xC1, 0x96, 0x00, 0x3F, 0xC1, 0x96, 0x00, ++ 0x3F, 0xC1, 0x96, 0x00, 0x3F, 0xC1, 0x96, 0x00, 0x3F, 0xC1, 0x96, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x2D, 0x20, 0x53, 0x65, 0x70, 0x20, 0x31, 0x33, 0x20, 0x32, 0x30, 0x32, ++ 0x32, 0x20, 0x31, 0x30, 0x3A, 0x33, 0x38, 0x3A, 0x33, 0x39, 0x20, 0x2D, ++ 0x20, 0x67, 0x69, 0x74, 0x20, 0x30, 0x61, 0x61, 0x62, 0x66, 0x62, 0x66, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, ++}; ++ ++struct firmware_info { ++ char fw_name[30]; ++ char *fw_array; ++ int fw_size; ++}; ++ ++struct firmware_info firmware[] = { ++ { "fmacfw.bin", fmacfw, sizeof(fmacfw) }, ++ { "fw_adid_u03.bin", fw_adid_u03, sizeof(fw_adid_u03) }, ++ { "fw_patch_table_u03.bin", fw_patch_table_u03, ++ sizeof(fw_patch_table_u03) }, ++ { "fw_patch_u03.bin", fw_patch_u03, sizeof(fw_patch_u03) } ++}; ++ ++int aicwf_get_firmware_array(char *fw_name, u32 **fw_buf) ++{ ++ int firmware_number = 0; ++ int index = 0; ++ int fw_size = 0; ++ ++ firmware_number = sizeof(firmware) / sizeof(struct firmware_info); ++ printk("%s search:%s \r\n", __func__, fw_name); ++ ++ for (index = 0; index < firmware_number; index++) { ++ if (!strcmp(firmware[index].fw_name, fw_name)) { ++ fw_size = firmware[index].fw_size; ++ printk("%s find %s len:%d\r\n", __func__, fw_name, ++ fw_size); ++ *fw_buf = (u32 *)firmware[index].fw_array; ++ return fw_size; ++ } ++ } ++ ++ printk("%s %s not found \r\n", __func__, fw_name); ++ ++ return 0; ++} +\ No newline at end of file +diff --git a/drivers/net/wireless/aic8800/aic8800_bsp/aicwf_firmware_array.h b/drivers/net/wireless/aic8800/aic8800_bsp/aicwf_firmware_array.h +new file mode 100755 +index 000000000..d2ef82aea +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_bsp/aicwf_firmware_array.h +@@ -0,0 +1 @@ ++int aicwf_get_firmware_array(char *fw_name, u32 **fw_buf); +diff --git a/drivers/net/wireless/aic8800/aic8800_bsp/aicwf_txq_prealloc.c b/drivers/net/wireless/aic8800/aic8800_bsp/aicwf_txq_prealloc.c +new file mode 100755 +index 000000000..ffd27b3df +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_bsp/aicwf_txq_prealloc.c +@@ -0,0 +1,59 @@ ++#include ++#include "aicsdio_txrxif.h" ++#include "aic_bsp_driver.h" ++ ++struct prealloc_txq { ++ int prealloced; ++ void *txq; ++ size_t size; ++}; ++ ++struct prealloc_txq prealloc_txq; ++#define MAX_TXQ_SIZE 100 * 1024 ++ ++void *aicwf_prealloc_txq_alloc(size_t size) ++{ ++ BUG_ON(size > MAX_TXQ_SIZE); ++ ++ //check prealloc_txq.size ++ if ((int)prealloc_txq.size != (int)size) { ++ AICWFDBG(LOGINFO, "%s size is diff will to be kzalloc \r\n", ++ __func__); ++ ++ if (prealloc_txq.txq != NULL) { ++ AICWFDBG(LOGINFO, "%s txq to kfree \r\n", __func__); ++ kfree(prealloc_txq.txq); ++ prealloc_txq.txq = NULL; ++ } ++ ++ prealloc_txq.size = size; ++ prealloc_txq.prealloced = 0; ++ } ++ ++ //check prealloc or not ++ if (!prealloc_txq.prealloced) { ++ prealloc_txq.txq = kzalloc(size, GFP_KERNEL); ++ if (!prealloc_txq.txq) { ++ AICWFDBG(LOGERROR, "%s txq kzalloc fail \r\n", ++ __func__); ++ } else { ++ AICWFDBG(LOGINFO, "%s txq kzalloc successful \r\n", ++ __func__); ++ prealloc_txq.prealloced = 1; ++ } ++ } else { ++ AICWFDBG(LOGINFO, "%s txq not need to kzalloc \r\n", __func__); ++ } ++ ++ return prealloc_txq.txq; ++} ++void aicwf_prealloc_txq_free(void) ++{ ++ if (prealloc_txq.txq != NULL) { ++ AICWFDBG(LOGINFO, "%s txq to kfree \r\n", __func__); ++ kfree(prealloc_txq.txq); ++ prealloc_txq.txq = NULL; ++ } ++} ++ ++EXPORT_SYMBOL(aicwf_prealloc_txq_alloc); +diff --git a/drivers/net/wireless/aic8800/aic8800_bsp/aicwf_txq_prealloc.h b/drivers/net/wireless/aic8800/aic8800_bsp/aicwf_txq_prealloc.h +new file mode 100755 +index 000000000..9b5addaba +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_bsp/aicwf_txq_prealloc.h +@@ -0,0 +1,3 @@ ++ ++ ++void aicwf_prealloc_txq_free(void); +diff --git a/drivers/net/wireless/aic8800/aic8800_bsp/md5.c b/drivers/net/wireless/aic8800/aic8800_bsp/md5.c +new file mode 100755 +index 000000000..f21eba9a3 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_bsp/md5.c +@@ -0,0 +1,154 @@ ++#include ++#include "md5.h" ++ ++unsigned char PADDING[] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; ++ ++void MD5Init(MD5_CTX *context) ++{ ++ context->count[0] = 0; ++ context->count[1] = 0; ++ context->state[0] = 0x67452301; ++ context->state[1] = 0xEFCDAB89; ++ context->state[2] = 0x98BADCFE; ++ context->state[3] = 0x10325476; ++} ++void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int inputlen) ++{ ++ unsigned int i = 0, index = 0, partlen = 0; ++ index = (context->count[0] >> 3) & 0x3F; ++ partlen = 64 - index; ++ context->count[0] += inputlen << 3; ++ if (context->count[0] < (inputlen << 3)) ++ context->count[1]++; ++ context->count[1] += inputlen >> 29; ++ ++ if (inputlen >= partlen) { ++ memcpy(&context->buffer[index], input, partlen); ++ MD5Transform(context->state, context->buffer); ++ for (i = partlen; i + 64 <= inputlen; i += 64) ++ MD5Transform(context->state, &input[i]); ++ index = 0; ++ } else { ++ i = 0; ++ } ++ memcpy(&context->buffer[index], &input[i], inputlen - i); ++} ++void MD5Final(MD5_CTX *context, unsigned char digest[16]) ++{ ++ unsigned int index = 0, padlen = 0; ++ unsigned char bits[8]; ++ index = (context->count[0] >> 3) & 0x3F; ++ padlen = (index < 56) ? (56 - index) : (120 - index); ++ MD5Encode(bits, context->count, 8); ++ MD5Update(context, PADDING, padlen); ++ MD5Update(context, bits, 8); ++ MD5Encode(digest, context->state, 16); ++} ++void MD5Encode(unsigned char *output, unsigned int *input, unsigned int len) ++{ ++ unsigned int i = 0, j = 0; ++ while (j < len) { ++ output[j] = input[i] & 0xFF; ++ output[j + 1] = (input[i] >> 8) & 0xFF; ++ output[j + 2] = (input[i] >> 16) & 0xFF; ++ output[j + 3] = (input[i] >> 24) & 0xFF; ++ i++; ++ j += 4; ++ } ++} ++void MD5Decode(unsigned int *output, unsigned char *input, unsigned int len) ++{ ++ unsigned int i = 0, j = 0; ++ while (j < len) { ++ output[i] = (input[j]) | (input[j + 1] << 8) | ++ (input[j + 2] << 16) | (input[j + 3] << 24); ++ i++; ++ j += 4; ++ } ++} ++void MD5Transform(unsigned int state[4], unsigned char block[64]) ++{ ++ unsigned int a = state[0]; ++ unsigned int b = state[1]; ++ unsigned int c = state[2]; ++ unsigned int d = state[3]; ++ unsigned int x[64]; ++ MD5Decode(x, block, 64); ++ FF(a, b, c, d, x[0], 7, 0xd76aa478); /* 1 */ ++ FF(d, a, b, c, x[1], 12, 0xe8c7b756); /* 2 */ ++ FF(c, d, a, b, x[2], 17, 0x242070db); /* 3 */ ++ FF(b, c, d, a, x[3], 22, 0xc1bdceee); /* 4 */ ++ FF(a, b, c, d, x[4], 7, 0xf57c0faf); /* 5 */ ++ FF(d, a, b, c, x[5], 12, 0x4787c62a); /* 6 */ ++ FF(c, d, a, b, x[6], 17, 0xa8304613); /* 7 */ ++ FF(b, c, d, a, x[7], 22, 0xfd469501); /* 8 */ ++ FF(a, b, c, d, x[8], 7, 0x698098d8); /* 9 */ ++ FF(d, a, b, c, x[9], 12, 0x8b44f7af); /* 10 */ ++ FF(c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */ ++ FF(b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */ ++ FF(a, b, c, d, x[12], 7, 0x6b901122); /* 13 */ ++ FF(d, a, b, c, x[13], 12, 0xfd987193); /* 14 */ ++ FF(c, d, a, b, x[14], 17, 0xa679438e); /* 15 */ ++ FF(b, c, d, a, x[15], 22, 0x49b40821); /* 16 */ ++ ++ /* Round 2 */ ++ GG(a, b, c, d, x[1], 5, 0xf61e2562); /* 17 */ ++ GG(d, a, b, c, x[6], 9, 0xc040b340); /* 18 */ ++ GG(c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */ ++ GG(b, c, d, a, x[0], 20, 0xe9b6c7aa); /* 20 */ ++ GG(a, b, c, d, x[5], 5, 0xd62f105d); /* 21 */ ++ GG(d, a, b, c, x[10], 9, 0x2441453); /* 22 */ ++ GG(c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */ ++ GG(b, c, d, a, x[4], 20, 0xe7d3fbc8); /* 24 */ ++ GG(a, b, c, d, x[9], 5, 0x21e1cde6); /* 25 */ ++ GG(d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */ ++ GG(c, d, a, b, x[3], 14, 0xf4d50d87); /* 27 */ ++ GG(b, c, d, a, x[8], 20, 0x455a14ed); /* 28 */ ++ GG(a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */ ++ GG(d, a, b, c, x[2], 9, 0xfcefa3f8); /* 30 */ ++ GG(c, d, a, b, x[7], 14, 0x676f02d9); /* 31 */ ++ GG(b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */ ++ ++ /* Round 3 */ ++ HH(a, b, c, d, x[5], 4, 0xfffa3942); /* 33 */ ++ HH(d, a, b, c, x[8], 11, 0x8771f681); /* 34 */ ++ HH(c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */ ++ HH(b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */ ++ HH(a, b, c, d, x[1], 4, 0xa4beea44); /* 37 */ ++ HH(d, a, b, c, x[4], 11, 0x4bdecfa9); /* 38 */ ++ HH(c, d, a, b, x[7], 16, 0xf6bb4b60); /* 39 */ ++ HH(b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */ ++ HH(a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */ ++ HH(d, a, b, c, x[0], 11, 0xeaa127fa); /* 42 */ ++ HH(c, d, a, b, x[3], 16, 0xd4ef3085); /* 43 */ ++ HH(b, c, d, a, x[6], 23, 0x4881d05); /* 44 */ ++ HH(a, b, c, d, x[9], 4, 0xd9d4d039); /* 45 */ ++ HH(d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */ ++ HH(c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */ ++ HH(b, c, d, a, x[2], 23, 0xc4ac5665); /* 48 */ ++ ++ /* Round 4 */ ++ II(a, b, c, d, x[0], 6, 0xf4292244); /* 49 */ ++ II(d, a, b, c, x[7], 10, 0x432aff97); /* 50 */ ++ II(c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */ ++ II(b, c, d, a, x[5], 21, 0xfc93a039); /* 52 */ ++ II(a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */ ++ II(d, a, b, c, x[3], 10, 0x8f0ccc92); /* 54 */ ++ II(c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */ ++ II(b, c, d, a, x[1], 21, 0x85845dd1); /* 56 */ ++ II(a, b, c, d, x[8], 6, 0x6fa87e4f); /* 57 */ ++ II(d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */ ++ II(c, d, a, b, x[6], 15, 0xa3014314); /* 59 */ ++ II(b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */ ++ II(a, b, c, d, x[4], 6, 0xf7537e82); /* 61 */ ++ II(d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */ ++ II(c, d, a, b, x[2], 15, 0x2ad7d2bb); /* 63 */ ++ II(b, c, d, a, x[9], 21, 0xeb86d391); /* 64 */ ++ state[0] += a; ++ state[1] += b; ++ state[2] += c; ++ state[3] += d; ++} +diff --git a/drivers/net/wireless/aic8800/aic8800_bsp/md5.h b/drivers/net/wireless/aic8800/aic8800_bsp/md5.h +new file mode 100755 +index 000000000..9b2c52eed +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_bsp/md5.h +@@ -0,0 +1,46 @@ ++#ifndef MD5_H ++#define MD5_H ++ ++typedef struct { ++ unsigned int count[2]; ++ unsigned int state[4]; ++ unsigned char buffer[64]; ++} MD5_CTX; ++ ++#define F(x, y, z) ((x & y) | (~x & z)) ++#define G(x, y, z) ((x & z) | (y & ~z)) ++#define H(x, y, z) (x ^ y ^ z) ++#define I(x, y, z) (y ^ (x | ~z)) ++#define ROTATE_LEFT(x, n) ((x << n) | (x >> (32 - n))) ++#define FF(a, b, c, d, x, s, ac) \ ++ { \ ++ a += F(b, c, d) + x + ac; \ ++ a = ROTATE_LEFT(a, s); \ ++ a += b; \ ++ } ++#define GG(a, b, c, d, x, s, ac) \ ++ { \ ++ a += G(b, c, d) + x + ac; \ ++ a = ROTATE_LEFT(a, s); \ ++ a += b; \ ++ } ++#define HH(a, b, c, d, x, s, ac) \ ++ { \ ++ a += H(b, c, d) + x + ac; \ ++ a = ROTATE_LEFT(a, s); \ ++ a += b; \ ++ } ++#define II(a, b, c, d, x, s, ac) \ ++ { \ ++ a += I(b, c, d) + x + ac; \ ++ a = ROTATE_LEFT(a, s); \ ++ a += b; \ ++ } ++void MD5Init(MD5_CTX *context); ++void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int inputlen); ++void MD5Final(MD5_CTX *context, unsigned char digest[16]); ++void MD5Transform(unsigned int state[4], unsigned char block[64]); ++void MD5Encode(unsigned char *output, unsigned int *input, unsigned int len); ++void MD5Decode(unsigned int *output, unsigned char *input, unsigned int len); ++ ++#endif +diff --git a/drivers/net/wireless/aic8800/aic8800_bsp/rwnx_version_gen.h b/drivers/net/wireless/aic8800/aic8800_bsp/rwnx_version_gen.h +new file mode 100755 +index 000000000..6fcb679c8 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_bsp/rwnx_version_gen.h +@@ -0,0 +1,4 @@ ++#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 RELEASE_DATE "2025_0410_b99ca8b6" +diff --git a/drivers/net/wireless/aic8800/aic8800_btlpm/Kconfig b/drivers/net/wireless/aic8800/aic8800_btlpm/Kconfig +new file mode 100755 +index 000000000..872a6064d +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_btlpm/Kconfig +@@ -0,0 +1,7 @@ ++config AIC8800_BTLPM_SUPPORT ++ tristate "AIC8800 bluetooth Support" ++ default y ++ help ++ This is support for the aic8800 bluetooth low-power-mode / HCI ++ wake companion module (aic8800_btlpm). Built-in (y) by default — ++ see the aic8800 port notes in warden-sdk/kernel/rv1106-enablement/wifi/. +diff --git a/drivers/net/wireless/aic8800/aic8800_btlpm/Makefile b/drivers/net/wireless/aic8800/aic8800_btlpm/Makefile +new file mode 100755 +index 000000000..21750dd72 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_btlpm/Makefile +@@ -0,0 +1,16 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++# ++# aic8800_btlpm — Bluetooth low-power-mode / HCI wake companion module, ++# ported in-tree from the vendor out-of-tree Makefile ++# (flare-edge/sdk/sysdrv/drv_ko/wifi/aic8800dc/aic8800_btlpm/Makefile). ++# lpm.c stays out of the build (CONFIG_SUPPORT_LPM was already off in the ++# vendor default; aic8800_btlpm.c's own has_lpm_enabled/lpm_fops logic is ++# self-contained and does not call into lpm.c). ++ ++ccflags-y += -DCONFIG_PLATFORM_ROCKCHIP ++ccflags-y += -I$(srctree)/$(src)/../aic8800_bsp ++ ++obj-$(CONFIG_AIC8800_BTLPM_SUPPORT) += aic8800_btlpm.o ++aic8800_btlpm-y := \ ++ aic_bluetooth_main.o \ ++ rfkill.o +diff --git a/drivers/net/wireless/aic8800/aic8800_btlpm/aic8800_btlpm.c b/drivers/net/wireless/aic8800/aic8800_btlpm/aic8800_btlpm.c +new file mode 100755 +index 000000000..f249d0885 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_btlpm/aic8800_btlpm.c +@@ -0,0 +1,1166 @@ ++/* ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ ++ * 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. ++ * ++ */ ++ ++#define DEBUG ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) ++#include ++#endif ++ ++#include "aic_bsp_export.h" ++ ++/* ++ * #define BT_SLEEP_DBG ++ */ ++#define BT_SLEEP_DBG ++#undef BT_DBG ++#undef BT_ERR ++#ifdef BT_SLEEP_DBG ++#define BT_DBG(fmt, arg...) pr_debug("[BT_LPM] %s: " fmt "\n", __func__, ##arg) ++#else ++#define BT_DBG(fmt, arg...) ++#endif ++#define BT_ERR(fmt, arg...) pr_debug("[BT_LPM] %s: " fmt "\n", __func__, ##arg) ++ ++/* ++ * Defines ++ */ ++ ++#define VERSION "1.3.3" ++#define PROC_DIR "bluetooth/sleep" ++ ++#define DEFAULT_UART_INDEX 1 ++#define BT_BLUEDROID_SUPPORT 1 ++static int bluesleep_start(void); ++static void bluesleep_stop(void); ++ ++struct bluesleep_info { ++ unsigned int wakeup_enable; ++ unsigned host_wake; ++ unsigned ext_wake; ++ unsigned host_wake_irq; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ struct wakeup_source *ws; ++#else ++ struct wake_lock wake_lock; ++#endif ++ struct uart_port *uport; ++ unsigned host_wake_assert : 1; ++ unsigned ext_wake_assert : 1; ++ struct platform_device *pdev; ++}; ++ ++/* work function */ ++static void bluesleep_sleep_work(struct work_struct *work); ++static void bluesleep_tx_allow_sleep(void); ++ ++/* work queue */ ++DECLARE_DELAYED_WORK(sleep_workqueue, bluesleep_sleep_work); ++ ++/* Macros for handling sleep work */ ++#define bluesleep_rx_busy() schedule_delayed_work(&sleep_workqueue, 0) ++#define bluesleep_tx_busy() schedule_delayed_work(&sleep_workqueue, 0) ++#define bluesleep_rx_idle() schedule_delayed_work(&sleep_workqueue, 0) ++#define bluesleep_tx_idle() schedule_delayed_work(&sleep_workqueue, 0) ++ ++/* 1 second timeout */ ++#define RX_TIMER_INTERVAL 1 ++ ++/* state variable names and bit positions */ ++#define BT_PROTO 0x01 ++#define BT_TXDATA 0x02 ++#define BT_ASLEEP 0x04 ++#define BT_TXIDLE 0x08 ++#define BT_PAUSE 0x09 ++#define BT_RXTIMER 0x0a ++ ++#if BT_BLUEDROID_SUPPORT ++static bool has_lpm_enabled; ++#else ++/* global pointer to a single hci device. */ ++static struct hci_dev *bluesleep_hdev; ++#endif ++ ++#if BT_BLUEDROID_SUPPORT ++static struct platform_device *bluesleep_uart_dev; ++#endif ++static struct bluesleep_info *bsi; ++ ++/* module usage */ ++static atomic_t open_count = ATOMIC_INIT(1); ++ ++/* ++ * Local function prototypes ++ */ ++ ++#if !BT_BLUEDROID_SUPPORT ++static int bluesleep_hci_event(struct notifier_block *this, unsigned long event, ++ void *data); ++#endif ++ ++/* ++ * Global variables ++ */ ++ ++/** Global state flags */ ++static unsigned long flags; ++ ++/** Tasklet to respond to change in hostwake line */ ++static struct tasklet_struct hostwake_task; ++ ++/** Reception timer */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) ++static void bluesleep_rx_timer_expire(struct timer_list *t); ++#else ++static void bluesleep_rx_timer_expire(unsigned long data); ++#endif ++static struct timer_list rx_timer; ++ ++/** Lock for state transitions */ ++static spinlock_t rw_lock; ++ ++#if !BT_BLUEDROID_SUPPORT ++/** Notifier block for HCI events */ ++struct notifier_block hci_event_nblock = { ++ .notifier_call = bluesleep_hci_event, ++}; ++#endif ++ ++struct proc_dir_entry *bluetooth_dir, *sleep_dir; ++ ++/* ++ * Local functions ++ */ ++ ++/* ++ * bt go to sleep will call this function tell uart stop data interactive ++ */ ++static void hsuart_power(int on) ++{ ++ if (bsi->uport != NULL) { ++ if (on) ++ bsi->uport->ops->set_mctrl(bsi->uport, TIOCM_RTS); ++ else ++ bsi->uport->ops->set_mctrl(bsi->uport, 0); ++ } else { ++ BT_ERR("bsi->uport = NULL, has_lpm_enabled = %d", ++ has_lpm_enabled); ++ } ++} ++ ++/** ++ * @return 1 if the Host can go to sleep, 0 otherwise. ++ */ ++static inline int bluesleep_can_sleep(void) ++{ ++ /* check if HOST_WAKE_BT_GPIO and BT_WAKE_HOST_GPIO ++ * are both deasserted ++ */ ++ return (gpio_get_value(bsi->ext_wake) != bsi->ext_wake_assert) && ++ (gpio_get_value(bsi->host_wake) != bsi->host_wake_assert) && ++ (!test_bit(BT_RXTIMER, &flags)) && (bsi->uport != NULL); ++} ++ ++/** ++ * @brief@ main sleep work handling function which update the flags ++ * and activate and deactivate UART ,check FIFO. ++ */ ++static void bluesleep_sleep_work(struct work_struct *work) ++{ ++ if (!has_lpm_enabled) ++ return; ++ ++ if (bluesleep_can_sleep()) { ++ /* already asleep, this is an error case */ ++ if (test_bit(BT_ASLEEP, &flags)) { ++ BT_DBG("already asleep"); ++ return; ++ } ++ if (bsi->uport->ops->tx_empty(bsi->uport)) { ++ BT_DBG("going to sleep..."); ++ set_bit(BT_ASLEEP, &flags); ++ /*Deactivating UART */ ++ hsuart_power(0); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ __pm_wakeup_event(bsi->ws, HZ / 2); ++#else ++ wake_lock_timeout(&bsi->wake_lock, HZ / 2); ++#endif ++ } else { ++ BT_DBG("This should never happen.\n"); ++ return; ++ } ++ } else if (test_bit(BT_ASLEEP, &flags)) { ++ BT_DBG("hold wake locks for rx_task."); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ __pm_stay_awake(bsi->ws); ++#else ++ wake_lock(&bsi->wake_lock); ++#endif ++ clear_bit(BT_ASLEEP, &flags); ++ ++ /* Add a timer to make sure that UART ++ * would not be turned on&off very frequentently ++ */ ++ mod_timer(&rx_timer, jiffies + (RX_TIMER_INTERVAL * HZ)); ++ ++ set_bit(BT_RXTIMER, &flags); ++ hsuart_power(1); ++ } else { ++ mod_timer(&rx_timer, jiffies + (RX_TIMER_INTERVAL * HZ)); ++ 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)) { ++ 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); ++ } ++ } ++} ++ ++/** ++ * A tasklet function that runs in tasklet context and reads the value ++ * of the HOST_WAKE GPIO pin and further defer the work. ++ * @param data Not used. ++ */ ++static void bluesleep_hostwake_task(unsigned long data) ++{ ++ BT_DBG("hostwake line change"); ++ spin_lock(&rw_lock); ++ ++ if (gpio_get_value(bsi->host_wake) == bsi->host_wake_assert) ++ bluesleep_rx_busy(); ++ else ++ bluesleep_rx_idle(); ++ ++ spin_unlock(&rw_lock); ++} ++ ++/** ++ * Handles proper timer action when outgoing data is delivered to the ++ * HCI line discipline. Sets BT_TXDATA. ++ */ ++static void bluesleep_outgoing_data(void) ++{ ++ unsigned long irq_flags; ++ int power_on_uart = 0; ++ ++ spin_lock_irqsave(&rw_lock, irq_flags); ++ ++ /* if the tx side is sleeping... */ ++ if (gpio_get_value(bsi->ext_wake) != bsi->ext_wake_assert) { ++ BT_DBG("tx was sleeping, wakeup it"); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ __pm_stay_awake(bsi->ws); ++#else ++ wake_lock(&bsi->wake_lock); ++#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; ++ } ++ ++ spin_unlock_irqrestore(&rw_lock, irq_flags); ++ if (power_on_uart == 1) ++ hsuart_power(1); ++} ++ ++#if BT_BLUEDROID_SUPPORT ++static struct uart_port *bluesleep_get_uart_port(void) ++{ ++ struct uart_port *uport = NULL; ++ ++ if (bluesleep_uart_dev) { ++ uport = platform_get_drvdata(bluesleep_uart_dev); ++ if (uport) ++ BT_DBG("%s get uart_port from blusleep_uart_dev: %s, port irq: %d", ++ __func__, bluesleep_uart_dev->name, uport->irq); ++ } ++ return uport; ++} ++ ++static int bluesleep_lpm_proc_show(struct seq_file *m, void *v) ++{ ++ seq_printf(m, "lpm enable: %d\n", has_lpm_enabled); ++ return 0; ++} ++ ++static int bluesleep_lpm_proc_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, bluesleep_lpm_proc_show, NULL); ++} ++ ++static ssize_t bluesleep_write_proc_lpm(struct file *file, ++ const char __user *buffer, size_t count, ++ loff_t *pos) ++{ ++ char b; ++ ++ if (count < 1) ++ return -EINVAL; ++ ++ if (copy_from_user(&b, buffer, 1)) ++ 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; ++ if (bluesleep_uart_dev) ++ bsi->uport = bluesleep_get_uart_port(); ++ ++ /* if bluetooth started, start bluesleep*/ ++ bluesleep_start(); ++ } ++ } ++ ++ return count; ++} ++ ++static int bluesleep_btwrite_proc_show(struct seq_file *m, void *v) ++{ ++ seq_puts(m, "it's not support\n"); ++ return 0; ++} ++ ++static int bluesleep_btwrite_proc_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, bluesleep_btwrite_proc_show, NULL); ++} ++ ++static ssize_t bluesleep_write_proc_btwrite(struct file *file, ++ const char __user *buffer, ++ size_t count, loff_t *pos) ++{ ++ char b; ++ ++ if (count < 1) ++ return -EINVAL; ++ ++ if (copy_from_user(&b, buffer, 1)) ++ return -EFAULT; ++ ++ /* HCI_DEV_WRITE */ ++ if (b != '0') ++ bluesleep_outgoing_data(); ++ else ++ bluesleep_tx_allow_sleep(); ++ ++ 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, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++ .write = bluesleep_write_proc_lpm, ++}; ++static const struct file_operations btwrite_fops = { ++ .owner = THIS_MODULE, ++ .open = bluesleep_btwrite_proc_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++ .write = bluesleep_write_proc_btwrite, ++}; ++#endif ++ ++#else ++/** ++ * Handles HCI device events. ++ * @param this Not used. ++ * @param event The event that occurred. ++ * @param data The HCI device associated with the event. ++ * @return NOTIFY_DONE. ++ */ ++static int bluesleep_hci_event(struct notifier_block *this, unsigned long event, ++ void *data) ++{ ++ struct hci_dev *hdev = (struct hci_dev *)data; ++ struct hci_uart *hu; ++ struct uart_state *state; ++ ++ if (!hdev) ++ return NOTIFY_DONE; ++ ++ switch (event) { ++ case HCI_DEV_REG: ++ if (!bluesleep_hdev) { ++ bluesleep_hdev = hdev; ++ hu = (struct hci_uart *)hdev->driver_data; ++ state = (struct uart_state *)hu->tty->driver_data; ++ bsi->uport = state->uart_port; ++ } ++ break; ++ case HCI_DEV_UNREG: ++ bluesleep_hdev = NULL; ++ bsi->uport = NULL; ++ break; ++ case HCI_DEV_WRITE: ++ bluesleep_outgoing_data(); ++ break; ++ } ++ ++ return NOTIFY_DONE; ++} ++#endif ++ ++/** ++ * Function to check wheather bluetooth can sleep when btwrite was deasserted ++ * by bluedroid. ++ */ ++static void bluesleep_tx_allow_sleep(void) ++{ ++ unsigned long irq_flags; ++ 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); ++} ++ ++/* Handles reception timer expiration. ++ * Clear BT_RXTIMER. ++ * @param data Not used. ++ */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) ++static void bluesleep_rx_timer_expire(struct timer_list *t) ++#else ++static void bluesleep_rx_timer_expire(unsigned long data) ++#endif ++{ ++ BT_DBG("bluesleep_rx_timer_expire"); ++ clear_bit(BT_RXTIMER, &flags); ++ bluesleep_rx_idle(); ++} ++ ++/** ++ * Schedules a tasklet to run when receiving an interrupt on the ++ * HOST_WAKE GPIO pin. ++ * @param irq Not used. ++ * @param dev_id Not used. ++ */ ++static irqreturn_t bluesleep_hostwake_isr(int irq, void *dev_id) ++{ ++ /* schedule a tasklet to handle the change in the host wake line */ ++ tasklet_schedule(&hostwake_task); ++ return IRQ_HANDLED; ++} ++ ++/** ++ * Starts the Sleep-Mode Protocol on the Host. ++ * @return On success, 0. On error, -1, and errno is set ++ * appropriately. ++ */ ++static int bluesleep_start(void) ++{ ++ int retval; ++ unsigned long irq_flags; ++ ++ spin_lock_irqsave(&rw_lock, irq_flags); ++ ++ if (test_bit(BT_PROTO, &flags)) { ++ spin_unlock_irqrestore(&rw_lock, irq_flags); ++ return 0; ++ } ++ ++ spin_unlock_irqrestore(&rw_lock, irq_flags); ++ ++ if (!atomic_dec_and_test(&open_count)) { ++ atomic_inc(&open_count); ++ return -EBUSY; ++ } ++ ++ /* 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); ++ retval = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr, ++ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, ++ "bluetooth hostwake", &bsi->pdev->dev); ++ if (retval < 0) { ++ BT_ERR("Couldn't acquire BT_HOST_WAKE IRQ"); ++ goto fail; ++ } ++ ++ set_bit(BT_PROTO, &flags); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ __pm_stay_awake(bsi->ws); ++#else ++ wake_lock(&bsi->wake_lock); ++#endif ++ ++ return 0; ++fail: ++ timer_delete(&rx_timer); ++ atomic_inc(&open_count); ++ ++ return retval; ++} ++ ++/** ++ * Stops the Sleep-Mode Protocol on the Host. ++ */ ++static void bluesleep_stop(void) ++{ ++ unsigned long irq_flags; ++ ++ spin_lock_irqsave(&rw_lock, irq_flags); ++ ++ if (!test_bit(BT_PROTO, &flags)) { ++ spin_unlock_irqrestore(&rw_lock, irq_flags); ++ return; ++ } ++ ++ /* assert BT_WAKE */ ++ gpio_set_value(bsi->ext_wake, bsi->ext_wake_assert); ++ ++ timer_delete(&rx_timer); ++ clear_bit(BT_PROTO, &flags); ++ ++ if (test_bit(BT_ASLEEP, &flags)) { ++ clear_bit(BT_ASLEEP, &flags); ++ hsuart_power(1); ++ } ++ ++ atomic_inc(&open_count); ++ ++ spin_unlock_irqrestore(&rw_lock, irq_flags); ++ free_irq(bsi->host_wake_irq, &bsi->pdev->dev); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ __pm_wakeup_event(bsi->ws, HZ / 2); ++#else ++ wake_lock_timeout(&bsi->wake_lock, HZ / 2); ++#endif ++} ++#if 0 ++/** ++ * Read the BT_WAKE GPIO pin value via the proc interface. ++ * When this function returns, page will contain a 1 if the ++ * pin is high, 0 otherwise. ++ * @param page Buffer for writing data. ++ * @param start Not used. ++ * @param offset Not used. ++ * @param count Not used. ++ * @param eof Whether or not there is more data to be read. ++ * @param data Not used. ++ * @return The number of bytes written. ++ */ ++static int bluepower_read_proc_btwake(char *page, char **start, off_t offset, ++ int count, int *eof, void *data) ++{ ++ *eof = 1; ++ return sprintf(page, "btwake:%u\n", ++ (gpio_get_value(bsi->ext_wake) == bsi->ext_wake_assert)); ++} ++ ++/** ++ * Write the BT_WAKE GPIO pin value via the proc interface. ++ * @param file Not used. ++ * @param buffer The buffer to read from. ++ * @param count The number of bytes to be written. ++ * @param data Not used. ++ * @return On success, the number of bytes written. On error, -1, and ++ * errno is set appropriately. ++ */ ++static int bluepower_write_proc_btwake(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ char *buf; ++ ++ if (count < 1) ++ return -EINVAL; ++ ++ buf = kmalloc(count, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ if (copy_from_user(buf, buffer, count)) { ++ kfree(buf); ++ return -EFAULT; ++ } ++ ++ if (buf[0] == '0') { ++ gpio_set_value(bsi->ext_wake, !bsi->ext_wake_assert); ++ } else if (buf[0] == '1') { ++ gpio_set_value(bsi->ext_wake, bsi->ext_wake_assert); ++ } else { ++ kfree(buf); ++ return -EINVAL; ++ } ++ ++ kfree(buf); ++ return count; ++} ++ ++/** ++ * Read the BT_HOST_WAKE GPIO pin value via the proc interface. ++ * When this function returns, page will contain a 1 if the pin ++ * is high, 0 otherwise. ++ * @param page Buffer for writing data. ++ * @param start Not used. ++ * @param offset Not used. ++ * @param count Not used. ++ * @param eof Whether or not there is more data to be read. ++ * @param data Not used. ++ * @return The number of bytes written. ++ */ ++static int bluepower_read_proc_hostwake(char *page, char **start, off_t offset, ++ int count, int *eof, void *data) ++{ ++ *eof = 1; ++ return sprintf(page, "hostwake: %u\n", ++ (gpio_get_value(bsi->host_wake) == bsi->host_wake_assert)); ++} ++ ++ ++/** ++ * Read the low-power status of the Host via the proc interface. ++ * When this function returns, page contains a 1 if the Host ++ * is asleep, 0 otherwise. ++ * @param page Buffer for writing data. ++ * @param start Not used. ++ * @param offset Not used. ++ * @param count Not used. ++ * @param eof Whether or not there is more data to be read. ++ * @param data Not used. ++ * @return The number of bytes written. ++ */ ++static int bluesleep_read_proc_asleep(char *page, char **start, off_t offset, ++ int count, int *eof, void *data) ++{ ++ unsigned int asleep; ++ ++ asleep = test_bit(BT_ASLEEP, &flags) ? 1 : 0; ++ *eof = 1; ++ return sprintf(page, "asleep: %u\n", asleep); ++} ++ ++/** ++ * Read the low-power protocol being used by the Host via the proc interface. ++ * When this function returns, page will contain a 1 if the Host ++ * is using the Sleep Mode Protocol, 0 otherwise. ++ * @param page Buffer for writing data. ++ * @param start Not used. ++ * @param offset Not used. ++ * @param count Not used. ++ * @param eof Whether or not there is more data to be read. ++ * @param data Not used. ++ * @return The number of bytes written. ++ */ ++static int bluesleep_read_proc_proto(char *page, char **start, off_t offset, ++ int count, int *eof, void *data) ++{ ++ unsigned int proto; ++ ++ proto = test_bit(BT_PROTO, &flags) ? 1 : 0; ++ *eof = 1; ++ return sprintf(page, "proto: %u\n", proto); ++} ++ ++/** ++ * Modify the low-power protocol used by the Host via the proc interface. ++ * @param file Not used. ++ * @param buffer The buffer to read from. ++ * @param count The number of bytes to be written. ++ * @param data Not used. ++ * @return On success, the number of bytes written. On error, -1, and ++ * errno is set appropriately. ++ */ ++static int bluesleep_write_proc_proto(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ char proto; ++ ++ if (count < 1) ++ return -EINVAL; ++ ++ if (copy_from_user(&proto, buffer, 1)) ++ return -EFAULT; ++ ++ if (proto == '0') ++ bluesleep_stop(); ++ else ++ bluesleep_start(); ++ ++ /* claim that we wrote everything */ ++ return count; ++} ++#endif ++ ++static int assert_level = -1; ++module_param(assert_level, int, S_IRUGO); ++MODULE_PARM_DESC(assert_level, "BT_LPM hostwake/btwake assert level"); ++ ++static struct platform_device *sw_uart_get_pdev(int id) ++{ ++ struct device_node *np; ++ char match[20]; ++ sprintf(match, "uart%d", id); ++ np = of_find_node_by_type(NULL, match); ++ return of_find_device_by_node(np); ++} ++ ++static int __init bluesleep_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct device *dev = &pdev->dev; ++ enum of_gpio_flags config; ++ int ret, uart_index; ++ u32 val; ++ struct aicbsp_feature_t bsp_feature_lpm; ++ ++ bsi = devm_kzalloc(&pdev->dev, sizeof(struct bluesleep_info), ++ GFP_KERNEL); ++ if (!bsi) ++ return -ENOMEM; ++ ++ 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"); ++ ret = -EINVAL; ++ goto err0; ++ } ++ ++ /* set host_wake_assert */ ++ aicbsp_get_feature(&bsp_feature_lpm); ++ if (bsp_feature_lpm.irqf == 0) ++ bsi->host_wake_assert = (config == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ else ++ bsi->host_wake_assert = (config == OF_GPIO_ACTIVE_LOW) ? 1 : 0; ++ ++ BT_DBG("bt_hostwake gpio=%d assert=%d\n", bsi->host_wake, ++ bsi->host_wake_assert); ++ ++ if (assert_level != -1) { ++ bsi->host_wake_assert = (assert_level & 0x02) > 0; ++ BT_DBG("override host_wake assert to %d", ++ bsi->host_wake_assert); ++ } ++ ++ ret = devm_gpio_request(dev, bsi->host_wake, "bt_hostwake"); ++ if (ret < 0) { ++ BT_ERR("can't request bt_hostwake gpio %d\n", bsi->host_wake); ++ 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); ++ goto err1; ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) ++ if (!of_property_read_bool(np, "wakeup-source")) { ++#else ++ if (!of_property_read_u32(np, "wakeup-source", &bsi->wakeup_enable) && ++ (bsi->wakeup_enable == 0)) { ++#endif ++ BT_DBG("wakeup source is disabled!\n"); ++ } else { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) ++ ret = device_init_wakeup(dev, true); ++ if (ret < 0) { ++ BT_ERR("device init wakeup failed!\n"); ++ 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); ++ goto err2; ++ } ++ bsi->wakeup_enable = 1; ++#else ++ BT_ERR("%s kernel unsupport this feature!\r\n", __func__); ++#endif ++ } ++ ++ 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"); ++ 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); ++ goto err2; ++ } ++ ++ /* set ext_wake_assert */ ++ bsi->ext_wake_assert = (config == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ BT_DBG("bt_wake gpio=%d assert=%d\n", bsi->ext_wake, ++ bsi->ext_wake_assert); ++ ++ if (assert_level != -1) { ++ bsi->ext_wake_assert = (assert_level & 0x01) > 0; ++ BT_DBG("override ext_wake assert to %d", bsi->ext_wake_assert); ++ } ++ ++ /* 1.set bt_wake as output and the level is assert, assert bt wake */ ++ ret = gpio_direction_output(bsi->ext_wake, bsi->ext_wake_assert); ++ if (ret < 0) { ++ BT_ERR("can't request output direction bt_wake gpio %d\n", ++ bsi->ext_wake); ++ 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); ++ if (bsi->host_wake_irq < 0) { ++ BT_ERR("map gpio [%d] to virq failed, errno = %d\n", ++ bsi->host_wake, bsi->host_wake_irq); ++ ret = -ENODEV; ++ goto err3; ++ } ++ ++ uart_index = DEFAULT_UART_INDEX; ++ if (!of_property_read_u32(np, "uart_index", &val)) { ++ switch (val) { ++ case 0: ++ case 1: ++ case 2: ++ uart_index = val; ++ break; ++ default: ++ BT_ERR("unsupported uart_index (%u)\n", val); ++ } ++ } ++ BT_DBG("uart_index (%u)\n", uart_index); ++ bluesleep_uart_dev = sw_uart_get_pdev(uart_index); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ bsi->ws = wakeup_source_register(dev, "bluesleep"); ++#else ++ 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) ++{ ++ /* 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); ++ timer_delete(&rx_timer); ++ if (test_bit(BT_ASLEEP, &flags)) ++ hsuart_power(1); ++ } ++ gpio_free(bsi->host_wake); ++ gpio_free(bsi->ext_wake); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ wakeup_source_unregister(bsi->ws); ++#else ++ wake_lock_destroy(&bsi->wake_lock); ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) ++ if (bsi->wakeup_enable) { ++ BT_DBG("Deinit wakeup source"); ++ device_init_wakeup(&pdev->dev, false); ++ dev_pm_clear_wake_irq(&pdev->dev); ++ } ++#else ++ BT_ERR("%s kernel unsupport this feature!\r\n", __func__); ++#endif ++ return 0; ++} ++ ++#ifdef CONFIG_AUTO_PM ++static int bluesleep_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ printk("%s\n", __func__); ++ ++ bluesleep_tx_allow_sleep(); ++ return 0; ++} ++ ++static int bluesleep_resume(struct platform_device *pdev) ++{ ++ printk("%s\n", __func__); ++ ++ bluesleep_outgoing_data(); ++ return 0; ++} ++#endif ++ ++static const struct of_device_id sunxi_btlpm_ids[] = { ++ { .compatible = "allwinner,sunxi-btlpm" }, ++ { /* Sentinel */ } ++}; ++ ++static struct platform_driver bluesleep_driver = { ++ .remove = bluesleep_remove, ++#ifdef CONFIG_AUTO_PM ++ .suspend = bluesleep_suspend, ++ .resume = bluesleep_resume, ++#endif ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "sunxi-btlpm", ++ .of_match_table = sunxi_btlpm_ids, ++ }, ++}; ++ ++/** ++ * Initializes the module. ++ * @return On success, 0. On error, -1, and errno is set ++ * appropriately. ++ */ ++static int __init bluesleep_init(void) ++{ ++ int retval; ++ struct proc_dir_entry *ent; ++ ++ BT_DBG("BlueSleep Mode Driver Ver %s", VERSION); ++ ++ retval = platform_driver_probe(&bluesleep_driver, bluesleep_probe); ++ if (retval) ++ return retval; ++ ++#if !BT_BLUEDROID_SUPPORT ++ bluesleep_hdev = NULL; ++#endif ++ ++ bluetooth_dir = proc_mkdir("bluetooth", NULL); ++ if (bluetooth_dir == NULL) { ++ BT_ERR("Unable to create /proc/bluetooth directory"); ++ return -ENOMEM; ++ } ++ ++ sleep_dir = proc_mkdir("sleep", bluetooth_dir); ++ if (sleep_dir == NULL) { ++ BT_ERR("Unable to create /proc/%s directory", PROC_DIR); ++ return -ENOMEM; ++ } ++#if 0 ++ /* Creating read/write "btwake" entry */ ++ ent = create_proc_entry("btwake", 0, sleep_dir); ++ if (ent == NULL) { ++ BT_ERR("Unable to create /proc/%s/btwake entry", PROC_DIR); ++ retval = -ENOMEM; ++ goto fail; ++ } ++ ent->read_proc = bluepower_read_proc_btwake; ++ ent->write_proc = bluepower_write_proc_btwake; ++ ++ /* read only proc entries */ ++ if (create_proc_read_entry("hostwake", 0, sleep_dir, ++ bluepower_read_proc_hostwake, NULL) == NULL) { ++ BT_ERR("Unable to create /proc/%s/hostwake entry", PROC_DIR); ++ retval = -ENOMEM; ++ goto fail; ++ } ++ ++ /* read/write proc entries */ ++ ent = create_proc_entry("proto", 0666, sleep_dir); ++ if (ent == NULL) { ++ BT_ERR("Unable to create /proc/%s/proto entry", PROC_DIR); ++ retval = -ENOMEM; ++ goto fail; ++ } ++ ent->read_proc = bluesleep_read_proc_proto; ++ ent->write_proc = bluesleep_write_proc_proto; ++ ++ /* read only proc entries */ ++ if (create_proc_read_entry("asleep", 0, ++ sleep_dir, bluesleep_read_proc_asleep, NULL) == NULL) { ++ BT_ERR("Unable to create /proc/%s/asleep entry", PROC_DIR); ++ retval = -ENOMEM; ++ goto fail; ++ } ++#endif ++#if BT_BLUEDROID_SUPPORT ++ /* read/write proc entries */ ++ ent = proc_create("lpm", 0660, sleep_dir, &lpm_fops); ++ if (ent == NULL) { ++ BT_ERR("Unable to create /proc/%s/lpm entry", PROC_DIR); ++ retval = -ENOMEM; ++ goto fail; ++ } ++ ++ ent = proc_create("btwrite", 0660, sleep_dir, &btwrite_fops); ++ if (ent == NULL) { ++ BT_ERR("Unable to create /proc/%s/btwrite entry", PROC_DIR); ++ retval = -ENOMEM; ++ goto fail; ++ } ++#endif ++ ++ flags = 0; /* clear all status bits */ ++ ++ /* Initialize spinlock. */ ++ spin_lock_init(&rw_lock); ++ ++ /* Initialize timer */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) ++ timer_setup(&rx_timer, bluesleep_rx_timer_expire, 0); ++#else ++ init_timer(&rx_timer); ++ rx_timer.function = bluesleep_rx_timer_expire; ++ rx_timer.data = 0; ++#endif ++ ++ /* initialize host wake tasklet */ ++ tasklet_init(&hostwake_task, bluesleep_hostwake_task, 0); ++ ++#if !BT_BLUEDROID_SUPPORT ++ hci_register_notifier(&hci_event_nblock); ++#endif ++ ++ return 0; ++ ++fail: ++#if BT_BLUEDROID_SUPPORT ++ remove_proc_entry("btwrite", sleep_dir); ++ remove_proc_entry("lpm", sleep_dir); ++#endif ++#if 0 ++ remove_proc_entry("asleep", sleep_dir); ++ remove_proc_entry("proto", sleep_dir); ++ remove_proc_entry("hostwake", sleep_dir); ++ remove_proc_entry("btwake", sleep_dir); ++#endif ++ remove_proc_entry("sleep", bluetooth_dir); ++ remove_proc_entry("bluetooth", 0); ++ return retval; ++} ++ ++/** ++ * Cleans up the module. ++ */ ++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); ++ remove_proc_entry("lpm", sleep_dir); ++#endif ++#if 0 ++ remove_proc_entry("asleep", sleep_dir); ++ remove_proc_entry("proto", sleep_dir); ++ remove_proc_entry("hostwake", sleep_dir); ++ remove_proc_entry("btwake", sleep_dir); ++#endif ++ remove_proc_entry("sleep", bluetooth_dir); ++ remove_proc_entry("bluetooth", 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/drivers/net/wireless/aic8800/aic8800_btlpm/aic_bluetooth_main.c b/drivers/net/wireless/aic8800/aic8800_btlpm/aic_bluetooth_main.c +new file mode 100755 +index 000000000..f6f84bb42 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_btlpm/aic_bluetooth_main.c +@@ -0,0 +1,91 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#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); ++ goto err0; ++ } ++ ++ ret = rfkill_bluetooth_init(aicbt_pdev); ++ if (ret) { ++ pr_err("rfkill init fail\n"); ++ goto err1; ++ } ++#if defined(ANDROID_PLATFORM) && !defined(CONFIG_PLATFORM_ROCKCHIP) && \ ++ !defined(CONFIG_PLATFORM_ROCKCHIP2) ++ ret = bluesleep_init(aicbt_pdev); ++ if (ret) { ++ pr_err("bluesleep init fail\n"); ++ goto err2; ++ } ++#endif ++ ++ return 0; ++ ++#if defined(ANDROID_PLATFORM) && !defined(CONFIG_PLATFORM_ROCKCHIP) && \ ++ !defined(CONFIG_PLATFORM_ROCKCHIP2) ++err2: ++#endif ++ rfkill_bluetooth_remove(aicbt_pdev); ++err1: ++ platform_device_del(aicbt_pdev); ++err0: ++ platform_driver_unregister(&aicbt_driver); ++ return ret; ++} ++ ++static void __exit aic_bluetooth_mod_exit(void) ++{ ++ printk("%s\n", __func__); ++#if defined(ANDROID_PLATFORM) && !defined(CONFIG_PLATFORM_ROCKCHIP) && \ ++ !defined(CONFIG_PLATFORM_ROCKCHIP2) ++ bluesleep_exit(aicbt_pdev); ++#endif ++ 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/drivers/net/wireless/aic8800/aic8800_btlpm/aic_bsp_export.h b/drivers/net/wireless/aic8800/aic8800_btlpm/aic_bsp_export.h +new file mode 100755 +index 000000000..3b002d7bb +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_btlpm/aic_bsp_export.h +@@ -0,0 +1,19 @@ ++#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 ++ ++struct aicbsp_feature_t { ++ bool band_5g_support; ++ uint32_t sdio_clock; ++ uint8_t sdio_phase; ++ uint8_t irqf; ++}; ++ ++int aicbsp_set_subsys(int, int); ++int aicbsp_get_feature(struct aicbsp_feature_t *feature); ++ ++#endif +diff --git a/drivers/net/wireless/aic8800/aic8800_btlpm/lpm.c b/drivers/net/wireless/aic8800/aic8800_btlpm/lpm.c +new file mode 100755 +index 000000000..eaa0fe0f9 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_btlpm/lpm.c +@@ -0,0 +1,1109 @@ ++/* ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ ++ * 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. ++ * ++ */ ++ ++#define DEBUG ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) ++#include ++#endif ++#include ++#include ++#include ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) ++#include ++#endif ++ ++/* ++ * #define BT_SLEEP_DBG ++ */ ++#define BT_SLEEP_DBG ++#undef BT_DBG ++#undef BT_ERR ++#ifdef BT_SLEEP_DBG ++#define BT_DBG(fmt, arg...) pr_debug("[BT_LPM] %s: " fmt "\n", __func__, ##arg) ++#else ++#define BT_DBG(fmt, arg...) ++#endif ++#define BT_ERR(fmt, arg...) pr_debug("[BT_LPM] %s: " fmt "\n", __func__, ##arg) ++ ++/* ++ * Defines ++ */ ++ ++#define VERSION "1.3.3" ++#define PROC_DIR "bluetooth/sleep" ++ ++#define DEFAULT_UART_INDEX 1 ++#define BT_BLUEDROID_SUPPORT 1 ++static int bluesleep_start(void); ++static void bluesleep_stop(void); ++ ++struct bluesleep_info { ++ unsigned int wakeup_enable; ++ unsigned host_wake; ++ unsigned ext_wake; ++ unsigned host_wake_irq; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ struct wakeup_source *ws; ++#else ++ struct wake_lock wake_lock; ++#endif ++ struct uart_port *uport; ++ unsigned host_wake_assert : 1; ++ unsigned ext_wake_assert : 1; ++ struct platform_device *pdev; ++}; ++ ++/* work function */ ++static void bluesleep_sleep_work(struct work_struct *work); ++static void bluesleep_tx_allow_sleep(void); ++ ++/* work queue */ ++DECLARE_DELAYED_WORK(sleep_workqueue, bluesleep_sleep_work); ++ ++/* Macros for handling sleep work */ ++#define bluesleep_rx_busy() schedule_delayed_work(&sleep_workqueue, 0) ++#define bluesleep_tx_busy() schedule_delayed_work(&sleep_workqueue, 0) ++#define bluesleep_rx_idle() schedule_delayed_work(&sleep_workqueue, 0) ++#define bluesleep_tx_idle() schedule_delayed_work(&sleep_workqueue, 0) ++ ++/* 1 second timeout */ ++#define RX_TIMER_INTERVAL 1 ++ ++/* state variable names and bit positions */ ++#define BT_PROTO 0x01 ++#define BT_TXDATA 0x02 ++#define BT_ASLEEP 0x04 ++#define BT_RXTIMER 0x20 ++#define BT_TXIDLE 0x08 ++ ++#if BT_BLUEDROID_SUPPORT ++static bool has_lpm_enabled; ++#else ++/* global pointer to a single hci device. */ ++static struct hci_dev *bluesleep_hdev; ++#endif ++ ++#if BT_BLUEDROID_SUPPORT ++static struct platform_device *bluesleep_uart_dev; ++#endif ++static struct bluesleep_info *bsi; ++ ++/* module usage */ ++static atomic_t open_count = ATOMIC_INIT(1); ++ ++/* ++ * Local function prototypes ++ */ ++ ++#if !BT_BLUEDROID_SUPPORT ++static int bluesleep_hci_event(struct notifier_block *this, unsigned long event, ++ void *data); ++#endif ++ ++/* ++ * Global variables ++ */ ++ ++/** Global state flags */ ++static unsigned long flags; ++ ++/** Tasklet to respond to change in hostwake line */ ++static struct tasklet_struct hostwake_task; ++ ++/** Reception timer */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++static void bluesleep_rx_timer_expire(struct timer_list *t); ++#else ++static void bluesleep_rx_timer_expire(unsigned long data); ++#endif ++static struct timer_list rx_timer; ++ ++/** Lock for state transitions */ ++static spinlock_t rw_lock; ++ ++#if !BT_BLUEDROID_SUPPORT ++/** Notifier block for HCI events */ ++struct notifier_block hci_event_nblock = { ++ .notifier_call = bluesleep_hci_event, ++}; ++#endif ++ ++struct proc_dir_entry *bluetooth_dir, *sleep_dir; ++ ++/* ++ * Local functions ++ */ ++ ++/* ++ * bt go to sleep will call this function tell uart stop data interactive ++ */ ++static void hsuart_power(int on) ++{ ++ if (bsi->uport != NULL) { ++ if (on) ++ bsi->uport->ops->set_mctrl(bsi->uport, TIOCM_RTS); ++ else ++ bsi->uport->ops->set_mctrl(bsi->uport, 0); ++ } else { ++ BT_ERR("bsi->uport = NULL, has_lpm_enabled = %d", ++ has_lpm_enabled); ++ } ++} ++ ++/** ++ * @return 1 if the Host can go to sleep, 0 otherwise. ++ */ ++static inline int bluesleep_can_sleep(void) ++{ ++ /* check if HOST_WAKE_BT_GPIO and BT_WAKE_HOST_GPIO ++ * are both deasserted ++ */ ++ return (gpio_get_value(bsi->ext_wake) != bsi->ext_wake_assert) && ++ (gpio_get_value(bsi->host_wake) != bsi->host_wake_assert) && ++ (!test_bit(BT_RXTIMER, &flags)) && (bsi->uport != NULL); ++} ++ ++/** ++ * @brief@ main sleep work handling function which update the flags ++ * and activate and deactivate UART ,check FIFO. ++ */ ++static void bluesleep_sleep_work(struct work_struct *work) ++{ ++ if (!has_lpm_enabled) ++ return; ++ ++ if (bluesleep_can_sleep()) { ++ /* already asleep, this is an error case */ ++ if (test_bit(BT_ASLEEP, &flags)) { ++ BT_DBG("already asleep"); ++ return; ++ } ++ if (bsi->uport->ops->tx_empty(bsi->uport)) { ++ BT_DBG("going to sleep..."); ++ set_bit(BT_ASLEEP, &flags); ++ /*Deactivating UART */ ++ hsuart_power(0); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ __pm_wakeup_event(bsi->ws, HZ / 2); ++#else ++ wake_lock_timeout(&bsi->wake_lock, HZ / 2); ++#endif ++ } else { ++ BT_DBG("This should never happen.\n"); ++ return; ++ } ++ } else if (test_bit(BT_ASLEEP, &flags)) { ++ BT_DBG("hold wake locks for rx_task."); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ __pm_stay_awake(bsi->ws); ++#else ++ wake_lock(&bsi->wake_lock); ++#endif ++ clear_bit(BT_ASLEEP, &flags); ++ ++ /* Add a timer to make sure that UART ++ * would not be turned on&off very frequentently ++ */ ++ mod_timer(&rx_timer, jiffies + (RX_TIMER_INTERVAL * HZ)); ++ ++ set_bit(BT_RXTIMER, &flags); ++ hsuart_power(1); ++ } else { ++ mod_timer(&rx_timer, jiffies + (RX_TIMER_INTERVAL * HZ)); ++ if (gpio_get_value(bsi->ext_wake) != bsi->ext_wake_assert && ++ !test_bit(BT_TXIDLE, &flags)) { ++ 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); ++ } ++ } ++} ++ ++/** ++ * A tasklet function that runs in tasklet context and reads the value ++ * of the HOST_WAKE GPIO pin and further defer the work. ++ * @param data Not used. ++ */ ++static void bluesleep_hostwake_task(unsigned long data) ++{ ++ BT_DBG("hostwake line change"); ++ spin_lock(&rw_lock); ++ ++ if (gpio_get_value(bsi->host_wake) == bsi->host_wake_assert) ++ bluesleep_rx_busy(); ++ else ++ bluesleep_rx_idle(); ++ ++ spin_unlock(&rw_lock); ++} ++ ++/** ++ * Handles proper timer action when outgoing data is delivered to the ++ * HCI line discipline. Sets BT_TXDATA. ++ */ ++static void bluesleep_outgoing_data(void) ++{ ++ unsigned long irq_flags; ++ int power_on_uart = 0; ++ ++ spin_lock_irqsave(&rw_lock, irq_flags); ++ ++ /* if the tx side is sleeping... */ ++ if (gpio_get_value(bsi->ext_wake) != bsi->ext_wake_assert) { ++ BT_DBG("tx was sleeping, wakeup it"); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ __pm_stay_awake(bsi->ws); ++#else ++ wake_lock(&bsi->wake_lock); ++#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; ++ } ++ ++ spin_unlock_irqrestore(&rw_lock, irq_flags); ++ if (power_on_uart == 1) ++ hsuart_power(1); ++} ++ ++#if BT_BLUEDROID_SUPPORT ++static struct uart_port *bluesleep_get_uart_port(void) ++{ ++ struct uart_port *uport = NULL; ++ ++ if (bluesleep_uart_dev) { ++ uport = platform_get_drvdata(bluesleep_uart_dev); ++ if (uport) ++ BT_DBG("%s get uart_port from blusleep_uart_dev: %s, port irq: %d", ++ __func__, bluesleep_uart_dev->name, uport->irq); ++ } ++ return uport; ++} ++ ++static int bluesleep_lpm_proc_show(struct seq_file *m, void *v) ++{ ++ seq_printf(m, "lpm enable: %d\n", has_lpm_enabled); ++ return 0; ++} ++ ++static int bluesleep_lpm_proc_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, bluesleep_lpm_proc_show, NULL); ++} ++ ++static ssize_t bluesleep_write_proc_lpm(struct file *file, ++ const char __user *buffer, size_t count, ++ loff_t *pos) ++{ ++ char b; ++ ++ if (count < 1) ++ return -EINVAL; ++ ++ if (copy_from_user(&b, buffer, 1)) ++ return -EFAULT; ++ ++ if (b == '0') { ++ /* HCI_DEV_UNREG */ ++ bluesleep_stop(); ++ has_lpm_enabled = false; ++ bsi->uport = NULL; ++ } else { ++ /* HCI_DEV_REG */ ++ if (!has_lpm_enabled) { ++ has_lpm_enabled = true; ++ if (bluesleep_uart_dev) ++ bsi->uport = bluesleep_get_uart_port(); ++ ++ /* if bluetooth started, start bluesleep*/ ++ bluesleep_start(); ++ } ++ } ++ ++ return count; ++} ++ ++static int bluesleep_btwrite_proc_show(struct seq_file *m, void *v) ++{ ++ seq_puts(m, "it's not support\n"); ++ return 0; ++} ++ ++static int bluesleep_btwrite_proc_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, bluesleep_btwrite_proc_show, NULL); ++} ++ ++static ssize_t bluesleep_write_proc_btwrite(struct file *file, ++ const char __user *buffer, ++ size_t count, loff_t *pos) ++{ ++ char b; ++ ++ if (count < 1) ++ return -EINVAL; ++ ++ if (copy_from_user(&b, buffer, 1)) ++ return -EFAULT; ++ ++ /* HCI_DEV_WRITE */ ++ if (b != '0') ++ bluesleep_outgoing_data(); ++ else ++ bluesleep_tx_allow_sleep(); ++ ++ return count; ++} ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(5, 10, 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, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++ .write = bluesleep_write_proc_lpm, ++}; ++static const struct file_operations btwrite_fops = { ++ .owner = THIS_MODULE, ++ .open = bluesleep_btwrite_proc_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++ .write = bluesleep_write_proc_btwrite, ++}; ++#endif ++#else ++/** ++ * Handles HCI device events. ++ * @param this Not used. ++ * @param event The event that occurred. ++ * @param data The HCI device associated with the event. ++ * @return NOTIFY_DONE. ++ */ ++static int bluesleep_hci_event(struct notifier_block *this, unsigned long event, ++ void *data) ++{ ++ struct hci_dev *hdev = (struct hci_dev *)data; ++ struct hci_uart *hu; ++ struct uart_state *state; ++ ++ if (!hdev) ++ return NOTIFY_DONE; ++ ++ switch (event) { ++ case HCI_DEV_REG: ++ if (!bluesleep_hdev) { ++ bluesleep_hdev = hdev; ++ hu = (struct hci_uart *)hdev->driver_data; ++ state = (struct uart_state *)hu->tty->driver_data; ++ bsi->uport = state->uart_port; ++ } ++ break; ++ case HCI_DEV_UNREG: ++ bluesleep_hdev = NULL; ++ bsi->uport = NULL; ++ break; ++ case HCI_DEV_WRITE: ++ bluesleep_outgoing_data(); ++ break; ++ } ++ ++ return NOTIFY_DONE; ++} ++#endif ++ ++/** ++ * Function to check wheather bluetooth can sleep when btwrite was deasserted ++ * by bluedroid. ++ */ ++static void bluesleep_tx_allow_sleep(void) ++{ ++ unsigned long irq_flags; ++ 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); ++ bluesleep_tx_idle(); ++ spin_unlock_irqrestore(&rw_lock, irq_flags); ++} ++ ++/* Handles reception timer expiration. ++ * Clear BT_RXTIMER. ++ * @param data Not used. ++ */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++static void bluesleep_rx_timer_expire(struct timer_list *t) ++#else ++static void bluesleep_rx_timer_expire(unsigned long data) ++#endif ++{ ++ BT_DBG("bluesleep_rx_timer_expire"); ++ clear_bit(BT_RXTIMER, &flags); ++ bluesleep_rx_idle(); ++} ++ ++/** ++ * Schedules a tasklet to run when receiving an interrupt on the ++ * HOST_WAKE GPIO pin. ++ * @param irq Not used. ++ * @param dev_id Not used. ++ */ ++static irqreturn_t bluesleep_hostwake_isr(int irq, void *dev_id) ++{ ++ /* schedule a tasklet to handle the change in the host wake line */ ++ tasklet_schedule(&hostwake_task); ++ return IRQ_HANDLED; ++} ++ ++/** ++ * Starts the Sleep-Mode Protocol on the Host. ++ * @return On success, 0. On error, -1, and errno is set ++ * appropriately. ++ */ ++static int bluesleep_start(void) ++{ ++ int retval; ++ unsigned long irq_flags; ++ ++ spin_lock_irqsave(&rw_lock, irq_flags); ++ ++ if (test_bit(BT_PROTO, &flags)) { ++ spin_unlock_irqrestore(&rw_lock, irq_flags); ++ return 0; ++ } ++ ++ spin_unlock_irqrestore(&rw_lock, irq_flags); ++ ++ if (!atomic_dec_and_test(&open_count)) { ++ atomic_inc(&open_count); ++ return -EBUSY; ++ } ++ ++ /* 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); ++ retval = request_irq(bsi->host_wake_irq, bluesleep_hostwake_isr, ++ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, ++ "bluetooth hostwake", &bsi->pdev->dev); ++ if (retval < 0) { ++ BT_ERR("Couldn't acquire BT_HOST_WAKE IRQ"); ++ goto fail; ++ } ++ ++ set_bit(BT_PROTO, &flags); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ __pm_stay_awake(bsi->ws); ++#else ++ wake_lock(&bsi->wake_lock); ++#endif ++ ++ return 0; ++fail: ++ timer_delete(&rx_timer); ++ atomic_inc(&open_count); ++ ++ return retval; ++} ++ ++/** ++ * Stops the Sleep-Mode Protocol on the Host. ++ */ ++static void bluesleep_stop(void) ++{ ++ unsigned long irq_flags; ++ ++ spin_lock_irqsave(&rw_lock, irq_flags); ++ ++ if (!test_bit(BT_PROTO, &flags)) { ++ spin_unlock_irqrestore(&rw_lock, irq_flags); ++ return; ++ } ++ ++ /* assert BT_WAKE */ ++ gpio_set_value(bsi->ext_wake, bsi->ext_wake_assert); ++ ++ timer_delete(&rx_timer); ++ clear_bit(BT_PROTO, &flags); ++ ++ if (test_bit(BT_ASLEEP, &flags)) { ++ clear_bit(BT_ASLEEP, &flags); ++ hsuart_power(1); ++ } ++ ++ atomic_inc(&open_count); ++ ++ spin_unlock_irqrestore(&rw_lock, irq_flags); ++ free_irq(bsi->host_wake_irq, &bsi->pdev->dev); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ __pm_wakeup_event(bsi->ws, HZ / 2); ++#else ++ wake_lock_timeout(&bsi->wake_lock, HZ / 2); ++#endif ++} ++#if 0 ++/** ++ * Read the BT_WAKE GPIO pin value via the proc interface. ++ * When this function returns, page will contain a 1 if the ++ * pin is high, 0 otherwise. ++ * @param page Buffer for writing data. ++ * @param start Not used. ++ * @param offset Not used. ++ * @param count Not used. ++ * @param eof Whether or not there is more data to be read. ++ * @param data Not used. ++ * @return The number of bytes written. ++ */ ++static int bluepower_read_proc_btwake(char *page, char **start, off_t offset, ++ int count, int *eof, void *data) ++{ ++ *eof = 1; ++ return sprintf(page, "btwake:%u\n", ++ (gpio_get_value(bsi->ext_wake) == bsi->ext_wake_assert)); ++} ++ ++/** ++ * Write the BT_WAKE GPIO pin value via the proc interface. ++ * @param file Not used. ++ * @param buffer The buffer to read from. ++ * @param count The number of bytes to be written. ++ * @param data Not used. ++ * @return On success, the number of bytes written. On error, -1, and ++ * errno is set appropriately. ++ */ ++static int bluepower_write_proc_btwake(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ char *buf; ++ ++ if (count < 1) ++ return -EINVAL; ++ ++ buf = kmalloc(count, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ if (copy_from_user(buf, buffer, count)) { ++ kfree(buf); ++ return -EFAULT; ++ } ++ ++ if (buf[0] == '0') { ++ gpio_set_value(bsi->ext_wake, !bsi->ext_wake_assert); ++ } else if (buf[0] == '1') { ++ gpio_set_value(bsi->ext_wake, bsi->ext_wake_assert); ++ } else { ++ kfree(buf); ++ return -EINVAL; ++ } ++ ++ kfree(buf); ++ return count; ++} ++ ++/** ++ * Read the BT_HOST_WAKE GPIO pin value via the proc interface. ++ * When this function returns, page will contain a 1 if the pin ++ * is high, 0 otherwise. ++ * @param page Buffer for writing data. ++ * @param start Not used. ++ * @param offset Not used. ++ * @param count Not used. ++ * @param eof Whether or not there is more data to be read. ++ * @param data Not used. ++ * @return The number of bytes written. ++ */ ++static int bluepower_read_proc_hostwake(char *page, char **start, off_t offset, ++ int count, int *eof, void *data) ++{ ++ *eof = 1; ++ return sprintf(page, "hostwake: %u\n", ++ (gpio_get_value(bsi->host_wake) == bsi->host_wake_assert)); ++} ++ ++ ++/** ++ * Read the low-power status of the Host via the proc interface. ++ * When this function returns, page contains a 1 if the Host ++ * is asleep, 0 otherwise. ++ * @param page Buffer for writing data. ++ * @param start Not used. ++ * @param offset Not used. ++ * @param count Not used. ++ * @param eof Whether or not there is more data to be read. ++ * @param data Not used. ++ * @return The number of bytes written. ++ */ ++static int bluesleep_read_proc_asleep(char *page, char **start, off_t offset, ++ int count, int *eof, void *data) ++{ ++ unsigned int asleep; ++ ++ asleep = test_bit(BT_ASLEEP, &flags) ? 1 : 0; ++ *eof = 1; ++ return sprintf(page, "asleep: %u\n", asleep); ++} ++ ++/** ++ * Read the low-power protocol being used by the Host via the proc interface. ++ * When this function returns, page will contain a 1 if the Host ++ * is using the Sleep Mode Protocol, 0 otherwise. ++ * @param page Buffer for writing data. ++ * @param start Not used. ++ * @param offset Not used. ++ * @param count Not used. ++ * @param eof Whether or not there is more data to be read. ++ * @param data Not used. ++ * @return The number of bytes written. ++ */ ++static int bluesleep_read_proc_proto(char *page, char **start, off_t offset, ++ int count, int *eof, void *data) ++{ ++ unsigned int proto; ++ ++ proto = test_bit(BT_PROTO, &flags) ? 1 : 0; ++ *eof = 1; ++ return sprintf(page, "proto: %u\n", proto); ++} ++ ++/** ++ * Modify the low-power protocol used by the Host via the proc interface. ++ * @param file Not used. ++ * @param buffer The buffer to read from. ++ * @param count The number of bytes to be written. ++ * @param data Not used. ++ * @return On success, the number of bytes written. On error, -1, and ++ * errno is set appropriately. ++ */ ++static int bluesleep_write_proc_proto(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ char proto; ++ ++ if (count < 1) ++ return -EINVAL; ++ ++ if (copy_from_user(&proto, buffer, 1)) ++ return -EFAULT; ++ ++ if (proto == '0') ++ bluesleep_stop(); ++ else ++ bluesleep_start(); ++ ++ /* claim that we wrote everything */ ++ return count; ++} ++#endif ++ ++static int assert_level = -1; ++module_param(assert_level, int, S_IRUGO); ++MODULE_PARM_DESC(assert_level, "BT_LPM hostwake/btwake assert level"); ++ ++#if 1 ++static struct platform_device *sw_uart_get_pdev(int id) ++{ ++ struct device_node *np; ++ char match[20]; ++ sprintf(match, "uart%d", id); ++ np = of_find_node_by_type(NULL, match); ++ return of_find_device_by_node(np); ++} ++#endif ++ ++static int bluesleep_probe(struct platform_device *pdev) ++{ ++#if 1 ++ struct device_node *np = ++ of_find_compatible_node(NULL, NULL, "allwinner,sunxi-btlpm"); ++ struct device *dev = &pdev->dev; ++ enum of_gpio_flags config; ++ int ret, uart_index; ++ u32 val; ++ ++ bsi = devm_kzalloc(&pdev->dev, sizeof(struct bluesleep_info), ++ GFP_KERNEL); ++ if (!bsi) ++ return -ENOMEM; ++ ++ 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"); ++ ret = -EINVAL; ++ goto err0; ++ } ++ ++ /* set host_wake_assert */ ++ bsi->host_wake_assert = (config == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ BT_DBG("bt_hostwake gpio=%d assert=%d\n", bsi->host_wake, ++ bsi->host_wake_assert); ++ ++ if (assert_level != -1) { ++ bsi->host_wake_assert = (assert_level & 0x02) > 0; ++ BT_DBG("override host_wake assert to %d", ++ bsi->host_wake_assert); ++ } ++ ++ ret = devm_gpio_request(dev, bsi->host_wake, "bt_hostwake"); ++ if (ret < 0) { ++ BT_ERR("can't request bt_hostwake gpio %d\n", bsi->host_wake); ++ 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); ++ goto err1; ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) ++ if (!of_property_read_bool(np, "wakeup-source")) { ++#else ++ if (!of_property_read_u32(np, "wakeup-source", &bsi->wakeup_enable) && ++ (bsi->wakeup_enable == 0)) { ++#endif ++ BT_DBG("wakeup source is disabled!\n"); ++ } else { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) ++ ret = device_init_wakeup(dev, true); ++ if (ret < 0) { ++ BT_ERR("device init wakeup failed!\n"); ++ 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); ++ goto err2; ++ } ++ bsi->wakeup_enable = 1; ++#else ++ BT_ERR("%s kernel unsupport this feature!\r\n", __func__); ++#endif ++ } ++ ++ 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"); ++ 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); ++ goto err2; ++ } ++ ++ /* set ext_wake_assert */ ++ bsi->ext_wake_assert = (config == OF_GPIO_ACTIVE_LOW) ? 0 : 1; ++ BT_DBG("bt_wake gpio=%d assert=%d\n", bsi->ext_wake, ++ bsi->ext_wake_assert); ++ ++ if (assert_level != -1) { ++ bsi->ext_wake_assert = (assert_level & 0x01) > 0; ++ BT_DBG("override ext_wake assert to %d", bsi->ext_wake_assert); ++ } ++ ++ /* 1.set bt_wake as output and the level is assert, assert bt wake */ ++ ret = gpio_direction_output(bsi->ext_wake, bsi->ext_wake_assert); ++ if (ret < 0) { ++ BT_ERR("can't request output direction bt_wake gpio %d\n", ++ bsi->ext_wake); ++ 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); ++ if (bsi->host_wake_irq < 0) { ++ BT_ERR("map gpio [%d] to virq failed, errno = %d\n", ++ bsi->host_wake, bsi->host_wake_irq); ++ ret = -ENODEV; ++ goto err3; ++ } ++ ++ uart_index = DEFAULT_UART_INDEX; ++ if (!of_property_read_u32(np, "uart_index", &val)) { ++ switch (val) { ++ case 0: ++ case 1: ++ case 2: ++ uart_index = val; ++ break; ++ default: ++ BT_ERR("unsupported uart_index (%u)\n", val); ++ } ++ } ++ BT_DBG("uart_index (%u)\n", uart_index); ++ bluesleep_uart_dev = sw_uart_get_pdev(uart_index); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0) ++ bsi->ws = wakeup_source_register(dev, "bluesleep"); ++#else ++ bsi->ws = wakeup_source_register("bluesleep"); ++#endif ++ ++#else ++ 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; ++#endif ++ return 0; ++} ++ ++static int bluesleep_remove(struct platform_device *pdev) ++{ ++ /* 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); ++ timer_delete(&rx_timer); ++ if (test_bit(BT_ASLEEP, &flags)) ++ hsuart_power(1); ++ } ++ gpio_free(bsi->host_wake); ++ gpio_free(bsi->ext_wake); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ wakeup_source_unregister(bsi->ws); ++#else ++ wake_lock_destroy(&bsi->wake_lock); ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) ++ if (bsi->wakeup_enable) { ++ BT_DBG("Deinit wakeup source"); ++ device_init_wakeup(&pdev->dev, false); ++ dev_pm_clear_wake_irq(&pdev->dev); ++ } ++#else ++ BT_ERR("%s kernel unsupport this feature!\r\n", __func__); ++#endif ++ return 0; ++} ++ ++/** ++ * Initializes the module. ++ * @return On success, 0. On error, -1, and errno is set ++ * appropriately. ++ */ ++int bluesleep_init(struct platform_device *pdev) ++{ ++ int retval; ++ struct proc_dir_entry *ent; ++ ++ BT_DBG("BlueSleep Mode Driver Ver %s", VERSION); ++ ++#if 1 ++ retval = bluesleep_probe(pdev); ++ if (retval) ++ return retval; ++#endif ++ ++#if !BT_BLUEDROID_SUPPORT ++ bluesleep_hdev = NULL; ++#endif ++ ++ bluetooth_dir = proc_mkdir("bluetooth", NULL); ++ if (bluetooth_dir == NULL) { ++ BT_ERR("Unable to create /proc/bluetooth directory"); ++ return -ENOMEM; ++ } ++ ++ sleep_dir = proc_mkdir("sleep", bluetooth_dir); ++ if (sleep_dir == NULL) { ++ BT_ERR("Unable to create /proc/%s directory", PROC_DIR); ++ return -ENOMEM; ++ } ++#if 0 ++ /* Creating read/write "btwake" entry */ ++ ent = create_proc_entry("btwake", 0, sleep_dir); ++ if (ent == NULL) { ++ BT_ERR("Unable to create /proc/%s/btwake entry", PROC_DIR); ++ retval = -ENOMEM; ++ goto fail; ++ } ++ ent->read_proc = bluepower_read_proc_btwake; ++ ent->write_proc = bluepower_write_proc_btwake; ++ ++ /* read only proc entries */ ++ if (create_proc_read_entry("hostwake", 0, sleep_dir, ++ bluepower_read_proc_hostwake, NULL) == NULL) { ++ BT_ERR("Unable to create /proc/%s/hostwake entry", PROC_DIR); ++ retval = -ENOMEM; ++ goto fail; ++ } ++ ++ /* read/write proc entries */ ++ ent = create_proc_entry("proto", 0666, sleep_dir); ++ if (ent == NULL) { ++ BT_ERR("Unable to create /proc/%s/proto entry", PROC_DIR); ++ retval = -ENOMEM; ++ goto fail; ++ } ++ ent->read_proc = bluesleep_read_proc_proto; ++ ent->write_proc = bluesleep_write_proc_proto; ++ ++ /* read only proc entries */ ++ if (create_proc_read_entry("asleep", 0, ++ sleep_dir, bluesleep_read_proc_asleep, NULL) == NULL) { ++ BT_ERR("Unable to create /proc/%s/asleep entry", PROC_DIR); ++ retval = -ENOMEM; ++ goto fail; ++ } ++#endif ++#if BT_BLUEDROID_SUPPORT ++ /* read/write proc entries */ ++ ent = proc_create("lpm", 0660, sleep_dir, &lpm_fops); ++ if (ent == NULL) { ++ BT_ERR("Unable to create /proc/%s/lpm entry", PROC_DIR); ++ retval = -ENOMEM; ++ goto fail; ++ } ++ ++ ent = proc_create("btwrite", 0660, sleep_dir, &btwrite_fops); ++ if (ent == NULL) { ++ BT_ERR("Unable to create /proc/%s/btwrite entry", PROC_DIR); ++ retval = -ENOMEM; ++ goto fail; ++ } ++#endif ++ ++ flags = 0; /* clear all status bits */ ++ ++ /* Initialize spinlock. */ ++ spin_lock_init(&rw_lock); ++ ++ /* Initialize timer */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ timer_setup(&rx_timer, bluesleep_rx_timer_expire, 0); ++#else ++ init_timer(&rx_timer); ++ rx_timer.function = bluesleep_rx_timer_expire; ++ rx_timer.data = 0; ++#endif ++ ++ /* initialize host wake tasklet */ ++ tasklet_init(&hostwake_task, bluesleep_hostwake_task, 0); ++ ++#if !BT_BLUEDROID_SUPPORT ++ hci_register_notifier(&hci_event_nblock); ++#endif ++ ++ return 0; ++ ++fail: ++#if BT_BLUEDROID_SUPPORT ++ remove_proc_entry("btwrite", sleep_dir); ++ remove_proc_entry("lpm", sleep_dir); ++#endif ++#if 0 ++ remove_proc_entry("asleep", sleep_dir); ++ remove_proc_entry("proto", sleep_dir); ++ remove_proc_entry("hostwake", sleep_dir); ++ remove_proc_entry("btwake", sleep_dir); ++#endif ++ remove_proc_entry("sleep", bluetooth_dir); ++ remove_proc_entry("bluetooth", 0); ++ return retval; ++} ++ ++/** ++ * Cleans up the module. ++ */ ++int bluesleep_exit(struct platform_device *dev) ++{ ++#if !BT_BLUEDROID_SUPPORT ++ hci_unregister_notifier(&hci_event_nblock); ++#endif ++ ++#if BT_BLUEDROID_SUPPORT ++ remove_proc_entry("btwrite", sleep_dir); ++ remove_proc_entry("lpm", sleep_dir); ++#endif ++#if 0 ++ remove_proc_entry("asleep", sleep_dir); ++ remove_proc_entry("proto", sleep_dir); ++ remove_proc_entry("hostwake", sleep_dir); ++ remove_proc_entry("btwake", sleep_dir); ++#endif ++ remove_proc_entry("sleep", bluetooth_dir); ++ remove_proc_entry("bluetooth", 0); ++ bluesleep_remove(dev); ++ return 0; ++} +diff --git a/drivers/net/wireless/aic8800/aic8800_btlpm/lpm.h b/drivers/net/wireless/aic8800/aic8800_btlpm/lpm.h +new file mode 100755 +index 000000000..8b3973604 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_btlpm/lpm.h +@@ -0,0 +1,20 @@ ++/* ++ * 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/drivers/net/wireless/aic8800/aic8800_btlpm/rfkill.c b/drivers/net/wireless/aic8800/aic8800_btlpm/rfkill.c +new file mode 100755 +index 000000000..89879ac3f +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_btlpm/rfkill.c +@@ -0,0 +1,79 @@ ++/* ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#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/drivers/net/wireless/aic8800/aic8800_btlpm/rfkill.h b/drivers/net/wireless/aic8800/aic8800_btlpm/rfkill.h +new file mode 100755 +index 000000000..ce0d5761a +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_btlpm/rfkill.h +@@ -0,0 +1,17 @@ ++/* ++ * 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/drivers/net/wireless/aic8800/aic8800_fdrv/Kconfig b/drivers/net/wireless/aic8800/aic8800_fdrv/Kconfig +new file mode 100755 +index 000000000..33728e7fb +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/Kconfig +@@ -0,0 +1,7 @@ ++config AIC8800_WLAN_SUPPORT ++ tristate "AIC8800 wlan Support" ++ default y ++ help ++ This is support for the aic8800 cfg80211 full-MAC wifi driver ++ (aic8800_fdrv). Built-in (y) by default — see the aic8800 port ++ notes in warden-sdk/kernel/rv1106-enablement/wifi/. +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/Makefile b/drivers/net/wireless/aic8800/aic8800_fdrv/Makefile +new file mode 100755 +index 000000000..26138f09d +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/Makefile +@@ -0,0 +1,94 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++# ++# aic8800_fdrv — the cfg80211 full-MAC driver ("fdrv"), ported in-tree from ++# the vendor out-of-tree Makefile (flare-edge/sdk/sysdrv/drv_ko/wifi/ ++# aic8800dc/aic8800_fdrv/Makefile). SDIO-only build (this board has no ++# USB/PCI variant) — usb_host.c and rwnx_pci.c are dropped from the tree ++# entirely (PORT-PLAN.md §4.1 flagged both as candidates to drop "unless a ++# build error proves them referenced elsewhere" — that held for these two). ++# rwnx_mesh.c was ALSO dropped initially on the same theory but had to be ++# restored: rwnx_tx.c's NL80211_IFTYPE_MESH_POINT switch-case is not ++# preprocessor-gated, so rwnx_mesh.h's types/prototypes are needed to ++# compile even though this board never creates a mesh-type interface. ++# md5.o: fdrv carries its OWN copy (vendor ships md5.c in both aic8800_bsp/ and ++# aic8800_fdrv/). As separate modules each .ko needs its own MD5 — bsp does not ++# EXPORT_SYMBOL(MD5Init/...), so fdrv.ko cannot resolve them from aic8800_bsp.ko ++# (modpost: "MD5Final undefined"). The two copies are byte-identical and live in ++# separate module namespaces, so there is no collision. (When these were briefly ++# built =y this object was dropped to avoid a vmlinux multiple-definition; the ++# module build restores it.) ++ ++ccflags-y += -DCONFIG_RWNX_FULLMAC ++ccflags-y += -DAICWF_SDIO_SUPPORT ++ccflags-y += -DCONFIG_SDIO_PWRCTRL ++ccflags-y += -DCONFIG_PLATFORM_ROCKCHIP ++ccflags-y += -DCONFIG_START_FROM_BOOTROM ++ccflags-y += -DCONFIG_PMIC_SETTING ++ccflags-y += -DCONFIG_VRF_DCDC_MODE ++ccflags-y += -DCONFIG_ROM_PATCH_EN ++ccflags-y += -DCONFIG_RWNX_RADAR ++ccflags-y += -DCONFIG_RWNX_BCMC ++ccflags-y += -DNX_TXQ_CNT=5 ++ccflags-y += -DCONFIG_USER_MAX=1 ++ccflags-y += -DCONFIG_RWNX_DBG ++ccflags-y += -DUSE_5G ++ccflags-y += -DCONFIG_TXRX_THREAD_PRIO ++ccflags-y += -DCONFIG_SUPPORT_REALTIME_CHANGE_MAC ++ccflags-y += -DCONFIG_PREALLOC_TXQ ++ccflags-y += -DCONFIG_DPD -DCONFIG_FORCE_DPD_CALIB ++ccflags-y += -DCONFIG_FILTER_TCP_ACK ++ccflags-y += -DCONFIG_RESV_MEM_SUPPORT ++ccflags-y += -DCONFIG_SHUTDOWN_CALLBACK ++ccflags-y += -DCONFIG_MCC ++ccflags-y += -DCONFIG_RFTEST ++ccflags-y += -DCONFIG_RX_NETIF_RECV_SKB ++ccflags-y += -DAICWF_RX_REORDER ++ccflags-y += -DAICWF_ARP_OFFLOAD ++ ++# FW/IPC sizing (vendor 8800DCDW u02 variant) ++ccflags-y += -DNX_VIRT_DEV_MAX=4 ++ccflags-y += -DNX_REMOTE_STA_MAX_FOR_OLD_IC=10 ++ccflags-y += -DNX_REMOTE_STA_MAX=32 ++ccflags-y += -DNX_MU_GROUP_MAX=62 ++ccflags-y += -DNX_TXDESC_CNT=64 ++ccflags-y += -DNX_TX_MAX_RATES=4 ++ccflags-y += -DNX_CHAN_CTXT_CNT=3 ++ccflags-y += -DDEFAULT_COUNTRY_CODE=\"00\" ++ccflags-y += -DAIC_TRACE_INCLUDE_PATH=$(src) ++ ++ccflags-y += -I$(srctree)/$(src)/../aic8800_bsp ++ccflags-y += -Wno-implicit-fallthrough -Wno-unused-function -Wno-unused-variable ++ ++obj-$(CONFIG_AIC8800_WLAN_SUPPORT) += aic8800_fdrv.o ++aic8800_fdrv-y := \ ++ md5.o \ ++ rwnx_msg_tx.o \ ++ rwnx_msg_rx.o \ ++ rwnx_utils.o \ ++ rwnx_cmds.o \ ++ rwnx_irqs.o \ ++ rwnx_cfgfile.o \ ++ rwnx_strs.o \ ++ rwnx_rx.o \ ++ rwnx_tx.o \ ++ rwnx_txq.o \ ++ rwnx_main.o \ ++ rwnx_mod_params.o \ ++ rwnx_mesh.o \ ++ rwnx_platform.o \ ++ rwnx_dini.o \ ++ rwnx_v7.o \ ++ ipc_host.o \ ++ rwnx_tdls.o \ ++ aic_vendor.o \ ++ aicwf_compat_8800dc.o \ ++ aicwf_compat_8800d80.o \ ++ rwnx_wakelock.o \ ++ regdb.o \ ++ aic_priv_cmd.o \ ++ aicwf_rx_prealloc.o \ ++ rwnx_radar.o \ ++ sdio_host.o \ ++ aicwf_txrxif.o \ ++ aicwf_sdio.o \ ++ aicwf_tcp_ack.o +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/aic_br_ext.c b/drivers/net/wireless/aic8800/aic8800_fdrv/aic_br_ext.c +new file mode 100755 +index 000000000..c86fe7d35 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/aic_br_ext.c +@@ -0,0 +1,1737 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * 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. ++ * ++ *****************************************************************************/ ++#define _AIC_BR_EXT_C_ ++ ++#ifdef __KERNEL__ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "rwnx_defs.h" ++#endif ++ ++#ifdef CL_IPV6_PASS ++#ifdef __KERNEL__ ++#include ++#include ++#include ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)) ++#include ++#else ++#include ++#endif ++#endif ++#endif ++ ++#ifdef CONFIG_BR_SUPPORT ++ ++/* #define BR_SUPPORT_DEBUG */ ++ ++#define NAT25_IPV4 01 ++#define NAT25_IPV6 02 ++#define NAT25_IPX 03 ++#define NAT25_APPLE 04 ++#define NAT25_PPPOE 05 ++ ++#define RTL_RELAY_TAG_LEN (ETH_ALEN) ++#define TAG_HDR_LEN 4 ++ ++#define MAGIC_CODE 0x8186 ++#define MAGIC_CODE_LEN 2 ++#define WAIT_TIME_PPPOE 5 /* waiting time for pppoe server in sec */ ++ ++/*----------------------------------------------------------------- ++ How database records network address: ++ 0 1 2 3 4 5 6 7 8 9 10 ++ |----|----|----|----|----|----|----|----|----|----|----| ++ IPv4 |type| | IP addr | ++ IPX |type| Net addr | Node addr | ++ IPX |type| Net addr |Sckt addr| ++ Apple |type| Network |node| ++ PPPoE |type| SID | AC MAC | ++-----------------------------------------------------------------*/ ++ ++/* Find a tag in pppoe frame and return the pointer */ ++static __inline__ unsigned char *__nat25_find_pppoe_tag(struct pppoe_hdr *ph, ++ unsigned short type) ++{ ++ unsigned char *cur_ptr, *start_ptr; ++ unsigned short tagLen, tagType; ++ ++ start_ptr = cur_ptr = (unsigned char *)ph->tag; ++ while ((cur_ptr - start_ptr) < ntohs(ph->length)) { ++ /* prevent un-alignment access */ ++ tagType = (unsigned short)((cur_ptr[0] << 8) + cur_ptr[1]); ++ tagLen = (unsigned short)((cur_ptr[2] << 8) + cur_ptr[3]); ++ if (tagType == type) ++ return cur_ptr; ++ cur_ptr = cur_ptr + TAG_HDR_LEN + tagLen; ++ } ++ return 0; ++} ++ ++static __inline__ int __nat25_add_pppoe_tag(struct sk_buff *skb, ++ struct pppoe_tag *tag) ++{ ++ struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN); ++ int data_len; ++ ++ data_len = tag->tag_len + TAG_HDR_LEN; ++ if (skb_tailroom(skb) < data_len) { ++ printk("skb_tailroom() failed in add SID tag!\n"); ++ return -1; ++ } ++ ++ skb_put(skb, data_len); ++ /* have a room for new tag */ ++ memmove(((unsigned char *)ph->tag + data_len), (unsigned char *)ph->tag, ++ ntohs(ph->length)); ++ ph->length = htons(ntohs(ph->length) + data_len); ++ memcpy((unsigned char *)ph->tag, tag, data_len); ++ return data_len; ++} ++ ++static int skb_pull_and_merge(struct sk_buff *skb, unsigned char *src, int len) ++{ ++ int tail_len; ++ unsigned long end, tail; ++ ++ if ((src + len) > skb_tail_pointer(skb) || skb->len < len) ++ return -1; ++ ++ tail = (unsigned long)skb_tail_pointer(skb); ++ end = (unsigned long)src + len; ++ if (tail < end) ++ return -1; ++ ++ tail_len = (int)(tail - end); ++ if (tail_len > 0) ++ memmove(src, src + len, tail_len); ++ ++ skb_trim(skb, skb->len - len); ++ return 0; ++} ++ ++static __inline__ unsigned long __nat25_timeout(struct rwnx_vif *vif) ++{ ++ unsigned long timeout; ++ ++ timeout = jiffies - NAT25_AGEING_TIME * HZ; ++ ++ return timeout; ++} ++ ++static __inline__ int __nat25_has_expired(struct rwnx_vif *vif, ++ struct nat25_network_db_entry *fdb) ++{ ++ if (time_before_eq(fdb->ageing_timer, __nat25_timeout(vif))) ++ return 1; ++ ++ return 0; ++} ++ ++static __inline__ void ++__nat25_generate_ipv4_network_addr(unsigned char *networkAddr, ++ unsigned int *ipAddr) ++{ ++ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); ++ ++ networkAddr[0] = NAT25_IPV4; ++ memcpy(networkAddr + 7, (unsigned char *)ipAddr, 4); ++} ++ ++static __inline__ void ++__nat25_generate_ipx_network_addr_with_node(unsigned char *networkAddr, ++ unsigned int *ipxNetAddr, ++ unsigned char *ipxNodeAddr) ++{ ++ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); ++ ++ networkAddr[0] = NAT25_IPX; ++ memcpy(networkAddr + 1, (unsigned char *)ipxNetAddr, 4); ++ memcpy(networkAddr + 5, ipxNodeAddr, 6); ++} ++ ++static __inline__ void ++__nat25_generate_ipx_network_addr_with_socket(unsigned char *networkAddr, ++ unsigned int *ipxNetAddr, ++ unsigned short *ipxSocketAddr) ++{ ++ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); ++ ++ networkAddr[0] = NAT25_IPX; ++ memcpy(networkAddr + 1, (unsigned char *)ipxNetAddr, 4); ++ memcpy(networkAddr + 5, (unsigned char *)ipxSocketAddr, 2); ++} ++ ++static __inline__ void ++__nat25_generate_apple_network_addr(unsigned char *networkAddr, ++ unsigned short *network, ++ unsigned char *node) ++{ ++ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); ++ ++ networkAddr[0] = NAT25_APPLE; ++ memcpy(networkAddr + 1, (unsigned char *)network, 2); ++ networkAddr[3] = *node; ++} ++ ++static __inline__ void ++__nat25_generate_pppoe_network_addr(unsigned char *networkAddr, ++ unsigned char *ac_mac, unsigned short *sid) ++{ ++ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); ++ ++ networkAddr[0] = NAT25_PPPOE; ++ memcpy(networkAddr + 1, (unsigned char *)sid, 2); ++ memcpy(networkAddr + 3, (unsigned char *)ac_mac, 6); ++} ++ ++#ifdef CL_IPV6_PASS ++static void __nat25_generate_ipv6_network_addr(unsigned char *networkAddr, ++ unsigned int *ipAddr) ++{ ++ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); ++ ++ networkAddr[0] = NAT25_IPV6; ++ memcpy(networkAddr + 1, (unsigned char *)ipAddr, 16); ++} ++ ++static unsigned char *scan_tlv(unsigned char *data, int len, unsigned char tag, ++ unsigned char len8b) ++{ ++ while (len > 0) { ++ if (*data == tag && *(data + 1) == len8b && len >= len8b * 8) ++ return data + 2; ++ ++ len -= (*(data + 1)) * 8; ++ data += (*(data + 1)) * 8; ++ } ++ return NULL; ++} ++ ++static int update_nd_link_layer_addr(unsigned char *data, int len, ++ unsigned char *replace_mac) ++{ ++ struct icmp6hdr *icmphdr = (struct icmp6hdr *)data; ++ unsigned char *mac; ++ ++ if (icmphdr->icmp6_type == NDISC_ROUTER_SOLICITATION) { ++ if (len >= 8) { ++ mac = scan_tlv(&data[8], len - 8, 1, 1); ++ if (mac) { ++ printk("Router Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ mac[0], mac[1], mac[2], mac[3], mac[4], ++ mac[5], replace_mac[0], replace_mac[1], ++ replace_mac[2], replace_mac[3], ++ replace_mac[4], replace_mac[5]); ++ memcpy(mac, replace_mac, 6); ++ return 1; ++ } ++ } ++ } else if (icmphdr->icmp6_type == NDISC_ROUTER_ADVERTISEMENT) { ++ if (len >= 16) { ++ mac = scan_tlv(&data[16], len - 16, 1, 1); ++ if (mac) { ++ printk("Router Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ mac[0], mac[1], mac[2], mac[3], mac[4], ++ mac[5], replace_mac[0], replace_mac[1], ++ replace_mac[2], replace_mac[3], ++ replace_mac[4], replace_mac[5]); ++ memcpy(mac, replace_mac, 6); ++ return 1; ++ } ++ } ++ } else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) { ++ if (len >= 24) { ++ mac = scan_tlv(&data[24], len - 24, 1, 1); ++ if (mac) { ++ printk("Neighbor Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ mac[0], mac[1], mac[2], mac[3], mac[4], ++ mac[5], replace_mac[0], replace_mac[1], ++ replace_mac[2], replace_mac[3], ++ replace_mac[4], replace_mac[5]); ++ memcpy(mac, replace_mac, 6); ++ return 1; ++ } ++ } ++ } else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT) { ++ if (len >= 24) { ++ mac = scan_tlv(&data[24], len - 24, 2, 1); ++ if (mac) { ++ printk("Neighbor Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ mac[0], mac[1], mac[2], mac[3], mac[4], ++ mac[5], replace_mac[0], replace_mac[1], ++ replace_mac[2], replace_mac[3], ++ replace_mac[4], replace_mac[5]); ++ memcpy(mac, replace_mac, 6); ++ return 1; ++ } ++ } ++ } else if (icmphdr->icmp6_type == NDISC_REDIRECT) { ++ if (len >= 40) { ++ mac = scan_tlv(&data[40], len - 40, 2, 1); ++ if (mac) { ++ printk("Redirect, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ mac[0], mac[1], mac[2], mac[3], mac[4], ++ mac[5], replace_mac[0], replace_mac[1], ++ replace_mac[2], replace_mac[3], ++ replace_mac[4], replace_mac[5]); ++ memcpy(mac, replace_mac, 6); ++ return 1; ++ } ++ } ++ } ++ return 0; ++} ++ ++#ifdef SUPPORT_RX_UNI2MCAST ++static void convert_ipv6_mac_to_mc(struct sk_buff *skb) ++{ ++ struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + ETH_HLEN); ++ unsigned char *dst_mac = skb->data; ++ ++ /* dst_mac[0] = 0xff; */ ++ /* dst_mac[1] = 0xff; */ ++ /*modified by qinjunjie,ipv6 multicast address ix 0x33-33-xx-xx-xx-xx*/ ++ dst_mac[0] = 0x33; ++ dst_mac[1] = 0x33; ++ memcpy(&dst_mac[2], &iph->daddr.s6_addr32[3], 4); ++#if defined(__LINUX_2_6__) ++ /*modified by qinjunjie,warning:should not remove next line*/ ++ skb->pkt_type = PACKET_MULTICAST; ++#endif ++} ++#endif /* CL_IPV6_PASS */ ++#endif /* SUPPORT_RX_UNI2MCAST */ ++ ++static __inline__ int __nat25_network_hash(unsigned char *networkAddr) ++{ ++ if (networkAddr[0] == NAT25_IPV4) { ++ unsigned long x; ++ ++ x = networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ ++ networkAddr[10]; ++ ++ return x & (NAT25_HASH_SIZE - 1); ++ } else if (networkAddr[0] == NAT25_IPX) { ++ unsigned long x; ++ ++ x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ ++ networkAddr[4] ^ networkAddr[5] ^ networkAddr[6] ^ ++ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ ++ networkAddr[10]; ++ ++ return x & (NAT25_HASH_SIZE - 1); ++ } else if (networkAddr[0] == NAT25_APPLE) { ++ unsigned long x; ++ ++ x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3]; ++ ++ return x & (NAT25_HASH_SIZE - 1); ++ } else if (networkAddr[0] == NAT25_PPPOE) { ++ unsigned long x; ++ ++ x = networkAddr[0] ^ networkAddr[1] ^ networkAddr[2] ^ ++ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ ++ networkAddr[6] ^ networkAddr[7] ^ networkAddr[8]; ++ ++ return x & (NAT25_HASH_SIZE - 1); ++ } ++#ifdef CL_IPV6_PASS ++ else if (networkAddr[0] == NAT25_IPV6) { ++ unsigned long x; ++ ++ x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ ++ networkAddr[4] ^ networkAddr[5] ^ networkAddr[6] ^ ++ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ ++ networkAddr[10] ^ networkAddr[11] ^ networkAddr[12] ^ ++ networkAddr[13] ^ networkAddr[14] ^ networkAddr[15] ^ ++ networkAddr[16]; ++ ++ return x & (NAT25_HASH_SIZE - 1); ++ } ++#endif ++ else { ++ unsigned long x = 0; ++ int i; ++ ++ for (i = 0; i < MAX_NETWORK_ADDR_LEN; i++) ++ x ^= networkAddr[i]; ++ ++ return x & (NAT25_HASH_SIZE - 1); ++ } ++} ++ ++static __inline__ void __network_hash_link(struct rwnx_vif *vif, ++ struct nat25_network_db_entry *ent, ++ int hash) ++{ ++ /* Caller must _enter_critical_bh already! */ ++ /* _irqL irqL; */ ++ /* _enter_critical_bh(&priv->br_ext_lock, &irqL); */ ++ ++ ent->next_hash = vif->nethash[hash]; ++ if (ent->next_hash != NULL) ++ ent->next_hash->pprev_hash = &ent->next_hash; ++ vif->nethash[hash] = ent; ++ ent->pprev_hash = &vif->nethash[hash]; ++ ++ /* _exit_critical_bh(&priv->br_ext_lock, &irqL); */ ++} ++ ++static __inline__ void __network_hash_unlink(struct nat25_network_db_entry *ent) ++{ ++ /* Caller must _enter_critical_bh already! */ ++ /* _irqL irqL; */ ++ /* _enter_critical_bh(&priv->br_ext_lock, &irqL); */ ++ ++ *(ent->pprev_hash) = ent->next_hash; ++ if (ent->next_hash != NULL) ++ ent->next_hash->pprev_hash = ent->pprev_hash; ++ ent->next_hash = NULL; ++ ent->pprev_hash = NULL; ++ ++ /* _exit_critical_bh(&priv->br_ext_lock, &irqL); */ ++} ++ ++static int __nat25_db_network_lookup_and_replace(struct rwnx_vif *vif, ++ struct sk_buff *skb, ++ unsigned char *networkAddr) ++{ ++ struct nat25_network_db_entry *db; ++ spin_lock_bh(&vif->br_ext_lock); ++ ++ db = vif->nethash[__nat25_network_hash(networkAddr)]; ++ while (db != NULL) { ++ if (!memcmp(db->networkAddr, networkAddr, ++ MAX_NETWORK_ADDR_LEN)) { ++ if (!__nat25_has_expired(vif, db)) { ++ /* replace the destination mac address */ ++ memcpy(skb->data, db->macAddr, ETH_ALEN); ++ atomic_inc(&db->use_count); ++ ++#ifdef CL_IPV6_PASS ++ printk("NAT25: Lookup M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" ++ "%02x%02x%02x%02x%02x%02x\n", ++ db->macAddr[0], db->macAddr[1], ++ db->macAddr[2], db->macAddr[3], ++ db->macAddr[4], db->macAddr[5], ++ db->networkAddr[0], db->networkAddr[1], ++ db->networkAddr[2], db->networkAddr[3], ++ db->networkAddr[4], db->networkAddr[5], ++ db->networkAddr[6], db->networkAddr[7], ++ db->networkAddr[8], db->networkAddr[9], ++ db->networkAddr[10], db->networkAddr[11], ++ db->networkAddr[12], db->networkAddr[13], ++ db->networkAddr[14], db->networkAddr[15], ++ db->networkAddr[16]); ++#else ++ printk("NAT25: Lookup M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", ++ db->macAddr[0], db->macAddr[1], ++ db->macAddr[2], db->macAddr[3], ++ db->macAddr[4], db->macAddr[5], ++ db->networkAddr[0], db->networkAddr[1], ++ db->networkAddr[2], db->networkAddr[3], ++ db->networkAddr[4], db->networkAddr[5], ++ db->networkAddr[6], db->networkAddr[7], ++ db->networkAddr[8], db->networkAddr[9], ++ db->networkAddr[10]); ++#endif ++ } ++ spin_unlock_bh(&vif->br_ext_lock); ++ return 1; ++ } ++ ++ db = db->next_hash; ++ } ++ ++ spin_unlock_bh(&vif->br_ext_lock); ++ return 0; ++} ++ ++static void __nat25_db_network_insert(struct rwnx_vif *vif, ++ unsigned char *macAddr, ++ unsigned char *networkAddr) ++{ ++ struct nat25_network_db_entry *db; ++ int hash; ++ spin_lock_bh(&vif->br_ext_lock); ++ ++ hash = __nat25_network_hash(networkAddr); ++ db = vif->nethash[hash]; ++ ++ while (db != NULL) { ++ if (!memcmp(db->networkAddr, networkAddr, ++ MAX_NETWORK_ADDR_LEN)) { ++ memcpy(db->macAddr, macAddr, ETH_ALEN); ++ db->ageing_timer = jiffies; ++ spin_unlock_bh(&vif->br_ext_lock); ++ return; ++ } ++ ++ db = db->next_hash; ++ } ++ ++ db = (struct nat25_network_db_entry *)kmalloc( ++ sizeof(*db), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); ++ if (db == NULL) { ++ spin_unlock_bh(&vif->br_ext_lock); ++ return; ++ } ++ ++ memcpy(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN); ++ memcpy(db->macAddr, macAddr, ETH_ALEN); ++ atomic_set(&db->use_count, 1); ++ db->ageing_timer = jiffies; ++ ++ __network_hash_link(vif, db, hash); ++ ++ spin_unlock_bh(&vif->br_ext_lock); ++} ++ ++static void __nat25_db_print(struct rwnx_vif *vif) ++{ ++ spin_lock_bh(&vif->br_ext_lock); ++ ++#ifdef BR_SUPPORT_DEBUG ++ static int counter = 0; ++ int i, j; ++ struct nat25_network_db_entry *db; ++ ++ counter++; ++ if ((counter % 16) != 0) ++ return; ++ ++ for (i = 0, j = 0; i < NAT25_HASH_SIZE; i++) { ++ db = vif->nethash[i]; ++ ++ while (db != NULL) { ++#ifdef CL_IPV6_PASS ++ printk("NAT25: DB(%d) H(%02d) C(%d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" ++ "%02x%02x%02x%02x%02x%02x\n", ++ j, i, atomic_read(&db->use_count), ++ db->macAddr[0], db->macAddr[1], db->macAddr[2], ++ db->macAddr[3], db->macAddr[4], db->macAddr[5], ++ db->networkAddr[0], db->networkAddr[1], ++ db->networkAddr[2], db->networkAddr[3], ++ db->networkAddr[4], db->networkAddr[5], ++ db->networkAddr[6], db->networkAddr[7], ++ db->networkAddr[8], db->networkAddr[9], ++ db->networkAddr[10], db->networkAddr[11], ++ db->networkAddr[12], db->networkAddr[13], ++ db->networkAddr[14], db->networkAddr[15], ++ db->networkAddr[16]); ++#else ++ printk("NAT25: DB(%d) H(%02d) C(%d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", ++ j, i, atomic_read(&db->use_count), ++ db->macAddr[0], db->macAddr[1], db->macAddr[2], ++ db->macAddr[3], db->macAddr[4], db->macAddr[5], ++ db->networkAddr[0], db->networkAddr[1], ++ db->networkAddr[2], db->networkAddr[3], ++ db->networkAddr[4], db->networkAddr[5], ++ db->networkAddr[6], db->networkAddr[7], ++ db->networkAddr[8], db->networkAddr[9], ++ db->networkAddr[10]); ++#endif ++ j++; ++ ++ db = db->next_hash; ++ } ++ } ++#endif ++ ++ spin_unlock_bh(&vif->br_ext_lock); ++} ++ ++/* ++ * NAT2.5 interface ++ */ ++ ++void nat25_db_cleanup(struct rwnx_vif *vif) ++{ ++ int i; ++ spin_lock_bh(&vif->br_ext_lock); ++ ++ for (i = 0; i < NAT25_HASH_SIZE; i++) { ++ struct nat25_network_db_entry *f; ++ f = vif->nethash[i]; ++ while (f != NULL) { ++ struct nat25_network_db_entry *g; ++ ++ g = f->next_hash; ++ if (vif->scdb_entry == f) { ++ memset(vif->scdb_mac, 0, ETH_ALEN); ++ memset(vif->scdb_ip, 0, 4); ++ vif->scdb_entry = NULL; ++ } ++ __network_hash_unlink(f); ++ kfree(f); ++ ++ f = g; ++ } ++ } ++ ++ spin_unlock_bh(&vif->br_ext_lock); ++} ++ ++void nat25_db_expire(struct rwnx_vif *vif) ++{ ++ int i; ++ spin_lock_bh(&vif->br_ext_lock); ++ ++ /* if(!priv->ethBrExtInfo.nat25_disable) */ ++ { ++ for (i = 0; i < NAT25_HASH_SIZE; i++) { ++ struct nat25_network_db_entry *f; ++ f = vif->nethash[i]; ++ ++ while (f != NULL) { ++ struct nat25_network_db_entry *g; ++ g = f->next_hash; ++ ++ if (__nat25_has_expired(vif, f)) { ++ if (atomic_dec_and_test( ++ &f->use_count)) { ++#ifdef BR_SUPPORT_DEBUG ++#ifdef CL_IPV6_PASS ++ panic_printk( ++ "NAT25 Expire H(%02d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" ++ "%02x%02x%02x%02x%02x%02x\n", ++ i, f->macAddr[0], ++ f->macAddr[1], ++ f->macAddr[2], ++ f->macAddr[3], ++ f->macAddr[4], ++ f->macAddr[5], ++ f->networkAddr[0], ++ f->networkAddr[1], ++ f->networkAddr[2], ++ f->networkAddr[3], ++ f->networkAddr[4], ++ f->networkAddr[5], ++ f->networkAddr[6], ++ f->networkAddr[7], ++ f->networkAddr[8], ++ f->networkAddr[9], ++ f->networkAddr[10], ++ f->networkAddr[11], ++ f->networkAddr[12], ++ f->networkAddr[13], ++ f->networkAddr[14], ++ f->networkAddr[15], ++ f->networkAddr[16]); ++#else ++ ++ panic_printk( ++ "NAT25 Expire H(%02d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", ++ i, f->macAddr[0], ++ f->macAddr[1], ++ f->macAddr[2], ++ f->macAddr[3], ++ f->macAddr[4], ++ f->macAddr[5], ++ f->networkAddr[0], ++ f->networkAddr[1], ++ f->networkAddr[2], ++ f->networkAddr[3], ++ f->networkAddr[4], ++ f->networkAddr[5], ++ f->networkAddr[6], ++ f->networkAddr[7], ++ f->networkAddr[8], ++ f->networkAddr[9], ++ f->networkAddr[10]); ++#endif ++#endif ++ if (vif->scdb_entry == f) { ++ memset(vif->scdb_mac, 0, ++ ETH_ALEN); ++ memset(vif->scdb_ip, 0, ++ 4); ++ vif->scdb_entry = NULL; ++ } ++ __network_hash_unlink(f); ++ kfree(f); ++ } ++ } ++ ++ f = g; ++ } ++ } ++ } ++ ++ spin_unlock_bh(&vif->br_ext_lock); ++} ++ ++#ifdef SUPPORT_TX_MCAST2UNI ++static int checkIPMcAndReplace(struct rwnx_vif *vif, struct sk_buff *skb, ++ unsigned int *dst_ip) ++{ ++ struct stat_info *pstat; ++ struct list_head *phead, *plist; ++ int i; ++ ++ phead = &vif->asoc_list; ++ plist = phead->next; ++ ++ while (plist != phead) { ++ pstat = list_entry(plist, struct stat_info, asoc_list); ++ plist = plist->next; ++ ++ if (pstat->ipmc_num == 0) ++ continue; ++ ++ for (i = 0; i < MAX_IP_MC_ENTRY; i++) { ++ if (pstat->ipmc[i].used && ++ !memcmp(&pstat->ipmc[i].mcmac[3], ++ ((unsigned char *)dst_ip) + 1, 3)) { ++ memcpy(skb->data, pstat->ipmc[i].mcmac, ++ ETH_ALEN); ++ return 1; ++ } ++ } ++ } ++ return 0; ++} ++#endif ++ ++int nat25_db_handle(struct rwnx_vif *vif, struct sk_buff *skb, int method) ++{ ++ unsigned short protocol; ++ unsigned char networkAddr[MAX_NETWORK_ADDR_LEN]; ++ ++ if (skb == NULL) ++ return -1; ++ ++ if ((method <= NAT25_MIN) || (method >= NAT25_MAX)) ++ return -1; ++ ++ protocol = *((unsigned short *)(skb->data + 2 * ETH_ALEN)); ++ ++ /*---------------------------------------------------*/ ++ /* Handle IP frame */ ++ /*---------------------------------------------------*/ ++ if (protocol == __constant_htons(ETH_P_IP)) { ++ struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN); ++ ++ if (((unsigned char *)(iph) + (iph->ihl << 2)) >= ++ (skb->data + ETH_HLEN + skb->len)) { ++ printk("NAT25: malformed IP packet !\n"); ++ return -1; ++ } ++ ++ switch (method) { ++ case NAT25_CHECK: ++ return -1; ++ ++ case NAT25_INSERT: { ++ /* some muticast with source IP is all zero, maybe other case is illegal */ ++ /* in class A, B, C, host address is all zero or all one is illegal */ ++ if (iph->saddr == 0) ++ return 0; ++ printk("NAT25: Insert IP, SA=%08x, DA=%08x\n", ++ iph->saddr, iph->daddr); ++ __nat25_generate_ipv4_network_addr(networkAddr, ++ &iph->saddr); ++ /* record source IP address and , source mac address into db */ ++ __nat25_db_network_insert(vif, skb->data + ETH_ALEN, ++ networkAddr); ++ ++ __nat25_db_print(vif); ++ } ++ return 0; ++ ++ case NAT25_LOOKUP: { ++ printk("NAT25: Lookup IP, SA=%08x, DA=%08x\n", ++ iph->saddr, iph->daddr); ++#ifdef SUPPORT_TX_MCAST2UNI ++ if (vif->pshare->rf_ft_var.mc2u_disable || ++ ((((OPMODE & ++ (WIFI_STATION_STATE | WIFI_ASOC_STATE)) == ++ (WIFI_STATION_STATE | WIFI_ASOC_STATE)) && ++ !checkIPMcAndReplace(vif, skb, &iph->daddr)) || ++ (OPMODE & WIFI_ADHOC_STATE))) ++#endif ++ { ++ __nat25_generate_ipv4_network_addr(networkAddr, ++ &iph->daddr); ++ ++ if (!__nat25_db_network_lookup_and_replace( ++ vif, skb, networkAddr)) { ++ if (*((unsigned char *)&iph->daddr + ++ 3) == 0xff) { ++ /* L2 is unicast but L3 is broadcast, make L2 bacome broadcast */ ++ printk("NAT25: Set DA as boardcast\n"); ++ memset(skb->data, 0xff, ++ ETH_ALEN); ++ } else { ++ /* forward unknow IP packet to upper TCP/IP */ ++ printk("NAT25: Replace DA with BR's MAC\n"); ++ if ((*(u32 *)vif->br_mac) == ++ 0 && ++ (*(u16 *)(vif->br_mac + ++ 4)) == 0) { ++ void netdev_br_init( ++ struct net_device * ++ netdev); ++ printk("Re-init netdev_br_init() due to br_mac==0!\n"); ++ netdev_br_init( ++ vif->ndev); ++ } ++ memcpy(skb->data, vif->br_mac, ++ ETH_ALEN); ++ } ++ } ++ } ++ } ++ return 0; ++ ++ default: ++ return -1; ++ } ++ } ++ ++ /*---------------------------------------------------*/ ++ /* Handle ARP frame */ ++ /*---------------------------------------------------*/ ++ else if (protocol == __constant_htons(ETH_P_ARP)) { ++ struct arphdr *arp = (struct arphdr *)(skb->data + ETH_HLEN); ++ unsigned char *arp_ptr = (unsigned char *)(arp + 1); ++ unsigned int *sender, *target; ++ ++ if (arp->ar_pro != __constant_htons(ETH_P_IP)) { ++ printk("NAT25: arp protocol unknown (%4x)!\n", ++ htons(arp->ar_pro)); ++ return -1; ++ } ++ ++ switch (method) { ++ case NAT25_CHECK: ++ return 0; /* skb_copy for all ARP frame */ ++ ++ case NAT25_INSERT: { ++ printk("NAT25: Insert ARP, MAC=%02x%02x%02x%02x%02x%02x\n", ++ arp_ptr[0], arp_ptr[1], arp_ptr[2], arp_ptr[3], ++ arp_ptr[4], arp_ptr[5]); ++ ++ /* change to ARP sender mac address to wlan STA address */ ++ memcpy(arp_ptr, vif->ndev->dev_addr, ETH_ALEN); ++ ++ arp_ptr += arp->ar_hln; ++ sender = (unsigned int *)arp_ptr; ++ ++ __nat25_generate_ipv4_network_addr(networkAddr, sender); ++ ++ __nat25_db_network_insert(vif, skb->data + ETH_ALEN, ++ networkAddr); ++ ++ __nat25_db_print(vif); ++ } ++ return 0; ++ ++ case NAT25_LOOKUP: { ++ printk("NAT25: Lookup ARP\n"); ++ ++ arp_ptr += arp->ar_hln; ++ sender = (unsigned int *)arp_ptr; ++ arp_ptr += (arp->ar_hln + arp->ar_pln); ++ target = (unsigned int *)arp_ptr; ++ ++ __nat25_generate_ipv4_network_addr(networkAddr, target); ++ ++ __nat25_db_network_lookup_and_replace(vif, skb, ++ networkAddr); ++ ++ /* change to ARP target mac address to Lookup result */ ++ arp_ptr = (unsigned char *)(arp + 1); ++ arp_ptr += (arp->ar_hln + arp->ar_pln); ++ memcpy(arp_ptr, skb->data, ETH_ALEN); ++ } ++ return 0; ++ ++ default: ++ return -1; ++ } ++ } ++ ++ /*---------------------------------------------------*/ ++ /* Handle IPX and Apple Talk frame */ ++ /*---------------------------------------------------*/ ++ else if ((protocol == __constant_htons(ETH_P_IPX)) || ++ (protocol == __constant_htons(ETH_P_ATALK)) || ++ (protocol == __constant_htons(ETH_P_AARP))) { ++ unsigned char ipx_header[2] = { 0xFF, 0xFF }; ++ struct ipxhdr *ipx = NULL; ++ struct elapaarp *ea = NULL; ++ struct ddpehdr *ddp = NULL; ++ unsigned char *framePtr = skb->data + ETH_HLEN; ++ ++ if (protocol == __constant_htons(ETH_P_IPX)) { ++ printk("NAT25: Protocol=IPX (Ethernet II)\n"); ++ ipx = (struct ipxhdr *)framePtr; ++ } else { /* if(protocol <= __constant_htons(ETH_FRAME_LEN)) */ ++ if (!memcmp(ipx_header, framePtr, 2)) { ++ printk("NAT25: Protocol=IPX (Ethernet 802.3)\n"); ++ ipx = (struct ipxhdr *)framePtr; ++ } else { ++ unsigned char ipx_8022_type = 0xE0; ++ unsigned char snap_8022_type = 0xAA; ++ ++ if (*framePtr == snap_8022_type) { ++ unsigned char ipx_snap_id[5] = { ++ 0x0, 0x0, 0x0, 0x81, 0x37 ++ }; /* IPX SNAP ID */ ++ unsigned char aarp_snap_id[5] = { ++ 0x00, 0x00, 0x00, 0x80, 0xF3 ++ }; /* Apple Talk AARP SNAP ID */ ++ unsigned char ddp_snap_id[5] = { ++ 0x08, 0x00, 0x07, 0x80, 0x9B ++ }; /* Apple Talk DDP SNAP ID */ ++ ++ framePtr += ++ 3; /* eliminate the 802.2 header */ ++ ++ if (!memcmp(ipx_snap_id, framePtr, 5)) { ++ framePtr += ++ 5; /* eliminate the SNAP header */ ++ ++ printk("NAT25: Protocol=IPX (Ethernet SNAP)\n"); ++ ipx = (struct ipxhdr *)framePtr; ++ } else if (!memcmp(aarp_snap_id, ++ framePtr, 5)) { ++ framePtr += ++ 5; /* eliminate the SNAP header */ ++ ++ ea = (struct elapaarp *)framePtr; ++ } else if (!memcmp(ddp_snap_id, ++ framePtr, 5)) { ++ framePtr += ++ 5; /* eliminate the SNAP header */ ++ ++ ddp = (struct ddpehdr *)framePtr; ++ } else { ++ printk("NAT25: Protocol=Ethernet SNAP %02x%02x%02x%02x%02x\n", ++ framePtr[0], framePtr[1], ++ framePtr[2], framePtr[3], ++ framePtr[4]); ++ return -1; ++ } ++ } else if (*framePtr == ipx_8022_type) { ++ framePtr += ++ 3; /* eliminate the 802.2 header */ ++ ++ if (!memcmp(ipx_header, framePtr, 2)) { ++ printk("NAT25: Protocol=IPX (Ethernet 802.2)\n"); ++ ipx = (struct ipxhdr *)framePtr; ++ } else ++ return -1; ++ } ++ } ++ } ++ ++ /* IPX */ ++ if (ipx != NULL) { ++ switch (method) { ++ case NAT25_CHECK: ++ if (!memcmp(skb->data + ETH_ALEN, ++ ipx->ipx_source.node, ETH_ALEN)) { ++ printk("NAT25: Check IPX skb_copy\n"); ++ return 0; ++ } ++ return -1; ++ ++ case NAT25_INSERT: { ++ printk("NAT25: Insert IPX, Dest=%08x,%02x%02x%02x%02x%02x%02x,%04x Source=%08x,%02x%02x%02x%02x%02x%02x,%04x\n", ++ ipx->ipx_dest.net, ipx->ipx_dest.node[0], ++ ipx->ipx_dest.node[1], ++ ipx->ipx_dest.node[2], ++ ipx->ipx_dest.node[3], ++ ipx->ipx_dest.node[4], ++ ipx->ipx_dest.node[5], ++ ipx->ipx_dest.sock, ipx->ipx_source.net, ++ ipx->ipx_source.node[0], ++ ipx->ipx_source.node[1], ++ ipx->ipx_source.node[2], ++ ipx->ipx_source.node[3], ++ ipx->ipx_source.node[4], ++ ipx->ipx_source.node[5], ++ ipx->ipx_source.sock); ++ ++ if (!memcmp(skb->data + ETH_ALEN, ++ ipx->ipx_source.node, ETH_ALEN)) { ++ printk("NAT25: Use IPX Net, and Socket as network addr\n"); ++ ++ __nat25_generate_ipx_network_addr_with_socket( ++ networkAddr, ++ &ipx->ipx_source.net, ++ &ipx->ipx_source.sock); ++ ++ /* change IPX source node addr to wlan STA address */ ++ memcpy(ipx->ipx_source.node, ++ vif->ndev->dev_addr, ETH_ALEN); ++ } else ++ __nat25_generate_ipx_network_addr_with_node( ++ networkAddr, ++ &ipx->ipx_source.net, ++ ipx->ipx_source.node); ++ ++ __nat25_db_network_insert( ++ vif, skb->data + ETH_ALEN, networkAddr); ++ ++ __nat25_db_print(vif); ++ } ++ return 0; ++ ++ case NAT25_LOOKUP: { ++ if (!memcmp(vif->ndev->dev_addr, ++ ipx->ipx_dest.node, ETH_ALEN)) { ++ printk("NAT25: Lookup IPX, Modify Destination IPX Node addr\n"); ++ ++ __nat25_generate_ipx_network_addr_with_socket( ++ networkAddr, &ipx->ipx_dest.net, ++ &ipx->ipx_dest.sock); ++ ++ __nat25_db_network_lookup_and_replace( ++ vif, skb, networkAddr); ++ ++ /* replace IPX destination node addr with Lookup destination MAC addr */ ++ memcpy(ipx->ipx_dest.node, skb->data, ++ ETH_ALEN); ++ } else { ++ __nat25_generate_ipx_network_addr_with_node( ++ networkAddr, &ipx->ipx_dest.net, ++ ipx->ipx_dest.node); ++ ++ __nat25_db_network_lookup_and_replace( ++ vif, skb, networkAddr); ++ } ++ } ++ return 0; ++ ++ default: ++ return -1; ++ } ++ } ++ ++ /* AARP */ ++ else if (ea != NULL) { ++ /* Sanity check fields. */ ++ if (ea->hw_len != ETH_ALEN || ++ ea->pa_len != AARP_PA_ALEN) { ++ printk("NAT25: Appletalk AARP Sanity check fail!\n"); ++ return -1; ++ } ++ ++ switch (method) { ++ case NAT25_CHECK: ++ return 0; ++ ++ case NAT25_INSERT: { ++ /* change to AARP source mac address to wlan STA address */ ++ memcpy(ea->hw_src, vif->ndev->dev_addr, ++ ETH_ALEN); ++ ++ printk("NAT25: Insert AARP, Source=%d,%d Destination=%d,%d\n", ++ ea->pa_src_net, ea->pa_src_node, ++ ea->pa_dst_net, ea->pa_dst_node); ++ ++ __nat25_generate_apple_network_addr( ++ networkAddr, &ea->pa_src_net, ++ &ea->pa_src_node); ++ ++ __nat25_db_network_insert( ++ vif, skb->data + ETH_ALEN, networkAddr); ++ ++ __nat25_db_print(vif); ++ } ++ return 0; ++ ++ case NAT25_LOOKUP: { ++ printk("NAT25: Lookup AARP, Source=%d,%d Destination=%d,%d\n", ++ ea->pa_src_net, ea->pa_src_node, ++ ea->pa_dst_net, ea->pa_dst_node); ++ ++ __nat25_generate_apple_network_addr( ++ networkAddr, &ea->pa_dst_net, ++ &ea->pa_dst_node); ++ ++ __nat25_db_network_lookup_and_replace( ++ vif, skb, networkAddr); ++ ++ /* change to AARP destination mac address to Lookup result */ ++ memcpy(ea->hw_dst, skb->data, ETH_ALEN); ++ } ++ return 0; ++ ++ default: ++ return -1; ++ } ++ } ++ ++ /* DDP */ ++ else if (ddp != NULL) { ++ switch (method) { ++ case NAT25_CHECK: ++ return -1; ++ ++ case NAT25_INSERT: { ++ printk("NAT25: Insert DDP, Source=%d,%d Destination=%d,%d\n", ++ ddp->deh_snet, ddp->deh_snode, ++ ddp->deh_dnet, ddp->deh_dnode); ++ ++ __nat25_generate_apple_network_addr( ++ networkAddr, &ddp->deh_snet, ++ &ddp->deh_snode); ++ ++ __nat25_db_network_insert( ++ vif, skb->data + ETH_ALEN, networkAddr); ++ ++ __nat25_db_print(vif); ++ } ++ return 0; ++ ++ case NAT25_LOOKUP: { ++ printk("NAT25: Lookup DDP, Source=%d,%d Destination=%d,%d\n", ++ ddp->deh_snet, ddp->deh_snode, ++ ddp->deh_dnet, ddp->deh_dnode); ++ ++ __nat25_generate_apple_network_addr( ++ networkAddr, &ddp->deh_dnet, ++ &ddp->deh_dnode); ++ ++ __nat25_db_network_lookup_and_replace( ++ vif, skb, networkAddr); ++ } ++ return 0; ++ ++ default: ++ return -1; ++ } ++ } ++ ++ return -1; ++ } ++ ++ /*---------------------------------------------------*/ ++ /* Handle PPPoE frame */ ++ /*---------------------------------------------------*/ ++ else if ((protocol == __constant_htons(ETH_P_PPP_DISC)) || ++ (protocol == __constant_htons(ETH_P_PPP_SES))) { ++ struct pppoe_hdr *ph = ++ (struct pppoe_hdr *)(skb->data + ETH_HLEN); ++ unsigned short *pMagic; ++ ++ switch (method) { ++ case NAT25_CHECK: ++ if (ph->sid == 0) ++ return 0; ++ return 1; ++ ++ case NAT25_INSERT: ++ if (ph->sid == ++ 0) { /* Discovery phase according to tag */ ++ if (ph->code == PADI_CODE || ++ ph->code == PADR_CODE) { ++ if (vif->ethBrExtInfo.addPPPoETag) { ++ struct pppoe_tag *tag, *pOldTag; ++ unsigned char tag_buf[40]; ++ int old_tag_len = 0; ++ ++ tag = (struct pppoe_tag *) ++ tag_buf; ++ pOldTag = (struct pppoe_tag *) ++ __nat25_find_pppoe_tag( ++ ph, ++ ntohs(PTT_RELAY_SID)); ++ if (pOldTag) { /* if SID existed, copy old value and delete it */ ++ old_tag_len = ntohs( ++ pOldTag->tag_len); ++ if (old_tag_len + ++ TAG_HDR_LEN + ++ MAGIC_CODE_LEN + ++ RTL_RELAY_TAG_LEN > ++ sizeof(tag_buf)) { ++ printk("SID tag length too long!\n"); ++ return -1; ++ } ++ ++ memcpy(tag->tag_data + ++ MAGIC_CODE_LEN + ++ RTL_RELAY_TAG_LEN, ++ pOldTag->tag_data, ++ old_tag_len); ++ ++ if (skb_pull_and_merge( ++ skb, ++ (unsigned char ++ *) ++ pOldTag, ++ TAG_HDR_LEN + ++ old_tag_len) < ++ 0) { ++ printk("call skb_pull_and_merge() failed in PADI/R packet!\n"); ++ return -1; ++ } ++ ph->length = htons( ++ ntohs(ph->length) - ++ TAG_HDR_LEN - ++ old_tag_len); ++ } ++ ++ tag->tag_type = PTT_RELAY_SID; ++ tag->tag_len = htons( ++ MAGIC_CODE_LEN + ++ RTL_RELAY_TAG_LEN + ++ old_tag_len); ++ ++ /* insert the magic_code+client mac in relay tag */ ++ pMagic = (unsigned short *) ++ tag->tag_data; ++ *pMagic = htons(MAGIC_CODE); ++ memcpy(tag->tag_data + ++ MAGIC_CODE_LEN, ++ skb->data + ETH_ALEN, ++ ETH_ALEN); ++ ++ /* Add relay tag */ ++ if (__nat25_add_pppoe_tag( ++ skb, tag) < 0) ++ return -1; ++ ++ printk("NAT25: Insert PPPoE, forward %s packet\n", ++ (ph->code == PADI_CODE ? ++ "PADI" : ++ "PADR")); ++ } else { /* not add relay tag */ ++ if (vif->pppoe_connection_in_progress && ++ memcmp(skb->data + ETH_ALEN, ++ vif->pppoe_addr, ++ ETH_ALEN)) { ++ printk("Discard PPPoE packet due to another PPPoE connection is in progress!\n"); ++ return -2; ++ } ++ ++ if (vif->pppoe_connection_in_progress == ++ 0) ++ memcpy(vif->pppoe_addr, ++ skb->data + ++ ETH_ALEN, ++ ETH_ALEN); ++ ++ vif->pppoe_connection_in_progress = ++ WAIT_TIME_PPPOE; ++ } ++ } else ++ return -1; ++ } else { /* session phase */ ++ printk("NAT25: Insert PPPoE, insert session packet to %s\n", ++ skb->dev->name); ++ ++ __nat25_generate_pppoe_network_addr( ++ networkAddr, skb->data, &(ph->sid)); ++ ++ __nat25_db_network_insert( ++ vif, skb->data + ETH_ALEN, networkAddr); ++ ++ __nat25_db_print(vif); ++ ++ if (!vif->ethBrExtInfo.addPPPoETag && ++ vif->pppoe_connection_in_progress && ++ !memcmp(skb->data + ETH_ALEN, ++ vif->pppoe_addr, ETH_ALEN)) ++ vif->pppoe_connection_in_progress = 0; ++ } ++ return 0; ++ ++ case NAT25_LOOKUP: ++ if (ph->code == PADO_CODE || ph->code == PADS_CODE) { ++ if (vif->ethBrExtInfo.addPPPoETag) { ++ struct pppoe_tag *tag; ++ unsigned char *ptr; ++ unsigned short tagType, tagLen; ++ int offset = 0; ++ ++ ptr = __nat25_find_pppoe_tag( ++ ph, ntohs(PTT_RELAY_SID)); ++ if (ptr == 0) { ++ printk("Fail to find PTT_RELAY_SID in FADO!\n"); ++ return -1; ++ } ++ ++ tag = (struct pppoe_tag *)ptr; ++ tagType = ++ (unsigned short)((ptr[0] << 8) + ++ ptr[1]); ++ tagLen = ++ (unsigned short)((ptr[2] << 8) + ++ ptr[3]); ++ ++ if ((tagType != ntohs(PTT_RELAY_SID)) || ++ (tagLen < (MAGIC_CODE_LEN + ++ RTL_RELAY_TAG_LEN))) { ++ printk("Invalid PTT_RELAY_SID tag length [%d]!\n", ++ tagLen); ++ return -1; ++ } ++ ++ pMagic = ++ (unsigned short *)tag->tag_data; ++ if (ntohs(*pMagic) != MAGIC_CODE) { ++ printk("Can't find MAGIC_CODE in %s packet!\n", ++ (ph->code == PADO_CODE ? ++ "PADO" : ++ "PADS")); ++ return -1; ++ } ++ ++ memcpy(skb->data, ++ tag->tag_data + MAGIC_CODE_LEN, ++ ETH_ALEN); ++ ++ if (tagLen > ++ MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN) ++ offset = TAG_HDR_LEN; ++ ++ if (skb_pull_and_merge( ++ skb, ptr + offset, ++ TAG_HDR_LEN + ++ MAGIC_CODE_LEN + ++ RTL_RELAY_TAG_LEN - ++ offset) < 0) { ++ printk("call skb_pull_and_merge() failed in PADO packet!\n"); ++ return -1; ++ } ++ ph->length = htons( ++ ntohs(ph->length) - ++ (TAG_HDR_LEN + MAGIC_CODE_LEN + ++ RTL_RELAY_TAG_LEN - offset)); ++ if (offset > 0) ++ tag->tag_len = htons( ++ tagLen - ++ MAGIC_CODE_LEN - ++ RTL_RELAY_TAG_LEN); ++ ++ printk("NAT25: Lookup PPPoE, forward %s Packet from %s\n", ++ (ph->code == PADO_CODE ? "PADO" : ++ "PADS"), ++ skb->dev->name); ++ } else { /* not add relay tag */ ++ if (!vif->pppoe_connection_in_progress) { ++ printk("Discard PPPoE packet due to no connection in progresss!\n"); ++ return -1; ++ } ++ memcpy(skb->data, vif->pppoe_addr, ++ ETH_ALEN); ++ vif->pppoe_connection_in_progress = ++ WAIT_TIME_PPPOE; ++ } ++ } else { ++ if (ph->sid != 0) { ++ printk("NAT25: Lookup PPPoE, lookup session packet from %s\n", ++ skb->dev->name); ++ __nat25_generate_pppoe_network_addr( ++ networkAddr, ++ skb->data + ETH_ALEN, ++ &(ph->sid)); ++ ++ __nat25_db_network_lookup_and_replace( ++ vif, skb, networkAddr); ++ ++ __nat25_db_print(vif); ++ } else ++ return -1; ++ } ++ return 0; ++ ++ default: ++ return -1; ++ } ++ } ++ ++ /*---------------------------------------------------*/ ++ /* Handle EAP frame */ ++ /*---------------------------------------------------*/ ++ else if (protocol == __constant_htons(0x888e)) { ++ switch (method) { ++ case NAT25_CHECK: ++ return -1; ++ ++ case NAT25_INSERT: ++ return 0; ++ ++ case NAT25_LOOKUP: ++ return 0; ++ ++ default: ++ return -1; ++ } ++ } ++ ++ /*---------------------------------------------------*/ ++ /* Handle C-Media proprietary frame */ ++ /*---------------------------------------------------*/ ++ else if ((protocol == __constant_htons(0xe2ae)) || ++ (protocol == __constant_htons(0xe2af))) { ++ switch (method) { ++ case NAT25_CHECK: ++ return -1; ++ ++ case NAT25_INSERT: ++ return 0; ++ ++ case NAT25_LOOKUP: ++ return 0; ++ ++ default: ++ return -1; ++ } ++ } ++ /*---------------------------------------------------*/ ++ /* Handle IPV6 frame */ ++ /*---------------------------------------------------*/ ++#ifdef CL_IPV6_PASS ++ else if (protocol == __constant_htons(ETH_P_IPV6)) { ++ struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + ETH_HLEN); ++ ++ if (sizeof(*iph) >= (skb->len - ETH_HLEN)) { ++ printk("NAT25: malformed IPv6 packet !\n"); ++ return -1; ++ } ++ ++ switch (method) { ++ case NAT25_CHECK: ++ if (skb->data[0] & 1) ++ return 0; ++ return -1; ++ ++ case NAT25_INSERT: { ++ printk("NAT25: Insert IP, SA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x," ++ " DA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n", ++ iph->saddr.s6_addr16[0], iph->saddr.s6_addr16[1], ++ iph->saddr.s6_addr16[2], iph->saddr.s6_addr16[3], ++ iph->saddr.s6_addr16[4], iph->saddr.s6_addr16[5], ++ iph->saddr.s6_addr16[6], iph->saddr.s6_addr16[7], ++ iph->daddr.s6_addr16[0], iph->daddr.s6_addr16[1], ++ iph->daddr.s6_addr16[2], iph->daddr.s6_addr16[3], ++ iph->daddr.s6_addr16[4], iph->daddr.s6_addr16[5], ++ iph->daddr.s6_addr16[6], ++ iph->daddr.s6_addr16[7]); ++ ++ if (memcmp(&iph->saddr, ++ "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0", ++ 16)) { ++ __nat25_generate_ipv6_network_addr( ++ networkAddr, ++ (unsigned int *)&iph->saddr); ++ __nat25_db_network_insert( ++ vif, skb->data + ETH_ALEN, networkAddr); ++ __nat25_db_print(vif); ++ ++ if (iph->nexthdr == IPPROTO_ICMPV6 && ++ skb->len > (ETH_HLEN + sizeof(*iph) + 4)) { ++ if (update_nd_link_layer_addr( ++ skb->data + ETH_HLEN + ++ sizeof(*iph), ++ skb->len - ETH_HLEN - ++ sizeof(*iph), ++ vif->ndev->dev_addr)) { ++ struct icmp6hdr *hdr = ++ (struct icmp6hdr ++ *)(skb->data + ++ ETH_HLEN + ++ sizeof(*iph)); ++ hdr->icmp6_cksum = 0; ++ hdr->icmp6_cksum = csum_ipv6_magic( ++ &iph->saddr, ++ &iph->daddr, ++ iph->payload_len, ++ IPPROTO_ICMPV6, ++ csum_partial( ++ (__u8 *)hdr, ++ iph->payload_len, ++ 0)); ++ } ++ } ++ } ++ } ++ return 0; ++ ++ case NAT25_LOOKUP: ++ printk("NAT25: Lookup IP, SA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x," ++ " DA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n", ++ iph->saddr.s6_addr16[0], iph->saddr.s6_addr16[1], ++ iph->saddr.s6_addr16[2], iph->saddr.s6_addr16[3], ++ iph->saddr.s6_addr16[4], iph->saddr.s6_addr16[5], ++ iph->saddr.s6_addr16[6], iph->saddr.s6_addr16[7], ++ iph->daddr.s6_addr16[0], iph->daddr.s6_addr16[1], ++ iph->daddr.s6_addr16[2], iph->daddr.s6_addr16[3], ++ iph->daddr.s6_addr16[4], iph->daddr.s6_addr16[5], ++ iph->daddr.s6_addr16[6], ++ iph->daddr.s6_addr16[7]); ++ ++ __nat25_generate_ipv6_network_addr( ++ networkAddr, (unsigned int *)&iph->daddr); ++ if (!__nat25_db_network_lookup_and_replace( ++ vif, skb, networkAddr)) { ++#ifdef SUPPORT_RX_UNI2MCAST ++ if (iph->daddr.s6_addr[0] == 0xff) ++ convert_ipv6_mac_to_mc(skb); ++#endif ++ } ++ return 0; ++ ++ default: ++ return -1; ++ } ++ } ++#endif /* CL_IPV6_PASS */ ++ ++ return -1; ++} ++ ++int nat25_handle_frame(struct rwnx_vif *vif, struct sk_buff *skb) ++{ ++ //printk("%s : vif_type=%d \n",__func__,RWNX_VIF_TYPE(vif)); ++#ifdef BR_SUPPORT_DEBUG ++ if ((!vif->ethBrExtInfo.nat25_disable) && (!(skb->data[0] & 1))) { ++ printk("NAT25: Input Frame: DA=%02x%02x%02x%02x%02x%02x SA=%02x%02x%02x%02x%02x%02x\n", ++ skb->data[0], skb->data[1], skb->data[2], skb->data[3], ++ skb->data[4], skb->data[5], skb->data[6], skb->data[7], ++ skb->data[8], skb->data[9], skb->data[10], ++ skb->data[11]); ++ } ++#endif ++ ++ if (!(skb->data[0] & 1)) { ++ int is_vlan_tag = 0, i, retval = 0; ++ unsigned short vlan_hdr = 0; ++ ++ if (*((unsigned short *)(skb->data + ETH_ALEN * 2)) == ++ __constant_htons(ETH_P_8021Q)) { ++ is_vlan_tag = 1; ++ vlan_hdr = *((unsigned short *)(skb->data + ++ ETH_ALEN * 2 + 2)); ++ for (i = 0; i < 6; i++) ++ *((unsigned short *)(skb->data + ETH_ALEN * 2 + ++ 2 - i * 2)) = ++ *((unsigned short *)(skb->data + ++ ETH_ALEN * 2 - 2 - ++ i * 2)); ++ skb_pull(skb, 4); ++ } ++ ++ if (!vif->ethBrExtInfo.nat25_disable) { ++ unsigned long irqL; ++ spin_lock_bh(&vif->br_ext_lock); ++ /* ++ * This function look up the destination network address from ++ * the NAT2.5 database. Return value = -1 means that the ++ * corresponding network protocol is NOT support. ++ */ ++ if (!vif->ethBrExtInfo.nat25sc_disable && ++ (*((unsigned short *)(skb->data + ETH_ALEN * 2)) == ++ __constant_htons(ETH_P_IP)) && ++ !memcmp(vif->scdb_ip, skb->data + ETH_HLEN + 16, ++ 4)) { ++ memcpy(skb->data, vif->scdb_mac, ETH_ALEN); ++ ++ spin_unlock_bh(&vif->br_ext_lock); ++ } else { ++ spin_unlock_bh(&vif->br_ext_lock); ++ ++ retval = ++ nat25_db_handle(vif, skb, NAT25_LOOKUP); ++ } ++ } else { ++ if (((*((unsigned short *)(skb->data + ETH_ALEN * 2)) == ++ __constant_htons(ETH_P_IP)) && ++ !memcmp(vif->br_ip, skb->data + ETH_HLEN + 16, ++ 4)) || ++ ((*((unsigned short *)(skb->data + ETH_ALEN * 2)) == ++ __constant_htons(ETH_P_ARP)) && ++ !memcmp(vif->br_ip, skb->data + ETH_HLEN + 24, ++ 4))) { ++ /* for traffic to upper TCP/IP */ ++ retval = ++ nat25_db_handle(vif, skb, NAT25_LOOKUP); ++ } ++ } ++ ++ if (is_vlan_tag) { ++ skb_push(skb, 4); ++ for (i = 0; i < 6; i++) ++ *((unsigned short *)(skb->data + i * 2)) = ++ *((unsigned short *)(skb->data + 4 + ++ i * 2)); ++ *((unsigned short *)(skb->data + ETH_ALEN * 2)) = ++ __constant_htons(ETH_P_8021Q); ++ *((unsigned short *)(skb->data + ETH_ALEN * 2 + 2)) = ++ vlan_hdr; ++ } ++ ++ if (retval == -1) { ++ /* DEBUG_ERR("NAT25: Lookup fail!\n"); */ ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++#if 0 ++void mac_clone(_adapter *priv, unsigned char *addr) ++{ ++ struct sockaddr sa; ++ ++ memcpy(sa.sa_data, addr, ETH_ALEN); ++ RTW_INFO("MAC Clone: Addr=%02x%02x%02x%02x%02x%02x\n", ++ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); ++ rtl8192cd_set_hwaddr(priv->dev, &sa); ++} ++ ++ ++int mac_clone_handle_frame(_adapter *priv, struct sk_buff *skb) ++{ ++ if (priv->ethBrExtInfo.macclone_enable && !priv->macclone_completed) { ++ if (!(skb->data[ETH_ALEN] & 1)) { /* check any other particular MAC add */ ++ if (memcmp(skb->data + ETH_ALEN, GET_MY_HWADDR(priv), ETH_ALEN) && ++ ((priv->dev->br_port) && ++ memcmp(skb->data + ETH_ALEN, priv->br_mac, ETH_ALEN))) { ++ mac_clone(priv, skb->data + ETH_ALEN); ++ priv->macclone_completed = 1; ++ } ++ } ++ } ++ ++ return 0; ++} ++#endif /* 0 */ ++ ++#define SERVER_PORT 67 ++#define CLIENT_PORT 68 ++#define DHCP_MAGIC 0x63825363 ++#define BROADCAST_FLAG 0x8000 ++ ++struct dhcpMessage { ++ u_int8_t op; ++ u_int8_t htype; ++ u_int8_t hlen; ++ u_int8_t hops; ++ u_int32_t xid; ++ u_int16_t secs; ++ u_int16_t flags; ++ u_int32_t ciaddr; ++ u_int32_t yiaddr; ++ u_int32_t siaddr; ++ u_int32_t giaddr; ++ u_int8_t chaddr[16]; ++ u_int8_t sname[64]; ++ u_int8_t file[128]; ++ u_int32_t cookie; ++ u_int8_t options[308]; /* 312 - cookie */ ++}; ++ ++void dhcp_flag_bcast(struct rwnx_vif *vif, struct sk_buff *skb) ++{ ++ if (skb == NULL) ++ return; ++ //print_hex_dump(KERN_ERR, "SKB DUMP: SKB->DATA== ", DUMP_PREFIX_NONE, 32, 1, skb->data, 64,false); ++ if (!vif->ethBrExtInfo.dhcp_bcst_disable) { ++ unsigned short protocol = ++ *((unsigned short *)(skb->data + 2 * ETH_ALEN)); ++ printk("%s protocol: %04x\n", __func__, protocol); ++ ++ if (protocol == __constant_htons(ETH_P_IP)) { /* IP */ ++ struct iphdr *iph = ++ (struct iphdr *)(skb->data + ETH_HLEN); ++ ++ if (iph->protocol == IPPROTO_UDP) { /* UDP */ ++ struct udphdr *udph = ++ (struct udphdr *)((u8 *)iph + ++ (iph->ihl << 2)); ++ ++ if ((udph->source == ++ __constant_htons(CLIENT_PORT)) && ++ (udph->dest == ++ __constant_htons( ++ SERVER_PORT))) { /* DHCP request */ ++ struct dhcpMessage *dhcph = ++ (struct dhcpMessage ++ *)((u8 *)udph + ++ sizeof(struct udphdr)); ++ ++ if (dhcph->cookie == ++ __constant_htonl( ++ DHCP_MAGIC)) { /* match magic word */ ++ if (!(dhcph->flags & ++ htons(BROADCAST_FLAG))) { /* if not broadcast */ ++ register int sum = 0; ++ ++ printk("DHCP: change flag of DHCP request to broadcast.\n"); ++ ++#if 1 ++ /* or BROADCAST flag */ ++ dhcph->flags |= htons( ++ BROADCAST_FLAG); ++ /* recalculate checksum */ ++ sum = ~(udph->check) & ++ 0xffff; ++ sum += dhcph->flags; ++ while (sum >> 16) ++ sum = (sum & ++ 0xffff) + ++ (sum >> ++ 16); ++ udph->check = ~sum; ++#endif ++ } ++ } ++ } ++ } ++ } ++ } ++} ++ ++void *scdb_findEntry(struct rwnx_vif *vif, unsigned char *macAddr, ++ unsigned char *ipAddr) ++{ ++ printk("%s()\n", __func__); ++ unsigned char networkAddr[MAX_NETWORK_ADDR_LEN]; ++ struct nat25_network_db_entry *db; ++ int hash; ++ /* _irqL irqL; */ ++ /* _enter_critical_bh(&priv->br_ext_lock, &irqL); */ ++ ++ __nat25_generate_ipv4_network_addr(networkAddr, (unsigned int *)ipAddr); ++ hash = __nat25_network_hash(networkAddr); ++ db = vif->nethash[hash]; ++ while (db != NULL) { ++ if (!memcmp(db->networkAddr, networkAddr, ++ MAX_NETWORK_ADDR_LEN)) { ++ /* _exit_critical_bh(&priv->br_ext_lock, &irqL); */ ++ return (void *)db; ++ } ++ ++ db = db->next_hash; ++ } ++ ++ /* _exit_critical_bh(&priv->br_ext_lock, &irqL); */ ++ return NULL; ++} ++ ++#endif /* CONFIG_BR_SUPPORT */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/aic_br_ext.h b/drivers/net/wireless/aic8800/aic8800_fdrv/aic_br_ext.h +new file mode 100755 +index 000000000..d297ce4ca +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/aic_br_ext.h +@@ -0,0 +1,74 @@ ++/****************************************************************************** ++ * ++ * Copyright(c) 2007 - 2017 Realtek Corporation. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * 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 _AIC_BR_EXT_H_ ++#define _AIC_BR_EXT_H_ ++ ++#define CL_IPV6_PASS 1 ++#define MACADDRLEN 6 ++#define WLAN_ETHHDR_LEN 14 ++ ++#define NAT25_HASH_BITS 4 ++#define NAT25_HASH_SIZE (1 << NAT25_HASH_BITS) ++#define NAT25_AGEING_TIME 300 ++ ++#define NDEV_FMT "%s" ++#define NDEV_ARG(ndev) ndev->name ++#define ADPT_FMT "%s" ++//#define ADPT_ARG(adapter) (adapter->pnetdev ? adapter->pnetdev->name : NULL) ++#define FUNC_NDEV_FMT "%s(%s)" ++#define FUNC_NDEV_ARG(ndev) __func__, ndev->name ++#define FUNC_ADPT_FMT "%s(%s)" ++//#define FUNC_ADPT_ARG(adapter) __func__, (adapter->pnetdev ? adapter->pnetdev->name : NULL) ++#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" ++#define MAC_ARG(x) \ ++ ((u8 *)(x))[0], ((u8 *)(x))[1], ((u8 *)(x))[2], ((u8 *)(x))[3], \ ++ ((u8 *)(x))[4], ((u8 *)(x))[5] ++ ++#ifdef CL_IPV6_PASS ++#define MAX_NETWORK_ADDR_LEN 17 ++#else ++#define MAX_NETWORK_ADDR_LEN 11 ++#endif ++ ++struct nat25_network_db_entry { ++ struct nat25_network_db_entry *next_hash; ++ struct nat25_network_db_entry **pprev_hash; ++ atomic_t use_count; ++ unsigned char macAddr[6]; ++ unsigned long ageing_timer; ++ unsigned char networkAddr[MAX_NETWORK_ADDR_LEN]; ++}; ++ ++enum NAT25_METHOD { ++ NAT25_MIN, ++ NAT25_CHECK, ++ NAT25_INSERT, ++ NAT25_LOOKUP, ++ NAT25_PARSE, ++ NAT25_MAX ++}; ++ ++struct br_ext_info { ++ unsigned int nat25_disable; ++ unsigned int macclone_enable; ++ unsigned int dhcp_bcst_disable; ++ int addPPPoETag; /* 1: Add PPPoE relay-SID, 0: disable */ ++ unsigned char nat25_dmzMac[MACADDRLEN]; ++ unsigned int nat25sc_disable; ++}; ++ ++void nat25_db_cleanup(struct rwnx_vif *vif); ++ ++#endif /* _AIC_BR_EXT_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/aic_bsp_export.h b/drivers/net/wireless/aic8800/aic8800_fdrv/aic_bsp_export.h +new file mode 100755 +index 000000000..48e1fa59a +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/aic_bsp_export.h +@@ -0,0 +1,64 @@ ++#ifndef __AIC_BSP_EXPORT_H ++#define __AIC_BSP_EXPORT_H ++ ++enum aicbsp_subsys { ++ AIC_BLUETOOTH, ++ AIC_WIFI, ++}; ++ ++enum aicbsp_pwr_state { ++ AIC_PWR_OFF, ++ AIC_PWR_ON, ++}; ++ ++struct aicbsp_feature_t { ++ int hwinfo; ++ uint32_t sdio_clock; ++ uint8_t sdio_phase; ++ int fwlog_en; ++ uint8_t irqf; ++}; ++ ++enum skb_buff_id { ++ AIC_RESV_MEM_TXDATA, ++}; ++ ++#if defined(CONFIG_DPD) || defined(CONFIG_LOFT_CALIB) ++typedef struct { ++ uint32_t bit_mask[3]; ++ uint32_t reserved; ++ uint32_t dpd_high[96]; ++ uint32_t dpd_11b[96]; ++ uint32_t dpd_low[96]; ++ uint32_t idac_11b[48]; ++ uint32_t idac_high[48]; ++ uint32_t idac_low[48]; ++ uint32_t loft_res[18]; ++ uint32_t rx_iqim_res[16]; ++} rf_misc_ram_t; ++ ++typedef struct { ++ uint32_t bit_mask[4]; ++ uint32_t dpd_high[96]; ++ uint32_t loft_res[18]; ++} rf_misc_ram_lite_t; ++ ++#define MEMBER_SIZE(type, member) sizeof(((type *)0)->member) ++#define DPD_RESULT_SIZE_8800DC sizeof(rf_misc_ram_lite_t) ++#endif ++ ++#ifdef CONFIG_DPD ++extern rf_misc_ram_lite_t dpd_res; ++#endif ++ ++#ifdef CONFIG_LOFT_CALIB ++extern rf_misc_ram_lite_t loft_res_local; ++#endif ++ ++int aicbsp_set_subsys(int, int); ++int aicbsp_get_feature(struct aicbsp_feature_t *feature, char *fw_path); ++bool aicbsp_get_load_fw_in_fdrv(void); ++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/drivers/net/wireless/aic8800/aic8800_fdrv/aic_btsdio.h b/drivers/net/wireless/aic8800/aic8800_fdrv/aic_btsdio.h +new file mode 100755 +index 000000000..79e354ba8 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/aic_btsdio.h +@@ -0,0 +1,547 @@ ++#ifndef _AICWF_SDIO_BT_H_ ++#define _AICWF_SDIO_BT_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_PLATFORM_UBUNTU ++#define CONFIG_BLUEDROID 0 /* bleuz 0, bluedroid 1 */ ++#else ++#define CONFIG_BLUEDROID 1 /* bleuz 0, bluedroid 1 */ ++#endif ++/* #define HCI_VERSION_CODE KERNEL_VERSION(3, 14, 41) */ ++#define HCI_VERSION_CODE LINUX_VERSION_CODE ++ ++#define PRINT_CMD_EVENT 1 ++#define PRINT_ACL_DATA 1 ++#define PRINT_SCO_DATA 1 ++ ++#define AICBT_DBG_FLAG 1 ++ ++#if AICBT_DBG_FLAG ++#define AICBT_DBG(fmt, arg...) printk("aic_btsdio: " fmt "\n", ##arg) ++#else ++#define AICBT_DBG(fmt, arg...) ++#endif ++ ++#define AICBT_INFO(fmt, arg...) printk("aic_btsdio: " fmt "\n", ##arg) ++#define AICBT_WARN(fmt, arg...) printk("aic_btsdio: " fmt "\n", ##arg) ++#define AICBT_ERR(fmt, arg...) printk("aic_btsdio: " fmt "\n", ##arg) ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 4, 0) ++#define GET_DRV_DATA(x) hci_get_drvdata(x) ++#else ++#define GET_DRV_DATA(x) x->driver_data ++#endif ++ ++#if CONFIG_BLUEDROID ++struct btusb_data { ++ struct hci_dev *hdev; ++ //struct usb_device *udev; ++ //struct usb_interface *intf; ++ //struct usb_interface *isoc; ++ ++ spinlock_t lock; ++ ++ unsigned long flags; ++ ++ struct work_struct work; ++ struct work_struct waker; ++ ++ /*struct usb_anchor tx_anchor; ++ struct usb_anchor intr_anchor; ++ struct usb_anchor bulk_anchor; ++ struct usb_anchor isoc_anchor; ++ struct usb_anchor deferred;*/ ++ int tx_in_flight; ++ spinlock_t txlock; ++ ++#if (CONFIG_BLUEDROID == 0) ++#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0) ++ spinlock_t rxlock; ++ struct sk_buff *evt_skb; ++ struct sk_buff *acl_skb; ++ struct sk_buff *sco_skb; ++#endif ++#endif ++ ++ /*struct usb_endpoint_descriptor *intr_ep; ++ struct usb_endpoint_descriptor *bulk_tx_ep; ++ struct usb_endpoint_descriptor *bulk_rx_ep; ++ struct usb_endpoint_descriptor *isoc_tx_ep; ++ struct usb_endpoint_descriptor *isoc_rx_ep;*/ ++ ++ __u8 cmdreq_type; ++ ++ unsigned int sco_num; ++ int isoc_altsetting; ++ int suspend_count; ++ uint16_t sco_handle; ++ ++#if (CONFIG_BLUEDROID == 0) ++#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0) ++ int (*recv_bulk)(struct btusb_data *data, void *buffer, int count); ++#endif ++#endif ++ ++//#ifdef CONFIG_HAS_EARLYSUSPEND ++#if 0 ++ struct early_suspend early_suspend; ++#else ++ struct notifier_block pm_notifier; ++ struct notifier_block reboot_notifier; ++#endif ++ //firmware_info *fw_info; ++ ++#ifdef CONFIG_SCO_OVER_HCI ++ AIC_sco_card_t *pSCOSnd; ++#endif ++}; ++ ++#define QUEUE_SIZE 500 ++ ++/*************************************** ++** AicSemi - Integrate from bluetooth.h ** ++*****************************************/ ++/* Reserv for core and drivers use */ ++#define BT_SKB_RESERVE 8 ++ ++/* BD Address */ ++typedef struct { ++ __u8 b[6]; ++} __packed bdaddr_t; ++ ++/* Skb helpers */ ++struct bt_skb_cb { ++ __u8 pkt_type; ++ __u8 incoming; ++ __u16 expect; ++ __u16 tx_seq; ++ __u8 retries; ++ __u8 sar; ++ __u8 force_active; ++}; ++ ++#define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb)) ++ ++/*********************************** ++** AicSemi - Integrate from hci.h ** ++***********************************/ ++#define HCI_MAX_ACL_SIZE 1024 ++#define HCI_MAX_SCO_SIZE 255 ++#define HCI_MAX_EVENT_SIZE 260 ++#define HCI_MAX_FRAME_SIZE (HCI_MAX_ACL_SIZE + 4) ++ ++/* HCI bus types */ ++#define HCI_VIRTUAL 0 ++#define HCI_USB 1 ++#define HCI_PCCARD 2 ++#define HCI_UART 3 ++#define HCI_RS232 4 ++#define HCI_PCI 5 ++#define HCI_SDIO 6 ++ ++/* HCI controller types */ ++#define HCI_BREDR 0x00 ++#define HCI_AMP 0x01 ++ ++/* HCI device flags */ ++enum { ++ HCI_UP, ++ HCI_INIT, ++ HCI_RUNNING, ++ ++ HCI_PSCAN, ++ HCI_ISCAN, ++ HCI_AUTH, ++ HCI_ENCRYPT, ++ HCI_INQUIRY, ++ ++ HCI_RAW, ++ ++ HCI_RESET, ++}; ++ ++/* ++ * BR/EDR and/or LE controller flags: the flags defined here should represent ++ * states from the controller. ++ */ ++enum { ++ HCI_SETUP, ++ HCI_AUTO_OFF, ++ HCI_MGMT, ++ HCI_PAIRABLE, ++ HCI_SERVICE_CACHE, ++ HCI_LINK_KEYS, ++ HCI_DEBUG_KEYS, ++ HCI_UNREGISTER, ++ ++ HCI_LE_SCAN, ++ HCI_SSP_ENABLED, ++ HCI_HS_ENABLED, ++ HCI_LE_ENABLED, ++ HCI_CONNECTABLE, ++ HCI_DISCOVERABLE, ++ HCI_LINK_SECURITY, ++ HCI_PENDING_CLASS, ++}; ++ ++/* HCI data types */ ++#define HCI_COMMAND_PKT 0x01 ++#define HCI_ACLDATA_PKT 0x02 ++#define HCI_SCODATA_PKT 0x03 ++#define HCI_EVENT_PKT 0x04 ++#define HCI_VENDOR_PKT 0xff ++ ++#define HCI_MAX_NAME_LENGTH 248 ++#define HCI_MAX_EIR_LENGTH 240 ++ ++#define HCI_OP_READ_LOCAL_VERSION 0x1001 ++struct hci_rp_read_local_version { ++ __u8 status; ++ __u8 hci_ver; ++ __le16 hci_rev; ++ __u8 lmp_ver; ++ __le16 manufacturer; ++ __le16 lmp_subver; ++} __packed; ++ ++#define HCI_EV_CMD_COMPLETE 0x0e ++struct hci_ev_cmd_complete { ++ __u8 ncmd; ++ __le16 opcode; ++} __packed; ++ ++/* ---- HCI Packet structures ---- */ ++#define HCI_COMMAND_HDR_SIZE 3 ++#define HCI_EVENT_HDR_SIZE 2 ++#define HCI_ACL_HDR_SIZE 4 ++#define HCI_SCO_HDR_SIZE 3 ++ ++struct hci_command_hdr { ++ __le16 opcode; /* OCF & OGF */ ++ __u8 plen; ++} __packed; ++ ++struct hci_event_hdr { ++ __u8 evt; ++ __u8 plen; ++} __packed; ++ ++struct hci_acl_hdr { ++ __le16 handle; /* Handle & Flags(PB, BC) */ ++ __le16 dlen; ++} __packed; ++ ++struct hci_sco_hdr { ++ __le16 handle; ++ __u8 dlen; ++} __packed; ++ ++static inline struct hci_event_hdr *hci_event_hdr(const struct sk_buff *skb) ++{ ++ return (struct hci_event_hdr *)skb->data; ++} ++ ++static inline struct hci_acl_hdr *hci_acl_hdr(const struct sk_buff *skb) ++{ ++ return (struct hci_acl_hdr *)skb->data; ++} ++ ++static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb) ++{ ++ return (struct hci_sco_hdr *)skb->data; ++} ++ ++/* ---- HCI Ioctl requests structures ---- */ ++struct hci_dev_stats { ++ __u32 err_rx; ++ __u32 err_tx; ++ __u32 cmd_tx; ++ __u32 evt_rx; ++ __u32 acl_tx; ++ __u32 acl_rx; ++ __u32 sco_tx; ++ __u32 sco_rx; ++ __u32 byte_rx; ++ __u32 byte_tx; ++}; ++/* AicSemi - Integrate from hci.h end */ ++ ++/***************************************** ++** AicSemi - Integrate from hci_core.h ** ++*****************************************/ ++struct hci_conn_hash { ++ struct list_head list; ++ unsigned int acl_num; ++ unsigned int sco_num; ++ unsigned int le_num; ++}; ++ ++#define HCI_MAX_SHORT_NAME_LENGTH 10 ++ ++#define NUM_REASSEMBLY 4 ++struct hci_dev { ++ struct mutex lock; ++ ++ char name[8]; ++ unsigned long flags; ++ __u16 id; ++ __u8 bus; ++ __u8 dev_type; ++ ++ struct sk_buff *reassembly[NUM_REASSEMBLY]; ++ ++ struct hci_conn_hash conn_hash; ++ ++ struct hci_dev_stats stat; ++ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 4, 0) ++ atomic_t refcnt; ++ struct module *owner; ++ void *driver_data; ++#endif ++ ++ atomic_t promisc; ++ ++ struct device *parent; ++ struct device dev; ++ ++ unsigned long dev_flags; ++ ++ int (*open)(struct hci_dev *hdev); ++ int (*close)(struct hci_dev *hdev); ++ int (*flush)(struct hci_dev *hdev); ++ int (*send)(struct sk_buff *skb); ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 4, 0) ++ void (*destruct)(struct hci_dev *hdev); ++#endif ++#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 7, 1) ++ __u16 voice_setting; ++#endif ++ void (*notify)(struct hci_dev *hdev, unsigned int evt); ++ int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg); ++ u8 *align_data; ++}; ++ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 4, 0) ++static inline struct hci_dev *__hci_dev_hold(struct hci_dev *d) ++{ ++ atomic_inc(&d->refcnt); ++ return d; ++} ++ ++static inline void __hci_dev_put(struct hci_dev *d) ++{ ++ if (atomic_dec_and_test(&d->refcnt)) ++ d->destruct(d); ++} ++#endif ++ ++static inline void *hci_get_drvdata(struct hci_dev *hdev) ++{ ++ return dev_get_drvdata(&hdev->dev); ++} ++ ++static inline void hci_set_drvdata(struct hci_dev *hdev, void *data) ++{ ++ dev_set_drvdata(&hdev->dev, data); ++} ++ ++#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->parent = (pdev)) ++ ++/* ---- HCI Packet structures ---- */ ++#define HCI_COMMAND_HDR_SIZE 3 ++#define HCI_EVENT_HDR_SIZE 2 ++#define HCI_ACL_HDR_SIZE 4 ++#define HCI_SCO_HDR_SIZE 3 ++ ++/* ----- HCI Commands ---- */ ++#define HCI_OP_INQUIRY 0x0401 ++#define HCI_OP_INQUIRY_CANCEL 0x0402 ++#define HCI_OP_EXIT_PERIODIC_INQ 0x0404 ++#define HCI_OP_CREATE_CONN 0x0405 ++#define HCI_OP_DISCONNECT 0x0406 ++#define HCI_OP_ADD_SCO 0x0407 ++#define HCI_OP_CREATE_CONN_CANCEL 0x0408 ++#define HCI_OP_ACCEPT_CONN_REQ 0x0409 ++#define HCI_OP_REJECT_CONN_REQ 0x040a ++#define HCI_OP_LINK_KEY_REPLY 0x040b ++#define HCI_OP_LINK_KEY_NEG_REPLY 0x040c ++#define HCI_OP_PIN_CODE_REPLY 0x040d ++#define HCI_OP_PIN_CODE_NEG_REPLY 0x040e ++#define HCI_OP_CHANGE_CONN_PTYPE 0x040f ++#define HCI_OP_AUTH_REQUESTED 0x0411 ++#define HCI_OP_SET_CONN_ENCRYPT 0x0413 ++#define HCI_OP_CHANGE_CONN_LINK_KEY 0x0415 ++#define HCI_OP_REMOTE_NAME_REQ 0x0419 ++#define HCI_OP_REMOTE_NAME_REQ_CANCEL 0x041a ++#define HCI_OP_READ_REMOTE_FEATURES 0x041b ++#define HCI_OP_READ_REMOTE_EXT_FEATURES 0x041c ++#define HCI_OP_READ_REMOTE_VERSION 0x041d ++#define HCI_OP_SETUP_SYNC_CONN 0x0428 ++#define HCI_OP_ACCEPT_SYNC_CONN_REQ 0x0429 ++#define HCI_OP_REJECT_SYNC_CONN_REQ 0x042a ++#define HCI_OP_SNIFF_MODE 0x0803 ++#define HCI_OP_EXIT_SNIFF_MODE 0x0804 ++#define HCI_OP_ROLE_DISCOVERY 0x0809 ++#define HCI_OP_SWITCH_ROLE 0x080b ++#define HCI_OP_READ_LINK_POLICY 0x080c ++#define HCI_OP_WRITE_LINK_POLICY 0x080d ++#define HCI_OP_READ_DEF_LINK_POLICY 0x080e ++#define HCI_OP_WRITE_DEF_LINK_POLICY 0x080f ++#define HCI_OP_SNIFF_SUBRATE 0x0811 ++#define HCI_OP_Write_Link_Policy_Settings 0x080d ++#define HCI_OP_SET_EVENT_MASK 0x0c01 ++#define HCI_OP_RESET 0x0c03 ++#define HCI_OP_SET_EVENT_FLT 0x0c05 ++#define HCI_OP_Write_Extended_Inquiry_Response 0x0c52 ++#define HCI_OP_Write_Simple_Pairing_Mode 0x0c56 ++#define HCI_OP_Read_Buffer_Size 0x1005 ++#define HCI_OP_Host_Buffer_Size 0x0c33 ++#define HCI_OP_Read_Local_Version_Information 0x1001 ++#define HCI_OP_Read_BD_ADDR 0x1009 ++#define HCI_OP_Read_Local_Supported_Commands 0x1002 ++#define HCI_OP_Write_Scan_Enable 0x0c1a ++#define HCI_OP_Write_Current_IAC_LAP 0x0c3a ++#define HCI_OP_Write_Inquiry_Scan_Activity 0x0c1e ++#define HCI_OP_Write_Class_of_Device 0x0c24 ++#define HCI_OP_LE_Rand 0x2018 ++#define HCI_OP_LE_Set_Random_Address 0x2005 ++#define HCI_OP_LE_Set_Extended_Scan_Enable 0x2042 ++#define HCI_OP_LE_Set_Extended_Scan_Parameters 0x2041 ++#define HCI_OP_Set_Event_Filter 0x0c05 ++#define HCI_OP_Write_Voice_Setting 0x0c26 ++#define HCI_OP_Change_Local_Name 0x0c13 ++#define HCI_OP_Read_Local_Name 0x0c14 ++#define HCI_OP_Wirte_Page_Timeout 0x0c18 ++#define HCI_OP_LE_Clear_Resolving_List 0x0c29 ++#define HCI_OP_LE_Set_Addres_Resolution_Enable_Command 0x0c2e ++#define HCI_OP_Write_Inquiry_mode 0x0c45 ++#define HCI_OP_Write_Page_Scan_Type 0x0c47 ++#define HCI_OP_Write_Inquiry_Scan_Type 0x0c43 ++ ++#define HCI_OP_Delete_Stored_Link_Key 0x0c12 ++#define HCI_OP_LE_Read_Local_Resolvable_Address 0x202d ++#define HCI_OP_LE_Extended_Create_Connection 0x2043 ++#define HCI_OP_Read_Remote_Version_Information 0x041d ++#define HCI_OP_LE_Start_Encryption 0x2019 ++#define HCI_OP_LE_Add_Device_to_Resolving_List 0x2027 ++#define HCI_OP_LE_Set_Privacy_Mode 0x204e ++#define HCI_OP_LE_Connection_Update 0x2013 ++ ++/* ----- HCI events---- */ ++#define HCI_OP_DISCONNECT 0x0406 ++#define HCI_EV_INQUIRY_COMPLETE 0x01 ++#define HCI_EV_INQUIRY_RESULT 0x02 ++#define HCI_EV_CONN_COMPLETE 0x03 ++#define HCI_EV_CONN_REQUEST 0x04 ++#define HCI_EV_DISCONN_COMPLETE 0x05 ++#define HCI_EV_AUTH_COMPLETE 0x06 ++#define HCI_EV_REMOTE_NAME 0x07 ++#define HCI_EV_ENCRYPT_CHANGE 0x08 ++#define HCI_EV_CHANGE_LINK_KEY_COMPLETE 0x09 ++ ++#define HCI_EV_REMOTE_FEATURES 0x0b ++#define HCI_EV_REMOTE_VERSION 0x0c ++#define HCI_EV_QOS_SETUP_COMPLETE 0x0d ++#define HCI_EV_CMD_COMPLETE 0x0e ++#define HCI_EV_CMD_STATUS 0x0f ++ ++#define HCI_EV_ROLE_CHANGE 0x12 ++#define HCI_EV_NUM_COMP_PKTS 0x13 ++#define HCI_EV_MODE_CHANGE 0x14 ++#define HCI_EV_PIN_CODE_REQ 0x16 ++#define HCI_EV_LINK_KEY_REQ 0x17 ++#define HCI_EV_LINK_KEY_NOTIFY 0x18 ++#define HCI_EV_CLOCK_OFFSET 0x1c ++#define HCI_EV_PKT_TYPE_CHANGE 0x1d ++#define HCI_EV_PSCAN_REP_MODE 0x20 ++ ++#define HCI_EV_INQUIRY_RESULT_WITH_RSSI 0x22 ++#define HCI_EV_REMOTE_EXT_FEATURES 0x23 ++#define HCI_EV_SYNC_CONN_COMPLETE 0x2c ++#define HCI_EV_SYNC_CONN_CHANGED 0x2d ++#define HCI_EV_SNIFF_SUBRATE 0x2e ++#define HCI_EV_EXTENDED_INQUIRY_RESULT 0x2f ++#define HCI_EV_IO_CAPA_REQUEST 0x31 ++#define HCI_EV_SIMPLE_PAIR_COMPLETE 0x36 ++#define HCI_EV_REMOTE_HOST_FEATURES 0x3d ++#define HCI_EV_LE_Meta 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 ++#define HCI_BLE_PHY_UPDATE_COMPLETE_EVT 0x0c ++#define HCI_LE_EXTENDED_ADVERTISING_REPORT_EVT 0x0D ++#define HCI_BLE_PERIODIC_ADV_SYNC_EST_EVT 0x0E ++#define HCI_BLE_PERIODIC_ADV_REPORT_EVT 0x0F ++#define HCI_BLE_PERIODIC_ADV_SYNC_LOST_EVT 0x10 ++#define HCI_BLE_SCAN_TIMEOUT_EVT 0x11 ++#define HCI_LE_ADVERTISING_SET_TERMINATED_EVT 0x12 ++#define HCI_BLE_SCAN_REQ_RX_EVT 0x13 ++#define HCI_BLE_CIS_EST_EVT 0x19 ++#define HCI_BLE_CIS_REQ_EVT 0x1a ++#define HCI_BLE_CREATE_BIG_CPL_EVT 0x1b ++#define HCI_BLE_TERM_BIG_CPL_EVT 0x1c ++#define HCI_BLE_BIG_SYNC_EST_EVT 0x1d ++#define HCI_BLE_BIG_SYNC_LOST_EVT 0x1e ++#define HCI_BLE_REQ_PEER_SCA_CPL_EVT 0x1f ++ ++#define HCI_VENDOR_SPECIFIC_EVT 0xFF /* Vendor specific events */ ++ ++#define CONFIG_MAC_OFFSET_GEN_1_2 \ ++ (0x3C) //MAC's OFFSET in config/efuse for aic generation 1~2 bluetooth chip ++#define CONFIG_MAC_OFFSET_GEN_3PLUS \ ++ (0x44) //MAC's OFFSET in config/efuse for aic generation 3+ bluetooth chip ++ ++//Define ioctl cmd the same as HCIDEVUP in the kernel ++#define DOWN_FW_CFG _IOW('E', 176, int) ++//#ifdef CONFIG_SCO_OVER_HCI ++//#define SET_ISO_CFG _IOW('H', 202, int) ++//#else ++#define SET_ISO_CFG _IOW('E', 177, int) ++//#endif ++#define RESET_CONTROLLER _IOW('E', 178, int) ++#define DWFW_CMPLT _IOW('E', 179, int) ++ ++#define GET_USB_INFO _IOR('E', 180, int) ++ ++void bt_data_dump(char *tag, void *data, unsigned long len); ++int aic_enqueue(struct sk_buff *skb); ++int aic_queue_cnt(void); ++int bt_sdio_recv(u8 *data, u32 data_len); ++ ++int btchr_init(void); ++void btchr_exit(void); ++int hdev_init(void); ++void hdev_exit(void); ++ ++struct hci_dev *hci_dev_get(int index); ++int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count); ++#else ++int btsdio_init(void); ++void btsdio_remove(void); ++int bt_sdio_recv(u8 *data, u32 data_len); ++#endif ++#endif //_AICWF_SDIO_BT_H_ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/aic_priv_cmd.c b/drivers/net/wireless/aic8800/aic8800_fdrv/aic_priv_cmd.c +new file mode 100755 +index 000000000..07eb25b91 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/aic_priv_cmd.c +@@ -0,0 +1,2217 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file aic_priv_cmd.c ++ * ++ * @brief Entry point of the AIC driver ++ * ++ * Copyright (C) Aicsemi 2018-2024 ++ * ++ ****************************************************************************** ++ */ ++ ++#include ++#include ++#include "rwnx_defs.h" ++#include "rwnx_msg_tx.h" ++#include "rwnx_debugfs.h" ++#include "rwnx_main.h" ++#include "aicwf_sdio.h" ++#include "aic_priv_cmd.h" ++#include "rwnx_mod_params.h" ++ ++extern int testmode; ++static void print_help(const char *cmd); ++struct dbg_rftest_cmd_cfm cfm = { { ++ 0, ++} }; ++ ++#ifdef CONFIG_RFTEST ++enum { ++ SET_TX, ++ SET_TXSTOP, ++ SET_TXTONE, ++ SET_RX, ++ GET_RX_RESULT, ++ SET_RXSTOP, ++ SET_RX_METER, ++ SET_POWER, ++ SET_XTAL_CAP, ++ SET_XTAL_CAP_FINE, ++ GET_EFUSE_BLOCK, ++ SET_FREQ_CAL, ++ SET_FREQ_CAL_FINE, ++ GET_FREQ_CAL, ++ SET_MAC_ADDR, ++ GET_MAC_ADDR, ++ SET_BT_MAC_ADDR, ++ GET_BT_MAC_ADDR, ++ SET_VENDOR_INFO, ++ GET_VENDOR_INFO, ++ RDWR_PWRMM, ++ RDWR_PWRIDX, ++ RDWR_PWRLVL = RDWR_PWRIDX, ++ RDWR_PWROFST, ++ RDWR_DRVIBIT, ++ RDWR_EFUSE_PWROFST, ++ RDWR_EFUSE_DRVIBIT, ++ SET_PAPR, ++ SET_CAL_XTAL, ++ GET_CAL_XTAL_RES, ++ SET_COB_CAL, ++ GET_COB_CAL_RES, ++ RDWR_EFUSE_USRDATA, ++ SET_NOTCH, ++ RDWR_PWROFSTFINE, ++ RDWR_EFUSE_PWROFSTFINE, ++ RDWR_EFUSE_SDIOCFG, ++ RDWR_EFUSE_USBVIDPID, ++ SET_SRRC, ++ SET_FSS, ++ RDWR_EFUSE_HE_OFF, ++ SET_USB_OFF, ++ SET_PLL_TEST, ++ SET_ANT_MODE, ++ RDWR_BT_EFUSE_PWROFST, ++}; ++ ++typedef struct { ++ u8_l chan; ++ u8_l bw; ++ u8_l mode; ++ u8_l rate; ++ u16_l length; ++ u16_l tx_intv_us; ++ s8_l max_pwr; ++} cmd_rf_settx_t; ++ ++typedef struct { ++ u8_l val; ++} cmd_rf_setfreq_t; ++ ++typedef struct { ++ u8_l chan; ++ u8_l bw; ++} cmd_rf_rx_t; ++ ++typedef struct { ++ u8_l block; ++} cmd_rf_getefuse_t; ++ ++typedef struct { ++ u8_l dutid; ++ u8_l chip_num; ++ u8_l dis_xtal; ++} cmd_rf_setcobcal_t; ++ ++typedef struct { ++ u16_l dut_rcv_golden_num; ++ u8_l golden_rcv_dut_num; ++ s8_l rssi_static; ++ s8_l snr_static; ++ s8_l dut_rssi_static; ++ u16_l reserved; ++} cob_result_ptr_t; ++#endif ++ ++typedef struct { ++ u8_l func; ++ u8_l cnt; ++ u8_l reserved[2]; ++ u32_l usrdata[3]; // 3 words totally ++} cmd_ef_usrdata_t; ++ ++#define CMD_MAXARGS 10 ++#define POWER_LEVEL_INVALID_VAL (127) ++ ++extern char country_code[]; ++ ++#if 0 //#include ++#define isblank(c) ((c) == ' ' || (c) == '\t') ++#define isascii(c) (((unsigned char)(c)) <= 0x7F) ++ ++static int isdigit(unsigned char c) ++{ ++ return ((c >= '0') && (c <='9')); ++} ++ ++static int isxdigit(unsigned char c) ++{ ++ if ((c >= '0') && (c <='9')) ++ return 1; ++ if ((c >= 'a') && (c <='f')) ++ return 1; ++ if ((c >= 'A') && (c <='F')) ++ return 1; ++ return 0; ++} ++ ++static int islower(unsigned char c) ++{ ++ return ((c >= 'a') && (c <='z')); ++} ++ ++static unsigned char toupper(unsigned char c) ++{ ++ if (islower(c)) ++ c -= 'a'-'A'; ++ return c; ++} ++#endif ++ ++static int parse_line(char *line, char *argv[]) ++{ ++ int nargs = 0; ++ ++ while (nargs < CMD_MAXARGS) { ++ /* skip any white space */ ++ while ((*line == ' ') || (*line == '\t')) { ++ ++line; ++ } ++ ++ if (*line == '\0') { /* end of line, no more args */ ++ argv[nargs] = 0; ++ return nargs; ++ } ++ ++ /* Argument include space should be bracketed by quotation mark */ ++ if (*line == '\"') { ++ /* Skip quotation mark */ ++ line++; ++ ++ /* Begin of argument string */ ++ argv[nargs++] = line; ++ ++ /* Until end of argument */ ++ while (*line && (*line != '\"')) { ++ ++line; ++ } ++ } else { ++ argv[nargs++] = line; /* begin of argument string */ ++ ++ /* find end of string */ ++ while (*line && (*line != ' ') && (*line != '\t')) { ++ ++line; ++ } ++ } ++ ++ if (*line == '\0') { /* end of line, no more args */ ++ argv[nargs] = 0; ++ return nargs; ++ } ++ ++ *line++ = '\0'; /* terminate current arg */ ++ } ++ ++ printk("** Too many args (max. %d) **\n", CMD_MAXARGS); ++ ++ return nargs; ++} ++ ++unsigned int command_strtoul(const char *cp, char **endp, unsigned int base) ++{ ++ unsigned int result = 0, value, is_neg = 0; ++ ++ if (*cp == '0') { ++ cp++; ++ if ((*cp == 'x') && isxdigit(cp[1])) { ++ base = 16; ++ cp++; ++ } ++ if (!base) { ++ base = 8; ++ } ++ } ++ if (!base) { ++ base = 10; ++ } ++ if (*cp == '-') { ++ is_neg = 1; ++ cp++; ++ } ++ while (isxdigit(*cp) && ++ (value = isdigit(*cp) ? *cp - '0' : ++ (islower(*cp) ? toupper(*cp) : *cp) - ++ 'A' + 10) < base) { ++ result = result * base + value; ++ cp++; ++ } ++ if (is_neg) ++ result = (unsigned int)((int)result * (-1)); ++ ++ if (endp) ++ *endp = (char *)cp; ++ return result; ++} ++ ++/* ++ * aic_priv_cmd handers. ++ */ ++static int aic_priv_cmd_set_tx(struct rwnx_hw *rwnx_hw, int argc, char *argv[], ++ char *command) ++{ ++ cmd_rf_settx_t settx_param; ++ u8_l set_p = 0; ++ u8_l lvl_band, lvl_mod, lvl_idx, lvl_pwr = 0; ++ u8_l buf[10]; ++#ifdef CONFIG_POWER_LIMIT ++ int8_t max_pwr; ++ uint8_t r_idx; ++ txpwr_loss_conf_t txpwr_loss_tmp; ++ txpwr_loss_conf_t *txpwr_loss; ++ txpwr_loss = &txpwr_loss_tmp; ++#endif ++#ifdef AICWF_SDIO_SUPPORT ++ struct aic_sdio_dev *dev = g_rwnx_plat->sdiodev; ++#endif ++#ifdef AICWF_USB_SUPPORT ++ struct aic_usb_dev *dev = g_rwnx_plat->usbdev; ++#endif ++ ++ if (argc < 6) ++ return -EINVAL; ++ ++ settx_param.chan = command_strtoul(argv[1], NULL, 10); ++ settx_param.bw = command_strtoul(argv[2], NULL, 10); ++ settx_param.mode = command_strtoul(argv[3], NULL, 10); ++ settx_param.rate = command_strtoul(argv[4], NULL, 10); ++ settx_param.length = command_strtoul(argv[5], NULL, 10); ++ if (argc > 6) { ++ settx_param.tx_intv_us = command_strtoul(argv[6], NULL, 10); ++ } else { ++ settx_param.tx_intv_us = 10000; // set default val 10ms ++ } ++ if (argc > 7) { ++ if (dev->chipid == PRODUCT_ID_AIC8801) { ++ AICWFDBG(LOGERROR, "unsupported cmd\n"); ++ return -EINVAL; ++ } ++ lvl_pwr = command_strtoul(argv[7], NULL, 10); ++ AICWFDBG(LOGINFO, "lvl_pwr: %d\n", lvl_pwr); ++ ++ if (settx_param.chan >= 36) ++ lvl_band = 2; ++ else ++ lvl_band = 1; ++ if (settx_param.mode == 0) ++ lvl_mod = 0; ++ else if (settx_param.mode == 2 || settx_param.mode == 4) ++ lvl_mod = 1; ++ else if (settx_param.mode == 5) ++ lvl_mod = 2; ++ if (settx_param.mode >= 4) ++ lvl_idx = settx_param.rate & 0xF; ++ else if (settx_param.mode >= 2) ++ lvl_idx = settx_param.rate & 0x7; ++ else ++ lvl_idx = settx_param.rate; ++ ++ buf[0] = lvl_band; ++ buf[1] = lvl_mod; ++ buf[2] = lvl_idx; ++ buf[3] = lvl_pwr; ++ ++ set_p = 1; ++ } ++ settx_param.max_pwr = POWER_LEVEL_INVALID_VAL; ++ AICWFDBG(LOGINFO, "txparam:%d,%d,%d,%d,%d,%d\n", settx_param.chan, ++ settx_param.bw, settx_param.mode, settx_param.rate, ++ settx_param.length, settx_param.tx_intv_us); ++ ++#ifdef CONFIG_POWER_LIMIT ++ r_idx = get_ccode_region(country_code); ++ txpwr_loss = &txpwr_loss_tmp; ++ get_userconfig_txpwr_loss(txpwr_loss); ++ if (txpwr_loss->loss_enable_2g4 == 1) ++ AICWFDBG(LOGINFO, "%s:loss_value_2g4: %d\r\n", __func__, ++ txpwr_loss->loss_value_2g4); ++ if (txpwr_loss->loss_enable_5g == 1) ++ AICWFDBG(LOGINFO, "%s:loss_value_5g: %d\r\n", __func__, ++ txpwr_loss->loss_value_5g); ++ max_pwr = get_powerlimit_by_chnum(settx_param.chan, r_idx, ++ settx_param.bw); ++ if (settx_param.chan >= 36) { ++ if (txpwr_loss->loss_enable_5g == 1) ++ max_pwr -= txpwr_loss->loss_value_5g; ++ } else { ++ if (txpwr_loss->loss_enable_2g4 == 1) ++ max_pwr -= txpwr_loss->loss_value_2g4; ++ } ++ ++ if (!set_p || (lvl_pwr == 255)) { ++ settx_param.max_pwr = max_pwr; ++ AICWFDBG(LOGINFO, "max_pwr:%d\n", settx_param.max_pwr); ++ } else ++ AICWFDBG(LOGINFO, ++ "the specified power is input without power limit\n"); ++#endif ++ ++ if (set_p && (lvl_pwr != 255)) ++ rwnx_send_rftest_req(rwnx_hw, RDWR_PWRLVL, 4, buf, &cfm); ++ ++ rwnx_send_rftest_req(rwnx_hw, SET_TX, sizeof(cmd_rf_settx_t), ++ (u8_l *)&settx_param, NULL); ++ return 0; ++} ++ ++static int aic_priv_cmd_set_txstop(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ rwnx_send_rftest_req(rwnx_hw, SET_TXSTOP, 0, NULL, NULL); ++ return 0; ++} ++ ++static int aic_priv_cmd_set_rx(struct rwnx_hw *rwnx_hw, int argc, char *argv[], ++ char *command) ++{ ++ cmd_rf_rx_t setrx_param; ++ ++ if (argc < 3) { ++ return -EINVAL; ++ } ++ setrx_param.chan = command_strtoul(argv[1], NULL, 10); ++ setrx_param.bw = command_strtoul(argv[2], NULL, 10); ++ rwnx_send_rftest_req(rwnx_hw, SET_RX, sizeof(cmd_rf_rx_t), ++ (u8_l *)&setrx_param, NULL); ++ return 0; ++} ++ ++static int aic_priv_cmd_get_rx_result(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ rwnx_send_rftest_req(rwnx_hw, GET_RX_RESULT, 0, NULL, &cfm); ++ memcpy(command, &cfm.rftest_result[0], 8); ++ return 8; ++} ++ ++static int aic_priv_cmd_set_rxstop(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ rwnx_send_rftest_req(rwnx_hw, SET_RXSTOP, 0, NULL, NULL); ++ return 0; ++} ++ ++static int aic_priv_cmd_set_tx_tone(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u8_l func = 0; ++ u8_l buf[2]; ++ s8_l freq_ = 0; ++ ++ AICWFDBG(LOGINFO, "%s argc:%d\n", argv[0], argc); ++ if ((argc == 2) || (argc == 3)) { ++ AICWFDBG(LOGINFO, "argv 1:%s\n", argv[1]); ++ func = (u8_l)command_strtoul(argv[1], NULL, 16); ++ if (argc == 3) { ++ AICWFDBG(LOGINFO, "argv 2:%s\n", argv[2]); ++ freq_ = (u8_l)command_strtoul(argv[2], NULL, 10); ++ } else { ++ freq_ = 0; ++ }; ++ buf[0] = func; ++ buf[1] = (u8_l)freq_; ++ rwnx_send_rftest_req(rwnx_hw, SET_TXTONE, argc - 1, buf, NULL); ++ } else { ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int aic_priv_cmd_set_rx_meter(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ s8_l freq = 0; ++ ++ freq = (int)command_strtoul(argv[1], NULL, 10); ++ rwnx_send_rftest_req(rwnx_hw, SET_RX_METER, sizeof(freq), (u8_l *)&freq, ++ NULL); ++ return 0; ++} ++ ++static int aic_priv_cmd_set_set_power(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u8_l ana_pwr; ++ u8_l dig_pwr; ++ u8_l pwr; ++#ifdef AICWF_SDIO_SUPPORT ++ struct aic_sdio_dev *dev = g_rwnx_plat->sdiodev; ++#endif ++#ifdef AICWF_USB_SUPPORT ++ struct aic_usb_dev *dev = g_rwnx_plat->usbdev; ++#endif ++ ++ if (dev->chipid == PRODUCT_ID_AIC8801) { ++ ana_pwr = command_strtoul(argv[1], NULL, 16); ++ dig_pwr = command_strtoul(argv[2], NULL, 16); ++ pwr = (ana_pwr << 4 | dig_pwr); ++ if (ana_pwr > 0xf || dig_pwr > 0xf) ++ return -EINVAL; ++ } else { ++ ana_pwr = command_strtoul(argv[1], NULL, 10); ++ pwr = ana_pwr; ++ if (ana_pwr > 0x1e) ++ return -EINVAL; ++ } ++ AICWFDBG(LOGINFO, "pwr =%x\r\n", pwr); ++ rwnx_send_rftest_req(rwnx_hw, SET_POWER, sizeof(pwr), (u8_l *)&pwr, ++ NULL); ++ return 0; ++} ++ ++static int aic_priv_cmd_set_xtal_cap(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u8_l xtal_cap; ++ ++ if (argc < 2) ++ return -EINVAL; ++ ++ xtal_cap = command_strtoul(argv[1], NULL, 10); ++ AICWFDBG(LOGINFO, "xtal_cap =%x\r\n", xtal_cap); ++ rwnx_send_rftest_req(rwnx_hw, SET_XTAL_CAP, sizeof(xtal_cap), ++ (u8_l *)&xtal_cap, &cfm); ++ memcpy(command, &cfm.rftest_result[0], 4); ++ return 4; ++} ++ ++static int aic_priv_cmd_set_xtal_cap_fine(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u8_l xtal_cap_fine; ++ ++ if (argc < 2) ++ return -EINVAL; ++ ++ xtal_cap_fine = command_strtoul(argv[1], NULL, 10); ++ AICWFDBG(LOGINFO, "xtal_cap_fine =%x\r\n", xtal_cap_fine); ++ rwnx_send_rftest_req(rwnx_hw, SET_XTAL_CAP_FINE, sizeof(xtal_cap_fine), ++ (u8_l *)&xtal_cap_fine, &cfm); ++ memcpy(command, &cfm.rftest_result[0], 4); ++ return 4; ++} ++ ++static int aic_priv_cmd_get_efuse_block(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ cmd_rf_getefuse_t getefuse_param; ++ ++ if (argc < 2) ++ return -EINVAL; ++ ++ getefuse_param.block = command_strtoul(argv[1], NULL, 10); ++ rwnx_send_rftest_req(rwnx_hw, GET_EFUSE_BLOCK, ++ sizeof(cmd_rf_getefuse_t), (u8_l *)&getefuse_param, ++ &cfm); ++ AICWFDBG(LOGINFO, "get val=%x\r\n", cfm.rftest_result[0]); ++ memcpy(command, &cfm.rftest_result[0], 4); ++ return 4; ++} ++ ++static int aic_priv_cmd_set_freq_cal(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ cmd_rf_setfreq_t cmd_setfreq; ++ ++ if (argc < 2) ++ return -EINVAL; ++ ++ cmd_setfreq.val = command_strtoul(argv[1], NULL, 16); ++ AICWFDBG(LOGINFO, "param:%x\r\n", cmd_setfreq.val); ++ rwnx_send_rftest_req(rwnx_hw, SET_FREQ_CAL, sizeof(cmd_rf_setfreq_t), ++ (u8_l *)&cmd_setfreq, &cfm); ++ memcpy(command, &cfm.rftest_result[0], 4); ++ return 4; ++} ++ ++static int aic_priv_cmd_set_freq_cal_fine(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ cmd_rf_setfreq_t cmd_setfreq; ++ ++ if (argc < 2) ++ return -EINVAL; ++ ++ cmd_setfreq.val = command_strtoul(argv[1], NULL, 16); ++ AICWFDBG(LOGINFO, "param:%x\r\n", cmd_setfreq.val); ++ rwnx_send_rftest_req(rwnx_hw, SET_FREQ_CAL_FINE, ++ sizeof(cmd_rf_setfreq_t), (u8_l *)&cmd_setfreq, ++ &cfm); ++ memcpy(command, &cfm.rftest_result[0], 4); ++ return 4; ++} ++ ++static int aic_priv_cmd_get_freq_cal(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u32_l val; ++#ifdef AICWF_SDIO_SUPPORT ++ struct aic_sdio_dev *dev = g_rwnx_plat->sdiodev; ++#endif ++#ifdef AICWF_USB_SUPPORT ++ struct aic_usb_dev *dev = g_rwnx_plat->usbdev; ++#endif ++ ++ rwnx_send_rftest_req(rwnx_hw, GET_FREQ_CAL, 0, NULL, &cfm); ++ memcpy(command, &cfm.rftest_result[0], 4); ++ val = cfm.rftest_result[0]; ++ if (dev->chipid != PRODUCT_ID_AIC8801) { ++ AICWFDBG(LOGINFO, ++ "cap=0x%x (remain:%x), cap_fine=%x (remain:%x)\n", ++ val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff, ++ (val >> 24) & 0xff); ++ } else { ++ AICWFDBG(LOGINFO, "cap=0x%x, cap_fine=0x%x\n", val & 0xff, ++ (val >> 8) & 0xff); ++ } ++ return 4; ++} ++ ++static int aic_priv_cmd_set_mac_addr(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u8_l mac_addr[6]; ++ ++ if (argc < 7) ++ return -EINVAL; ++ ++ mac_addr[5] = command_strtoul(argv[1], NULL, 16); ++ mac_addr[4] = command_strtoul(argv[2], NULL, 16); ++ mac_addr[3] = command_strtoul(argv[3], NULL, 16); ++ mac_addr[2] = command_strtoul(argv[4], NULL, 16); ++ mac_addr[1] = command_strtoul(argv[5], NULL, 16); ++ mac_addr[0] = command_strtoul(argv[6], NULL, 16); ++ AICWFDBG(LOGINFO, "set macaddr:%x,%x,%x,%x,%x,%x\n", mac_addr[5], ++ mac_addr[4], mac_addr[3], mac_addr[2], mac_addr[1], ++ mac_addr[0]); ++ rwnx_send_rftest_req(rwnx_hw, SET_MAC_ADDR, sizeof(mac_addr), ++ (u8_l *)&mac_addr, NULL); ++ return 0; ++} ++ ++static int aic_priv_cmd_get_mac_addr(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u32_l addr0, addr1; ++#ifdef AICWF_SDIO_SUPPORT ++ struct aic_sdio_dev *dev = g_rwnx_plat->sdiodev; ++#endif ++#ifdef AICWF_USB_SUPPORT ++ struct aic_usb_dev *dev = g_rwnx_plat->usbdev; ++#endif ++ ++ rwnx_send_rftest_req(rwnx_hw, GET_MAC_ADDR, 0, NULL, &cfm); ++ memcpy(command, &cfm.rftest_result[0], 8); ++ addr0 = cfm.rftest_result[0]; ++ if ((dev->chipid == PRODUCT_ID_AIC8800DC) || ++ (dev->chipid == PRODUCT_ID_AIC8800DW)) { ++ int rem_cnt = (cfm.rftest_result[1] >> 16) & 0x00FF; ++ addr1 = cfm.rftest_result[1] & 0x0000FFFF; ++ AICWFDBG(LOGINFO, "0x%x,0x%x (remain:%x)\n", addr0, addr1, ++ rem_cnt); ++ } else { ++ addr1 = cfm.rftest_result[1]; ++ AICWFDBG(LOGINFO, "0x%x,0x%x\n", addr0, addr1); ++ } ++ return 8; ++} ++ ++static int aic_priv_cmd_set_bt_mac_addr(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u8_l mac_addr[6]; ++ ++ if (argc < 7) ++ return -EINVAL; ++ ++ mac_addr[5] = command_strtoul(argv[1], NULL, 16); ++ mac_addr[4] = command_strtoul(argv[2], NULL, 16); ++ mac_addr[3] = command_strtoul(argv[3], NULL, 16); ++ mac_addr[2] = command_strtoul(argv[4], NULL, 16); ++ mac_addr[1] = command_strtoul(argv[5], NULL, 16); ++ mac_addr[0] = command_strtoul(argv[6], NULL, 16); ++ AICWFDBG(LOGINFO, "set bt macaddr:%x,%x,%x,%x,%x,%x\n", mac_addr[5], ++ mac_addr[4], mac_addr[3], mac_addr[2], mac_addr[1], ++ mac_addr[0]); ++ rwnx_send_rftest_req(rwnx_hw, SET_BT_MAC_ADDR, sizeof(mac_addr), ++ (u8_l *)&mac_addr, NULL); ++ return 0; ++} ++ ++static int aic_priv_cmd_get_bt_mac_addr(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u32_l addr0, addr1; ++#ifdef AICWF_SDIO_SUPPORT ++ struct aic_sdio_dev *dev = g_rwnx_plat->sdiodev; ++#endif ++#ifdef AICWF_USB_SUPPORT ++ struct aic_usb_dev *dev = g_rwnx_plat->usbdev; ++#endif ++ ++ rwnx_send_rftest_req(rwnx_hw, GET_BT_MAC_ADDR, 0, NULL, &cfm); ++ memcpy(command, &cfm.rftest_result[0], 8); ++ addr0 = cfm.rftest_result[0]; ++ if ((dev->chipid == PRODUCT_ID_AIC8800DC) || ++ (dev->chipid == PRODUCT_ID_AIC8800DW)) { ++ int rem_cnt = (cfm.rftest_result[1] >> 16) & 0x00FF; ++ addr1 = cfm.rftest_result[1] & 0x0000FFFF; ++ AICWFDBG(LOGINFO, "0x%x,0x%x (remain:%x)\n", addr0, addr1, ++ rem_cnt); ++ } else { ++ addr1 = cfm.rftest_result[1]; ++ AICWFDBG(LOGINFO, "0x%x,0x%x\n", addr0, addr1); ++ } ++ return 8; ++} ++ ++static int aic_priv_cmd_set_vendor_info(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u8_l vendor_info; ++#ifdef AICWF_SDIO_SUPPORT ++ struct aic_sdio_dev *dev = g_rwnx_plat->sdiodev; ++#endif ++#ifdef AICWF_USB_SUPPORT ++ struct aic_usb_dev *dev = g_rwnx_plat->usbdev; ++#endif ++ ++ vendor_info = command_strtoul(argv[1], NULL, 16); ++ AICWFDBG(LOGINFO, "set vendor info:%x\n", vendor_info); ++ rwnx_send_rftest_req(rwnx_hw, SET_VENDOR_INFO, 1, &vendor_info, &cfm); ++ if ((dev->chipid == PRODUCT_ID_AIC8800DC) || ++ (dev->chipid == PRODUCT_ID_AIC8800DW)) { ++ memcpy(command, &cfm.rftest_result[0], 2); ++ return 2; ++ } else { ++ memcpy(command, &cfm.rftest_result[0], 1); ++ return 1; ++ } ++ AICWFDBG(LOGINFO, "0x%x\n", cfm.rftest_result[0]); ++} ++ ++static int aic_priv_cmd_get_vendor_info(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++#ifdef AICWF_SDIO_SUPPORT ++ struct aic_sdio_dev *dev = g_rwnx_plat->sdiodev; ++#endif ++#ifdef AICWF_USB_SUPPORT ++ struct aic_usb_dev *dev = g_rwnx_plat->usbdev; ++#endif ++ ++ rwnx_send_rftest_req(rwnx_hw, GET_VENDOR_INFO, 0, NULL, &cfm); ++ if ((dev->chipid == PRODUCT_ID_AIC8800DC) || ++ (dev->chipid == PRODUCT_ID_AIC8800DW)) { ++ memcpy(command, &cfm.rftest_result[0], 2); ++ return 2; ++ } else { ++ memcpy(command, &cfm.rftest_result[0], 1); ++ return 1; ++ } ++ AICWFDBG(LOGINFO, "0x%x\n", cfm.rftest_result[0]); ++} ++ ++static int aic_priv_cmd_rdwr_pwrmm(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ if (argc <= 1) { // read cur ++ rwnx_send_rftest_req(rwnx_hw, RDWR_PWRMM, 0, NULL, &cfm); ++ } else { // write ++ u8_l pwrmm = (u8_l)command_strtoul(argv[1], NULL, 16); ++ pwrmm = (pwrmm) ? 1 : 0; ++ AICWFDBG(LOGINFO, "set pwrmm = %x\r\n", pwrmm); ++ rwnx_send_rftest_req(rwnx_hw, RDWR_PWRMM, sizeof(pwrmm), ++ (u8_l *)&pwrmm, &cfm); ++ } ++ memcpy(command, &cfm.rftest_result[0], 4); ++ return 4; ++} ++ ++static int aic_priv_cmd_rdwr_pwridx(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u8_l func = 0; ++#ifdef AICWF_SDIO_SUPPORT ++ struct aic_sdio_dev *dev = g_rwnx_plat->sdiodev; ++#endif ++#ifdef AICWF_USB_SUPPORT ++ struct aic_usb_dev *dev = g_rwnx_plat->usbdev; ++#endif ++ ++ if (dev->chipid != PRODUCT_ID_AIC8801) { ++ AICWFDBG(LOGERROR, "unsupported cmd\n"); ++ return -EINVAL; ++ } ++ if (argc > 1) { ++ func = (u8_l)command_strtoul(argv[1], NULL, 16); ++ } ++ if (func == 0) { // read cur ++ rwnx_send_rftest_req(rwnx_hw, RDWR_PWRIDX, 0, NULL, &cfm); ++ } else if (func <= 2) { // write 2.4g/5g pwr idx ++ if (argc > 3) { ++ u8_l type = (u8_l)command_strtoul(argv[2], NULL, 16); ++ u8_l pwridx = (u8_l)command_strtoul(argv[3], NULL, 10); ++ u8_l buf[3] = { func, type, pwridx }; ++ AICWFDBG(LOGINFO, "set pwridx:[%x][%x]=%x\r\n", func, ++ type, pwridx); ++ rwnx_send_rftest_req(rwnx_hw, RDWR_PWRIDX, sizeof(buf), ++ buf, &cfm); ++ } else { ++ return -EINVAL; ++ } ++ } else { ++ return -EINVAL; ++ } ++ memcpy(command, &cfm.rftest_result[0], 9); ++ return 9; ++} ++ ++static int aic_priv_cmd_rdwr_pwrlvl(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u8_l func = 0; ++#ifdef AICWF_SDIO_SUPPORT ++ struct aic_sdio_dev *dev = g_rwnx_plat->sdiodev; ++#endif ++#ifdef AICWF_USB_SUPPORT ++ struct aic_usb_dev *dev = g_rwnx_plat->usbdev; ++#endif ++ ++ if (dev->chipid == PRODUCT_ID_AIC8801) { ++ AICWFDBG(LOGERROR, "unsupported cmd\n"); ++ return -EINVAL; ++ } ++ if (argc > 1) { ++ func = (u8_l)command_strtoul(argv[1], NULL, 16); ++ } ++ if (func == 0) { // read cur ++ rwnx_send_rftest_req(rwnx_hw, RDWR_PWRLVL, 0, NULL, &cfm); ++ } else if (func <= 2) { // write 2.4g/5g pwr lvl ++ if (argc > 4) { ++ u8_l grp = (u8_l)command_strtoul(argv[2], NULL, 16); ++ u8_l idx, size; ++ u8_l buf[14] = { ++ func, ++ grp, ++ }; ++ if (argc > 12) { // set all grp ++ AICWFDBG(LOGINFO, ++ "set pwrlvl %s:\n" ++ " [%x] =", ++ (func == 1) ? "2.4g" : "5g", grp); ++ if (grp == 1) { // TXPWR_LVL_GRP_11N_11AC ++ size = 10; ++ } else { ++ size = 12; ++ } ++ for (idx = 0; idx < size; idx++) { ++ s8_l pwrlvl = (s8_l)command_strtoul( ++ argv[3 + idx], NULL, 10); ++ buf[2 + idx] = (u8_l)pwrlvl; ++ if (idx && !(idx & 0x3)) { ++ AICWFDBG(LOGINFO, " "); ++ } ++ AICWFDBG(LOGINFO, " %2d", pwrlvl); ++ } ++ AICWFDBG(LOGINFO, "\n"); ++ size += 2; ++ } else { // set grp[idx] ++ u8_l idx = (u8_l)command_strtoul(argv[3], NULL, ++ 10); ++ s8_l pwrlvl = (s8_l)command_strtoul(argv[4], ++ NULL, 10); ++ buf[2] = idx; ++ buf[3] = (u8_l)pwrlvl; ++ size = 4; ++ AICWFDBG(LOGINFO, ++ "set pwrlvl %s:\n" ++ " [%x][%d] = %d\n", ++ (func == 1) ? "2.4g" : "5g", grp, idx, ++ pwrlvl); ++ } ++ rwnx_send_rftest_req(rwnx_hw, RDWR_PWRLVL, size, buf, ++ &cfm); ++ } else { ++ AICWFDBG(LOGERROR, "wrong args\n"); ++ return -EINVAL; ++ } ++ } else { ++ AICWFDBG(LOGERROR, "wrong func: %x\n", func); ++ return -EINVAL; ++ } ++ if (dev->chipid == PRODUCT_ID_AIC8800D80 || ++ dev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ memcpy(command, &cfm.rftest_result[0], 6 * 12); ++ return (6 * 12); ++ } else { ++ memcpy(command, &cfm.rftest_result[0], 3 * 12); ++ return (3 * 12); ++ } ++} ++ ++static int aic_priv_cmd_rdwr_pwrofst(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u8_l func = 0; ++ int res_len = 0; ++#ifdef AICWF_SDIO_SUPPORT ++ struct aic_sdio_dev *dev = g_rwnx_plat->sdiodev; ++#endif ++#ifdef AICWF_USB_SUPPORT ++ struct aic_usb_dev *dev = g_rwnx_plat->usbdev; ++#endif ++ ++ if (argc > 1) { ++ func = (u8_l)command_strtoul(argv[1], NULL, 16); ++ } ++ if (func == 0) { // read cur ++ rwnx_send_rftest_req(rwnx_hw, RDWR_PWROFST, 0, NULL, &cfm); ++ } else if (func <= 4) { // write 2.4g/5g pwr ofst and ant0/1 ++ if ((argc > 4) && (dev->chipid == PRODUCT_ID_AIC8800D80 || ++ dev->chipid == PRODUCT_ID_AIC8800D80X2)) { ++ u8_l type = (u8_l)command_strtoul(argv[2], NULL, 16); ++ u8_l chgrp = (u8_l)command_strtoul(argv[3], NULL, 16); ++ s8_l pwrofst = (u8_l)command_strtoul(argv[4], NULL, 10); ++ u8_l buf[4] = { func, type, chgrp, (u8_l)pwrofst }; ++ AICWFDBG(LOGINFO, "set pwrofst_%s:[%x][%x]=%d\r\n", ++ (func == 1) ? "2.4g" : "5g", type, chgrp, ++ pwrofst); ++ rwnx_send_rftest_req(rwnx_hw, RDWR_PWROFST, sizeof(buf), ++ buf, &cfm); ++ } else if ((argc > 3) && ++ (dev->chipid != PRODUCT_ID_AIC8800D80) && ++ (dev->chipid != PRODUCT_ID_AIC8800D80X2)) { ++ 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 }; ++ AICWFDBG(LOGINFO, "set pwrofst_%s:[%x]=%d\r\n", ++ (func == 1) ? "2.4g" : "5g", chgrp, pwrofst); ++ rwnx_send_rftest_req(rwnx_hw, RDWR_PWROFST, sizeof(buf), ++ buf, &cfm); ++ } else { ++ return -EINVAL; ++ } ++ } else { ++ AICWFDBG(LOGERROR, "wrong func: %x\n", func); ++ return -EINVAL; ++ } ++ if ((dev->chipid == PRODUCT_ID_AIC8800DC) || ++ (dev->chipid == PRODUCT_ID_AIC8800DW)) { // 3 = 3 (2.4g) ++ res_len = 3; ++ } else if (dev->chipid == ++ PRODUCT_ID_AIC8800D80) { // 3 * 2 (2.4g) + 3 * 6 (5g) ++ res_len = 3 * 3 + 3 * 6; ++ } else if (dev->chipid == PRODUCT_ID_AIC8800D80X2) { // ant0/1 ++ res_len = (3 * 3 + 3 * 6) * 2; ++ } else { ++ res_len = 3 + 4; ++ } ++ memcpy(command, &cfm.rftest_result[0], res_len); ++ return res_len; ++} ++ ++static int aic_priv_cmd_rdwr_pwrofstfine(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u8_l func = 0; ++ ++ if (argc > 1) { ++ func = (u8_l)command_strtoul(argv[1], NULL, 16); ++ } ++ if (func == 0) { // read cur ++ rwnx_send_rftest_req(rwnx_hw, RDWR_PWROFSTFINE, 0, NULL, &cfm); ++ } else if (func <= 2) { // write 2.4g/5g pwr ofst ++ if (argc > 3) { ++ u8_l chgrp = (u8_l)command_strtoul(argv[2], NULL, 16); ++ s8_l pwrofst = (u8_l)command_strtoul(argv[3], NULL, 10); ++ u8_l buf[3] = { func, chgrp, (u8_l)pwrofst }; ++ AICWFDBG(LOGINFO, "set pwrofstfine:[%x][%x]=%d\r\n", ++ func, chgrp, pwrofst); ++ rwnx_send_rftest_req(rwnx_hw, RDWR_PWROFSTFINE, ++ sizeof(buf), buf, &cfm); ++ } else { ++ AICWFDBG(LOGERROR, "wrong args\n"); ++ return -EINVAL; ++ } ++ } else { ++ AICWFDBG(LOGERROR, "wrong func: %x\n", func); ++ return -EINVAL; ++ } ++ memcpy(command, &cfm.rftest_result[0], 7); ++ return 7; ++} ++ ++static int aic_priv_cmd_rdwr_drvibit(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u8_l func = 0; ++ ++ if (argc > 1) { ++ func = (u8_l)command_strtoul(argv[1], NULL, 16); ++ } ++ if (func == 0) { // read cur ++ rwnx_send_rftest_req(rwnx_hw, RDWR_DRVIBIT, 0, NULL, &cfm); ++ } else if (func == 1) { // write 2.4g pa drv_ibit ++ if (argc > 2) { ++ u8_l ibit = (u8_l)command_strtoul(argv[2], NULL, 16); ++ u8_l buf[2] = { func, ibit }; ++ AICWFDBG(LOGINFO, "set drvibit:[%x]=%x\r\n", func, ++ ibit); ++ rwnx_send_rftest_req(rwnx_hw, RDWR_DRVIBIT, sizeof(buf), ++ buf, &cfm); ++ } else { ++ AICWFDBG(LOGERROR, "wrong args\n"); ++ return -EINVAL; ++ } ++ } else { ++ AICWFDBG(LOGERROR, "wrong func: %x\n", func); ++ return -EINVAL; ++ } ++ memcpy(command, &cfm.rftest_result[0], 16); ++ return 16; ++} ++ ++static int aic_priv_cmd_rdwr_efuse_pwrofst(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u8_l func = 0; ++ int res_len = 0; ++#ifdef AICWF_SDIO_SUPPORT ++ struct aic_sdio_dev *dev = g_rwnx_plat->sdiodev; ++#endif ++#ifdef AICWF_USB_SUPPORT ++ struct aic_usb_dev *dev = g_rwnx_plat->usbdev; ++#endif ++ ++ if (argc > 1) { ++ func = (u8_l)command_strtoul(argv[1], NULL, 16); ++ } ++ if (func == 0) { // read cur ++ rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_PWROFST, 0, NULL, ++ &cfm); ++ } else if (func <= 4) { // write 2.4g/5g pwr ofst and ant0/1 ++ if ((argc > 4) && (dev->chipid == PRODUCT_ID_AIC8800D80 || ++ dev->chipid == PRODUCT_ID_AIC8800D80X2)) { ++ u8_l type = (u8_l)command_strtoul(argv[2], NULL, 16); ++ u8_l chgrp = (u8_l)command_strtoul(argv[3], NULL, 16); ++ s8_l pwrofst = (u8_l)command_strtoul(argv[4], NULL, 10); ++ u8_l buf[4] = { func, type, chgrp, (u8_l)pwrofst }; ++ AICWFDBG(LOGINFO, ++ "set efuse pwrofst_%s:[%x][%x]=%d\r\n", ++ (func == 1) ? "2.4g" : "5g", type, chgrp, ++ pwrofst); ++ rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_PWROFST, ++ sizeof(buf), buf, &cfm); ++ } else if ((argc > 3) && ++ (dev->chipid != PRODUCT_ID_AIC8800D80) && ++ (dev->chipid != PRODUCT_ID_AIC8800D80X2)) { ++ 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 }; ++ AICWFDBG(LOGINFO, "set efuse pwrofst_%s:[%x]=%d\r\n", ++ (func == 1) ? "2.4g" : "5g", chgrp, pwrofst); ++ rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_PWROFST, ++ sizeof(buf), buf, &cfm); ++ } else { ++ AICWFDBG(LOGERROR, "wrong args\n"); ++ return -EINVAL; ++ } ++ } else { ++ AICWFDBG(LOGERROR, "wrong func: %x\n", func); ++ return -EINVAL; ++ } ++ if ((dev->chipid == PRODUCT_ID_AIC8800DC) || ++ (dev->chipid == PRODUCT_ID_AIC8800DW)) { // 6 = 3 (2.4g) * 2 ++ res_len = 3 * 2; ++ } else if (dev->chipid == PRODUCT_ID_AIC8800D80 || ++ dev->chipid == ++ PRODUCT_ID_AIC8800D80X2) { // 3 * 2 (2.4g) + 3 * 6 (5g) ++ res_len = (3 * 3 + 3 * 6) * 2; ++ } else { // 7 = 3(2.4g) + 4(5g) ++ res_len = 3 + 4; ++ } ++ memcpy(command, &cfm.rftest_result[0], res_len); ++ return res_len; ++} ++ ++static int aic_priv_cmd_rdwr_efuse_pwrofstfine(struct rwnx_hw *rwnx_hw, ++ int argc, char *argv[], ++ char *command) ++{ ++ u8_l func = 0; ++ ++ if (argc > 1) { ++ func = (u8_l)command_strtoul(argv[1], NULL, 16); ++ } ++ if (func == 0) { // read cur ++ rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_PWROFSTFINE, 0, NULL, ++ &cfm); ++ } else if (func <= 2) { // write 2.4g/5g pwr ofst ++ if (argc > 3) { ++ u8_l chgrp = (u8_l)command_strtoul(argv[2], NULL, 16); ++ s8_l pwrofst = (u8_l)command_strtoul(argv[3], NULL, 10); ++ u8_l buf[3] = { func, chgrp, (u8_l)pwrofst }; ++ AICWFDBG(LOGINFO, "set pwrofstfine:[%x][%x]=%d\r\n", ++ func, chgrp, pwrofst); ++ rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_PWROFSTFINE, ++ sizeof(buf), buf, &cfm); ++ } else { ++ AICWFDBG(LOGERROR, "wrong args\n"); ++ return -EINVAL; ++ } ++ } else { ++ AICWFDBG(LOGERROR, "wrong func: %x\n", func); ++ return -EINVAL; ++ } ++ memcpy(command, &cfm.rftest_result[0], 7); ++ return 7; ++} ++ ++static int aic_priv_cmd_rdwr_efuse_drvibit(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u8_l func = 0; ++ ++ if (argc > 1) { ++ func = (u8_l)command_strtoul(argv[1], NULL, 16); ++ } ++ if (func == 0) { // read cur ++ rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_DRVIBIT, 0, NULL, ++ &cfm); ++ } else if (func == 1) { // write 2.4g pa drv_ibit ++ if (argc > 2) { ++ u8_l ibit = (u8_l)command_strtoul(argv[2], NULL, 16); ++ u8_l buf[2] = { func, ibit }; ++ AICWFDBG(LOGINFO, "set efuse drvibit:[%x]=%x\r\n", func, ++ ibit); ++ rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_DRVIBIT, ++ sizeof(buf), buf, &cfm); ++ } else { ++ AICWFDBG(LOGERROR, "wrong args\n"); ++ return -EINVAL; ++ } ++ } else { ++ AICWFDBG(LOGERROR, "wrong func: %x\n", func); ++ return -EINVAL; ++ } ++ memcpy(command, &cfm.rftest_result[0], 4); ++ return 4; ++} ++ ++static int aic_priv_cmd_rdwr_efuse_usrdata(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ cmd_ef_usrdata_t cmd_ef_usrdata; ++ ++ if (argc <= 1) { // read all ++ cmd_ef_usrdata.func = 0; ++ cmd_ef_usrdata.cnt = 3; ++ } else if (argc >= 2) { // read/write ++ cmd_ef_usrdata.func = (u8_l)command_strtoul(argv[1], NULL, 10); ++ cmd_ef_usrdata.cnt = (u8_l)command_strtoul(argv[2], NULL, 10); ++ if (cmd_ef_usrdata.func == 1) { ++ int idx; ++ for (idx = 0; idx < cmd_ef_usrdata.cnt; idx++) { ++ cmd_ef_usrdata.usrdata[idx] = ++ (u32_l)command_strtoul(argv[3 + idx], ++ NULL, 16); ++ } ++ } ++ } else { ++ AICWFDBG(LOGERROR, "wrong argc: %x\n", argc); ++ return -EINVAL; ++ } ++ rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_USRDATA, ++ sizeof(cmd_ef_usrdata), (u8_l *)&cmd_ef_usrdata, ++ &cfm); ++ memcpy(command, &cfm.rftest_result[0], 12); ++ return 12; ++} ++ ++static int aic_priv_cmd_rdwr_efuse_sdiocfg(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u8_l func = 0; ++ ++ if (argc > 1) { ++ func = (u8_l)command_strtoul(argv[1], NULL, 16); ++ } ++ if (func == 0) { // read cur ++ rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_SDIOCFG, 0, NULL, ++ &cfm); ++ } else if (func == 1) { // write sdiocfg ++ if (argc > 2) { ++ u8_l ibit = (u8_l)command_strtoul(argv[2], NULL, 16); ++ u8_l buf[2] = { func, ibit }; ++ AICWFDBG(LOGINFO, "set efuse sdiocfg:[%x]=%x\r\n", func, ++ ibit); ++ rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_SDIOCFG, ++ sizeof(buf), buf, &cfm); ++ } else { ++ AICWFDBG(LOGERROR, "wrong args\n"); ++ return -EINVAL; ++ } ++ } else { ++ AICWFDBG(LOGERROR, "wrong func: %x\n", func); ++ return -EINVAL; ++ } ++ memcpy(command, &cfm.rftest_result[0], 4); ++ return 4; ++} ++ ++static int aic_priv_cmd_rdwr_efuse_usbvidpid(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u8_l func = 0; ++ AICWFDBG(LOGINFO, "read/write usb vid/pid into efuse\n"); ++ if (argc > 1) { ++ func = (u8_l)command_strtoul(argv[1], NULL, 16); ++ } ++ if (func == 0) { // read cur ++ rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_USBVIDPID, 0, NULL, ++ &cfm); ++ } else if (func == 1) { // write USB vid+pid ++ if (argc > 2) { ++ u32_l usb_id = ++ (u32_l)command_strtoul(argv[2], NULL, 16); ++ u8_l buf[5] = { func, (u8_l)usb_id, (u8_l)(usb_id >> 8), ++ (u8_l)(usb_id >> 16), ++ (u8_l)(usb_id >> 24) }; ++ AICWFDBG(LOGINFO, "set efuse usb vid/pid:[%x]=%x\r\n", ++ func, usb_id); ++ rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_USBVIDPID, ++ sizeof(buf), buf, &cfm); ++ } else { ++ AICWFDBG(LOGERROR, "wrong args\n"); ++ return -EINVAL; ++ } ++ } else { ++ AICWFDBG(LOGERROR, "wrong func: %x\n", func); ++ return -EINVAL; ++ } ++ memcpy(command, &cfm.rftest_result[0], 4); ++ return 4; ++} ++ ++static int aic_priv_cmd_rdwr_efuse_he_off(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u8_l func = 0; ++ ++ func = command_strtoul(argv[1], NULL, 10); ++ AICWFDBG(LOGINFO, "set he off: %d\n", func); ++ if (func == 1 || func == 0) { ++ rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_HE_OFF, sizeof(func), ++ (u8_l *)&func, &cfm); ++ AICWFDBG(LOGINFO, "he_off cfm: %d\n", cfm.rftest_result[0]); ++ memcpy(command, &cfm.rftest_result[0], 4); ++ return 4; ++ } ++ return 0; ++} ++ ++static int aic_priv_cmd_set_cal_xtal(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ rwnx_send_rftest_req(rwnx_hw, SET_CAL_XTAL, 0, NULL, NULL); ++ return 0; ++} ++ ++static int aic_priv_cmd_get_cal_xtal_res(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ rwnx_send_rftest_req(rwnx_hw, GET_CAL_XTAL_RES, 0, NULL, &cfm); ++ memcpy(command, &cfm.rftest_result[0], 4); ++ AICWFDBG(LOGINFO, "cap=0x%x, cap_fine=0x%x\n", ++ cfm.rftest_result[0] & 0x0000ffff, ++ (cfm.rftest_result[0] >> 16) & 0x0000ffff); ++ return 4; ++} ++ ++static int aic_priv_cmd_set_cob_cal(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ cmd_rf_setcobcal_t setcob_cal; ++ ++ if (argc < 3) ++ return -EINVAL; ++ setcob_cal.dutid = command_strtoul(argv[1], NULL, 10); ++ setcob_cal.chip_num = command_strtoul(argv[2], NULL, 10); ++ setcob_cal.dis_xtal = command_strtoul(argv[3], NULL, 10); ++ rwnx_send_rftest_req(rwnx_hw, SET_COB_CAL, sizeof(cmd_rf_setcobcal_t), ++ (u8_l *)&setcob_cal, NULL); ++ return 0; ++} ++ ++static int aic_priv_cmd_get_cob_cal_res(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u8_l state; ++ cob_result_ptr_t *cob_result_ptr; ++ ++ rwnx_send_rftest_req(rwnx_hw, GET_COB_CAL_RES, 0, NULL, &cfm); ++ state = (cfm.rftest_result[0] >> 16) & 0x000000ff; ++ if (!state) { ++ AICWFDBG(LOGINFO, ++ "cap= 0x%x, cap_fine= 0x%x, freq_ofst= %d Hz\n", ++ cfm.rftest_result[0] & 0x000000ff, ++ (cfm.rftest_result[0] >> 8) & 0x000000ff, ++ cfm.rftest_result[1]); ++ cob_result_ptr = (cob_result_ptr_t *)&(cfm.rftest_result[2]); ++ AICWFDBG( ++ LOGINFO, ++ "golden_rcv_dut= %d , tx_rssi= %d dBm, snr = %d dB\ndut_rcv_godlden= %d , rx_rssi= %d dBm", ++ cob_result_ptr->golden_rcv_dut_num, ++ cob_result_ptr->rssi_static, cob_result_ptr->snr_static, ++ cob_result_ptr->dut_rcv_golden_num, ++ cob_result_ptr->dut_rssi_static); ++ memcpy(command, &cfm.rftest_result, 16); ++ return 16; ++ } else { ++ AICWFDBG(LOGERROR, "cob not idle\n"); ++ return -EINVAL; ++ } ++} ++ ++static int aic_priv_cmd_do_cob_test(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u8_l state; ++ cmd_rf_setcobcal_t setcob_cal; ++ cob_result_ptr_t *cob_result_ptr; ++ ++ setcob_cal.dutid = 1; ++ setcob_cal.chip_num = 1; ++ setcob_cal.dis_xtal = 0; ++ if (argc > 1) ++ setcob_cal.dis_xtal = command_strtoul(argv[1], NULL, 10); ++ rwnx_send_rftest_req(rwnx_hw, SET_COB_CAL, sizeof(cmd_rf_setcobcal_t), ++ (u8_l *)&setcob_cal, NULL); ++ msleep(2000); ++ rwnx_send_rftest_req(rwnx_hw, GET_COB_CAL_RES, 0, NULL, &cfm); ++ state = (cfm.rftest_result[0] >> 16) & 0x000000ff; ++ if (!state) { ++ AICWFDBG(LOGINFO, ++ "cap= 0x%x, cap_fine= 0x%x, freq_ofst= %d Hz\n", ++ cfm.rftest_result[0] & 0x000000ff, ++ (cfm.rftest_result[0] >> 8) & 0x000000ff, ++ cfm.rftest_result[1]); ++ cob_result_ptr = (cob_result_ptr_t *)&(cfm.rftest_result[2]); ++ AICWFDBG( ++ LOGINFO, ++ "golden_rcv_dut= %d , tx_rssi= %d dBm, snr = %d dB\ndut_rcv_godlden= %d , rx_rssi= %d dBm", ++ cob_result_ptr->golden_rcv_dut_num, ++ cob_result_ptr->rssi_static, cob_result_ptr->snr_static, ++ cob_result_ptr->dut_rcv_golden_num, ++ cob_result_ptr->dut_rssi_static); ++ memcpy(command, &cfm.rftest_result, 16); ++ return 16; ++ } else { ++ AICWFDBG(LOGERROR, "cob not idle\n"); ++ return -EINVAL; ++ } ++} ++ ++static int aic_priv_cmd_set_papr(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u8_l func = 0; ++ if (argc > 1) { ++ func = command_strtoul(argv[1], NULL, 10); ++ AICWFDBG(LOGINFO, "papr %d\r\n", func); ++ rwnx_send_rftest_req(rwnx_hw, SET_PAPR, sizeof(func), ++ (u8_l *)&func, NULL); ++ } else { ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int aic_priv_cmd_set_notch(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u8_l func = 0; ++ if (argc > 1) { ++ func = command_strtoul(argv[1], NULL, 10); ++ AICWFDBG(LOGINFO, "notch %d\r\n", func); ++ rwnx_send_rftest_req(rwnx_hw, SET_NOTCH, sizeof(func), ++ (u8_l *)&func, NULL); ++ } else { ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int aic_priv_cmd_set_srrc(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u8_l func = 0; ++ if (argc > 1) { ++ func = command_strtoul(argv[1], NULL, 10); ++ AICWFDBG(LOGINFO, "srrc %d\r\n", func); ++ rwnx_send_rftest_req(rwnx_hw, SET_SRRC, sizeof(func), ++ (u8_l *)&func, NULL); ++ } else { ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int aic_priv_cmd_set_fss(struct rwnx_hw *rwnx_hw, int argc, char *argv[], ++ char *command) ++{ ++ u8_l func = 0; ++ if (argc > 1) { ++ func = command_strtoul(argv[1], NULL, 10); ++ AICWFDBG(LOGINFO, "fss %d\r\n", func); ++ rwnx_send_rftest_req(rwnx_hw, SET_FSS, sizeof(func), ++ (u8_l *)&func, NULL); ++ } else { ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int aic_priv_cmd_set_usb_off(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ rwnx_send_rftest_req(rwnx_hw, SET_USB_OFF, 0, NULL, NULL); ++ return 0; ++} ++ ++static int aic_priv_cmd_set_pll_test(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u8_l func = 0, tx_pwr = 0xc; ++ s8_l freq = 0; ++ ++ if (argc > 1) { ++ func = command_strtoul(argv[1], NULL, 16); ++ } ++ if (argc > 3) { ++ freq = (s8_l)command_strtoul(argv[2], NULL, 10); ++ tx_pwr = command_strtoul(argv[3], NULL, 16); ++ } ++ if (func <= 1) { ++ u8_l buf[3] = { func, (u8_l)freq, tx_pwr }; ++ AICWFDBG(LOGINFO, "set pll_test %d: freq=%d, tx_pwr=0x%x\n", ++ func, freq, tx_pwr); ++ rwnx_send_rftest_req(rwnx_hw, SET_PLL_TEST, sizeof(buf), buf, ++ &cfm); ++ } else { ++ AICWFDBG(LOGERROR, "wrong func: %x\n", func); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int aic_priv_cmd_get_txpwr(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ s8_l power = 0; ++ power = get_txpwr_max(power); ++ memcpy(command, &power, 1); ++ return 1; ++} ++ ++static int aic_priv_cmd_set_txpwr_loss(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ s8_l func; ++ if (argc > 1) { ++ func = (s8_l)command_strtoul(argv[1], NULL, 10); ++ printk("set txpwr loss: %d\n", func); ++ if (g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800D80) { ++ set_txpwr_loss_ofst(func); ++ rwnx_send_txpwr_lvl_v3_req( ++ g_rwnx_plat->sdiodev->rwnx_hw); ++ } else if (g_rwnx_plat->sdiodev->chipid == ++ PRODUCT_ID_AIC8800D80X2) { ++ set_txpwr_loss_ofst(func); ++ rwnx_send_txpwr_lvl_v4_req( ++ g_rwnx_plat->sdiodev->rwnx_hw); ++ } else if (g_rwnx_plat->sdiodev->chipid == ++ PRODUCT_ID_AIC8800DC || ++ g_rwnx_plat->sdiodev->chipid == ++ PRODUCT_ID_AIC8800DW) { ++ set_txpwr_loss_ofst(func); ++ rwnx_send_txpwr_lvl_req(g_rwnx_plat->sdiodev->rwnx_hw); ++ } else { ++ AICWFDBG(LOGINFO, "error:don't support 8800D"); ++ } ++ } else { ++ printk("wrong args\n"); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int aic_priv_cmd_set_ant_mode(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u8_l func = 0; ++ if (argc > 1) { ++ func = command_strtoul(argv[1], NULL, 10); ++ AICWFDBG(LOGINFO, "ant %d\r\n", func); ++ rwnx_send_rftest_req(rwnx_hw, SET_ANT_MODE, sizeof(func), ++ (u8_l *)&func, NULL); ++ } else { ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int aic_priv_cmd_rdwr_bt_efuse_pwrofst(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ u8_l func = 0; ++ if (argc == 1) { ++ func = 0; ++ } else if (argc == 2) { ++ func = 1; ++ } ++ if (func == 0) { // read cur ++ rwnx_send_rftest_req(rwnx_hw, RDWR_BT_EFUSE_PWROFST, 0, NULL, ++ &cfm); ++ } else if (func == 1) { // write bt tx pwrofst ++ int8_t bt_txpwrofst = command_strtoul(argv[1], NULL, 10); ++ AICWFDBG(LOGINFO, "set bt efuse pwrofst %d\r\n", bt_txpwrofst); ++ if (bt_txpwrofst < -7 || bt_txpwrofst > 7) { ++ AICWFDBG(LOGERROR, ++ "wrong params %d, pwrofst limit -7 ~ 7\n", ++ bt_txpwrofst); ++ return -EINVAL; ++ } else { ++ rwnx_send_rftest_req(rwnx_hw, RDWR_BT_EFUSE_PWROFST, ++ sizeof(bt_txpwrofst), ++ &bt_txpwrofst, &cfm); ++ } ++ } else { ++ AICWFDBG(LOGERROR, "wrong func: %x\n", func); ++ return -EINVAL; ++ } ++ memcpy(command, &cfm.rftest_result[0], 2); ++ return 2; ++} ++ ++static int aic_priv_cmd_country_set(struct rwnx_hw *rwnx_hw, int argc, ++ char *argv[], char *command) ++{ ++ int ret = 0; ++ struct ieee80211_regdomain *regdomain; ++ ++ if (argc < 2) { ++ AICWFDBG(LOGINFO, "%s param err\n", __func__); ++ return -1; ++ } ++ ++ AICWFDBG(LOGINFO, "cmd country_set: %s\n", argv[1]); ++ ++ regdomain = getRegdomainFromRwnxDB(rwnx_hw->wiphy, argv[1]); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) ++ ret = regulatory_set_wiphy_regd(rwnx_hw->wiphy, regdomain); ++#else ++ ret = wiphy_apply_custom_regulatory(rwnx_hw->wiphy, regdomain); ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */ ++ ++#ifdef CONFIG_RADAR_OR_IR_DETECT ++ rwnx_radar_set_domain(&rwnx_hw->radar, regdomain->dfs_region); ++#endif ++ ++#ifdef CONFIG_POWER_LIMIT ++ if (!testmode) { ++ rwnx_send_me_chan_config_req(rwnx_hw, argv[1]); ++ } ++#endif ++ ++ return ret; ++} ++ ++static int aic_priv_cmd_help(struct rwnx_hw *rwnx_hw, int argc, char *argv[], ++ char *command) ++{ ++ print_help(argc > 0 ? argv[0] : NULL); ++ return 0; ++} ++ ++struct aic_priv_cmd { ++ const char *cmd; ++ int (*handler)(struct rwnx_hw *rwnx_hw, int argc, char *argv[], ++ char *command); ++ const char *usage; ++}; ++ ++static const struct aic_priv_cmd aic_priv_commands[] = { ++ { "set_tx", aic_priv_cmd_set_tx, ++ " " }, ++ { "set_txstop", aic_priv_cmd_set_txstop, "= stop tx " }, ++ { "set_rx", aic_priv_cmd_set_rx, " " }, ++ { "get_rx_result", aic_priv_cmd_get_rx_result, ++ "= display rx fcsok/total pkt num" }, ++ { "set_rxstop", aic_priv_cmd_set_rxstop, "= stop rx " }, ++ { "set_txtone", aic_priv_cmd_set_tx_tone, " val = 0/off" }, ++ { "set_rx_meter", aic_priv_cmd_set_rx_meter, "= set rx meter " }, ++ { "set_power", aic_priv_cmd_set_set_power, " " }, ++ { "set_xtal_cap", aic_priv_cmd_set_xtal_cap, " [0 ~ 31]" }, ++ { "set_xtal_cap_fine", aic_priv_cmd_set_xtal_cap_fine, ++ " [0 ~ 63]" }, ++ { "get_efuse_block", aic_priv_cmd_get_efuse_block, "" }, ++ { "set_freq_cal", aic_priv_cmd_set_freq_cal, "" }, ++ { "set_freq_cal_fine", aic_priv_cmd_set_freq_cal_fine, "" }, ++ { "get_freq_cal", aic_priv_cmd_get_freq_cal, ++ "= display cap & cap fine" }, ++ { "set_mac_addr", aic_priv_cmd_set_mac_addr, ++ "= write WiFi MAC into efuse or flash is limited to a maximum of two times" }, ++ { "get_mac_addr", aic_priv_cmd_get_mac_addr, ++ "= display WiFi MAC stored in efuse or flash" }, ++ { "set_bt_mac_addr", aic_priv_cmd_set_bt_mac_addr, ++ "= write BT MAC into efuse or flash is limited to a maximum of two times" }, ++ { "get_bt_mac_addr", aic_priv_cmd_get_bt_mac_addr, ++ "= display BT MAC stored in efuse or flash" }, ++ { "set_vendor_info", aic_priv_cmd_set_vendor_info, ++ "= write vendor info into efuse or flash is allowed only once" }, ++ { "get_vendor_info", aic_priv_cmd_get_vendor_info, ++ "= display vendor info stored in efuse or flash" }, ++ { "rdwr_pwrmm", aic_priv_cmd_rdwr_pwrmm, ++ " = 0/rdwr_pwrlvl, 1/set_power = read/write txpwr manul mode" }, ++ { "rdwr_pwridx", aic_priv_cmd_rdwr_pwridx, " " }, ++ { "rdwr_pwrlvl", aic_priv_cmd_rdwr_pwrlvl, " " }, ++ { "rdwr_pwrofst", aic_priv_cmd_rdwr_pwrofst, ++ " " }, ++ { "rdwr_pwrofstfine", aic_priv_cmd_rdwr_pwrofstfine, ++ " " }, ++ { "rdwr_drvibit", aic_priv_cmd_rdwr_drvibit, ++ " read/write 8800D pa drvibit" }, ++ { "set_cal_xtal", aic_priv_cmd_set_cal_xtal, "= set cal xtal" }, ++ { "get_cal_xtal_res", aic_priv_cmd_get_cal_xtal_res, ++ "= get cal xtal result cap & cap_fine" }, ++ { "set_cob_cal", aic_priv_cmd_set_cob_cal, ++ " = dut cob test" }, ++ { "get_cob_cal_res", aic_priv_cmd_get_cob_cal_res, ++ "= get cob cal result" }, ++ { "do_cob_test", aic_priv_cmd_do_cob_test, ++ " = 0/xtal, 1/dis_xtal, 2/only_xtal" }, ++ { "rdwr_efuse_pwrofst", aic_priv_cmd_rdwr_efuse_pwrofst, ++ " limited to a maximum of two times" }, ++ { "rdwr_efuse_pwrofstfine", aic_priv_cmd_rdwr_efuse_pwrofstfine, ++ " limited to a maximum of two times" }, ++ { "rdwr_efuse_drvibit", aic_priv_cmd_rdwr_efuse_drvibit, ++ " = read/write 8800D efuse pa drvibitis allowed only once" }, ++ { "rdwr_efuse_usrdata", aic_priv_cmd_rdwr_efuse_usrdata, ++ " = read/write efuse usrdata" }, ++ { "rdwr_efuse_sdiocfg", aic_priv_cmd_rdwr_efuse_sdiocfg, ++ " = read/write sdiocfg_bit into efuse" }, ++ { "rdwr_efuse_usbvidpid", aic_priv_cmd_rdwr_efuse_usbvidpid, ++ " = read/write usb vid/pid into efuse" }, ++ { "rdwr_efuse_he_off", aic_priv_cmd_rdwr_efuse_he_off, ++ " = read/write he_off into efuse" }, ++ { "set_papr", aic_priv_cmd_set_papr, ++ " = configure papr filter to optimize sideband suppression" }, ++ { "set_notch", aic_priv_cmd_set_notch, ++ " = configure filter to optimize sideband suppression" }, ++ { "set_srrc", aic_priv_cmd_set_srrc, ++ " = disable/enable sideband suppression for SRRC" }, ++ { "set_fss", aic_priv_cmd_set_fss, ++ " = disable/enable treatment of spurious emissions and burrs" }, ++ { "set_usb_off", aic_priv_cmd_set_usb_off, ++ "= off usb configure before usb disconnect" }, ++ { "set_pll_test", aic_priv_cmd_set_pll_test, ++ " = use pll test to measure saturation power" }, ++ { "get_txpwr", aic_priv_cmd_get_txpwr, "= get userconfig max txpwr" }, ++ { "set_txpwr_loss", aic_priv_cmd_set_txpwr_loss, ++ " = txpwr will change ,val can be negative" }, ++ { "set_ant", aic_priv_cmd_set_ant_mode, ++ " = 0/ant0, 1/ant1, 2/both" }, ++ { "rdwr_bt_efuse_pwrofst", aic_priv_cmd_rdwr_bt_efuse_pwrofst, ++ " = read/write bt tx power offset into efuse" }, ++ { "country_set", aic_priv_cmd_country_set, "" }, ++ //Reserve for new aic_priv_cmd. ++ { "help", aic_priv_cmd_help, "= show usage help" }, ++ { NULL, NULL, NULL } ++ ++}; ++ ++/* ++ * Prints command usage, lines are padded with the specified string. ++ */ ++static void print_help(const char *cmd) ++{ ++ int n; ++ printk("commands:\n"); ++ for (n = 0; aic_priv_commands[n].cmd; n++) { ++ if (cmd != NULL) ++ printk("%s %s\n", aic_priv_commands[n].cmd, ++ aic_priv_commands[n].usage); ++ } ++} ++ ++int handle_private_cmd(struct net_device *net, char *command, u32 cmd_len) ++{ ++ const struct aic_priv_cmd *cmd, *match = NULL; ++ int count; ++ int bytes_written = 0; ++ char *argv[CMD_MAXARGS + 1]; ++ int argc; ++ struct rwnx_vif *vif = ++ container_of(net->ieee80211_ptr, struct rwnx_vif, wdev); ++ struct rwnx_hw *p_rwnx_hw = vif->rwnx_hw; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++#if 1 ++ if (!testmode) { ++ AICWFDBG(LOGERROR, "not in testmdoe\n"); ++ return -1; ++ } ++#endif ++ argc = parse_line(command, argv); ++ if (argc == 0) { ++ return -1; ++ } ++ ++ count = 0; ++ cmd = aic_priv_commands; ++ while (cmd->cmd) { ++ if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0 && ++ strncasecmp(cmd->cmd, argv[0], strlen(cmd->cmd)) == 0) { ++ match = cmd; ++ if (strcasecmp(cmd->cmd, argv[0]) == 0) { ++ /* we have an exact match */ ++ count = 1; ++ break; ++ } ++ count++; ++ } ++ cmd++; ++ } ++ ++ if (count > 1) { ++ AICWFDBG(LOGINFO, ++ "Ambiguous command '%s'; possible commands:", argv[0]); ++ cmd = aic_priv_commands; ++ while (cmd->cmd) { ++ if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == ++ 0) { ++ AICWFDBG(LOGINFO, " %s", cmd->cmd); ++ } ++ cmd++; ++ } ++ AICWFDBG(LOGINFO, "\n"); ++ } else if (count == 0) { ++ AICWFDBG(LOGERROR, "Unknown command '%s'\n", argv[0]); ++ } else { ++ AICWFDBG(LOGINFO, "match %s", match->cmd); ++ bytes_written = ++ match->handler(p_rwnx_hw, argc, &argv[0], command); ++ } ++ ++ if (bytes_written < 0) ++ AICWFDBG(LOGERROR, "wrong param\n"); ++ ++ return bytes_written; ++} ++ ++#define RWNX_COUNTRY_CODE_LEN 2 ++#define CMD_SET_COUNTRY "COUNTRY" ++#define CMD_SET_VENDOR_EX_IE "SET_VENDOR_EX_IE" ++#define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE" ++#define CMD_SETSUSPENDMODE "SETSUSPENDMODE" ++#define CMD_SET_MON_FREQ "SET_MON_FREQ" ++ ++struct ieee80211_regdomain *getRegdomainFromRwnxDB(struct wiphy *wiphy, ++ char *alpha2); ++struct ieee80211_regdomain *getRegdomainFromRwnxDBIndex(struct wiphy *wiphy, ++ int index); ++extern int reg_regdb_size; ++ ++#ifdef CONFIG_SET_VENDOR_EXTENSION_IE ++extern u8_l vendor_extension_data[256]; ++extern int vendor_extension_len; ++extern int testmode = 0; ++ ++void set_vendor_extension_ie(char *command) ++{ ++ char databyte[3] = { 0x00, 0x00, 0x00 }; ++ int skip = strlen(CMD_SET_VENDOR_EX_IE) + 1; ++ int command_index = skip; ++ int data_index = 0; ++ ++ memset(vendor_extension_data, 0, 256); ++ vendor_extension_len = 0; ++ memcpy(databyte, command + command_index, 2); ++ vendor_extension_len = command_strtoul(databyte, NULL, 16); ++ printk("%s len:%d \r\n", __func__, vendor_extension_len); ++ ++ //parser command and save data in vendor_extension_data ++ for (data_index = 0; data_index < vendor_extension_len; data_index++) { ++ command_index = command_index + 3; ++ memcpy(databyte, command + command_index, 2); ++ vendor_extension_data[data_index] = ++ command_strtoul(databyte, NULL, 16); ++ } ++} ++#endif //CONFIG_SET_VENDOR_EXTENSION_IE ++int rwnx_cfg80211_set_monitor_channel_(struct wiphy *wiphy, ++ struct cfg80211_chan_def *chandef); ++int rwnx_atoi2(char *value, int c_len); ++void set_mon_chan(struct rwnx_vif *vif, char *parameter) ++{ ++ struct cfg80211_chan_def *chandef = NULL; ++ int freq = 0; ++ ++ chandef = (struct cfg80211_chan_def *)vmalloc( ++ sizeof(struct cfg80211_chan_def)); ++ memset(chandef, 0, sizeof(struct cfg80211_chan_def)); ++ chandef->chan = (struct ieee80211_channel *)vmalloc( ++ sizeof(struct ieee80211_channel)); ++ memset(chandef->chan, 0, sizeof(struct ieee80211_channel)); ++ ++ freq = rwnx_atoi2(parameter, 4); ++ ++ if (freq <= 2484) { ++ chandef->chan->band = NL80211_BAND_2GHZ; ++ } else { ++ chandef->chan->band = NL80211_BAND_5GHZ; ++ } ++ chandef->chan->center_freq = freq; ++ chandef->width = NL80211_CHAN_WIDTH_20; ++ chandef->center_freq1 = chandef->chan->center_freq; ++ chandef->center_freq2 = 0; ++ ++ rwnx_cfg80211_set_monitor_channel_(vif->rwnx_hw->wiphy, chandef); ++ ++ vfree(chandef->chan); ++ vfree(chandef); ++} ++ ++int android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) ++{ ++#define PRIVATE_COMMAND_MAX_LEN 8192 ++#define PRIVATE_COMMAND_DEF_LEN 4096 ++ ++ struct rwnx_vif *vif = netdev_priv(net); ++ int ret = 0; ++ char *command = NULL; ++ int bytes_written = 0; ++ android_wifi_priv_cmd priv_cmd; ++ int buf_size = 0; ++ int skip = 0; ++ char *country = NULL; ++#ifdef CONFIG_GPIO_WAKEUP ++ int setsusp_mode; ++#endif ++ struct ieee80211_regdomain *regdomain; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ ///todo: add our lock ++ //net_os_wake_lock(net); ++ ++ /* if (!capable(CAP_NET_ADMIN)) { ++ ret = -EPERM; ++ goto exit; ++ }*/ ++ if (!ifr->ifr_data) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++#ifdef CONFIG_COMPAT ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0)) ++ if (in_compat_syscall()) ++#else ++ if (is_compat_task()) ++#endif ++ { ++ compat_android_wifi_priv_cmd compat_priv_cmd; ++ if (copy_from_user(&compat_priv_cmd, ifr->ifr_data, ++ sizeof(compat_android_wifi_priv_cmd))) { ++ ret = -EFAULT; ++ goto exit; ++ } ++ priv_cmd.buf = compat_ptr(compat_priv_cmd.buf); ++ priv_cmd.used_len = compat_priv_cmd.used_len; ++ priv_cmd.total_len = compat_priv_cmd.total_len; ++ } else ++#endif /* CONFIG_COMPAT */ ++ { ++ if (copy_from_user(&priv_cmd, ifr->ifr_data, ++ sizeof(android_wifi_priv_cmd))) { ++ ret = -EFAULT; ++ goto exit; ++ } ++ } ++ if ((priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) || ++ (priv_cmd.total_len < 0)) { ++ printk("%s: buf length invalid:%d\n", __FUNCTION__, ++ priv_cmd.total_len); ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ buf_size = max(priv_cmd.total_len, PRIVATE_COMMAND_DEF_LEN); ++ command = kmalloc((buf_size + 1), GFP_KERNEL); ++ ++ if (!command) { ++ printk("%s: failed to allocate memory\n", __FUNCTION__); ++ ret = -ENOMEM; ++ goto exit; ++ } ++ if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) { ++ ret = -EFAULT; ++ goto exit; ++ } ++ command[priv_cmd.total_len] = '\0'; ++ ++ /* outputs */ ++ AICWFDBG(LOGINFO, "%s: Android private cmd \"%s\" on %s\n", ++ __FUNCTION__, command, ifr->ifr_name); ++ AICWFDBG(LOGINFO, "cmd = %d\n", cmd); ++ AICWFDBG(LOGINFO, "buf_size=%d\n", buf_size); ++ ++#if 1 //Handle Android command ++ if (!strncasecmp(command, CMD_SET_COUNTRY, strlen(CMD_SET_COUNTRY)) && ++ strncasecmp(command, "country_set", strlen("country_set"))) { ++ skip = strlen(CMD_SET_COUNTRY) + 1; ++ country = command + skip; ++ if (!country || strlen(country) < RWNX_COUNTRY_CODE_LEN) { ++ printk("%s: invalid country code\n", __func__); ++ ret = -EINVAL; ++ goto exit; ++ } ++#if 0 ++ for(index = 0; index < reg_regdb_size; index++){ ++ regdomain = getRegdomainFromRwnxDBIndex(vif->rwnx_hw->wiphy, index); ++ if((ret = regulatory_set_wiphy_regd(vif->rwnx_hw->wiphy, regdomain))){ ++ printk("regulatory_set_wiphy_regd fail \r\n"); ++ }else{ ++ printk("regulatory_set_wiphy_regd ok \r\n"); ++ } ++ } ++#endif ++ AICWFDBG(LOGINFO, "%s country code:%c%c\n", __func__, ++ toupper(country[0]), toupper(country[1])); ++ regdomain = ++ getRegdomainFromRwnxDB(vif->rwnx_hw->wiphy, country); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) ++ if ((ret = regulatory_set_wiphy_regd(vif->rwnx_hw->wiphy, ++ regdomain))) { ++ printk("regulatory_set_wiphy_regd fail \r\n"); ++ } ++#else ++ wiphy_apply_custom_regulatory(vif->rwnx_hw->wiphy, regdomain); ++#endif ++ ++#ifdef CONFIG_RADAR_OR_IR_DETECT ++ rwnx_radar_set_domain(&vif->rwnx_hw->radar, ++ regdomain->dfs_region); ++#endif ++ ++#ifdef CONFIG_POWER_LIMIT ++ if (!testmode) ++ rwnx_send_me_chan_config_req(vif->rwnx_hw, country); ++#endif ++ ret = 0; ++ goto exit; ++ } ++#ifdef CONFIG_SET_VENDOR_EXTENSION_IE ++ else if (!strncasecmp(command, CMD_SET_VENDOR_EX_IE, ++ strlen(CMD_SET_VENDOR_EX_IE))) { ++ set_vendor_extension_ie(command); ++ ret = 0; ++ goto exit; ++ } ++#endif //CONFIG_SET_VENDOR_EXTENSION_IE ++ else if (!strncasecmp(command, CMD_SET_AP_WPS_P2P_IE, ++ strlen(CMD_SET_AP_WPS_P2P_IE))) { ++ ret = 0; ++ goto exit; ++ } else if (!strncasecmp(command, CMD_SETSUSPENDMODE, ++ strlen(CMD_SETSUSPENDMODE)) && ++ testmode == 0) { ++#ifdef AICWF_SDIO_SUPPORT ++#if defined(CONFIG_GPIO_WAKEUP) && !defined(CONFIG_AUTO_POWERSAVE) ++ skip = strlen(CMD_SETSUSPENDMODE) + 1; ++ setsusp_mode = command_strtoul((command + skip), NULL, 10); ++#ifdef AICWF_LATENCY_MODE ++ if (setsusp_mode) ++ rwnx_send_me_set_lp_level(g_rwnx_plat->sdiodev->rwnx_hw, ++ setsusp_mode, 0); ++ else ++ rwnx_send_me_set_lp_level(g_rwnx_plat->sdiodev->rwnx_hw, ++ 1, 1); ++#else ++ rwnx_send_me_set_lp_level(g_rwnx_plat->sdiodev->rwnx_hw, ++ setsusp_mode, !setsusp_mode); ++#endif ++#if 0 ++ if (setsusp_mode == 1) { ++#if defined(CONFIG_SDIO_PWRCTRL) ++ aicwf_sdio_pwr_stctl(g_rwnx_plat->sdiodev, SDIO_SLEEP_ST); ++#endif ++ 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); ++ } ++ } ++#endif ++ AICWFDBG(LOGINFO, "set suspend mode %d\n", setsusp_mode); ++#endif //CONFIG_GPIO_WAKEUP ++#endif ++ goto exit; ++ } ++#ifdef CONFIG_RWNX_MON_DATA ++ else if (!strncasecmp(command, CMD_SET_MON_FREQ, ++ strlen(CMD_SET_MON_FREQ))) { ++ char *set_parameter; ++ skip = strlen(CMD_SET_MON_FREQ) + 1; ++ set_parameter = command + skip; ++ set_mon_chan(vif, set_parameter); ++ ret = 0; ++ goto exit; ++ } ++#endif ++ ++#endif //Handle Android command ++ ++ bytes_written = handle_private_cmd(net, command, priv_cmd.total_len); ++ if (bytes_written >= 0) { ++ if ((bytes_written == 0) && (priv_cmd.total_len > 0)) { ++ command[0] = '\0'; ++ } ++ if (bytes_written >= priv_cmd.total_len) { ++ printk("%s: err. bytes_written:%d >= buf_size:%d \n", ++ __FUNCTION__, bytes_written, buf_size); ++ goto exit; ++ } ++ bytes_written++; ++ priv_cmd.used_len = bytes_written; ++ if (copy_to_user(priv_cmd.buf, command, bytes_written)) { ++ printk("%s: failed to copy data to user buffer\n", ++ __FUNCTION__); ++ ret = -EFAULT; ++ } ++ } else { ++ /* Propagate the error */ ++ ret = bytes_written; ++ } ++ ++exit: ++ ///todo: add our unlock ++ //net_os_wake_unlock(net); ++ kfree(command); ++ return ret; ++} ++ ++#ifdef CONFIG_MCU_MESSAGE ++#define CMD_GET_VERSION_STR "GET_VERSION" ++#define CMD_GET_SSID_STR "GET_SSID" ++#define CMD_SET_SSID_STR "SET_SSID" ++#define CMD_GET_PASS_STR "GET_PASS" ++#define CMD_SET_PASS_STR "SET_PASS" ++#define CMD_GET_VAR_STR "GET_VAR" ++#define CMD_SET_VAR_STR "SET_VAR" ++ ++enum custmsg_cmd_tag { ++ CUST_CMD_GET_VERSION = 0, ++ CUST_CMD_GET_SSID, ++ CUST_CMD_SET_SSID, ++ CUST_CMD_GET_PASS, ++ CUST_CMD_SET_PASS, ++ CUST_CMD_GET_VAR, ++ CUST_CMD_SET_VAR, ++ CUST_CMD_MAX ++}; ++ ++int handle_custom_msg(char *command, u32 cmd_len) ++{ ++ int bytes_read = 0, max_bytes_to_read = 0; ++ struct rwnx_hw *p_rwnx_hw = NULL; ++ u32 cmd, len = 0, flags = 0; ++ char *buf = NULL; ++ struct dbg_custom_msg_cfm *cust_msg_cfm; ++ printk("cmd,%s,%ld\n", command, strlen(command)); ++ if (strncasecmp(command, CMD_GET_VERSION_STR, ++ strlen(CMD_GET_VERSION_STR)) == 0) { ++ cmd = CUST_CMD_GET_VERSION; ++ max_bytes_to_read = 32; // max str len for version ++ } else if (strncasecmp(command, CMD_GET_SSID_STR, ++ strlen(CMD_GET_SSID_STR)) == 0) { ++ cmd = CUST_CMD_GET_SSID; ++ max_bytes_to_read = 48; // max str len for ssid ++ } else if (strncasecmp(command, CMD_SET_SSID_STR, ++ strlen(CMD_SET_SSID_STR)) == 0) { ++ cmd = CUST_CMD_SET_SSID; ++ len = cmd_len - (strlen(CMD_SET_SSID_STR) + 1); ++ buf = command + (strlen(CMD_SET_SSID_STR) + 1); ++ max_bytes_to_read = 0; ++ } else if (strncasecmp(command, CMD_GET_PASS_STR, ++ strlen(CMD_GET_PASS_STR)) == 0) { ++ cmd = CUST_CMD_GET_PASS; ++ max_bytes_to_read = 64; // max str len for PASS ++ } else if (strncasecmp(command, CMD_SET_PASS_STR, ++ strlen(CMD_SET_PASS_STR)) == 0) { ++ cmd = CUST_CMD_SET_PASS; ++ len = cmd_len - (strlen(CMD_SET_PASS_STR) + 1); ++ buf = command + (strlen(CMD_SET_PASS_STR) + 1); ++ max_bytes_to_read = 0; ++ } else if (strncasecmp(command, CMD_GET_VAR_STR, ++ strlen(CMD_GET_VAR_STR)) == 0) { ++ cmd = CUST_CMD_GET_VAR; ++ max_bytes_to_read = 64; // max str len for VAR ++ } else if (strncasecmp(command, CMD_SET_VAR_STR, ++ strlen(CMD_SET_VAR_STR)) == 0) { ++ cmd = CUST_CMD_SET_VAR; ++ len = cmd_len - (strlen(CMD_SET_VAR_STR) + 1); ++ buf = command + (strlen(CMD_SET_VAR_STR) + 1); ++ max_bytes_to_read = 0; ++ } else { ++ printk("invalid cmd: %s\r\n", command); ++ return -1; ++ } ++ if (len < 0) { ++ printk("invalid len: %d\r\n", len); ++ return -3; ++ } ++#ifdef AICWF_SDIO_SUPPORT ++ p_rwnx_hw = g_rwnx_plat->sdiodev->rwnx_hw; ++#endif ++#ifdef AICWF_USB_SUPPORT ++ p_rwnx_hw = g_rwnx_plat->usbdev->rwnx_hw; ++#endif ++ cust_msg_cfm = (struct dbg_custom_msg_cfm *)kmalloc( ++ (offsetof(struct dbg_custom_msg_cfm, buf) + max_bytes_to_read), ++ GFP_KERNEL); ++ if (cust_msg_cfm == NULL) { ++ printk("msg cfm alloc fail\r\n"); ++ return -2; ++ } ++ rwnx_send_dbg_custom_msg_req(p_rwnx_hw, cmd, buf, len, flags, ++ cust_msg_cfm); ++ bytes_read = cust_msg_cfm->len; ++ printk("Custom msg cfm: cmd=%d, len=%d, status=%x\n", cust_msg_cfm->cmd, ++ bytes_read, cust_msg_cfm->status); ++ if (bytes_read) { ++ memcpy(command, cust_msg_cfm->buf, bytes_read); ++ command[bytes_read] = '\0'; ++ } else { ++ command[0] = '\0'; ++ } ++ if (cust_msg_cfm->status) { ++ printk("cfm status: %x", cust_msg_cfm->status); ++ } ++ return bytes_read; ++} ++ ++int devipc_cust_msg(struct net_device *net, struct ifreq *ifr, int cmd) ++{ ++#ifdef PRIVATE_COMMAND_MAX_LEN ++#undef PRIVATE_COMMAND_MAX_LEN ++#undef PRIVATE_COMMAND_DEF_LEN ++#define PRIVATE_COMMAND_MAX_LEN 8192 ++#define PRIVATE_COMMAND_DEF_LEN 4096 ++#endif ++ int ret = 0; ++ char *command = NULL; ++ 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); ++ ++ /* if (!capable(CAP_NET_ADMIN)) { ++ ret = -EPERM; ++ goto exit; ++ }*/ ++ if (!ifr->ifr_data) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++#ifdef CONFIG_COMPAT ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0)) ++ if (in_compat_syscall()) ++#else ++ if (is_compat_task()) ++#endif ++ { ++ compat_android_wifi_priv_cmd compat_priv_cmd; ++ if (copy_from_user(&compat_priv_cmd, ifr->ifr_data, ++ sizeof(compat_android_wifi_priv_cmd))) { ++ ret = -EFAULT; ++ goto exit; ++ } ++ priv_cmd.buf = compat_ptr(compat_priv_cmd.buf); ++ priv_cmd.used_len = compat_priv_cmd.used_len; ++ priv_cmd.total_len = compat_priv_cmd.total_len; ++ } else ++#endif /* CONFIG_COMPAT */ ++ { ++ if (copy_from_user(&priv_cmd, ifr->ifr_data, ++ sizeof(android_wifi_priv_cmd))) { ++ ret = -EFAULT; ++ goto exit; ++ } ++ } ++ if ((priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) || ++ (priv_cmd.total_len < 0)) { ++ printk("%s: buf length invalid:%d\n", __FUNCTION__, ++ priv_cmd.total_len); ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ buf_size = max(priv_cmd.total_len, PRIVATE_COMMAND_DEF_LEN); ++ command = kmalloc((buf_size + 1), GFP_KERNEL); ++ ++ if (!command) { ++ printk("%s: failed to allocate memory\n", __FUNCTION__); ++ ret = -ENOMEM; ++ goto exit; ++ } ++ if (copy_from_user(command, priv_cmd.buf, priv_cmd.used_len)) { ++ ret = -EFAULT; ++ goto exit; ++ } ++ command[priv_cmd.used_len] = '\0'; ++ ++ /* outputs */ ++ printk("%s: Devipc custom msg \"%s\" on %s\n", __FUNCTION__, command, ++ ifr->ifr_name); ++ printk("cmd = %x\n", cmd); ++ printk("buf_size=%d\n", buf_size); ++ ++ bytes_written = handle_custom_msg(command, priv_cmd.used_len); ++ if (bytes_written >= 0) { ++ if ((bytes_written == 0) && (priv_cmd.total_len > 0)) { ++ command[0] = '\0'; ++ } ++ if (bytes_written >= priv_cmd.total_len) { ++ printk("%s: err. bytes_written:%d >= buf_size:%d \n", ++ __FUNCTION__, bytes_written, buf_size); ++ goto exit; ++ } ++ bytes_written++; ++ priv_cmd.used_len = bytes_written; ++ if (copy_to_user(priv_cmd.buf, command, bytes_written)) { ++ printk("%s: failed to copy data to user buffer\n", ++ __FUNCTION__); ++ ret = -EFAULT; ++ } ++ } else { ++ /* Propagate the error */ ++ ret = bytes_written; ++ } ++ ++exit: ++ ///todo: add our unlock ++ //net_os_wake_unlock(net); ++ kfree(command); ++ Sreturn ret; ++} ++#endif +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/aic_priv_cmd.h b/drivers/net/wireless/aic8800/aic8800_fdrv/aic_priv_cmd.h +new file mode 100755 +index 000000000..a2f9226df +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/aic_priv_cmd.h +@@ -0,0 +1,32 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file private_cmd.h ++ * ++ * Copyright (C) Aicsemi 2018-2024 ++ * ++ ****************************************************************************** ++ */ ++ ++#ifndef _AIC_PRIV_CMD_H_ ++#define _AIC_PRIV_CMD_H_ ++ ++#include "rwnx_defs.h" ++ ++typedef struct _android_wifi_priv_cmd { ++ char *buf; ++ int used_len; ++ int total_len; ++} android_wifi_priv_cmd; ++ ++#ifdef CONFIG_COMPAT ++typedef struct _compat_android_wifi_priv_cmd { ++ compat_caddr_t buf; ++ int used_len; ++ int total_len; ++} compat_android_wifi_priv_cmd; ++#endif /* CONFIG_COMPAT */ ++ ++int android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd); ++ ++#endif /* _AIC_PRIV_CMD_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/aic_vendor.c b/drivers/net/wireless/aic8800/aic8800_fdrv/aic_vendor.c +new file mode 100755 +index 000000000..f30893d65 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/aic_vendor.c +@@ -0,0 +1,1253 @@ ++#include "aic_vendor.h" ++#include "rwnx_defs.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "rwnx_version_gen.h" ++#include "rwnx_msg_tx.h" ++ ++#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, ++ }, ++}; ++ ++static struct wlan_driver_wake_reason_cnt_t wake_reason_cnt = { ++ .total_cmd_event_wake = 10, ++}; ++ ++#endif ++ ++#ifdef CONFIG_APF ++#define AIC_APF_MEM_SIZE 2048 ++#define AIC_APF_VERSION 4 ++ ++static char apfProgram[AIC_APF_MEM_SIZE]; ++#endif ++ ++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) ++{ ++ u8 *data, *pos; ++ ++ data = kzalloc(ip_pkt_len + 14, GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ pos = data; ++ memcpy(pos, dst_mac, 6); ++ pos += 6; ++ memcpy(pos, src_mac, 6); ++ pos += 6; ++ /* Mapping Ethernet type (ETHERTYPE_IP: 0x0800) */ ++ *(pos++) = 0x08; ++ *(pos++) = 0x00; ++ ++ /* Mapping IP pkt */ ++ memcpy(pos, ip_pkt, ip_pkt_len); ++ pos += ip_pkt_len; ++ ++ //add send 802.3 pkt(raw data) ++ kfree(data); ++ ++ 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; ++ ++ /* ++ * The mkeep_alive packet is for STA interface only; if the bss is configured as AP, ++ * dongle shall reject a mkeep_alive request. ++ */ ++ if (rwnx_vif->wdev.iftype != NL80211_IFTYPE_STATION) ++ return res; ++ ++ printk("%s execution\n", __func__); ++ ++ //add send stop keep alive ++ res = 0; ++ 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) ++{ ++ /* max size of IP packet for keep alive */ ++ const int MKEEP_ALIVE_IP_PKT_MAX = 256; ++ ++ int ret = 0, rem, type; ++ u8 mkeep_alive_id = 0; ++ u8 *ip_pkt = NULL; ++ u16 ip_pkt_len = 0; ++ u8 src_mac[6]; ++ u8 dst_mac[6]; ++ u32 period_msec = 0; ++ const struct nlattr *iter; ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *rwnx_vif = container_of(wdev, struct rwnx_vif, wdev); ++ gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; ++ printk("%s\n", __func__); ++ ++ nla_for_each_attr (iter, data, len, rem) { ++ type = nla_type(iter); ++ switch (type) { ++ case MKEEP_ALIVE_ATTRIBUTE_ID: ++ mkeep_alive_id = nla_get_u8(iter); ++ break; ++ case MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN: ++ ip_pkt_len = nla_get_u16(iter); ++ if (ip_pkt_len > MKEEP_ALIVE_IP_PKT_MAX) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ break; ++ case MKEEP_ALIVE_ATTRIBUTE_IP_PKT: ++ if (!ip_pkt_len) { ++ ret = -EINVAL; ++ printk("ip packet length is 0\n"); ++ goto exit; ++ } ++ ip_pkt = (u8 *)kzalloc(ip_pkt_len, kflags); ++ if (ip_pkt == NULL) { ++ ret = -ENOMEM; ++ printk("Failed to allocate mem for ip packet\n"); ++ goto exit; ++ } ++ memcpy(ip_pkt, (u8 *)nla_data(iter), ip_pkt_len); ++ break; ++ case MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR: ++ memcpy(src_mac, nla_data(iter), 6); ++ break; ++ case MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR: ++ memcpy(dst_mac, nla_data(iter), 6); ++ break; ++ case MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC: ++ period_msec = nla_get_u32(iter); ++ break; ++ default: ++ pr_err("%s(%d), Unknown type: %d\n", __func__, __LINE__, ++ type); ++ ret = -EINVAL; ++ goto exit; ++ } ++ } ++ ++ if (ip_pkt == NULL) { ++ ret = -EINVAL; ++ printk("ip packet is NULL\n"); ++ goto exit; ++ } ++ ++ ret = aic_dev_start_mkeep_alive(rwnx_hw, rwnx_vif, mkeep_alive_id, ++ ip_pkt, ip_pkt_len, src_mac, dst_mac, ++ period_msec); ++ if (ret < 0) { ++ printk("start_mkeep_alive is failed ret: %d\n", ret); ++ } ++ ++exit: ++ if (ip_pkt) { ++ kfree(ip_pkt); ++ } ++ ++ return ret; ++} ++ ++static int aicwf_vendor_stop_mkeep_alive(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ const void *data, int len) ++{ ++ int ret = 0, rem, type; ++ u8 mkeep_alive_id = 0; ++ const struct nlattr *iter; ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *rwnx_vif = container_of(wdev, struct rwnx_vif, wdev); ++ ++ printk("%s\n", __func__); ++ nla_for_each_attr (iter, data, len, rem) { ++ type = nla_type(iter); ++ switch (type) { ++ case MKEEP_ALIVE_ATTRIBUTE_ID: ++ mkeep_alive_id = nla_get_u8(iter); ++ break; ++ default: ++ pr_err("%s(%d), Unknown type: %d\n", __func__, __LINE__, ++ type); ++ ret = -EINVAL; ++ break; ++ } ++ } ++ ++ ret = aic_dev_stop_mkeep_alive(rwnx_hw, rwnx_vif, mkeep_alive_id); ++ if (ret < 0) { ++ printk("stop_mkeep_alive is failed ret: %d\n", ret); ++ } ++ ++ return ret; ++} ++ ++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: ++ AICWFDBG(LOGERROR, "%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; ++} ++ ++struct ieee80211_regdomain *getRegdomainFromRwnxDB(struct wiphy *wiphy, ++ char *alpha2); ++ ++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; ++ struct ieee80211_regdomain *regdomain; ++ char *country = NULL; ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ ++ 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)); ++ country = (char *)nla_data(iter); ++ ++ AICWFDBG(LOGINFO, "%s country code:%c%c\n", __func__, ++ country[0], country[1]); ++ ++ regdomain = ++ getRegdomainFromRwnxDB(rwnx_hw->wiphy, country); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) ++ if ((ret = regulatory_set_wiphy_regd(rwnx_hw->wiphy, ++ regdomain))) { ++ printk("regulatory_set_wiphy_regd fail \r\n"); ++ } ++#else ++ wiphy_apply_custom_regulatory(rwnx_hw->wiphy, ++ regdomain); ++#endif ++ ++ 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; ++ ++#ifdef AICWF_LATENCY_MODE ++ feature |= WIFI_FEATURE_SET_LATENCY_MODE; ++#endif ++ 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: ++ AICWFDBG(LOGERROR, "%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_logger_get_tx_pkt_fates(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ const void *data, int len) ++{ ++#if 0 ++ int ret = 0, rem, type; ++ const struct nlattr *iter; ++ int fate_num; ++ int fate_data; ++ ++ AICWFDBG(LOGDEBUG, "%s Enter\r\n", __func__); ++ nla_for_each_attr(iter, data, len, rem) { ++ type = nla_type(iter); ++ switch (type) { ++ case LOGGER_ATTRIBUTE_PKT_FATE_NUM: ++ fate_num = nla_get_u32(iter); ++ break; ++ case LOGGER_ATTRIBUTE_PKT_FATE_DATA: ++ fate_data = nla_get_u64(iter); ++ break; ++ default: ++ AICWFDBG(LOGERROR, "%s(%d), Unknown type: %d\n", __func__, __LINE__, type); ++ return -EINVAL; ++ } ++ } ++#endif ++ /* TODO ++ * Add handle in the future ++ */ ++ return 0; ++} ++ ++static int aicwf_vendor_logger_get_rx_pkt_fates(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ const void *data, int len) ++{ ++#if 0 ++ int ret = 0, rem, type; ++ const struct nlattr *iter; ++ int fate_num; ++ int fate_data; ++ ++ AICWFDBG(LOGDEBUG, "%s Enter\r\n", __func__); ++ nla_for_each_attr(iter, data, len, rem) { ++ type = nla_type(iter); ++ switch (type) { ++ case LOGGER_ATTRIBUTE_PKT_FATE_NUM: ++ fate_num = nla_get_u32(iter); ++ break; ++ case LOGGER_ATTRIBUTE_PKT_FATE_DATA: ++ fate_data = nla_get_u64(iter); ++ break; ++ default: ++ AICWFDBG(LOGERROR, "%s(%d), Unknown type: %d\n", __func__, __LINE__, type); ++ return -EINVAL; ++ } ++ } ++#endif ++ /* TODO ++ * Add handle in the future ++ */ ++ return 0; ++} ++ ++#ifdef AICWF_LATENCY_MODE ++static int aicwf_vendor_subcmd_set_latency_mode(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ const void *data, int len) ++{ ++ int err = 0, rem, type; ++ u32 latency_mode; ++ const struct nlattr *iter; ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ ++ nla_for_each_attr (iter, data, len, rem) { ++ type = nla_type(iter); ++ switch (type) { ++ case ANDR_WIFI_ATTRIBUTE_LATENCY_MODE: ++ latency_mode = nla_get_u32(iter); ++ printk("%s,Setting latency mode %d\n", __func__, ++ latency_mode); ++#ifdef AICWF_SDIO_SUPPORT ++ if (latency_mode) { ++ rwnx_send_me_set_lp_level(rwnx_hw, 0, 1); ++ } else { ++ rwnx_send_me_set_lp_level(rwnx_hw, 1, 0); ++ } ++#endif ++ break; ++ default: ++ pr_err("%s(%d), Unknown type: %d\n", __func__, __LINE__, ++ type); ++ return err; ++ } ++ } ++ ++ return err; ++} ++#endif ++ ++static int ++aicwf_vendor_logger_start_pkt_fate_monitoring(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ const void *data, int len) ++{ ++ /* TODO ++ * Add handle in the future ++ */ ++ return 0; ++} ++ ++#ifdef CONFIG_APF ++static int aicwf_vendor_apf_subcmd_get_capabilities(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ const void *data, int len) ++{ ++ int ret; ++ struct sk_buff *reply; ++ uint32_t payload; ++ printk("%s\n", __func__); ++ ++ /* APF_ATTRIBUTE_VERSION + APF_ATTRIBUTE_MAX_LEN */ ++ payload = sizeof(u32) * 2; ++ reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload); ++ ++ if (!reply) ++ return -ENOMEM; ++ ++ if (nla_put_u32(reply, APF_ATTRIBUTE_VERSION, AIC_APF_VERSION)) ++ goto out_put_fail; ++ ++ if (nla_put_u32(reply, APF_ATTRIBUTE_MAX_LEN, AIC_APF_MEM_SIZE)) ++ 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_set_filter(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ const void *data, int len) ++{ ++ int ret = 0, rem, type; ++ const struct nlattr *iter; ++ unsigned int mProgramLen = 0; ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ ++ printk("%s\n", __func__); ++ ++ nla_for_each_attr (iter, data, len, rem) { ++ type = nla_type(iter); ++ switch (type) { ++ case APF_ATTRIBUTE_PROGRAM_LEN: ++ memcpy(&mProgramLen, nla_data(iter), ++ sizeof(unsigned int)); ++ ret = (mProgramLen > 0 && ++ mProgramLen <= AIC_APF_MEM_SIZE) ? ++ 0 : ++ -EINVAL; ++ break; ++ case APF_ATTRIBUTE_PROGRAM: ++ if (mProgramLen > AIC_APF_MEM_SIZE || ++ mProgramLen == 0) { ++ printk("%s: apf program size invalid: %d (should > 0 and <= %d)\n", ++ __func__, mProgramLen, AIC_APF_MEM_SIZE); ++ return -EINVAL; ++ } ++ ++ memcpy(apfProgram, nla_data(iter), mProgramLen); ++ ret = rwnx_send_set_apf_prog_req(rwnx_hw, apfProgram, ++ mProgramLen); ++ break; ++ default: ++ pr_err("%s(%d), Unknown type: %d\n", __func__, __LINE__, ++ type); ++ return -EINVAL; ++ } ++ } ++ ++ return ret; ++} ++ ++static int aicwf_vendor_apf_read_filter_data(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ const void *data, int len) ++{ ++ struct sk_buff *reply; ++ int ret, payload, apf_mem_size; ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ ++ printk("%s\n", __func__); ++ ++ apf_mem_size = AIC_APF_MEM_SIZE; ++ payload = sizeof(u32) + apf_mem_size; ++ ++ ret = rwnx_send_get_apf_prog_req(rwnx_hw, apfProgram, apf_mem_size); ++ if (ret != 0) { ++ pr_err("%s, Failed to read apf mem from firmware, ret = %d\n", ++ __func__, ret); ++ return ret; ++ } ++ ++ reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload); ++ if (!reply) ++ return -ENOMEM; ++ ++ ret = nla_put_u32(reply, APF_ATTRIBUTE_PROGRAM_LEN, apf_mem_size); ++ if (ret < 0) { ++ pr_err("%s, Failed to put APF_ATTRIBUTE_MAX_LEN, ret = %d\n", ++ __func__, ret); ++ goto out_put_fail; ++ } ++ ++ /* copy the full apf mem */ ++ ret = nla_put(reply, APF_ATTRIBUTE_PROGRAM, apf_mem_size, ++ &apfProgram[0]); ++ if (ret < 0) { ++ pr_err("%s, Failed to put APF_ATTRIBUTE_PROGRAM, ret = %d\n", ++ __func__, ret); ++ 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; ++} ++#endif ++ ++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 }, ++ [MKEEP_ALIVE_ATTRIBUTE_ID] = { .type = NLA_U8 }, ++ [MKEEP_ALIVE_ATTRIBUTE_IP_PKT] = { .type = NLA_MSECS }, ++ [MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN] = { .type = NLA_U16 }, ++ [MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR] = { .type = NLA_MSECS, ++ .len = ETH_ALEN }, ++ [MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR] = { .type = NLA_MSECS, ++ .len = ETH_ALEN }, ++ [MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC] = { .type = NLA_U32 }, ++ }; ++ ++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 }, ++ }; ++ ++#ifdef CONFIG_APF ++static const struct nla_policy ++ aicwf_cfg80211_apf_policy[APF_ATTRIBUTE_MAX + 1] = { ++ [0] = { .type = NLA_UNSPEC }, ++ [APF_ATTRIBUTE_VERSION] = { .type = NLA_U32 }, ++ [APF_ATTRIBUTE_MAX_LEN] = { .type = NLA_U32 }, ++ [APF_ATTRIBUTE_PROGRAM] = { .type = NLA_BINARY }, ++ [APF_ATTRIBUTE_PROGRAM_LEN] = { .type = NLA_U32 }, ++ }; ++#endif ++ ++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(4, 4, 0) ++static int aicwf_dump_interface(struct wiphy *wiphy, struct wireless_dev *wdev, ++ struct sk_buff *skb, const void *data, ++ int data_len, unsigned long *storage) ++{ ++ return 0; ++} ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) ++const struct wiphy_vendor_command aicwf_vendor_cmd[] = { ++ { { .vendor_id = GOOGLE_OUI, ++ .subcmd = WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = aicwf_vendor_start_mkeep_alive, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) ++ .dumpit = aicwf_dump_interface, ++#endif ++#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 = WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = aicwf_vendor_stop_mkeep_alive, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) ++ .dumpit = aicwf_dump_interface, ++#endif ++#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, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) ++ .dumpit = aicwf_dump_interface, ++#endif ++#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, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) ++ .dumpit = aicwf_dump_interface, ++#endif ++#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, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) ++ .dumpit = aicwf_dump_interface, ++#endif ++#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, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) ++ .dumpit = aicwf_dump_interface, ++#endif ++#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, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) ++ .dumpit = aicwf_dump_interface, ++#endif ++#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, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) ++ .dumpit = aicwf_dump_interface, ++#endif ++#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, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) ++ .dumpit = aicwf_dump_interface, ++#endif ++#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, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) ++ .dumpit = aicwf_dump_interface, ++#endif ++#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, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) ++ .dumpit = aicwf_dump_interface, ++#endif ++#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, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) ++ .dumpit = aicwf_dump_interface, ++#endif ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0) ++ .policy = VENDOR_CMD_RAW_DATA, ++#endif ++ }, ++#ifdef CONFIG_APF ++ { ++ { .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, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) ++ .dumpit = aicwf_dump_interface, ++#endif ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0) ++ .policy = aicwf_cfg80211_apf_policy, ++ .maxattr = APF_ATTRIBUTE_MAX, ++#endif ++ }, ++ { ++ { .vendor_id = GOOGLE_OUI, .subcmd = APF_SUBCMD_SET_FILTER }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | ++ WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = aicwf_vendor_apf_set_filter, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0) ++ .policy = aicwf_cfg80211_apf_policy, ++ .maxattr = APF_ATTRIBUTE_MAX, ++#endif ++ }, ++ { { .vendor_id = GOOGLE_OUI, .subcmd = APF_SUBCMD_READ_FILTER_DATA }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = aicwf_vendor_apf_read_filter_data, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) ++ .policy = aicwf_cfg80211_apf_policy, ++ .maxattr = APF_ATTRIBUTE_MAX ++#endif /* LINUX_VERSION >= 5.3 */ ++ }, ++#endif ++ { ++ { .vendor_id = GOOGLE_OUI, ++ .subcmd = LOGGER_START_PKT_FATE_MONITORING }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | ++ WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = aicwf_vendor_logger_start_pkt_fate_monitoring, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) ++ .dumpit = aicwf_dump_interface, ++#endif ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0) ++ .policy = VENDOR_CMD_RAW_DATA, ++#endif ++ }, ++ { ++ { .vendor_id = GOOGLE_OUI, .subcmd = LOGGER_GET_TX_PKT_FATES }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | ++ WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = aicwf_vendor_logger_get_tx_pkt_fates, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) ++ .dumpit = aicwf_dump_interface, ++#endif ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0) ++ .policy = VENDOR_CMD_RAW_DATA, ++#endif ++ }, ++ { ++ { .vendor_id = GOOGLE_OUI, .subcmd = LOGGER_GET_RX_PKT_FATES }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | ++ WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = aicwf_vendor_logger_get_rx_pkt_fates, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) ++ .dumpit = aicwf_dump_interface, ++#endif ++#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, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) ++ .dumpit = aicwf_dump_interface, ++#endif ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0) ++ .policy = aicwf_cfg80211_subcmd_set_mac_policy, ++ .maxattr = WIFI_VENDOR_ATTR_DRIVER_MAX, ++#endif ++ }, ++ { ++ { .vendor_id = BRCM_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, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) ++ .dumpit = aicwf_dump_interface, ++#endif ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0) ++ .policy = aicwf_cfg80211_subcmd_set_mac_policy, ++ .maxattr = WIFI_VENDOR_ATTR_DRIVER_MAX, ++#endif ++ }, ++#ifdef AICWF_LATENCY_MODE ++ { { .vendor_id = GOOGLE_OUI, .subcmd = WIFI_SUBCMD_SET_LATENCY_MODE }, ++ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, ++ .doit = aicwf_vendor_subcmd_set_latency_mode, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) ++ .policy = aicwf_cfg80211_andr_wifi_policy, ++ .maxattr = ANDR_WIFI_ATTRIBUTE_MAX ++#endif /* LINUX_VERSION >= 5.3 */ ++ }, ++#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); ++#endif ++ return 0; ++} +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/aic_vendor.h b/drivers/net/wireless/aic8800/aic8800_fdrv/aic_vendor.h +new file mode 100755 +index 000000000..2a9b4424b +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/aic_vendor.h +@@ -0,0 +1,378 @@ ++#ifndef _AIC_VENDOR_H ++#define _AIC_VENDOR_H ++ ++#include ++ ++#define GOOGLE_OUI 0x001A11 ++#define BRCM_OUI 0x001018 ++ ++typedef enum { ++ START_MKEEP_ALIVE, ++ STOP_MKEEP_ALIVE, ++} GetCmdType; ++ ++typedef enum { ++ /* don't use 0 as a valid subcommand */ ++ VENDOR_NL80211_SUBCMD_UNSPECIFIED, ++ ++ /* define all vendor startup commands between 0x0 and 0x0FFF */ ++ VENDOR_NL80211_SUBCMD_RANGE_START = 0x0001, ++ VENDOR_NL80211_SUBCMD_RANGE_END = 0x0FFF, ++ ++ /* define all GScan related commands between 0x1000 and 0x10FF */ ++ ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START = 0x1000, ++ ANDROID_NL80211_SUBCMD_GSCAN_RANGE_END = 0x10FF, ++ ++ /* define all NearbyDiscovery related commands between 0x1100 and 0x11FF */ ++ ANDROID_NL80211_SUBCMD_NBD_RANGE_START = 0x1100, ++ ANDROID_NL80211_SUBCMD_NBD_RANGE_END = 0x11FF, ++ ++ /* define all RTT related commands between 0x1100 and 0x11FF */ ++ ANDROID_NL80211_SUBCMD_RTT_RANGE_START = 0x1100, ++ ANDROID_NL80211_SUBCMD_RTT_RANGE_END = 0x11FF, ++ ++ ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START = 0x1200, ++ ANDROID_NL80211_SUBCMD_LSTATS_RANGE_END = 0x12FF, ++ ++ /* define all Logger related commands between 0x1400 and 0x14FF */ ++ ANDROID_NL80211_SUBCMD_DEBUG_RANGE_START = 0x1400, ++ ANDROID_NL80211_SUBCMD_DEBUG_RANGE_END = 0x14FF, ++ ++ /* define all wifi offload related commands between 0x1600 and 0x16FF */ ++ ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START = 0x1600, ++ ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_END = 0x16FF, ++ ++ /* define all NAN related commands between 0x1700 and 0x17FF */ ++ ANDROID_NL80211_SUBCMD_NAN_RANGE_START = 0x1700, ++ ANDROID_NL80211_SUBCMD_NAN_RANGE_END = 0x17FF, ++ ++ /* define all Android Packet Filter related commands between 0x1800 and 0x18FF */ ++ ANDROID_NL80211_SUBCMD_PKT_FILTER_RANGE_START = 0x1800, ++ ANDROID_NL80211_SUBCMD_PKT_FILTER_RANGE_END = 0x18FF, ++ ++ /* This is reserved for future usage */ ++ ++} ANDROID_VENDOR_SUB_COMMAND; ++ ++typedef enum { ++ WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE = ++ ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START, ++ WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE, ++} WIFI_OFFLOAD_SUB_COMMAND; ++ ++enum mkeep_alive_attributes { ++ MKEEP_ALIVE_ATTRIBUTE_ID = 0x1, ++ MKEEP_ALIVE_ATTRIBUTE_IP_PKT, ++ MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN, ++ MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR, ++ MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR, ++ MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC, ++ MKEEP_ALIVE_ATTRIBUTE_AFTER_LAST, ++ 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, ++}; ++ ++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, ++}; ++ ++#ifdef CONFIG_APF ++enum wifi_apf_attr { ++ APF_ATTRIBUTE_VERSION, ++ APF_ATTRIBUTE_MAX_LEN, ++ APF_ATTRIBUTE_PROGRAM, ++ APF_ATTRIBUTE_PROGRAM_LEN, ++ APF_ATTRIBUTE_LAST, ++ APF_ATTRIBUTE_MAX = APF_ATTRIBUTE_LAST - 1, ++}; ++#endif ++ ++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 */ ++ WIFI_SUBCMD_SET_LATENCY_MODE, /* 0x1018 */ ++ /* Add more sub commands here */ ++ GSCAN_SUBCMD_MAX, ++ APF_SUBCMD_GET_CAPABILITIES = ++ ANDROID_NL80211_SUBCMD_PKT_FILTER_RANGE_START, ++ APF_SUBCMD_SET_FILTER, ++#ifdef CONFIG_APF ++ APF_SUBCMD_READ_FILTER_DATA, ++#endif ++}; ++ ++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, ++ ANDR_WIFI_ATTRIBUTE_LATENCY_MODE, ++ // 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_SET_LATENCY_MODE = ++ 0x40000000, /* Support Latency mode setting */ ++ 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]; ++} wl_mkeep_alive_pkt_t; ++ ++#endif /* _AIC_VENDOR_H */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_compat_8800d80.c b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_compat_8800d80.c +new file mode 100755 +index 000000000..37edb8d20 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_compat_8800d80.c +@@ -0,0 +1,161 @@ ++#include "rwnx_main.h" ++#include "rwnx_msg_tx.h" ++#include "reg_access.h" ++#include "aicwf_compat_8800d80.h" ++ ++#define FW_USERCONFIG_NAME_8800D80 "aic_userconfig_8800d80.txt" ++#define FW_USERCONFIG_NAME_8800D80X2 "aic_userconfig_8800d80x2.txt" ++#define FW_POWERLIMIT_NAME_8800D80 "aic_powerlimit_8800d80.txt" ++ ++int rwnx_request_firmware_common(struct rwnx_hw *rwnx_hw, u32 **buffer, ++ const char *filename); ++void rwnx_plat_userconfig_parsing2(char *buffer, int size); ++void rwnx_plat_userconfig_parsing3(char *buffer, int size); ++void rwnx_plat_userconfig_parsing_8800d80x2(char *buffer, int size); ++ ++void rwnx_release_firmware_common(u32 **buffer); ++ ++int aicwf_set_rf_config_8800d80(struct rwnx_hw *rwnx_hw, ++ struct mm_set_rf_calib_cfm *cfm) ++{ ++ int ret = 0; ++ ++ if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80) { ++ if ((ret = rwnx_send_txpwr_lvl_v3_req(rwnx_hw))) { ++ return -1; ++ } ++ ++ if ((ret = rwnx_send_txpwr_ofst2x_req(rwnx_hw))) { ++ return -1; ++ } ++ } else if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ if ((ret = rwnx_send_txpwr_lvl_v4_req(rwnx_hw))) { ++ return -1; ++ } ++ if ((ret = rwnx_send_txpwr_ofst2x_v2_req(rwnx_hw))) { ++ return -1; ++ } ++ } ++ ++ if ((ret = rwnx_send_txpwr_lvl_adj_req(rwnx_hw))) { ++ return -1; ++ } ++ ++ if ((ret = rwnx_send_rf_calib_req(rwnx_hw, cfm))) { ++ return -1; ++ } ++ ++ return 0; ++} ++ ++int rwnx_plat_userconfig_load_8800d80(struct rwnx_hw *rwnx_hw) ++{ ++ int size; ++ u32 *dst = NULL; ++ char *filename = FW_USERCONFIG_NAME_8800D80; ++ ++ AICWFDBG(LOGINFO, "userconfig file path:%s \r\n", filename); ++ ++ /* load file */ ++ size = rwnx_request_firmware_common(rwnx_hw, &dst, filename); ++ if (size <= 0) { ++ AICWFDBG(LOGERROR, "wrong size of firmware file\n"); ++ dst = NULL; ++ return 0; ++ } ++ ++ /* Copy the file on the Embedded side */ ++ AICWFDBG(LOGINFO, "### Load file done: %s, size=%d\n", filename, size); ++ ++ rwnx_plat_userconfig_parsing3((char *)dst, size); ++ ++ rwnx_release_firmware_common(&dst); ++ ++ AICWFDBG(LOGINFO, "userconfig download complete\n\n"); ++ return 0; ++} ++ ++int rwnx_plat_userconfig_load_8800d80x2(struct rwnx_hw *rwnx_hw) ++{ ++ int size; ++ u32 *dst = NULL; ++ char *filename = FW_USERCONFIG_NAME_8800D80X2; ++ ++ AICWFDBG(LOGINFO, "userconfig file path:%s \r\n", filename); ++ ++ /* load file */ ++ size = rwnx_request_firmware_common(rwnx_hw, &dst, filename); ++ if (size <= 0) { ++ AICWFDBG(LOGERROR, "wrong size of firmware file\n"); ++ dst = NULL; ++ return 0; ++ } ++ ++ /* Copy the file on the Embedded side */ ++ AICWFDBG(LOGINFO, "### Load file done: %s, size=%d\n", filename, size); ++ ++ rwnx_plat_userconfig_parsing_8800d80x2((char *)dst, size); ++ ++ rwnx_release_firmware_common(&dst); ++ ++ AICWFDBG(LOGINFO, "userconfig download complete\n\n"); ++ return 0; ++} ++ ++#ifdef CONFIG_POWER_LIMIT ++extern char country_code[4]; ++int rwnx_plat_powerlimit_load_8800d80(struct rwnx_hw *rwnx_hw) ++{ ++ int size; ++ u32 *dst = NULL; ++ char *filename = FW_POWERLIMIT_NAME_8800D80; ++ ++ AICWFDBG(LOGDEBUG, "powerlimit file path:%s \r\n", filename); ++ ++ /* load file */ ++ size = rwnx_request_firmware_common(rwnx_hw, &dst, filename); ++ if (size <= 0) { ++ AICWFDBG(LOGERROR, "wrong size of cfg file\n"); ++ dst = NULL; ++ return 0; ++ } ++ ++ AICWFDBG(LOGDEBUG, "### Load file done: %s, size=%d\n", filename, size); ++ ++ /* parsing the file */ ++ rwnx_plat_powerlimit_parsing((char *)dst, size, country_code); ++ ++ rwnx_release_firmware_common(&dst); ++ ++ AICWFDBG(LOGDEBUG, "powerlimit download complete\n\n"); ++ return 0; ++} ++ ++int rwnx_plat_powerlimit_load_8800d80x2(struct rwnx_hw *rwnx_hw) ++{ ++ int size; ++ u32 *dst = NULL; ++ char *filename = FW_POWERLIMIT_NAME_8800D80; ++ ++ AICWFDBG(LOGDEBUG, "powerlimit file path:%s \r\n", filename); ++ ++ /* load file */ ++ size = rwnx_request_firmware_common(rwnx_hw, &dst, filename); ++ if (size <= 0) { ++ AICWFDBG(LOGERROR, "wrong size of cfg file\n"); ++ dst = NULL; ++ return 0; ++ } ++ ++ AICWFDBG(LOGDEBUG, "### Load file done: %s, size=%d\n", filename, size); ++ ++ /* parsing the file */ ++ rwnx_plat_powerlimit_parsing((char *)dst, size, country_code); ++ ++ rwnx_release_firmware_common(&dst); ++ ++ AICWFDBG(LOGDEBUG, "powerlimit download complete\n\n"); ++ return 0; ++} ++ ++#endif +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_compat_8800d80.h b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_compat_8800d80.h +new file mode 100755 +index 000000000..e3cac501d +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_compat_8800d80.h +@@ -0,0 +1,15 @@ ++#ifndef _AICWF_COMPAT_8800D80_H_ ++#define _AICWF_COMPAT_8800D80_H_ ++#include ++ ++int aicwf_set_rf_config_8800d80(struct rwnx_hw *rwnx_hw, ++ struct mm_set_rf_calib_cfm *cfm); ++int rwnx_plat_userconfig_load_8800d80(struct rwnx_hw *rwnx_hw); ++int rwnx_plat_userconfig_load_8800d80x2(struct rwnx_hw *rwnx_hw); ++ ++#ifdef CONFIG_POWER_LIMIT ++int rwnx_plat_powerlimit_load_8800d80(struct rwnx_hw *rwnx_hw); ++int rwnx_plat_powerlimit_load_8800d80x2(struct rwnx_hw *rwnx_hw); ++#endif ++ ++#endif +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_compat_8800dc.c b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_compat_8800dc.c +new file mode 100755 +index 000000000..4ec29c436 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_compat_8800dc.c +@@ -0,0 +1,678 @@ ++#include "rwnx_main.h" ++#include "rwnx_msg_tx.h" ++#include "reg_access.h" ++#include "aic_bsp_export.h" ++ ++#define RWNX_MAC_RF_PATCH_BASE_NAME_8800DC "fmacfw_rf_patch_8800dc" ++#define RWNX_MAC_RF_PATCH_NAME_8800DC RWNX_MAC_RF_PATCH_BASE_NAME_8800DC ".bin" ++#define FW_USERCONFIG_NAME_8800DC "aic_userconfig_8800dc.txt" ++#define FW_USERCONFIG_NAME_8800DW "aic_userconfig_8800dw.txt" ++ ++int rwnx_plat_bin_fw_upload_2(struct rwnx_hw *rwnx_hw, u32 fw_addr, ++ char *filename); ++int rwnx_request_firmware_common(struct rwnx_hw *rwnx_hw, u32 **buffer, ++ const char *filename); ++void rwnx_plat_userconfig_parsing2(char *buffer, int size); ++ ++void rwnx_release_firmware_common(u32 **buffer); ++ ++#if !defined(CONFIG_EXT_FEM_8800DCDW) ++u32 wifi_txgain_table_24g_8800dcdw[32] = { 0xA4B22189, //index 0 ++ 0x00007825, ++ 0xA4B2214B, //index 1 ++ 0x00007825, ++ 0xA4B2214F, //index 2 ++ 0x00007825, ++ 0xA4B221D5, //index 3 ++ 0x00007825, ++ 0xA4B221DC, //index 4 ++ 0x00007825, ++ 0xA4B221E5, //index 5 ++ 0x00007825, ++ 0xAC9221E5, //index 6 ++ 0x00006825, ++ 0xAC9221EF, //index 7 ++ 0x00006825, ++ 0xBC9221EE, //index 8 ++ 0x00006825, ++ 0xBC9221FF, //index 9 ++ 0x00006825, ++ 0xBC9221FF, //index 10 ++ 0x00004025, ++ 0xB792203F, //index 11 ++ 0x00004026, ++ 0xDC92203F, //index 12 ++ 0x00004025, ++ 0xE692203F, //index 13 ++ 0x00004025, ++ 0xFF92203F, //index 14 ++ 0x00004035, ++ 0xFFFE203F, //index 15 ++ 0x00004832 }; ++ ++u32 wifi_txgain_table_24g_1_8800dcdw[32] = { ++ 0x096E2011, //index 0 ++ 0x00004001, ++ 0x096E2015, //index 1 ++ 0x00004001, ++ 0x096E201B, //index 2 ++ 0x00004001, ++ 0x116E2018, //index 3 ++ 0x00004001, ++ 0x116E201E, //index 4 ++ 0x00004001, ++ 0x116E2023, //index 5 ++ 0x00004001, ++ 0x196E2021, //index 6 ++ 0x00004001, ++ 0x196E202B, //index 7 ++ 0x00004001, ++ 0x216E202B, //index 8 ++ 0x00004001, ++ 0x236E2027, //index 9 ++ 0x00004001, ++ 0x236E2031, //index 10 ++ 0x00004001, ++ 0x246E2039, //index 11 ++ 0x00004001, ++ 0x26922039, //index 12 ++ 0x00004001, ++ 0x2E92203F, //index 13 ++ 0x00004001, ++ 0x3692203F, //index 14 ++ 0x00004001, ++ 0x3FF2203F, //index 15 ++ 0x00004001, ++}; ++ ++u32 wifi_txgain_table_24g_8800dcdw_h[32] = { ++ 0xA55629C9, //index 0 ++ 0x00005825, ++ 0xAE5629C9, //index 1 ++ 0x00005825, ++ 0xAD5629CD, //index 2 ++ 0x00005825, ++ 0xAD5629D1, //index 3 ++ 0x00005825, ++ 0xAD5629D7, //index 4 ++ 0x00005825, ++ 0xAD5629DE, //index 5 ++ 0x00005825, ++ 0xAD5629E6, //index 6 ++ 0x00005825, ++ 0xBD5629E6, //index 7 ++ 0x00005825, ++ 0xBD5629F0, //index 8 ++ 0x00005825, ++ 0xCD5629F0, //index 9 ++ 0x00005825, ++ 0xE55629F0, //index 10 ++ 0x00005825, ++ 0xE55629FF, //index 11 ++ 0x00005825, ++ 0xE55629FF, //index 12 ++ 0x00002825, ++ 0xE75629FF, //index 13 ++ 0x00002825, ++ 0xFF5629FF, //index 14 ++ 0x00001825, ++ 0xFF5628FF, //index 15 ++ 0x00001025, ++}; ++ ++u32 wifi_txgain_table_24g_1_8800dcdw_h[32] = { ++ 0x941A2048, //index 0 ++ 0x00001825, ++ 0x961A2048, //index 1 ++ 0x00001825, ++ 0x9D1A2048, //index 2 ++ 0x00001825, ++ 0x9A1A204F, //index 3 ++ 0x00001825, ++ 0x961A204F, //index 4 ++ 0x00001825, ++ 0x9A1A2057, //index 5 ++ 0x00001825, ++ 0x9C1A2057, //index 6 ++ 0x00001825, ++ 0xA31A205B, //index 7 ++ 0x00001825, ++ 0xAB1A205B, //index 8 ++ 0x00001825, ++ 0xAD1A205B, //index 9 ++ 0x00001825, ++ 0xA71A2064, //index 10 ++ 0x00001825, ++ 0xAD1A2070, //index 11 ++ 0x00001825, ++ 0xAD72207F, //index 12 ++ 0x00001825, ++ 0xBCAE207F, //index 13 ++ 0x00001825, ++ 0xBFB2207F, //index 14 ++ 0x00001825, ++ 0xD73A207F, //index 15 ++ 0x00001825, ++}; ++ ++#else /* #ifdef CONFIG_EXT_FEM_8800DCDW */ ++// ofdm ++uint32_t wifi_txgain_table_24g_8800dcdw_femkct[32] = { ++ 0x919221C2, //index 0 ++ 0x00007825, ++ 0x899221C3, //index 1 ++ 0x00007825, ++ 0x8B9221C3, //index 2 ++ 0x00007825, ++ 0x929221C3, //index 3 ++ 0x00007825, ++ 0x949221C4, //index 4 ++ 0x00007825, ++ 0x969221C4, //index 5 ++ 0x00007825, ++ 0x949221C6, //index 6 ++ 0x00007825, ++ 0x949221C8, //index 7 ++ 0x00007825, ++ 0x9C9221C8, //index 8 ++ 0x00007825, ++ 0x9C9221CA, //index 9 ++ 0x00007825, ++ 0x9C9221CB, //index 10 ++ 0x00007825, ++ 0x939221D5, //index 11 ++ 0x00007825, ++ 0x9B9221D7, //index 12 ++ 0x00007825, ++ 0xA49221D7, //index 13 ++ 0x00007825, ++ 0xA79221D7, //index 14 ++ 0x00007825, ++ 0xBD9221D7, //index 15 ++ 0x00007825, ++}; ++ ++// 11b ++uint32_t wifi_txgain_table_24g_1_8800dcdw_femkct[32] = { ++ 0x836E20C2, //index 0 ++ 0x00003024, ++ 0x856E20C2, //index 1 ++ 0x00003024, ++ 0x826E20C3, //index 2 ++ 0x00003024, ++ 0x836E20C3, //index 3 ++ 0x00003024, ++ 0x856E20C3, //index 4 ++ 0x00003024, ++ 0x876E20C3, //index 5 ++ 0x00003024, ++ 0x8B6E20C3, //index 6 ++ 0x00003024, ++ 0x926E20C4, //index 7 ++ 0x00003024, ++ 0x9A6E20C4, //index 8 ++ 0x00003024, ++ 0x936E20C5, //index 9 ++ 0x00003024, ++ 0x936E20C7, //index 10 ++ 0x00003024, ++ 0xA16E20C8, //index 11 ++ 0x00003024, ++ 0xA16E20CA, //index 12 ++ 0x00003024, ++ 0xA26E20CB, //index 13 ++ 0x00003024, ++ 0xAA6E20CD, //index 14 ++ 0x00003024, ++ 0xAC7220CF, //index 15 ++ 0x00003024, ++}; ++#endif ++ ++u32 wifi_rxgain_table_24g_20m_8800dcdw[64] = { ++ 0x82f282d1, //index 0 ++ 0x9591a324, 0x80808419, 0x000000f0, ++ 0x42f282d1, //index 1 ++ 0x95923524, 0x80808419, 0x000000f0, ++ 0x22f282d1, //index 2 ++ 0x9592c724, 0x80808419, 0x000000f0, ++ 0x02f282d1, //index 3 ++ 0x9591a324, 0x80808419, 0x000000f0, ++ 0x06f282d1, //index 4 ++ 0x9591a324, 0x80808419, 0x000000f0, ++ 0x0ef29ad1, //index 5 ++ 0x9591a324, 0x80808419, 0x000000f0, ++ 0x0ef29ad3, //index 6 ++ 0x95923524, 0x80808419, 0x000000f0, ++ 0x0ef29ad7, //index 7 ++ 0x9595a324, 0x80808419, 0x000000f0, ++ 0x02f282d2, //index 8 ++ 0x95951124, 0x80808419, 0x000000f0, ++ 0x02f282f4, //index 9 ++ 0x95951124, 0x80808419, 0x000000f0, ++ 0x02f282e6, //index 10 ++ 0x9595a324, 0x80808419, 0x000000f0, ++ 0x02f282e6, //index 11 ++ 0x9599a324, 0x80808419, 0x000000f0, ++ 0x02f282e6, //index 12 ++ 0x959da324, 0x80808419, 0x000000f0, ++ 0x02f282e6, //index 13 ++ 0x959f5924, 0x80808419, 0x000000f0, ++ 0x06f282e6, //index 14 ++ 0x959f5924, 0x80808419, 0x000000f0, ++ 0x0ef29ae6, //index 15 ++ 0x959f5924, //loft [35:34]=3 ++ 0x80808419, 0x000000f0 ++}; ++ ++u32 wifi_rxgain_table_24g_40m_8800dcdw[64] = { ++ 0x83428151, //index 0 ++ 0x9631a328, 0x80808419, 0x000000f0, ++ 0x43428151, //index 1 ++ 0x96323528, 0x80808419, 0x000000f0, ++ 0x23428151, //index 2 ++ 0x9632c728, 0x80808419, 0x000000f0, ++ 0x03428151, //index 3 ++ 0x9631a328, 0x80808419, 0x000000f0, ++ 0x07429951, //index 4 ++ 0x9631a328, 0x80808419, 0x000000f0, ++ 0x0f42d151, //index 5 ++ 0x9631a328, 0x80808419, 0x000000f0, ++ 0x0f42d153, //index 6 ++ 0x96323528, 0x80808419, 0x000000f0, ++ 0x0f42d157, //index 7 ++ 0x9635a328, 0x80808419, 0x000000f0, ++ 0x03428152, //index 8 ++ 0x96351128, 0x80808419, 0x000000f0, ++ 0x03428174, //index 9 ++ 0x96351128, 0x80808419, 0x000000f0, ++ 0x03428166, //index 10 ++ 0x9635a328, 0x80808419, 0x000000f0, ++ 0x03428166, //index 11 ++ 0x9639a328, 0x80808419, 0x000000f0, ++ 0x03428166, //index 12 ++ 0x963da328, 0x80808419, 0x000000f0, ++ 0x03428166, //index 13 ++ 0x963f5928, 0x80808419, 0x000000f0, ++ 0x07429966, //index 14 ++ 0x963f5928, 0x80808419, 0x000000f0, ++ 0x0f42d166, //index 15 ++ 0x963f5928, 0x80808419, 0x000000f0 ++}; ++ ++#define RAM_LMAC_FW_ADDR 0x00150000 ++#ifdef CONFIG_DPD ++#if (defined(CONFIG_DPD) && !defined(CONFIG_FORCE_DPD_CALIB)) ++extern int is_file_exist(char *name); ++#endif ++extern rf_misc_ram_lite_t dpd_res; ++ ++int aicwf_fdrv_dpd_result_apply_8800dc(struct rwnx_hw *rwnx_hw, ++ rf_misc_ram_lite_t *dpd_res) ++{ ++ int ret = 0; ++ uint32_t cfg_base = 0x10164; ++ struct dbg_mem_read_cfm cfm; ++ uint32_t misc_ram_addr; ++ uint32_t ram_base_addr, ram_byte_cnt; ++ AICWFDBG(LOGINFO, "bit_mask[1]=%x\n", dpd_res->bit_mask[1]); ++ if (dpd_res->bit_mask[1] == 0) { ++ AICWFDBG(LOGERROR, "void dpd_res, bypass it.\n"); ++ return 0; ++ } ++ if (testmode == 1) { ++ cfg_base = RAM_LMAC_FW_ADDR + 0x0164; ++ } ++ if ((ret = rwnx_send_dbg_mem_read_req(rwnx_hw, cfg_base + 0x14, ++ &cfm))) { ++ AICWFDBG(LOGERROR, "rf misc ram[0x%x] rd fail: %d\n", ++ cfg_base + 0x14, ret); ++ return ret; ++ } ++ misc_ram_addr = cfm.memdata; ++ AICWFDBG(LOGINFO, "misc_ram_addr: %x\n", misc_ram_addr); ++ /* Copy dpd_res on the Embedded side */ ++ // bit_mask ++ AICWFDBG(LOGINFO, "bit_mask[0]=%x\n", dpd_res->bit_mask[0]); ++ ram_base_addr = misc_ram_addr + offsetof(rf_misc_ram_t, bit_mask); ++ ram_byte_cnt = MEMBER_SIZE(rf_misc_ram_t, bit_mask) + ++ MEMBER_SIZE(rf_misc_ram_t, reserved); ++ ret = rwnx_send_dbg_mem_block_write_req(rwnx_hw, ram_base_addr, ++ ram_byte_cnt, ++ (u32 *)&dpd_res->bit_mask[0]); ++ if (ret) { ++ AICWFDBG(LOGERROR, "bit_mask wr fail: %x, ret:%d\r\n", ++ ram_base_addr, ret); ++ return ret; ++ } ++ // dpd_high ++ AICWFDBG(LOGINFO, "dpd_high[0]=%x\n", dpd_res->dpd_high[0]); ++ ram_base_addr = misc_ram_addr + offsetof(rf_misc_ram_t, dpd_high); ++ ram_byte_cnt = MEMBER_SIZE(rf_misc_ram_t, dpd_high); ++ ret = rwnx_send_dbg_mem_block_write_req(rwnx_hw, ram_base_addr, ++ ram_byte_cnt, ++ (u32 *)&dpd_res->dpd_high[0]); ++ if (ret) { ++ AICWFDBG(LOGERROR, "dpd_high wr fail: %x, ret:%d\r\n", ++ ram_base_addr, ret); ++ return ret; ++ } ++ // loft_res ++ AICWFDBG(LOGINFO, "loft_res[0]=%x\n", dpd_res->loft_res[0]); ++ ram_base_addr = misc_ram_addr + offsetof(rf_misc_ram_t, loft_res); ++ ram_byte_cnt = MEMBER_SIZE(rf_misc_ram_t, loft_res); ++ ret = rwnx_send_dbg_mem_block_write_req(rwnx_hw, ram_base_addr, ++ ram_byte_cnt, ++ (u32 *)&dpd_res->loft_res[0]); ++ if (ret) { ++ AICWFDBG(LOGERROR, "loft_res wr fail: %x, ret:%d\r\n", ++ ram_base_addr, ret); ++ return ret; ++ } ++ return ret; ++} ++ ++#ifndef CONFIG_FORCE_DPD_CALIB ++int aicwf_fdrv_dpd_result_load_8800dc(struct rwnx_hw *rwnx_hw, ++ rf_misc_ram_lite_t *dpd_res) ++{ ++ int ret = 0; ++ int size; ++ u32 *dst = NULL; ++ char *filename = FW_DPDRESULT_NAME_8800DC; ++ AICWFDBG(LOGINFO, "dpd_res file path:%s \r\n", filename); ++ /* load file */ ++ size = rwnx_request_firmware_common(rwnx_hw, &dst, filename); ++ if (size <= 0) { ++ AICWFDBG(LOGERROR, "wrong size of dpd_res file\n"); ++ dst = NULL; ++ return -1; ++ } ++ AICWFDBG(LOGINFO, "### Load file done: %s, size=%d, dst[0]=%x\n", ++ filename, size, dst[0]); ++ memcpy((u8 *)dpd_res, (u8 *)dst, sizeof(rf_misc_ram_lite_t)); ++ if (dst) { ++ rwnx_release_firmware_common(&dst); ++ } ++ return ret; ++} ++#endif ++#endif ++ ++#if defined(CONFIG_LOFT_CALIB) ++extern rf_misc_ram_lite_t loft_res_local; ++ ++int aicwf_fdrv_loft_result_apply_8800dc(struct rwnx_hw *rwnx_hw, ++ rf_misc_ram_lite_t *loft_res) ++{ ++ int ret = 0; ++ uint32_t cfg_base = 0x10164; ++ struct dbg_mem_read_cfm cfm; ++ uint32_t misc_ram_addr; ++ uint32_t ram_base_addr, ram_byte_cnt; ++ AICWFDBG(LOGINFO, "bit_mask[1]=%x\n", loft_res->bit_mask[1]); ++ if (loft_res->bit_mask[1] == 0) { ++ AICWFDBG(LOGERROR, "void loft_res, bypass it.\n"); ++ return 0; ++ } ++ if (testmode == 1) { ++ cfg_base = RAM_LMAC_FW_ADDR + 0x0164; ++ } ++ if ((ret = rwnx_send_dbg_mem_read_req(rwnx_hw, cfg_base + 0x14, ++ &cfm))) { ++ AICWFDBG(LOGERROR, "rf misc ram[0x%x] rd fail: %d\n", ++ cfg_base + 0x14, ret); ++ return ret; ++ } ++ misc_ram_addr = cfm.memdata; ++ AICWFDBG(LOGINFO, "misc_ram_addr: %x\n", misc_ram_addr); ++ /* Copy loft_res on the Embedded side */ ++ // bit_mask ++ AICWFDBG(LOGINFO, "bit_mask[0]=%x\n", loft_res->bit_mask[0]); ++ ram_base_addr = misc_ram_addr + offsetof(rf_misc_ram_t, bit_mask); ++ ram_byte_cnt = MEMBER_SIZE(rf_misc_ram_t, bit_mask) + ++ MEMBER_SIZE(rf_misc_ram_t, reserved); ++ ret = rwnx_send_dbg_mem_block_write_req(rwnx_hw, ram_base_addr, ++ ram_byte_cnt, ++ (u32 *)&loft_res->bit_mask[0]); ++ if (ret) { ++ AICWFDBG(LOGERROR, "bit_mask wr fail: %x, ret:%d\r\n", ++ ram_base_addr, ret); ++ return ret; ++ } ++ // loft_res ++ AICWFDBG(LOGINFO, "loft_res[0]=%x\n", loft_res->loft_res[0]); ++ ram_base_addr = misc_ram_addr + offsetof(rf_misc_ram_t, loft_res); ++ ram_byte_cnt = MEMBER_SIZE(rf_misc_ram_t, loft_res); ++ ret = rwnx_send_dbg_mem_block_write_req(rwnx_hw, ram_base_addr, ++ ram_byte_cnt, ++ (u32 *)&loft_res->loft_res[0]); ++ if (ret) { ++ AICWFDBG(LOGERROR, "loft_res wr fail: %x, ret:%d\r\n", ++ ram_base_addr, ret); ++ return ret; ++ } ++ return ret; ++} ++#endif ++ ++int aicwf_fdrv_misc_ram_init_8800dc(struct rwnx_hw *rwnx_hw) ++{ ++ int ret = 0; ++ uint32_t cfg_base = 0x10164; ++ struct dbg_mem_read_cfm cfm; ++ uint32_t misc_ram_addr; ++ uint32_t misc_ram_size = 12; ++ int i; ++ ++ if (testmode == 1) { ++ cfg_base = RAM_LMAC_FW_ADDR + 0x0164; ++ } ++ // init misc ram ++ printk("%s\n", __func__); ++ ret = rwnx_send_dbg_mem_read_req(rwnx_hw, cfg_base + 0x14, &cfm); ++ if (ret) { ++ AICWFDBG(LOGERROR, "rf misc ram[0x%x] rd fail: %d\n", ++ cfg_base + 0x14, ret); ++ return ret; ++ } ++ misc_ram_addr = cfm.memdata; ++ AICWFDBG(LOGERROR, "misc_ram_addr=%x\n", misc_ram_addr); ++ for (i = 0; i < (misc_ram_size / 4); i++) { ++ ret = rwnx_send_dbg_mem_write_req(rwnx_hw, ++ misc_ram_addr + i * 4, 0); ++ if (ret) { ++ AICWFDBG(LOGERROR, "rf misc ram[0x%x] wr fail: %d\n", ++ misc_ram_addr + i * 4, ret); ++ return ret; ++ } ++ } ++ return ret; ++} ++ ++int aicwf_set_rf_config_8800dc(struct rwnx_hw *rwnx_hw, ++ struct mm_set_rf_calib_cfm *cfm) ++{ ++ int ret = 0; ++ ++ if ((ret = rwnx_send_txpwr_lvl_req(rwnx_hw))) { ++ return -1; ++ } ++ ++ if ((ret = rwnx_send_txpwr_ofst_req(rwnx_hw))) { ++ return -1; ++ } ++ ++ if (testmode == 0) { ++#if !defined(CONFIG_EXT_FEM_8800DCDW) ++ if (IS_CHIP_ID_H()) { ++ if ((ret = rwnx_send_rf_config_req( ++ rwnx_hw, 0, 1, ++ (u8_l *)wifi_txgain_table_24g_8800dcdw_h, ++ 128))) ++ return -1; ++ ++ if ((ret = rwnx_send_rf_config_req( ++ rwnx_hw, 16, 1, ++ (u8_l *)wifi_txgain_table_24g_1_8800dcdw_h, ++ 128))) ++ return -1; ++ } else { ++ if ((ret = rwnx_send_rf_config_req( ++ rwnx_hw, 0, 1, ++ (u8_l *)wifi_txgain_table_24g_8800dcdw, ++ 128))) ++ return -1; ++ ++ if ((ret = rwnx_send_rf_config_req( ++ rwnx_hw, 16, 1, ++ (u8_l *)wifi_txgain_table_24g_1_8800dcdw, ++ 128))) ++ return -1; ++ } ++#else /* #ifdef CONFIG_EXT_FEM_8800DCDW */ ++ { ++ ret = rwnx_send_rf_config_req( ++ rwnx_hw, 0, 1, ++ (u8_l *)wifi_txgain_table_24g_8800dcdw_femkct, ++ 128); ++ if (ret) { ++ return -1; ++ } ++ ret = rwnx_send_rf_config_req( ++ rwnx_hw, 16, 1, ++ (u8_l *)wifi_txgain_table_24g_1_8800dcdw_femkct, ++ 128); ++ if (ret) { ++ return -1; ++ } ++ } ++#endif ++ ++ if ((ret = rwnx_send_rf_config_req( ++ rwnx_hw, 0, 0, ++ (u8_l *)wifi_rxgain_table_24g_20m_8800dcdw, 256))) ++ return -1; ++ ++ if ((ret = rwnx_send_rf_config_req( ++ rwnx_hw, 32, 0, ++ (u8_l *)wifi_rxgain_table_24g_40m_8800dcdw, 256))) ++ return -1; ++ ++ if ((ret = rwnx_send_rf_calib_req(rwnx_hw, cfm))) { ++ return -1; ++ } ++ } else if (testmode == 1) { ++ if (chip_sub_id >= 1) { ++#ifdef CONFIG_DPD ++#ifndef CONFIG_FORCE_DPD_CALIB ++ if (is_file_exist(FW_DPDRESULT_NAME_8800DC) == 1) { ++ AICWFDBG(LOGINFO, "%s load dpd bin\n", ++ __func__); ++ ret = aicwf_fdrv_dpd_result_load_8800dc( ++ rwnx_hw, &dpd_res); ++ if (ret) { ++ AICWFDBG(LOGINFO, ++ "load dpd bin fail: %d\n", ++ ret); ++ return ret; ++ } ++ } ++#endif ++ if (dpd_res.bit_mask[1]) { ++ ret = aicwf_fdrv_dpd_result_apply_8800dc( ++ rwnx_hw, &dpd_res); ++ if (ret) { ++ AICWFDBG(LOGINFO, ++ "apply dpd bin fail: %d\n", ++ ret); ++ return ret; ++ } ++ } ++#elif defined(CONFIG_LOFT_CALIB) ++ if (loft_res_local.bit_mask[1]) { ++ ret = aicwf_fdrv_loft_result_apply_8800dc( ++ rwnx_hw, &loft_res_local); ++ if (ret) { ++ AICWFDBG(LOGINFO, ++ "apply loft res fail: %d\n", ++ ret); ++ return ret; ++ } ++ } ++#else ++ { ++ ret = aicwf_fdrv_misc_ram_init_8800dc(rwnx_hw); ++ if (ret) { ++ AICWFDBG(LOGINFO, ++ "misc ram init fail: %d\n", ++ ret); ++ return ret; ++ } ++ } ++#endif ++ ret = rwnx_send_rf_calib_req(rwnx_hw, cfm); ++ if (ret) { ++ AICWFDBG(LOGINFO, "rf calib req fail: %d\n", ++ ret); ++ return ret; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++int rwnx_plat_userconfig_load_8800dc(struct rwnx_hw *rwnx_hw) ++{ ++ int size; ++ u32 *dst = NULL; ++ char *filename = FW_USERCONFIG_NAME_8800DC; ++ ++ AICWFDBG(LOGINFO, "userconfig file path:%s \r\n", filename); ++ ++ /* load file */ ++ size = rwnx_request_firmware_common(rwnx_hw, &dst, filename); ++ if (size <= 0) { ++ AICWFDBG(LOGERROR, "wrong size of firmware file\n"); ++ dst = NULL; ++ return 0; ++ } ++ ++ /* Copy the file on the Embedded side */ ++ AICWFDBG(LOGINFO, "### Load file done: %s, size=%d\n", filename, size); ++ ++ rwnx_plat_userconfig_parsing2((char *)dst, size); ++ ++ rwnx_release_firmware_common(&dst); ++ ++ AICWFDBG(LOGINFO, "userconfig download complete\n\n"); ++ return 0; ++} ++ ++int rwnx_plat_userconfig_load_8800dw(struct rwnx_hw *rwnx_hw) ++{ ++ int size; ++ u32 *dst = NULL; ++ char *filename = FW_USERCONFIG_NAME_8800DC; ++ ++ AICWFDBG(LOGINFO, "userconfig file path:%s \r\n", filename); ++ ++ /* load file */ ++ size = rwnx_request_firmware_common(rwnx_hw, &dst, filename); ++ if (size <= 0) { ++ AICWFDBG(LOGERROR, "wrong size of firmware file\n"); ++ dst = NULL; ++ return 0; ++ } ++ ++ /* Copy the file on the Embedded side */ ++ AICWFDBG(LOGINFO, "### Load file done: %s, size=%d\n", filename, size); ++ ++ rwnx_plat_userconfig_parsing2((char *)dst, size); ++ ++ rwnx_release_firmware_common(&dst); ++ ++ AICWFDBG(LOGINFO, "userconfig download complete\n\n"); ++ return 0; ++} +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_compat_8800dc.h b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_compat_8800dc.h +new file mode 100755 +index 000000000..0af1af834 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_compat_8800dc.h +@@ -0,0 +1,16 @@ ++#include ++#include "aic_bsp_export.h" ++ ++#ifdef CONFIG_DPD ++int aicwf_fdrv_dpd_result_apply_8800dc(struct rwnx_hw *rwnx_hw, ++ rf_misc_ram_lite_t *dpd_res); ++#ifndef CONFIG_FORCE_DPD_CALIB ++int aicwf_fdrv_dpd_result_load_8800dc(struct rwnx_hw *rwnx_hw, ++ rf_misc_ram_lite_t *dpd_res); ++#endif ++#endif ++int aicwf_fdrv_misc_ram_init_8800dc(struct rwnx_hw *rwnx_hw); ++int aicwf_set_rf_config_8800dc(struct rwnx_hw *rwnx_hw, ++ struct mm_set_rf_calib_cfm *cfm); ++int rwnx_plat_userconfig_load_8800dc(struct rwnx_hw *rwnx_hw); ++int rwnx_plat_userconfig_load_8800dw(struct rwnx_hw *rwnx_hw); +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_debug.h b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_debug.h +new file mode 100755 +index 000000000..b2a05d9ac +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_debug.h +@@ -0,0 +1,58 @@ ++ ++ ++#define RWNX_FN_ENTRY_STR ">>> %s()\n", __func__ ++ ++/* message levels */ ++#define LOGERROR 0x0001 ++#define LOGINFO 0x0002 ++#define LOGTRACE 0x0004 ++#define LOGDEBUG 0x0008 ++#define LOGDATA 0x0010 ++#define LOGIRQ 0x0020 ++#define LOGSDPWRC 0x0040 ++#define LOGWAKELOCK 0x0080 ++#define LOGRXPOLL 0x0100 ++ ++extern int aicwf_dbg_level; ++void rwnx_data_dump(char *tag, void *data, unsigned long len); ++ ++#define AICWF_LOG "AICWFDBG(" ++ ++#ifdef DEBUG ++#define AICWFDBG(level, args, arg...) \ ++ do { \ ++ if (aicwf_dbg_level & level) { \ ++ printk(AICWF_LOG #level ")\t" args, ##arg); \ ++ } \ ++ } while (0) ++ ++#define RWNX_DBG(fmt, ...) \ ++ do { \ ++ if (aicwf_dbg_level & LOGTRACE) { \ ++ printk(AICWF_LOG "LOGTRACE)\t" fmt, ##__VA_ARGS__); \ ++ } \ ++ } while (0) ++#else ++ ++#define AICWFDBG(level, args, arg...) ++#define RWNX_DBG(fmt, ...) ++ ++#endif ++ ++#if 0 ++#define RWNX_DBG(fmt, ...) \ ++ do { \ ++ if (aicwf_dbg_level & LOGTRACE) { \ ++ printk(AICWF_LOG "LOGTRACE" \ ++ ")\t" fmt, \ ++ ##__VA_ARGS__); \ ++ } \ ++ } while (0) ++#define AICWFDBG(args, level) \ ++ do { \ ++ if (aicwf_dbg_level & level) { \ ++ printk(AICWF_LOG "(%s)\t", #level); \ ++ printf args; \ ++ } \ ++ } while (0) ++#endif +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_rx_prealloc.c b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_rx_prealloc.c +new file mode 100755 +index 000000000..2b39fa95a +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_rx_prealloc.c +@@ -0,0 +1,100 @@ ++#include ++#include ++#include ++#include ++#include ++#include "aicwf_rx_prealloc.h" ++ ++#ifdef CONFIG_PREALLOC_RX_SKB ++struct aicwf_rx_buff_list aic_rx_buff_list; ++ ++int aic_rxbuff_num_max = 30; ++ ++int aic_rxbuff_size = (64 * 512); ++ ++struct rx_buff *aicwf_prealloc_rxbuff_alloc(spinlock_t *lock) ++{ ++ unsigned long flags; ++ struct rx_buff *rxbuff = NULL; ++ ++ spin_lock_irqsave(lock, flags); ++ if (list_empty(&aic_rx_buff_list.rxbuff_list)) { ++ spin_unlock_irqrestore(lock, flags); ++ printk("%s %d, rxbuff list is empty\n", __func__, __LINE__); ++ return NULL; ++ } else { ++ rxbuff = list_first_entry(&aic_rx_buff_list.rxbuff_list, ++ struct rx_buff, queue); ++ list_del_init(&rxbuff->queue); ++ atomic_dec(&aic_rx_buff_list.rxbuff_list_len); ++ } ++ spin_unlock_irqrestore(lock, flags); ++ //printk("len:%d\n", aic_rx_buff_list.rxbuff_list_len); ++ memset(rxbuff->data, 0, aic_rxbuff_size); ++ rxbuff->len = 0; ++ rxbuff->start = NULL; ++ rxbuff->read = NULL; ++ rxbuff->end = NULL; ++ ++ return rxbuff; ++} ++ ++void aicwf_prealloc_rxbuff_free(struct rx_buff *rxbuff, spinlock_t *lock) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(lock, flags); ++ list_add_tail(&rxbuff->queue, &aic_rx_buff_list.rxbuff_list); ++ atomic_inc(&aic_rx_buff_list.rxbuff_list_len); ++ spin_unlock_irqrestore(lock, flags); ++} ++ ++int aicwf_prealloc_init() ++{ ++ struct rx_buff *rxbuff; ++ int i = 0; ++ ++ printk("%s enter\n", __func__); ++ INIT_LIST_HEAD(&aic_rx_buff_list.rxbuff_list); ++ ++ for (i = 0; i < aic_rxbuff_num_max; i++) { ++ rxbuff = kzalloc(sizeof(struct rx_buff), GFP_KERNEL); ++ if (rxbuff) { ++ rxbuff->data = kzalloc(aic_rxbuff_size, GFP_KERNEL); ++ if (rxbuff->data == NULL) { ++ printk("failed to alloc rxbuff data\n"); ++ kfree(rxbuff); ++ continue; ++ } ++ rxbuff->len = 0; ++ rxbuff->start = NULL; ++ rxbuff->read = NULL; ++ rxbuff->end = NULL; ++ list_add_tail(&rxbuff->queue, ++ &aic_rx_buff_list.rxbuff_list); ++ atomic_inc(&aic_rx_buff_list.rxbuff_list_len); ++ } ++ } ++ ++ printk("pre alloc rxbuff list len: %d\n", ++ (int)atomic_read(&aic_rx_buff_list.rxbuff_list_len)); ++ return 0; ++} ++ ++void aicwf_prealloc_exit() ++{ ++ struct rx_buff *rxbuff; ++ struct rx_buff *pos; ++ ++ printk("%s enter\n", __func__); ++ ++ printk("free pre alloc rxbuff list %d\n", ++ (int)atomic_read(&aic_rx_buff_list.rxbuff_list_len)); ++ list_for_each_entry_safe (rxbuff, pos, &aic_rx_buff_list.rxbuff_list, ++ queue) { ++ list_del_init(&rxbuff->queue); ++ kfree(rxbuff->data); ++ kfree(rxbuff); ++ } ++} ++#endif +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_rx_prealloc.h b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_rx_prealloc.h +new file mode 100755 +index 000000000..608af7476 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_rx_prealloc.h +@@ -0,0 +1,24 @@ ++#ifndef _AICWF_RX_PREALLOC_H_ ++#define _AICWF_RX_PREALLOC_H_ ++ ++#ifdef CONFIG_PREALLOC_RX_SKB ++struct rx_buff { ++ struct list_head queue; ++ unsigned char *data; ++ u32 len; ++ uint8_t *start; ++ uint8_t *end; ++ uint8_t *read; ++}; ++ ++struct aicwf_rx_buff_list { ++ struct list_head rxbuff_list; ++ atomic_t rxbuff_list_len; ++}; ++ ++struct rx_buff *aicwf_prealloc_rxbuff_alloc(spinlock_t *lock); ++void aicwf_prealloc_rxbuff_free(struct rx_buff *rxbuff, spinlock_t *lock); ++int aicwf_prealloc_init(void); ++void aicwf_prealloc_exit(void); ++#endif ++#endif /* _AICWF_RX_PREALLOC_H_ */ +\ No newline at end of file +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_sdio.c b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_sdio.c +new file mode 100755 +index 000000000..8b37017e2 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_sdio.c +@@ -0,0 +1,3717 @@ ++/** ++ * aicwf_sdmmc.c ++ * ++ * SDIO function declarations ++ * ++ * Copyright (C) AICSemi 2018-2020 ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "aicwf_txrxif.h" ++#include "aicwf_sdio.h" ++#include "sdio_host.h" ++#include "rwnx_defs.h" ++#include "rwnx_platform.h" ++#include "aicwf_rx_prealloc.h" ++#include "rwnx_msg_tx.h" ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) ++#include ++#else ++#include ++#endif ++#include "rwnx_wakelock.h" ++ ++#ifdef CONFIG_INGENIC_T20 ++#include "mach/jzmmc.h" ++#endif /* CONFIG_INGENIC_T20 */ ++/* flare-edge (6.18 port, PORT-PLAN.md §3.7): is a ++ * Rockchip-BSP-vendor-only header, not present in mainline. Every ++ * rockchip_wifi_power()/rockchip_wifi_set_carddetect() call site in this ++ * file is already #if 0'd out upstream; the mainline mmc-pwrseq-simple DT ++ * node does the power/reset sequencing instead. Do not include it. */ ++ ++#include "aic_bsp_export.h" ++extern uint8_t scanning; ++ ++#ifdef CONFIG_SDIO_ADMA ++unsigned char sdio_tx_buf_fill[512]; ++unsigned char sdio_tx_buf_dummy[SDIO_TX_SLIST_MAX][8]; ++#endif ++ ++#ifdef CONFIG_GPIO_WAKEUP ++extern int rwnx_send_me_set_lp_level(struct rwnx_hw *rwnx_hw, u8 lp_level, ++ u8 disable_filter); ++ ++#ifdef CONFIG_WIFI_SUSPEND_FOR_LINUX ++#include ++void rwnx_init_wifi_suspend_node(void); ++void rwnx_deinit_wifi_suspend_node(void); ++void rwnx_set_wifi_suspend(char onoff); ++struct proc_dir_entry *wifi_suspend_node; ++#endif //CONFIG_WIFI_SUSPEND_FOR_LINUX ++ ++#endif //CONFIG_GPIO_WAKEUP ++ ++int tx_aggr_counter = 32; ++module_param_named(tx_aggr_counter, tx_aggr_counter, int, 0644); ++ ++#ifdef CONFIG_TX_NETIF_FLOWCTRL ++int tx_fc_low_water = AICWF_SDIO_TX_LOW_WATER; ++module_param_named(tx_fc_low_water, tx_fc_low_water, int, 0644); ++ ++int tx_fc_high_water = AICWF_SDIO_TX_HIGH_WATER; ++module_param_named(tx_fc_high_water, tx_fc_high_water, int, 0644); ++#endif ++ ++#if 0 ++void rwnx_data_dump(char* tag, void* data, unsigned long len){ ++ if(dump){ ++ unsigned long i = 0; ++ uint8_t* data_ = (uint8_t* )data; ++ ++ printk("%s %s len:(%lu)\r\n", __func__, tag, len); ++ ++ for (i = 0; i < len; i += 16){ ++ printk("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\r\n", ++ data_[0 + i], ++ data_[1 + i], ++ data_[2 + i], ++ data_[3 + i], ++ data_[4 + i], ++ data_[5 + i], ++ data_[6 + i], ++ data_[7 + i], ++ data_[8 + i], ++ data_[9 + i], ++ data_[10 + i], ++ data_[11 + i], ++ data_[12 + i], ++ data_[13 + i], ++ data_[14 + i], ++ data_[15 + i]); ++ } ++ } ++} ++#endif ++ ++int aicwf_sdio_readb(struct aic_sdio_dev *sdiodev, uint regaddr, u8 *val) ++{ ++ int ret; ++ sdio_claim_host(sdiodev->func); ++ *val = sdio_readb(sdiodev->func, regaddr, &ret); ++ sdio_release_host(sdiodev->func); ++ return ret; ++} ++ ++int aicwf_sdio_writeb(struct aic_sdio_dev *sdiodev, uint regaddr, u8 val) ++{ ++ int ret; ++ sdio_claim_host(sdiodev->func); ++ sdio_writeb(sdiodev->func, val, regaddr, &ret); ++ sdio_release_host(sdiodev->func); ++ return ret; ++} ++ ++int aicwf_sdio_func2_readb(struct aic_sdio_dev *sdiodev, uint regaddr, u8 *val) ++{ ++ int ret; ++ sdio_claim_host(sdiodev->func2); ++ *val = sdio_readb(sdiodev->func2, regaddr, &ret); ++ sdio_release_host(sdiodev->func2); ++ return ret; ++} ++ ++int aicwf_sdio_func2_writeb(struct aic_sdio_dev *sdiodev, uint regaddr, u8 val) ++{ ++ int ret; ++ sdio_claim_host(sdiodev->func2); ++ sdio_writeb(sdiodev->func2, val, regaddr, &ret); ++ sdio_release_host(sdiodev->func2); ++ return ret; ++} ++ ++#ifdef CONFIG_TX_NETIF_FLOWCTRL ++void aicwf_sdio_tx_netif_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 (state) ++ netif_tx_stop_all_queues( ++ rwnx_vif->ndev); //netif_stop_queue(rwnx_vif->ndev); ++ else ++ netif_tx_wake_all_queues( ++ rwnx_vif->ndev); //netif_wake_queue(rwnx_vif->ndev); ++ } ++} ++#endif ++ ++#ifdef CONFIG_TEMP_CONTROL ++//int interval = 30; ++//module_param(interval, int, 0660); ++static int update_state(s8_l value, u8_l current_state) ++{ ++ if (value > TEMP_THD_2) ++ return 2; ++ else if (value > (TEMP_THD_2 - BUFFERING_V2) && (current_state == 2)) ++ return 2; ++ else if (value > TEMP_THD_1 && current_state != 2) ++ return 1; ++ else if (value > (TEMP_THD_1 - BUFFERING_V1) && current_state == 1) ++ return 1; ++ else if (current_state == 0) ++ return 0; ++ else ++ return 1; ++} ++ ++void aicwf_netif_ctrl(struct aic_sdio_dev *sdiodev, int val) ++{ ++ unsigned long flags; ++ struct rwnx_vif *rwnx_vif; ++ ++ if (sdiodev->net_stop) ++ return; ++ ++ spin_lock_irqsave(&sdiodev->tx_flow_lock, flags); ++ list_for_each_entry (rwnx_vif, &sdiodev->rwnx_hw->vifs, list) { ++ if (!rwnx_vif || !rwnx_vif->ndev || !rwnx_vif->up) ++ continue; ++ netif_tx_stop_all_queues( ++ rwnx_vif->ndev); //netif_stop_queue(rwnx_vif->ndev); ++ } ++ spin_unlock_irqrestore(&sdiodev->tx_flow_lock, flags); ++ sdiodev->net_stop = true; ++ mod_timer(&sdiodev->netif_timer, jiffies + msecs_to_jiffies(val)); ++ ++ return; ++} ++ ++void aicwf_temp_ctrl(struct aic_sdio_dev *sdiodev) ++{ ++ if (sdiodev->set_level) { ++ if (sdiodev->set_level == 1) { ++ sdiodev->get_level = 1; ++ aicwf_netif_ctrl( ++ sdiodev, ++ sdiodev->interval_t1 /*TMR_INTERVAL_1*/); ++ //mdelay(1); ++ } else if (sdiodev->set_level == 2) { ++ sdiodev->get_level = 2; ++ aicwf_netif_ctrl( ++ sdiodev, ++ sdiodev->interval_t2 /*TMR_INTERVAL_2*/); ++ //mdelay(2); ++ } ++ return; ++ } else { ++ if (sdiodev->cur_temp > (TEMP_THD_1 - 8)) { ++ //if ((sdiodev->cur_temp > TEMP_THD_1 && sdiodev->cur_temp <= TEMP_THD_2) || (sdiodev->cur_stat == 1)) { ++ if (update_state(sdiodev->cur_temp, ++ sdiodev->cur_stat) == 1) { ++ sdiodev->get_level = 1; ++ sdiodev->cur_stat = 1; ++ aicwf_netif_ctrl( ++ sdiodev, ++ sdiodev->interval_t1 /*TMR_INTERVAL_1*/); ++ //mdelay(1); ++ //break; ++ //} else if ((sdiodev->cur_temp > TEMP_THD_2) || (sdiodev->cur_stat == 2)) { ++ } else if (update_state(sdiodev->cur_temp, ++ sdiodev->cur_stat) == 2) { ++ sdiodev->get_level = 2; ++ sdiodev->cur_stat = 2; ++ aicwf_netif_ctrl( ++ sdiodev, ++ sdiodev->interval_t2 /*TMR_INTERVAL_2*/); ++ //mdelay(2); ++ //break; ++ } ++ return; ++ } ++ ++ if (sdiodev->cur_stat) { ++ AICWFDBG(LOGINFO, "reset cur_stat"); ++ sdiodev->cur_stat = 0; ++ } ++ ++ return; ++ } ++} ++ ++void aicwf_netif_worker(struct work_struct *work) ++{ ++ struct aic_sdio_dev *sdiodev = ++ container_of(work, struct aic_sdio_dev, netif_work); ++ unsigned long flags; ++ struct rwnx_vif *rwnx_vif; ++ spin_lock_irqsave(&sdiodev->tx_flow_lock, flags); ++ list_for_each_entry (rwnx_vif, &sdiodev->rwnx_hw->vifs, list) { ++ if (!rwnx_vif || !rwnx_vif->ndev || !rwnx_vif->up) ++ continue; ++ netif_tx_wake_all_queues( ++ rwnx_vif->ndev); //netif_wake_queue(rwnx_vif->ndev); ++ } ++ spin_unlock_irqrestore(&sdiodev->tx_flow_lock, flags); ++ sdiodev->net_stop = false; ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) ++static void aicwf_netif_timer(ulong data) ++#else ++static void aicwf_netif_timer(struct timer_list *t) ++#endif ++{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) ++ struct aic_sdio_dev *sdiodev = (struct aic_sdio_dev *)data; ++#else ++ struct aic_sdio_dev *sdiodev = timer_container_of(sdiodev, t, netif_timer); ++#endif ++ ++ if (!work_pending(&sdiodev->netif_work)) ++ schedule_work(&sdiodev->netif_work); ++ ++ return; ++} ++ ++void aicwf_temp_ctrl_worker(struct work_struct *work) ++{ ++ struct rwnx_hw *rwnx_hw; ++ struct mm_set_vendor_swconfig_cfm cfm; ++ struct aic_sdio_dev *sdiodev = ++ container_of(work, struct aic_sdio_dev, tp_ctrl_work); ++ rwnx_hw = sdiodev->rwnx_hw; ++ //AICWFDBG(LOGINFO, "%s\n", __func__); ++ ++ rwnx_hw->started_jiffies = jiffies; ++ ++ rwnx_send_get_temp_req(rwnx_hw, &cfm); ++ sdiodev->cur_temp = cfm.temp_comp_get_cfm.degree; ++ ++ mod_timer(&sdiodev->tp_ctrl_timer, ++ jiffies + msecs_to_jiffies(TEMP_GET_INTERVAL)); ++ ++ return; ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) ++static void aicwf_temp_ctrl_timer(ulong data) ++#else ++static void aicwf_temp_ctrl_timer(struct timer_list *t) ++#endif ++{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) ++ struct aic_sdio_dev *sdiodev = (struct aic_sdio_dev *)data; ++#else ++ struct aic_sdio_dev *sdiodev = timer_container_of(sdiodev, t, tp_ctrl_timer); ++#endif ++ ++ if (!work_pending(&sdiodev->tp_ctrl_work)) ++ schedule_work(&sdiodev->tp_ctrl_work); ++ ++ return; ++} ++#endif ++ ++int aicwf_sdio_flow_ctrl_msg(struct aic_sdio_dev *sdiodev) ++{ ++ int ret = -1; ++ u8 fc_reg = 0; ++ u32 count = 0; ++ ++ while (true) { ++ ret = aicwf_sdio_readb(sdiodev, sdiodev->sdio_reg.flow_ctrl_reg, ++ &fc_reg); ++ if (ret) { ++ return -1; ++ } ++ ++ if (sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ fc_reg = fc_reg & SDIOWIFI_FLOWCTRL_MASK_REG; ++ } ++ ++ if (fc_reg != 0) { ++ ret = fc_reg; ++ if (ret > tx_aggr_counter) { ++ ret = tx_aggr_counter; ++ } ++ 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); ++ } ++ } ++ ++ 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, sdiodev->sdio_reg.flow_ctrl_reg, ++ &fc_reg); ++ if (ret) { ++ return -1; ++ } ++ ++ if (sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ fc_reg = fc_reg & SDIOWIFI_FLOWCTRL_MASK_REG; ++ } ++ ++ if (fc_reg > DATA_FLOW_CTRL_THRESH) { ++ ret = fc_reg; ++ if (ret > tx_aggr_counter) { ++ ret = tx_aggr_counter; ++ } ++ 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); ++ } ++ } ++ ++ return ret; ++} ++ ++int aicwf_sdio_send_pkt(struct aic_sdio_dev *sdiodev, u8 *buf, uint count) ++{ ++ int ret = 0; ++ ++ sdio_claim_host(sdiodev->func); ++ ret = sdio_writesb(sdiodev->func, sdiodev->sdio_reg.wr_fifo_addr, buf, ++ count); ++ sdio_release_host(sdiodev->func); ++ ++ return ret; ++} ++ ++#ifdef CONFIG_PREALLOC_RX_SKB ++int aicwf_sdio_recv_pkt(struct aic_sdio_dev *sdiodev, struct rx_buff *rxbuff, ++ u32 size) ++{ ++ int ret; ++ ++ if ((!rxbuff->data) || (!size)) { ++ return -EINVAL; ++ ; ++ } ++ ++ sdio_claim_host(sdiodev->func); ++ ret = sdio_readsb(sdiodev->func, rxbuff->data, ++ sdiodev->sdio_reg.rd_fifo_addr, size); ++ sdio_release_host(sdiodev->func); ++ ++ if (ret < 0) { ++ return ret; ++ } ++ rxbuff->len = size; ++ ++ return ret; ++} ++#else ++int aicwf_sdio_recv_pkt(struct aic_sdio_dev *sdiodev, struct sk_buff *skbbuf, ++ u32 size) ++{ ++ int ret; ++ ++ if ((!skbbuf) || (!size)) { ++ return -EINVAL; ++ ; ++ } ++ ++ sdio_claim_host(sdiodev->func); ++ ret = sdio_readsb(sdiodev->func, skbbuf->data, ++ sdiodev->sdio_reg.rd_fifo_addr, size); ++ sdio_release_host(sdiodev->func); ++ ++ if (ret < 0) { ++ return ret; ++ } ++ skbbuf->len = size; ++ ++ return ret; ++} ++#endif ++ ++#ifdef CONFIG_GPIO_WAKEUP ++static int wakeup_enable; ++static u32 hostwake_irq_num; ++#endif //CONFIG_GPIO_WAKEUP ++ ++#if LINUX_VERSION_CODE >= \ ++ KERNEL_VERSION(4, 14, \ ++ 0) //LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0) ++//static struct wakeup_source *ws_rx_sdio; ++//static struct wakeup_source *ws_sdio_pwrctrl; ++//static struct wakeup_source *ws_tx_sdio; ++#ifdef CONFIG_GPIO_WAKEUP ++//static struct wakeup_source *ws; ++#endif ++#else ++#ifdef ANDROID_PLATFORM ++#ifdef CONFIG_GPIO_WAKEUP ++#include ++static struct wake_lock irq_wakelock; ++//struct wake_lock irq_wakelock; ++#endif //CONFIG_GPIO_WAKEUP ++#endif //ANDROID_PLATFORM ++#endif ++ ++#ifdef CONFIG_PLATFORM_ALLWINNER ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0) ++extern int sunxi_wlan_get_oob_irq(int *, int *); ++#else ++extern int sunxi_wlan_get_oob_irq(void); ++extern int sunxi_wlan_get_oob_irq_flags(void); ++#endif ++#endif // CONFIG_PLATFORM_ALLWINNER ++ ++#if 0 ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++static struct wakeup_source *ws; ++#else ++#ifdef ANDROID_PLATFORM ++#ifdef CONFIG_GPIO_WAKEUP ++#include ++static struct wake_lock irq_wakelock; ++#endif //CONFIG_GPIO_WAKEUP ++#endif //ANDROID_PLATFORM ++#endif ++#endif ++ ++#if 0 ++void rwnx_pm_stay_awake(struct aic_sdio_dev *sdiodev){ ++ ++#ifdef CONFIG_GPIO_WAKEUP ++ spin_lock_bh(&sdiodev->wslock); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) ++ if(ws != NULL){ ++ __pm_stay_awake(ws); ++ AICWFDBG(LOGWAKELOCK, "%s active_count:%d relax_count:%d\r\n", __func__, (int)ws->active_count, (int)ws->relax_count); ++ } ++#else ++#ifdef ANDROID_PLATFORM ++#ifdef CONFIG_GPIO_WAKEUP ++ wake_lock(&irq_wakelock); ++#endif //CONFIG_GPIO_WAKEUP ++#endif //ANDROID_PLATFORM ++#endif ++ ++ spin_unlock_bh(&sdiodev->wslock); ++#endif ++} ++ ++void rwnx_pm_relax(struct aic_sdio_dev *sdiodev){ ++ ++#ifdef CONFIG_GPIO_WAKEUP ++ spin_lock_bh(&sdiodev->wslock); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) ++ if(ws != NULL){ ++ __pm_relax(ws); ++ AICWFDBG(LOGWAKELOCK, "%s active_count:%d relax_count:%d\r\n", __func__, (int)ws->active_count, (int)ws->relax_count); ++ } ++#else ++#ifdef ANDROID_PLATFORM ++#ifdef CONFIG_GPIO_WAKEUP ++ wake_unlock(&irq_wakelock); ++#endif //CONFIG_GPIO_WAKEUP ++#endif //ANDROID_PLATFORM ++#endif ++ spin_unlock_bh(&sdiodev->wslock); ++#endif ++ ++} ++#endif ++ ++#ifdef CONFIG_GPIO_WAKEUP ++ ++void rwnx_set_wifi_suspend(char onoff); ++ ++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) ++ rwnx_wakeup_lock_timeout(g_rwnx_plat->sdiodev->rwnx_hw->ws_rx, 1000); ++#else ++#ifdef ANDROID_PLATFORM ++ wake_lock_timeout(&irq_wakelock, HZ); ++#endif //ANDROID_PLATFORM ++#endif ++ ++ AICWFDBG(LOGIRQ, "%s(%d): wake_irq_cnt = %d\n", __func__, __LINE__, ++ wake_cnt); ++ ++#ifdef CONFIG_OOB ++#if 0 //old oob feature ++ complete(&g_rwnx_plat->sdiodev->bus_if->busrx_trgg); ++#else //new oob feature ++ if (g_rwnx_plat->sdiodev->oob_enable) { ++ complete(&g_rwnx_plat->sdiodev->bus_if->busirq_trgg); ++ } ++#endif //old oob feature ++#endif ++ ++ return IRQ_HANDLED; ++} ++#endif //CONFIG_GPIO_WAKEUP ++ ++#ifdef CONFIG_GPIO_WAKEUP ++static int rwnx_disable_hostwake_irq(void); ++static int rwnx_enable_hostwake_irq(void); ++#endif ++ ++static int rwnx_register_hostwake_irq(struct device *dev) ++{ ++ int ret = 0; //-1; ++#ifdef CONFIG_GPIO_WAKEUP ++ unsigned long flag_edge; ++ struct aicbsp_feature_t aicwf_feature; ++ int irq_flags; ++ //TODO hostwake_irq_num hostwake_irq_num and wakeup_enable ++ ++ aicbsp_get_feature(&aicwf_feature, NULL); ++ if (aicwf_feature.irqf == 0) ++ flag_edge = IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND; ++ else ++ flag_edge = IRQF_TRIGGER_FALLING | IRQF_NO_SUSPEND; ++ ++#ifdef CONFIG_PLATFORM_ALLWINNER ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0) ++ hostwake_irq_num = sunxi_wlan_get_oob_irq(&irq_flags, &wakeup_enable); ++#else ++ hostwake_irq_num = sunxi_wlan_get_oob_irq(); ++ irq_flags = sunxi_wlan_get_oob_irq_flags(); ++ wakeup_enable = 1; ++#endif ++#endif //CONFIG_PLATFORM_ALLWINNER ++ ++//For Rockchip ++#ifdef CONFIG_PLATFORM_ROCKCHIP ++ hostwake_irq_num = rockchip_wifi_get_oob_irq(); ++ printk("%s hostwake_irq_num:%d \r\n", __func__, hostwake_irq_num); ++ irq_flags = (IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | ++ IORESOURCE_IRQ_SHAREABLE) & ++ IRQF_TRIGGER_MASK; ++ printk("%s irq_flags:%d \r\n", __func__, irq_flags); ++ wakeup_enable = 1; ++#endif //CONFIG_PLATFORM_ROCKCHIP ++ //For Rockchip ++#ifdef CONFIG_PLATFORM_ROCKCHIP2 ++ hostwake_irq_num = rockchip_wifi_get_oob_irq(); ++ printk("%s hostwake_irq_num:%d \r\n", __func__, hostwake_irq_num); ++ irq_flags = (IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | ++ IORESOURCE_IRQ_SHAREABLE) & ++ IRQF_TRIGGER_MASK; ++ printk("%s irq_flags:%d \r\n", __func__, irq_flags); ++ wakeup_enable = 1; ++#endif //CONFIG_PLATFORM_ROCKCHIP ++ ++ if (wakeup_enable) { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ //ws = wakeup_source_register(dev, "wifisleep"); ++ //ws_tx_sdio = wakeup_source_register(dev, "wifi_tx_sleep"); ++ //ws_rx_sdio = wakeup_source_register(dev, "wifi_rx_sleep"); ++ //ws_sdio_pwrctrl = wakeup_source_register(dev, "sdio_pwrctrl_sleep"); ++#else ++#ifdef ANDROID_PLATFORM ++ wake_lock_init(&irq_wakelock, WAKE_LOCK_SUSPEND, "wifisleep"); ++#endif ++#endif ++ ret = device_init_wakeup(dev, true); ++ if (ret < 0) { ++ pr_err("%s(%d): device init wakeup failed!\n", __func__, ++ __LINE__); ++ return ret; ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) ++ ret = dev_pm_set_wake_irq(dev, hostwake_irq_num); ++#endif ++ if (ret < 0) { ++ pr_err("%s(%d): can't enable wakeup src!\n", __func__, ++ __LINE__); ++ goto fail1; ++ } ++ ++ ret = request_irq(hostwake_irq_num, rwnx_hostwake_irq_handler, ++ flag_edge, "rwnx_hostwake_irq", NULL); ++ ++ if (ret < 0) { ++ pr_err("%s(%d): request_irq fail! ret = %d\n", __func__, ++ __LINE__, ret); ++ goto fail2; ++ } ++ } ++ //disable_irq(hostwake_irq_num); ++ rwnx_disable_hostwake_irq(); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) ++ dev_pm_clear_wake_irq(dev); ++#endif ++ rwnx_enable_hostwake_irq(); ++ AICWFDBG(LOGINFO, "%s(%d)\n", __func__, __LINE__); ++ return ret; ++ ++fail2: ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) ++ dev_pm_clear_wake_irq(dev); ++#endif ++fail1: ++ device_init_wakeup(dev, false); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ //wakeup_source_unregister(ws); ++ //wakeup_source_unregister(ws_tx_sdio); ++ //wakeup_source_unregister(ws_rx_sdio); ++ //wakeup_source_unregister(ws_sdio_pwrctrl); ++#else ++#ifdef ANDROID_PLATFORM ++ wake_lock_destroy(&irq_wakelock); ++#endif ++#endif ++#endif //CONFIG_GPIO_WAKEUP ++ return ret; ++} ++ ++static int rwnx_unregister_hostwake_irq(struct device *dev) ++{ ++#ifdef CONFIG_GPIO_WAKEUP ++ rwnx_disable_hostwake_irq(); ++ if (wakeup_enable) { ++ device_init_wakeup(dev, false); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) ++ dev_pm_clear_wake_irq(dev); ++#else ++ AICWFDBG(LOGERROR, "%s kernel unsupport this feature!\r\n", ++ __func__); ++#endif ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ //wakeup_source_unregister(ws); ++ //wakeup_source_unregister(ws_tx_sdio); ++ //wakeup_source_unregister(ws_rx_sdio); ++ //wakeup_source_unregister(ws_sdio_pwrctrl); ++#else ++#ifdef ANDROID_PLATFORM ++ wake_lock_destroy(&irq_wakelock); ++#endif //ANDROID_PLATFORM ++#endif ++ } ++ free_irq(hostwake_irq_num, NULL); ++#endif //CONFIG_GPIO_WAKEUP ++ AICWFDBG(LOGINFO, "%s(%d)\n", __func__, __LINE__); ++ return 0; ++} ++ ++#ifdef CONFIG_GPIO_WAKEUP ++static int rwnx_enable_hostwake_irq(void) ++{ ++#ifdef CONFIG_GPIO_WAKEUP ++ enable_irq(hostwake_irq_num); ++ enable_irq_wake(hostwake_irq_num); ++#endif //CONFIG_GPIO_WAKEUP ++ AICWFDBG(LOGINFO, "%s(%d)\n", __func__, __LINE__); ++ return 0; ++} ++ ++static int rwnx_disable_hostwake_irq(void) ++{ ++ AICWFDBG(LOGINFO, "%s(%d)\n", __func__, __LINE__); ++#ifdef CONFIG_GPIO_WAKEUP ++ disable_irq_nosync(hostwake_irq_num); ++ //disable_irq_wake(hostwake_irq_num); ++ //disable_irq(hostwake_irq_num); ++#endif //CONFIG_GPIO_WAKEUP ++ return 0; ++} ++#endif ++ ++static int aicwf_sdio_chipmatch(struct aic_sdio_dev *sdio_dev, u16_l vid, ++ u16_l did) ++{ ++ if (vid == SDIO_VENDOR_ID_AIC8801 && did == SDIO_DEVICE_ID_AIC8801) { ++ sdio_dev->chipid = PRODUCT_ID_AIC8801; ++ AICWFDBG(LOGINFO, "%s USE AIC8801\r\n", __func__); ++ return 0; ++ } else if (vid == SDIO_VENDOR_ID_AIC8800DC && ++ did == SDIO_DEVICE_ID_AIC8800DC) { ++ sdio_dev->chipid = PRODUCT_ID_AIC8800DC; ++ AICWFDBG(LOGINFO, "%s USE AIC8800DC\r\n", __func__); ++ return 0; ++ } else if (vid == SDIO_VENDOR_ID_AIC8800D80 && ++ did == SDIO_DEVICE_ID_AIC8800D80) { ++ sdio_dev->chipid = PRODUCT_ID_AIC8800D80; ++ AICWFDBG(LOGINFO, "%s USE AIC8800D80\r\n", __func__); ++ return 0; ++ } else if (vid == SDIO_VENDOR_ID_AIC8800D80X2 && ++ did == SDIO_DEVICE_ID_AIC8800D80X2) { ++ sdio_dev->chipid = PRODUCT_ID_AIC8800D80X2; ++ AICWFDBG(LOGINFO, "%s USE AIC8800D80X2\r\n", __func__); ++ return 0; ++ } else { ++ return -1; ++ } ++} ++ ++extern int rwnx_send_me_set_lp_level(struct rwnx_hw *rwnx_hw, u8 lp_level, ++ u8 disable_filter); ++ ++static int aicwf_sdio_probe(struct sdio_func *func, ++ const struct sdio_device_id *id) ++{ ++ struct mmc_host *host; ++ struct aic_sdio_dev *sdiodev; ++ struct aicwf_bus *bus_if; ++ int err = -ENODEV; ++ ++ AICWFDBG(LOGDEBUG, "%s:%d\n", __func__, func->num); ++ AICWFDBG(LOGDEBUG, "Class=%x\n", func->class); ++ AICWFDBG(LOGDEBUG, "sdio vendor ID: 0x%04x\n", func->vendor); ++ AICWFDBG(LOGDEBUG, "sdio device ID: 0x%04x\n", func->device); ++ AICWFDBG(LOGDEBUG, "Function#: %d\n", func->num); ++ ++ host = func->card->host; ++ if (func->num != 1) { ++ return err; ++ } ++ ++ bus_if = kzalloc(sizeof(struct aicwf_bus), GFP_KERNEL); ++ if (!bus_if) { ++ sdio_err("alloc bus fail\n"); ++ return -ENOMEM; ++ } ++ ++ sdiodev = kzalloc(sizeof(struct aic_sdio_dev), GFP_KERNEL); ++ if (!sdiodev) { ++ sdio_err("alloc sdiodev fail\n"); ++ kfree(bus_if); ++ return -ENOMEM; ++ } ++ ++ err = aicwf_sdio_chipmatch(sdiodev, func->vendor, func->device); ++ ++ sdiodev->func = func; ++ sdiodev->bus_if = bus_if; ++ ++#ifdef CONFIG_OOB ++ if (sdiodev->chipid == PRODUCT_ID_AIC8801) { ++ AICWFDBG(LOGERROR, "%s ERROR!!! 8801 not support OOB \r\n", ++ __func__); ++ sdiodev->oob_enable = false; ++ } else { ++ sdiodev->oob_enable = true; ++ } ++#else ++ sdiodev->oob_enable = false; ++#endif ++ ++ atomic_set(&sdiodev->is_bus_suspend, 0); ++ bus_if->bus_priv.sdio = sdiodev; ++ ++ dev_set_drvdata(&func->dev, bus_if); ++ sdiodev->dev = &func->dev; ++ ++ if (sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ sdiodev->func2 = func->card->sdio_func[1]; ++ } ++ ++ //sdio func init start ++ if (sdiodev->chipid != PRODUCT_ID_AIC8800D80 && ++ sdiodev->chipid != PRODUCT_ID_AIC8800D80X2) { ++ err = aicwf_sdio_func_init(sdiodev); ++ } else { ++ err = aicwf_sdiov3_func_init(sdiodev); ++ } ++ if (err < 0) { ++ sdio_err("sdio func init fail\n"); ++ goto fail; ++ } ++ //sdio func init end ++ ++ 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; ++ ++#ifdef CONFIG_GPIO_WAKEUP ++#ifdef CONFIG_OOB ++ if (sdiodev->oob_enable) { ++ AICWFDBG(LOGINFO, "%s SDIOWIFI_INTR_CONFIG_REG Disable\n", ++ __func__); ++ sdio_claim_host(sdiodev->func); ++ //disable sdio interrupt ++ err = aicwf_sdio_writeb(sdiodev, SDIOWIFI_INTR_CONFIG_REG, 0x0); ++ if (err < 0) { ++ sdio_err("reg:%d write failed!\n", ++ SDIOWIFI_INTR_CONFIG_REG); ++ } ++ sdio_release_irq(sdiodev->func); ++ sdio_release_host(sdiodev->func); ++#if 0 ++#if 0 //old oob feature ++ sdiodev->oob_enable = true; ++#else //new oob feature ++ sdiodev->oob_enable = true; ++#endif //old oob feature ++#endif ++ } ++#endif ++ ++#ifdef CONFIG_WIFI_SUSPEND_FOR_LINUX ++ rwnx_init_wifi_suspend_node(); ++#endif //CONFIG_WIFI_SUSPEND_FOR_LINUX ++#endif //CONFIG_GPIO_WAKEUP ++ device_disable_async_suspend(sdiodev->dev); ++ ++ return 0; ++fail: ++ aicwf_sdio_func_deinit(sdiodev); ++ dev_set_drvdata(&func->dev, NULL); ++ kfree(sdiodev); ++ kfree(bus_if); ++ aicwf_hostif_fail(); ++ return err; ++} ++ ++void aicwf_sdio_probe_(struct sdio_func *func, const struct sdio_device_id *id) ++{ ++ aicwf_sdio_probe(func, NULL); ++} ++ ++static void aicwf_sdio_remove(struct sdio_func *func) ++{ ++ struct mmc_host *host; ++ struct aicwf_bus *bus_if = NULL; ++ struct aic_sdio_dev *sdiodev = NULL; ++ ++ AICWFDBG(LOGINFO, "%s Enter\n", __func__); ++ host = func->card->host; ++ host->caps &= ~MMC_CAP_NONREMOVABLE; ++ bus_if = dev_get_drvdata(&func->dev); ++ if (!bus_if) { ++ return; ++ } ++ ++ sdiodev = bus_if->bus_priv.sdio; ++ if (!sdiodev) { ++ return; ++ } ++ ++ sdiodev->bus_if->state = BUS_DOWN_ST; ++ aicwf_sdio_release(sdiodev); ++ aicwf_sdio_func_deinit(sdiodev); ++ rwnx_unregister_hostwake_irq(sdiodev->dev); ++ dev_set_drvdata(&sdiodev->func->dev, NULL); ++ kfree(sdiodev); ++ kfree(bus_if); ++#ifdef CONFIG_WIFI_SUSPEND_FOR_LINUX ++ rwnx_deinit_wifi_suspend_node(); ++#endif //CONFIG_WIFI_SUSPEND_FOR_LINUX ++ AICWFDBG(LOGINFO, "%s done\n", __func__); ++} ++ ++void aicwf_sdio_remove_(struct sdio_func *func) ++{ ++ aicwf_sdio_remove(func); ++} ++ ++#if defined(CONFIG_PLATFORM_ROCKCHIP) || defined(CONFIG_PLATFORM_ROCKCHIP2) ++#ifdef CONFIG_SHUTDOWN_CALLBACK ++int rwnx_close_(struct net_device *dev); ++ ++void aicwf_sdio_shutdown(struct device *dev) ++{ ++ struct rwnx_vif *rwnx_vif, *tmp; ++ struct aicwf_bus *bus_if = dev_get_drvdata(dev); ++ struct aic_sdio_dev *sdiodev = bus_if->bus_priv.sdio; ++ ++ AICWFDBG(LOGINFO, "%s Enter", __func__); ++ list_for_each_entry_safe (rwnx_vif, tmp, &sdiodev->rwnx_hw->vifs, ++ list) { ++ if (rwnx_vif->ndev && ++ test_bit(RWNX_DEV_STARTED, &rwnx_vif->drv_flags)) { ++ AICWFDBG(LOGINFO, "%s rwnx_close by shutdown", ++ __func__); ++ rwnx_close_(rwnx_vif->ndev); ++ ++ } else { ++ if (!rwnx_vif->ndev) { ++ AICWFDBG(LOGERROR, ++ "%s rwnx_vif->ndev is NULL \r\n", ++ __func__); ++ } ++ if (!test_bit(RWNX_DEV_STARTED, &rwnx_vif->drv_flags)) { ++ AICWFDBG(LOGERROR, ++ "%s rwnx_vif->drv_flags close\r\n", ++ __func__); ++ } ++ } ++ } ++ AICWFDBG(LOGINFO, "%s Exit", __func__); ++} ++#endif ++#endif ++ ++#if defined(CONFIG_AUTO_POWERSAVE) ++static int aicwf_wakeup_lock_status(struct rwnx_hw *rwnx_hw) ++{ ++ if (rwnx_hw->ws_tx && rwnx_hw->ws_tx->active) ++ return -1; ++ ++ if (rwnx_hw->ws_rx && rwnx_hw->ws_rx->active) ++ return -1; ++ ++ if (rwnx_hw->ws_pwrctrl && rwnx_hw->ws_pwrctrl->active) ++ return -1; ++ ++ if (rwnx_hw->ws_irqrx && rwnx_hw->ws_irqrx->active) ++ return -1; ++ ++ return 0; ++} ++#endif ++ ++static int aicwf_sdio_suspend(struct device *dev) ++{ ++ int ret = 0; ++ struct aicwf_bus *bus_if = dev_get_drvdata(dev); ++ struct aic_sdio_dev *sdiodev = bus_if->bus_priv.sdio; ++ mmc_pm_flag_t sdio_flags; ++ struct rwnx_vif *rwnx_vif, *tmp; ++ ++ sdio_dbg("%s enter\n", __func__); ++ ++ list_for_each_entry_safe (rwnx_vif, tmp, &sdiodev->rwnx_hw->vifs, ++ list) { ++ if (rwnx_vif->ndev) ++ netif_device_detach(rwnx_vif->ndev); ++ } ++ ++ sdio_flags = sdio_get_host_pm_caps(sdiodev->func); ++ if (!(sdio_flags & MMC_PM_KEEP_POWER)) { ++ return -EINVAL; ++ } ++ ret = sdio_set_host_pm_flags(sdiodev->func, MMC_PM_KEEP_POWER); ++ if (ret) { ++ return ret; ++ } ++ ++#ifdef CONFIG_TEMP_CONTROL ++ timer_delete_sync(&sdiodev->tp_ctrl_timer); ++ cancel_work_sync(&sdiodev->tp_ctrl_work); ++ ++ mod_timer(&sdiodev->tp_ctrl_timer, ++ jiffies + msecs_to_jiffies(TEMP_GET_INTERVAL)); ++ ++ timer_delete_sync(&sdiodev->netif_timer); ++ cancel_work_sync(&sdiodev->netif_work); ++#endif ++ ++#if (defined(CONFIG_AUTO_POWERSAVE) && defined(CONFIG_SDIO_PWRCTRL)) ++ aicwf_sdio_pwr_stctl(sdiodev, SDIO_ACTIVE_ST); ++ ++ if ((sdiodev->chipid == PRODUCT_ID_AIC8800D80) || ++ (sdiodev->chipid == PRODUCT_ID_AIC8800D80X2)) { ++ sdio_dbg("autops set\n"); ++ ret = aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.wakeup_reg, ++ 0x8); ++ if (ret) { ++ sdio_err("sdio set autops fail\n"); ++ } ++ } ++#endif ++ ++#if (!defined(CONFIG_AUTO_POWERSAVE)) ++ while (sdiodev->state == SDIO_ACTIVE_ST) { ++ if (down_interruptible(&sdiodev->tx_priv->txctl_sema)) ++ continue; ++#if defined(CONFIG_SDIO_PWRCTRL) ++ aicwf_sdio_pwr_stctl(sdiodev, SDIO_SLEEP_ST); ++#endif ++ up(&sdiodev->tx_priv->txctl_sema); ++ break; ++ } ++#else ++#if defined(CONFIG_SDIO_PWRCTRL) ++ aicwf_sdio_pwr_stctl(sdiodev, SDIO_SLEEP_ST); ++#endif ++#endif ++#ifdef CONFIG_GPIO_WAKEUP ++// rwnx_enable_hostwake_irq(); ++#endif ++ ++#if defined(CONFIG_PLATFORM_ROCKCHIP) || defined(CONFIG_PLATFORM_ROCKCHIP2) ++ if (sdiodev->chipid == PRODUCT_ID_AIC8801) { ++ sdio_dbg("%s SDIOWIFI_INTR_CONFIG_REG Disable\n", __func__); ++ sdio_claim_host(sdiodev->func); ++ //disable sdio interrupt ++ ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_INTR_CONFIG_REG, 0x0); ++ if (ret < 0) { ++ sdio_err("reg:%d write failed!\n", ++ SDIOWIFI_INTR_CONFIG_REG); ++ } ++ sdio_release_irq(sdiodev->func); ++ sdio_release_host(sdiodev->func); ++ } ++#endif ++ atomic_set(&sdiodev->is_bus_suspend, 1); ++ // smp_mb(); ++ ++#if defined(CONFIG_AUTO_POWERSAVE) ++ if (aicwf_wakeup_lock_status(sdiodev->rwnx_hw)) { ++ printk("%s ws active dont suspend", __func__); ++ aicwf_sdio_pwr_stctl(sdiodev, SDIO_ACTIVE_ST); ++ ++ if ((sdiodev->chipid == PRODUCT_ID_AIC8800D80) || ++ (sdiodev->chipid == PRODUCT_ID_AIC8800D80X2)) { ++ sdio_dbg("autops clear\n"); ++ ret = aicwf_sdio_writeb( ++ sdiodev, sdiodev->sdio_reg.wakeup_reg, 0x8); ++ if (ret) { ++ sdio_err("sdio clear autops fail\n"); ++ } ++ } ++ ++ return -EBUSY; ++ } ++#endif ++ ++ sdio_dbg("%s exit\n", __func__); ++ ++ return 0; ++} ++ ++static int aicwf_sdio_resume(struct device *dev) ++{ ++ struct aicwf_bus *bus_if = dev_get_drvdata(dev); ++ struct aic_sdio_dev *sdiodev = bus_if->bus_priv.sdio; ++ struct rwnx_vif *rwnx_vif, *tmp; ++#if defined(CONFIG_PLATFORM_ROCKCHIP) || defined(CONFIG_PLATFORM_ROCKCHIP2) || \ ++ defined(CONFIG_AUTO_POWERSAVE) ++ int ret; ++#endif ++ ++ sdio_dbg("%s enter \n", __func__); ++ ++#ifdef CONFIG_TEMP_CONTROL ++ mod_timer(&sdiodev->tp_ctrl_timer, ++ jiffies + msecs_to_jiffies(TEMP_GET_INTERVAL)); ++#endif ++ ++ //#ifdef CONFIG_GPIO_WAKEUP ++ // rwnx_disable_hostwake_irq(); ++ //#endif ++ //dev_pm_clear_wake_irq(dev); ++ list_for_each_entry_safe (rwnx_vif, tmp, &sdiodev->rwnx_hw->vifs, ++ list) { ++ if (rwnx_vif->ndev) ++ netif_device_attach(rwnx_vif->ndev); ++ } ++ ++#if defined(CONFIG_SDIO_PWRCTRL) ++ aicwf_sdio_pwr_stctl(sdiodev, SDIO_ACTIVE_ST); ++#endif ++ ++#if defined(CONFIG_AUTO_POWERSAVE) && defined(CONFIG_SDIO_PWRCTRL) ++ if (sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ sdio_dbg("autops clear\n"); ++ ret = aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.wakeup_reg, ++ 0x8); ++ if (ret) { ++ sdio_err("sdio clear autops fail\n"); ++ } ++ } ++#endif ++ ++ // aicwf_sdio_hal_irqhandler(sdiodev->func); ++ ++#if defined(CONFIG_PLATFORM_ROCKCHIP) || defined(CONFIG_PLATFORM_ROCKCHIP2) ++ if (sdiodev->chipid == PRODUCT_ID_AIC8801) { ++ sdio_dbg("%s SDIOWIFI_INTR_CONFIG_REG Enable\n", __func__); ++ sdio_claim_host(sdiodev->func); ++ sdio_claim_irq(sdiodev->func, aicwf_sdio_hal_irqhandler); ++ ++ //enable sdio interrupt ++ ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_INTR_CONFIG_REG, ++ 0x07); ++ if (ret != 0) ++ sdio_err("intr register failed:%d\n", ret); ++ sdio_release_host(sdiodev->func); ++ } ++#endif ++ atomic_set(&sdiodev->is_bus_suspend, 0); ++ // smp_mb(); ++#ifdef CONFIG_WIFI_SUSPEND_FOR_LINUX ++ rwnx_set_wifi_suspend('0'); ++#endif //CONFIG_WIFI_SUSPEND_FOR_LINUX ++ ++ sdio_dbg("%s exit\n", __func__); ++ return 0; ++} ++ ++static const struct sdio_device_id aicwf_sdmmc_ids[] = { ++ { SDIO_DEVICE(SDIO_VENDOR_ID_AIC8801, SDIO_DEVICE_ID_AIC8801) }, ++ { SDIO_DEVICE(SDIO_VENDOR_ID_AIC8800DC, SDIO_DEVICE_ID_AIC8800DC) }, ++ { SDIO_DEVICE(SDIO_VENDOR_ID_AIC8800D80, SDIO_DEVICE_ID_AIC8800D80) }, ++ { SDIO_DEVICE(SDIO_VENDOR_ID_AIC8800D80X2, ++ SDIO_DEVICE_ID_AIC8800D80X2) }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(sdio, aicwf_sdmmc_ids); ++ ++static const struct dev_pm_ops aicwf_sdio_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS( ++ aicwf_sdio_suspend, aicwf_sdio_resume) }; ++ ++#ifndef CONFIG_FDRV_NO_REG_SDIO ++static struct sdio_driver aicwf_sdio_driver = { ++ .probe = aicwf_sdio_probe, ++ .remove = aicwf_sdio_remove, ++ .name = AICWF_SDIO_NAME, ++ .id_table = aicwf_sdmmc_ids, ++ .drv = { ++ .pm = &aicwf_sdio_pm_ops, ++#if defined(CONFIG_PLATFORM_ROCKCHIP) || defined(CONFIG_PLATFORM_ROCKCHIP2) ++#ifdef CONFIG_SHUTDOWN_CALLBACK ++ .shutdown = aicwf_sdio_shutdown, ++#endif ++#endif ++ }, ++}; ++#endif ++ ++#if 0 ++#ifdef CONFIG_NANOPI_M4 ++extern int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq); ++extern unsigned aic_max_freqs; ++extern struct mmc_host *aic_host_drv; ++extern int __mmc_claim_host(struct mmc_host *host, atomic_t *abort); ++extern void mmc_release_host(struct mmc_host *host); ++#endif ++#endif ++ ++#ifdef CONFIG_FDRV_NO_REG_SDIO ++extern struct sdio_func *get_sdio_func(void); ++void aicwf_sdio_probe_(struct sdio_func *func, const struct sdio_device_id *id); ++void aicwf_sdio_remove_(struct sdio_func *func); ++#endif ++ ++void aicwf_sdio_register(void) ++{ ++#if 0 ++#ifdef CONFIG_PLATFORM_NANOPI ++ extern_wifi_set_enable(0); ++ mdelay(200); ++ extern_wifi_set_enable(1); ++ mdelay(200); ++ sdio_reinit(); ++#endif /*CONFIG_PLATFORM_NANOPI*/ ++ ++#ifdef CONFIG_PLATFORM_ROCKCHIP ++ rockchip_wifi_power(0); ++ mdelay(200); ++ rockchip_wifi_power(1); ++ mdelay(200); ++ rockchip_wifi_set_carddetect(1); ++#endif /*CONFIG_PLATFORM_ROCKCHIP*/ ++ ++#ifdef CONFIG_INGENIC_T20 ++ jzmmc_manual_detect(1, 1); ++#endif /* CONFIG_INGENIC_T20 */ ++ ++#ifdef CONFIG_NANOPI_M4 ++ if (aic_host_drv->card == NULL) { ++ __mmc_claim_host(aic_host_drv, NULL); ++ printk("aic: >>>mmc_rescan_try_freq\n"); ++ mmc_rescan_try_freq(aic_host_drv, aic_max_freqs); ++ mmc_release_host(aic_host_drv); ++ } ++#endif ++#endif ++ ++#ifndef CONFIG_FDRV_NO_REG_SDIO ++ if (sdio_register_driver(&aicwf_sdio_driver)) { ++ } else { ++ //may add mmc_rescan here ++ } ++#else ++ aicwf_sdio_probe_(get_sdio_func(), NULL); ++#endif ++} ++ ++void aicwf_sdio_exit(void) ++{ ++ if (g_rwnx_plat && g_rwnx_plat->enabled) { ++#ifdef CONFIG_TEMP_CONTROL ++ if (timer_pending(&g_rwnx_plat->sdiodev->tp_ctrl_timer)) { ++ AICWFDBG(LOGINFO, "%s del tp_ctrl_timer\n", __func__); ++ timer_delete_sync(&g_rwnx_plat->sdiodev->tp_ctrl_timer); ++ } ++ cancel_work_sync(&g_rwnx_plat->sdiodev->tp_ctrl_work); ++ ++ if (timer_pending(&g_rwnx_plat->sdiodev->netif_timer)) { ++ AICWFDBG(LOGINFO, "%s del netif_timer\n", __func__); ++ timer_delete_sync(&g_rwnx_plat->sdiodev->netif_timer); ++ } ++ cancel_work_sync(&g_rwnx_plat->sdiodev->netif_work); ++#endif ++ rwnx_platform_deinit(g_rwnx_plat->sdiodev->rwnx_hw); ++ } else { ++ AICWFDBG(LOGERROR, "%s g_rwnx_plat is not ready \r\n", ++ __func__); ++ } ++ ++ udelay(500); ++ ++#ifndef CONFIG_FDRV_NO_REG_SDIO ++ sdio_unregister_driver(&aicwf_sdio_driver); ++#else ++ aicwf_sdio_remove_(get_sdio_func()); ++#endif ++ ++#if 0 ++#ifdef CONFIG_PLATFORM_AMLOGIC ++ extern_wifi_set_enable(0); ++#endif /*CONFIG_PLATFORM_AMLOGIC*/ ++#endif ++ ++#if 0 ++#ifdef CONFIG_PLATFORM_ROCKCHIP ++ rockchip_wifi_set_carddetect(0); ++ mdelay(200); ++ rockchip_wifi_power(0); ++ mdelay(200); ++#endif /*CONFIG_PLATFORM_ROCKCHIP*/ ++#endif ++ ++ if (g_rwnx_plat) { ++ kfree(g_rwnx_plat); ++ } ++} ++ ++#if defined(CONFIG_SDIO_PWRCTRL) ++int aicwf_sdio_wakeup(struct aic_sdio_dev *sdiodev) ++{ ++ int ret = 0; ++ int read_retry; ++ int write_retry = 1; ++ int wakeup_reg_val = 0; ++ ++ if (sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ wakeup_reg_val = 1; ++ } else if (sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ wakeup_reg_val = 0x11; ++ } ++ ++ if (sdiodev->state == SDIO_SLEEP_ST) { ++ int woke = 0; ++ ++ AICWFDBG(LOGSDPWRC, "%s w\n", __func__); ++ ++ //rwnx_pm_stay_awake(sdiodev); ++ ++ while (write_retry) { ++ ret = aicwf_sdio_writeb(sdiodev, ++ sdiodev->sdio_reg.wakeup_reg, ++ wakeup_reg_val); ++ if (ret) { ++ txrx_err("sdio wakeup fail\n"); ++ ret = -1; ++ } else { ++ read_retry = 50; ++ while (read_retry) { ++ u8 val; ++ ret = aicwf_sdio_readb( ++ sdiodev, ++ sdiodev->sdio_reg.wakeup_reg, ++ &val); ++ if (ret < 0) ++ txrx_err( ++ "sdio wakeup read fail\n"); ++ else if ((val & 0x1) == 0) { ++ woke = 1; ++ break; ++ } ++ read_retry--; ++ /* ++ * flare-edge: sleep, do NOT udelay() ++ * here. This is a sleepable context ++ * (reached only under pwrctl_wakeup_sema ++ * from the bustx kthread), and that ++ * thread re-enters this path on every ++ * TX. A busy-wait therefore pins the ++ * single Cortex-A7 core whenever the ++ * SDIO link wedges, starving the UI ++ * render loop -- the "extremely laggy" ++ * failure. Sleeping frees the core. ++ */ ++ usleep_range(200, 400); ++ } ++ if (woke) ++ break; ++ } ++ sdio_dbg("write retry: %d \n", write_retry); ++ write_retry--; ++ if (write_retry) ++ usleep_range(100, 200); ++ } ++ ++ /* ++ * flare-edge: never fake SDIO_ACTIVE_ST on a failed wake. The ++ * stock driver advanced state unconditionally, so a wedged link ++ * looked "awake" and every later TX hammered a dead chip forever ++ * with no recovery. Advance state only when the chip actually ++ * acknowledged; otherwise stay SLEEP and report the error so the ++ * caller (and the reset-recovery path added in a later patch) ++ * can act on it. ++ */ ++ if (woke) { ++ sdiodev->state = SDIO_ACTIVE_ST; ++ aicwf_sdio_pwrctl_timer(sdiodev, ++ sdiodev->active_duration); ++ ret = 0; ++ } else { ++ printk_ratelimited( ++ KERN_WARNING ++ "aic8800: SDIO wakeup failed; chip may be wedged\n"); ++ ret = -1; ++ } ++ } ++ return ret; ++} ++ ++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; ++ u8 read_retry; ++ u8 val; ++ ++ if (bus_if->state == BUS_DOWN_ST) { ++ ret = aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.sleep_reg, ++ 0x10); ++ if (ret) { ++ sdio_err("Write sleep fail!\n"); ++ } ++ aicwf_sdio_pwrctl_timer(sdiodev, 0); ++ return ret; ++ } ++ ++ 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 && ++ (int)(atomic_read(&sdiodev->tx_priv->tx_pktcnt) <= 0) && ++ (sdiodev->tx_priv->cmd_txstate == false) && ++ (int)(atomic_read(&sdiodev->rx_priv->rx_cnt) == 0)) { ++ AICWFDBG(LOGSDPWRC, "%s s\n", __func__); ++ if (sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ if (aicwf_sdio_writeb(sdiodev, ++ sdiodev->sdio_reg.wakeup_reg, ++ 0x02) < 0) { ++ sdio_err("reg:%d write failed!\n", ++ sdiodev->sdio_reg.wakeup_reg); ++ } ++ } else if (sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ if (aicwf_sdio_func2_writeb( ++ sdiodev, sdiodev->sdio_reg.wakeup_reg, ++ 0x2) < 0) { ++ sdio_err("reg:%d write failed!\n", ++ sdiodev->sdio_reg.wakeup_reg); ++ } ++ read_retry = 100; ++ while (read_retry) { ++ val = 0; ++ if (aicwf_sdio_func2_readb( ++ sdiodev, ++ sdiodev->sdio_reg.wakeup_reg, ++ &val) < 0) { ++ sdio_err("reg %d read fail\n", ++ sdiodev->sdio_reg.wakeup_reg); ++ } else if ((val & 0x2) == 0) { ++ break; ++ } else { ++ sdio_err("val:%d\n", val); ++ } ++ read_retry--; ++ if (read_retry < 90) ++ printk("warning: read cnt %d\n", ++ read_retry); ++ udelay(500); ++ } ++ } ++ sdiodev->state = SDIO_SLEEP_ST; ++ aicwf_sdio_pwrctl_timer(sdiodev, 0); ++ //rwnx_pm_relax(sdiodev); ++ } else { ++ aicwf_sdio_pwrctl_timer(sdiodev, sdiodev->active_duration); ++ } ++ ++ return ret; ++} ++ ++int aicwf_sdio_pwr_stctl(struct aic_sdio_dev *sdiodev, uint target) ++{ ++ int ret = 0; ++ ++ if (sdiodev->bus_if->state == BUS_DOWN_ST) { ++ 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; ++ } ++ ++ switch (target) { ++ case SDIO_ACTIVE_ST: ++ aicwf_sdio_wakeup(sdiodev); ++ break; ++ case SDIO_SLEEP_ST: ++ aicwf_sdio_sleep_allow(sdiodev); ++ break; ++ } ++ ++ up(&sdiodev->pwrctl_wakeup_sema); ++ return ret; ++} ++#endif ++ ++#if 0 ++int align_param = 16; ++module_param(align_param, int, 0660); ++#endif ++ ++int aicwf_sdio_txpkt(struct aic_sdio_dev *sdiodev, struct sk_buff *pkt) ++{ ++ int ret = 0; ++ u8 *frame; ++ u32 len = 0; ++ struct aicwf_bus *bus_if = dev_get_drvdata(sdiodev->dev); ++#if 0 ++ int align = 0; ++#endif ++ if (bus_if->state == BUS_DOWN_ST) { ++ sdio_dbg("tx bus is down!\n"); ++ return -EINVAL; ++ } ++ ++#if 0 ++ len = pkt->len; ++ len = (len + SDIOWIFI_FUNC_BLOCKSIZE - 1) / SDIOWIFI_FUNC_BLOCKSIZE * SDIOWIFI_FUNC_BLOCKSIZE; ++ ++ frame = (u8*)kmalloc(sizeof(u8) * len + align_param, GFP_ATOMIC); ++ align = ((unsigned long)(frame)) & (align_param - 1); ++ memcpy(frame + (align_param - align), (u8 *) (pkt->data), len); ++ ++ ret = aicwf_sdio_send_pkt(sdiodev, frame + (align_param - align), len); ++ if (ret) ++ sdio_err("aicwf_sdio_send_pkt fail%d\n", ret); ++ ++ kfree(frame); ++#endif ++#if 1 ++ frame = (u8 *)(pkt->data); ++ len = pkt->len; ++ len = (len + SDIOWIFI_FUNC_BLOCKSIZE - 1) / SDIOWIFI_FUNC_BLOCKSIZE * ++ SDIOWIFI_FUNC_BLOCKSIZE; ++ ++ ret = aicwf_sdio_send_pkt(sdiodev, pkt->data, len); ++ if (ret) ++ sdio_err("aicwf_sdio_send_pkt fail%d\n", ret); ++#endif ++ return ret; ++} ++ ++#ifdef CONFIG_SDIO_ADMA ++int aicwf_sdio_txscatterpkt(struct aicwf_tx_priv *tx_priv) ++{ ++ int ret = 0; ++ u8 *frame; ++ u32 len = 0; ++ struct aicwf_bus *bus_if = dev_get_drvdata(tx_priv->sdiodev->dev); ++ struct aic_sdio_dev *sdiodev = tx_priv->sdiodev; ++ int nents = tx_priv->aggr_segcnt; ++ int i = 0; ++ ++ if (bus_if->state == BUS_DOWN_ST) { ++ sdio_dbg("tx bus is down!\n"); ++ return -EINVAL; ++ } ++ ++ //AICWFDBG(LOGTRACE,"%s aggr_segcnt %d len %d \n",__func__,tx_priv->aggr_segcnt, tx_priv->len); ++ sdio_claim_host(sdiodev->func); ++ ret = sdio_write_sg(sdiodev->func, sdiodev->sdio_reg.wr_fifo_addr, ++ &(tx_priv->sg_list[0]), tx_priv->aggr_segcnt, ++ tx_priv->len); //&(tx_priv->sg_list[0]) ++ //sdio_writesb(sdiodev->func, sdiodev->sdio_reg.wr_fifo_addr, tx_priv->sg_list[0].buf, tx_priv->sg_list[0].len); ++ /*for(i=0;i<1;i++){ ++ sdio_writesb(sdiodev->func, sdiodev->sdio_reg.wr_fifo_addr, tx_priv->sg_list[i].buf, tx_priv->sg_list[i].len); ++ }*/ ++ sdio_release_host(sdiodev->func); ++ ++ return ret; ++} ++ ++void aicwf_adma_add(struct aicwf_tx_priv *tx_priv, struct sk_buff *pkt) ++{ ++ u8 adj_len = 0; ++ u8 *sdio_header = NULL; ++ u32 sdio_len = 0; ++ u32 curr_len = 0; ++ unsigned int align_len = 0; ++ u8 *start_ptr = NULL; ++ ++ adj_len = ALIGN4_ADJ_LEN((uint32_t)pkt->data); ++ start_ptr = skb_push(pkt, adj_len); //skb_push(pkt,adj_len) ++ //ASSERT((adj_len==0)||(adj_len==2)); // mgmt-pkt or data-pkt ++ //ASSERT((((uint32_t)start_ptr)&3) == 0); // start_ptr addr word align ++ if (!((adj_len == 0) || (adj_len == 2))) ++ AICWFDBG(LOGTRACE, "adj_len false %u \n", adj_len); ++ ++ if ((((uint32_t)start_ptr) & 3) != 0) ++ AICWFDBG(LOGTRACE, "start_ptr %x \n", ++ (((uint32_t)start_ptr) & 3)); ++ ++ //AICWFDBG(LOGTRACE,"start adj_len %d aggrcnt %d segcnt %d len %d \n",adj_len,atomic_read(&tx_priv->aggr_count),tx_priv->aggr_segcnt,tx_priv->len); ++ ++ if (adj_len == 0) { ++ sdio_len = pkt->len + SDIO_MGMT_FAKE_LEN; ++ if (sdio_len & (TX_ALIGNMENT - 1)) { ++ align_len = ++ TX_ALIGNMENT - (sdio_len & (TX_ALIGNMENT - 1)); ++ //#ifdef CONFIG_SDIO_ADMA_ADJ ++ //memset(pkt->data + sdio_len,0,align_len); ++ //#endif ++ //skb_put(pkt,align_len); ++ sdio_len += align_len; ++ } ++ ++ //AICWFDBG(LOGTRACE,"pkt_len %d \n",pkt->len); ++ start_ptr = ++ skb_push(pkt, (SDIO_HEADER_LEN + SDIO_MGMT_FAKE_LEN)); ++ //AICWFDBG(LOGTRACE,"push_pkt_len %d \n",pkt->len); ++ sdio_header = start_ptr; ++ ++ sdio_header[0] = ((sdio_len)&0xff); ++ sdio_header[1] = (((sdio_len) >> 8) & 0x0f); ++ sdio_header[2] = 0x01; //data ++ if (tx_priv->sdiodev->chipid == PRODUCT_ID_AIC8800D80) ++ sdio_header[3] = ++ crc8_ponl_107(&sdio_header[0], 3); // crc8 ++ else ++ sdio_header[3] = 0; //reserved ++ ++ // fill 4 byte 0x00, need to fasync with data-pkt. ++ sdio_header[4] = 0; ++ sdio_header[5] = 0; ++ sdio_header[6] = 0; ++ sdio_header[7] = 0; ++ ++ curr_len = sdio_len + SDIO_HEADER_LEN; ++ ++ tx_priv->sg_list[tx_priv->aggr_segcnt].buf = start_ptr; ++ tx_priv->sg_list[tx_priv->aggr_segcnt].len = curr_len; ++ tx_priv->free_buf[tx_priv->aggr_segcnt] = pkt; ++ ++ //AICWFDBG(LOGTRACE,"curr_len %d \n",curr_len); ++ //rwnx_data_dump("adj0",pkt->data,((pkt->len>32) ? 32 : pkt->len)); ++ ++ tx_priv->aggr_segcnt++; ++ atomic_inc(&tx_priv->aggr_count); ++ tx_priv->len += curr_len; ++ } else if (adj_len == 1) { ++ sdio_len = pkt->len + 3; ++ if (sdio_len & (TX_ALIGNMENT - 1)) { ++ align_len = ++ TX_ALIGNMENT - (sdio_len & (TX_ALIGNMENT - 1)); ++ //#ifdef CONFIG_SDIO_ADMA_ADJ ++ //memset(pkt->data + sdio_len,0,align_len); ++ //#endif ++ //skb_put(pkt,align_len); ++ sdio_len += align_len; ++ } ++ ++ sdio_tx_buf_dummy[tx_priv->aggr_segcnt][0] = ((sdio_len)&0xff); ++ sdio_tx_buf_dummy[tx_priv->aggr_segcnt][1] = ++ (((sdio_len) >> 8) & 0x0f); ++ sdio_tx_buf_dummy[tx_priv->aggr_segcnt][2] = 0x01; // data ++ sdio_tx_buf_dummy[tx_priv->aggr_segcnt][3] = 0; ++ sdio_tx_buf_dummy[tx_priv->aggr_segcnt][4] = 0; ++ sdio_tx_buf_dummy[tx_priv->aggr_segcnt][5] = 0; ++ sdio_tx_buf_dummy[tx_priv->aggr_segcnt][6] = 0; ++ ++ tx_priv->sg_list[tx_priv->aggr_segcnt].buf = ++ sdio_tx_buf_dummy[tx_priv->aggr_segcnt]; ++ tx_priv->sg_list[tx_priv->aggr_segcnt].len = ++ SDIO_HEADER_LEN + 3; ++ tx_priv->free_buf[tx_priv->aggr_segcnt] = NULL; ++ ++ tx_priv->aggr_segcnt++; ++ ++ sdio_header = start_ptr; ++ sdio_header[0] = 0; ++ ++ curr_len = sdio_len - 3; ++ ++ tx_priv->sg_list[tx_priv->aggr_segcnt].buf = start_ptr; ++ tx_priv->sg_list[tx_priv->aggr_segcnt].len = curr_len; ++ tx_priv->free_buf[tx_priv->aggr_segcnt] = pkt; ++ ++ //AICWFDBG(LOGTRACE,"curr_len %d \n",curr_len); ++ //rwnx_data_dump("adj1",start_ptr,((curr_len>32) ? 32 : curr_len)); ++ ++ tx_priv->aggr_segcnt++; ++ atomic_inc(&tx_priv->aggr_count); ++ ++ tx_priv->len += curr_len + SDIO_HEADER_LEN + 3; ++ ++ } else if (adj_len == 2) { // adj_len==2 ++ sdio_len = pkt->len + SDIO_DATA_FAKE_LEN; //adj_len + ++ if (sdio_len & (TX_ALIGNMENT - 1)) { ++ align_len = ++ TX_ALIGNMENT - (sdio_len & (TX_ALIGNMENT - 1)); ++ //#ifdef CONFIG_SDIO_ADMA_ADJ ++ //memset(pkt->data + sdio_len,0,align_len); ++ //#endif ++ //skb_put(pkt,align_len); ++ sdio_len += align_len; ++ } ++ ++ sdio_tx_buf_dummy[tx_priv->aggr_segcnt][0] = ((sdio_len)&0xff); ++ sdio_tx_buf_dummy[tx_priv->aggr_segcnt][1] = ++ (((sdio_len) >> 8) & 0x0f); ++ sdio_tx_buf_dummy[tx_priv->aggr_segcnt][2] = 0x01; // data ++ sdio_tx_buf_dummy[tx_priv->aggr_segcnt][3] = 0; ++ sdio_tx_buf_dummy[tx_priv->aggr_segcnt][4] = 0; ++ sdio_tx_buf_dummy[tx_priv->aggr_segcnt][5] = 0; ++ ++ tx_priv->sg_list[tx_priv->aggr_segcnt].buf = ++ sdio_tx_buf_dummy[tx_priv->aggr_segcnt]; ++ tx_priv->sg_list[tx_priv->aggr_segcnt].len = ++ SDIO_HEADER_LEN + SDIO_DATA_FAKE_LEN; ++ tx_priv->free_buf[tx_priv->aggr_segcnt] = NULL; ++ ++ tx_priv->aggr_segcnt++; ++ ++ sdio_header = start_ptr; ++ sdio_header[0] = 0; ++ sdio_header[1] = 0; ++ ++ curr_len = sdio_len - SDIO_DATA_FAKE_LEN; ++ ++ tx_priv->sg_list[tx_priv->aggr_segcnt].buf = start_ptr; ++ tx_priv->sg_list[tx_priv->aggr_segcnt].len = curr_len; ++ tx_priv->free_buf[tx_priv->aggr_segcnt] = pkt; ++ ++ //AICWFDBG(LOGTRACE,"curr_len %d \n",curr_len); ++ //rwnx_data_dump("adj2",start_ptr,((curr_len>32) ? 32 : curr_len)); ++ ++ tx_priv->aggr_segcnt++; ++ atomic_inc(&tx_priv->aggr_count); ++ ++ tx_priv->len += curr_len + SDIO_HEADER_LEN + SDIO_DATA_FAKE_LEN; ++ } else if (adj_len == 3) { ++ sdio_len = pkt->len + 1; ++ if (sdio_len & (TX_ALIGNMENT - 1)) { ++ align_len = ++ TX_ALIGNMENT - (sdio_len & (TX_ALIGNMENT - 1)); ++ //#ifdef CONFIG_SDIO_ADMA_ADJ ++ //memset(pkt->data + sdio_len,0,align_len); ++ //#endif ++ //skb_put(pkt,align_len); ++ sdio_len += align_len; ++ } ++ ++ sdio_tx_buf_dummy[tx_priv->aggr_segcnt][0] = ((sdio_len)&0xff); ++ sdio_tx_buf_dummy[tx_priv->aggr_segcnt][1] = ++ (((sdio_len) >> 8) & 0x0f); ++ sdio_tx_buf_dummy[tx_priv->aggr_segcnt][2] = 0x01; // data ++ sdio_tx_buf_dummy[tx_priv->aggr_segcnt][3] = 0; ++ sdio_tx_buf_dummy[tx_priv->aggr_segcnt][4] = 0; ++ ++ tx_priv->sg_list[tx_priv->aggr_segcnt].buf = ++ sdio_tx_buf_dummy[tx_priv->aggr_segcnt]; ++ tx_priv->sg_list[tx_priv->aggr_segcnt].len = ++ SDIO_HEADER_LEN + 1; ++ tx_priv->free_buf[tx_priv->aggr_segcnt] = NULL; ++ ++ tx_priv->aggr_segcnt++; ++ ++ sdio_header = start_ptr; ++ sdio_header[0] = 0; ++ sdio_header[1] = 0; ++ sdio_header[2] = 0; ++ ++ curr_len = sdio_len - 1; ++ ++ tx_priv->sg_list[tx_priv->aggr_segcnt].buf = start_ptr; ++ tx_priv->sg_list[tx_priv->aggr_segcnt].len = curr_len; ++ tx_priv->free_buf[tx_priv->aggr_segcnt] = pkt; ++ ++ //AICWFDBG(LOGTRACE,"curr_len %d \n",curr_len); ++ //rwnx_data_dump("adj3",start_ptr,((curr_len>32) ? 32 : curr_len)); ++ ++ tx_priv->aggr_segcnt++; ++ atomic_inc(&tx_priv->aggr_count); ++ ++ tx_priv->len += curr_len + SDIO_HEADER_LEN + 1; ++ } ++ ++ //AICWFDBG(LOGTRACE,"end aggrcnt %d segcnt %d len %d \n",atomic_read(&tx_priv->aggr_count),tx_priv->aggr_segcnt,tx_priv->len); ++} ++ ++#endif ++ ++static int aicwf_sdio_intr_get_len_bytemode(struct aic_sdio_dev *sdiodev, ++ u8 *byte_len) ++{ ++ int ret = 0; ++ ++ if (!byte_len) ++ return -EBADE; ++ ++ if (sdiodev->bus_if->state == BUS_DOWN_ST) { ++ *byte_len = 0; ++ } else { ++ ret = aicwf_sdio_readb( ++ sdiodev, sdiodev->sdio_reg.bytemode_len_reg, byte_len); ++ sdiodev->rx_priv->data_len = (*byte_len) * 4; ++ } ++ ++ return ret; ++} ++ ++static void aicwf_sdio_bus_stop(struct device *dev) ++{ ++ struct aicwf_bus *bus_if = dev_get_drvdata(dev); ++ struct aic_sdio_dev *sdiodev = bus_if->bus_priv.sdio; ++ int ret = 0; ++ ++#if defined(CONFIG_SDIO_PWRCTRL) ++ aicwf_sdio_pwrctl_timer(sdiodev, 0); ++#endif ++ AICWFDBG(LOGINFO, "%s Enter\n", __func__); ++ ++ bus_if->state = BUS_DOWN_ST; ++ if (sdiodev->tx_priv) { ++ ret = down_interruptible(&sdiodev->tx_priv->txctl_sema); ++ if (ret) ++ AICWFDBG(LOGERROR, "down txctl_sema fail\n"); ++ } ++ ++#if defined(CONFIG_SDIO_PWRCTRL) ++ aicwf_sdio_pwr_stctl(sdiodev, SDIO_SLEEP_ST); ++#endif ++ ++ if (sdiodev->tx_priv) { ++ if (!ret) ++ up(&sdiodev->tx_priv->txctl_sema); ++ aicwf_frame_queue_flush(&sdiodev->tx_priv->txq); ++ } ++ AICWFDBG(LOGINFO, "%s Exit \n", __func__); ++} ++ ++#ifdef CONFIG_PREALLOC_RX_SKB ++struct rx_buff *aicwf_sdio_readframes(struct aic_sdio_dev *sdiodev) ++{ ++ int ret = 0; ++ u32 size = 0; ++ struct aicwf_bus *bus_if = dev_get_drvdata(sdiodev->dev); ++ struct rx_buff *rxbuff; ++ ++ if (bus_if->state == BUS_DOWN_ST) { ++ sdio_dbg("bus down\n"); ++ return NULL; ++ } ++ ++ size = sdiodev->rx_priv->data_len; ++ rxbuff = aicwf_prealloc_rxbuff_alloc(&sdiodev->rx_priv->rxbuff_lock); ++ if (rxbuff == NULL) { ++ printk("failed to alloc rxbuff\n"); ++ return NULL; ++ } ++ rxbuff->len = 0; ++ rxbuff->start = rxbuff->data; ++ rxbuff->read = rxbuff->start; ++ rxbuff->end = rxbuff->data + size; ++ ++ ret = aicwf_sdio_recv_pkt(sdiodev, rxbuff, size); ++ if (ret) { ++ printk("%s %d, sdio recv pkt fail\n", __func__, __LINE__); ++ aicwf_prealloc_rxbuff_free(rxbuff, ++ &sdiodev->rx_priv->rxbuff_lock); ++ return NULL; ++ } ++ ++ return rxbuff; ++} ++#else ++struct sk_buff *aicwf_sdio_readframes(struct aic_sdio_dev *sdiodev) ++{ ++ int ret = 0; ++ u32 size = 0; ++ struct sk_buff *skb = NULL; ++ struct aicwf_bus *bus_if = dev_get_drvdata(sdiodev->dev); ++ ++ if (bus_if->state == BUS_DOWN_ST) { ++ sdio_dbg("bus down\n"); ++ return NULL; ++ } ++ ++ size = sdiodev->rx_priv->data_len; ++ skb = __dev_alloc_skb(size, GFP_KERNEL); ++ if (!skb) { ++ return NULL; ++ } ++ ++ ret = aicwf_sdio_recv_pkt(sdiodev, skb, size); ++ if (ret) { ++ dev_kfree_skb(skb); ++ skb = NULL; ++ } ++ ++ return skb; ++} ++#endif ++ ++static int aicwf_sdio_tx_msg(struct aic_sdio_dev *sdiodev) ++{ ++ int err = 0; ++ u16 len; ++ u8 *payload = sdiodev->tx_priv->cmd_buf; ++ u16 payload_len = sdiodev->tx_priv->cmd_len; ++ u8 adjust_str[4] = { 0, 0, 0, 0 }; ++ int adjust_len = 0; ++ int buffer_cnt = 0; ++ u8 retry = 0; ++ ++ len = payload_len; ++ if ((len % TX_ALIGNMENT) != 0) { ++ adjust_len = roundup(len, TX_ALIGNMENT); ++ memcpy(payload + payload_len, adjust_str, (adjust_len - len)); ++ payload_len += (adjust_len - len); ++ } ++ len = payload_len; ++ ++ //link tail is necessary ++ if ((len % SDIOWIFI_FUNC_BLOCKSIZE) != 0) { ++ memset(payload + payload_len, 0, TAIL_LEN); ++ payload_len += TAIL_LEN; ++ len = (payload_len / SDIOWIFI_FUNC_BLOCKSIZE + 1) * ++ SDIOWIFI_FUNC_BLOCKSIZE; ++ } else ++ len = payload_len; ++ ++ if (sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ buffer_cnt = aicwf_sdio_flow_ctrl_msg(sdiodev); ++ while ((buffer_cnt <= 0 || ++ (buffer_cnt > 0 && len > (buffer_cnt * BUFFER_SIZE))) && ++ retry < 10) { ++ retry++; ++ buffer_cnt = aicwf_sdio_flow_ctrl_msg(sdiodev); ++ printk("buffer_cnt = %d\n", buffer_cnt); ++ } ++ } ++ down(&sdiodev->tx_priv->cmd_txsema); ++ ++ if (sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ if (buffer_cnt > 0 && len < (buffer_cnt * BUFFER_SIZE)) { ++ err = aicwf_sdio_send_pkt(sdiodev, payload, len); ++ if (err) { ++ sdio_err("aicwf_sdio_send_pkt fail%d\n", err); ++ } ++ } else { ++ sdio_err("tx msg fc retry fail:%d, %d\n", buffer_cnt, ++ len); ++ up(&sdiodev->tx_priv->cmd_txsema); ++ return -1; ++ } ++ } else if (sdiodev->chipid == PRODUCT_ID_AIC8800DC) { ++ err = aicwf_sdio_send_pkt(sdiodev, payload, len); ++ if (err) { ++ sdio_err("aicwf_sdio_send_pkt fail%d\n", err); ++ } ++ } else { ++ sdio_err("tx msg fc retry fail:%d, %d\n", buffer_cnt, len); ++ up(&sdiodev->tx_priv->cmd_txsema); ++ return -1; ++ } ++ ++ sdiodev->tx_priv->cmd_txstate = false; ++ if (!err) ++ sdiodev->tx_priv->cmd_tx_succ = true; ++ else ++ sdiodev->tx_priv->cmd_tx_succ = false; ++ ++ up(&sdiodev->tx_priv->cmd_txsema); ++ ++ return err; ++} ++ ++static void aicwf_sdio_tx_process(struct aic_sdio_dev *sdiodev) ++{ ++ int err = 0; ++#ifdef CONFIG_TX_NETIF_FLOWCTRL ++ unsigned long flags; ++#endif ++ ++ if (sdiodev->bus_if->state == BUS_DOWN_ST) { ++ sdio_err("Bus is down\n"); ++ return; ++ } ++ ++#if defined(CONFIG_SDIO_PWRCTRL) ++ aicwf_sdio_pwr_stctl(sdiodev, SDIO_ACTIVE_ST); ++#endif ++ ++ //config ++ sdio_info("send cmd\n"); ++ if (sdiodev->tx_priv->cmd_txstate) { ++ if (down_interruptible(&sdiodev->tx_priv->txctl_sema)) { ++ txrx_err("txctl down bus->txctl_sema fail\n"); ++ return; ++ } ++ if (sdiodev->state != SDIO_ACTIVE_ST) { ++ txrx_err("state err\n"); ++ up(&sdiodev->tx_priv->txctl_sema); ++ txrx_err("txctl up bus->txctl_sema fail\n"); ++ return; ++ } ++ err = aicwf_sdio_tx_msg(sdiodev); ++ up(&sdiodev->tx_priv->txctl_sema); ++ if (waitqueue_active(&sdiodev->tx_priv->cmd_txdone_wait)) ++ wake_up(&sdiodev->tx_priv->cmd_txdone_wait); ++ } ++ ++ //data ++ sdio_info("send data\n"); ++ if (down_interruptible(&sdiodev->tx_priv->txctl_sema)) { ++ txrx_err("txdata down bus->txctl_sema\n"); ++ return; ++ } ++ ++ if (sdiodev->state != SDIO_ACTIVE_ST) { ++ txrx_err("sdio state err\n"); ++ up(&sdiodev->tx_priv->txctl_sema); ++ return; ++ } ++ ++ if (!aicwf_is_framequeue_empty(&sdiodev->tx_priv->txq)) { ++ sdiodev->tx_priv->fw_avail_bufcnt = ++ aicwf_sdio_flow_ctrl(sdiodev); ++ } ++ while (!aicwf_is_framequeue_empty(&sdiodev->tx_priv->txq)) { ++ if (sdiodev->bus_if->state == BUS_DOWN_ST) { ++ break; ++ } ++#ifdef CONFIG_TEMP_CONTROL ++ if (sdiodev->on_off) ++ aicwf_temp_ctrl(sdiodev); ++#endif ++ ++ 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); ++ } ++ } ++ } ++ ++#ifdef CONFIG_TX_NETIF_FLOWCTRL ++ spin_lock_irqsave(&sdiodev->tx_flow_lock, flags); ++ if (atomic_read(&sdiodev->tx_priv->tx_pktcnt) < tx_fc_low_water) { ++ //printk("sdiodev->tx_priv->tx_pktcnt < tx_fc_low_water:%d %d\r\n", ++ // atomic_read(&sdiodev->tx_priv->tx_pktcnt), tx_fc_low_water); ++ if (sdiodev->flowctrl) { ++ sdiodev->flowctrl = 0; ++ aicwf_sdio_tx_netif_flowctrl(sdiodev->rwnx_hw, false); ++ } ++ } ++ spin_unlock_irqrestore(&sdiodev->tx_flow_lock, flags); ++#endif ++ ++ up(&sdiodev->tx_priv->txctl_sema); ++} ++ ++static int aicwf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt) ++{ ++ uint prio; ++ int ret = -EBADE; ++ struct rwnx_txhdr *txhdr = NULL; ++ int headroom = 0; ++ struct aicwf_bus *bus_if = dev_get_drvdata(dev); ++ struct aic_sdio_dev *sdiodev = bus_if->bus_priv.sdio; ++#ifdef CONFIG_TX_NETIF_FLOWCTRL ++ unsigned long flags; ++#endif ++ ++ if (bus_if->state == BUS_DOWN_ST) { ++ sdio_err("bus_if stopped\n"); ++ txhdr = (struct rwnx_txhdr *)pkt->data; ++ 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); ++ return -1; ++ } ++ ++ prio = (pkt->priority & 0x7); ++ spin_lock_bh(&sdiodev->tx_priv->txqlock); ++ if (!aicwf_frame_enq(sdiodev->dev, &sdiodev->tx_priv->txq, pkt, prio)) { ++ txhdr = (struct rwnx_txhdr *)pkt->data; ++ 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; ++ goto flowctrl; ++ } else { ++ ret = 0; ++ } ++ ++ atomic_inc(&sdiodev->tx_priv->tx_pktcnt); ++ spin_unlock_bh(&sdiodev->tx_priv->txqlock); ++ complete(&bus_if->bustx_trgg); ++ ++flowctrl: ++#ifdef CONFIG_TX_NETIF_FLOWCTRL ++ spin_lock_irqsave(&sdiodev->tx_flow_lock, flags); ++ if (atomic_read(&sdiodev->tx_priv->tx_pktcnt) >= tx_fc_high_water) { ++ //printk("sdiodev->tx_priv->tx_pktcnt >= tx_fc_high_water:%d %d\r\n", ++ // atomic_read(&sdiodev->tx_priv->tx_pktcnt), tx_fc_high_water); ++ if (!sdiodev->flowctrl) { ++ sdiodev->flowctrl = 1; ++ aicwf_sdio_tx_netif_flowctrl(sdiodev->rwnx_hw, true); ++ } ++ } ++ spin_unlock_irqrestore(&sdiodev->tx_flow_lock, flags); ++#endif ++ ++ return ret; ++} ++ ++static int aicwf_sdio_bus_txmsg(struct device *dev, u8 *msg, uint msglen) ++{ ++ struct aicwf_bus *bus_if = dev_get_drvdata(dev); ++ struct aic_sdio_dev *sdiodev = bus_if->bus_priv.sdio; ++ ++ down(&sdiodev->tx_priv->cmd_txsema); ++ sdiodev->tx_priv->cmd_txstate = true; ++ sdiodev->tx_priv->cmd_tx_succ = false; ++ sdiodev->tx_priv->cmd_buf = msg; ++ sdiodev->tx_priv->cmd_len = msglen; ++ up(&sdiodev->tx_priv->cmd_txsema); ++ ++ if (bus_if->state != BUS_UP_ST) { ++ sdio_err("bus has stop\n"); ++ return -1; ++ } ++ ++ complete(&bus_if->bustx_trgg); ++#if 0 ++ 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, \ ++ !(sdiodev->tx_priv->cmd_txstate), timeout); ++ } ++ ++ if (!sdiodev->tx_priv->cmd_txstate && sdiodev->tx_priv->cmd_tx_succ) { ++ ret = 0; ++ } else { ++ sdio_err("send faild:%d, %d,%x\n", sdiodev->tx_priv->cmd_txstate, sdiodev->tx_priv->cmd_tx_succ, ret); ++ ret = -EIO; ++ } ++#endif ++ return 0; ++} ++ ++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; ++#ifdef CONFIG_TX_NETIF_FLOWCTRL ++ unsigned long flags; ++#endif ++ ++#ifdef CONFIG_SDIO_ADMA ++ aggr_len = tx_priv->len; ++#else ++ aggr_len = (tx_priv->tail - tx_priv->head); ++#endif ++ ++ if (((atomic_read(&tx_priv->aggr_count) == 0) && (aggr_len != 0)) || ++ ((atomic_read(&tx_priv->aggr_count) != 0) && (aggr_len == 0))) { ++ if (aggr_len > 0) { ++#ifdef CONFIG_SDIO_ADMA ++ printk("len %d seg_cnt %d aggr_cnt %d avail_cnt %d \n", ++ aggr_len, tx_priv->aggr_segcnt, ++ atomic_read(&tx_priv->aggr_count), ++ tx_priv->fw_avail_bufcnt); ++#endif ++ aicwf_sdio_aggrbuf_reset(tx_priv); ++#ifdef CONFIG_SDIO_ADMA ++ printk("set len %d seg_cnt %d aggr_cnt %d avail_cnt %d \n", ++ aggr_len, tx_priv->aggr_segcnt, ++ atomic_read(&tx_priv->aggr_count), ++ tx_priv->fw_avail_bufcnt); ++#endif ++ } ++ ++ return 0; ++ } ++ ++ 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; ++ } ++ return 0; ++ } else { ++ spin_lock_bh(&sdiodev->tx_priv->txqlock); ++ pkt = aicwf_frame_dequeue(&sdiodev->tx_priv->txq); ++ if (pkt == NULL) { ++ sdio_err("txq no pkt\n"); ++ spin_unlock_bh(&sdiodev->tx_priv->txqlock); ++ return 0; ++ } ++ //atomic_dec(&sdiodev->tx_priv->tx_pktcnt); ++ spin_unlock_bh(&sdiodev->tx_priv->txqlock); ++ ++#ifdef CONFIG_TX_NETIF_FLOWCTRL ++ spin_lock_irqsave(&sdiodev->tx_flow_lock, flags); ++ if (atomic_read(&sdiodev->tx_priv->tx_pktcnt) < ++ tx_fc_low_water) { ++ //printk("sdiodev->tx_priv->tx_pktcnt < tx_fc_low_water:%d %d\r\n", ++ // atomic_read(&sdiodev->tx_priv->tx_pktcnt), tx_fc_low_water); ++ if (sdiodev->flowctrl) { ++ sdiodev->flowctrl = 0; ++ aicwf_sdio_tx_netif_flowctrl(sdiodev->rwnx_hw, ++ false); ++ } ++ } ++ spin_unlock_irqrestore(&sdiodev->tx_flow_lock, flags); ++#endif ++ ++#ifndef CONFIG_SDIO_ADMA ++ if (tx_priv == NULL || tx_priv->tail == NULL || pkt == NULL) ++ txrx_err("null error\n"); ++#endif ++ if (aicwf_sdio_aggr(tx_priv, pkt)) { ++ aicwf_sdio_aggrbuf_reset(tx_priv); ++ sdio_err("add aggr pkts failed!\n"); ++ atomic_dec(&sdiodev->tx_priv->tx_pktcnt); ++ return 0; ++ } ++ ++ //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) == 1 || ++ 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); ++ atomic_dec(&sdiodev->tx_priv->tx_pktcnt); ++ return 0; ++ } else { ++ atomic_dec(&sdiodev->tx_priv->tx_pktcnt); ++ return 0; ++ } ++ } ++} ++ ++int aicwf_sdio_aggr(struct aicwf_tx_priv *tx_priv, struct sk_buff *pkt) ++{ ++#ifdef CONFIG_SDIO_ADMA ++ u8 adj_len = 0; ++ struct rwnx_txhdr *txhdr = (struct rwnx_txhdr *)pkt->data; ++ u8 *sdio_header = NULL; ++ u32 sdio_len = 0; ++ u32 curr_len = 0; ++ int align_len = 0; ++ int headroom; ++ u32 pkt_len = 0; ++ struct txdesc_api tmp_txdesc; ++ struct sk_buff *tmp_skb; ++ ++ //AICWFDBG(LOGTRACE,"%s \n",__func__); ++ //pkt (txhdr + data),aggr only need txhdr->sw_hdr->desc and data ++ memcpy(&tmp_txdesc, (u8 *)(long)&txhdr->sw_hdr->desc, ++ sizeof(struct txdesc_api)); ++ ++ if (txhdr->sw_hdr->need_cfm) { ++ tmp_skb = skb_copy( ++ pkt, ++ GFP_ATOMIC); //save pkt when cfm get,then release,send skb is copy ++ if (!tmp_skb) { ++ AICWFDBG(LOGERROR, "skb copy fail"); ++ return -ENOMEM; ++ } ++ //AICWFDBG(LOGTRACE,"tmp_len %d pkt_len %d \n",tmp_skb->len,pkt->len); ++ ++ skb_pull(tmp_skb, txhdr->sw_hdr->headroom); ++ ++ //AICWFDBG(LOGTRACE,"pull_tmp_len %d \n",tmp_skb->len); ++ ++ skb_push(tmp_skb, ++ sizeof(struct txdesc_api)); //skb header is enough ++ ++ //AICWFDBG(LOGTRACE,"push_tmp_len %d \n",tmp_skb->len); ++ ++ memcpy(tmp_skb->data, (u8 *)(long)&tmp_txdesc, ++ sizeof(struct txdesc_api)); ++ AICWFDBG(LOGTRACE, "need cfm len %d \n", tmp_skb->len); ++ ++ //printk("cfm alloc %p \n",tmp_skb); ++ //printk("delay free %p \n",pkt); ++ aicwf_adma_add(tx_priv, tmp_skb); ++ tx_priv->copyd[tx_priv->aggr_segcnt - 1] = true; ++ } else { ++ 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); ++ ++ //AICWFDBG(LOGTRACE,"pull_pkt_len %d \n",pkt->len); ++ ++ skb_push(pkt, sizeof(struct txdesc_api)); //skb header is enough ++ ++ //AICWFDBG(LOGTRACE,"push_pkt_len %d \n",pkt->len); ++ ++ memcpy(pkt->data, (u8 *)(long)&tmp_txdesc, ++ sizeof(struct txdesc_api)); ++ ++ //rwnx_data_dump("data",pkt->data,((pkt->len>64) ? 64 : pkt->len)); ++ ++ //printk("alloc %p \n",pkt); ++ ++ aicwf_adma_add(tx_priv, pkt); ++ tx_priv->copyd[tx_priv->aggr_segcnt - 1] = false; ++ } ++ ++#else ++ ++ struct rwnx_txhdr *txhdr = (struct rwnx_txhdr *)pkt->data; ++ u8 *start_ptr = tx_priv->tail; ++ u8 sdio_header[4]; ++ u8 adjust_str[4] = { 0, 0, 0, 0 }; ++ u32 curr_len = 0; ++ int allign_len = 0; ++ int headroom; ++ ++ sdio_header[0] = ((pkt->len - txhdr->sw_hdr->headroom + ++ sizeof(struct txdesc_api)) & ++ 0xff); ++ sdio_header[1] = (((pkt->len - txhdr->sw_hdr->headroom + ++ sizeof(struct txdesc_api)) >> ++ 8) & ++ 0x0f); ++ sdio_header[2] = 0x01; //data ++ if (tx_priv->sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ tx_priv->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ tx_priv->sdiodev->chipid == PRODUCT_ID_AIC8800DW) ++ sdio_header[3] = 0; //reserved ++ else if (tx_priv->sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ tx_priv->sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) ++ sdio_header[3] = crc8_ponl_107(&sdio_header[0], 3); // crc8 ++ ++ memcpy(tx_priv->tail, (u8 *)&sdio_header, sizeof(sdio_header)); ++ tx_priv->tail += sizeof(sdio_header); ++ //payload ++ memcpy(tx_priv->tail, (u8 *)(long)&txhdr->sw_hdr->desc, ++ sizeof(struct txdesc_api)); ++ tx_priv->tail += sizeof(struct txdesc_api); //hostdesc ++ memcpy(tx_priv->tail, (u8 *)((u8 *)txhdr + txhdr->sw_hdr->headroom), ++ pkt->len - txhdr->sw_hdr->headroom); ++ tx_priv->tail += (pkt->len - txhdr->sw_hdr->headroom); ++ ++ //word alignment ++ curr_len = tx_priv->tail - tx_priv->head; ++ if (curr_len & (TX_ALIGNMENT - 1)) { ++ allign_len = roundup(curr_len, TX_ALIGNMENT) - curr_len; ++ memcpy(tx_priv->tail, adjust_str, allign_len); ++ tx_priv->tail += allign_len; ++ } ++ ++ if (tx_priv->sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ tx_priv->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ tx_priv->sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ start_ptr[0] = ((tx_priv->tail - start_ptr - 4) & 0xff); ++ start_ptr[1] = (((tx_priv->tail - start_ptr - 4) >> 8) & 0x0f); ++ } ++ tx_priv->aggr_buf->dev = pkt->dev; ++ ++ if (!txhdr->sw_hdr->need_cfm) { ++ 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); ++ } ++ ++ atomic_inc(&tx_priv->aggr_count); ++#endif /* CONFIG_SDIO_ADMA */ ++ ++ return 0; ++} ++ ++void aicwf_sdio_aggr_send(struct aicwf_tx_priv *tx_priv) ++{ ++#ifdef CONFIG_SDIO_ADMA ++ int ret = 0; ++ int i = 0; ++ int nents = tx_priv->aggr_segcnt; ++ //struct sk_buff *scatter_buf; ++ ++ if (tx_priv->len & (TXPKT_BLOCKSIZE - 1)) { ++ uint16_t alen = TXPKT_BLOCKSIZE - ++ (tx_priv->len & (TXPKT_BLOCKSIZE - 1)); ++ ++ memset(sdio_tx_buf_fill, 0, 32); ++ tx_priv->sg_list[tx_priv->aggr_segcnt].buf = sdio_tx_buf_fill; ++ tx_priv->sg_list[tx_priv->aggr_segcnt].len = alen; ++ tx_priv->free_buf[tx_priv->aggr_segcnt] = NULL; ++ tx_priv->aggr_segcnt += 1; ++ tx_priv->len += alen; ++ } ++ ++ //AICWFDBG(LOGTRACE,"nents %d \n",tx_priv->aggr_segcnt); ++ /*for(i=0;iaggr_segcnt;i++){ ++ if(tx_priv->sg_list[i].buf != NULL){ ++ rwnx_data_dump("send",tx_priv->sg_list[i].buf,((tx_priv->sg_list[i].len>64) ? 64 : tx_priv->sg_list[i].len)); ++ } ++ }*/ ++ ++ ret = aicwf_sdio_txscatterpkt(tx_priv); ++ if (ret < 0) { ++ sdio_err("fail to send scatter pkt %d !\n", ret); ++ } ++ ++#else ++ ++ struct sk_buff *tx_buf = tx_priv->aggr_buf; ++ int ret = 0; ++ int curr_len = 0; ++ ++ //link tail is necessary ++ curr_len = tx_priv->tail - tx_priv->head; ++ if ((curr_len % TXPKT_BLOCKSIZE) != 0) { ++ memset(tx_priv->tail, 0, TAIL_LEN); ++ tx_priv->tail += TAIL_LEN; ++ } ++ ++ tx_buf->len = tx_priv->tail - tx_priv->head; ++ ret = aicwf_sdio_txpkt(tx_priv->sdiodev, tx_buf); ++ if (ret < 0) { ++ sdio_err("fail to send aggr pkt!\n"); ++ } ++#endif /* CONFIG_SDIO_ADMA */ ++ ++ aicwf_sdio_aggrbuf_reset(tx_priv); ++} ++ ++void aicwf_sdio_aggrbuf_reset(struct aicwf_tx_priv *tx_priv) ++{ ++#ifdef CONFIG_SDIO_ADMA ++ struct sk_buff *scatter_buf; ++ int i = 0; ++ int nents = tx_priv->aggr_segcnt; ++ ++ for (i = 0; i < nents; i++) { ++ scatter_buf = (struct sk_buff *)tx_priv->free_buf[i]; ++ if (scatter_buf != NULL) { ++ //printk("free %p \n",scatter_buf); ++ if (tx_priv->copyd[i]) { ++ kfree_skb(scatter_buf); ++ tx_priv->copyd[i] = false; ++ } else ++ consume_skb(scatter_buf); ++ } ++ } ++ ++ tx_priv->len = 0; ++ tx_priv->aggr_segcnt = 0; ++ atomic_set(&tx_priv->aggr_count, 0); ++ AICWFDBG(LOGTRACE, "reset len %d seg_cnt %d aggr_cnt %d \n", ++ tx_priv->len, tx_priv->aggr_segcnt, ++ atomic_read(&tx_priv->aggr_count)); ++#else ++ ++ struct sk_buff *aggr_buf = tx_priv->aggr_buf; ++ ++ tx_priv->tail = tx_priv->head; ++ aggr_buf->len = 0; ++ atomic_set(&tx_priv->aggr_count, 0); ++#endif /* CONFIG_SDIO_ADMA */ ++} ++ ++extern void set_irq_handler(void *fn); ++ ++static int aicwf_sdio_bus_start(struct device *dev) ++{ ++ struct aicwf_bus *bus_if = dev_get_drvdata(dev); ++ struct aic_sdio_dev *sdiodev = bus_if->bus_priv.sdio; ++ int ret = 0; ++ ++ sdio_claim_host(sdiodev->func); ++#ifndef CONFIG_FDRV_NO_REG_SDIO ++ sdio_claim_irq(sdiodev->func, aicwf_sdio_hal_irqhandler); ++#else ++ set_irq_handler(aicwf_sdio_hal_irqhandler); ++#endif ++ if (sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ sdio_f0_writeb(sdiodev->func, 0x07, 0x04, &ret); ++ if (ret) { ++ sdio_err("set func0 int en fail %d\n", ret); ++ } ++ } ++ sdio_release_host(sdiodev->func); ++ ++ //enable sdio interrupt ++ ret = aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.intr_config_reg, ++ 0x07); ++ if (ret != 0) ++ sdio_err("intr register failed:%d\n", ret); ++ ++ bus_if->state = BUS_UP_ST; ++ ++ return ret; ++} ++ ++#ifdef CONFIG_TXRX_THREAD_PRIO ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)) ++#include "uapi/linux/sched/types.h" ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) ++#include "linux/sched/types.h" ++#else ++#include "linux/sched/rt.h" ++#endif ++ ++int bustx_thread_prio = 1; ++module_param_named(bustx_thread_prio, bustx_thread_prio, int, 0644); ++//module_param(bustx_thread_prio, int, 0); ++int busrx_thread_prio = 1; ++module_param_named(busrx_thread_prio, busrx_thread_prio, int, 0644); ++//module_param(busrx_thread_prio, int, 0); ++#endif ++ ++static inline void aic_thread_wait_stop(void) ++{ ++#if 1 // PLATFORM_LINUX ++#if 0 ++ while (!kthread_should_stop()){ ++ AICWFDBG(LOGINFO, "%s waiting for thread_stop notify \r\n", __func__); ++ msleep(100); ++ } ++#else ++ set_current_state(TASK_INTERRUPTIBLE); ++ while (!kthread_should_stop()) { ++ AICWFDBG(LOGINFO, "%s waiting for thread_stop notify \r\n", ++ __func__); ++ schedule(); ++ set_current_state(TASK_INTERRUPTIBLE); ++ } ++ __set_current_state(TASK_RUNNING); ++#endif ++#endif ++} ++ ++#ifdef CONFIG_OOB ++int rx_thread_wait_to = 1000; ++module_param_named(rx_thread_wait_to, rx_thread_wait_to, int, 0644); ++ ++//new oob feature ++int sdio_busirq_thread(void *data) ++{ ++ struct aicwf_rx_priv *rx_priv = (struct aicwf_rx_priv *)data; ++ struct aicwf_bus *bus_if = rx_priv->sdiodev->bus_if; ++#if 0 ++#ifdef CONFIG_THREAD_INFO_IN_TASK ++ int set_cpu_ret = 0; ++ ++ AICWFDBG(LOGINFO, "%s the cpu is:%d\n", __func__, current->cpu); ++ set_cpu_ret = set_cpus_allowed_ptr(current, cpumask_of(0)); ++ AICWFDBG(LOGINFO, "%s set_cpu_ret is:%d\n", __func__, set_cpu_ret); ++ AICWFDBG(LOGINFO, "%s change cpu to:%d\n", __func__, current->cpu); ++#endif ++#endif ++ ++#ifdef CONFIG_TXRX_THREAD_PRIO ++ if (busrx_thread_prio > 0) { ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)) ++ sched_set_fifo_low(current); ++#else ++ struct sched_param param; ++ param.sched_priority = (busrx_thread_prio - 1 < MAX_RT_PRIO) ? ++ busrx_thread_prio : ++ (MAX_RT_PRIO - 1); ++ sched_setscheduler(current, SCHED_FIFO, ¶m); ++#endif ++ } ++#endif ++ ++ AICWFDBG(LOGINFO, "%s the policy of current thread is:%d\n", __func__, ++ current->policy); ++ AICWFDBG(LOGINFO, "%s the rt_priority of current thread is:%d\n", ++ __func__, current->rt_priority); ++ AICWFDBG(LOGINFO, "%s the current pid is:%d\n", __func__, current->pid); ++ ++ while (1) { ++#if 0 ++ if (kthread_should_stop()) { ++ AICWFDBG(LOGERROR, "sdio busirq thread stop\n"); ++ break; ++ } ++#endif ++ if (!wait_for_completion_timeout( ++ &bus_if->busirq_trgg, ++ msecs_to_jiffies(rx_thread_wait_to))) { ++ AICWFDBG(LOGRXPOLL, ++ "%s wait for completion timout \r\n", ++ __func__); ++ } ++ ++ if (bus_if->state == BUS_DOWN_ST) { ++ AICWFDBG(LOGERROR, "%s bus down thread exit \r\n", ++ __func__); ++ break; ++ } ++ //continue; ++#if 1 ++#ifdef CONFIG_SDIO_PWRCTRL ++ while (atomic_read(&bus_if->bus_priv.sdio->is_bus_suspend) == ++ 1) { ++ AICWFDBG(LOGDEBUG, ++ "%s waiting for sdio bus resume \r\n", ++ __func__); ++ msleep(100); ++ } ++ aicwf_sdio_pwr_stctl(bus_if->bus_priv.sdio, SDIO_ACTIVE_ST); ++#endif //CONFIG_SDIO_PWRCTRL ++#endif ++ aicwf_sdio_hal_irqhandler(bus_if->bus_priv.sdio->func); ++ } ++ ++ aic_thread_wait_stop(); ++ ++ return 0; ++} ++ ++#endif //CONFIG_OOB ++ ++#if 0 ++#include ++#endif ++int sdio_bustx_thread(void *data) ++{ ++ struct aicwf_bus *bus = (struct aicwf_bus *)data; ++ struct aic_sdio_dev *sdiodev = bus->bus_priv.sdio; ++#if 0 ++#ifdef CONFIG_THREAD_INFO_IN_TASK ++ int set_cpu_ret = 0; ++ ++ AICWFDBG(LOGINFO, "%s the cpu is:%d\n", __func__, current->cpu); ++ set_cpu_ret = set_cpus_allowed_ptr(current, cpumask_of(1)); ++ AICWFDBG(LOGINFO, "%s set_cpu_ret is:%d\n", __func__, set_cpu_ret); ++ AICWFDBG(LOGINFO, "%s change cpu to:%d\n", __func__, current->cpu); ++#endif ++#endif ++ ++#if 0 ++ struct cpumask cpumask; ++ cpumask_clear(&cpumask); ++ cpumask_set_cpu(1, &cpumask); ++ cpumask_set_cpu(2, &cpumask); ++ cpumask_set_cpu(3, &cpumask); ++ sched_setaffinity(0, &cpumask);//need to add EXPORT_SYMBOL_GPL(sched_setaffinity) in kernel/sched/core.c ++#endif ++#ifdef CONFIG_TXRX_THREAD_PRIO ++ if (bustx_thread_prio > 0) { ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)) ++ sched_set_fifo_low(current); ++#else ++ struct sched_param param; ++ param.sched_priority = (bustx_thread_prio < MAX_RT_PRIO) ? ++ bustx_thread_prio : ++ (MAX_RT_PRIO - 1); ++ sched_setscheduler(current, SCHED_FIFO, ¶m); ++#endif ++ } ++#endif ++ ++ AICWFDBG(LOGINFO, "%s the policy of current thread is:%d\n", __func__, ++ current->policy); ++ AICWFDBG(LOGINFO, "%s the rt_priority of current thread is:%d\n", ++ __func__, current->rt_priority); ++ AICWFDBG(LOGINFO, "%s the current pid is:%d\n", __func__, current->pid); ++ ++ while (1) { ++#if 0 ++ if (kthread_should_stop()) { ++ AICWFDBG(LOGERROR, "sdio bustx thread stop\n"); ++ break; ++ } ++#endif ++ if (!wait_for_completion_interruptible(&bus->bustx_trgg)) { ++ if (sdiodev->bus_if->state == BUS_DOWN_ST) ++ break; ++ //continue; ++ ++ rwnx_wakeup_lock(sdiodev->rwnx_hw->ws_tx); ++ if ((int)(atomic_read(&sdiodev->tx_priv->tx_pktcnt) > ++ 0) || ++ (sdiodev->tx_priv->cmd_txstate == true)) { ++ aicwf_sdio_tx_process(sdiodev); ++ } ++ rwnx_wakeup_unlock(sdiodev->rwnx_hw->ws_tx); ++ } ++ } ++ ++ aic_thread_wait_stop(); ++ AICWFDBG(LOGINFO, "%s Exit\r\n", __func__); ++ return 0; ++} ++ ++#if 0 //old oob feature ++int sdio_busrx_thread(void *data) ++{ ++ struct aicwf_rx_priv *rx_priv = (struct aicwf_rx_priv *)data; ++ struct aicwf_bus *bus_if = rx_priv->sdiodev->bus_if; ++#if 0 ++ struct cpumask cpumask; ++ cpumask_clear(&cpumask); ++ cpumask_set_cpu(1, &cpumask); ++ cpumask_set_cpu(2, &cpumask); ++ cpumask_set_cpu(3, &cpumask); ++ sched_setaffinity(0, &cpumask); ++#endif ++#ifdef CONFIG_TXRX_THREAD_PRIO ++ if (busrx_thread_prio > 0) { ++ struct sched_param param; ++ param.sched_priority = (busrx_thread_prio < MAX_RT_PRIO)?busrx_thread_prio:(MAX_RT_PRIO-1); ++ sched_setscheduler(current, SCHED_FIFO, ¶m); ++ } ++#endif ++ ++ AICWFDBG(LOGINFO, "%s the policy of current thread is:%d\n", __func__, current->policy); ++ AICWFDBG(LOGINFO, "%s the rt_priority of current thread is:%d\n", __func__, current->rt_priority); ++ AICWFDBG(LOGINFO, "%s the current pid is:%d\n", __func__, current->pid); ++ ++while (1) { ++ if (kthread_should_stop()) { ++ AICWFDBG(LOGERROR, "sdio busrx thread stop\n"); ++ break; ++ } ++#ifndef CONFIG_OOB ++ if (!wait_for_completion_interruptible(&bus_if->busrx_trgg)) { ++#else ++ if(!wait_for_completion_timeout(&bus_if->busrx_trgg, msecs_to_jiffies(rx_thread_wait_to))){ ++ AICWFDBG(LOGDEBUG, "%s wait for completion timout \r\n", __func__); ++ } ++#endif ++ if (bus_if->state == BUS_DOWN_ST) ++ continue; ++#ifdef CONFIG_OOB ++#ifdef CONFIG_SDIO_PWRCTRL ++ while(atomic_read(&bus_if->bus_priv.sdio->is_bus_suspend) == 1){ ++ AICWFDBG(LOGDEBUG, "%s waiting for sdio bus resume \r\n", __func__); ++ msleep(100); ++ } ++ aicwf_sdio_pwr_stctl(bus_if->bus_priv.sdio, SDIO_ACTIVE_ST); ++#endif //CONFIG_SDIO_PWRCTRL ++ aicwf_sdio_hal_irqhandler(bus_if->bus_priv.sdio->func); ++#endif //CONFIG_OOB ++ rwnx_wakeup_lock(rx_priv->sdiodev->rwnx_hw->ws_rx); ++ aicwf_process_rxframes(rx_priv); ++ rwnx_wakeup_unlock(rx_priv->sdiodev->rwnx_hw->ws_rx); ++#ifndef CONFIG_OOB ++ } ++#endif ++ } ++ ++ return 0; ++ ++} ++#else //new oob feature ++int sdio_busrx_thread(void *data) ++{ ++ struct aicwf_rx_priv *rx_priv = (struct aicwf_rx_priv *)data; ++ struct aicwf_bus *bus_if = rx_priv->sdiodev->bus_if; ++ ++#if 0 ++ struct cpumask cpumask; ++ cpumask_clear(&cpumask); ++ cpumask_set_cpu(1, &cpumask); ++ cpumask_set_cpu(2, &cpumask); ++ cpumask_set_cpu(3, &cpumask); ++ sched_setaffinity(0, &cpumask); ++#endif ++#if 0 ++#ifdef CONFIG_THREAD_INFO_IN_TASK ++ int set_cpu_ret = 0; ++ ++ AICWFDBG(LOGINFO, "%s the cpu is:%d\n", __func__, current->cpu); ++ set_cpu_ret = set_cpus_allowed_ptr(current, cpumask_of(2)); ++ AICWFDBG(LOGINFO, "%s set_cpu_ret is:%d\n", __func__, set_cpu_ret); ++ AICWFDBG(LOGINFO, "%s change cpu to:%d\n", __func__, current->cpu); ++#endif ++#endif ++#ifdef CONFIG_TXRX_THREAD_PRIO ++ if (busrx_thread_prio > 0) { ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)) ++ sched_set_fifo_low(current); ++#else ++ struct sched_param param; ++ param.sched_priority = (busrx_thread_prio < MAX_RT_PRIO) ? ++ busrx_thread_prio : ++ (MAX_RT_PRIO - 1); ++ sched_setscheduler(current, SCHED_FIFO, ¶m); ++#endif ++ } ++#endif ++ ++ AICWFDBG(LOGINFO, "%s the policy of current thread is:%d\n", __func__, ++ current->policy); ++ AICWFDBG(LOGINFO, "%s the rt_priority of current thread is:%d\n", ++ __func__, current->rt_priority); ++ AICWFDBG(LOGINFO, "%s the current pid is:%d\n", __func__, current->pid); ++ ++ while (1) { ++#if 0 ++ if (kthread_should_stop()) { ++ AICWFDBG(LOGERROR, "sdio busrx thread stop\n"); ++ break; ++ } ++#endif ++ if (!wait_for_completion_interruptible(&bus_if->busrx_trgg)) { ++ if (bus_if->state == BUS_DOWN_ST) ++ break; ++ //continue; ++ rwnx_wakeup_lock(rx_priv->sdiodev->rwnx_hw->ws_rx); ++ aicwf_process_rxframes(rx_priv); ++ rwnx_wakeup_unlock(rx_priv->sdiodev->rwnx_hw->ws_rx); ++ } ++ } ++ aic_thread_wait_stop(); ++ AICWFDBG(LOGINFO, "%s Exit\r\n", __func__); ++ return 0; ++} ++ ++#endif //old oob feature ++ ++#if defined(CONFIG_SDIO_PWRCTRL) ++static int aicwf_sdio_pwrctl_thread(void *data) ++{ ++ struct aic_sdio_dev *sdiodev = (struct aic_sdio_dev *)data; ++ ++ while (1) { ++ if (kthread_should_stop()) { ++ sdio_err("sdio pwrctl thread stop\n"); ++ break; ++ } ++ if (!wait_for_completion_interruptible( ++ &sdiodev->pwrctrl_trgg)) { ++ //printk("%s working\r\n", __func__); ++ ++ if (sdiodev->bus_if->state == BUS_DOWN_ST) ++ 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); ++ } ++ } ++ ++ return 0; ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) ++static void aicwf_sdio_bus_pwrctl(ulong data) ++#else ++static void aicwf_sdio_bus_pwrctl(struct timer_list *t) ++#endif ++{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) ++ struct aic_sdio_dev *sdiodev = (struct aic_sdio_dev *)data; ++#else ++ struct aic_sdio_dev *sdiodev = timer_container_of(sdiodev, t, timer); ++#endif ++ ++ if (sdiodev->bus_if->state == BUS_DOWN_ST) { ++ sdio_err("bus down\n"); ++ return; ++ } ++ ++ if (sdiodev->pwrctl_tsk) { ++ complete(&sdiodev->pwrctrl_trgg); ++ } ++} ++#endif ++ ++#ifdef CONFIG_PREALLOC_RX_SKB ++static void aicwf_sdio_enq_rxpkt(struct aic_sdio_dev *sdiodev, ++ struct rx_buff *pkt) ++#else ++static void aicwf_sdio_enq_rxpkt(struct aic_sdio_dev *sdiodev, ++ struct sk_buff *pkt) ++#endif ++{ ++ struct aicwf_rx_priv *rx_priv = sdiodev->rx_priv; ++ unsigned long flags = 0; ++ ++ spin_lock_irqsave(&rx_priv->rxqlock, flags); ++#ifdef CONFIG_PREALLOC_RX_SKB ++ if (!aicwf_rxbuff_enqueue(sdiodev->dev, &rx_priv->rxq, pkt)) { ++ spin_unlock_irqrestore(&rx_priv->rxqlock, flags); ++ printk("%s %d, enqueue rxq fail\n", __func__, __LINE__); ++ aicwf_prealloc_rxbuff_free(pkt, &rx_priv->rxbuff_lock); ++ return; ++ } ++#else ++ if (!aicwf_rxframe_enqueue(sdiodev->dev, &rx_priv->rxq, pkt)) { ++ spin_unlock_irqrestore(&rx_priv->rxqlock, flags); ++ aicwf_dev_skb_free(pkt); ++ return; ++ } ++#endif ++ spin_unlock_irqrestore(&rx_priv->rxqlock, flags); ++ ++ atomic_inc(&rx_priv->rx_cnt); ++} ++ ++#define SDIO_OTHER_INTERRUPT (0x1ul << 7) ++ ++void aicwf_sdio_hal_irqhandler(struct sdio_func *func) ++{ ++ struct aicwf_bus *bus_if = dev_get_drvdata(&func->dev); ++ struct aic_sdio_dev *sdiodev = bus_if->bus_priv.sdio; ++ u8 intstatus = 0; ++ u8 byte_len = 0; ++#ifdef CONFIG_PREALLOC_RX_SKB ++ struct rx_buff *pkt = NULL; ++#else ++ struct sk_buff *pkt = NULL; ++#endif ++ int ret; ++ ++ if ((sdiodev->rwnx_hw) == NULL) { ++ sdio_err("waiting for rwnx_hw->irq_enable is true\r\n"); ++ return; ++ } ++ ++ //AICWFDBG(LOGDEBUG, "fdrv %s enter \r\n", __func__); ++ rwnx_wakeup_lock(sdiodev->rwnx_hw->ws_irqrx); ++ ++ if (!bus_if || bus_if->state == BUS_DOWN_ST) { ++ sdio_err("bus err\n"); ++ rwnx_wakeup_unlock(sdiodev->rwnx_hw->ws_irqrx); ++ return; ++ } ++ ++#ifdef CONFIG_PREALLOC_RX_SKB ++ if (list_empty(&aic_rx_buff_list.rxbuff_list)) { ++ printk("%s %d, rxbuff list is empty\n", __func__, __LINE__); ++ rwnx_wakeup_unlock(sdiodev->rwnx_hw->ws_irqrx); ++ return; ++ } ++#endif ++ ++ if (sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ ret = aicwf_sdio_readb(sdiodev, sdiodev->sdio_reg.block_cnt_reg, ++ &intstatus); ++ while (ret || (intstatus & SDIO_OTHER_INTERRUPT)) { ++ sdio_err("ret=%d, intstatus=%x\r\n", ret, intstatus); ++ ret = aicwf_sdio_readb(sdiodev, ++ sdiodev->sdio_reg.block_cnt_reg, ++ &intstatus); ++ if (!ret) { ++ return; ++ } ++ } ++ sdiodev->rx_priv->data_len = ++ intstatus * SDIOWIFI_FUNC_BLOCKSIZE; ++ ++ if (intstatus > 0) { ++ if (intstatus < 64) { ++ pkt = aicwf_sdio_readframes(sdiodev); ++ } else { ++ aicwf_sdio_intr_get_len_bytemode( ++ sdiodev, ++ &byte_len); //byte_len must<= 128 ++ sdio_info("byte mode len=%d\r\n", byte_len); ++ pkt = aicwf_sdio_readframes(sdiodev); ++ } ++ } else { ++#ifndef CONFIG_PLATFORM_ALLWINNER ++// sdio_err("Interrupt but no data\n"); ++#endif ++ } ++ ++ if (pkt) ++ aicwf_sdio_enq_rxpkt(sdiodev, pkt); ++ ++ if (atomic_read(&sdiodev->rx_priv->rx_cnt) == 1) { ++ complete(&bus_if->busrx_trgg); ++ } ++ ++ } else if (sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ do { ++ ret = aicwf_sdio_readb( ++ sdiodev, sdiodev->sdio_reg.misc_int_status_reg, ++ &intstatus); ++ if (!ret) { ++ break; ++ } ++ sdio_err("ret=%d, intstatus=%x\r\n", ret, intstatus); ++ return; ++ } while (1); ++ if (intstatus & SDIO_OTHER_INTERRUPT) { ++ u8 int_pending; ++ ret = aicwf_sdio_readb(sdiodev, ++ sdiodev->sdio_reg.sleep_reg, ++ &int_pending); ++ if (ret < 0) { ++ sdio_err("reg:%d read failed!\n", ++ sdiodev->sdio_reg.sleep_reg); ++ } ++ int_pending &= ~0x01; // dev to host soft irq ++ ret = aicwf_sdio_writeb(sdiodev, ++ sdiodev->sdio_reg.sleep_reg, ++ int_pending); ++ if (ret < 0) { ++ sdio_err("reg:%d write failed!\n", ++ sdiodev->sdio_reg.sleep_reg); ++ } ++ } ++ ++ if (intstatus > 0) { ++ uint8_t intmaskf2 = intstatus | (0x1UL << 3); ++ if (intmaskf2 > 120U) { // func2 ++ if (intmaskf2 == 127U) { // byte mode ++ //aicwf_sdio_intr_get_len_bytemode(sdiodev, &byte_len, 1);//byte_len must<= 128 ++ aicwf_sdio_intr_get_len_bytemode( ++ sdiodev, ++ &byte_len); //byte_len must<= 128 ++ sdio_info("byte mode len=%d\r\n", ++ byte_len); ++ //pkt = aicwf_sdio_readframes(sdiodev, 1); ++ pkt = aicwf_sdio_readframes(sdiodev); ++ } else { // block mode ++ sdiodev->rx_priv->data_len = ++ (intstatus & 0x7U) * ++ SDIOWIFI_FUNC_BLOCKSIZE; ++ //pkt = aicwf_sdio_readframes(sdiodev, 1); ++ pkt = aicwf_sdio_readframes(sdiodev); ++ } ++ } else { // func1 ++ if (intstatus == 120U) { // byte mode ++ //aicwf_sdio_intr_get_len_bytemode(sdiodev, &byte_len, 0);//byte_len must<= 128 ++ aicwf_sdio_intr_get_len_bytemode( ++ sdiodev, ++ &byte_len); //byte_len must<= 128 ++ sdio_info("byte mode len=%d\r\n", ++ byte_len); ++ //pkt = aicwf_sdio_readframes(sdiodev, 0); ++ pkt = aicwf_sdio_readframes(sdiodev); ++ } else { // block mode ++ sdiodev->rx_priv->data_len = ++ (intstatus & 0x7FU) * ++ SDIOWIFI_FUNC_BLOCKSIZE; ++ //pkt = aicwf_sdio_readframes(sdiodev, 0); ++ pkt = aicwf_sdio_readframes(sdiodev); ++ } ++ } ++ } else { ++#ifndef CONFIG_PLATFORM_ALLWINNER ++ //sdio_err("Interrupt but no data\n"); ++#endif ++ } ++ ++ if (pkt) ++ aicwf_sdio_enq_rxpkt(sdiodev, pkt); ++ ++ if (atomic_read(&sdiodev->rx_priv->rx_cnt) == 1) { ++ complete(&bus_if->busrx_trgg); ++ } ++ } ++ ++ rwnx_wakeup_unlock(sdiodev->rwnx_hw->ws_irqrx); ++} ++ ++#if defined(CONFIG_SDIO_PWRCTRL) ++void aicwf_sdio_pwrctl_timer(struct aic_sdio_dev *sdiodev, uint duration) ++{ ++ uint timeout; ++ ++ //printk("%s duration:%d\r\n", __func__, duration); ++ if (sdiodev->bus_if->state == BUS_DOWN_ST && duration) ++ return; ++ ++ spin_lock_bh(&sdiodev->pwrctl_lock); ++ if (!duration) { ++ if (timer_pending(&sdiodev->timer)) ++ timer_delete_sync(&sdiodev->timer); ++ } else { ++ sdiodev->active_duration = duration; ++ timeout = msecs_to_jiffies(sdiodev->active_duration); ++ mod_timer(&sdiodev->timer, jiffies + timeout); ++ } ++ spin_unlock_bh(&sdiodev->pwrctl_lock); ++} ++#endif ++ ++static struct aicwf_bus_ops aicwf_sdio_bus_ops = { ++ .stop = aicwf_sdio_bus_stop, ++ .start = aicwf_sdio_bus_start, ++ .txdata = aicwf_sdio_bus_txdata, ++ .txmsg = aicwf_sdio_bus_txmsg, ++}; ++ ++void aicwf_sdio_release(struct aic_sdio_dev *sdiodev) ++{ ++ struct aicwf_bus *bus_if; ++ int ret = 0; ++ AICWFDBG(LOGINFO, "%s Enter\n", __func__); ++ ++ bus_if = dev_get_drvdata(sdiodev->dev); ++ bus_if->state = BUS_DOWN_ST; ++#ifdef CONFIG_OOB ++ if (sdiodev->oob_enable) { ++ sdio_claim_host(sdiodev->func); ++ //disable sdio interrupt ++ ret = aicwf_sdio_writeb(sdiodev, ++ sdiodev->sdio_reg.intr_config_reg, 0x0); ++ if (ret < 0) { ++ AICWFDBG(LOGERROR, "reg:%d write failed!\n", ++ sdiodev->sdio_reg.intr_config_reg); ++ } ++ sdio_release_irq(sdiodev->func); ++ sdio_release_host(sdiodev->func); ++ } ++#else ++ sdio_claim_host(sdiodev->func); ++ //disable sdio interrupt ++ ret = aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.intr_config_reg, ++ 0x0); ++ if (ret < 0) { ++ sdio_err("reg:%d write failed!\n", ++ sdiodev->sdio_reg.intr_config_reg); ++ } ++ sdio_release_irq(sdiodev->func); ++ sdio_release_host(sdiodev->func); ++#endif ++ if (sdiodev->dev) ++ aicwf_bus_deinit(sdiodev->dev); ++ ++ if (sdiodev->tx_priv) ++ aicwf_tx_deinit(sdiodev->tx_priv); ++ ++ if (sdiodev->rx_priv) ++ aicwf_rx_deinit(sdiodev->rx_priv); ++ ++#if defined(CONFIG_SDIO_PWRCTRL) ++ if (sdiodev->pwrctl_tsk) { ++ complete_all(&sdiodev->pwrctrl_trgg); ++ kthread_stop(sdiodev->pwrctl_tsk); ++ sdiodev->pwrctl_tsk = NULL; ++ } ++ ++ AICWFDBG(LOGINFO, "%s:pwrctl stopped\n", __func__); ++#endif ++ ++ if (sdiodev->cmd_mgr.state == RWNX_CMD_MGR_STATE_INITED) ++ rwnx_cmd_mgr_deinit(&sdiodev->cmd_mgr); ++ AICWFDBG(LOGINFO, "%s Exit\n", __func__); ++} ++ ++void aicwf_sdio_reg_init(struct aic_sdio_dev *sdiodev) ++{ ++ sdio_dbg("%s\n", __func__); ++ ++ if (sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ sdiodev->sdio_reg.bytemode_len_reg = SDIOWIFI_BYTEMODE_LEN_REG; ++ sdiodev->sdio_reg.intr_config_reg = SDIOWIFI_INTR_CONFIG_REG; ++ sdiodev->sdio_reg.sleep_reg = SDIOWIFI_SLEEP_REG; ++ sdiodev->sdio_reg.wakeup_reg = SDIOWIFI_WAKEUP_REG; ++ sdiodev->sdio_reg.flow_ctrl_reg = SDIOWIFI_FLOW_CTRL_REG; ++ sdiodev->sdio_reg.register_block = SDIOWIFI_REGISTER_BLOCK; ++ sdiodev->sdio_reg.bytemode_enable_reg = ++ SDIOWIFI_BYTEMODE_ENABLE_REG; ++ sdiodev->sdio_reg.block_cnt_reg = SDIOWIFI_BLOCK_CNT_REG; ++ sdiodev->sdio_reg.rd_fifo_addr = SDIOWIFI_RD_FIFO_ADDR; ++ sdiodev->sdio_reg.wr_fifo_addr = SDIOWIFI_WR_FIFO_ADDR; ++ } else if (sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ sdiodev->sdio_reg.bytemode_len_reg = ++ SDIOWIFI_BYTEMODE_LEN_REG_V3; ++ sdiodev->sdio_reg.intr_config_reg = SDIOWIFI_INTR_ENABLE_REG_V3; ++ sdiodev->sdio_reg.sleep_reg = SDIOWIFI_INTR_PENDING_REG_V3; ++ sdiodev->sdio_reg.wakeup_reg = SDIOWIFI_INTR_TO_DEVICE_REG_V3; ++ sdiodev->sdio_reg.flow_ctrl_reg = SDIOWIFI_FLOW_CTRL_Q1_REG_V3; ++ sdiodev->sdio_reg.bytemode_enable_reg = ++ SDIOWIFI_BYTEMODE_ENABLE_REG_V3; ++ sdiodev->sdio_reg.misc_int_status_reg = ++ SDIOWIFI_MISC_INT_STATUS_REG_V3; ++ sdiodev->sdio_reg.rd_fifo_addr = SDIOWIFI_RD_FIFO_ADDR_V3; ++ sdiodev->sdio_reg.wr_fifo_addr = SDIOWIFI_WR_FIFO_ADDR_V3; ++ } ++} ++ ++int aicwf_sdio_func_init(struct aic_sdio_dev *sdiodev) ++{ ++ struct mmc_host *host; ++ u8 block_bit0 = 0x1; ++ u8 byte_mode_disable = 0x1; //1: no byte mode ++ int ret = 0; ++ struct aicbsp_feature_t feature; ++ //u8 val = 0; ++ ++ aicbsp_get_feature(&feature, NULL); ++ aicwf_sdio_reg_init(sdiodev); ++ ++ host = sdiodev->func->card->host; ++ ++ sdio_claim_host(sdiodev->func); ++#if 0 //SDIO PHASE SETTING ++ sdiodev->func->card->quirks |= MMC_QUIRK_LENIENT_FN0; ++ sdio_f0_writeb(sdiodev->func, feature.sdio_phase, 0x13, &ret); ++ if (ret < 0) { ++ AICWFDBG(LOGERROR, "write func0 fail %d\n", ret); ++ sdio_release_host(sdiodev->func); ++ return ret; ++ } ++#endif ++ ret = sdio_set_block_size(sdiodev->func, SDIOWIFI_FUNC_BLOCKSIZE); ++ if (ret < 0) { ++ AICWFDBG(LOGERROR, "set blocksize fail %d\n", ret); ++ sdio_release_host(sdiodev->func); ++ return ret; ++ } ++ ret = sdio_enable_func(sdiodev->func); ++ if (ret < 0) { ++ sdio_release_host(sdiodev->func); ++ AICWFDBG(LOGERROR, "enable func fail %d.\n", ret); ++ return ret; ++ } ++ ++#if 1 //SDIO CLOCK SETTING ++ if (feature.sdio_clock > 0) { ++ host->ios.clock = feature.sdio_clock; ++ host->ops->set_ios(host, &host->ios); ++ AICWFDBG(LOGINFO, "Set SDIO Clock %d MHz\n", ++ host->ios.clock / 1000000); ++ } ++#endif ++ ++ sdio_release_host(sdiodev->func); ++ ++ if (sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ sdio_claim_host(sdiodev->func2); ++ //set sdio blocksize ++ ret = sdio_set_block_size(sdiodev->func2, ++ SDIOWIFI_FUNC_BLOCKSIZE); ++ if (ret < 0) { ++ AICWFDBG(LOGERROR, "set func2 blocksize fail %d\n", ++ ret); ++ sdio_release_host(sdiodev->func2); ++ return ret; ++ } ++ ++ //set sdio enable func ++ ret = sdio_enable_func(sdiodev->func2); ++ if (ret < 0) { ++ sdio_release_host(sdiodev->func2); ++ AICWFDBG(LOGERROR, "enable func2 fail %d.\n", ret); ++ return ret; ++ } ++ ++ sdio_release_host(sdiodev->func2); ++ ++ ret = aicwf_sdio_func2_writeb( ++ sdiodev, sdiodev->sdio_reg.register_block, block_bit0); ++ if (ret < 0) { ++ AICWFDBG(LOGERROR, "reg:%d write failed!\n", ++ sdiodev->sdio_reg.register_block); ++ return ret; ++ } ++ ++ //1: no byte mode ++ ret = aicwf_sdio_func2_writeb( ++ sdiodev, sdiodev->sdio_reg.bytemode_enable_reg, ++ byte_mode_disable); ++ if (ret < 0) { ++ AICWFDBG(LOGERROR, "reg:%d write failed!\n", ++ sdiodev->sdio_reg.bytemode_enable_reg); ++ return ret; ++ } ++ } ++ ++ ret = aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.register_block, ++ block_bit0); ++ if (ret < 0) { ++ AICWFDBG(LOGERROR, "reg:%d write failed!\n", ++ sdiodev->sdio_reg.register_block); ++ return ret; ++ } ++ ++ //1: no byte mode ++ ret = aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.bytemode_enable_reg, ++ byte_mode_disable); ++ if (ret < 0) { ++ AICWFDBG(LOGERROR, "reg:%d write failed!\n", ++ sdiodev->sdio_reg.bytemode_enable_reg); ++ return ret; ++ } ++ ++#if 0 ++ ret = aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.wakeup_reg, 1); ++ if (ret < 0) { ++ AICWFDBG(LOGERROR, "reg:%d write failed!\n", sdiodev->sdio_reg.wakeup_reg); ++ return ret; ++ } ++ ++ mdelay(5); ++ ret = aicwf_sdio_readb(sdiodev, sdiodev->sdio_reg.sleep_reg, &val); ++ if (ret < 0) { ++ AICWFDBG(LOGERROR, "reg:%d read failed!\n", sdiodev->sdio_reg.sleep_reg); ++ return ret; ++ } ++ ++ if(!(val & 0x10)){ ++ AICWFDBG(LOGERROR, "wakeup fail\n"); ++ }else{ ++ AICWFDBG(LOGINFO, "sdio ready\n"); ++ } ++#else ++ mdelay(10); ++#endif ++ return ret; ++} ++ ++int aicwf_sdiov3_func_init(struct aic_sdio_dev *sdiodev) ++{ ++ struct mmc_host *host; ++ u8 byte_mode_disable = 0x1; //1: no byte mode ++ int ret = 0; ++ struct aicbsp_feature_t feature; ++ //u8 val = 0; ++ u8 val1 = 0; ++ ++ aicbsp_get_feature(&feature, NULL); ++ aicwf_sdio_reg_init(sdiodev); ++ ++ host = sdiodev->func->card->host; ++ ++ sdio_claim_host(sdiodev->func); ++ sdiodev->func->card->quirks |= MMC_QUIRK_LENIENT_FN0; ++ ++ ret = sdio_set_block_size(sdiodev->func, SDIOWIFI_FUNC_BLOCKSIZE); ++ if (ret < 0) { ++ AICWFDBG(LOGERROR, "set blocksize fail %d\n", ret); ++ sdio_release_host(sdiodev->func); ++ return ret; ++ } ++ ret = sdio_enable_func(sdiodev->func); ++ if (ret < 0) { ++ sdio_release_host(sdiodev->func); ++ AICWFDBG(LOGERROR, "enable func fail %d.\n", ret); ++ return ret; ++ } ++ ++ sdio_f0_writeb(sdiodev->func, 0x7F, 0xF2, &ret); ++ if (ret) { ++ sdio_err("set fn0 0xF2 fail %d\n", ret); ++ sdio_release_host(sdiodev->func); ++ return ret; ++ } ++#if 0 ++ if (host->ios.timing == MMC_TIMING_UHS_DDR50) { ++ val = 0x21;//0x1D;//0x5; ++ } else { ++ val = 0x01;//0x19;//0x1; ++ } ++ val |= SDIOCLK_FREE_RUNNING_BIT; ++ sdio_f0_writeb(sdiodev->func, val, 0xF0, &ret); ++ if (ret) { ++ sdio_err("set iopad ctrl fail %d\n", ret); ++ sdio_release_host(sdiodev->func); ++ return ret; ++ } ++ sdio_f0_writeb(sdiodev->func, 0x0, 0xF8, &ret); ++ if (ret) { ++ sdio_err("set iopad delay2 fail %d\n", ret); ++ sdio_release_host(sdiodev->func); ++ return ret; ++ } ++ sdio_f0_writeb(sdiodev->func, 0x20, 0xF1, &ret); ++ if (ret) { ++ sdio_err("set iopad delay1 fail %d\n", ret); ++ sdio_release_host(sdiodev->func); ++ return ret; ++ } ++ msleep(1); ++#if 1 //SDIO CLOCK SETTING ++ if ((feature.sdio_clock > 0) && (host->ios.timing != MMC_TIMING_UHS_DDR50)) { ++ host->ios.clock = feature.sdio_clock; ++ host->ops->set_ios(host, &host->ios); ++ AICWFDBG(LOGINFO, "Set SDIO Clock %d MHz\n", host->ios.clock/1000000); ++ } ++#endif ++#endif ++ sdio_release_host(sdiodev->func); ++ ++ //1: no byte mode ++ ret = aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.bytemode_enable_reg, ++ byte_mode_disable); ++ if (ret < 0) { ++ AICWFDBG(LOGERROR, "reg:%d write failed!\n", ++ sdiodev->sdio_reg.bytemode_enable_reg); ++ return ret; ++ } ++ ++ ret = aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.wakeup_reg, 0x11); ++ if (ret < 0) { ++ AICWFDBG(LOGERROR, "reg:%d write failed!\n", ++ sdiodev->sdio_reg.wakeup_reg); ++ return ret; ++ } ++ ++#if 1 ++ mdelay(5); ++ ret = aicwf_sdio_readb(sdiodev, sdiodev->sdio_reg.sleep_reg, &val1); ++ if (ret < 0) { ++ AICWFDBG(LOGERROR, "reg:%d read failed!\n", ++ sdiodev->sdio_reg.sleep_reg); ++ return ret; ++ } ++ ++ if (!(val1 & 0x10)) { ++ AICWFDBG(LOGERROR, "wakeup fail\n"); ++ } else { ++ AICWFDBG(LOGINFO, "sdio ready\n"); ++ } ++#endif ++ return ret; ++} ++ ++void aicwf_sdio_func_deinit(struct aic_sdio_dev *sdiodev) ++{ ++ sdio_claim_host(sdiodev->func); ++ sdio_disable_func(sdiodev->func); ++ sdio_release_host(sdiodev->func); ++ ++ if (sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ sdio_claim_host(sdiodev->func2); ++ sdio_disable_func(sdiodev->func2); ++ sdio_release_host(sdiodev->func2); ++ } ++} ++ ++void *aicwf_sdio_bus_init(struct aic_sdio_dev *sdiodev) ++{ ++ int ret; ++ struct aicwf_bus *bus_if; ++ struct aicwf_rx_priv *rx_priv; ++ struct aicwf_tx_priv *tx_priv; ++ ++#if defined(CONFIG_SDIO_PWRCTRL) ++ spin_lock_init(&sdiodev->pwrctl_lock); ++ sema_init(&sdiodev->pwrctl_wakeup_sema, 1); ++#endif ++ ++ bus_if = sdiodev->bus_if; ++ bus_if->dev = sdiodev->dev; ++ bus_if->ops = &aicwf_sdio_bus_ops; ++ bus_if->state = BUS_DOWN_ST; ++#if defined(CONFIG_SDIO_PWRCTRL) ++ sdiodev->state = SDIO_SLEEP_ST; ++ sdiodev->active_duration = SDIOWIFI_PWR_CTRL_INTERVAL; ++#else ++ sdiodev->state = SDIO_ACTIVE_ST; ++#endif ++ ++ rx_priv = aicwf_rx_init(sdiodev); ++ if (!rx_priv) { ++ sdio_err("rx init fail\n"); ++ goto fail; ++ } ++ sdiodev->rx_priv = rx_priv; ++ ++ tx_priv = aicwf_tx_init(sdiodev); ++ if (!tx_priv) { ++ sdio_err("tx init fail\n"); ++ goto fail; ++ } ++ sdiodev->tx_priv = tx_priv; ++ aicwf_frame_queue_init(&tx_priv->txq, 8, TXQLEN); ++ spin_lock_init(&tx_priv->txqlock); ++ sema_init(&tx_priv->txctl_sema, 1); ++ sema_init(&tx_priv->cmd_txsema, 1); ++ init_waitqueue_head(&tx_priv->cmd_txdone_wait); ++ atomic_set(&tx_priv->tx_pktcnt, 0); ++ ++#if defined(CONFIG_SDIO_PWRCTRL) ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) ++ init_timer(&sdiodev->timer); ++ sdiodev->timer.data = (ulong)sdiodev; ++ sdiodev->timer.function = aicwf_sdio_bus_pwrctl; ++#else ++ timer_setup(&sdiodev->timer, aicwf_sdio_bus_pwrctl, 0); ++#endif ++ init_completion(&sdiodev->pwrctrl_trgg); ++#ifdef AICWF_SDIO_SUPPORT ++ sdiodev->pwrctl_tsk = ++ kthread_run(aicwf_sdio_pwrctl_thread, sdiodev, "aicwf_pwrctl"); ++#endif ++ if (IS_ERR(sdiodev->pwrctl_tsk)) { ++ sdiodev->pwrctl_tsk = NULL; ++ } ++#endif ++#ifdef CONFIG_TX_NETIF_FLOWCTRL ++ sdiodev->flowctrl = 0; ++ spin_lock_init(&sdiodev->tx_flow_lock); ++#endif ++ ++#ifdef CONFIG_TEMP_CONTROL ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) ++ init_timer(&sdiodev->tp_ctrl_timer); ++ sdiodev->tp_ctrl_timer.data = (ulong)sdiodev; ++ sdiodev->tp_ctrl_timer.function = aicwf_temp_ctrl_timer; ++ init_timer(&sdiodev->netif_timer); ++ sdiodev->netif_timer.data = (ulong)sdiodev; ++ sdiodev->netif_timer.function = aicwf_netif_timer; ++#else ++ timer_setup(&sdiodev->tp_ctrl_timer, aicwf_temp_ctrl_timer, 0); ++ timer_setup(&sdiodev->netif_timer, aicwf_netif_timer, 0); ++#endif ++ INIT_WORK(&sdiodev->tp_ctrl_work, aicwf_temp_ctrl_worker); ++ INIT_WORK(&sdiodev->netif_work, aicwf_netif_worker); ++ mod_timer(&sdiodev->tp_ctrl_timer, ++ jiffies + msecs_to_jiffies(TEMP_GET_INTERVAL)); ++ sdiodev->net_stop = false; ++ ; ++ sdiodev->on_off = true; ++ sdiodev->cur_temp = 0; ++ sdiodev->get_level = 0; ++ sdiodev->set_level = 0; ++ sdiodev->interval_t1 = TMR_INTERVAL_1; ++ sdiodev->interval_t2 = TMR_INTERVAL_2; ++ sdiodev->cur_stat = 0; ++#endif ++ ++ ret = aicwf_bus_init(0, sdiodev->dev); ++ if (ret < 0) { ++ sdio_err("bus init fail\n"); ++ goto fail; ++ } ++ ++ ret = aicwf_bus_start(bus_if); ++ if (ret != 0) { ++ sdio_err("bus start fail\n"); ++ goto fail; ++ } ++ ++ return sdiodev; ++ ++fail: ++ aicwf_sdio_release(sdiodev); ++ return NULL; ++} ++ ++uint8_t crc8_ponl_107(uint8_t *p_buffer, uint16_t cal_size) ++{ ++ uint8_t i; ++ uint8_t crc = 0; ++ if (cal_size == 0) { ++ return crc; ++ } ++ while (cal_size--) { ++ for (i = 0x80; i > 0; i /= 2) { ++ if (crc & 0x80) { ++ crc *= 2; ++ crc ^= 0x07; //polynomial X8 + X2 + X + 1,(0x107) ++ } else { ++ crc *= 2; ++ } ++ if ((*p_buffer) & i) { ++ crc ^= 0x07; ++ } ++ } ++ p_buffer++; ++ } ++ ++ return crc; ++} ++ ++#ifdef CONFIG_WIFI_SUSPEND_FOR_LINUX ++void rwnx_set_wifi_suspend(char onoff) ++{ ++ int ret = 0; ++ if (onoff == '0') { ++ printk("%s resume \r\n", __func__); ++ rwnx_send_me_set_lp_level(g_rwnx_plat->sdiodev->rwnx_hw, 0, 1); ++ } else { ++ printk("%s suspend \r\n", __func__); ++ ret = rwnx_send_me_set_lp_level(g_rwnx_plat->sdiodev->rwnx_hw, ++ 1, 0); ++ if (!ret) { ++ 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); ++ } ++ } ++ } ++} ++ ++static ssize_t rwnx_wifi_suspend_write_proc(struct file *file, ++ const char __user *buffer, ++ size_t count, loff_t *pos) ++{ ++ char onoff; ++ ++ if (count < 1) ++ return -EINVAL; ++ ++ if (copy_from_user(&onoff, buffer, 1)) ++ return -EFAULT; ++ ++ rwnx_set_wifi_suspend(onoff); ++ ++ return count; ++} ++ ++static const struct file_operations wifi_suspend_fops = { ++ .owner = THIS_MODULE, ++ .write = rwnx_wifi_suspend_write_proc, ++}; ++ ++void rwnx_init_wifi_suspend_node(void) ++{ ++ struct proc_dir_entry *ent; ++ ++ wifi_suspend_node = proc_mkdir("wifi_suspend", NULL); ++ if (wifi_suspend_node == NULL) { ++ printk("Unable to create /proc/wifi_suspend directory"); ++ } ++ ++ ent = proc_create("suspend", 0660, wifi_suspend_node, ++ &wifi_suspend_fops); ++ if (ent == NULL) { ++ printk("Unable to create /proc/wifi_suspend/suspend"); ++ } ++} ++ ++void rwnx_deinit_wifi_suspend_node(void) ++{ ++ remove_proc_entry("suspend", wifi_suspend_node); ++ remove_proc_entry("wifi_suspend", 0); ++} ++#endif //CONFIG_WIFI_SUSPEND_FOR_LINUX +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_sdio.h b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_sdio.h +new file mode 100755 +index 000000000..0dd55e349 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_sdio.h +@@ -0,0 +1,226 @@ ++/** ++ * aicwf_sdio.h ++ * ++ * SDIO function declarations ++ * ++ * Copyright (C) AICSemi 2018-2020 ++ */ ++ ++#ifndef _AICWF_SDMMC_H_ ++#define _AICWF_SDMMC_H_ ++ ++#ifdef AICWF_SDIO_SUPPORT ++#include ++#include ++#include ++#include ++#include "rwnx_cmds.h" ++#include "aicwf_rx_prealloc.h" ++#define AICWF_SDIO_NAME "aicwf_sdio" ++#define SDIOWIFI_FUNC_BLOCKSIZE 512 ++ ++#define SDIOWIFI_BYTEMODE_LEN_REG 0x02 ++#define SDIOWIFI_INTR_CONFIG_REG 0x04 ++#define SDIOWIFI_SLEEP_REG 0x05 ++#define SDIOWIFI_WAKEUP_REG 0x09 ++#define SDIOWIFI_FLOW_CTRL_REG 0x0A ++#define SDIOWIFI_REGISTER_BLOCK 0x0B ++#define SDIOWIFI_BYTEMODE_ENABLE_REG 0x11 ++#define SDIOWIFI_BLOCK_CNT_REG 0x12 ++#define SDIOWIFI_FLOWCTRL_MASK_REG 0x7F ++#define SDIOWIFI_WR_FIFO_ADDR 0x07 ++#define SDIOWIFI_RD_FIFO_ADDR 0x08 ++ ++#define SDIOWIFI_INTR_ENABLE_REG_V3 0x00 ++#define SDIOWIFI_INTR_PENDING_REG_V3 0x01 ++#define SDIOWIFI_INTR_TO_DEVICE_REG_V3 0x02 ++#define SDIOWIFI_FLOW_CTRL_Q1_REG_V3 0x03 ++#define SDIOWIFI_MISC_INT_STATUS_REG_V3 0x04 ++#define SDIOWIFI_BYTEMODE_LEN_REG_V3 0x05 ++#define SDIOWIFI_BYTEMODE_LEN_MSB_REG_V3 0x06 ++#define SDIOWIFI_BYTEMODE_ENABLE_REG_V3 0x07 ++#define SDIOWIFI_MISC_CTRL_REG_V3 0x08 ++#define SDIOWIFI_FLOW_CTRL_Q2_REG_V3 0x09 ++#define SDIOWIFI_CLK_TEST_RESULT_REG_V3 0x0A ++#define SDIOWIFI_RD_FIFO_ADDR_V3 0x0F ++#define SDIOWIFI_WR_FIFO_ADDR_V3 0x10 ++ ++#define SDIOCLK_FREE_RUNNING_BIT (1 << 6) ++ ++#define SDIOWIFI_PWR_CTRL_INTERVAL 30 ++#define FLOW_CTRL_RETRY_COUNT 50 ++#define BUFFER_SIZE 1536 ++#define TAIL_LEN 4 ++#define TXQLEN (2048 * 4) ++ ++#define SDIO_SLEEP_ST 0 ++#define SDIO_ACTIVE_ST 1 ++ ++#define DATA_FLOW_CTRL_THRESH 2 ++#ifdef CONFIG_TX_NETIF_FLOWCTRL ++#define AICWF_SDIO_TX_LOW_WATER 100 ++#define AICWF_SDIO_TX_HIGH_WATER 500 ++#endif ++ ++#ifdef CONFIG_TEMP_CONTROL ++#define TEMP_GET_INTERVAL (60 * 1000) ++#define TEMP_THD_1 80 //temperature 1 (℃) ++#define TEMP_THD_2 95 //temperature 2 (℃) ++#define BUFFERING_V1 8 ++#define BUFFERING_V2 13 ++#define TMR_INTERVAL_1 60 //timer_1 60ms ++#define TMR_INTERVAL_2 180 //timer_2 130ms ++#endif ++ ++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_PRINT = 0X13 ++} sdio_type; ++ ++/* SDIO Device ID */ ++#define SDIO_VENDOR_ID_AIC8801 0x5449 ++#define SDIO_VENDOR_ID_AIC8800DC 0xc8a1 ++#define SDIO_VENDOR_ID_AIC8800D80 0xc8a1 ++#define SDIO_VENDOR_ID_AIC8800D80X2 0xc8a1 ++ ++#define SDIO_DEVICE_ID_AIC8801 0x0145 ++#define SDIO_DEVICE_ID_AIC8800DC 0xc08d ++#define SDIO_DEVICE_ID_AIC8800D80 0x0082 ++#define SDIO_DEVICE_ID_AIC8800D80X2 0x2082 ++ ++enum AICWF_IC { ++ PRODUCT_ID_AIC8801 = 0, ++ PRODUCT_ID_AIC8800DC, ++ PRODUCT_ID_AIC8800DW, ++ PRODUCT_ID_AIC8800D80, ++ PRODUCT_ID_AIC8800D80X2 ++}; ++ ++struct rwnx_hw; ++ ++struct aic_sdio_reg { ++ u8 bytemode_len_reg; ++ u8 intr_config_reg; ++ u8 sleep_reg; ++ u8 wakeup_reg; ++ u8 flow_ctrl_reg; ++ u8 flowctrl_mask_reg; ++ u8 register_block; ++ u8 bytemode_enable_reg; ++ u8 block_cnt_reg; ++ u8 misc_int_status_reg; ++ u8 rd_fifo_addr; ++ u8 wr_fifo_addr; ++}; ++ ++struct aic_sdio_dev { ++ struct rwnx_hw *rwnx_hw; ++ struct sdio_func *func; ++ struct sdio_func *func2; ++ struct device *dev; ++ struct aicwf_bus *bus_if; ++ struct rwnx_cmd_mgr cmd_mgr; ++ ++ struct aicwf_rx_priv *rx_priv; ++ struct aicwf_tx_priv *tx_priv; ++ u32 state; ++#ifdef CONFIG_TX_NETIF_FLOWCTRL ++ u8 flowctrl; ++ spinlock_t tx_flow_lock; ++#endif ++ ++#if defined(CONFIG_SDIO_PWRCTRL) ++ //for sdio pwr ctrl ++ struct timer_list timer; ++ uint active_duration; ++ struct completion pwrctrl_trgg; ++ struct task_struct *pwrctl_tsk; ++ spinlock_t pwrctl_lock; ++ struct semaphore pwrctl_wakeup_sema; ++#endif ++ u16 chipid; ++ struct aic_sdio_reg sdio_reg; ++ ++ spinlock_t wslock; //AIDEN test ++ bool oob_enable; ++ atomic_t is_bus_suspend; ++ ++#ifdef CONFIG_TEMP_CONTROL ++ spinlock_t tx_flow_lock; ++ struct timer_list netif_timer; ++ struct timer_list tp_ctrl_timer; ++ struct work_struct tp_ctrl_work; ++ struct work_struct netif_work; ++ s8_l cur_temp; ++ bool net_stop; ++ bool on_off; //for command, 0 - off, 1 - on ++ int8_t get_level; //for command, 0 - 100%, 1 - 12%, 2 - 3% ++ int8_t set_level; //for command, 0 - driver auto, 1 - 12%, 2 - 3% ++ int interval_t1; ++ int interval_t2; ++ u8_l cur_stat; //0--normal temp, 1/2--buffering temp ++#endif ++}; ++ ++#ifdef CONFIG_TEMP_CONTROL ++void aicwf_netif_worker(struct work_struct *work); ++void aicwf_temp_ctrl_worker(struct work_struct *work); ++void aicwf_temp_ctrl(struct aic_sdio_dev *sdiodev); ++void aicwf_netif_ctrl(struct aic_sdio_dev *sdiodev, int val); ++#endif ++extern struct aicwf_rx_buff_list aic_rx_buff_list; ++int aicwf_sdio_writeb(struct aic_sdio_dev *sdiodev, uint regaddr, u8 val); ++int aicwf_sdio_func2_readb(struct aic_sdio_dev *sdiodev, uint regaddr, u8 *val); ++int aicwf_sdio_func2_writeb(struct aic_sdio_dev *sdiodev, uint regaddr, u8 val); ++void aicwf_sdio_hal_irqhandler(struct sdio_func *func); ++ ++#if defined(CONFIG_SDIO_PWRCTRL) ++void aicwf_sdio_pwrctl_timer(struct aic_sdio_dev *sdiodev, uint duration); ++int aicwf_sdio_pwr_stctl(struct aic_sdio_dev *sdiodev, uint target); ++#endif ++void aicwf_sdio_reg_init(struct aic_sdio_dev *sdiodev); ++int aicwf_sdio_func_init(struct aic_sdio_dev *sdiodev); ++int aicwf_sdiov3_func_init(struct aic_sdio_dev *sdiodev); ++void aicwf_sdio_func_deinit(struct aic_sdio_dev *sdiodev); ++#ifdef CONFIG_TX_NETIF_FLOWCTRL ++void aicwf_sdio_tx_netif_flowctrl(struct rwnx_hw *rwnx_hw, bool state); ++#endif ++int aicwf_sdio_flow_ctrl(struct aic_sdio_dev *sdiodev); ++int aicwf_sdio_flow_ctrl_msg(struct aic_sdio_dev *sdiodev); ++#ifdef CONFIG_PREALLOC_RX_SKB ++int aicwf_sdio_recv_pkt(struct aic_sdio_dev *sdiodev, struct rx_buff *rxbbuf, ++ u32 size); ++#else ++int aicwf_sdio_recv_pkt(struct aic_sdio_dev *sdiodev, struct sk_buff *skbbuf, ++ u32 size); ++#endif ++int aicwf_sdio_send_pkt(struct aic_sdio_dev *sdiodev, u8 *buf, uint count); ++void *aicwf_sdio_bus_init(struct aic_sdio_dev *sdiodev); ++void aicwf_sdio_release(struct aic_sdio_dev *sdiodev); ++void aicwf_sdio_exit(void); ++void aicwf_sdio_register(void); ++int aicwf_sdio_txpkt(struct aic_sdio_dev *sdiodev, struct sk_buff *pkt); ++int sdio_bustx_thread(void *data); ++int sdio_busrx_thread(void *data); ++#ifdef CONFIG_OOB ++//new oob feature ++int sdio_busirq_thread(void *data); ++#endif //CONFIG_OOB ++int aicwf_sdio_aggr(struct aicwf_tx_priv *tx_priv, struct sk_buff *pkt); ++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_AMLOGIC ++extern void extern_wifi_set_enable(int is_on); ++extern void sdio_reinit(void); ++#endif /*CONFIG_PLATFORM_AMLOGIC*/ ++uint8_t crc8_ponl_107(uint8_t *p_buffer, uint16_t cal_size); ++ ++#endif /* AICWF_SDIO_SUPPORT */ ++ ++#endif /*_AICWF_SDMMC_H_*/ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_tcp_ack.c b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_tcp_ack.c +new file mode 100755 +index 000000000..73033b5a0 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_tcp_ack.c +@@ -0,0 +1,611 @@ ++#include "aicwf_tcp_ack.h" ++//#include"rwnx_tx.h" ++//#include "aicwf_tcp_ack.h" ++#include "rwnx_defs.h" ++extern int intf_tx(struct rwnx_hw *priv, struct msg_buf *msg); ++struct msg_buf *intf_tcp_alloc_msg(struct msg_buf *msg) ++{ ++ //printk("%s \n",__func__); ++ int len = sizeof(struct msg_buf); ++ msg = kzalloc(len, /*GFP_KERNEL*/ GFP_ATOMIC); ++ if (!msg) ++ printk("%s: alloc failed \n", __func__); ++ memset(msg, 0, len); ++ return msg; ++} ++ ++void intf_tcp_drop_msg(struct rwnx_hw *priv, struct msg_buf *msg) ++{ ++ //printk("%s \n",__func__); ++ if (msg->skb) ++ dev_kfree_skb_any(msg->skb); ++ ++ kfree(msg); ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) ++void tcp_ack_timeout(unsigned long data) ++#else ++void tcp_ack_timeout(struct timer_list *t) ++#endif ++{ ++ //printk("%s \n",__func__); ++ struct tcp_ack_info *ack_info; ++ struct msg_buf *msg; ++ struct tcp_ack_manage *ack_m = NULL; ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) ++ ack_info = (struct tcp_ack_info *)data; ++#else ++ ack_info = container_of(t, struct tcp_ack_info, timer); ++#endif ++ ++ ack_m = container_of(ack_info, struct tcp_ack_manage, ++ ack_info[ack_info->ack_info_num]); ++ ++ write_seqlock_bh(&ack_info->seqlock); ++ msg = ack_info->msgbuf; ++ if (ack_info->busy && msg && !ack_info->in_send_msg) { ++ ack_info->msgbuf = NULL; ++ ack_info->drop_cnt = 0; ++ ack_info->in_send_msg = msg; ++ write_sequnlock_bh(&ack_info->seqlock); ++ intf_tx(ack_m->priv, msg); //send skb ++ //ack_info->in_send_msg = NULL;//add by dwx ++ //write_sequnlock_bh(&ack_info->seqlock); ++ //intf_tx(ack_m->priv, msg); ++ return; ++ } ++ write_sequnlock_bh(&ack_info->seqlock); ++} ++ ++void tcp_ack_init(struct rwnx_hw *priv) ++{ ++ int i; ++ struct tcp_ack_info *ack_info; ++ struct tcp_ack_manage *ack_m = &priv->ack_m; ++ ++ printk("%s \n", __func__); ++ memset(ack_m, 0, sizeof(struct tcp_ack_manage)); ++ ack_m->priv = priv; ++ spin_lock_init(&ack_m->lock); ++ atomic_set(&ack_m->max_drop_cnt, TCP_ACK_DROP_CNT); ++ ack_m->last_time = jiffies; ++ ack_m->timeout = msecs_to_jiffies(ACK_OLD_TIME); ++ ++ for (i = 0; i < TCP_ACK_NUM; i++) { ++ ack_info = &ack_m->ack_info[i]; ++ ack_info->ack_info_num = i; ++ seqlock_init(&ack_info->seqlock); ++ ack_info->last_time = jiffies; ++ ack_info->timeout = msecs_to_jiffies(ACK_OLD_TIME); ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) ++ setup_timer(&ack_info->timer, tcp_ack_timeout, ++ (unsigned long)ack_info); ++#else ++ timer_setup(&ack_info->timer, tcp_ack_timeout, 0); ++#endif ++ } ++ ++ atomic_set(&ack_m->enable, 1); ++ ack_m->ack_winsize = MIN_WIN; ++} ++ ++void tcp_ack_deinit(struct rwnx_hw *priv) ++{ ++ int i; ++ struct tcp_ack_manage *ack_m = &priv->ack_m; ++ struct msg_buf *drop_msg = NULL; ++ ++ printk("%s \n", __func__); ++ atomic_set(&ack_m->enable, 0); ++ ++ for (i = 0; i < TCP_ACK_NUM; i++) { ++ drop_msg = NULL; ++ ++ write_seqlock_bh(&ack_m->ack_info[i].seqlock); ++ timer_delete(&ack_m->ack_info[i].timer); ++ drop_msg = ack_m->ack_info[i].msgbuf; ++ ack_m->ack_info[i].msgbuf = NULL; ++ write_sequnlock_bh(&ack_m->ack_info[i].seqlock); ++ ++ if (drop_msg) ++ intf_tcp_drop_msg(priv, drop_msg); //drop skb ++ } ++} ++ ++int tcp_check_quick_ack(unsigned char *buf, struct tcp_ack_msg *msg) ++{ ++ int ip_hdr_len; ++ unsigned char *temp; ++ struct ethhdr *ethhdr; ++ struct iphdr *iphdr; ++ struct tcphdr *tcphdr; ++ ++ ethhdr = (struct ethhdr *)buf; ++ if (ethhdr->h_proto != htons(ETH_P_IP)) ++ return 0; ++ iphdr = (struct iphdr *)(ethhdr + 1); ++ if (iphdr->version != 4 || iphdr->protocol != IPPROTO_TCP) ++ return 0; ++ ip_hdr_len = iphdr->ihl * 4; ++ temp = (unsigned char *)(iphdr) + ip_hdr_len; ++ tcphdr = (struct tcphdr *)temp; ++ /* TCP_FLAG_ACK */ ++ if (!(temp[13] & 0x10)) ++ return 0; ++ ++ if (temp[13] & 0x8) { ++ msg->saddr = iphdr->daddr; ++ msg->daddr = iphdr->saddr; ++ msg->source = tcphdr->dest; ++ msg->dest = tcphdr->source; ++ msg->seq = ntohl(tcphdr->seq); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++int is_drop_tcp_ack(struct tcphdr *tcphdr, int tcp_tot_len, ++ unsigned short *win_scale) ++{ ++ //printk("%s \n",__func__); ++ int drop = 1; ++ int len = tcphdr->doff * 4; ++ unsigned char *ptr; ++ ++ if (tcp_tot_len > len) { ++ drop = 0; ++ } else { ++ len -= sizeof(struct tcphdr); ++ ptr = (unsigned char *)(tcphdr + 1); ++ ++ while ((len > 0) && drop) { ++ int opcode = *ptr++; ++ int opsize; ++ ++ switch (opcode) { ++ case TCPOPT_EOL: ++ break; ++ case TCPOPT_NOP: ++ len--; ++ continue; ++ default: ++ opsize = *ptr++; ++ if (opsize < 2) ++ break; ++ if (opsize > len) ++ break; ++ ++ switch (opcode) { ++ /* TODO: Add other ignore opt */ ++ case TCPOPT_TIMESTAMP: ++ break; ++ case TCPOPT_WINDOW: ++ if (*ptr < 15) ++ *win_scale = (1 << (*ptr)); ++ //printk("%d\n",*win_scale); ++ break; ++ default: ++ drop = 2; ++ } ++ ++ ptr += opsize - 2; ++ len -= opsize; ++ } ++ } ++ } ++ ++ return drop; ++} ++ ++/* flag:0 for not tcp ack ++ * 1 for ack which can be drop ++ * 2 for other ack whith more info ++ */ ++ ++int tcp_check_ack(unsigned char *buf, struct tcp_ack_msg *msg, ++ unsigned short *win_scale) ++{ ++ int ret; ++ int ip_hdr_len; ++ int tcp_tot_len; ++ unsigned char *temp; ++ struct ethhdr *ethhdr; ++ struct iphdr *iphdr; ++ struct tcphdr *tcphdr; ++ ++ ethhdr = (struct ethhdr *)buf; ++ if (ethhdr->h_proto != htons(ETH_P_IP)) ++ return 0; ++ ++ iphdr = (struct iphdr *)(ethhdr + 1); ++ if (iphdr->version != 4 || iphdr->protocol != IPPROTO_TCP) ++ return 0; ++ ++ ip_hdr_len = iphdr->ihl * 4; ++ temp = (unsigned char *)(iphdr) + ip_hdr_len; ++ tcphdr = (struct tcphdr *)temp; ++ /* TCP_FLAG_ACK */ ++ if (!(temp[13] & 0x10)) ++ return 0; ++ ++ tcp_tot_len = ntohs(iphdr->tot_len) - ip_hdr_len; // tcp total len ++ ret = is_drop_tcp_ack(tcphdr, tcp_tot_len, win_scale); ++ //printk("is drop:%d \n",ret); ++ ++ if (ret > 0) { ++ msg->saddr = iphdr->saddr; ++ msg->daddr = iphdr->daddr; ++ msg->source = tcphdr->source; ++ msg->dest = tcphdr->dest; ++ msg->seq = ntohl(tcphdr->ack_seq); ++ msg->win = ntohs(tcphdr->window); ++ } ++ ++ return ret; ++} ++ ++/* return val: -1 for not match, others for match */ ++int tcp_ack_match(struct tcp_ack_manage *ack_m, struct tcp_ack_msg *ack_msg) ++{ ++ int i, ret = -1; ++ unsigned start; ++ struct tcp_ack_info *ack_info; ++ struct tcp_ack_msg *ack; ++ ++ for (i = 0; ((ret < 0) && (i < TCP_ACK_NUM)); i++) { ++ ack_info = &ack_m->ack_info[i]; ++ do { ++ start = read_seqbegin(&ack_info->seqlock); ++ ret = -1; ++ ++ ack = &ack_info->ack_msg; ++ if (ack_info->busy && ack->dest == ack_msg->dest && ++ ack->source == ack_msg->source && ++ ack->saddr == ack_msg->saddr && ++ ack->daddr == ack_msg->daddr) ++ ret = i; ++ } while (read_seqretry(&ack_info->seqlock, start)); ++ } ++ ++ return ret; ++} ++ ++void tcp_ack_update(struct tcp_ack_manage *ack_m) ++{ ++ int i; ++ struct tcp_ack_info *ack_info; ++ ++ if (time_after(jiffies, ack_m->last_time + ack_m->timeout)) { ++ spin_lock_bh(&ack_m->lock); ++ ack_m->last_time = jiffies; ++ for (i = TCP_ACK_NUM - 1; i >= 0; i--) { ++ ack_info = &ack_m->ack_info[i]; ++ write_seqlock_bh(&ack_info->seqlock); ++ if (ack_info->busy && ++ time_after(jiffies, ack_info->last_time + ++ ack_info->timeout)) { ++ ack_m->free_index = i; ++ ack_m->max_num--; ++ ack_info->busy = 0; ++ } ++ write_sequnlock_bh(&ack_info->seqlock); ++ } ++ spin_unlock_bh(&ack_m->lock); ++ } ++} ++ ++/* return val: -1 for no index, others for index */ ++int tcp_ack_alloc_index(struct tcp_ack_manage *ack_m) ++{ ++ int i, ret = -1; ++ struct tcp_ack_info *ack_info; ++ unsigned start; ++ ++ spin_lock_bh(&ack_m->lock); ++ if (ack_m->max_num == TCP_ACK_NUM) { ++ spin_unlock_bh(&ack_m->lock); ++ return -1; ++ } ++ ++ if (ack_m->free_index >= 0) { ++ i = ack_m->free_index; ++ ack_m->free_index = -1; ++ ack_m->max_num++; ++ spin_unlock_bh(&ack_m->lock); ++ return i; ++ } ++ ++ for (i = 0; ((ret < 0) && (i < TCP_ACK_NUM)); i++) { ++ ack_info = &ack_m->ack_info[i]; ++ do { ++ start = read_seqbegin(&ack_info->seqlock); ++ ret = -1; ++ if (!ack_info->busy) { ++ ack_m->free_index = -1; ++ ack_m->max_num++; ++ ret = i; ++ } ++ } while (read_seqretry(&ack_info->seqlock, start)); ++ } ++ spin_unlock_bh(&ack_m->lock); ++ ++ return ret; ++} ++ ++/* return val: 0 for not handle tx, 1 for handle tx */ ++int tcp_ack_handle(struct msg_buf *new_msgbuf, struct tcp_ack_manage *ack_m, ++ struct tcp_ack_info *ack_info, struct tcp_ack_msg *ack_msg, ++ int type) ++{ ++ int quick_ack = 0; ++ struct tcp_ack_msg *ack; ++ int ret = 0; ++ struct msg_buf *drop_msg = NULL; ++ ++ //printk("%s %d",__func__,type); ++ write_seqlock_bh(&ack_info->seqlock); ++ ++ ack_info->last_time = jiffies; ++ ack = &ack_info->ack_msg; ++ ++ if (type == 2) { ++ if (U32_BEFORE(ack->seq, ack_msg->seq)) { ++ ack->seq = ack_msg->seq; ++ if (ack_info->psh_flag && ++ !U32_BEFORE(ack_msg->seq, ack_info->psh_seq)) { ++ ack_info->psh_flag = 0; ++ } ++ ++ if (ack_info->msgbuf) { ++ //printk("%lx \n",ack_info->msgbuf); ++ drop_msg = ack_info->msgbuf; ++ ack_info->msgbuf = NULL; ++ timer_delete(&ack_info->timer); ++ } else { ++ //printk("msgbuf is NULL \n"); ++ } ++ ++ ack_info->in_send_msg = NULL; ++ ack_info->drop_cnt = atomic_read(&ack_m->max_drop_cnt); ++ } else { ++ printk("%s before abnormal ack: %d, %d\n", __func__, ++ ack->seq, ack_msg->seq); ++ drop_msg = new_msgbuf; ++ ret = 1; ++ } ++ } else if (U32_BEFORE(ack->seq, ack_msg->seq)) { ++ if (ack_info->msgbuf) { ++ drop_msg = ack_info->msgbuf; ++ ack_info->msgbuf = NULL; ++ } ++ ++ if (ack_info->psh_flag && ++ !U32_BEFORE(ack_msg->seq, ack_info->psh_seq)) { ++ ack_info->psh_flag = 0; ++ quick_ack = 1; ++ } else { ++ ack_info->drop_cnt++; ++ } ++ ++ ack->seq = ack_msg->seq; ++ ++ if (quick_ack || (!ack_info->in_send_msg && ++ (ack_info->drop_cnt >= ++ atomic_read(&ack_m->max_drop_cnt)))) { ++ ack_info->drop_cnt = 0; ++ ack_info->in_send_msg = new_msgbuf; ++ timer_delete(&ack_info->timer); ++ } else { ++ ret = 1; ++ ack_info->msgbuf = new_msgbuf; ++ if (!timer_pending(&ack_info->timer)) ++ mod_timer(&ack_info->timer, ++ (jiffies + msecs_to_jiffies(5))); ++ } ++ } else { ++ printk("%s before ack: %d, %d\n", __func__, ack->seq, ++ ack_msg->seq); ++ drop_msg = new_msgbuf; ++ ret = 1; ++ } ++ ++ write_sequnlock_bh(&ack_info->seqlock); ++ ++ if (drop_msg) ++ intf_tcp_drop_msg(ack_m->priv, drop_msg); // drop skb ++ ++ return ret; ++} ++ ++int tcp_ack_handle_new(struct msg_buf *new_msgbuf, struct tcp_ack_manage *ack_m, ++ struct tcp_ack_info *ack_info, ++ struct tcp_ack_msg *ack_msg, int type) ++{ ++ int quick_ack = 0; ++ struct tcp_ack_msg *ack; ++ int ret = 0; ++ struct msg_buf *drop_msg = NULL; ++ //struct msg_buf * send_msg = NULL; ++ //printk("",); ++ write_seqlock_bh(&ack_info->seqlock); ++ ++ ack_info->last_time = jiffies; ++ ack = &ack_info->ack_msg; ++ ++ if (U32_BEFORE(ack->seq, ack_msg->seq)) { ++ if (ack_info->msgbuf) { ++ drop_msg = ack_info->msgbuf; ++ ack_info->msgbuf = NULL; ++ //ack_info->drop_cnt++; ++ } ++ ++ if (ack_info->psh_flag && ++ !U32_BEFORE(ack_msg->seq, ack_info->psh_seq)) { ++ ack_info->psh_flag = 0; ++ quick_ack = 1; ++ } else { ++ ack_info->drop_cnt++; ++ } ++ ++ ack->seq = ack_msg->seq; ++ ++ if (quick_ack || (!ack_info->in_send_msg && ++ (ack_info->drop_cnt >= ++ atomic_read(&ack_m->max_drop_cnt)))) { ++ ack_info->drop_cnt = 0; ++ //send_msg = new_msgbuf; ++ ack_info->in_send_msg = new_msgbuf; ++ timer_delete(&ack_info->timer); ++ } else { ++ ret = 1; ++ ack_info->msgbuf = new_msgbuf; ++ if (!timer_pending(&ack_info->timer)) ++ mod_timer(&ack_info->timer, ++ (jiffies + msecs_to_jiffies(5))); ++ } ++ ++ //ret = 1; ++ } else { ++ printk("%s before ack: %d, %d\n", __func__, ack->seq, ++ ack_msg->seq); ++ drop_msg = new_msgbuf; ++ ret = 1; ++ } ++ ++ /*if(send_msg){ ++ intf_tx(ack_m->priv,send_msg); ++ ack_info->in_send_msg=NULL; ++ }*/ ++ ++ //ack_info->in_send_msg=NULL; ++ ++ write_sequnlock_bh(&ack_info->seqlock); ++ ++ /*if(send_msg){ ++ intf_tx(ack_m->priv,send_msg); ++ //ack_info->in_send_msg=NULL; ++ }*/ ++ ++ if (drop_msg) ++ intf_tcp_drop_msg(ack_m->priv, drop_msg); // drop skb ++ ++ return ret; ++} ++ ++void filter_rx_tcp_ack(struct rwnx_hw *priv, unsigned char *buf, unsigned plen) ++{ ++ int index; ++ struct tcp_ack_msg ack_msg; ++ struct tcp_ack_info *ack_info; ++ struct tcp_ack_manage *ack_m = &priv->ack_m; ++ ++ if (!atomic_read(&ack_m->enable)) ++ return; ++ ++ if ((plen > MAX_TCP_ACK) || !tcp_check_quick_ack(buf, &ack_msg)) ++ return; ++ ++ index = tcp_ack_match(ack_m, &ack_msg); ++ if (index >= 0) { ++ ack_info = ack_m->ack_info + index; ++ write_seqlock_bh(&ack_info->seqlock); ++ ack_info->psh_flag = 1; ++ ack_info->psh_seq = ack_msg.seq; ++ write_sequnlock_bh(&ack_info->seqlock); ++ } ++} ++ ++/* return val: 0 for not filter, 1 for filter */ ++int filter_send_tcp_ack(struct rwnx_hw *priv, struct msg_buf *msgbuf, ++ unsigned char *buf, unsigned int plen) ++{ ++ //printk("%s \n",__func__); ++ int ret = 0; ++ int index, drop; ++ unsigned short win_scale = 0; ++ unsigned int win = 0; ++ struct tcp_ack_msg ack_msg; ++ struct tcp_ack_msg *ack; ++ struct tcp_ack_info *ack_info; ++ struct tcp_ack_manage *ack_m = &priv->ack_m; ++ ++ tcp_ack_update(ack_m); ++ drop = tcp_check_ack(buf, &ack_msg, &win_scale); ++ //printk("drop:%d win_scale:%d",drop,win_scale); ++ if (!drop && (0 == win_scale)) ++ return 0; ++ ++ index = tcp_ack_match(ack_m, &ack_msg); ++ if (index >= 0) { ++ ack_info = ack_m->ack_info + index; ++ if ((0 != win_scale) && (ack_info->win_scale != win_scale)) { ++ write_seqlock_bh(&ack_info->seqlock); ++ ack_info->win_scale = win_scale; ++ write_sequnlock_bh(&ack_info->seqlock); ++ } ++ ++ if (drop > 0 && atomic_read(&ack_m->enable)) { ++ win = ack_info->win_scale * ack_msg.win; ++ if ((win_scale != 0) && ++ (win < (ack_m->ack_winsize * SIZE_KB))) { ++ drop = 2; ++ printk("%d %d %d", win_scale, win, ++ (ack_m->ack_winsize * SIZE_KB)); ++ } ++ ret = tcp_ack_handle_new(msgbuf, ack_m, ack_info, ++ &ack_msg, drop); ++ } ++ ++ goto out; ++ } ++ ++ index = tcp_ack_alloc_index(ack_m); ++ if (index >= 0) { ++ write_seqlock_bh(&ack_m->ack_info[index].seqlock); ++ ack_m->ack_info[index].busy = 1; ++ ack_m->ack_info[index].psh_flag = 0; ++ ack_m->ack_info[index].last_time = jiffies; ++ ack_m->ack_info[index].drop_cnt = ++ atomic_read(&ack_m->max_drop_cnt); ++ ack_m->ack_info[index].win_scale = ++ (win_scale != 0) ? win_scale : 1; ++ ++ //ack_m->ack_info[index].msgbuf = NULL; ++ //ack_m->ack_info[index].in_send_msg = NULL; ++ ack = &ack_m->ack_info[index].ack_msg; ++ ack->dest = ack_msg.dest; ++ ack->source = ack_msg.source; ++ ack->saddr = ack_msg.saddr; ++ ack->daddr = ack_msg.daddr; ++ ack->seq = ack_msg.seq; ++ write_sequnlock_bh(&ack_m->ack_info[index].seqlock); ++ } ++ ++out: ++ return ret; ++} ++ ++void move_tcpack_msg(struct rwnx_hw *priv, struct msg_buf *msg) ++{ ++ struct tcp_ack_info *ack_info; ++ struct tcp_ack_manage *ack_m = &priv->ack_m; ++ int i = 0; ++ ++ if (!atomic_read(&ack_m->enable)) ++ return; ++ ++ //if (msg->len > MAX_TCP_ACK) ++ // return; ++ ++ for (i = 0; i < TCP_ACK_NUM; i++) { ++ ack_info = &ack_m->ack_info[i]; ++ write_seqlock_bh(&ack_info->seqlock); ++ if (ack_info->busy && (ack_info->in_send_msg == msg)) ++ ack_info->in_send_msg = NULL; ++ write_sequnlock_bh(&ack_info->seqlock); ++ } ++} +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_tcp_ack.h b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_tcp_ack.h +new file mode 100755 +index 000000000..f415e8caf +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_tcp_ack.h +@@ -0,0 +1,90 @@ ++#ifndef _AICWF_TCP_ACK_H_ ++#define _AICWF_TCP_ACK_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define TCP_ACK_NUM 32 ++#define TCP_ACK_EXIT_VAL 0x800 ++#define TCP_ACK_DROP_CNT 10 ++ ++#define ACK_OLD_TIME 4000 ++#define U32_BEFORE(a, b) ((__s32)((__u32)a - (__u32)b) <= 0) ++ ++#define MAX_TCP_ACK 200 ++/*min window size in KB, it's 256KB*/ ++#define MIN_WIN 256 ++#define SIZE_KB 1024 ++ ++struct msg_buf { ++ //struct list_head list; ++ struct sk_buff *skb; ++ struct rwnx_vif *rwnx_vif; ++ /* data just tx cmd use,not include the head */ ++}; ++ ++struct tcp_ack_msg { ++ u16 source; ++ u16 dest; ++ s32 saddr; ++ s32 daddr; ++ u32 seq; ++ u16 win; ++}; ++ ++struct tcp_ack_info { ++ int ack_info_num; ++ int busy; ++ int drop_cnt; ++ int psh_flag; ++ u32 psh_seq; ++ u16 win_scale; ++ /* seqlock for ack info */ ++ seqlock_t seqlock; ++ unsigned long last_time; ++ unsigned long timeout; ++ struct timer_list timer; ++ struct msg_buf *msgbuf; ++ struct msg_buf *in_send_msg; ++ struct tcp_ack_msg ack_msg; ++}; ++ ++struct tcp_ack_manage { ++ /* 1 filter */ ++ atomic_t enable; ++ int max_num; ++ int free_index; ++ unsigned long last_time; ++ unsigned long timeout; ++ atomic_t max_drop_cnt; ++ /* lock for tcp ack alloc and free */ ++ spinlock_t lock; ++ struct rwnx_hw *priv; ++ struct tcp_ack_info ack_info[TCP_ACK_NUM]; ++ /*size in KB*/ ++ unsigned int ack_winsize; ++}; ++ ++struct msg_buf *intf_tcp_alloc_msg(struct msg_buf *msg); ++ ++void tcp_ack_init(struct rwnx_hw *priv); ++ ++void tcp_ack_deinit(struct rwnx_hw *priv); ++ ++int is_drop_tcp_ack(struct tcphdr *tcphdr, int tcp_tot_len, ++ unsigned short *win_scale); ++ ++int is_tcp_ack(struct sk_buff *skb, unsigned short *win_scale); ++ ++int filter_send_tcp_ack(struct rwnx_hw *priv, struct msg_buf *msgbuf, ++ unsigned char *buf, unsigned int plen); ++ ++void filter_rx_tcp_ack(struct rwnx_hw *priv, unsigned char *buf, unsigned plen); ++ ++void move_tcpack_msg(struct rwnx_hw *priv, struct msg_buf *msg); ++#endif +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_txrxif.c b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_txrxif.c +new file mode 100755 +index 000000000..9b5d7acf1 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_txrxif.c +@@ -0,0 +1,960 @@ ++/** ++ * aicwf_bus.c ++ * ++ * bus function declarations ++ * ++ * Copyright (C) AICSemi 2018-2020 ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "lmac_msg.h" ++#include "aicwf_txrxif.h" ++#include "rwnx_platform.h" ++#include "rwnx_defs.h" ++#include "rwnx_msg_rx.h" ++#include "rwnx_rx.h" ++#include "aicwf_rx_prealloc.h" ++#ifdef AICWF_SDIO_SUPPORT ++#include "sdio_host.h" ++#endif ++#include "aic_bsp_export.h" ++ ++#ifdef CONFIG_PREALLOC_RX_SKB ++void aicwf_rxframe_queue_init_2(struct rx_frame_queue *pq, int max_len) ++{ ++ //int prio; ++ ++ memset(pq, 0, ++ offsetof(struct rx_frame_queue, queuelist) + ++ (sizeof(struct list_head))); ++ pq->qmax = (u16)max_len; ++ INIT_LIST_HEAD(&pq->queuelist); ++#if 0 ++ memset(pq, 0, offsetof(struct rx_frame_queue, queuelist) + (sizeof(struct list_head) * num_prio)); ++ pq->num_prio = (u16)num_prio; ++ pq->qmax = (u16)max_len; ++ ++ for (prio = 0; prio < num_prio; prio++) { ++ INIT_LIST_HEAD(&pq->queuelist[prio]); ++ } ++#endif ++} ++ ++//extern struct aic_sdio_dev *g_sdiodev; ++void rxbuff_queue_flush(struct aicwf_rx_priv *rx_priv) ++{ ++ //int prio; ++ struct rx_frame_queue *pq = &rx_priv->rxq; ++ struct list_head *pos; ++ struct list_head *n; ++ struct list_head *head; ++ struct rx_buff *tempbuf = NULL; ++ ++ head = &pq->queuelist; ++ list_for_each_safe (pos, n, head) { ++ tempbuf = list_entry(pos, struct rx_buff, queue); ++ list_del_init(&tempbuf->queue); ++#if 0 ++ rxbuff_free(tempbuf); ++#else ++ aicwf_prealloc_rxbuff_free(tempbuf, &rx_priv->rxbuff_lock); ++#endif ++ pq->qcnt--; ++ } ++} ++#endif ++ ++int aicwf_bus_init(uint bus_hdrlen, struct device *dev) ++{ ++ int ret = 0; ++ struct aicwf_bus *bus_if; ++ ++ if (!dev) { ++ txrx_err("device not found\n"); ++ return -1; ++ } ++ 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; ++ } ++ memset(bus_if->cmd_buf, '\0', CMD_BUF_MAX); ++ ++ init_completion(&bus_if->bustx_trgg); ++ init_completion(&bus_if->busrx_trgg); ++ //new oob feature ++ init_completion(&bus_if->busirq_trgg); ++#ifdef AICWF_SDIO_SUPPORT ++ spin_lock_init(&bus_if->bus_priv.sdio->wslock); //AIDEN test ++ bus_if->bustx_thread = kthread_run(sdio_bustx_thread, (void *)bus_if, ++ "aicwf_bustx_thread"); ++ bus_if->busrx_thread = ++ kthread_run(sdio_busrx_thread, ++ (void *)bus_if->bus_priv.sdio->rx_priv, ++ "aicwf_busrx_thread"); ++ //new oob feature ++#ifdef CONFIG_OOB ++ if (bus_if->bus_priv.sdio->oob_enable) { ++ bus_if->busirq_thread = ++ kthread_run(sdio_busirq_thread, ++ (void *)bus_if->bus_priv.sdio->rx_priv, ++ "aicwf_busirq_thread"); ++ } ++#endif //CONFIG_OOB ++#endif ++#ifdef AICWF_USB_SUPPORT ++ bus_if->bustx_thread = kthread_run(usb_bustx_thread, (void *)bus_if, ++ "aicwf_bustx_thread"); ++ bus_if->busrx_thread = ++ kthread_run(usb_busrx_thread, ++ (void *)bus_if->bus_priv.usb->rx_priv, ++ "aicwf_busrx_thread"); ++#endif ++ ++ if (IS_ERR(bus_if->bustx_thread)) { ++ bus_if->bustx_thread = NULL; ++ txrx_err("aicwf_bustx_thread run fail\n"); ++ goto fail; ++ } ++ ++ if (IS_ERR(bus_if->busrx_thread)) { ++ bus_if->busrx_thread = NULL; ++ txrx_err("aicwf_bustx_thread run fail\n"); ++ goto fail; ++ } ++ ++ return ret; ++fail: ++ aicwf_bus_deinit(dev); ++ ++ return ret; ++} ++ ++void aicwf_bus_deinit(struct device *dev) ++{ ++ struct aicwf_bus *bus_if; ++#ifdef AICWF_USB_SUPPORT ++ struct aic_usb_dev *usb; ++#endif ++#ifdef AICWF_SDIO_SUPPORT ++ struct aic_sdio_dev *sdiodev; ++#endif ++ ++ if (!dev) { ++ txrx_err("device not found\n"); ++ return; ++ } ++ AICWFDBG(LOGINFO, "%s Enter\r\n", __func__); ++ bus_if = dev_get_drvdata(dev); ++ aicwf_bus_stop(bus_if); ++ ++#ifdef AICWF_USB_SUPPORT ++ usb = bus_if->bus_priv.usb; ++ if (g_rwnx_plat->enabled) ++ rwnx_platform_deinit(usb->rwnx_hw); ++#endif ++#ifdef AICWF_SDIO_SUPPORT ++ sdiodev = bus_if->bus_priv.sdio; ++ if (g_rwnx_plat && g_rwnx_plat->enabled) { ++ rwnx_platform_deinit(sdiodev->rwnx_hw); ++ } ++#endif ++ ++ if (bus_if->cmd_buf) { ++ kfree(bus_if->cmd_buf); ++ bus_if->cmd_buf = NULL; ++ } ++ ++ if (bus_if->bustx_thread) { ++ complete_all(&bus_if->bustx_trgg); ++ kthread_stop(bus_if->bustx_thread); ++ bus_if->bustx_thread = NULL; ++ } ++ AICWFDBG(LOGINFO, "%s Exit\r\n", __func__); ++} ++ ++void aicwf_frame_tx(void *dev, struct sk_buff *skb) ++{ ++#ifdef AICWF_SDIO_SUPPORT ++ struct aic_sdio_dev *sdiodev = (struct aic_sdio_dev *)dev; ++ aicwf_bus_txdata(sdiodev->bus_if, skb); ++#else ++ struct aic_usb_dev *usbdev = (struct aic_usb_dev *)dev; ++ ++ if (!usbdev->state) { ++ txrx_err("down\n"); ++ aicwf_usb_tx_flowctrl(usbdev->rwnx_hw, true); ++ dev_kfree_skb(skb); ++ return; ++ } ++ aicwf_bus_txdata(usbdev->bus_if, skb); ++#endif ++} ++ ++struct aicwf_tx_priv *aicwf_tx_init(void *arg) ++{ ++ struct aicwf_tx_priv *tx_priv; ++ ++ tx_priv = kzalloc(sizeof(struct aicwf_tx_priv), GFP_KERNEL); ++ if (!tx_priv) ++ return NULL; ++ ++#ifdef AICWF_SDIO_SUPPORT ++ tx_priv->sdiodev = (struct aic_sdio_dev *)arg; ++#else ++ tx_priv->usbdev = (struct aic_usb_dev *)arg; ++#endif ++ ++ atomic_set(&tx_priv->aggr_count, 0); ++#ifdef CONFIG_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); ++ return NULL; ++ } ++ tx_priv->head = tx_priv->aggr_buf->data; ++ tx_priv->tail = tx_priv->aggr_buf->data; ++ ++#ifdef CONFIG_SDIO_ADMA ++ tx_priv->aggr_segcnt = 0; ++ tx_priv->len = 0; ++#endif ++ ++ return tx_priv; ++} ++ ++void aicwf_tx_deinit(struct aicwf_tx_priv *tx_priv) ++{ ++ if (tx_priv && tx_priv->aggr_buf) { ++#ifdef CONFIG_RESV_MEM_SUPPORT ++ aicbsp_resv_mem_kfree_skb(tx_priv->aggr_buf, ++ AIC_RESV_MEM_TXDATA); ++#else ++ dev_kfree_skb(tx_priv->aggr_buf); ++#endif ++ kfree(tx_priv); ++ } ++#ifdef CONFIG_SDIO_ADMA ++ aicwf_sdio_aggrbuf_reset(tx_priv); ++#endif ++} ++ ++#ifdef AICWF_SDIO_SUPPORT ++#ifdef CONFIG_PREALLOC_RX_SKB ++static bool aicwf_another_ptk_1(struct rx_buff *buffer) ++{ ++ u8 *read = buffer->read; ++ u16 aggr_len = 0; ++ ++ BUG_ON((read - buffer->start) % 4 != 0); ++ ++ if (read == NULL || read >= buffer->end) { ++ return false; ++ } ++ ++ aggr_len = (*read | (*(read + 1) << 8)); ++ if (aggr_len == 0) { ++ return false; ++ } ++ ++ return true; ++} ++#else ++static bool aicwf_another_ptk(struct sk_buff *skb) ++{ ++ u8 *data; ++ u16 aggr_len = 0; ++ ++ if (skb->data == NULL || skb->len == 0) { ++ return false; ++ } ++ data = skb->data; ++ aggr_len = (*skb->data | (*(skb->data + 1) << 8)); ++ if (aggr_len == 0) { ++ return false; ++ } ++ ++ return true; ++} ++#endif ++#endif ++ ++int aicwf_process_rxframes(struct aicwf_rx_priv *rx_priv) ++{ ++#ifdef AICWF_SDIO_SUPPORT ++ int ret = 0; ++ unsigned long flags = 0; ++#ifndef CONFIG_PREALLOC_RX_SKB ++ struct sk_buff *skb = NULL; ++#endif ++ u16 pkt_len = 0; ++ struct sk_buff *skb_inblock = NULL; ++ u16 aggr_len = 0, adjust_len = 0; ++ u8 *data = NULL; ++ u8_l *msg = NULL; ++#ifdef CONFIG_PREALLOC_RX_SKB ++ struct rx_buff *buffer = NULL; ++ ++ while (1) { ++ spin_lock_irqsave(&rx_priv->rxqlock, flags); ++ if (!rx_priv->rxq.qcnt) { ++ spin_unlock_irqrestore(&rx_priv->rxqlock, flags); ++ break; ++ } ++ buffer = rxbuff_dequeue(&rx_priv->rxq); ++ spin_unlock_irqrestore(&rx_priv->rxqlock, flags); ++ if (buffer == NULL) { ++ txrx_err("skb_error\r\n"); ++ break; ++ } ++ while (aicwf_another_ptk_1(buffer)) { ++ data = buffer->read; ++ pkt_len = (*data | (*(data + 1) << 8)); ++ ++ if ((data[2] & SDIO_TYPE_CFG) != ++ SDIO_TYPE_CFG) { // type : data ++ aggr_len = pkt_len + RX_HWHRD_LEN; ++ ++ if (aggr_len & (RX_ALIGNMENT - 1)) ++ adjust_len = ++ roundup(aggr_len, RX_ALIGNMENT); ++ 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"); ++ buffer->read = ++ buffer->read + adjust_len; ++ continue; ++ } ++ ++ 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); ++ buffer->read = buffer->read + 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_prealloc_rxbuff_free( ++ buffer, &rx_priv->rxbuff_lock); ++ return -EBADE; ++ } ++ ++ memcpy(msg, data, aggr_len + 4); ++ if (((*(msg + 2) & 0x7f) == ++ SDIO_TYPE_CFG_CMD_RSP) && ++ (rx_priv->sdiodev->bus_if->state != ++ BUS_DOWN_ST)) ++ 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); ++ ++ buffer->read = buffer->read + (adjust_len + 4); ++ kfree(msg); ++ } ++ } ++ ++ aicwf_prealloc_rxbuff_free(buffer, &rx_priv->rxbuff_lock); ++ ++ atomic_dec(&rx_priv->rx_cnt); ++ } ++ ++#else ++ ++ while (1) { ++ spin_lock_irqsave(&rx_priv->rxqlock, flags); ++ if (aicwf_is_framequeue_empty(&rx_priv->rxq)) { ++ spin_unlock_irqrestore(&rx_priv->rxqlock, flags); ++ break; ++ } ++ skb = aicwf_frame_dequeue(&rx_priv->rxq); ++ spin_unlock_irqrestore(&rx_priv->rxqlock, flags); ++ if (skb == NULL) { ++ txrx_err("skb_error\r\n"); ++ break; ++ } ++ while (aicwf_another_ptk(skb)) { ++ data = skb->data; ++ pkt_len = (*skb->data | (*(skb->data + 1) << 8)); ++ ++ if ((skb->data[2] & SDIO_TYPE_CFG) != ++ SDIO_TYPE_CFG) { // type : data ++ aggr_len = pkt_len + RX_HWHRD_LEN; ++ ++ if (aggr_len & (RX_ALIGNMENT - 1)) ++ adjust_len = ++ roundup(aggr_len, RX_ALIGNMENT); ++ 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_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) && ++ (rx_priv->sdiodev->bus_if->state != ++ BUS_DOWN_ST)) ++ 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); ++ } ++ } ++ ++ dev_kfree_skb(skb); ++ atomic_dec(&rx_priv->rx_cnt); ++ } ++#endif ++ ++#if defined(CONFIG_SDIO_PWRCTRL) ++ aicwf_sdio_pwr_stctl(rx_priv->sdiodev, SDIO_ACTIVE_ST); ++#endif ++ ++ return ret; ++#else //AICWF_USB_SUPPORT ++ int ret = 0; ++ unsigned long flags = 0; ++ struct sk_buff *skb = NULL; /* Packet for event or data frames */ ++ u16 pkt_len = 0; ++ struct sk_buff *skb_inblock = NULL; ++ u16 aggr_len = 0, adjust_len = 0; ++ u8 *data = NULL; ++ u8_l *msg = NULL; ++ ++ while (1) { ++ spin_lock_irqsave(&rx_priv->rxqlock, flags); ++ if (aicwf_is_framequeue_empty(&rx_priv->rxq)) { ++ usb_info("no more rxdata\n"); ++ spin_unlock_irqrestore(&rx_priv->rxqlock, flags); ++ break; ++ } ++ skb = aicwf_frame_dequeue(&rx_priv->rxq); ++ spin_unlock_irqrestore(&rx_priv->rxqlock, flags); ++ if (skb == NULL) { ++ txrx_err("skb_error\r\n"); ++ break; ++ } ++ data = skb->data; ++ pkt_len = (*skb->data | (*(skb->data + 1) << 8)); ++ //printk("p:%d, s:%d , %x\n", pkt_len, skb->len, data[2]); ++ if (pkt_len > 1600) { ++ dev_kfree_skb(skb); ++ atomic_dec(&rx_priv->rx_cnt); ++ continue; ++ } ++ ++ if ((skb->data[2] & USB_TYPE_CFG) != ++ USB_TYPE_CFG) { // type : data ++ aggr_len = pkt_len + RX_HWHRD_LEN; ++ if (aggr_len & (RX_ALIGNMENT - 1)) ++ adjust_len = roundup(aggr_len, RX_ALIGNMENT); ++ 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_put(skb_inblock, aggr_len); ++ memcpy(skb_inblock->data, data, aggr_len); ++ rwnx_rxdataind_aicwf(rx_priv->usbdev->rwnx_hw, ++ skb_inblock, (void *)rx_priv); ++ ///TODO: here need to add rx data process ++ ++ 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) == USB_TYPE_CFG_CMD_RSP) ++ rwnx_rx_handle_msg( ++ rx_priv->usbdev->rwnx_hw, ++ (struct ipc_e2a_msg *)(msg + 4)); ++ ++ if ((*(msg + 2) & 0x7f) == USB_TYPE_CFG_DATA_CFM) ++ aicwf_usb_host_tx_cfm_handler( ++ &(rx_priv->usbdev->rwnx_hw->usb_env), ++ (u32 *)(msg + 4)); ++ skb_pull(skb, adjust_len + 4); ++ kfree(msg); ++ } ++ ++ dev_kfree_skb(skb); ++ atomic_dec(&rx_priv->rx_cnt); ++ } ++ ++ return ret; ++#endif //AICWF_SDIO_SUPPORT ++} ++ ++static struct recv_msdu *aicwf_rxframe_queue_init(struct list_head *q, ++ int qsize) ++{ ++ int i; ++ struct recv_msdu *req, *reqs; ++ ++ reqs = vmalloc(qsize * sizeof(struct recv_msdu)); ++ if (reqs == NULL) ++ return NULL; ++ ++ req = reqs; ++ for (i = 0; i < qsize; i++) { ++ INIT_LIST_HEAD(&req->rxframe_list); ++ list_add(&req->rxframe_list, q); ++ req++; ++ } ++ ++ return reqs; ++} ++ ++struct aicwf_rx_priv *aicwf_rx_init(void *arg) ++{ ++ struct aicwf_rx_priv *rx_priv; ++ rx_priv = kzalloc(sizeof(struct aicwf_rx_priv), GFP_KERNEL); ++ if (!rx_priv) ++ return NULL; ++ ++#ifdef AICWF_SDIO_SUPPORT ++ rx_priv->sdiodev = (struct aic_sdio_dev *)arg; ++#else ++ rx_priv->usbdev = (struct aic_usb_dev *)arg; ++#endif ++ ++#ifdef CONFIG_PREALLOC_RX_SKB ++ aicwf_rxframe_queue_init_2(&rx_priv->rxq, MAX_RXQLEN); ++#else ++ aicwf_frame_queue_init(&rx_priv->rxq, 1, MAX_RXQLEN); ++#endif ++ spin_lock_init(&rx_priv->rxqlock); ++#ifdef CONFIG_PREALLOC_RX_SKB ++ spin_lock_init(&rx_priv->rxbuff_lock); ++ aicwf_prealloc_init(); ++#endif ++ atomic_set(&rx_priv->rx_cnt, 0); ++ ++#ifdef AICWF_RX_REORDER ++ INIT_LIST_HEAD(&rx_priv->rxframes_freequeue); ++ spin_lock_init(&rx_priv->freeq_lock); ++ rx_priv->recv_frames = aicwf_rxframe_queue_init( ++ &rx_priv->rxframes_freequeue, MAX_REORD_RXFRAME); ++ if (!rx_priv->recv_frames) { ++ txrx_err("no enough buffer for free recv frame queue!\n"); ++ kfree(rx_priv); ++ return NULL; ++ } ++ spin_lock_init(&rx_priv->stas_reord_lock); ++ INIT_LIST_HEAD(&rx_priv->stas_reord_list); ++#endif ++ ++ return rx_priv; ++} ++ ++static void aicwf_recvframe_queue_deinit(struct list_head *q) ++{ ++ struct recv_msdu *req, *next; ++ ++ list_for_each_entry_safe (req, next, q, rxframe_list) { ++ list_del_init(&req->rxframe_list); ++ } ++} ++ ++void aicwf_rx_deinit(struct aicwf_rx_priv *rx_priv) ++{ ++#ifdef AICWF_RX_REORDER ++ struct reord_ctrl_info *reord_info, *tmp; ++ ++ AICWFDBG(LOGINFO, "%s\n", __func__); ++ ++ list_for_each_entry_safe (reord_info, tmp, &rx_priv->stas_reord_list, ++ list) { ++ reord_deinit_sta(rx_priv, reord_info); ++ } ++#endif ++ ++#ifdef AICWF_SDIO_SUPPORT ++ AICWFDBG(LOGINFO, "sdio rx thread\n"); ++ if (rx_priv->sdiodev->bus_if->busrx_thread) { ++ complete_all(&rx_priv->sdiodev->bus_if->busrx_trgg); ++ kthread_stop(rx_priv->sdiodev->bus_if->busrx_thread); ++ rx_priv->sdiodev->bus_if->busrx_thread = NULL; ++ } ++#ifdef CONFIG_OOB ++ if (rx_priv->sdiodev->oob_enable) { ++ //new oob feature ++ if (rx_priv->sdiodev->bus_if->busirq_thread) { ++ complete_all(&rx_priv->sdiodev->bus_if->busirq_trgg); ++ kthread_stop(rx_priv->sdiodev->bus_if->busirq_thread); ++ rx_priv->sdiodev->bus_if->busirq_thread = NULL; ++ } ++ } ++#endif //CONFIG_OOB ++#endif ++#ifdef AICWF_USB_SUPPORT ++ if (rx_priv->usbdev->bus_if->busrx_thread) { ++ 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; ++ } ++#endif ++ ++#ifdef CONFIG_PREALLOC_RX_SKB ++ rxbuff_queue_flush(rx_priv); ++#else ++ aicwf_frame_queue_flush(&rx_priv->rxq); ++#endif ++ ++#ifdef AICWF_RX_REORDER ++ aicwf_recvframe_queue_deinit(&rx_priv->rxframes_freequeue); ++ if (rx_priv->recv_frames) ++ vfree(rx_priv->recv_frames); ++#endif ++ ++#ifdef CONFIG_PREALLOC_RX_SKB ++ aicwf_prealloc_exit(); ++#endif ++ kfree(rx_priv); ++ ++ AICWFDBG(LOGINFO, "%s exit \n", __func__); ++} ++ ++bool aicwf_rxframe_enqueue(struct device *dev, struct frame_queue *q, ++ struct sk_buff *pkt) ++{ ++ return aicwf_frame_enq(dev, q, pkt, 0); ++} ++ ++void aicwf_dev_skb_free(struct sk_buff *skb) ++{ ++ if (!skb) ++ return; ++ ++ dev_kfree_skb_any(skb); ++} ++ ++static struct sk_buff *aicwf_frame_queue_penq(struct frame_queue *pq, int prio, ++ struct sk_buff *p) ++{ ++ struct sk_buff_head *q; ++ ++ if (pq->queuelist[prio].qlen >= pq->qmax) ++ return NULL; ++ ++ q = &pq->queuelist[prio]; ++ __skb_queue_tail(q, p); ++ pq->qcnt++; ++ if (pq->hi_prio < prio) ++ pq->hi_prio = (u16)prio; ++ ++ return p; ++} ++ ++void aicwf_frame_queue_flush(struct frame_queue *pq) ++{ ++ int prio; ++ struct sk_buff_head *q; ++ struct sk_buff *p, *next; ++ ++ for (prio = 0; prio < pq->num_prio; prio++) { ++ q = &pq->queuelist[prio]; ++ skb_queue_walk_safe(q, p, next) ++ { ++ skb_unlink(p, q); ++ aicwf_dev_skb_free(p); ++ pq->qcnt--; ++ } ++ } ++} ++ ++void aicwf_frame_queue_init(struct frame_queue *pq, int num_prio, int max_len) ++{ ++ int prio; ++ ++ memset(pq, 0, ++ offsetof(struct frame_queue, queuelist) + ++ (sizeof(struct sk_buff_head) * num_prio)); ++ pq->num_prio = (u16)num_prio; ++ pq->qmax = (u16)max_len; ++ ++ for (prio = 0; prio < num_prio; prio++) { ++ skb_queue_head_init(&pq->queuelist[prio]); ++ } ++} ++ ++struct sk_buff *aicwf_frame_queue_peek_tail(struct frame_queue *pq, ++ int *prio_out) ++{ ++ int prio; ++ ++ if (pq->qcnt == 0) ++ return NULL; ++ ++ for (prio = 0; prio < pq->hi_prio; prio++) ++ if (!skb_queue_empty(&pq->queuelist[prio])) ++ break; ++ ++ if (prio_out) ++ *prio_out = prio; ++ ++ return skb_peek_tail(&pq->queuelist[prio]); ++} ++ ++bool aicwf_is_framequeue_empty(struct frame_queue *pq) ++{ ++ int prio, len = 0; ++ ++ for (prio = 0; prio <= pq->hi_prio; prio++) ++ len += pq->queuelist[prio].qlen; ++ ++ if (len > 0) ++ return false; ++ else ++ return true; ++} ++ ++struct sk_buff *aicwf_frame_dequeue(struct frame_queue *pq) ++{ ++ struct sk_buff_head *q; ++ struct sk_buff *p; ++ int prio; ++ ++ if (pq->qcnt == 0) ++ return NULL; ++ ++ while ((prio = pq->hi_prio) > 0 && ++ skb_queue_empty(&pq->queuelist[prio])) ++ pq->hi_prio--; ++ ++ q = &pq->queuelist[prio]; ++ p = __skb_dequeue(q); ++ if (p == NULL) ++ return NULL; ++ ++ pq->qcnt--; ++ ++ return p; ++} ++#if 0 ++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; ++} ++#endif ++ ++bool aicwf_frame_enq(struct device *dev, struct frame_queue *q, ++ struct sk_buff *pkt, int prio) ++{ ++#if 0 ++ 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 ++ if (q->queuelist[prio].qlen < q->qmax && q->qcnt < q->qmax) { ++ aicwf_frame_queue_penq(q, prio, pkt); ++ return true; ++ } else ++ return false; ++#endif ++} ++ ++#ifdef CONFIG_PREALLOC_RX_SKB ++void rxbuff_free(struct rx_buff *rxbuff) ++{ ++ kfree(rxbuff->data); ++ kfree(rxbuff); ++} ++ ++struct rx_buff *rxbuff_queue_penq(struct rx_frame_queue *pq, struct rx_buff *p) ++{ ++ struct list_head *q; ++ if (pq->qcnt >= pq->qmax) ++ return NULL; ++ ++ q = &pq->queuelist; ++ list_add_tail(&p->queue, q); ++ ++ pq->qcnt++; ++ ++ return p; ++} ++ ++struct rx_buff *rxbuff_dequeue(struct rx_frame_queue *pq) ++{ ++ struct rx_buff *p = NULL; ++ ++ if (pq->qcnt == 0) { ++ printk("%s %d, rxq is empty\n", __func__, __LINE__); ++ return NULL; ++ } ++ ++ if (list_empty(&pq->queuelist)) { ++ printk("%s %d, rxq is empty\n", __func__, __LINE__); ++ return NULL; ++ } else { ++ p = list_first_entry(&pq->queuelist, struct rx_buff, queue); ++ list_del_init(&p->queue); ++ pq->qcnt--; ++ } ++ ++ return p; ++} ++ ++bool aicwf_rxbuff_enqueue(struct device *dev, struct rx_frame_queue *rxq, ++ struct rx_buff *pkt) ++{ ++ // struct rx_buff *p = NULL; ++ ++ if ((rxq == NULL) || (pkt == NULL)) { ++ printk("%s %d, rxq or pkt is NULL\n", __func__, __LINE__); ++ return false; ++ } ++ ++ if (rxq->qcnt < rxq->qmax) { ++ if (rxbuff_queue_penq(rxq, pkt)) { ++ return true; ++ } else { ++ printk("%s %d, rxbuff enqueue fail\n", __func__, ++ __LINE__); ++ return false; ++ } ++ } else { ++ printk("%s %d, rxq or pkt is full\n", __func__, __LINE__); ++ return false; ++ } ++} ++#endif +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_txrxif.h b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_txrxif.h +new file mode 100755 +index 000000000..2ec52cf20 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_txrxif.h +@@ -0,0 +1,287 @@ ++/** ++ * aicwf_txrxif.h ++ * ++ * bus function declarations ++ * ++ * Copyright (C) AICSemi 2018-2020 ++ */ ++ ++#ifndef _AICWF_TXRXIF_H_ ++#define _AICWF_TXRXIF_H_ ++ ++#include ++#include ++#include "ipc_shared.h" ++#include "aicwf_rx_prealloc.h" ++#ifdef AICWF_SDIO_SUPPORT ++#include "aicwf_sdio.h" ++#else ++#include "aicwf_usb.h" ++#endif ++ ++#define CMD_BUF_MAX 1536 ++#define TXPKT_BLOCKSIZE 512 ++#define MAX_AGGR_TXPKT_LEN (1536 * 64) ++#define CMD_TX_TIMEOUT 5000 ++#define TX_ALIGNMENT 4 ++ ++#define RX_HWHRD_LEN 60 //58->60 word allined ++#define CCMP_OR_WEP_INFO 8 ++#define MAX_RXQLEN 2000 ++#define RX_ALIGNMENT 4 ++ ++#define DEBUG_ERROR_LEVEL 0 ++#define DEBUG_DEBUG_LEVEL 1 ++#define DEBUG_INFO_LEVEL 2 ++ ++#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__) ++#if DBG_LEVEL >= DEBUG_DEBUG_LEVEL ++#define txrx_dbg(fmt, ...) printk("txrx: " fmt, ##__VA_ARGS__) ++#define sdio_dbg(fmt, ...) printk("aicsdio: " fmt, ##__VA_ARGS__) ++#define usb_dbg(fmt, ...) printk("aicusb: " fmt, ##__VA_ARGS__) ++#else ++#define txrx_dbg(fmt, ...) ++#define sdio_dbg(fmt, ...) ++#define usb_dbg(fmt, ...) ++#endif ++#if DBG_LEVEL >= DEBUG_INFO_LEVEL ++#define txrx_info(fmt, ...) printk("aicsdio: " fmt, ##__VA_ARGS__) ++#define sdio_info(fmt, ...) printk("aicsdio: " fmt, ##__VA_ARGS__) ++#define usb_info(fmt, ...) printk("aicusb: " fmt, ##__VA_ARGS__) ++#else ++#define txrx_info(fmt, ...) ++#define sdio_info(fmt, ...) ++#define usb_info(fmt, ...) ++#endif ++ ++enum aicwf_bus_state { BUS_DOWN_ST, BUS_UP_ST }; ++ ++struct aicwf_bus_ops { ++ int (*start)(struct device *dev); ++ void (*stop)(struct device *dev); ++ int (*txdata)(struct device *dev, struct sk_buff *skb); ++ int (*txmsg)(struct device *dev, u8 *msg, uint len); ++}; ++ ++struct frame_queue { ++ u16 num_prio; ++ u16 hi_prio; ++ u16 qmax; /* max number of queued frames */ ++ u16 qcnt; ++ struct sk_buff_head queuelist[8]; ++}; ++ ++#ifdef CONFIG_PREALLOC_RX_SKB ++struct rx_frame_queue { ++ u16 qmax; /* max number of queued frames */ ++ u16 qcnt; ++ struct list_head queuelist; ++}; ++#endif ++ ++struct aicwf_bus { ++ union { ++ struct aic_sdio_dev *sdio; ++ struct aic_usb_dev *usb; ++ } bus_priv; ++ struct device *dev; ++ struct aicwf_bus_ops *ops; ++ enum aicwf_bus_state state; ++ u8 *cmd_buf; ++ struct completion bustx_trgg; ++ struct completion busrx_trgg; ++ struct completion busirq_trgg; //new oob feature ++ struct task_struct *bustx_thread; ++ struct task_struct *busrx_thread; ++ struct task_struct *busirq_thread; //new oob feature ++}; ++ ++#ifdef CONFIG_SDIO_ADMA ++#define SDIO_HEADER_LEN 4 ++#define SDIO_DATA_FAKE_LEN 2 ++#define SDIO_MGMT_FAKE_LEN 4 ++#define ALIGN4_ADJ_LEN(x) ((4 - (x & 3)) & 3) ++ ++#define SDIO_TX_SLIST_MAX 136 ++ ++/*struct tx_scatterlist { ++ const void *buf; ++ unsigned int len; ++};*/ ++#endif ++ ++struct aicwf_tx_priv { ++#ifdef AICWF_SDIO_SUPPORT ++ struct aic_sdio_dev *sdiodev; ++ int fw_avail_bufcnt; ++ //for cmd tx ++ u8 *cmd_buf; ++ uint cmd_len; ++ bool cmd_txstate; ++ bool cmd_tx_succ; ++ struct semaphore cmd_txsema; ++ wait_queue_head_t cmd_txdone_wait; ++ //for data tx ++ atomic_t tx_pktcnt; ++ ++ struct frame_queue txq; ++ spinlock_t txqlock; ++ struct semaphore txctl_sema; ++#endif ++#ifdef AICWF_USB_SUPPORT ++ struct aic_usb_dev *usbdev; ++#endif ++ struct sk_buff *aggr_buf; ++ atomic_t aggr_count; ++ u8 *head; ++ u8 *tail; ++ ++#ifdef CONFIG_SDIO_ADMA ++ struct tx_scatterlist sg_list[SDIO_TX_SLIST_MAX]; ++ void *free_buf[SDIO_TX_SLIST_MAX]; ++ bool copyd[SDIO_TX_SLIST_MAX]; ++ u32 aggr_segcnt; ++ u32 len; ++#endif ++}; ++ ++#define DEFRAG_MAX_WAIT 40 //100 ++#ifdef AICWF_RX_REORDER ++#define MAX_REORD_RXFRAME 250 ++#define REORDER_UPDATE_TIME 50 ++#define AICWF_REORDER_WINSIZE 64 ++#define SN_LESS(a, b) (((a - b) & 0x800) != 0) ++#define SN_EQUAL(a, b) (a == b) ++ ++struct reord_ctrl { ++ struct aicwf_rx_priv *rx_priv; ++ u8 enable; ++ u16 ind_sn; ++ u8 wsize_b; ++ spinlock_t reord_list_lock; ++ struct list_head reord_list; ++ struct timer_list reord_timer; ++ struct work_struct reord_timer_work; ++}; ++ ++struct reord_ctrl_info { ++ u8 mac_addr[6]; ++ struct reord_ctrl preorder_ctrl[8]; ++ struct list_head list; ++}; ++ ++struct recv_msdu { ++ struct sk_buff *pkt; ++ u8 tid; ++ u16 seq_num; ++ u8 forward; ++ //uint len; ++ u32 is_amsdu; ++ u8 *rx_data; ++ //for pending rx reorder list ++ struct list_head reord_pending_list; ++ //for total frame list, when rxframe from busif, dequeue, when submit frame to net, enqueue ++ struct list_head rxframe_list; ++ struct reord_ctrl *preorder_ctrl; ++}; ++#endif ++ ++struct aicwf_rx_priv { ++#ifdef AICWF_SDIO_SUPPORT ++ struct aic_sdio_dev *sdiodev; ++#endif ++#ifdef AICWF_USB_SUPPORT ++ struct aic_usb_dev *usbdev; ++#endif ++ ++ void *rwnx_vif; ++ atomic_t rx_cnt; ++ u32 data_len; ++ spinlock_t rxqlock; ++#ifdef CONFIG_PREALLOC_RX_SKB ++ struct rx_frame_queue rxq; ++#else ++ struct frame_queue rxq; ++#endif ++ ++#ifdef AICWF_RX_REORDER ++ spinlock_t freeq_lock; ++ struct list_head rxframes_freequeue; ++ struct list_head stas_reord_list; ++ spinlock_t stas_reord_lock; ++ struct recv_msdu *recv_frames; ++#endif ++#ifdef CONFIG_PREALLOC_RX_SKB ++ spinlock_t rxbuff_lock; ++#endif ++}; ++ ++static inline int aicwf_bus_start(struct aicwf_bus *bus) ++{ ++ return bus->ops->start(bus->dev); ++} ++ ++static inline void aicwf_bus_stop(struct aicwf_bus *bus) ++{ ++ bus->ops->stop(bus->dev); ++} ++ ++static inline int aicwf_bus_txdata(struct aicwf_bus *bus, struct sk_buff *skb) ++{ ++ return bus->ops->txdata(bus->dev, skb); ++} ++ ++static inline int aicwf_bus_txmsg(struct aicwf_bus *bus, u8 *msg, uint len) ++{ ++ return bus->ops->txmsg(bus->dev, msg, len); ++} ++ ++static inline void aicwf_sched_timeout(u32 millisec) ++{ ++ ulong timeout = 0, expires = 0; ++ expires = jiffies + msecs_to_jiffies(millisec); ++ timeout = millisec; ++ ++ while (timeout) { ++ timeout = schedule_timeout(timeout); ++ if (time_after(jiffies, expires)) ++ break; ++ } ++} ++ ++int aicwf_bus_init(uint bus_hdrlen, struct device *dev); ++void aicwf_bus_deinit(struct device *dev); ++void aicwf_tx_deinit(struct aicwf_tx_priv *tx_priv); ++void aicwf_rx_deinit(struct aicwf_rx_priv *rx_priv); ++struct aicwf_tx_priv *aicwf_tx_init(void *arg); ++struct aicwf_rx_priv *aicwf_rx_init(void *arg); ++void aicwf_frame_queue_init(struct frame_queue *pq, int num_prio, int max_len); ++void aicwf_frame_queue_flush(struct frame_queue *pq); ++bool aicwf_frame_enq(struct device *dev, struct frame_queue *q, ++ struct sk_buff *pkt, int prio); ++bool aicwf_rxframe_enqueue(struct device *dev, struct frame_queue *q, ++ struct sk_buff *pkt); ++bool aicwf_is_framequeue_empty(struct frame_queue *pq); ++void aicwf_frame_tx(void *dev, struct sk_buff *skb); ++void aicwf_dev_skb_free(struct sk_buff *skb); ++struct sk_buff *aicwf_frame_dequeue(struct frame_queue *pq); ++struct sk_buff *aicwf_frame_queue_peek_tail(struct frame_queue *pq, ++ int *prio_out); ++#ifdef CONFIG_PREALLOC_RX_SKB ++void rxbuff_queue_flush(struct aicwf_rx_priv *rx_priv); ++void aicwf_rxframe_queue_init_2(struct rx_frame_queue *pq, int max_len); ++void rxbuff_free(struct rx_buff *rxbuff); ++struct rx_buff *rxbuff_dequeue(struct rx_frame_queue *pq); ++bool aicwf_rxbuff_enqueue(struct device *dev, struct rx_frame_queue *rxq, ++ struct rx_buff *pkt); ++extern struct aicwf_rx_buff_list aic_rx_buff_list; ++#endif ++ ++#endif /* _AICWF_TXRXIF_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_usb.h b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_usb.h +new file mode 100755 +index 000000000..b5715d5fe +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/aicwf_usb.h +@@ -0,0 +1,95 @@ ++/** ++ * aicwf_usb.h ++ * ++ * USB function declarations ++ * ++ * Copyright (C) AICSemi 2018-2020 ++ */ ++ ++#ifndef _AICWF_USB_H_ ++#define _AICWF_USB_H_ ++ ++#include ++#include "rwnx_cmds.h" ++ ++#ifdef AICWF_USB_SUPPORT ++ ++/* USB Device ID */ ++#define USB_VENDOR_ID_AIC 0xA69C ++ ++#ifndef CONFIG_USB_BT ++#define USB_PRODUCT_ID_AIC 0x8800 ++#else ++#define USB_PRODUCT_ID_AIC 0x8801 ++#endif ++ ++#define AICWF_USB_RX_URBS (200) ++#define AICWF_USB_TX_URBS (100) ++#define AICWF_USB_TX_LOW_WATER (AICWF_USB_TX_URBS / 4) ++#define AICWF_USB_TX_HIGH_WATER (AICWF_USB_TX_LOW_WATER * 3) ++#define AICWF_USB_MAX_PKT_SIZE (2048) ++ ++typedef enum { ++ USB_TYPE_DATA = 0X00, ++ USB_TYPE_CFG = 0X10, ++ USB_TYPE_CFG_CMD_RSP = 0X11, ++ USB_TYPE_CFG_DATA_CFM = 0X12 ++} usb_type; ++ ++enum aicwf_usb_state { USB_DOWN_ST, USB_UP_ST, USB_SLEEP_ST }; ++ ++struct aicwf_usb_buf { ++ struct list_head list; ++ struct aic_usb_dev *usbdev; ++ struct urb *urb; ++ struct sk_buff *skb; ++ bool cfm; ++}; ++ ++struct aic_usb_dev { ++ struct rwnx_hw *rwnx_hw; ++ struct aicwf_bus *bus_if; ++ struct usb_device *udev; ++ struct device *dev; ++ struct aicwf_rx_priv *rx_priv; ++ enum aicwf_usb_state state; ++ struct rwnx_cmd_mgr cmd_mgr; ++ ++ struct usb_anchor rx_submitted; ++ struct work_struct rx_urb_work; ++ ++ spinlock_t rx_free_lock; ++ spinlock_t tx_free_lock; ++ spinlock_t tx_post_lock; ++ spinlock_t tx_flow_lock; ++ ++ struct list_head rx_free_list; ++ struct list_head tx_free_list; ++ struct list_head tx_post_list; ++ ++ uint bulk_in_pipe; ++ uint bulk_out_pipe; ++ ++ int tx_free_count; ++ int tx_post_count; ++ ++ struct aicwf_usb_buf usb_tx_buf[AICWF_USB_TX_URBS]; ++ struct aicwf_usb_buf usb_rx_buf[AICWF_USB_RX_URBS]; ++ ++ int msg_finished; ++ wait_queue_head_t msg_wait; ++ ulong msg_busy; ++ struct urb *msg_out_urb; ++ ++ bool tbusy; ++}; ++ ++extern void aicwf_usb_exit(void); ++extern void aicwf_usb_register(void); ++extern void aicwf_usb_tx_flowctrl(struct rwnx_hw *rwnx_hw, bool state); ++int usb_bustx_thread(void *data); ++int usb_busrx_thread(void *data); ++extern void aicwf_hostif_ready(void); ++ ++#endif /* AICWF_USB_SUPPORT */ ++#endif /* _AICWF_USB_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/hal_desc.h b/drivers/net/wireless/aic8800/aic8800_fdrv/hal_desc.h +new file mode 100755 +index 000000000..f47a55c43 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/hal_desc.h +@@ -0,0 +1,382 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file hal_desc.h ++ * ++ * @brief File containing the definition of HW descriptors. ++ * ++ * Contains the definition and structures used by HW ++ * ++ * Copyright (C) RivieraWaves 2011-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++#ifndef _HAL_DESC_H_ ++#define _HAL_DESC_H_ ++ ++#include "lmac_types.h" ++ ++/* Rate and policy table */ ++ ++#define N_CCK 8 ++#define N_OFDM 8 ++#define N_HT (8 * 2 * 2 * 4) ++#define N_VHT (10 * 4 * 2 * 8) ++#define N_HE_SU (12 * 4 * 3 * 8) ++#define N_HE_MU (12 * 6 * 3 * 8) ++#define N_HE_ER (3 * 3 + 3) //RU242 + RU106 ++ ++/* conversion table from NL80211 to MACHW enum */ ++extern const int chnl2bw[]; ++ ++/* conversion table from MACHW to NL80211 enum */ ++extern const int bw2chnl[]; ++ ++/* Rate cntrl info */ ++#define MCS_INDEX_TX_RCX_OFT 0 ++#define MCS_INDEX_TX_RCX_MASK (0x7F << MCS_INDEX_TX_RCX_OFT) ++#define BW_TX_RCX_OFT 7 ++#define BW_TX_RCX_MASK (0x3 << BW_TX_RCX_OFT) ++#define SHORT_GI_TX_RCX_OFT 9 ++#define SHORT_GI_TX_RCX_MASK (0x1 << SHORT_GI_TX_RCX_OFT) ++#define PRE_TYPE_TX_RCX_OFT 10 ++#define PRE_TYPE_TX_RCX_MASK (0x1 << PRE_TYPE_TX_RCX_OFT) ++#define FORMAT_MOD_TX_RCX_OFT 11 ++#define FORMAT_MOD_TX_RCX_MASK (0x7 << FORMAT_MOD_TX_RCX_OFT) ++ ++/* Values for formatModTx */ ++#define FORMATMOD_NON_HT 0 ++#define FORMATMOD_NON_HT_DUP_OFDM 1 ++#define FORMATMOD_HT_MF 2 ++#define FORMATMOD_HT_GF 3 ++#define FORMATMOD_VHT 4 ++#define FORMATMOD_HE_SU 5 ++#define FORMATMOD_HE_MU 6 ++#define FORMATMOD_HE_ER 7 ++#define FORMATMOD_HE_TB 8 ++ ++/* Values for navProtFrmEx */ ++#define NAV_PROT_NO_PROT_BIT 0 ++#define NAV_PROT_SELF_CTS_BIT 1 ++#define NAV_PROT_RTS_CTS_BIT 2 ++#define NAV_PROT_RTS_CTS_WITH_QAP_BIT 3 ++#define NAV_PROT_STBC_BIT 4 ++ ++/* THD MACCTRLINFO2 fields, used in struct umacdesc umac.flags */ ++/// WhichDescriptor definition - contains aMPDU bit and position value ++/// Offset of WhichDescriptor field in the MAC CONTROL INFO 2 word ++#define WHICHDESC_OFT 19 ++/// Mask of the WhichDescriptor field ++#define WHICHDESC_MSK (0x07 << WHICHDESC_OFT) ++/// Only 1 THD possible, describing an unfragmented MSDU ++#define WHICHDESC_UNFRAGMENTED_MSDU (0x00 << WHICHDESC_OFT) ++/// THD describing the first MPDU of a fragmented MSDU ++#define WHICHDESC_FRAGMENTED_MSDU_FIRST (0x01 << WHICHDESC_OFT) ++/// THD describing intermediate MPDUs of a fragmented MSDU ++#define WHICHDESC_FRAGMENTED_MSDU_INT (0x02 << WHICHDESC_OFT) ++/// THD describing the last MPDU of a fragmented MSDU ++#define WHICHDESC_FRAGMENTED_MSDU_LAST (0x03 << WHICHDESC_OFT) ++/// THD for extra descriptor starting an AMPDU ++#define WHICHDESC_AMPDU_EXTRA (0x04 << WHICHDESC_OFT) ++/// THD describing the first MPDU of an A-MPDU ++#define WHICHDESC_AMPDU_FIRST (0x05 << WHICHDESC_OFT) ++/// THD describing intermediate MPDUs of an A-MPDU ++#define WHICHDESC_AMPDU_INT (0x06 << WHICHDESC_OFT) ++/// THD describing the last MPDU of an A-MPDU ++#define WHICHDESC_AMPDU_LAST (0x07 << WHICHDESC_OFT) ++ ++/// aMPDU bit offset ++#define AMPDU_OFT 21 ++/// aMPDU bit ++#define AMPDU_BIT CO_BIT(AMPDU_OFT) ++ ++union rwnx_mcs_index { ++ struct { ++ u32 mcs : 3; ++ u32 nss : 2; ++ } ht; ++ struct { ++ u32 mcs : 4; ++ u32 nss : 3; ++ } vht; ++ struct { ++ u32 mcs : 4; ++ u32 nss : 3; ++ } he; ++ u32 legacy : 7; ++}; ++ ++enum { ++ HW_RATE_1MBPS = 0, ++ HW_RATE_2MBPS = 1, ++ HW_RATE_5_5MBPS = 2, ++ HW_RATE_11MBPS = 3, ++ HW_RATE_6MBPS = 4, ++ HW_RATE_9MBPS = 5, ++ HW_RATE_12MBPS = 6, ++ HW_RATE_18MBPS = 7, ++ HW_RATE_24MBPS = 8, ++ HW_RATE_36MBPS = 9, ++ HW_RATE_48MBPS = 10, ++ HW_RATE_54MBPS = 11, ++ HW_RATE_MAX ++}; ++ ++/* c.f RW-WLAN-nX-MAC-HW-UM */ ++union rwnx_rate_ctrl_info { ++ struct { ++ u32 mcsIndexTx : 7; ++ u32 bwTx : 2; ++ u32 giAndPreTypeTx : 2; ++ u32 formatModTx : 3; ++ u32 navProtFrmEx : 3; ++ u32 mcsIndexProtTx : 7; ++ u32 bwProtTx : 2; ++ u32 formatModProtTx : 3; ++ u32 nRetry : 3; ++ }; ++ u32 value; ++}; ++ ++/* c.f RW-WLAN-nX-MAC-HW-UM */ ++struct rwnx_power_ctrl_info { ++ u32 txPwrLevelPT : 8; ++ u32 txPwrLevelProtPT : 8; ++ u32 reserved : 16; ++}; ++ ++/* c.f RW-WLAN-nX-MAC-HW-UM */ ++union rwnx_pol_phy_ctrl_info_1 { ++ struct { ++ u32 rsvd1 : 3; ++ u32 bfFrmEx : 1; ++ u32 numExtnSS : 2; ++ u32 fecCoding : 1; ++ u32 stbc : 2; ++ u32 rsvd2 : 5; ++ u32 nTx : 3; ++ u32 nTxProt : 3; ++ }; ++ u32 value; ++}; ++ ++/* c.f RW-WLAN-nX-MAC-HW-UM */ ++union rwnx_pol_phy_ctrl_info_2 { ++ struct { ++ u32 antennaSet : 8; ++ u32 smmIndex : 8; ++ u32 beamFormed : 1; ++ }; ++ u32 value; ++}; ++ ++/* c.f RW-WLAN-nX-MAC-HW-UM */ ++union rwnx_pol_mac_ctrl_info_1 { ++ struct { ++ u32 keySRamIndex : 10; ++ u32 keySRamIndexRA : 10; ++ }; ++ u32 value; ++}; ++ ++/* c.f RW-WLAN-nX-MAC-HW-UM */ ++union rwnx_pol_mac_ctrl_info_2 { ++ struct { ++ u32 longRetryLimit : 8; ++ u32 shortRetryLimit : 8; ++ u32 rtsThreshold : 12; ++ }; ++ u32 value; ++}; ++ ++#define POLICY_TABLE_PATTERN 0xBADCAB1E ++ ++struct tx_policy_tbl { ++ /* Unique Pattern at the start of Policy Table */ ++ u32 upatterntx; ++ /* PHY Control 1 Information used by MAC HW */ ++ union rwnx_pol_phy_ctrl_info_1 phyctrlinfo_1; ++ /* PHY Control 2 Information used by MAC HW */ ++ union rwnx_pol_phy_ctrl_info_2 phyctrlinfo_2; ++ /* MAC Control 1 Information used by MAC HW */ ++ union rwnx_pol_mac_ctrl_info_1 macctrlinfo_1; ++ /* MAC Control 2 Information used by MAC HW */ ++ union rwnx_pol_mac_ctrl_info_2 macctrlinfo_2; ++ ++ union rwnx_rate_ctrl_info ratectrlinfos[NX_TX_MAX_RATES]; ++ struct rwnx_power_ctrl_info powerctrlinfos[NX_TX_MAX_RATES]; ++}; ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ ++/** ++ * struct rwnx_hw_txstatus - Bitfield of confirmation status ++ * ++ * @tx_done: packet has been processed by the firmware. ++ * @retry_required: packet has been transmitted but not acknoledged. ++ * Driver must repush it. ++ * @sw_retry_required: packet has not been transmitted (FW wasn't able to push ++ * it when it received it: not active channel ...). Driver must repush it. ++ * @acknowledged: packet has been acknowledged by peer ++ */ ++union rwnx_hw_txstatus { ++ struct { ++ u32 tx_done : 1; ++ u32 retry_required : 1; ++ u32 sw_retry_required : 1; ++ u32 acknowledged : 1; ++ u32 reserved : 28; ++ }; ++ u32 value; ++}; ++ ++/** ++ * struct tx_cfm_tag - Structure indicating the status and other ++ * information about the transmission ++ * ++ * @pn: PN that was used for the transmission ++ * @sn: Sequence number of the packet ++ * @timestamp: Timestamp of first transmission of this MPDU ++ * @credits: Number of credits to be reallocated for the txq that push this ++ * buffer (can be 0 or 1) ++ * @ampdu_size: Size of the ampdu in which the frame has been transmitted if ++ * this was the last frame of the a-mpdu, and 0 if the frame is not the last ++ * frame on a a-mdpu. ++ * 1 means that the frame has been transmitted as a singleton. ++ * @amsdu_size: Size, in bytes, allowed to create a-msdu. ++ * @status: transmission status ++ */ ++struct tx_cfm_tag { ++ /* ++ u16_l pn[4]; ++ u16_l sn; ++ u16_l timestamp; ++*/ ++ s8_l credits; ++ u8_l ampdu_size; ++#ifdef CONFIG_RWNX_SPLIT_TX_BUF ++ u16_l amsdu_size; ++#endif ++ union rwnx_hw_txstatus status; ++ u32_l hostid; ++}; ++ ++/** ++ * struct rwnx_hw_txhdr - Hardware part of tx header ++ * ++ * @cfm: Information updated by fw/hardware after sending a frame ++ */ ++struct rwnx_hw_txhdr { ++ struct tx_cfm_tag cfm; ++}; ++ ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++/* Modem */ ++ ++#define MDM_PHY_CONFIG_TRIDENT 0 ++#define MDM_PHY_CONFIG_ELMA 1 ++#define MDM_PHY_CONFIG_KARST 2 ++ ++// MODEM features (from reg_mdm_stat.h) ++/// MUMIMOTX field bit ++#define MDM_MUMIMOTX_BIT ((u32)0x80000000) ++/// MUMIMOTX field position ++#define MDM_MUMIMOTX_POS 31 ++/// MUMIMORX field bit ++#define MDM_MUMIMORX_BIT ((u32)0x40000000) ++/// MUMIMORX field position ++#define MDM_MUMIMORX_POS 30 ++/// BFMER field bit ++#define MDM_BFMER_BIT ((u32)0x20000000) ++/// BFMER field position ++#define MDM_BFMER_POS 29 ++/// BFMEE field bit ++#define MDM_BFMEE_BIT ((u32)0x10000000) ++/// BFMEE field position ++#define MDM_BFMEE_POS 28 ++/// LDPCDEC field bit ++#define MDM_LDPCDEC_BIT ((u32)0x08000000) ++/// LDPCDEC field position ++#define MDM_LDPCDEC_POS 27 ++/// LDPCENC field bit ++#define MDM_LDPCENC_BIT ((u32)0x04000000) ++/// LDPCENC field position ++#define MDM_LDPCENC_POS 26 ++/// CHBW field mask ++#define MDM_CHBW_MASK ((u32)0x03000000) ++/// CHBW field LSB position ++#define MDM_CHBW_LSB 24 ++/// CHBW field width ++#define MDM_CHBW_WIDTH ((u32)0x00000002) ++/// DSSSCCK field bit ++#define MDM_DSSSCCK_BIT ((u32)0x00800000) ++/// DSSSCCK field position ++#define MDM_DSSSCCK_POS 23 ++/// VHT field bit ++#define MDM_VHT_BIT ((u32)0x00400000) ++/// VHT field position ++#define MDM_VHT_POS 22 ++/// HE field bit ++#define MDM_HE_BIT ((u32)0x00200000) ++/// HE field position ++#define MDM_HE_POS 21 ++/// ESS field bit ++#define MDM_ESS_BIT ((u32)0x00100000) ++/// ESS field position ++#define MDM_ESS_POS 20 ++/// RFMODE field mask ++#define MDM_RFMODE_MASK ((u32)0x000F0000) ++/// RFMODE field LSB position ++#define MDM_RFMODE_LSB 16 ++/// RFMODE field width ++#define MDM_RFMODE_WIDTH ((u32)0x00000004) ++/// NSTS field mask ++#define MDM_NSTS_MASK ((u32)0x0000F000) ++/// NSTS field LSB position ++#define MDM_NSTS_LSB 12 ++/// NSTS field width ++#define MDM_NSTS_WIDTH ((u32)0x00000004) ++/// NSS field mask ++#define MDM_NSS_MASK ((u32)0x00000F00) ++/// NSS field LSB position ++#define MDM_NSS_LSB 8 ++/// NSS field width ++#define MDM_NSS_WIDTH ((u32)0x00000004) ++/// NTX field mask ++#define MDM_NTX_MASK ((u32)0x000000F0) ++/// NTX field LSB position ++#define MDM_NTX_LSB 4 ++/// NTX field width ++#define MDM_NTX_WIDTH ((u32)0x00000004) ++/// NRX field mask ++#define MDM_NRX_MASK ((u32)0x0000000F) ++/// NRX field LSB position ++#define MDM_NRX_LSB 0 ++/// NRX field width ++#define MDM_NRX_WIDTH ((u32)0x00000004) ++ ++#define __MDM_PHYCFG_FROM_VERS(v) (((v)&MDM_RFMODE_MASK) >> MDM_RFMODE_LSB) ++ ++#define RIU_FCU_PRESENT_MASK ((u32)0xFF000000) ++#define RIU_FCU_PRESENT_LSB 24 ++ ++#define __RIU_FCU_PRESENT(v) \ ++ (((v)&RIU_FCU_PRESENT_MASK) >> RIU_FCU_PRESENT_LSB == 5) ++ ++/// AGC load version field mask ++#define RIU_AGC_LOAD_MASK ((u32)0x00C00000) ++/// AGC load version field LSB position ++#define RIU_AGC_LOAD_LSB 22 ++ ++#define __RIU_AGCLOAD_FROM_VERS(v) (((v)&RIU_AGC_LOAD_MASK) >> RIU_AGC_LOAD_LSB) ++ ++#define __FPGA_TYPE(v) (((v)&0xFFFF0000) >> 16) ++ ++#define __MDM_MAJOR_VERSION(v) (((v)&0xFF000000) >> 24) ++#define __MDM_MINOR_VERSION(v) (((v)&0x00FF0000) >> 16) ++#define __MDM_VERSION(v) \ ++ ((__MDM_MAJOR_VERSION(v) + 2) * 10 + __MDM_MINOR_VERSION(v)) ++ ++#endif // _HAL_DESC_H_ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_compat.h b/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_compat.h +new file mode 100755 +index 000000000..10cabd094 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_compat.h +@@ -0,0 +1,26 @@ ++/** ++ **************************************************************************************** ++ * ++ * @file ipc_compat.h ++ * ++ * Copyright (C) RivieraWaves 2011-2019 ++ * ++ **************************************************************************************** ++ */ ++ ++#ifndef _IPC_H_ ++#define _IPC_H_ ++ ++#define __INLINE inline ++ ++#define __ALIGN4 __aligned(4) ++ ++#define ASSERT_ERR(condition) \ ++ do { \ ++ if (unlikely(!(condition))) { \ ++ printk(KERN_ERR "%s:%d:ASSERT_ERR(" #condition ")\n", \ ++ __FILE__, __LINE__); \ ++ } \ ++ } while (0) ++ ++#endif /* _IPC_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_host.c b/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_host.c +new file mode 100755 +index 000000000..8a82a9bab +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_host.c +@@ -0,0 +1,47 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file ipc_host.c ++ * ++ * @brief IPC module. ++ * ++ * Copyright (C) RivieraWaves 2011-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++/* ++ * INCLUDE FILES ++ ****************************************************************************** ++ */ ++#ifndef __KERNEL__ ++#include ++#else ++#include ++#include "rwnx_defs.h" ++#include "rwnx_prof.h" ++#endif ++ ++#include "ipc_host.h" ++ ++/* ++ * TYPES DEFINITION ++ ****************************************************************************** ++ */ ++ ++const int nx_txdesc_cnt[] = { ++ NX_TXDESC_CNT0, NX_TXDESC_CNT1, NX_TXDESC_CNT2, NX_TXDESC_CNT3, ++#if NX_TXQ_CNT == 5 ++ NX_TXDESC_CNT4, ++#endif ++}; ++ ++const int nx_txuser_cnt[] = { ++ CONFIG_USER_MAX, ++ CONFIG_USER_MAX, ++ CONFIG_USER_MAX, ++ CONFIG_USER_MAX, ++#if NX_TXQ_CNT == 5 ++ 1, ++#endif ++}; +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_host.h b/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_host.h +new file mode 100755 +index 000000000..cc5b6a5eb +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_host.h +@@ -0,0 +1,167 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file ipc_host.h ++ * ++ * @brief IPC module. ++ * ++ * Copyright (C) RivieraWaves 2011-2019 ++ * ++ ****************************************************************************** ++ */ ++#ifndef _IPC_HOST_H_ ++#define _IPC_HOST_H_ ++ ++/* ++ * INCLUDE FILES ++ ****************************************************************************** ++ */ ++#include "ipc_shared.h" ++#ifndef __KERNEL__ ++#include "arch.h" ++#else ++#include "ipc_compat.h" ++#endif ++ ++/** ++ ****************************************************************************** ++ * @brief This structure is used to initialize the MAC SW ++ * ++ * The WLAN device driver provides functions call-back with this structure ++ ****************************************************************************** ++ */ ++struct ipc_host_cb_tag { ++ /// WLAN driver call-back function: send_data_cfm ++ int (*send_data_cfm)(void *pthis, void *host_id); ++ ++ /// WLAN driver call-back function: recv_data_ind ++ uint8_t (*recv_data_ind)(void *pthis, void *host_id); ++ ++ /// WLAN driver call-back function: recv_radar_ind ++ uint8_t (*recv_radar_ind)(void *pthis, void *host_id); ++ ++ /// WLAN driver call-back function: recv_unsup_rx_vec_ind ++ uint8_t (*recv_unsup_rx_vec_ind)(void *pthis, void *host_id); ++ ++ /// WLAN driver call-back function: recv_msg_ind ++ uint8_t (*recv_msg_ind)(void *pthis, void *host_id); ++ ++ /// WLAN driver call-back function: recv_msgack_ind ++ uint8_t (*recv_msgack_ind)(void *pthis, void *host_id); ++ ++ /// WLAN driver call-back function: recv_dbg_ind ++ uint8_t (*recv_dbg_ind)(void *pthis, void *host_id); ++ ++ /// WLAN driver call-back function: prim_tbtt_ind ++ void (*prim_tbtt_ind)(void *pthis); ++ ++ /// WLAN driver call-back function: sec_tbtt_ind ++ void (*sec_tbtt_ind)(void *pthis); ++}; ++ ++/* ++ * Struct used to store information about host buffers (DMA Address and local pointer) ++ */ ++struct ipc_hostbuf { ++ void *hostid; ///< ptr to hostbuf client (ipc_host client) structure ++ uint32_t dma_addr; ///< ptr to real hostbuf dma address ++}; ++ ++/// Definition of the IPC Host environment structure. ++struct ipc_host_env_tag { ++ /// Structure containing the callback pointers ++ struct ipc_host_cb_tag cb; ++ ++ /// Pointer to the shared environment ++ struct ipc_shared_env_tag *shared; ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ // Array used to store the descriptor addresses ++ struct ipc_hostbuf ipc_host_rxdesc_array[IPC_RXDESC_CNT]; ++ // Index of the host RX descriptor array (ipc_shared environment) ++ uint8_t ipc_host_rxdesc_idx; ++ /// Store the number of RX Descriptors ++ uint8_t rxdesc_nb; ++#endif //(CONFIG_RWNX_FULLMAC) ++ ++ /// Fields for Data Rx handling ++ // Index used for ipc_host_rxbuf_array to point to current buffer ++ uint8_t ipc_host_rxbuf_idx; ++ // Store the number of Rx Data buffers ++ uint32_t rx_bufnb; ++ // Store the size of the Rx Data buffers ++ uint32_t rx_bufsz; ++ ++ /// Fields for Radar events handling ++ // Global array used to store the hostid and hostbuf addresses ++ struct ipc_hostbuf ipc_host_radarbuf_array[IPC_RADARBUF_CNT]; ++ // Index used for ipc_host_rxbuf_array to point to current buffer ++ uint8_t ipc_host_radarbuf_idx; ++ // Store the number of radar event buffers ++ uint32_t radar_bufnb; ++ // Store the size of the radar event buffers ++ uint32_t radar_bufsz; ++ ++ ///Fields for Unsupported frame handling ++ // Global array used to store the hostid and hostbuf addresses ++ struct ipc_hostbuf ipc_host_unsuprxvecbuf_array[IPC_UNSUPRXVECBUF_CNT]; ++ // Index used for ipc_host_unsuprxvecbuf_array to point to current buffer ++ uint8_t ipc_host_unsuprxvecbuf_idx; ++ // Store the number of unsupported rx vector buffers ++ uint32_t unsuprxvec_bufnb; ++ // Store the size of unsupported rx vector buffers ++ uint32_t unsuprxvec_bufsz; ++ ++ // Index used that points to the first free TX desc ++ uint32_t txdesc_free_idx[IPC_TXQUEUE_CNT][CONFIG_USER_MAX]; ++ // Index used that points to the first used TX desc ++ uint32_t txdesc_used_idx[IPC_TXQUEUE_CNT][CONFIG_USER_MAX]; ++ // Array storing the currently pushed host ids for the BK queue ++ void *tx_host_id0[CONFIG_USER_MAX][NX_TXDESC_CNT0]; ++ // Array storing the currently pushed host ids for the BE queue ++ void *tx_host_id1[CONFIG_USER_MAX][NX_TXDESC_CNT1]; ++ // Array storing the currently pushed host ids for the VI queue ++ void *tx_host_id2[CONFIG_USER_MAX][NX_TXDESC_CNT2]; ++ // Array storing the currently pushed host ids for the VO queue ++ void *tx_host_id3[CONFIG_USER_MAX][NX_TXDESC_CNT3]; ++#if NX_TXQ_CNT == 5 ++ // Array storing the currently pushed host ids for the BCN queue ++ void *tx_host_id4[1][NX_TXDESC_CNT4]; ++#endif ++ // Pointer to the different host ids arrays, per IPC queue ++ void **tx_host_id[IPC_TXQUEUE_CNT][CONFIG_USER_MAX]; ++ // Pointer to the different TX descriptor arrays, per IPC queue ++ volatile struct txdesc_host *txdesc[IPC_TXQUEUE_CNT][CONFIG_USER_MAX]; ++ ++ /// Fields for Emb->App MSGs handling ++ // Global array used to store the hostid and hostbuf addresses for msg/ind ++ struct ipc_hostbuf ipc_host_msgbuf_array[IPC_MSGE2A_BUF_CNT]; ++ // Index of the MSG E2A buffers array to point to current buffer ++ uint8_t ipc_host_msge2a_idx; ++ // Store the number of E2A MSG buffers ++ uint32_t ipc_e2amsg_bufnb; ++ // Store the size of the E2A MSG buffers ++ uint32_t ipc_e2amsg_bufsz; ++ ++ /// E2A ACKs of A2E MSGs ++ uint8_t msga2e_cnt; ++ void *msga2e_hostid; ++ ++ /// Fields for Debug MSGs handling ++ // Global array used to store the hostid and hostbuf addresses for Debug messages ++ struct ipc_hostbuf ipc_host_dbgbuf_array[IPC_DBGBUF_CNT]; ++ // Index of the Debug messages buffers array to point to current buffer ++ uint8_t ipc_host_dbg_idx; ++ // Store the number of Debug messages buffers ++ uint32_t ipc_dbg_bufnb; ++ // Store the size of the Debug messages buffers ++ uint32_t ipc_dbg_bufsz; ++ ++ /// Pointer to the attached object (used in callbacks and register accesses) ++ void *pthis; ++}; ++ ++extern const int nx_txdesc_cnt[]; ++extern const int nx_txuser_cnt[]; ++ ++#endif // _IPC_HOST_H_ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_shared.h b/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_shared.h +new file mode 100755 +index 000000000..b56ec0a2c +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/ipc_shared.h +@@ -0,0 +1,784 @@ ++/** ++ **************************************************************************************** ++ * ++ * @file ipc_shared.h ++ * ++ * @brief Shared data between both IPC modules. ++ * ++ * Copyright (C) RivieraWaves 2011-2019 ++ * ++ **************************************************************************************** ++ */ ++ ++#ifndef _IPC_SHARED_H_ ++#define _IPC_SHARED_H_ ++ ++/* ++ * INCLUDE FILES ++ **************************************************************************************** ++ */ ++#include "ipc_compat.h" ++#include "lmac_mac.h" ++ ++/* ++ * DEFINES AND MACROS ++ **************************************************************************************** ++ */ ++#define CO_BIT(pos) (1U << (pos)) ++ ++#define IPC_TXQUEUE_CNT NX_TXQ_CNT ++#define NX_TXDESC_CNT0 8 ++#define NX_TXDESC_CNT1 64 ++#define NX_TXDESC_CNT2 64 ++#define NX_TXDESC_CNT3 32 ++#if NX_TXQ_CNT == 5 ++#define NX_TXDESC_CNT4 8 ++#endif ++ ++/* ++ * Number of Host buffers available for Data Rx handling (through DMA) ++ */ ++#define IPC_RXBUF_CNT 128 ++ ++/* ++ * Number of shared descriptors available for Data RX handling ++ */ ++#define IPC_RXDESC_CNT 128 ++ ++/* ++ * Number of Host buffers available for Radar events handling (through DMA) ++ */ ++#define IPC_RADARBUF_CNT 16 ++ ++/* ++ * Number of Host buffers available for unsupported Rx vectors handling (through DMA) ++ */ ++#define IPC_UNSUPRXVECBUF_CNT 8 ++ ++/* ++ * Size of RxVector ++ */ ++#define IPC_RXVEC_SIZE 16 ++ ++/* ++ * Number of Host buffers available for Emb->App MSGs sending (through DMA) ++ */ ++#ifdef CONFIG_RWNX_FULLMAC ++#define IPC_MSGE2A_BUF_CNT 64 ++#endif ++/* ++ * Number of Host buffers available for Debug Messages sending (through DMA) ++ */ ++#define IPC_DBGBUF_CNT 32 ++ ++/* ++ * Length used in MSGs structures ++ */ ++#define IPC_A2E_MSG_BUF_SIZE 127 // size in 4-byte words ++#ifdef CONFIG_RWNX_FULLMAC ++#define IPC_E2A_MSG_SIZE_BASE 256 // size in 4-byte words ++#endif ++ ++#ifdef CONFIG_RWNX_TL4 ++#define IPC_E2A_MSG_PARAM_SIZE \ ++ (IPC_E2A_MSG_SIZE_BASE + (IPC_E2A_MSG_SIZE_BASE / 2)) ++#else ++#define IPC_E2A_MSG_PARAM_SIZE IPC_E2A_MSG_SIZE_BASE ++#endif ++ ++/* ++ * Debug messages buffers size (in bytes) ++ */ ++#define IPC_DBG_PARAM_SIZE 256 ++ ++/* ++ * Define used for Rx hostbuf validity. ++ * This value should appear only when hostbuf was used for a Reception. ++ */ ++#define RX_DMA_OVER_PATTERN 0xAAAAAA00 ++ ++/* ++ * Define used for MSG buffers validity. ++ * This value will be written only when a MSG buffer is used for sending from Emb to App. ++ */ ++#define IPC_MSGE2A_VALID_PATTERN 0xADDEDE2A ++ ++/* ++ * Define used for Debug messages buffers validity. ++ * This value will be written only when a DBG buffer is used for sending from Emb to App. ++ */ ++#define IPC_DBG_VALID_PATTERN 0x000CACA0 ++ ++/* ++ * Length of the receive vectors, in bytes ++ */ ++#define DMA_HDR_PHYVECT_LEN 36 ++ ++/* ++ * Maximum number of payload addresses and lengths present in the descriptor ++ */ ++#ifdef CONFIG_RWNX_SPLIT_TX_BUF ++#define NX_TX_PAYLOAD_MAX 6 ++#else ++#define NX_TX_PAYLOAD_MAX 1 ++#endif ++ ++/* ++ * Message struct/ID API version ++ */ ++#define MSG_API_VER 33 ++ ++/* ++ **************************************************************************************** ++ */ ++// c.f LMAC/src/tx/tx_swdesc.h ++/// Descriptor filled by the Host ++struct hostdesc { ++ /// Pointer to packet payload ++ //u32_l packet_addr; ++ /// Size of the payload ++ u16_l packet_len; ++ u16_l flags_ext; ++ ++ u32_l hostid; ++#ifdef CONFIG_RWNX_FULLMAC ++ /// Address of the status descriptor in host memory (used for confirmation upload) ++ //u32_l status_desc_addr; ++ /// Destination Address ++ struct mac_addr eth_dest_addr; ++ /// Source Address ++ struct mac_addr eth_src_addr; ++ /// Ethernet Type ++ u16_l ethertype; ++#else /* ! CONFIG_RWNX_FULLMAC */ ++#ifdef CONFIG_RWNX_AGG_TX ++ ///Sequence Number for AMPDU MPDUs - for quick check if it's allowed within window ++ u16_l sn; ++#endif /* CONFIG_RWNX_AGG_TX */ ++ /// 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 ++ u8_l vif_idx; ++ /// Station Id (0xFF if station is unknown) ++ u8_l staid; ++#ifdef CONFIG_RWNX_MUMIMO_TX ++ /// MU-MIMO information (GroupId and User Position in the group) - The GroupId ++ /// is located on bits 0-5 and the User Position on bits 6-7. The GroupId value is set ++ /// to 63 if MU-MIMO shall not be used ++ u8_l mumimo_info; ++#endif /* CONFIG_RWNX_MUMIMO_TX */ ++#ifdef CONFIG_RWNX_FULLMAC ++ /// TX flags ++ u16_l flags; ++#endif /* CONFIG_RWNX_FULLMAC */ ++}; ++ ++/// Descriptor filled by the UMAC ++struct umacdesc { ++#ifdef CONFIG_RWNX_AGG_TX ++ ///First Sequence Number of the BlockAck window ++ u16_l sn_win; ++ /// Flags from UMAC (match tx_hd.macctrlinfo2 format) ++ u32_l flags; ++ /// PHY related flags field - rate, GI type, BW type - filled by driver ++ u32_l phy_flags; ++#endif //(CONFIG_RWNX_AGG_TX) ++}; ++ ++struct txdesc_api { ++ /// Information provided by Host ++ struct hostdesc host; ++}; ++ ++struct txdesc_host { ++ u32_l ready; ++ ++ /// API of the embedded part ++ struct txdesc_api api; ++}; ++ ++/// Comes from ipc_dma.h ++/// Element in the pool of TX DMA bridge descriptors. ++struct dma_desc { ++ /** Application subsystem address which is used as source address for DMA payload ++ * transfer*/ ++ u32_l src; ++ /** Points to the start of the embedded data buffer associated with this descriptor. ++ * This address acts as the destination address for the DMA payload transfer*/ ++ u32_l dest; ++ /// Complete length of the buffer in memory ++ u16_l length; ++ /// Control word for the DMA engine (e.g. for interrupt generation) ++ u16_l ctrl; ++ /// Pointer to the next element of the chained list ++ u32_l next; ++}; ++ ++// Comes from la.h ++/// Length of the configuration data of a logic analyzer ++#define LA_CONF_LEN 10 ++ ++/// Structure containing the configuration data of a logic analyzer ++struct la_conf_tag { ++ u32_l conf[LA_CONF_LEN]; ++ u32_l trace_len; ++ u32_l diag_conf; ++}; ++ ++/// Size of a logic analyzer memory ++#define LA_MEM_LEN (1024 * 1024) ++ ++/// Type of errors ++enum { ++ /// Recoverable error, not requiring any action from Upper MAC ++ DBG_ERROR_RECOVERABLE = 0, ++ /// Fatal error, requiring Upper MAC to reset Lower MAC and HW and restart operation ++ DBG_ERROR_FATAL ++}; ++ ++/// Maximum length of the SW diag trace ++#define DBG_SW_DIAG_MAX_LEN 1024 ++ ++/// Maximum length of the error trace ++#define DBG_ERROR_TRACE_SIZE 256 ++ ++/// Number of MAC diagnostic port banks ++#define DBG_DIAGS_MAC_MAX 48 ++ ++/// Number of PHY diagnostic port banks ++#define DBG_DIAGS_PHY_MAX 32 ++ ++/// Maximum size of the RX header descriptor information in the debug dump ++#define DBG_RHD_MEM_LEN (5 * 1024) ++ ++/// Maximum size of the RX buffer descriptor information in the debug dump ++#define DBG_RBD_MEM_LEN (5 * 1024) ++ ++/// Maximum size of the TX header descriptor information in the debug dump ++#define DBG_THD_MEM_LEN (10 * 1024) ++ ++/// Structure containing the information about the PHY channel that is used ++struct phy_channel_info { ++ /// PHY channel information 1 ++ u32_l info1; ++ /// PHY channel information 2 ++ u32_l info2; ++}; ++ ++/// Debug information forwarded to host when an error occurs ++struct dbg_debug_info_tag { ++ /// Type of error (0: recoverable, 1: fatal) ++ u32_l error_type; ++ /// Pointer to the first RX Header Descriptor chained to the MAC HW ++ u32_l rhd; ++ /// Size of the RX header descriptor buffer ++ u32_l rhd_len; ++ /// Pointer to the first RX Buffer Descriptor chained to the MAC HW ++ u32_l rbd; ++ /// Size of the RX buffer descriptor buffer ++ u32_l rbd_len; ++ /// Pointer to the first TX Header Descriptors chained to the MAC HW ++ u32_l thd[NX_TXQ_CNT]; ++ /// Size of the TX header descriptor buffer ++ u32_l thd_len[NX_TXQ_CNT]; ++ /// MAC HW diag configuration ++ u32_l hw_diag; ++ /// Error message ++ u32_l error[DBG_ERROR_TRACE_SIZE / 4]; ++ /// SW diag configuration length ++ u32_l sw_diag_len; ++ /// SW diag configuration ++ u32_l sw_diag[DBG_SW_DIAG_MAX_LEN / 4]; ++ /// PHY channel information ++ struct phy_channel_info chan_info; ++ /// Embedded LA configuration ++ struct la_conf_tag la_conf; ++ /// MAC diagnostic port state ++ u16_l diags_mac[DBG_DIAGS_MAC_MAX]; ++ /// PHY diagnostic port state ++ u16_l diags_phy[DBG_DIAGS_PHY_MAX]; ++ /// MAC HW RX Header descriptor pointer ++ u32_l rhd_hw_ptr; ++ /// MAC HW RX Buffer descriptor pointer ++ u32_l rbd_hw_ptr; ++}; ++ ++/// Full debug dump that is forwarded to host in case of error ++struct dbg_debug_dump_tag { ++ /// Debug information ++ struct dbg_debug_info_tag dbg_info; ++ ++ /// RX header descriptor memory ++ u32_l rhd_mem[DBG_RHD_MEM_LEN / 4]; ++ ++ /// RX buffer descriptor memory ++ u32_l rbd_mem[DBG_RBD_MEM_LEN / 4]; ++ ++ /// TX header descriptor memory ++ u32_l thd_mem[NX_TXQ_CNT][DBG_THD_MEM_LEN / 4]; ++ ++ /// Logic analyzer memory ++ u32_l la_mem[LA_MEM_LEN / 4]; ++}; ++ ++/// Number of pulses in a radar event structure ++#define RADAR_PULSE_MAX 4 ++ ++/// Definition of an array of radar pulses ++struct radar_pulse_array_desc { ++ /// Buffer containing the radar pulses ++ u32_l pulse[RADAR_PULSE_MAX]; ++ /// Index of the radar detection chain that detected those pulses ++ u32_l idx; ++ /// Number of valid pulses in the buffer ++ u32_l cnt; ++}; ++ ++/// Bit mapping inside a radar pulse element ++struct radar_pulse { ++ s32_l freq : 6; /** Freq (resolution is 2Mhz range is [-Fadc/4 .. Fadc/4]) */ ++ u32_l fom : 4; /** Figure of Merit */ ++ u32_l len : 6; /** Length of the current radar pulse (resolution is 2us) */ ++ u32_l rep : 16; /** Time interval between the previous radar event ++ and the current one (in us) */ ++}; ++ ++/// Definition of a RX vector descriptor ++struct rx_vector_desc { ++ /// PHY channel information ++ struct phy_channel_info phy_info; ++ ++ /// RX vector 1 ++ u32_l rx_vect1[IPC_RXVEC_SIZE / 4]; ++ ++ /// Used to print a valid rx vector ++ u32_l pattern; ++}; ++ ++/// ++struct rxdesc_tag { ++ /// Host Buffer Address ++ u32_l host_id; ++ /// Length ++ u32_l frame_len; ++ /// Status ++ u16_l status; ++}; ++ ++/** ++ **************************************************************************************** ++ * @defgroup IPC IPC ++ * @ingroup NXMAC ++ * @brief Inter Processor Communication module. ++ * ++ * The IPC module implements the protocol to communicate between the Host CPU ++ * and the Embedded CPU. ++ * ++ * @see http://en.wikipedia.org/wiki/Circular_buffer ++ * For more information about the ring buffer typical use and difficulties. ++ **************************************************************************************** ++ */ ++ ++/** ++ **************************************************************************************** ++ * @addtogroup IPC_TX IPC Tx path ++ * @ingroup IPC ++ * @brief IPC Tx path structures and functions ++ * ++ * A typical use case of the IPC Tx path API: ++ * @msc ++ * hscale = "2"; ++ * ++ * a [label=Driver], ++ * b [label="IPC host"], ++ * c [label="IPC emb"], ++ * d [label=Firmware]; ++ * ++ * --- [label="Tx descriptor queue example"]; ++ * a=>a [label="Driver receives a Tx packet from OS"]; ++ * a=>b [label="ipc_host_txdesc_get()"]; ++ * a<a [label="Driver fill the descriptor"]; ++ * a=>b [label="ipc_host_txdesc_push()"]; ++ * ... [label="(several Tx desc can be pushed)"]; ++ * b:>c [label="Tx desc queue filled IRQ"]; ++ * c=>>d [label="EDCA sub-scheduler callback"]; ++ * c<>d [label="UMAC Tx desc callback"]; ++ * ... [label="(several Tx desc can be popped)"]; ++ * d=>d [label="Packets are sent or discarded"]; ++ * --- [label="Tx confirm queue example"]; ++ * c<=d [label="ipc_emb_txcfm_push()"]; ++ * c>>d [label="Request accepted"]; ++ * ... [label="(several Tx cfm can be pushed)"]; ++ * b<:c [label="Tx cfm queue filled IRQ"]; ++ * a<<=b [label="Driver's Tx Confirm callback"]; ++ * a=>b [label="ipc_host_txcfm_pop()"]; ++ * a<c [label="ipc_host_rxbuf_push()"]; ++ * d=>c [label="ipc_host_rxbuf_push()"]; ++ * d=>c [label="ipc_host_rxbuf_push()"]; ++ * ... [label="(several Rx buffer are pushed)"]; ++ * a=>a [label=" Frame is received\n from the medium"]; ++ * a<a [label=" Firmware fill the buffer\n with received frame"]; ++ * a<c [label="Rx desc queue filled IRQ"]; ++ * c=>>d [label="Driver Rx packet callback"]; ++ * c<=d [label="ipc_host_rxdesc_pop()"]; ++ * d=>d [label="Rx packet is handed \nover to the OS "]; ++ * ... [label="(several Rx desc can be poped)"]; ++ * --- [label="Rx buffer request exemple"]; ++ * b:>c [label="Low Rx buffer count IRQ"]; ++ * a<>d [label="Driver Rx buffer callback"]; ++ * d=>c [label="ipc_host_rxbuf_push()"]; ++ * d=>c [label="ipc_host_rxbuf_push()"]; ++ * d=>c [label="ipc_host_rxbuf_push()"]; ++ * ... [label="(several Rx buffer are pushed)"]; ++ * @endmsc ++ * ++ * @addtogroup IPC_RX ++ * @{ ++ **************************************************************************************** ++ */ ++ ++/// @} IPC_RX ++ ++/** ++ **************************************************************************************** ++ * @defgroup IPC_MISC IPC Misc ++ * @ingroup IPC ++ * @brief IPC miscellaneous functions ++ **************************************************************************************** ++ */ ++/** IPC header structure. This structure is stored at the beginning of every IPC message. ++ * @warning This structure's size must NOT exceed 4 bytes in length. ++ */ ++struct ipc_header { ++ /// IPC message type. ++ u16_l type; ++ /// IPC message size in number of bytes. ++ u16_l size; ++}; ++ ++struct ipc_msg_elt { ++ /// Message header (alignment forced on word size, see allocation in shared env). ++ struct ipc_header header __ALIGN4; ++}; ++ ++/// Message structure for MSGs from Emb to App ++struct ipc_e2a_msg { ++ u16_l id; ///< Message id. ++ u16_l dummy_dest_id; ++ u16_l dummy_src_id; ++ u16_l param_len; ///< Parameter embedded struct length. ++ u32_l pattern; ///< Used to stamp a valid MSG buffer ++ u32_l param[IPC_E2A_MSG_PARAM_SIZE]; ///< Parameter embedded struct. Must be word-aligned. ++}; ++ ++/// Message structure for Debug messages from Emb to App ++struct ipc_dbg_msg { ++ u32_l string[IPC_DBG_PARAM_SIZE / 4]; ///< Debug string ++ u32_l pattern; ///< Used to stamp a valid buffer ++}; ++ ++/// Message structure for MSGs from App to Emb. ++/// Actually a sub-structure will be used when filling the messages. ++struct ipc_a2e_msg { ++ u32_l dummy_word; // used to cope with kernel message structure ++ u32_l msg[IPC_A2E_MSG_BUF_SIZE]; // body of the msg ++}; ++ ++struct ipc_shared_rx_buf { ++ /// < ptr to hostbuf client (ipc_host client) structure ++ u32_l hostid; ++ /// < ptr to real hostbuf dma address ++ u32_l dma_addr; ++}; ++ ++struct ipc_shared_rx_desc { ++ /// DMA Address ++ u32_l dma_addr; ++}; ++ ++/// Structure containing FW characteristics for compatibility checking ++struct compatibility_tag { ++ /// Size of IPC shared memory ++ u16_l ipc_shared_size; ++ /// Message struct/ID API version ++ u16_l msg_api; ++ /// Version of IPC shared ++ u8_l ipc_shared_version; ++ /// Number of host buffers available for Emb->App MSGs sending ++ u8_l msge2a_buf_cnt; ++ /// Number of host buffers available for Debug Messages sending ++ u8_l dbgbuf_cnt; ++ /// Number of host buffers available for Radar events handling ++ u8_l radarbuf_cnt; ++ /// Number of host buffers available for unsupported Rx vectors handling ++ u8_l unsuprxvecbuf_cnt; ++ /// Number of shared descriptors available for Data RX handling ++ u8_l rxdesc_cnt; ++ /// Number of host buffers available for Data Rx handling ++ u8_l rxbuf_cnt; ++ /// Number of descriptors in BK TX queue (power of 2, min 4, max 64) ++ u8_l bk_txq; ++ /// Number of descriptors in BE TX queue (power of 2, min 4, max 64) ++ u8_l be_txq; ++ /// Number of descriptors in VI TX queue (power of 2, min 4, max 64) ++ u8_l vi_txq; ++ /// Number of descriptors in VO TX queue (power of 2, min 4, max 64) ++ u8_l vo_txq; ++ /// Number of descriptors in BCN TX queue (power of 2, min 4, max 64) ++ u8_l bcn_txq; ++}; ++ ++/* ++ * TYPE and STRUCT DEFINITIONS ++ **************************************************************************************** ++ */ ++ ++// Indexes are defined in the MIB shared structure ++struct ipc_shared_env_tag { ++ volatile struct compatibility_tag comp_info; //FW characteristics ++ ++ volatile struct ipc_a2e_msg ++ msg_a2e_buf; // room for MSG to be sent from App to Emb ++ ++ // Fields for MSGs sending from Emb to App ++ volatile struct ipc_e2a_msg ++ msg_e2a_buf; // room to build the MSG to be DMA Xferred ++ volatile struct dma_desc ++ msg_dma_desc; // DMA descriptor for Emb->App MSGs Xfers ++ volatile u32_l msg_e2a_hostbuf_addr ++ [IPC_MSGE2A_BUF_CNT]; // buffers @ for DMA Xfers ++ ++ // Fields for Debug MSGs sending from Emb to App ++ volatile struct ipc_dbg_msg ++ dbg_buf; // room to build the MSG to be DMA Xferred ++ volatile struct dma_desc ++ dbg_dma_desc; // DMA descriptor for Emb->App MSGs Xfers ++ volatile u32_l ++ dbg_hostbuf_addr[IPC_DBGBUF_CNT]; // buffers @ for MSGs DMA Xfers ++ volatile u32_l ++ la_dbginfo_addr; // Host buffer address for the debug information ++ volatile u32_l pattern_addr; ++ volatile u32_l ++ radarbuf_hostbuf[IPC_RADARBUF_CNT]; // buffers @ for Radar Events ++ volatile u32_l unsuprxvecbuf_hostbuf ++ [IPC_UNSUPRXVECBUF_CNT]; // buffers @ for unsupported Rx vectors ++ volatile struct txdesc_host txdesc0[CONFIG_USER_MAX][NX_TXDESC_CNT0]; ++ volatile struct txdesc_host txdesc1[CONFIG_USER_MAX][NX_TXDESC_CNT1]; ++ volatile struct txdesc_host txdesc2[CONFIG_USER_MAX][NX_TXDESC_CNT2]; ++ volatile struct txdesc_host txdesc3[CONFIG_USER_MAX][NX_TXDESC_CNT3]; ++#if NX_TXQ_CNT == 5 ++ volatile struct txdesc_host txdesc4[1][NX_TXDESC_CNT4]; ++#endif ++#ifdef CONFIG_RWNX_FULLMAC ++ // RX Descriptors Array ++ volatile struct ipc_shared_rx_desc host_rxdesc[IPC_RXDESC_CNT]; ++ // RX Buffers Array ++ volatile struct ipc_shared_rx_buf host_rxbuf[IPC_RXBUF_CNT]; ++#else ++ // buffers @ for Data Rx ++ volatile u32_l host_rxbuf[IPC_RXBUF_CNT]; ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++ u32_l buffered[NX_REMOTE_STA_MAX][TID_MAX]; ++ ++ volatile uint16_t trace_pattern; ++ volatile uint32_t trace_start; ++ volatile uint32_t trace_end; ++ volatile uint32_t trace_size; ++ volatile uint32_t trace_offset; ++ volatile uint32_t trace_nb_compo; ++ volatile uint32_t trace_offset_compo; ++}; ++ ++extern struct ipc_shared_env_tag ipc_shared_env; ++ ++/* ++ * TYPE and STRUCT DEFINITIONS ++ **************************************************************************************** ++ */ ++ ++// IRQs from app to emb ++/// Interrupts bits used for the TX descriptors of the AC queues ++#ifdef CONFIG_RWNX_MUMIMO_TX ++#ifdef CONFIG_RWNX_OLD_IPC ++#error "MU-MIMO cannot be compiled for old IPC" ++#endif ++/// Interrupts bits used ++#if CONFIG_USER_MAX > 3 ++#define IPC_IRQ_A2E_USER_MSK 0xF ++#elif CONFIG_USER_MAX > 2 ++#define IPC_IRQ_A2E_USER_MSK 0x7 ++#else ++#define IPC_IRQ_A2E_USER_MSK 0x3 ++#endif ++ ++/// Offset of the interrupts for AC0 ++#define IPC_IRQ_A2E_AC0_OFT 8 ++/// Mask of the interrupts for AC0 ++#define IPC_IRQ_A2E_AC0_MSK (IPC_IRQ_A2E_USER_MSK << IPC_IRQ_A2E_AC0_OFT) ++/// Offset of the interrupts for AC1 ++#define IPC_IRQ_A2E_AC1_OFT (IPC_IRQ_A2E_AC0_OFT + CONFIG_USER_MAX) ++/// Mask of the interrupts for AC1 ++#define IPC_IRQ_A2E_AC1_MSK (IPC_IRQ_A2E_USER_MSK << IPC_IRQ_A2E_AC1_OFT) ++/// Offset of the interrupts for AC2 ++#define IPC_IRQ_A2E_AC2_OFT (IPC_IRQ_A2E_AC1_OFT + CONFIG_USER_MAX) ++/// Mask of the interrupts for AC2 ++#define IPC_IRQ_A2E_AC2_MSK (IPC_IRQ_A2E_USER_MSK << IPC_IRQ_A2E_AC2_OFT) ++/// Offset of the interrupts for AC3 ++#define IPC_IRQ_A2E_AC3_OFT (IPC_IRQ_A2E_AC2_OFT + CONFIG_USER_MAX) ++/// Mask of the interrupts for AC3 ++#define IPC_IRQ_A2E_AC3_MSK (IPC_IRQ_A2E_USER_MSK << IPC_IRQ_A2E_AC3_OFT) ++/// Offset of the interrupts for BCN ++#define IPC_IRQ_A2E_BCN_OFT (IPC_IRQ_A2E_AC3_OFT + CONFIG_USER_MAX) ++/// Mask of the interrupts for BCN ++#define IPC_IRQ_A2E_BCN_MSK CO_BIT(IPC_IRQ_A2E_BCN_OFT) ++ ++#define IPC_IRQ_A2E_AC_TXDESC \ ++ (IPC_IRQ_A2E_AC0_MSK | IPC_IRQ_A2E_AC1_MSK | IPC_IRQ_A2E_AC2_MSK | \ ++ IPC_IRQ_A2E_AC3_MSK) ++ ++/// Interrupts bits used for the TX descriptors of the BCN queue ++#if NX_TXQ_CNT < 5 ++#define IPC_IRQ_A2E_BCN_TXDESC 0 ++#else ++#define IPC_IRQ_A2E_BCN_TXDESC (0x01 << IPC_IRQ_A2E_BCN_OFT) ++#endif ++ ++/// IPC TX descriptor interrupt mask ++#define IPC_IRQ_A2E_TXDESC (IPC_IRQ_A2E_AC_TXDESC | IPC_IRQ_A2E_BCN_TXDESC) ++#else ++/// IPC TX descriptor interrupt mask ++#define IPC_IRQ_A2E_TXDESC 0xFF00 ++#endif ++ ++#define IPC_IRQ_A2E_TXDESC_FIRSTBIT (8) ++#define IPC_IRQ_A2E_RXBUF_BACK CO_BIT(5) ++#define IPC_IRQ_A2E_RXDESC_BACK CO_BIT(4) ++ ++#define IPC_IRQ_A2E_MSG CO_BIT(1) ++#define IPC_IRQ_A2E_DBG CO_BIT(0) ++ ++#define IPC_IRQ_A2E_ALL (IPC_IRQ_A2E_TXDESC | IPC_IRQ_A2E_MSG | IPC_IRQ_A2E_DBG) ++ ++// IRQs from emb to app ++#define IPC_IRQ_E2A_TXCFM_POS 7 ++ ++#ifdef CONFIG_RWNX_MUMIMO_TX ++#ifdef CONFIG_RWNX_OLD_IPC ++#error "MU-MIMO cannot be compiled for old IPC" ++#endif ++/// Interrupts bits used ++#if CONFIG_USER_MAX > 3 ++#define IPC_IRQ_E2A_USER_MSK 0xF ++#elif CONFIG_USER_MAX > 2 ++#define IPC_IRQ_E2A_USER_MSK 0x7 ++#else ++#define IPC_IRQ_E2A_USER_MSK 0x3 ++#endif ++ ++/// Offset of the interrupts for AC0 ++#define IPC_IRQ_E2A_AC0_OFT IPC_IRQ_E2A_TXCFM_POS ++/// Mask of the interrupts for AC0 ++#define IPC_IRQ_E2A_AC0_MSK (IPC_IRQ_E2A_USER_MSK << IPC_IRQ_E2A_AC0_OFT) ++/// Offset of the interrupts for AC1 ++#define IPC_IRQ_E2A_AC1_OFT (IPC_IRQ_E2A_AC0_OFT + CONFIG_USER_MAX) ++/// Mask of the interrupts for AC1 ++#define IPC_IRQ_E2A_AC1_MSK (IPC_IRQ_E2A_USER_MSK << IPC_IRQ_E2A_AC1_OFT) ++/// Offset of the interrupts for AC2 ++#define IPC_IRQ_E2A_AC2_OFT (IPC_IRQ_E2A_AC1_OFT + CONFIG_USER_MAX) ++/// Mask of the interrupts for AC2 ++#define IPC_IRQ_E2A_AC2_MSK (IPC_IRQ_E2A_USER_MSK << IPC_IRQ_E2A_AC2_OFT) ++/// Offset of the interrupts for AC3 ++#define IPC_IRQ_E2A_AC3_OFT (IPC_IRQ_E2A_AC2_OFT + CONFIG_USER_MAX) ++/// Mask of the interrupts for AC3 ++#define IPC_IRQ_E2A_AC3_MSK (IPC_IRQ_E2A_USER_MSK << IPC_IRQ_E2A_AC3_OFT) ++/// Offset of the interrupts for BCN ++#define IPC_IRQ_E2A_BCN_OFT (IPC_IRQ_E2A_AC3_OFT + CONFIG_USER_MAX) ++/// Mask of the interrupts for BCN ++#define IPC_IRQ_E2A_BCN_MSK CO_BIT(IPC_IRQ_E2A_BCN_OFT) ++ ++#define IPC_IRQ_E2A_AC_TXCFM \ ++ (IPC_IRQ_E2A_AC0_MSK | IPC_IRQ_E2A_AC1_MSK | IPC_IRQ_E2A_AC2_MSK | \ ++ IPC_IRQ_E2A_AC3_MSK) ++ ++/// Interrupts bits used for the TX descriptors of the BCN queue ++#if NX_TXQ_CNT < 5 ++#define IPC_IRQ_E2A_BCN_TXCFM 0 ++#else ++#define IPC_IRQ_E2A_BCN_TXCFM (0x01 << IPC_IRQ_E2A_BCN_OFT) ++#endif ++ ++/// IPC TX descriptor interrupt mask ++#define IPC_IRQ_E2A_TXCFM (IPC_IRQ_E2A_AC_TXCFM | IPC_IRQ_E2A_BCN_TXCFM) ++ ++#else ++ ++#define IPC_IRQ_E2A_TXCFM (((1 << NX_TXQ_CNT) - 1) << IPC_IRQ_E2A_TXCFM_POS) ++ ++#endif /* CONFIG_RWNX_MUMIMO_TX */ ++ ++#define IPC_IRQ_E2A_UNSUP_RX_VEC CO_BIT(7) ++#define IPC_IRQ_E2A_RADAR CO_BIT(6) ++#define IPC_IRQ_E2A_TBTT_SEC CO_BIT(5) ++#define IPC_IRQ_E2A_TBTT_PRIM CO_BIT(4) ++#define IPC_IRQ_E2A_RXDESC CO_BIT(3) ++#define IPC_IRQ_E2A_MSG_ACK CO_BIT(2) ++#define IPC_IRQ_E2A_MSG CO_BIT(1) ++#define IPC_IRQ_E2A_DBG CO_BIT(0) ++ ++#define IPC_IRQ_E2A_ALL \ ++ (IPC_IRQ_E2A_TXCFM | IPC_IRQ_E2A_RXDESC | IPC_IRQ_E2A_MSG_ACK | \ ++ IPC_IRQ_E2A_MSG | IPC_IRQ_E2A_DBG | IPC_IRQ_E2A_TBTT_PRIM | \ ++ IPC_IRQ_E2A_TBTT_SEC | IPC_IRQ_E2A_RADAR | IPC_IRQ_E2A_UNSUP_RX_VEC) ++ ++// FLAGS for RX desc ++#define IPC_RX_FORWARD CO_BIT(1) ++#define IPC_RX_INTRABSS CO_BIT(0) ++ ++// IPC message TYPE ++enum { ++ IPC_MSG_NONE = 0, ++ IPC_MSG_WRAP, ++ IPC_MSG_KMSG, ++ ++ IPC_DBG_STRING, ++ ++}; ++ ++#endif // _IPC_SHARED_H_ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/lmac_mac.h b/drivers/net/wireless/aic8800/aic8800_fdrv/lmac_mac.h +new file mode 100755 +index 000000000..caac5e116 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/lmac_mac.h +@@ -0,0 +1,564 @@ ++/** ++ **************************************************************************************** ++ * ++ * @file lmac_mac_types.h ++ * ++ * @brief MAC related definitions. ++ * ++ * Adapted from mac_types.h to used lmac_types.h instead of standard types ++ * eg: perl -pi -e '$_ =~ s/uint(\d{1,2})_t/u$1_l/g; \ ++ * $_ =~ s/int(\d{1,2})_t/s$1_l/g; \ ++ * $_ =~ s/CO_BIT/BIT/g;' lmac_mac.h ++ * ++ * Copyright (C) RivieraWaves 2011-2019 ++ * ++ **************************************************************************************** ++ */ ++ ++#ifndef LMAC_MAC_H_ ++#define LMAC_MAC_H_ ++ ++#include "lmac_types.h" ++ ++/// Interface types ++enum mac_vif_type { ++ /// ESS STA interface ++ VIF_STA, ++ /// IBSS STA interface ++ VIF_IBSS, ++ /// AP interface ++ VIF_AP, ++ /// Mesh Point interface ++ VIF_MESH_POINT, ++ /// Monitor interface ++ VIF_MONITOR, ++ /// Unknown type ++ VIF_UNKNOWN ++}; ++ ++/// MAC address length in bytes. ++#define MAC_ADDR_LEN 6 ++ ++/// MAC address structure. ++struct mac_addr { ++ /// Array of 16-bit words that make up the MAC address. ++ u16_l array[MAC_ADDR_LEN / 2]; ++}; ++ ++/// SSID maximum length. ++#define MAC_SSID_LEN 32 ++ ++/// SSID. ++struct mac_ssid { ++ /// Actual length of the SSID. ++ u8_l length; ++ /// Array containing the SSID name. ++ u8_l array[MAC_SSID_LEN]; ++}; ++ ++/// BSS type ++enum mac_bss_type { ++ INFRASTRUCTURE_MODE = 1, ++ INDEPENDENT_BSS_MODE, ++ ANY_BSS_MODE ++}; ++ ++/// Channel Band ++enum mac_chan_band { ++ /// 2.4GHz Band ++ PHY_BAND_2G4, ++ /// 5GHz band ++ PHY_BAND_5G, ++ /// Number of bands ++ PHY_BAND_MAX, ++}; ++ ++/// Operating Channel Bandwidth ++enum mac_chan_bandwidth { ++ /// 20MHz BW ++ PHY_CHNL_BW_20, ++ /// 40MHz BW ++ PHY_CHNL_BW_40, ++ /// 80MHz BW ++ PHY_CHNL_BW_80, ++ /// 160MHz BW ++ PHY_CHNL_BW_160, ++ /// 80+80MHz BW ++ PHY_CHNL_BW_80P80, ++ /// Reserved BW ++ PHY_CHNL_BW_OTHER, ++}; ++ ++/// max number of channels in the 2.4 GHZ band ++#define MAC_DOMAINCHANNEL_24G_MAX 14 ++ ++/// max number of channels in the 5 GHZ band ++#define MAC_DOMAINCHANNEL_5G_MAX 28 ++ ++/// Channel Flag ++enum mac_chan_flags { ++ /// Cannot initiate radiation on this channel ++ CHAN_NO_IR = BIT(0), ++ /// Channel is not allowed ++ CHAN_DISABLED = BIT(1), ++ /// Radar detection required on this channel ++ CHAN_RADAR = BIT(2), ++}; ++ ++/// Primary Channel definition ++struct mac_chan_def { ++ /// Frequency of the channel (in MHz) ++ u16_l freq; ++ /// RF band (@ref mac_chan_band) ++ u8_l band; ++ /// Additional information (@ref mac_chan_flags) ++ u8_l flags; ++ /// Max transmit power allowed on this channel (dBm) ++ s8_l tx_power; ++}; ++ ++/// Operating Channel ++struct mac_chan_op { ++ /// Band (@ref mac_chan_band) ++ u8_l band; ++ /// Channel type (@ref mac_chan_bandwidth) ++ u8_l type; ++ /// Frequency for Primary 20MHz channel (in MHz) ++ u16_l prim20_freq; ++ /// Frequency center of the contiguous channel or center of Primary 80+80 (in MHz) ++ u16_l center1_freq; ++ /// Frequency center of the non-contiguous secondary 80+80 (in MHz) ++ u16_l center2_freq; ++ /// Max transmit power allowed on this channel (dBm) ++ s8_l tx_power; ++ /// Additional information (@ref mac_chan_flags) ++ u8_l flags; ++}; ++ ++/// Cipher suites (order is important as it is used by MACHW) ++enum mac_cipher_suite { ++ /// 00-0F-AC 1 ++ MAC_CIPHER_WEP40 = 0, ++ /// 00-0F-AC 2 ++ MAC_CIPHER_TKIP = 1, ++ /// 00-0F-AC 4 ++ MAC_CIPHER_CCMP = 2, ++ /// 00-0F-AC 5 ++ MAC_CIPHER_WEP104 = 3, ++ /// 00-14-72 1 ++ MAC_CIPHER_WPI_SMS4 = 4, ++ /// 00-0F-AC 6 (aka AES_CMAC) ++ MAC_CIPHER_BIP_CMAC_128 = 5, ++ ++ // following cipher are not supported by MACHW ++ /// 00-0F-AC 08 ++ MAC_CIPHER_GCMP_128, ++ /// 00-0F-AC 09 ++ MAC_CIPHER_GCMP_256, ++ /// 00-0F-AC 10 ++ MAC_CIPHER_CCMP_256, ++ /// 00-0F-AC 11 ++ MAC_CIPHER_BIP_GMAC_128, ++ /// 00-0F-AC 12 ++ MAC_CIPHER_BIP_GMAC_256, ++ /// 00-0F-AC 13 ++ MAC_CIPHER_BIP_CMAC_256, ++ ++ MAC_CIPHER_INVALID = 0xFF ++}; ++ ++/// Authentication and Key Management suite ++enum mac_akm_suite { ++ /// No security ++ MAC_AKM_NONE, ++ /// Pre RSN (WEP or WPA) ++ MAC_AKM_PRE_RSN, ++ /// 00-0F-AC 1 ++ MAC_AKM_8021X, ++ /// 00-0F-AC 2 ++ MAC_AKM_PSK, ++ /// 00-0F-AC 3 ++ MAC_AKM_FT_8021X, ++ /// 00-0F-AC 4 ++ MAC_AKM_FT_PSK, ++ /// 00-0F-AC 5 ++ MAC_AKM_8021X_SHA256, ++ /// 00-0F-AC 6 ++ MAC_AKM_PSK_SHA256, ++ /// 00-0F-AC 7 ++ MAC_AKM_TDLS, ++ /// 00-0F-AC 8 ++ MAC_AKM_SAE, ++ /// 00-0F-AC 9 ++ MAC_AKM_FT_OVER_SAE, ++ /// 00-0F-AC 11 ++ MAC_AKM_8021X_SUITE_B, ++ /// 00-0F-AC 12 ++ MAC_AKM_8021X_SUITE_B_192, ++ /// 00-0F-AC 14 ++ MAC_AKM_FILS_SHA256, ++ /// 00-0F-AC 15 ++ MAC_AKM_FILS_SHA384, ++ /// 00-0F-AC 16 ++ MAC_AKM_FT_FILS_SHA256, ++ /// 00-0F-AC 17 ++ MAC_AKM_FT_FILS_SHA384, ++ /// 00-0F-AC 18 ++ MAC_AKM_OWE, ++ ++ /// 00-14-72 1 ++ MAC_AKM_WAPI_CERT, ++ /// 00-14-72 2 ++ MAC_AKM_WAPI_PSK, ++}; ++ ++/// Scan result element, parsed from beacon or probe response frames. ++struct mac_scan_result { ++ /// Scan result is valid ++ bool valid_flag; ++ /// Network BSSID. ++ struct mac_addr bssid; ++ /// Network name. ++ struct mac_ssid ssid; ++ /// Network type (@ref mac_bss_type). ++ u16_l bsstype; ++ /// Network channel. ++ struct mac_chan_def *chan; ++ /// Network beacon period (in TU). ++ u16_l beacon_period; ++ /// Capability information ++ u16_l cap_info; ++ /// Supported AKM (bit-field of @ref mac_akm_suite) ++ u32_l akm; ++ /// Group cipher (bit-field of @ref mac_cipher_suite) ++ u16_l group_cipher; ++ /// Group cipher (bit-field of @ref mac_cipher_suite) ++ u16_l pairwise_cipher; ++ /// RSSI of the scanned BSS (in dBm) ++ s8_l rssi; ++}; ++ ++/// Legacy rate 802.11 definitions ++enum mac_legacy_rates { ++ /// DSSS/CCK 1Mbps ++ MAC_RATE_1MBPS = 2, ++ /// DSSS/CCK 2Mbps ++ MAC_RATE_2MBPS = 4, ++ /// DSSS/CCK 5.5Mbps ++ MAC_RATE_5_5MBPS = 11, ++ /// OFDM 6Mbps ++ MAC_RATE_6MBPS = 12, ++ /// OFDM 9Mbps ++ MAC_RATE_9MBPS = 18, ++ /// DSSS/CCK 11Mbps ++ MAC_RATE_11MBPS = 22, ++ /// OFDM 12Mbps ++ MAC_RATE_12MBPS = 24, ++ /// OFDM 18Mbps ++ MAC_RATE_18MBPS = 36, ++ /// OFDM 24Mbps ++ MAC_RATE_24MBPS = 48, ++ /// OFDM 36Mbps ++ MAC_RATE_36MBPS = 72, ++ /// OFDM 48Mbps ++ MAC_RATE_48MBPS = 96, ++ /// OFDM 54Mbps ++ MAC_RATE_54MBPS = 108 ++}; ++ ++/// BSS Membership Selector definitions ++enum mac_bss_membership { ++ /// HT PHY ++ MAC_BSS_MEMBERSHIP_HT_PHY = 127, ++ /// VHT PHY ++ MAC_BSS_MEMBERSHIP_VHT_PHY = 126, ++}; ++ ++/// MAC rateset maximum length ++#define MAC_RATESET_LEN 12 ++ ++/// Structure containing the legacy rateset of a station ++struct mac_rateset { ++ /// Number of legacy rates supported ++ u8_l length; ++ /// Array of legacy rates ++ u8_l array[MAC_RATESET_LEN]; ++}; ++ ++/// MAC Security Key maximum length ++#define MAC_SEC_KEY_LEN 32 // TKIP keys 256 bits (max length) with MIC keys ++ ++/// Structure defining a security key ++struct mac_sec_key { ++ /// Key material length ++ u8_l length; ++ /// Key material ++ u32_l array[MAC_SEC_KEY_LEN / 4]; ++}; ++ ++/// Access Category enumeration ++enum mac_ac { ++ /// Background ++ AC_BK = 0, ++ /// Best-effort ++ AC_BE, ++ /// Video ++ AC_VI, ++ /// Voice ++ AC_VO, ++ /// Number of access categories ++ AC_MAX ++}; ++ ++/// Traffic ID enumeration ++enum mac_tid { ++ /// TID_0. Mapped to @ref AC_BE as per 802.11 standard. ++ TID_0, ++ /// TID_1. Mapped to @ref AC_BK as per 802.11 standard. ++ TID_1, ++ /// TID_2. Mapped to @ref AC_BK as per 802.11 standard. ++ TID_2, ++ /// TID_3. Mapped to @ref AC_BE as per 802.11 standard. ++ TID_3, ++ /// TID_4. Mapped to @ref AC_VI as per 802.11 standard. ++ TID_4, ++ /// TID_5. Mapped to @ref AC_VI as per 802.11 standard. ++ TID_5, ++ /// TID_6. Mapped to @ref AC_VO as per 802.11 standard. ++ TID_6, ++ /// TID_7. Mapped to @ref AC_VO as per 802.11 standard. ++ TID_7, ++ /// Non standard Management TID used internally ++ TID_MGT, ++ /// Number of TID supported ++ TID_MAX ++}; ++ ++/// MCS bitfield maximum size (in bytes) ++#define MAX_MCS_LEN 16 // 16 * 8 = 128 ++ ++/// MAC HT capability information element ++struct mac_htcapability { ++ /// HT capability information ++ u16_l ht_capa_info; ++ /// A-MPDU parameters ++ u8_l a_mpdu_param; ++ /// Supported MCS ++ u8_l mcs_rate[MAX_MCS_LEN]; ++ /// HT extended capability information ++ u16_l ht_extended_capa; ++ /// Beamforming capability information ++ u32_l tx_beamforming_capa; ++ /// Antenna selection capability information ++ u8_l asel_capa; ++}; ++ ++/// MAC VHT capability information element ++struct mac_vhtcapability { ++ /// VHT capability information ++ u32_l vht_capa_info; ++ /// RX MCS map ++ u16_l rx_mcs_map; ++ /// RX highest data rate ++ u16_l rx_highest; ++ /// TX MCS map ++ u16_l tx_mcs_map; ++ /// TX highest data rate ++ u16_l tx_highest; ++}; ++ ++/// Length (in bytes) of the MAC HE capability field ++#define MAC_HE_MAC_CAPA_LEN 6 ++/// Length (in bytes) of the PHY HE capability field ++#define MAC_HE_PHY_CAPA_LEN 11 ++/// Maximum length (in bytes) of the PPE threshold data ++#define MAC_HE_PPE_THRES_MAX_LEN 25 ++ ++/// Structure listing the per-NSS, per-BW supported MCS combinations ++struct mac_he_mcs_nss_supp { ++ /// per-NSS supported MCS in RX, for BW <= 80MHz ++ u16_l rx_mcs_80; ++ /// per-NSS supported MCS in TX, for BW <= 80MHz ++ u16_l tx_mcs_80; ++ /// per-NSS supported MCS in RX, for BW = 160MHz ++ u16_l rx_mcs_160; ++ /// per-NSS supported MCS in TX, for BW = 160MHz ++ u16_l tx_mcs_160; ++ /// per-NSS supported MCS in RX, for BW = 80+80MHz ++ u16_l rx_mcs_80p80; ++ /// per-NSS supported MCS in TX, for BW = 80+80MHz ++ u16_l tx_mcs_80p80; ++}; ++ ++/// MAC HE capability information element ++struct mac_hecapability { ++ /// MAC HE capabilities ++ u8_l mac_cap_info[MAC_HE_MAC_CAPA_LEN]; ++ /// PHY HE capabilities ++ u8_l phy_cap_info[MAC_HE_PHY_CAPA_LEN]; ++ /// Supported MCS combinations ++ struct mac_he_mcs_nss_supp mcs_supp; ++ /// PPE Thresholds data ++ u8_l ppe_thres[MAC_HE_PPE_THRES_MAX_LEN]; ++}; ++ ++/// Station flags ++enum mac_sta_flags { ++ /// Bit indicating that a STA has QoS (WMM) capability ++ STA_QOS_CAPA = BIT(0), ++ /// Bit indicating that a STA has HT capability ++ STA_HT_CAPA = BIT(1), ++ /// Bit indicating that a STA has VHT capability ++ STA_VHT_CAPA = BIT(2), ++ /// Bit indicating that a STA has MFP capability ++ STA_MFP_CAPA = BIT(3), ++ /// Bit indicating that the STA included the Operation Notification IE ++ STA_OPMOD_NOTIF = BIT(4), ++ /// Bit indicating that a STA has HE capability ++ STA_HE_CAPA = BIT(5), ++}; ++ ++/// Connection flags ++enum mac_connection_flags { ++ /// Flag indicating whether the control port is controlled by host or not ++ CONTROL_PORT_HOST = BIT(0), ++ /// Flag indicating whether the control port frame shall be sent unencrypted ++ CONTROL_PORT_NO_ENC = BIT(1), ++ /// Flag indicating whether HT and VHT shall be disabled or not ++ DISABLE_HT = BIT(2), ++ /// Flag indicating whether WPA or WPA2 authentication is in use ++ WPA_WPA2_IN_USE = BIT(3), ++ /// Flag indicating whether MFP is in use ++ MFP_IN_USE = BIT(4), ++ // Flag indicating Roam ++ REASSOCIATION = BIT(5), ++}; ++ ++#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 ++#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G 0x04 ++#define IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD 0x20 ++#define IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US 0x40 ++#define IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS 0x80 ++#define IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS 0x01 ++#define IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US 0x02 ++#define IEEE80211_HE_PHY_CAP2_DOPPLER_RX 0x20 ++#define IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ 0x08 ++#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM 0x18 ++#define IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1 0x00 ++#define IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA 0x40 ++#define IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE 0x01 ++#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4 0x0c ++#define IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK 0x40 ++#define IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK 0x80 ++#define IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU 0x01 ++#define IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU 0x02 ++#define IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB 0x04 ++#define IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB 0x08 ++#define IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT 0x80 ++#define IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO 0x40 ++#define IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI 0x04 ++#define IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G 0x02 ++#define IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB 0x10 ++#define IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB 0x20 ++ ++#define IEEE80211_HE_PPE_THRES_MAX_LEN 25 ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) ++#define WLAN_EID_EXTENSION 255 ++/* Element ID Extensions for Element ID 255 */ ++ ++enum ieee80211_eid_ext { ++ WLAN_EID_EXT_ASSOC_DELAY_INFO = 1, ++ WLAN_EID_EXT_FILS_REQ_PARAMS = 2, ++ WLAN_EID_EXT_FILS_KEY_CONFIRM = 3, ++ WLAN_EID_EXT_FILS_SESSION = 4, ++ WLAN_EID_EXT_FILS_HLP_CONTAINER = 5, ++ WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN = 6, ++ WLAN_EID_EXT_KEY_DELIVERY = 7, ++ WLAN_EID_EXT_FILS_WRAPPED_DATA = 8, ++ WLAN_EID_EXT_FILS_PUBLIC_KEY = 12, ++ WLAN_EID_EXT_FILS_NONCE = 13, ++ WLAN_EID_EXT_FUTURE_CHAN_GUIDANCE = 14, ++ ++}; ++ ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0) ++#define WLAN_EID_EXT_HE_CAPABILITY 35 ++#define WLAN_EID_EXT_HE_OPERATION 36 ++#define WLAN_EID_EXT_UORA 37 ++#define WLAN_EID_EXT_HE_MU_EDCA 38 ++#define WLAN_EID_EXT_HE_SPR 39 ++#define WLAN_EID_EXT_NDP_FEEDBACK_REPORT_PARAMSET 41 ++#define WLAN_EID_EXT_BSS_COLOR_CHG_ANN 42 ++#define WLAN_EID_EXT_QUIET_TIME_PERIOD_SETUP 43 ++#define WLAN_EID_EXT_ESS_REPORT 45 ++#define WLAN_EID_EXT_OPS 46 ++#define WLAN_EID_EXT_HE_BSS_LOAD 47 ++#define WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME 52 ++#define WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION 55 ++#define WLAN_EID_EXT_NON_INHERITANCE 56 ++#define WLAN_EID_EXT_KNOWN_BSSID 57 ++#define WLAN_EID_EXT_SHORT_SSID_LIST 58 ++#define WLAN_EID_EXT_HE_6GHZ_CAPA 59 ++#define WLAN_EID_EXT_UL_MU_POWER_CAPA 60 ++#define WLAN_EID_EXT_EHT_OPERATION 106 ++#define WLAN_EID_EXT_EHT_MULTI_LINK 107 ++#define WLAN_EID_EXT_EHT_CAPABILITY 108 ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) ++#include ++#else ++struct ieee80211_he_cap_elem { ++ u8 mac_cap_info[6]; ++ u8 phy_cap_info[11]; ++} __packed; ++ ++struct ieee80211_he_mcs_nss_supp { ++ __le16 rx_mcs_80; ++ __le16 tx_mcs_80; ++ __le16 rx_mcs_160; ++ __le16 tx_mcs_160; ++ __le16 rx_mcs_80p80; ++ __le16 tx_mcs_80p80; ++} __packed; ++ ++struct ieee80211_sta_he_cap { ++ bool has_he; ++ struct ieee80211_he_cap_elem he_cap_elem; ++ struct ieee80211_he_mcs_nss_supp he_mcs_nss_supp; ++ u8 ppe_thres[IEEE80211_HE_PPE_THRES_MAX_LEN]; ++}; ++ ++struct ieee80211_sband_iftype_data { ++ u16 types_mask; ++ struct ieee80211_sta_he_cap he_cap; ++}; ++#endif ++#endif ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0) || \ ++ defined(CONFIG_VHT_FOR_OLD_KERNEL) ++struct ieee80211_vht_mcs_info { ++ __le16 rx_mcs_map; ++ __le16 rx_highest; ++ __le16 tx_mcs_map; ++ __le16 tx_highest; ++} __packed; ++ ++struct ieee80211_vht_cap { ++ __le32 vht_cap_info; ++ struct ieee80211_vht_mcs_info supp_mcs; ++}; ++#define WLAN_EID_VHT_CAPABILITY 191 ++ ++struct ieee80211_sta_vht_cap { ++ bool vht_supported; ++ u32 cap; /* use IEEE80211_VHT_CAP_ */ ++ struct ieee80211_vht_mcs_info vht_mcs; ++}; ++#endif ++#endif // LMAC_MAC_H_ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/lmac_msg.h b/drivers/net/wireless/aic8800/aic8800_fdrv/lmac_msg.h +new file mode 100755 +index 000000000..f5aa6e3af +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/lmac_msg.h +@@ -0,0 +1,3159 @@ ++/** ++ **************************************************************************************** ++ * ++ * @file lmac_msg.h ++ * ++ * @brief Main definitions for message exchanges with LMAC ++ * ++ * Copyright (C) RivieraWaves 2011-2019 ++ * ++ **************************************************************************************** ++ */ ++ ++#ifndef LMAC_MSG_H_ ++#define LMAC_MSG_H_ ++ ++/* ++ * INCLUDE FILES ++ **************************************************************************************** ++ */ ++// for MAC related elements (mac_addr, mac_ssid...) ++#include "lmac_mac.h" ++ ++#define LMAC_MSG_MAX_LEN 1024 ++ ++/* ++ **************************************************************************************** ++ */ ++///////////////////////////////////////////////////////////////////////////////// ++// COMMUNICATION WITH LMAC LAYER ++///////////////////////////////////////////////////////////////////////////////// ++/* Task identifiers for communication between LMAC and DRIVER */ ++enum { ++ TASK_NONE = (u8_l)-1, ++ ++ // MAC Management task. ++ TASK_MM = 0, ++ // DEBUG task ++ TASK_DBG, ++ /// SCAN task ++ TASK_SCAN, ++ /// TDLS task ++ TASK_TDLS, ++ /// SCANU task ++ TASK_SCANU, ++ /// ME task ++ TASK_ME, ++ /// SM task ++ TASK_SM, ++ /// APM task ++ TASK_APM, ++ /// BAM task ++ TASK_BAM, ++ /// MESH task ++ TASK_MESH, ++ /// RXU task ++ TASK_RXU, ++ /// RM_task ++ TASK_RM, ++ /// TWT task ++ TASK_TWT, ++#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_TWT, ++#else ++#error "Need to define SOFTMAC or FULLMAC" ++#endif ++ // nX API task ++ TASK_API, ++ TASK_MAX, ++}; ++ ++/// For MAC HW States copied from "hal_machw.h" ++enum { ++ /// MAC HW IDLE State. ++ HW_IDLE = 0, ++ /// MAC HW RESERVED State. ++ HW_RESERVED, ++ /// MAC HW DOZE State. ++ HW_DOZE, ++ /// MAC HW ACTIVE State. ++ HW_ACTIVE ++}; ++ ++/// Power Save mode setting ++enum mm_ps_mode_state { ++ MM_PS_MODE_OFF, ++ MM_PS_MODE_ON, ++ MM_PS_MODE_ON_DYN, ++}; ++ ++/// Status/error codes used in the MAC software. ++enum { ++ CO_OK, ++ CO_FAIL, ++ CO_EMPTY, ++ CO_FULL, ++ CO_BAD_PARAM, ++ CO_NOT_FOUND, ++ CO_NO_MORE_ELT_AVAILABLE, ++ CO_NO_ELT_IN_USE, ++ CO_BUSY, ++ CO_OP_IN_PROGRESS, ++}; ++ ++/// Remain on channel operation codes ++enum mm_remain_on_channel_op { ++ MM_ROC_OP_START = 0, ++ MM_ROC_OP_CANCEL, ++}; ++ ++#define DRV_TASK_ID 100 ++ ++/// Message Identifier. The number of messages is limited to 0xFFFF. ++/// The message ID is divided in two parts: ++/// - bits[15..10] : task index (no more than 64 tasks supported). ++/// - bits[9..0] : message index (no more that 1024 messages per task). ++typedef u16 lmac_msg_id_t; ++ ++typedef u16 lmac_task_id_t; ++ ++/// Build the first message ID of a task. ++#define LMAC_FIRST_MSG(task) ((lmac_msg_id_t)((task) << 10)) ++ ++#define MSG_T(msg) ((lmac_task_id_t)((msg) >> 10)) ++#define MSG_I(msg) ((msg) & ((1 << 10) - 1)) ++ ++/// Message structure. ++struct lmac_msg { ++ lmac_msg_id_t id; ///< Message id. ++ lmac_task_id_t dest_id; ///< Destination kernel identifier. ++ lmac_task_id_t src_id; ///< Source kernel identifier. ++ u16 param_len; ///< Parameter embedded struct length. ++ u32 param[]; ///< Parameter embedded struct. Must be word-aligned. ++}; ++ ++/// List of messages related to the task. ++enum mm_msg_tag { ++ /// RESET Request. ++ MM_RESET_REQ = LMAC_FIRST_MSG(TASK_MM), ++ /// RESET Confirmation. ++ MM_RESET_CFM, ++ /// START Request. ++ MM_START_REQ, ++ /// START Confirmation. ++ MM_START_CFM, ++ /// Read Version Request. ++ MM_VERSION_REQ, ++ /// Read Version Confirmation. ++ MM_VERSION_CFM, ++ /// ADD INTERFACE Request. ++ MM_ADD_IF_REQ, ++ /// ADD INTERFACE Confirmation. ++ MM_ADD_IF_CFM, ++ /// REMOVE INTERFACE Request. ++ MM_REMOVE_IF_REQ, ++ /// REMOVE INTERFACE Confirmation. ++ MM_REMOVE_IF_CFM, ++ /// STA ADD Request. ++ MM_STA_ADD_REQ, ++ /// STA ADD Confirm. ++ MM_STA_ADD_CFM, ++ /// STA DEL Request. ++ MM_STA_DEL_REQ, ++ /// STA DEL Confirm. ++ MM_STA_DEL_CFM, ++ /// RX FILTER CONFIGURATION Request. ++ MM_SET_FILTER_REQ, ++ /// RX FILTER CONFIGURATION Confirmation. ++ MM_SET_FILTER_CFM, ++ /// CHANNEL CONFIGURATION Request. ++ MM_SET_CHANNEL_REQ, ++ /// CHANNEL CONFIGURATION Confirmation. ++ MM_SET_CHANNEL_CFM, ++ /// DTIM PERIOD CONFIGURATION Request. ++ MM_SET_DTIM_REQ, ++ /// DTIM PERIOD CONFIGURATION Confirmation. ++ MM_SET_DTIM_CFM, ++ /// BEACON INTERVAL CONFIGURATION Request. ++ MM_SET_BEACON_INT_REQ, ++ /// BEACON INTERVAL CONFIGURATION Confirmation. ++ MM_SET_BEACON_INT_CFM, ++ /// BASIC RATES CONFIGURATION Request. ++ MM_SET_BASIC_RATES_REQ, ++ /// BASIC RATES CONFIGURATION Confirmation. ++ MM_SET_BASIC_RATES_CFM, ++ /// BSSID CONFIGURATION Request. ++ MM_SET_BSSID_REQ, ++ /// BSSID CONFIGURATION Confirmation. ++ MM_SET_BSSID_CFM, ++ /// EDCA PARAMETERS CONFIGURATION Request. ++ MM_SET_EDCA_REQ, ++ /// EDCA PARAMETERS CONFIGURATION Confirmation. ++ MM_SET_EDCA_CFM, ++ /// ABGN MODE CONFIGURATION Request. ++ MM_SET_MODE_REQ, ++ /// ABGN MODE CONFIGURATION Confirmation. ++ MM_SET_MODE_CFM, ++ /// Request setting the VIF active state (i.e associated or AP started) ++ MM_SET_VIF_STATE_REQ, ++ /// Confirmation of the @ref MM_SET_VIF_STATE_REQ message. ++ MM_SET_VIF_STATE_CFM, ++ /// SLOT TIME PARAMETERS CONFIGURATION Request. ++ MM_SET_SLOTTIME_REQ, ++ /// SLOT TIME PARAMETERS CONFIGURATION Confirmation. ++ MM_SET_SLOTTIME_CFM, ++ /// Power Mode Change Request. ++ MM_SET_IDLE_REQ, ++ /// Power Mode Change Confirm. ++ MM_SET_IDLE_CFM, ++ /// KEY ADD Request. ++ MM_KEY_ADD_REQ, ++ /// KEY ADD Confirm. ++ MM_KEY_ADD_CFM, ++ /// KEY DEL Request. ++ MM_KEY_DEL_REQ, ++ /// KEY DEL Confirm. ++ MM_KEY_DEL_CFM, ++ /// Block Ack agreement info addition ++ MM_BA_ADD_REQ, ++ /// Block Ack agreement info addition confirmation ++ MM_BA_ADD_CFM, ++ /// Block Ack agreement info deletion ++ MM_BA_DEL_REQ, ++ /// Block Ack agreement info deletion confirmation ++ MM_BA_DEL_CFM, ++ /// Indication of the primary TBTT to the upper MAC. Upon the reception of this ++ // message the upper MAC has to push the beacon(s) to the beacon transmission queue. ++ MM_PRIMARY_TBTT_IND, ++ /// Indication of the secondary TBTT to the upper MAC. Upon the reception of this ++ // message the upper MAC has to push the beacon(s) to the beacon transmission queue. ++ MM_SECONDARY_TBTT_IND, ++ /// Request for changing the TX power ++ MM_SET_POWER_REQ, ++ /// Confirmation of the TX power change ++ MM_SET_POWER_CFM, ++ /// Request to the LMAC to trigger the embedded logic analyzer and forward the debug ++ /// dump. ++ MM_DBG_TRIGGER_REQ, ++ /// Set Power Save mode ++ MM_SET_PS_MODE_REQ, ++ /// Set Power Save mode confirmation ++ MM_SET_PS_MODE_CFM, ++ /// Request to add a channel context ++ MM_CHAN_CTXT_ADD_REQ, ++ /// Confirmation of the channel context addition ++ MM_CHAN_CTXT_ADD_CFM, ++ /// Request to delete a channel context ++ MM_CHAN_CTXT_DEL_REQ, ++ /// Confirmation of the channel context deletion ++ MM_CHAN_CTXT_DEL_CFM, ++ /// Request to link a channel context to a VIF ++ MM_CHAN_CTXT_LINK_REQ, ++ /// Confirmation of the channel context link ++ MM_CHAN_CTXT_LINK_CFM, ++ /// Request to unlink a channel context from a VIF ++ MM_CHAN_CTXT_UNLINK_REQ, ++ /// Confirmation of the channel context unlink ++ MM_CHAN_CTXT_UNLINK_CFM, ++ /// Request to update a channel context ++ MM_CHAN_CTXT_UPDATE_REQ, ++ /// Confirmation of the channel context update ++ MM_CHAN_CTXT_UPDATE_CFM, ++ /// Request to schedule a channel context ++ MM_CHAN_CTXT_SCHED_REQ, ++ /// Confirmation of the channel context scheduling ++ MM_CHAN_CTXT_SCHED_CFM, ++ /// Request to change the beacon template in LMAC ++ MM_BCN_CHANGE_REQ, ++ /// Confirmation of the beacon change ++ MM_BCN_CHANGE_CFM, ++ /// Request to update the TIM in the beacon (i.e to indicate traffic bufferized at AP) ++ MM_TIM_UPDATE_REQ, ++ /// Confirmation of the TIM update ++ MM_TIM_UPDATE_CFM, ++ /// Connection loss indication ++ MM_CONNECTION_LOSS_IND, ++ /// Channel context switch indication to the upper layers ++ MM_CHANNEL_SWITCH_IND, ++ /// Channel context pre-switch indication to the upper layers ++ MM_CHANNEL_PRE_SWITCH_IND, ++ /// Request to remain on channel or cancel remain on channel ++ MM_REMAIN_ON_CHANNEL_REQ, ++ /// Confirmation of the (cancel) remain on channel request ++ MM_REMAIN_ON_CHANNEL_CFM, ++ /// Remain on channel expired indication ++ MM_REMAIN_ON_CHANNEL_EXP_IND, ++ /// Indication of a PS state change of a peer device ++ MM_PS_CHANGE_IND, ++ /// Indication that some buffered traffic should be sent to the peer device ++ MM_TRAFFIC_REQ_IND, ++ /// Request to modify the STA Power-save mode options ++ MM_SET_PS_OPTIONS_REQ, ++ /// Confirmation of the PS options setting ++ MM_SET_PS_OPTIONS_CFM, ++ /// Indication of PS state change for a P2P VIF ++ MM_P2P_VIF_PS_CHANGE_IND, ++ /// Indication that CSA counter has been updated ++ MM_CSA_COUNTER_IND, ++ /// Channel occupation report indication ++ MM_CHANNEL_SURVEY_IND, ++ /// Message containing Beamformer Information ++ MM_BFMER_ENABLE_REQ, ++ /// Request to Start/Stop/Update NOA - GO Only ++ MM_SET_P2P_NOA_REQ, ++ /// Request to Start/Stop/Update Opportunistic PS - GO Only ++ MM_SET_P2P_OPPPS_REQ, ++ /// Start/Stop/Update NOA Confirmation ++ MM_SET_P2P_NOA_CFM, ++ /// Start/Stop/Update Opportunistic PS Confirmation ++ MM_SET_P2P_OPPPS_CFM, ++ /// P2P NoA Update Indication - GO Only ++ MM_P2P_NOA_UPD_IND, ++ /// Request to set RSSI threshold and RSSI hysteresis ++ MM_CFG_RSSI_REQ, ++ /// Indication that RSSI level is below or above the threshold ++ MM_RSSI_STATUS_IND, ++ /// Indication that CSA is done ++ MM_CSA_FINISH_IND, ++ /// Indication that CSA is in prorgess (resp. done) and traffic must be stopped (resp. restarted) ++ MM_CSA_TRAFFIC_IND, ++ /// Request to update the group information of a station ++ MM_MU_GROUP_UPDATE_REQ, ++ /// Confirmation of the @ref MM_MU_GROUP_UPDATE_REQ message ++ MM_MU_GROUP_UPDATE_CFM, ++ /// Request to initialize the antenna diversity algorithm ++ MM_ANT_DIV_INIT_REQ, ++ /// Request to stop the antenna diversity algorithm ++ MM_ANT_DIV_STOP_REQ, ++ /// Request to update the antenna switch status ++ MM_ANT_DIV_UPDATE_REQ, ++ /// Request to switch the antenna connected to path_0 ++ MM_SWITCH_ANTENNA_REQ, ++ /// Indication that a packet loss has occurred ++ MM_PKTLOSS_IND, ++ ++ MM_SET_ARPOFFLOAD_REQ, ++ MM_SET_ARPOFFLOAD_CFM, ++ MM_SET_AGG_DISABLE_REQ, ++ MM_SET_AGG_DISABLE_CFM, ++ MM_SET_COEX_REQ, ++ MM_SET_COEX_CFM, ++ MM_SET_RF_CONFIG_REQ, ++ MM_SET_RF_CONFIG_CFM, ++ MM_SET_RF_CALIB_REQ, ++ MM_SET_RF_CALIB_CFM, ++ ++ /// MU EDCA PARAMETERS Configuration Request. ++ MM_SET_MU_EDCA_REQ, ++ /// MU EDCA PARAMETERS Configuration Confirmation. ++ MM_SET_MU_EDCA_CFM, ++ /// UORA PARAMETERS Configuration Request. ++ MM_SET_UORA_REQ, ++ /// UORA PARAMETERS Configuration Confirmation. ++ MM_SET_UORA_CFM, ++ /// TXOP RTS THRESHOLD Configuration Request. ++ MM_SET_TXOP_RTS_THRES_REQ, ++ /// TXOP RTS THRESHOLD Configuration Confirmation. ++ MM_SET_TXOP_RTS_THRES_CFM, ++ /// HE BSS Color Configuration Request. ++ MM_SET_BSS_COLOR_REQ, ++ /// HE BSS Color Configuration Confirmation. ++ MM_SET_BSS_COLOR_CFM, ++ ++ MM_GET_MAC_ADDR_REQ, ++ MM_GET_MAC_ADDR_CFM, ++ ++ MM_GET_STA_INFO_REQ, ++ MM_GET_STA_INFO_CFM, ++ ++ MM_SET_TXPWR_IDX_LVL_REQ, ++ MM_SET_TXPWR_IDX_LVL_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_VENDOR_HWCONFIG_REQ, ++ MM_SET_VENDOR_HWCONFIG_CFM, ++ ++ MM_GET_FW_VERSION_REQ, ++ MM_GET_FW_VERSION_CFM, ++ ++ MM_SET_RESUME_RESTORE_REQ, ++ MM_SET_RESUME_RESTORE_CFM, ++ ++ MM_GET_WIFI_DISABLE_REQ, ++ MM_GET_WIFI_DISABLE_CFM, ++ ++ MM_CFG_RSSI_CFM, ++ ++ MM_SET_VENDOR_SWCONFIG_REQ, ++ MM_SET_VENDOR_SWCONFIG_CFM, ++ ++ MM_SET_TXPWR_LVL_ADJ_REQ, ++ MM_SET_TXPWR_LVL_ADJ_CFM, ++ ++ MM_RADAR_DETECT_IND, ++ ++ MM_SET_APF_PROG_REQ, ++ MM_SET_APF_PROG_CFM, ++ ++ MM_GET_APF_PROG_REQ, ++ MM_GET_APF_PROG_CFM, ++ ++ /// MAX number of messages ++ MM_MAX, ++}; ++ ++/// Interface types ++enum { ++ /// ESS STA interface ++ MM_STA, ++ /// IBSS STA interface ++ MM_IBSS, ++ /// AP interface ++ MM_AP, ++ // Mesh Point interface ++ MM_MESH_POINT, ++ // Monitor interface ++ MM_MONITOR, ++}; ++ ++///BA agreement types ++enum { ++ ///BlockAck agreement for TX ++ BA_AGMT_TX, ++ ///BlockAck agreement for RX ++ BA_AGMT_RX, ++}; ++ ++///BA agreement related status ++enum { ++ ///Correct BA agreement establishment ++ BA_AGMT_ESTABLISHED, ++ ///BA agreement already exists for STA+TID requested, cannot override it (should have been deleted first) ++ BA_AGMT_ALREADY_EXISTS, ++ ///Correct BA agreement deletion ++ BA_AGMT_DELETED, ++ ///BA agreement for the (STA, TID) doesn't exist so nothing to delete ++ BA_AGMT_DOESNT_EXIST, ++}; ++ ++/// Features supported by LMAC - Positions ++enum mm_features { ++ /// Beaconing ++ MM_FEAT_BCN_BIT = 0, ++ /* ++ /// Autonomous Beacon Transmission ++ MM_FEAT_AUTOBCN_BIT, ++ /// Scan in LMAC ++ MM_FEAT_HWSCAN_BIT, ++ /// Connection Monitoring ++ MM_FEAT_CMON_BIT, ++ /// Multi Role ++ MM_FEAT_MROLE_BIT, ++*/ ++ /// Radar Detection ++ MM_FEAT_RADAR_BIT, ++ /// Power Save ++ MM_FEAT_PS_BIT, ++ /// UAPSD ++ MM_FEAT_UAPSD_BIT, ++ /// DPSM ++ // MM_FEAT_DPSM_BIT, ++ /// A-MPDU ++ MM_FEAT_AMPDU_BIT, ++ /// A-MSDU ++ MM_FEAT_AMSDU_BIT, ++ /// Channel Context ++ // MM_FEAT_CHNL_CTXT_BIT, ++ /// Packet reordering ++ // MM_FEAT_REORD_BIT, ++ /// P2P ++ MM_FEAT_P2P_BIT, ++ /// P2P Go ++ MM_FEAT_P2P_GO_BIT, ++ /// UMAC Present ++ MM_FEAT_UMAC_BIT, ++ /// VHT support ++ MM_FEAT_VHT_BIT, ++ /// Beamformee ++ MM_FEAT_BFMEE_BIT, ++ /// Beamformer ++ MM_FEAT_BFMER_BIT, ++ /// WAPI ++ MM_FEAT_WAPI_BIT, ++ /// MFP ++ MM_FEAT_MFP_BIT, ++ /// Mu-MIMO RX support ++ MM_FEAT_MU_MIMO_RX_BIT, ++ /// Mu-MIMO TX support ++ MM_FEAT_MU_MIMO_TX_BIT, ++ /// Wireless Mesh Networking ++ MM_FEAT_MESH_BIT, ++ /// TDLS support ++ MM_FEAT_TDLS_BIT, ++ /// Antenna Diversity support ++ MM_FEAT_ANT_DIV_BIT, ++ /// UF support ++ MM_FEAT_UF_BIT, ++ /// A-MSDU maximum size (bit0) ++ MM_AMSDU_MAX_SIZE_BIT0, ++ /// A-MSDU maximum size (bit1) ++ MM_AMSDU_MAX_SIZE_BIT1, ++ /// MON_DATA support ++ MM_FEAT_MON_DATA_BIT, ++ /// HE (802.11ax) support ++ MM_FEAT_HE_BIT, ++ /// TWT support ++ MM_FEAT_TWT_BIT, ++}; ++ ++/// Maximum number of words in the configuration buffer ++#define PHY_CFG_BUF_SIZE 16 ++ ++/// Structure containing the parameters of the PHY configuration ++struct phy_cfg_tag { ++ /// Buffer containing the parameters specific for the PHY used ++ u32_l parameters[PHY_CFG_BUF_SIZE]; ++}; ++ ++/// Structure containing the parameters of the Trident PHY configuration ++struct phy_trd_cfg_tag { ++ /// MDM type(nxm)(upper nibble) and MDM2RF path mapping(lower nibble) ++ u8_l path_mapping; ++ /// TX DC offset compensation ++ u32_l tx_dc_off_comp; ++}; ++ ++/// Structure containing the parameters of the Karst PHY configuration ++struct phy_karst_cfg_tag { ++ /// TX IQ mismatch compensation in 2.4GHz ++ u32_l tx_iq_comp_2_4G[2]; ++ /// RX IQ mismatch compensation in 2.4GHz ++ u32_l rx_iq_comp_2_4G[2]; ++ /// TX IQ mismatch compensation in 5GHz ++ u32_l tx_iq_comp_5G[2]; ++ /// RX IQ mismatch compensation in 5GHz ++ u32_l rx_iq_comp_5G[2]; ++ /// RF path used by default (0 or 1) ++ u8_l path_used; ++}; ++ ++/// Structure containing the parameters of the @ref MM_START_REQ message ++struct mm_start_req { ++ /// PHY configuration ++ struct phy_cfg_tag phy_cfg; ++ /// UAPSD timeout ++ u32_l uapsd_timeout; ++ /// Local LP clock accuracy (in ppm) ++ u16_l lp_clk_accuracy; ++}; ++ ++/// Structure containing the parameters of the @ref MM_SET_CHANNEL_REQ message ++struct mm_set_channel_req { ++ /// Channel information ++ struct mac_chan_op chan; ++ /// Index of the RF for which the channel has to be set (0: operating (primary), 1: secondary ++ /// RF (used for additional radar detection). This parameter is reserved if no secondary RF ++ /// is available in the system ++ u8_l index; ++}; ++ ++/// Structure containing the parameters of the @ref MM_SET_CHANNEL_CFM message ++struct mm_set_channel_cfm { ++ /// Radio index to be used in policy table ++ u8_l radio_idx; ++ /// TX power configured (in dBm) ++ s8_l power; ++}; ++ ++/// Structure containing the parameters of the @ref MM_SET_DTIM_REQ message ++struct mm_set_dtim_req { ++ /// DTIM period ++ u8_l dtim_period; ++}; ++ ++/// Structure containing the parameters of the @ref MM_SET_POWER_REQ message ++struct mm_set_power_req { ++ /// Index of the interface for which the parameter is configured ++ u8_l inst_nbr; ++ /// TX power (in dBm) ++ s8_l power; ++}; ++ ++/// Structure containing the parameters of the @ref MM_SET_POWER_CFM message ++struct mm_set_power_cfm { ++ /// Radio index to be used in policy table ++ u8_l radio_idx; ++ /// TX power configured (in dBm) ++ s8_l power; ++}; ++ ++/// Structure containing the parameters of the @ref MM_SET_BEACON_INT_REQ message ++struct mm_set_beacon_int_req { ++ /// Beacon interval ++ u16_l beacon_int; ++ /// Index of the interface for which the parameter is configured ++ u8_l inst_nbr; ++}; ++ ++/// Structure containing the parameters of the @ref MM_SET_BASIC_RATES_REQ message ++struct mm_set_basic_rates_req { ++ /// Basic rate set (as expected by bssBasicRateSet field of Rates MAC HW register) ++ u32_l rates; ++ /// Index of the interface for which the parameter is configured ++ u8_l inst_nbr; ++ /// Band on which the interface will operate ++ u8_l band; ++}; ++ ++/// Structure containing the parameters of the @ref MM_SET_BSSID_REQ message ++struct mm_set_bssid_req { ++ /// BSSID to be configured in HW ++ struct mac_addr bssid; ++ /// Index of the interface for which the parameter is configured ++ u8_l inst_nbr; ++}; ++ ++/// Structure containing the parameters of the @ref MM_SET_FILTER_REQ message ++struct mm_set_filter_req { ++ /// RX filter to be put into rxCntrlReg HW register ++ u32_l filter; ++}; ++ ++/// Structure containing the parameters of the @ref MM_ADD_IF_REQ message. ++struct mm_add_if_req { ++ /// Type of the interface (AP, STA, ADHOC, ...) ++ u8_l type; ++ /// MAC ADDR of the interface to start ++ struct mac_addr addr; ++ /// P2P Interface ++ bool_l p2p; ++}; ++ ++/// Structure containing the parameters of the @ref MM_SET_EDCA_REQ message ++struct mm_set_edca_req { ++ /// EDCA parameters of the queue (as expected by edcaACxReg HW register) ++ u32_l ac_param; ++ /// Flag indicating if UAPSD can be used on this queue ++ bool_l uapsd; ++ /// HW queue for which the parameters are configured ++ u8_l hw_queue; ++ /// Index of the interface for which the parameters are configured ++ u8_l inst_nbr; ++}; ++ ++/// Structure containing the parameters of the @ref MM_SET_MU_EDCA_REQ message ++struct mm_set_mu_edca_req { ++ /// MU EDCA parameters of the different HE queues ++ u32_l param[AC_MAX]; ++}; ++ ++/// Structure containing the parameters of the @ref MM_SET_UORA_REQ message ++struct mm_set_uora_req { ++ /// Minimum exponent of OFDMA Contention Window. ++ u8_l eocw_min; ++ /// Maximum exponent of OFDMA Contention Window. ++ u8_l eocw_max; ++}; ++ ++/// Structure containing the parameters of the @ref MM_SET_TXOP_RTS_THRES_REQ message ++struct mm_set_txop_rts_thres_req { ++ /// TXOP RTS threshold ++ u16_l txop_dur_rts_thres; ++ /// Index of the interface for which the parameter is configured ++ u8_l inst_nbr; ++}; ++ ++/// Structure containing the parameters of the @ref MM_SET_BSS_COLOR_REQ message ++struct mm_set_bss_color_req { ++ /// HE BSS color, formatted as per BSS_COLOR MAC HW register ++ u32_l bss_color; ++}; ++ ++struct mm_set_idle_req { ++ u8_l hw_idle; ++}; ++ ++/// Structure containing the parameters of the @ref MM_SET_SLOTTIME_REQ message ++struct mm_set_slottime_req { ++ /// Slot time expressed in us ++ u8_l slottime; ++}; ++ ++/// Structure containing the parameters of the @ref MM_SET_MODE_REQ message ++struct mm_set_mode_req { ++ /// abgnMode field of macCntrl1Reg register ++ u8_l abgnmode; ++}; ++ ++/// Structure containing the parameters of the @ref MM_SET_VIF_STATE_REQ message ++struct mm_set_vif_state_req { ++ /// Association Id received from the AP (valid only if the VIF is of STA type) ++ u16_l aid; ++ /// Flag indicating if the VIF is active or not ++ bool_l active; ++ /// Interface index ++ u8_l inst_nbr; ++}; ++ ++/// Structure containing the parameters of the @ref MM_ADD_IF_CFM message. ++struct mm_add_if_cfm { ++ /// Status of operation (different from 0 if unsuccessful) ++ u8_l status; ++ /// Interface index assigned by the LMAC ++ u8_l inst_nbr; ++}; ++ ++/// Structure containing the parameters of the @ref MM_REMOVE_IF_REQ message. ++struct mm_remove_if_req { ++ /// Interface index assigned by the LMAC ++ u8_l inst_nbr; ++}; ++ ++/// Structure containing the parameters of the @ref MM_VERSION_CFM message. ++struct mm_version_cfm { ++ /// Version of the LMAC FW ++ u32_l version_lmac; ++ /// Version1 of the MAC HW (as encoded in version1Reg MAC HW register) ++ u32_l version_machw_1; ++ /// Version2 of the MAC HW (as encoded in version2Reg MAC HW register) ++ u32_l version_machw_2; ++ /// Version1 of the PHY (depends on actual PHY) ++ u32_l version_phy_1; ++ /// Version2 of the PHY (depends on actual PHY) ++ u32_l version_phy_2; ++ /// Supported Features ++ u32_l features; ++ /// Maximum number of supported stations ++ u16_l max_sta_nb; ++ /// Maximum number of supported virtual interfaces ++ u8_l max_vif_nb; ++}; ++ ++/// Structure containing the parameters of the @ref MM_STA_ADD_REQ message. ++struct mm_sta_add_req { ++ /// Bitfield showing some capabilities of the STA (@ref enum mac_sta_flags) ++ u32_l capa_flags; ++ /// Maximum A-MPDU size, in bytes, for HE frames ++ u32_l ampdu_size_max_he; ++ /// Maximum A-MPDU size, in bytes, for VHT frames ++ u32_l ampdu_size_max_vht; ++ /// PAID/GID ++ u32_l paid_gid; ++ /// Maximum A-MPDU size, in bytes, for HT frames ++ u16_l ampdu_size_max_ht; ++ /// MAC address of the station to be added ++ struct mac_addr mac_addr; ++ /// A-MPDU spacing, in us ++ u8_l ampdu_spacing_min; ++ /// Interface index ++ u8_l inst_nbr; ++ /// TDLS station ++ bool_l tdls_sta; ++ /// Indicate if the station is TDLS link initiator station ++ bool_l tdls_sta_initiator; ++ /// Indicate if the TDLS Channel Switch is allowed ++ bool_l tdls_chsw_allowed; ++ /// nonTransmitted BSSID index, set to the BSSID index in case the STA added is an AP ++ /// that is a nonTransmitted BSSID. Should be set to 0 otherwise ++ u8_l bssid_index; ++ /// Maximum BSSID indicator, valid if the STA added is an AP that is a nonTransmitted ++ /// BSSID ++ u8_l max_bssid_ind; ++}; ++ ++/// Structure containing the parameters of the @ref MM_STA_ADD_CFM message. ++struct mm_sta_add_cfm { ++ /// Status of the operation (different from 0 if unsuccessful) ++ u8_l status; ++ /// Index assigned by the LMAC to the newly added station ++ u8_l sta_idx; ++ /// MAC HW index of the newly added station ++ u8_l hw_sta_idx; ++}; ++ ++/// Structure containing the parameters of the @ref MM_STA_DEL_REQ message. ++struct mm_sta_del_req { ++ /// Index of the station to be deleted ++ u8_l sta_idx; ++}; ++ ++/// Structure containing the parameters of the @ref MM_STA_DEL_CFM message. ++struct mm_sta_del_cfm { ++ /// Status of the operation (different from 0 if unsuccessful) ++ u8_l status; ++}; ++ ++/// Structure containing the parameters of the SET_POWER_MODE REQ message. ++struct mm_setpowermode_req { ++ u8_l mode; ++ u8_l sta_idx; ++}; ++ ++/// Structure containing the parameters of the SET_POWER_MODE CFM message. ++struct mm_setpowermode_cfm { ++ u8_l status; ++}; ++ ++/// Structure containing the parameters of the @ref MM_KEY_ADD REQ message. ++struct mm_key_add_req { ++ /// Key index (valid only for default keys) ++ u8_l key_idx; ++ /// STA index (valid only for pairwise or mesh group keys) ++ u8_l sta_idx; ++ /// Key material ++ struct mac_sec_key key; ++ /// Cipher suite (WEP64, WEP128, TKIP, CCMP) ++ u8_l cipher_suite; ++ /// Index of the interface for which the key is set (valid only for default keys or mesh group keys) ++ u8_l inst_nbr; ++ /// A-MSDU SPP parameter ++ u8_l spp; ++ /// Indicate if provided key is a pairwise key or not ++ bool_l pairwise; ++}; ++ ++/// Structure containing the parameters of the @ref MM_KEY_ADD_CFM message. ++struct mm_key_add_cfm { ++ /// Status of the operation (different from 0 if unsuccessful) ++ u8_l status; ++ /// HW index of the key just added ++ u8_l hw_key_idx; ++}; ++ ++/// Structure containing the parameters of the @ref MM_KEY_DEL_REQ message. ++struct mm_key_del_req { ++ /// HW index of the key to be deleted ++ u8_l hw_key_idx; ++}; ++ ++/// Structure containing the parameters of the @ref MM_BA_ADD_REQ message. ++struct mm_ba_add_req { ++ ///Type of agreement (0: TX, 1: RX) ++ u8_l type; ++ ///Index of peer station with which the agreement is made ++ u8_l sta_idx; ++ ///TID for which the agreement is made with peer station ++ u8_l tid; ++ ///Buffer size - number of MPDUs that can be held in its buffer per TID ++ u8_l bufsz; ++ /// Start sequence number negotiated during BA setup - the one in first aggregated MPDU counts more ++ u16_l ssn; ++}; ++ ++/// Structure containing the parameters of the @ref MM_BA_ADD_CFM message. ++struct mm_ba_add_cfm { ++ ///Index of peer station for which the agreement is being confirmed ++ u8_l sta_idx; ++ ///TID for which the agreement is being confirmed ++ u8_l tid; ++ /// Status of ba establishment ++ u8_l status; ++}; ++ ++/// Structure containing the parameters of the @ref MM_BA_DEL_REQ message. ++struct mm_ba_del_req { ++ ///Type of agreement (0: TX, 1: RX) ++ u8_l type; ++ ///Index of peer station for which the agreement is being deleted ++ u8_l sta_idx; ++ ///TID for which the agreement is being deleted ++ u8_l tid; ++}; ++ ++/// Structure containing the parameters of the @ref MM_BA_DEL_CFM message. ++struct mm_ba_del_cfm { ++ ///Index of peer station for which the agreement deletion is being confirmed ++ u8_l sta_idx; ++ ///TID for which the agreement deletion is being confirmed ++ u8_l tid; ++ /// Status of ba deletion ++ u8_l status; ++}; ++ ++/// Structure containing the parameters of the @ref MM_CHAN_CTXT_ADD_REQ message ++struct mm_chan_ctxt_add_req { ++ /// Operating channel ++ struct mac_chan_op chan; ++}; ++ ++/// Structure containing the parameters of the @ref MM_CHAN_CTXT_ADD_REQ message ++struct mm_chan_ctxt_add_cfm { ++ /// Status of the addition ++ u8_l status; ++ /// Index of the new channel context ++ u8_l index; ++}; ++ ++/// Structure containing the parameters of the @ref MM_CHAN_CTXT_DEL_REQ message ++struct mm_chan_ctxt_del_req { ++ /// Index of the new channel context to be deleted ++ u8_l index; ++}; ++ ++/// Structure containing the parameters of the @ref MM_CHAN_CTXT_LINK_REQ message ++struct mm_chan_ctxt_link_req { ++ /// VIF index ++ u8_l vif_index; ++ /// Channel context index ++ u8_l chan_index; ++ /// Indicate if this is a channel switch (unlink current ctx first if true) ++ u8_l chan_switch; ++}; ++ ++/// Structure containing the parameters of the @ref MM_CHAN_CTXT_UNLINK_REQ message ++struct mm_chan_ctxt_unlink_req { ++ /// VIF index ++ u8_l vif_index; ++}; ++ ++/// Structure containing the parameters of the @ref MM_CHAN_CTXT_UPDATE_REQ message ++struct mm_chan_ctxt_update_req { ++ /// Channel context index ++ u8_l chan_index; ++ /// New channel information ++ struct mac_chan_op chan; ++}; ++ ++/// Structure containing the parameters of the @ref MM_CHAN_CTXT_SCHED_REQ message ++struct mm_chan_ctxt_sched_req { ++ /// VIF index ++ u8_l vif_index; ++ /// Channel context index ++ u8_l chan_index; ++ /// Type of the scheduling request (0: normal scheduling, 1: derogatory ++ /// scheduling) ++ u8_l type; ++}; ++ ++/// Structure containing the parameters of the @ref MM_CHANNEL_SWITCH_IND message ++struct mm_channel_switch_ind { ++ /// Index of the channel context we will switch to ++ u8_l chan_index; ++ /// Indicate if the switch has been triggered by a Remain on channel request ++ bool_l roc; ++ /// VIF on which remain on channel operation has been started (if roc == 1) ++ u8_l vif_index; ++ /// Indicate if the switch has been triggered by a TDLS Remain on channel request ++ bool_l roc_tdls; ++}; ++ ++/// Structure containing the parameters of the @ref MM_CHANNEL_PRE_SWITCH_IND message ++struct mm_channel_pre_switch_ind { ++ /// Index of the channel context we will switch to ++ u8_l chan_index; ++}; ++ ++/// Structure containing the parameters of the @ref MM_CONNECTION_LOSS_IND message. ++struct mm_connection_loss_ind { ++ /// VIF instance number ++ u8_l inst_nbr; ++}; ++ ++/// Structure containing the parameters of the @ref MM_DBG_TRIGGER_REQ message. ++struct mm_dbg_trigger_req { ++ /// Error trace to be reported by the LMAC ++ char error[64]; ++}; ++ ++/// Structure containing the parameters of the @ref MM_SET_PS_MODE_REQ message. ++struct mm_set_ps_mode_req { ++ /// Power Save is activated or deactivated ++ u8_l new_state; ++}; ++ ++/// Structure containing the parameters of the @ref MM_BCN_CHANGE_REQ message. ++#define BCN_MAX_CSA_CPT 2 ++struct mm_bcn_change_req { ++ /// Pointer, in host memory, to the new beacon template ++ u32_l bcn_ptr; ++ /// Length of the beacon template ++ u16_l bcn_len; ++ /// Offset of the TIM IE in the beacon ++ u16_l tim_oft; ++ /// Length of the TIM IE ++ u8_l tim_len; ++ /// Index of the VIF for which the beacon is updated ++ u8_l inst_nbr; ++ /// Offset of CSA (channel switch announcement) counters (0 means no counter) ++ u8_l csa_oft[BCN_MAX_CSA_CPT]; ++}; ++ ++/// Structure containing the parameters of the @ref MM_TIM_UPDATE_REQ message. ++struct mm_tim_update_req { ++ /// Association ID of the STA the bit of which has to be updated (0 for BC/MC traffic) ++ u16_l aid; ++ /// Flag indicating the availability of data packets for the given STA ++ u8_l tx_avail; ++ /// Index of the VIF for which the TIM is updated ++ u8_l inst_nbr; ++}; ++ ++/// Structure containing the parameters of the @ref MM_REMAIN_ON_CHANNEL_REQ message. ++struct mm_remain_on_channel_req { ++ /// Operation Code ++ u8_l op_code; ++ /// VIF Index ++ u8_l vif_index; ++ /// Band (2.4GHz or 5GHz) ++ u8_l band; ++ /// Channel type: 20,40,80,160 or 80+80 MHz ++ u8_l type; ++ /// Frequency for Primary 20MHz channel (in MHz) ++ u16_l prim20_freq; ++ /// Frequency for Center of the contiguous channel or center of Primary 80+80 ++ u16_l center1_freq; ++ /// Frequency for Center of the non-contiguous secondary 80+80 ++ u16_l center2_freq; ++ /// Duration (in ms) ++ u32_l duration_ms; ++ /// TX power (in dBm) ++ s8_l tx_power; ++}; ++ ++/// Structure containing the parameters of the @ref MM_REMAIN_ON_CHANNEL_CFM message ++struct mm_remain_on_channel_cfm { ++ /// Operation Code ++ u8_l op_code; ++ /// Status of the operation ++ u8_l status; ++ /// Channel Context index ++ u8_l chan_ctxt_index; ++}; ++ ++/// Structure containing the parameters of the @ref MM_REMAIN_ON_CHANNEL_EXP_IND message ++struct mm_remain_on_channel_exp_ind { ++ /// VIF Index ++ u8_l vif_index; ++ /// Channel Context index ++ u8_l chan_ctxt_index; ++}; ++ ++/// Structure containing the parameters of the @ref MM_SET_UAPSD_TMR_REQ message. ++struct mm_set_uapsd_tmr_req { ++ /// action: Start or Stop the timer ++ u8_l action; ++ /// timeout value, in milliseconds ++ u32_l timeout; ++}; ++ ++/// Structure containing the parameters of the @ref MM_SET_UAPSD_TMR_CFM message. ++struct mm_set_uapsd_tmr_cfm { ++ /// Status of the operation (different from 0 if unsuccessful) ++ u8_l status; ++}; ++ ++/// Structure containing the parameters of the @ref MM_PS_CHANGE_IND message ++struct mm_ps_change_ind { ++ /// Index of the peer device that is switching its PS state ++ u8_l sta_idx; ++ /// New PS state of the peer device (0: active, 1: sleeping) ++ u8_l ps_state; ++}; ++ ++/// Structure containing the parameters of the @ref MM_P2P_VIF_PS_CHANGE_IND message ++struct mm_p2p_vif_ps_change_ind { ++ /// Index of the P2P VIF that is switching its PS state ++ u8_l vif_index; ++ /// New PS state of the P2P VIF interface (0: active, 1: sleeping) ++ u8_l ps_state; ++}; ++ ++/// Structure containing the parameters of the @ref MM_TRAFFIC_REQ_IND message ++struct mm_traffic_req_ind { ++ /// Index of the peer device that needs traffic ++ u8_l sta_idx; ++ /// Number of packets that need to be sent (if 0, all buffered traffic shall be sent and ++ /// if set to @ref PS_SP_INTERRUPTED, it means that current service period has been interrupted) ++ u8_l pkt_cnt; ++ /// Flag indicating if the traffic request concerns U-APSD queues or not ++ bool_l uapsd; ++}; ++ ++/// Structure containing the parameters of the @ref MM_SET_PS_OPTIONS_REQ message. ++struct mm_set_ps_options_req { ++ /// VIF Index ++ u8_l vif_index; ++ /// Listen interval (0 if wake up shall be based on DTIM period) ++ u16_l listen_interval; ++ /// Flag indicating if we shall listen the BC/MC traffic or not ++ bool_l dont_listen_bc_mc; ++}; ++ ++/// Structure containing the parameters of the @ref MM_CSA_COUNTER_IND message ++struct mm_csa_counter_ind { ++ /// Index of the VIF ++ u8_l vif_index; ++ /// Updated CSA counter value ++ u8_l csa_count; ++}; ++ ++/// Structure containing the parameters of the @ref MM_CHANNEL_SURVEY_IND message ++struct mm_channel_survey_ind { ++ /// Frequency of the channel ++ u16_l freq; ++ /// Noise in dbm ++ s8_l noise_dbm; ++ /// Amount of time spent of the channel (in ms) ++ u32_l chan_time_ms; ++ /// Amount of time the primary channel was sensed busy ++ u32_l chan_time_busy_ms; ++}; ++ ++/// Structure containing the parameters of the @ref MM_BFMER_ENABLE_REQ message. ++struct mm_bfmer_enable_req { ++ /** ++ * Address of the beamforming report space allocated in host memory ++ * (Valid only if vht_su_bfmee is true) ++ */ ++ u32_l host_bfr_addr; ++ /** ++ * Size of the beamforming report space allocated in host memory. This space should ++ * be twice the maximum size of the expected beamforming reports as the FW will ++ * divide it in two in order to be able to upload a new report while another one is ++ * used in transmission ++ */ ++ u16_l host_bfr_size; ++ /// AID ++ u16_l aid; ++ /// Station Index ++ u8_l sta_idx; ++ /// Maximum number of spatial streams the station can receive ++ u8_l rx_nss; ++ /** ++ * Indicate if peer STA is MU Beamformee (VHT) capable ++ * (Valid only if vht_su_bfmee is true) ++ */ ++ bool_l vht_mu_bfmee; ++}; ++ ++/// Structure containing the parameters of the @ref MM_SET_P2P_NOA_REQ message. ++struct mm_set_p2p_noa_req { ++ /// VIF Index ++ u8_l vif_index; ++ /// Allocated NOA Instance Number - Valid only if count = 0 ++ u8_l noa_inst_nb; ++ /// Count ++ u8_l count; ++ /// Indicate if NoA can be paused for traffic reason ++ bool_l dyn_noa; ++ /// Duration (in us) ++ u32_l duration_us; ++ /// Interval (in us) ++ u32_l interval_us; ++ /// Start Time offset from next TBTT (in us) ++ u32_l start_offset; ++}; ++ ++#ifdef AICWF_ARP_OFFLOAD ++struct mm_set_arpoffload_en_req { ++ u32_l ipaddr; ++ u8_l enable; ++ u8_l vif_idx; ++}; ++ ++struct mm_set_arpoffload_en_cfm { ++ u8_l status; ++}; ++#endif ++ ++struct mm_set_agg_disable_req { ++ u8_l disable; ++ u8_l staidx; ++ u8_l disable_rx; ++}; ++ ++struct mm_set_coex_req { ++ u8_l bt_on; ++ u8_l disable_coexnull; ++ u8_l enable_nullcts; ++ u8_l enable_periodic_timer; ++ u8_l coex_timeslot_set; ++ u32_l coex_timeslot[2]; ++}; ++#if 0 ++struct mm_set_rf_config_req { ++ u8_l def_band; ++ u8_l config_type; ++ u16_l offset; ++ u16_l len; ++ u16_l set; ++ u32_l rx_gain_24g[48][4]; ++ u32_l rx_gain_5g[32][4]; ++ u32_l tx_gain[32]; ++}; ++#endif ++struct mm_set_rf_config_req { ++ u8_l table_sel; ++ u8_l table_ofst; ++ u8_l table_num; ++ u8_l deft_page; ++ u32_l data[64]; ++}; ++ ++struct mm_set_rf_calib_req { ++ u32_l cal_cfg_24g; ++ u32_l cal_cfg_5g; ++ 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 { ++ u32_l rxgain_24g_addr; ++ u32_l rxgain_5g_addr; ++ u32_l txgain_24g_addr; ++ u32_l txgain_5g_addr; ++}; ++ ++struct mm_get_mac_addr_req { ++ u32_l get; ++}; ++ ++struct mm_get_mac_addr_cfm { ++ u8_l mac_addr[6]; ++}; ++ ++struct mm_get_sta_info_req { ++ u8_l sta_idx; ++}; ++ ++struct mm_get_sta_info_cfm { ++ u32_l rate_info; ++ u32_l txfailed; ++ u8 rssi; ++ u8 reserved[3]; ++ u32_l chan_busy_time; ++ u32_l ack_fail_stat; ++ u32_l ack_succ_stat; ++ u32_l chan_tx_busy_time; ++}; ++ ++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_lvl_conf_t; ++ ++typedef struct { ++ u8_l enable; ++ s8_l pwrlvl_11b_11ag_2g4[12]; ++ s8_l pwrlvl_11n_11ac_2g4[10]; ++ s8_l pwrlvl_11ax_2g4[12]; ++} txpwr_lvl_conf_v2_t; ++ ++typedef struct { ++ u8_l enable; ++ s8_l pwrlvl_11b_11ag_2g4[12]; ++ s8_l pwrlvl_11n_11ac_2g4[10]; ++ s8_l pwrlvl_11ax_2g4[12]; ++ s8_l pwrlvl_11a_5g[12]; ++ s8_l pwrlvl_11n_11ac_5g[10]; ++ s8_l pwrlvl_11ax_5g[12]; ++} txpwr_lvl_conf_v3_t; ++ ++typedef struct { ++ u8_l enable; ++ s8_l pwrlvl_11b_11ag_2g4[12]; ++ s8_l pwrlvl_11n_11ac_2g4[10]; ++ s8_l pwrlvl_11ax_2g4[12]; ++ s8_l pwrlvl_11a_5g[8]; ++ s8_l pwrlvl_11n_11ac_5g[10]; ++ s8_l pwrlvl_11ax_5g[12]; ++ s8_l pwrlvl_11a_6g[8]; ++ s8_l pwrlvl_11n_11ac_6g[10]; ++ s8_l pwrlvl_11ax_6g[12]; ++} txpwr_lvl_conf_v4_t; ++ ++typedef struct { ++ u8_l enable; ++ s8_l pwrlvl_adj_tbl_2g4[3]; ++ s8_l pwrlvl_adj_tbl_5g[6]; ++} txpwr_lvl_adj_conf_t; ++ ++typedef struct { ++ u8_l loss_enable_2g4; ++ s8_l loss_value_2g4; ++ u8_l loss_enable_5g; ++ s8_l loss_value_5g; ++} txpwr_loss_conf_t; ++ ++struct mm_set_txpwr_lvl_req { ++ union { ++ txpwr_lvl_conf_t txpwr_lvl; ++ txpwr_lvl_conf_v2_t txpwr_lvl_v2; ++ txpwr_lvl_conf_v3_t txpwr_lvl_v3; ++ txpwr_lvl_conf_v4_t txpwr_lvl_v4; ++ }; ++}; ++ ++struct mm_set_txpwr_lvl_adj_req { ++ txpwr_lvl_adj_conf_t txpwr_lvl_adj; ++}; ++ ++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; ++ ++/* ++ * pwrofst2x_tbl_2g4[3][3]: ++ * +---------------+----------+----------+----------+ ++ * | RateTyp\ChGrp | CH_1_4 | CH_5_9 | CH_10_13 | ++ * +---------------+----------+----------+----------+ ++ * | DSSS | [0][0] | [0][1] | [0][2] | ++ * +---------------+----------+----------+----------+ ++ * | OFDM_HIGHRATE | [1][0] | [1][1] | [1][2] | ++ * +---------------+----------+----------+----------+ ++ * | OFDM_LOWRATE | [2][0] | [2][1] | [2][2] | ++ * +---------------+----------+----------+----------+ ++ * pwrofst2x_tbl_5g[3][6]: ++ * +---------------+--------------+--------------+----------------+----------------+----------------+----------------+ ++ * | RateTyp\ChGrp | CH_42(36~50) | CH_58(51~64) | CH_106(98~114) | CH_122(115~130)| CH_138(131~146)| CH_155(147~166)| ++ * +---------------+--------------+--------------+----------------+----------------+----------------+----------------+ ++ * | OFDM_LOWRATE | [0][0] | [0][1] | [0][2] | [0][3] | [0][4] | [0][5] | ++ * +---------------+--------------+--------------+----------------+----------------+----------------+----------------+ ++ * | OFDM_HIGHRATE | [1][0] | [1][1] | [1][2] | [1][3] | [1][4] | [1][5] | ++ * +---------------+--------------+--------------+----------------+----------------+----------------+----------------+ ++ * | OFDM_MIDRATE | [2][0] | [2][1] | [2][2] | [2][3] | [2][4] | [2][5] | ++ * +---------------+--------------+--------------+----------------+----------------+----------------+----------------+ ++ */ ++ ++typedef struct { ++ int8_t enable; ++ int8_t pwrofst2x_tbl_2g4[3][3]; ++ int8_t pwrofst2x_tbl_5g[3][6]; ++} txpwr_ofst2x_conf_t; ++ ++/* ++ * pwrofst2x_v2_tbl_2g4_ant0/1[3][3]: ++ * +---------------+----------+---------------+--------------+ ++ * | ChGrp\RateTyp | DSSS | OFDM_HIGHRATE | OFDM_LOWRATE | ++ * +---------------+----------+---------------+--------------+ ++ * | CH_1_4 | [0][0] | [0][1] | Reserved | ++ * +---------------+----------+---------------+--------------+ ++ * | CH_5_9 | [1][0] | [1][1] | Reserved | ++ * +---------------+----------+---------------+--------------+ ++ * | CH_10_13 | [2][0] | [2][1] | Reserved | ++ * +---------------+----------+---------------+--------------+ ++ * pwrofst2x_v2_tbl_5g_ant0/1[6][3]: ++ * +-----------------+---------------+--------------+--------------+ ++ * | ChGrp\RateTyp | OFDM_HIGHRATE | OFDM_LOWRATE | OFDM_MIDRATE | ++ * +-----------------+---------------+--------------+--------------+ ++ * | CH_42(36~50) | [0][0] | Reserved | Reserved | ++ * +-----------------+---------------+--------------+--------------+ ++ * | CH_58(51~64) | [1][0] | Reserved | Reserved | ++ * +-----------------+---------------+--------------+--------------+ ++ * | CH_106(98~114) | [2][0] | Reserved | Reserved | ++ * +-----------------+---------------+--------------+--------------+ ++ * | CH_122(115~130) | [3][0] | Reserved | Reserved | ++ * +-----------------+---------------+--------------+--------------+ ++ * | CH_138(131~146) | [4][0] | Reserved | Reserved | ++ * +-----------------+---------------+--------------+--------------+ ++ * | CH_155(147~166) | [5][0] | Reserved | Reserved | ++ * +-----------------+---------------+--------------+--------------+ ++ */ ++ ++typedef struct { ++ u8_l enable; ++ u8_l pwrofst_flags; ++ s8_l pwrofst2x_tbl_2g4_ant0[3][3]; ++ s8_l pwrofst2x_tbl_2g4_ant1[3][3]; ++ s8_l pwrofst2x_tbl_5g_ant0[6][3]; ++ s8_l pwrofst2x_tbl_5g_ant1[6][3]; ++ s8_l pwrofst2x_tbl_6g_ant0[15]; ++ s8_l pwrofst2x_tbl_6g_ant1[15]; ++} txpwr_ofst2x_conf_v2_t; ++ ++typedef struct { ++ u8_l enable; ++ u8_l xtal_cap; ++ u8_l xtal_cap_fine; ++} xtal_cap_conf_t; ++ ++struct mm_set_txpwr_ofst_req { ++ union { ++ txpwr_ofst_conf_t txpwr_ofst; ++ txpwr_ofst2x_conf_t txpwr_ofst2x; ++ txpwr_ofst2x_conf_v2_t txpwr_ofst2x_v2; ++ }; ++}; ++ ++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. ++struct mm_set_p2p_oppps_req { ++ /// VIF Index ++ u8_l vif_index; ++ /// CTWindow ++ u8_l ctwindow; ++}; ++ ++/// Structure containing the parameters of the @ref MM_SET_P2P_NOA_CFM message. ++struct mm_set_p2p_noa_cfm { ++ /// Request status ++ u8_l status; ++}; ++ ++/// Structure containing the parameters of the @ref MM_SET_P2P_OPPPS_CFM message. ++struct mm_set_p2p_oppps_cfm { ++ /// Request status ++ u8_l status; ++}; ++ ++/// Structure containing the parameters of the @ref MM_P2P_NOA_UPD_IND message. ++struct mm_p2p_noa_upd_ind { ++ /// VIF Index ++ u8_l vif_index; ++ /// NOA Instance Number ++ u8_l noa_inst_nb; ++ /// NoA Type ++ u8_l noa_type; ++ /// Count ++ u8_l count; ++ /// Duration (in us) ++ u32_l duration_us; ++ /// Interval (in us) ++ u32_l interval_us; ++ /// Start Time ++ u32_l start_time; ++}; ++ ++/// Structure containing the parameters of the @ref MM_CFG_RSSI_REQ message ++struct mm_cfg_rssi_req { ++ /// Index of the VIF ++ u8_l vif_index; ++ /// RSSI threshold ++ s8_l rssi_thold; ++ /// RSSI hysteresis ++ u8_l rssi_hyst; ++}; ++ ++/// Structure containing the parameters of the @ref MM_RSSI_STATUS_IND message ++struct mm_rssi_status_ind { ++ /// Index of the VIF ++ u8_l vif_index; ++ /// Status of the RSSI ++ bool_l rssi_status; ++ /// Current RSSI ++ s8_l rssi; ++}; ++ ++/// Structure containing the parameters of the @ref MM_PKTLOSS_IND message ++struct mm_pktloss_ind { ++ /// Index of the VIF ++ u8_l vif_index; ++ /// Address of the STA for which there is a packet loss ++ struct mac_addr mac_addr; ++ /// Number of packets lost ++ u32 num_packets; ++}; ++ ++/// Structure containing the parameters of the @ref MM_CSA_FINISH_IND message ++struct mm_csa_finish_ind { ++ /// Index of the VIF ++ u8_l vif_index; ++ /// Status of the operation ++ u8_l status; ++ /// New channel ctx index ++ u8_l chan_idx; ++}; ++ ++/// Structure containing the parameters of the @ref MM_CSA_TRAFFIC_IND message ++struct mm_csa_traffic_ind { ++ /// Index of the VIF ++ u8_l vif_index; ++ /// Is tx traffic enable or disable ++ bool_l enable; ++}; ++ ++/// Structure containing the parameters of the @ref MM_MU_GROUP_UPDATE_REQ message. ++/// Size allocated for the structure depends of the number of group ++struct mm_mu_group_update_req { ++ /// Station index ++ u8_l sta_idx; ++ /// Number of groups the STA belongs to ++ u8_l group_cnt; ++ /// Group information ++ struct { ++ /// Group Id ++ u8_l group_id; ++ /// User position ++ u8_l user_pos; ++ } groups[0]; ++}; ++ ++/////////////////////////////////////////////////////////////////////////////// ++/////////// For Scan messages ++/////////////////////////////////////////////////////////////////////////////// ++enum scan_msg_tag { ++ /// Scanning start Request. ++ SCAN_START_REQ = LMAC_FIRST_MSG(TASK_SCAN), ++ /// Scanning start Confirmation. ++ SCAN_START_CFM, ++ /// End of scanning indication. ++ SCAN_DONE_IND, ++ /// Cancel scan request ++ SCAN_CANCEL_REQ, ++ /// Cancel scan confirmation ++ SCAN_CANCEL_CFM, ++ ++ /// MAX number of messages ++ SCAN_MAX, ++}; ++ ++/// Maximum number of SSIDs in a scan request ++#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) ++ ++/// Maximum length of the ProbeReq IEs (SoftMAC mode) ++#define SCAN_MAX_IE_LEN 300 ++ ++/// Maximum number of PHY bands supported ++#define SCAN_BAND_MAX 2 ++ ++/// Structure containing the parameters of the @ref SCAN_START_REQ message ++struct scan_start_req { ++ /// List of channel to be scanned ++ struct mac_chan_def chan[SCAN_CHANNEL_MAX]; ++ /// List of SSIDs to be scanned ++ struct mac_ssid ssid[SCAN_SSID_MAX]; ++ /// BSSID to be scanned ++ struct mac_addr bssid; ++ /// Pointer (in host memory) to the additional IEs that need to be added to the ProbeReq ++ /// (following the SSID element) ++ u32_l add_ies; ++ /// Length of the additional IEs ++ u16_l add_ie_len; ++ /// Index of the VIF that is scanning ++ u8_l vif_idx; ++ /// Number of channels to scan ++ u8_l chan_cnt; ++ /// Number of SSIDs to scan for ++ u8_l ssid_cnt; ++ /// no CCK - For P2P frames not being sent at CCK rate in 2GHz band. ++ bool no_cck; ++ /// Scan duration, in us ++ u32_l duration; ++}; ++ ++/// Structure containing the parameters of the @ref SCAN_START_CFM message ++struct scan_start_cfm { ++ /// Status of the request ++ u8_l status; ++}; ++ ++/// Structure containing the parameters of the @ref SCAN_CANCEL_REQ message ++struct scan_cancel_req {}; ++ ++/// Structure containing the parameters of the @ref SCAN_START_CFM message ++struct scan_cancel_cfm { ++ /// Status of the request ++ u8_l status; ++}; ++ ++/////////////////////////////////////////////////////////////////////////////// ++/////////// For Scanu messages ++/////////////////////////////////////////////////////////////////////////////// ++/// Messages that are logically related to the task. ++enum { ++ /// Scan request from host. ++ SCANU_START_REQ = LMAC_FIRST_MSG(TASK_SCANU), ++ /// Scanning start Confirmation. ++ SCANU_START_CFM, ++ /// Join request ++ SCANU_JOIN_REQ, ++ /// Join confirmation. ++ SCANU_JOIN_CFM, ++ /// Scan result indication. ++ SCANU_RESULT_IND, ++ /// Fast scan request from any other module. ++ SCANU_FAST_REQ, ++ /// Confirmation of fast scan request. ++ SCANU_FAST_CFM, ++ ++ SCANU_VENDOR_IE_REQ, ++ SCANU_VENDOR_IE_CFM, ++ SCANU_START_CFM_ADDTIONAL, ++ SCANU_CANCEL_REQ, ++ SCANU_CANCEL_CFM, ++ ++ /// MAX number of messages ++ SCANU_MAX, ++}; ++ ++/// Maximum length of the additional ProbeReq IEs (FullMAC mode) ++#define SCANU_MAX_IE_LEN 200 ++ ++/// Structure containing the parameters of the @ref SCANU_START_REQ message ++struct scanu_start_req { ++ /// List of channel to be scanned ++ struct mac_chan_def chan[SCAN_CHANNEL_MAX]; ++ /// List of SSIDs to be scanned ++ struct mac_ssid ssid[SCAN_SSID_MAX]; ++ /// BSSID to be scanned (or WILDCARD BSSID if no BSSID is searched in particular) ++ struct mac_addr bssid; ++ /// Address (in host memory) of the additional IEs that need to be added to the ProbeReq ++ /// (following the SSID element) ++ u32_l add_ies; ++ /// Length of the additional IEs ++ u16_l add_ie_len; ++ /// Index of the VIF that is scanning ++ u8_l vif_idx; ++ /// Number of channels to scan ++ u8_l chan_cnt; ++ /// Number of SSIDs to scan for ++ u8_l ssid_cnt; ++ /// no CCK - For P2P frames not being sent at CCK rate in 2GHz band. ++ bool no_cck; ++ /// Scan duration, in us ++ u32_l duration; ++}; ++ ++struct scanu_vendor_ie_req { ++ u16_l add_ie_len; ++ u8_l vif_idx; ++ u8_l ie[256]; ++}; ++ ++/// Structure containing the parameters of the @ref SCANU_START_CFM message ++struct scanu_start_cfm { ++ /// Index of the VIF that was scanning ++ u8_l vif_idx; ++ /// Status of the request ++ u8_l status; ++ /// Number of scan results available ++ u8_l result_cnt; ++}; ++ ++/// Parameters of the @SCANU_RESULT_IND message ++struct scanu_result_ind { ++ /// Length of the frame ++ u16_l length; ++ /// Frame control field of the frame. ++ u16_l framectrl; ++ /// Center frequency on which we received the packet ++ u16_l center_freq; ++ /// PHY band ++ u8_l band; ++ /// Index of the station that sent the frame. 0xFF if unknown. ++ u8_l sta_idx; ++ /// Index of the VIF that received the frame. 0xFF if unknown. ++ u8_l inst_nbr; ++ /// RSSI of the received frame. ++ s8_l rssi; ++ /// Frame payload. ++ u32_l payload[]; ++}; ++ ++/// Structure containing the parameters of the message. ++struct scanu_fast_req { ++ /// The SSID to scan in the channel. ++ struct mac_ssid ssid; ++ /// BSSID. ++ struct mac_addr bssid; ++ /// Probe delay. ++ u16_l probe_delay; ++ /// Minimum channel time. ++ u16_l minch_time; ++ /// Maximum channel time. ++ u16_l maxch_time; ++ /// The channel number to scan. ++ u16_l ch_nbr; ++}; ++ ++/////////////////////////////////////////////////////////////////////////////// ++/////////// For ME messages ++/////////////////////////////////////////////////////////////////////////////// ++/// Messages that are logically related to the task. ++enum { ++ /// Configuration request from host. ++ ME_CONFIG_REQ = LMAC_FIRST_MSG(TASK_ME), ++ /// Configuration confirmation. ++ ME_CONFIG_CFM, ++ /// Configuration request from host. ++ ME_CHAN_CONFIG_REQ, ++ /// Configuration confirmation. ++ ME_CHAN_CONFIG_CFM, ++ /// Set control port state for a station. ++ ME_SET_CONTROL_PORT_REQ, ++ /// Control port setting confirmation. ++ ME_SET_CONTROL_PORT_CFM, ++ /// TKIP MIC failure indication. ++ ME_TKIP_MIC_FAILURE_IND, ++ /// Add a station to the FW (AP mode) ++ ME_STA_ADD_REQ, ++ /// Confirmation of the STA addition ++ ME_STA_ADD_CFM, ++ /// Delete a station from the FW (AP mode) ++ ME_STA_DEL_REQ, ++ /// Confirmation of the STA deletion ++ ME_STA_DEL_CFM, ++ /// Indication of a TX RA/TID queue credit update ++ ME_TX_CREDITS_UPDATE_IND, ++ /// Request indicating to the FW that there is traffic buffered on host ++ ME_TRAFFIC_IND_REQ, ++ /// Confirmation that the @ref ME_TRAFFIC_IND_REQ has been executed ++ ME_TRAFFIC_IND_CFM, ++ /// Request of RC statistics to a station ++ ME_RC_STATS_REQ, ++ /// RC statistics confirmation ++ ME_RC_STATS_CFM, ++ /// RC fixed rate request ++ ME_RC_SET_RATE_REQ, ++ /// Configure monitor interface ++ ME_CONFIG_MONITOR_REQ, ++ /// Configure monitor interface response ++ ME_CONFIG_MONITOR_CFM, ++ /// Setting power Save mode request from host ++ ME_SET_PS_MODE_REQ, ++ /// Set power Save mode confirmation ++ ME_SET_PS_MODE_CFM, ++ /// Setting Low Power level request from host ++ ME_SET_LP_LEVEL_REQ, ++ /// Set Low Power level confirmation ++ ME_SET_LP_LEVEL_CFM, ++ /// MAX number of messages ++ ME_MAX, ++}; ++ ++/// Structure containing the parameters of the @ref ME_START_REQ message ++struct me_config_req { ++ /// HT Capabilities ++ struct mac_htcapability ht_cap; ++ /// VHT Capabilities ++ struct mac_vhtcapability vht_cap; ++ /// HE capabilities ++ struct mac_hecapability he_cap; ++ /// Lifetime of packets sent under a BlockAck agreement (expressed in TUs) ++ u16_l tx_lft; ++ /// Maximum supported BW ++ u8_l phy_bw_max; ++ /// Boolean indicating if HT is supported or not ++ bool_l ht_supp; ++ /// Boolean indicating if VHT is supported or not ++ bool_l vht_supp; ++ /// Boolean indicating if HE is supported or not ++ bool_l he_supp; ++ /// Boolean indicating if HE OFDMA UL is enabled or not ++ bool_l he_ul_on; ++ /// Boolean indicating if PS mode shall be enabled or not ++ bool_l ps_on; ++ /// Boolean indicating if Antenna Diversity shall be enabled or not ++ bool_l ant_div_on; ++ /// Boolean indicating if Dynamic PS mode shall be used or not ++ bool_l dpsm; ++}; ++ ++/// Structure containing the parameters of the @ref ME_CHAN_CONFIG_REQ message ++struct me_chan_config_req { ++ /// List of 2.4GHz supported channels ++ struct mac_chan_def chan2G4[MAC_DOMAINCHANNEL_24G_MAX]; ++ /// List of 5GHz supported channels ++ struct mac_chan_def chan5G[MAC_DOMAINCHANNEL_5G_MAX]; ++ /// Number of 2.4GHz channels in the list ++ u8_l chan2G4_cnt; ++ /// Number of 5GHz channels in the list ++ u8_l chan5G_cnt; ++}; ++ ++/// Structure containing the parameters of the @ref ME_SET_CONTROL_PORT_REQ message ++struct me_set_control_port_req { ++ /// Index of the station for which the control port is opened ++ u8_l sta_idx; ++ /// Control port state ++ bool_l control_port_open; ++}; ++ ++/// Structure containing the parameters of the @ref ME_TKIP_MIC_FAILURE_IND message ++struct me_tkip_mic_failure_ind { ++ /// Address of the sending STA ++ struct mac_addr addr; ++ /// TSC value ++ u64_l tsc; ++ /// Boolean indicating if the packet was a group or unicast one (true if group) ++ bool_l ga; ++ /// Key Id ++ u8_l keyid; ++ /// VIF index ++ u8_l vif_idx; ++}; ++ ++/// Structure containing the parameters of the @ref ME_STA_ADD_REQ message ++struct me_sta_add_req { ++ /// MAC address of the station to be added ++ struct mac_addr mac_addr; ++ /// Supported legacy rates ++ struct mac_rateset rate_set; ++ /// HT Capabilities ++ struct mac_htcapability ht_cap; ++ /// VHT Capabilities ++ struct mac_vhtcapability vht_cap; ++ /// HE capabilities ++ struct mac_hecapability he_cap; ++ /// Flags giving additional information about the station (@ref mac_sta_flags) ++ u32_l flags; ++ /// Association ID of the station ++ u16_l aid; ++ /// Bit field indicating which queues have U-APSD enabled ++ u8_l uapsd_queues; ++ /// Maximum size, in frames, of a APSD service period ++ u8_l max_sp_len; ++ /// Operation mode information (valid if bit @ref STA_OPMOD_NOTIF is ++ /// set in the flags) ++ u8_l opmode; ++ /// Index of the VIF the station is attached to ++ u8_l vif_idx; ++ /// Whether the the station is TDLS station ++ bool_l tdls_sta; ++ /// Indicate if the station is TDLS link initiator station ++ bool_l tdls_sta_initiator; ++ /// Indicate if the TDLS Channel Switch is allowed ++ bool_l tdls_chsw_allowed; ++}; ++ ++/// Structure containing the parameters of the @ref ME_STA_ADD_CFM message ++struct me_sta_add_cfm { ++ /// Station index ++ u8_l sta_idx; ++ /// Status of the station addition ++ u8_l status; ++ /// PM state of the station ++ u8_l pm_state; ++}; ++ ++/// Structure containing the parameters of the @ref ME_STA_DEL_REQ message. ++struct me_sta_del_req { ++ /// Index of the station to be deleted ++ u8_l sta_idx; ++ /// Whether the the station is TDLS station ++ bool_l tdls_sta; ++}; ++ ++/// Structure containing the parameters of the @ref ME_TX_CREDITS_UPDATE_IND message. ++struct me_tx_credits_update_ind { ++ /// Index of the station for which the credits are updated ++ u8_l sta_idx; ++ /// TID for which the credits are updated ++ u8_l tid; ++ /// Offset to be applied on the credit count ++ s8_l credits; ++}; ++ ++/// Structure containing the parameters of the @ref ME_TRAFFIC_IND_REQ message. ++struct me_traffic_ind_req { ++ /// Index of the station for which UAPSD traffic is available on host ++ u8_l sta_idx; ++ /// Flag indicating the availability of UAPSD packets for the given STA ++ u8_l tx_avail; ++ /// Indicate if traffic is on uapsd-enabled queues ++ bool_l uapsd; ++}; ++ ++struct mm_apm_staloss_ind { ++ u8_l sta_idx; ++ u8_l vif_idx; ++ u8_l mac_addr[6]; ++}; ++ ++#ifdef CONFIG_SDIO_BT ++struct mm_bt_recv_ind { ++ u32_l data_len; ++ u8_l bt_data[1024]; ++}; ++#endif ++ ++enum vendor_hwconfig_tag { ++ ACS_TXOP_REQ = 0, ++ CHANNEL_ACCESS_REQ, ++ MAC_TIMESCALE_REQ, ++ CCA_THRESHOLD_REQ, ++ BWMODE_REQ, ++ CHIP_TEMP_GET_REQ, ++ AP_PS_LEVEL_SET_REQ, ++ CUSTOMIZED_FREQ_REQ, ++ WAKEUP_INFO_REQ, ++ KEEPALIVE_PKT_REQ, ++}; ++ ++enum { ++ BWMODE20M = 0, ++ BWMODE10M, ++ BWMODE5M, ++}; ++ ++struct mm_set_acs_txop_req { ++ u32_l hwconfig_id; ++ u16_l txop_bk; ++ u16_l txop_be; ++ u16_l txop_vi; ++ u16_l txop_vo; ++}; ++ ++struct mm_set_channel_access_req { ++ u32_l hwconfig_id; ++ u32_l edca[4]; ++ u8_l vif_idx; ++ u8_l retry_cnt; ++ u8_l rts_en; ++ u8_l long_nav_en; ++ u8_l cfe_en; ++ u8_l rc_retry_cnt[3]; ++ s8_l ccademod_th; ++ u8_l remove_1m2m; ++}; ++ ++struct mm_set_mac_timescale_req { ++ u32_l hwconfig_id; ++ u8_l sifsA_time; ++ u8_l sifsB_time; ++ u8_l slot_time; ++ u8_l rx_startdelay_ofdm; ++ u8_l rx_startdelay_long; ++ u8_l rx_startdelay_short; ++}; ++ ++struct mm_set_cca_threshold_req { ++ u32_l hwconfig_id; ++ u8_l auto_cca_en; ++ s8_l cca20p_rise_th; ++ s8_l cca20s_rise_th; ++ s8_l cca20p_fall_th; ++ s8_l cca20s_fall_th; ++}; ++ ++struct mm_set_bwmode_req { ++ u32_l hwconfig_id; ++ u8_l bwmode; ++}; ++ ++struct mm_get_chip_temp_req { ++ u32_l hwconfig_id; ++}; ++ ++struct mm_get_chip_temp_cfm { ++ /// Temp degree val ++ s8_l degree; ++}; ++ ++struct mm_set_ap_ps_level_req { ++ u32_l hwconfig_id; ++ u8 ap_ps_level; ++}; ++ ++struct mm_set_vendor_hwconfig_cfm { ++ u32_l hwconfig_id; ++ union { ++ struct mm_get_chip_temp_cfm chip_temp_cfm; ++ }; ++}; ++ ++struct mm_set_customized_freq_req { ++ u32_l hwconfig_id; ++ u16_l raw_freq[4]; ++ u16_l map_freq[4]; ++}; ++ ++struct mm_set_wakeup_info_req { ++ u32_l hwconfig_id; ++ u16_l offset; ++ u8_l length; ++ u8_l mask_and_patten[]; ++}; ++ ++struct mm_set_keepalive_req { ++ u32_l hwconfig_id; ++ u16_l code; ++ u16_l length; ++ u32_l intv; ++ u8_l payload[]; ++}; ++ ++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; ++}; ++ ++#ifdef CONFIG_APF ++struct mm_set_apf_prog_req { ++ u32_l program_len; ++ u32_l offset; ++ u8_l program[LMAC_MSG_MAX_LEN]; ++}; ++ ++struct mm_get_apf_prog_req { ++ u16_l offset; ++}; ++ ++struct mm_get_apf_prog_cfm { ++ u8_l program[LMAC_MSG_MAX_LEN]; ++}; ++#endif ++ ++struct mm_get_fw_version_cfm { ++ u8_l fw_version_len; ++ u8_l fw_version[63]; ++}; ++ ++struct mm_get_wifi_disable_cfm { ++ u8_l wifi_disable; ++}; ++ ++enum vendor_swconfig_tag { ++ BCN_CFG_REQ = 0, ++ TEMP_COMP_SET_REQ, ++ TEMP_COMP_GET_REQ, ++ EXT_FLAGS_SET_REQ, ++ EXT_FLAGS_GET_REQ, ++ EXT_FLAGS_MASK_SET_REQ, ++}; ++ ++struct mm_set_bcn_cfg_req { ++ /// Ignore or not bcn tim bcmc bit ++ bool_l tim_bcmc_ignored_enable; ++}; ++ ++struct mm_set_bcn_cfg_cfm { ++ /// Request status ++ bool_l tim_bcmc_ignored_status; ++}; ++ ++struct mm_set_temp_comp_req { ++ /// Enable or not temp comp ++ u8_l enable; ++ u8_l reserved[3]; ++ u32_l tmr_period_ms; ++}; ++ ++struct mm_set_temp_comp_cfm { ++ /// Request status ++ u8_l status; ++}; ++ ++struct mm_get_temp_comp_cfm { ++ /// Request status ++ u8_l status; ++ /// Temp degree val ++ s8_l degree; ++}; ++ ++struct mm_set_ext_flags_req { ++ u32_l user_flags; ++}; ++ ++struct mm_set_ext_flags_cfm { ++ u32_l user_flags; ++}; ++ ++struct mm_get_ext_flags_cfm { ++ u32_l user_flags; ++}; ++ ++struct mm_mask_set_ext_flags_req { ++ u32_l user_flags_mask; ++ u32_l user_flags_val; ++}; ++ ++struct mm_mask_set_ext_flags_cfm { ++ u32_l user_flags; ++}; ++ ++struct mm_set_vendor_swconfig_req { ++ u32_l swconfig_id; ++ union { ++ struct mm_set_bcn_cfg_req bcn_cfg_req; ++ struct mm_set_temp_comp_req temp_comp_set_req; ++ struct mm_set_ext_flags_req ext_flags_set_req; ++ struct mm_mask_set_ext_flags_req ext_flags_mask_set_req; ++ }; ++}; ++ ++struct mm_set_vendor_swconfig_cfm { ++ u32_l swconfig_id; ++ union { ++ struct mm_set_bcn_cfg_cfm bcn_cfg_cfm; ++ struct mm_set_temp_comp_cfm temp_comp_set_cfm; ++ struct mm_get_temp_comp_cfm temp_comp_get_cfm; ++ struct mm_set_ext_flags_cfm ext_flags_set_cfm; ++ struct mm_get_ext_flags_cfm ext_flags_get_cfm; ++ struct mm_mask_set_ext_flags_cfm ext_flags_mask_set_cfm; ++ }; ++}; ++ ++#ifdef CONFIG_SDIO_BT ++struct mm_bt_send_req { ++ u32_l data_len; ++ u8_l bt_data[1024]; ++}; ++ ++struct mm_bt_send_cfm { ++ u8_l status; ++}; ++#endif ++ ++/// 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 ++ u8_l sta_idx; ++}; ++ ++/// Structure containing the rate control statistics ++struct rc_rate_stats { ++ /// Number of attempts (per sampling interval) ++ u16_l attempts; ++ /// Number of success (per sampling interval) ++ u16_l success; ++ /// Estimated probability of success (EWMA) ++ u16_l probability; ++ /// Rate configuration of the sample ++ u16_l rate_config; ++ union { ++ struct { ++ /// Number of times the sample has been skipped (per sampling interval) ++ u8_l sample_skipped; ++ /// Whether the old probability is available ++ bool_l old_prob_available; ++ /// Whether the rate can be used in the retry chain ++ bool_l rate_allowed; ++ }; ++ struct { ++ /// RU size and UL length received in the latest HE trigger frame ++ u16_l ru_and_length; ++ }; ++ }; ++}; ++ ++/// Number of RC samples ++#define RC_MAX_N_SAMPLE 10 ++/// Index of the HE statistics element in the table ++#define RC_HE_STATS_IDX RC_MAX_N_SAMPLE ++ ++/// Structure containing the parameters of the @ref ME_RC_STATS_CFM message. ++struct me_rc_stats_cfm { ++ /// Index of the station for which the RC statistics are provided ++ u8_l sta_idx; ++ /// Number of samples used in the RC algorithm ++ u16_l no_samples; ++ /// Number of MPDUs transmitted (per sampling interval) ++ u16_l ampdu_len; ++ /// Number of AMPDUs transmitted (per sampling interval) ++ u16_l ampdu_packets; ++ /// Average number of MPDUs in each AMPDU frame (EWMA) ++ u32_l avg_ampdu_len; ++ // Current step 0 of the retry chain ++ u8_l sw_retry_step; ++ /// Trial transmission period ++ u8_l sample_wait; ++ /// Retry chain steps ++ u16_l retry_step_idx[4]; ++ /// RC statistics - Max number of RC samples, plus one for the HE TB statistics ++ struct rc_rate_stats rate_stats[RC_MAX_N_SAMPLE + 1]; ++ /// Throughput - Max number of RC samples, plus one for the HE TB statistics ++ u32_l tp[RC_MAX_N_SAMPLE + 1]; ++}; ++ ++/// Structure containing the parameters of the @ref ME_RC_SET_RATE_REQ message. ++struct me_rc_set_rate_req { ++ /// Index of the station for which the fixed rate is set ++ u8_l sta_idx; ++ /// Rate configuration to be set ++ u16_l fixed_rate_cfg; ++}; ++ ++/// Structure containing the parameters of the @ref ME_CONFIG_MONITOR_REQ message. ++struct me_config_monitor_req { ++ /// Channel to configure ++ struct mac_chan_op chan; ++ /// Is channel data valid ++ bool_l chan_set; ++ /// Enable report of unsupported HT frames ++ bool_l uf; ++ /// Enable auto-reply as the mac_addr matches ++ bool_l auto_reply; ++}; ++ ++/// Structure containing the parameters of the @ref ME_CONFIG_MONITOR_CFM message. ++struct me_config_monitor_cfm { ++ /// Channel context index ++ u8_l chan_index; ++ /// Channel parameters ++ struct mac_chan_op chan; ++}; ++ ++/// Structure containing the parameters of the @ref ME_SET_PS_MODE_REQ message. ++struct me_set_ps_mode_req { ++ /// Power Save is activated or deactivated ++ u8_l ps_state; ++}; ++ ++/// Structure containing the parameters of the @ref ME_SET_LP_LEVEL_REQ message. ++struct me_set_lp_level_req { ++ /// Low Power level ++ u8_l lp_level; ++ u8_l disable_filter; ++}; ++ ++/////////////////////////////////////////////////////////////////////////////// ++/////////// For SM messages ++/////////////////////////////////////////////////////////////////////////////// ++/// Message API of the SM task ++enum sm_msg_tag { ++ /// Request to connect to an AP ++ SM_CONNECT_REQ = LMAC_FIRST_MSG(TASK_SM), ++ /// Confirmation of connection ++ SM_CONNECT_CFM, ++ /// Indicates that the SM associated to the AP ++ SM_CONNECT_IND, ++ /// Request to disconnect ++ SM_DISCONNECT_REQ, ++ /// Confirmation of disconnection ++ SM_DISCONNECT_CFM, ++ /// Indicates that the SM disassociated the AP ++ SM_DISCONNECT_IND, ++ /// Request to start external authentication ++ SM_EXTERNAL_AUTH_REQUIRED_IND, ++ /// Response to external authentication request ++ SM_EXTERNAL_AUTH_REQUIRED_RSP, ++ /// Request to update assoc elements after FT over the air authentication ++ SM_FT_AUTH_IND, ++ /// Response to FT authentication with updated assoc elements ++ SM_FT_AUTH_RSP, ++ ++ SM_RSP_TIMEOUT_IND, ++ ++ SM_COEX_TS_TIMEOUT_IND, ++ ++ SM_EXTERNAL_AUTH_REQUIRED_RSP_CFM, ++ /// MAX number of messages ++ SM_MAX, ++}; ++ ++/// Structure containing the parameters of @ref SM_CONNECT_REQ message. ++struct sm_connect_req { ++ /// SSID to connect to ++ struct mac_ssid ssid; ++ /// BSSID to connect to (if not specified, set this field to WILDCARD BSSID) ++ struct mac_addr bssid; ++ /// Channel on which we have to connect (if not specified, set -1 in the chan.freq field) ++ struct mac_chan_def chan; ++ /// Connection flags (see @ref mac_connection_flags) ++ u32_l flags; ++ /// Control port Ethertype (in network endianness) ++ u16_l ctrl_port_ethertype; ++ /// Length of the association request IEs ++ u16_l ie_len; ++ /// Listen interval to be used for this connection ++ u16_l listen_interval; ++ /// Flag indicating if the we have to wait for the BC/MC traffic after beacon or not ++ bool_l dont_wait_bcmc; ++ /// Authentication type ++ u8_l auth_type; ++ /// UAPSD queues (bit0: VO, bit1: VI, bit2: BE, bit3: BK) ++ u8_l uapsd_queues; ++ /// VIF index ++ u8_l vif_idx; ++ /// Buffer containing the additional information elements to be put in the ++ /// association request ++ u32_l ie_buf[64]; ++}; ++ ++/// Structure containing the parameters of the @ref SM_CONNECT_CFM message. ++struct sm_connect_cfm { ++ /// Status. If 0, it means that the connection procedure will be performed and that ++ /// a subsequent @ref SM_CONNECT_IND message will be forwarded once the procedure is ++ /// completed ++ u8_l status; ++}; ++ ++#define SM_ASSOC_IE_LEN 800 ++/// Structure containing the parameters of the @ref SM_CONNECT_IND message. ++struct sm_connect_ind { ++ /// Status code of the connection procedure ++ u16_l status_code; ++ /// BSSID ++ struct mac_addr bssid; ++ /// Flag indicating if the indication refers to an internal roaming or from a host request ++ bool_l roamed; ++ /// Index of the VIF for which the association process is complete ++ u8_l vif_idx; ++ /// Index of the STA entry allocated for the AP ++ u8_l ap_idx; ++ /// Index of the LMAC channel context the connection is attached to ++ u8_l ch_idx; ++ /// Flag indicating if the AP is supporting QoS ++ bool_l qos; ++ /// ACM bits set in the AP WMM parameter element ++ u8_l acm; ++ /// Length of the AssocReq IEs ++ u16_l assoc_req_ie_len; ++ /// Length of the AssocRsp IEs ++ u16_l assoc_rsp_ie_len; ++ /// IE buffer ++ u32_l assoc_ie_buf[SM_ASSOC_IE_LEN / 4]; ++ ++ u16_l aid; ++ u8_l band; ++ u16_l center_freq; ++ u8_l width; ++ u32_l center_freq1; ++ u32_l center_freq2; ++ ++ /// EDCA parameters ++ u32_l ac_param[AC_MAX]; ++}; ++ ++/// Structure containing the parameters of the @ref SM_DISCONNECT_REQ message. ++struct sm_disconnect_req { ++ /// Reason of the deauthentication. ++ u16_l reason_code; ++ /// Index of the VIF. ++ u8_l vif_idx; ++}; ++ ++/// Structure containing the parameters of SM_ASSOCIATION_IND the message ++struct sm_association_ind { ++ // MAC ADDR of the STA ++ struct mac_addr me_mac_addr; ++}; ++ ++/// Structure containing the parameters of the @ref SM_DISCONNECT_IND message. ++struct sm_disconnect_ind { ++ /// Reason of the disconnection. ++ u16_l reason_code; ++ /// Index of the VIF. ++ u8_l vif_idx; ++ /// FT over DS is ongoing ++ bool_l ft_over_ds; ++ u8_l reassoc; ++}; ++ ++/// Structure containing the parameters of the @ref SM_EXTERNAL_AUTH_REQUIRED_IND ++struct sm_external_auth_required_ind { ++ /// Index of the VIF. ++ u8_l vif_idx; ++ /// SSID to authenticate to ++ struct mac_ssid ssid; ++ /// BSSID to authenticate to ++ struct mac_addr bssid; ++ /// AKM suite of the respective authentication ++ u32_l akm; ++}; ++ ++/// Structure containing the parameters of the @ref SM_EXTERNAL_AUTH_REQUIRED_RSP ++struct sm_external_auth_required_rsp { ++ /// Index of the VIF. ++ u8_l vif_idx; ++ /// Authentication status ++ u16_l status; ++}; ++ ++/////////////////////////////////////////////////////////////////////////////// ++/////////// For APM messages ++/////////////////////////////////////////////////////////////////////////////// ++/// Message API of the APM task ++enum apm_msg_tag { ++ /// Request to start the AP. ++ APM_START_REQ = LMAC_FIRST_MSG(TASK_APM), ++ /// Confirmation of the AP start. ++ APM_START_CFM, ++ /// Request to stop the AP. ++ APM_STOP_REQ, ++ /// Confirmation of the AP stop. ++ APM_STOP_CFM, ++ /// Request to start CAC ++ APM_START_CAC_REQ, ++ /// Confirmation of the CAC start ++ APM_START_CAC_CFM, ++ /// Request to stop CAC ++ APM_STOP_CAC_REQ, ++ /// Confirmation of the CAC stop ++ APM_STOP_CAC_CFM, ++ ++ APM_SET_BEACON_IE_REQ, ++ APM_SET_BEACON_IE_CFM, ++ ++ /// MAX number of messages ++ APM_MAX, ++}; ++ ++/// Structure containing the parameters of the @ref APM_START_REQ message. ++struct apm_start_req { ++ /// Basic rate set ++ struct mac_rateset basic_rates; ++ /// Control channel on which we have to enable the AP ++ struct mac_chan_def chan; ++ /// Center frequency of the first segment ++ u32_l center_freq1; ++ /// Center frequency of the second segment (only in 80+80 configuration) ++ u32_l center_freq2; ++ /// Width of channel ++ u8_l ch_width; ++ /// Address, in host memory, to the beacon template ++ u32_l bcn_addr; ++ /// Length of the beacon template ++ u16_l bcn_len; ++ /// Offset of the TIM IE in the beacon ++ u16_l tim_oft; ++ /// Beacon interval ++ u16_l bcn_int; ++ /// Flags (@ref mac_connection_flags) ++ u32_l flags; ++ /// Control port Ethertype ++ u16_l ctrl_port_ethertype; ++ /// Length of the TIM IE ++ u8_l tim_len; ++ /// Index of the VIF for which the AP is started ++ u8_l vif_idx; ++}; ++ ++struct apm_set_bcn_ie_req { ++ u8_l vif_idx; ++ u16_l bcn_ie_len; ++ u8_l bcn_ie[512]; ++}; ++ ++/// Structure containing the parameters of the @ref APM_START_CFM message. ++struct apm_start_cfm { ++ /// Status of the AP starting procedure ++ u8_l status; ++ /// Index of the VIF for which the AP is started ++ u8_l vif_idx; ++ /// Index of the channel context attached to the VIF ++ u8_l ch_idx; ++ /// Index of the STA used for BC/MC traffic ++ u8_l bcmc_idx; ++}; ++ ++/// Structure containing the parameters of the @ref APM_STOP_REQ message. ++struct apm_stop_req { ++ /// Index of the VIF for which the AP has to be stopped ++ u8_l vif_idx; ++}; ++ ++/// Structure containing the parameters of the @ref APM_START_CAC_REQ message. ++struct apm_start_cac_req { ++ /// Control channel on which we have to start the CAC ++ struct mac_chan_op chan; ++ /// Center frequency of the first segment ++ //u32_l center_freq1; ++ /// Center frequency of the second segment (only in 80+80 configuration) ++ //u32_l center_freq2; ++ /// Width of channel ++ //u8_l ch_width; ++ /// Index of the VIF for which the CAC is started ++ u8_l vif_idx; ++}; ++ ++/// Structure containing the parameters of the @ref APM_START_CAC_CFM message. ++struct apm_start_cac_cfm { ++ /// Status of the CAC starting procedure ++ u8_l status; ++ /// Index of the channel context attached to the VIF for CAC ++ u8_l ch_idx; ++}; ++ ++/// Structure containing the parameters of the @ref APM_STOP_CAC_REQ message. ++struct apm_stop_cac_req { ++ /// Index of the VIF for which the CAC has to be stopped ++ u8_l vif_idx; ++}; ++ ++/////////////////////////////////////////////////////////////////////////////// ++/////////// For MESH messages ++/////////////////////////////////////////////////////////////////////////////// ++ ++/// Maximum length of the Mesh ID ++#define MESH_MESHID_MAX_LEN (32) ++ ++/// Message API of the MESH task ++enum mesh_msg_tag { ++ /// Request to start the MP ++ MESH_START_REQ = LMAC_FIRST_MSG(TASK_MESH), ++ /// Confirmation of the MP start. ++ MESH_START_CFM, ++ ++ /// Request to stop the MP. ++ MESH_STOP_REQ, ++ /// Confirmation of the MP stop. ++ MESH_STOP_CFM, ++ ++ // Request to update the MP ++ MESH_UPDATE_REQ, ++ /// Confirmation of the MP update ++ MESH_UPDATE_CFM, ++ ++ /// Request information about a given link ++ MESH_PEER_INFO_REQ, ++ /// Response to the MESH_PEER_INFO_REQ message ++ MESH_PEER_INFO_CFM, ++ ++ /// Request automatic establishment of a path with a given mesh STA ++ MESH_PATH_CREATE_REQ, ++ /// Confirmation to the MESH_PATH_CREATE_REQ message ++ MESH_PATH_CREATE_CFM, ++ ++ /// Request a path update (delete path, modify next hop mesh STA) ++ MESH_PATH_UPDATE_REQ, ++ /// Confirmation to the MESH_PATH_UPDATE_REQ message ++ MESH_PATH_UPDATE_CFM, ++ ++ /// Indication from Host that the indicated Mesh Interface is a proxy for an external STA ++ MESH_PROXY_ADD_REQ, ++ ++ /// Indicate that a connection has been established or lost ++ MESH_PEER_UPDATE_IND, ++ /// Notification that a connection has been established or lost (when MPM handled by userspace) ++ MESH_PEER_UPDATE_NTF = MESH_PEER_UPDATE_IND, ++ ++ /// Indicate that a path is now active or inactive ++ MESH_PATH_UPDATE_IND, ++ /// Indicate that proxy information have been updated ++ MESH_PROXY_UPDATE_IND, ++ ++ /// MAX number of messages ++ MESH_MAX, ++}; ++ ++/// Structure containing the parameters of the @ref MESH_START_REQ message. ++struct mesh_start_req { ++ /// Basic rate set ++ struct mac_rateset basic_rates; ++ /// Control channel on which we have to enable the AP ++ struct mac_chan_def chan; ++ /// Center frequency of the first segment ++ u32_l center_freq1; ++ /// Center frequency of the second segment (only in 80+80 configuration) ++ u32_l center_freq2; ++ /// Width of channel ++ u8_l ch_width; ++ /// DTIM Period ++ u8_l dtim_period; ++ /// Beacon Interval ++ u16_l bcn_int; ++ /// Index of the VIF for which the MP is started ++ u8_l vif_index; ++ /// Length of the Mesh ID ++ u8_l mesh_id_len; ++ /// Mesh ID ++ u8_l mesh_id[MESH_MESHID_MAX_LEN]; ++ /// Address of the IEs to download ++ u32_l ie_addr; ++ /// Length of the provided IEs ++ u8_l ie_len; ++ /// Indicate if Mesh Peering Management (MPM) protocol is handled in userspace ++ bool_l user_mpm; ++ /// Indicate if Mesh Point is using authentication ++ bool_l is_auth; ++ /// Indicate which authentication method is used ++ u8_l auth_id; ++}; ++ ++/// Structure containing the parameters of the @ref MESH_START_CFM message. ++struct mesh_start_cfm { ++ /// Status of the MP starting procedure ++ u8_l status; ++ /// Index of the VIF for which the MP is started ++ u8_l vif_idx; ++ /// Index of the channel context attached to the VIF ++ u8_l ch_idx; ++ /// Index of the STA used for BC/MC traffic ++ u8_l bcmc_idx; ++}; ++ ++/// Structure containing the parameters of the @ref MESH_STOP_REQ message. ++struct mesh_stop_req { ++ /// Index of the VIF for which the MP has to be stopped ++ u8_l vif_idx; ++}; ++ ++/// Structure containing the parameters of the @ref MESH_STOP_CFM message. ++struct mesh_stop_cfm { ++ /// Index of the VIF for which the MP has to be stopped ++ u8_l vif_idx; ++ /// Status ++ u8_l status; ++}; ++ ++/// Bit fields for mesh_update_req message's flags value ++enum mesh_update_flags_bit { ++ /// Root Mode ++ MESH_UPDATE_FLAGS_ROOT_MODE_BIT = 0, ++ /// Gate Mode ++ MESH_UPDATE_FLAGS_GATE_MODE_BIT, ++ /// Mesh Forwarding ++ MESH_UPDATE_FLAGS_MESH_FWD_BIT, ++ /// Local Power Save Mode ++ MESH_UPDATE_FLAGS_LOCAL_PSM_BIT, ++}; ++ ++/// Structure containing the parameters of the @ref MESH_UPDATE_REQ message. ++struct mesh_update_req { ++ /// Flags, indicate fields which have been updated ++ u8_l flags; ++ /// VIF Index ++ u8_l vif_idx; ++ /// Root Mode ++ u8_l root_mode; ++ /// Gate Announcement ++ bool_l gate_announ; ++ /// Mesh Forwarding ++ bool_l mesh_forward; ++ /// Local PS Mode ++ u8_l local_ps_mode; ++}; ++ ++/// Structure containing the parameters of the @ref MESH_UPDATE_CFM message. ++struct mesh_update_cfm { ++ /// Status ++ u8_l status; ++}; ++ ++/// Structure containing the parameters of the @ref MESH_PEER_INFO_REQ message. ++struct mesh_peer_info_req { ++ ///Index of the station allocated for the peer ++ u8_l sta_idx; ++}; ++ ++/// Structure containing the parameters of the @ref MESH_PEER_INFO_CFM message. ++struct mesh_peer_info_cfm { ++ /// Response status ++ u8_l status; ++ /// Index of the station allocated for the peer ++ u8_l sta_idx; ++ /// Local Link ID ++ u16_l local_link_id; ++ /// Peer Link ID ++ u16_l peer_link_id; ++ /// Local PS Mode ++ u8_l local_ps_mode; ++ /// Peer PS Mode ++ u8_l peer_ps_mode; ++ /// Non-peer PS Mode ++ u8_l non_peer_ps_mode; ++ /// Link State ++ u8_l link_state; ++}; ++ ++/// Structure containing the parameters of the @ref MESH_PATH_CREATE_REQ message. ++struct mesh_path_create_req { ++ /// Index of the interface on which path has to be created ++ u8_l vif_idx; ++ /// Indicate if originator MAC Address is provided ++ bool_l has_orig_addr; ++ /// Path Target MAC Address ++ struct mac_addr tgt_mac_addr; ++ /// Originator MAC Address ++ struct mac_addr orig_mac_addr; ++}; ++ ++/// Structure containing the parameters of the @ref MESH_PATH_CREATE_CFM message. ++struct mesh_path_create_cfm { ++ /// Confirmation status ++ u8_l status; ++ /// VIF Index ++ u8_l vif_idx; ++}; ++ ++/// Structure containing the parameters of the @ref MESH_PATH_UPDATE_REQ message. ++struct mesh_path_update_req { ++ /// Indicate if path must be deleted ++ bool_l delete; ++ /// Index of the interface on which path has to be created ++ u8_l vif_idx; ++ /// Path Target MAC Address ++ struct mac_addr tgt_mac_addr; ++ /// Next Hop MAC Address ++ struct mac_addr nhop_mac_addr; ++}; ++ ++/// Structure containing the parameters of the @ref MESH_PATH_UPDATE_CFM message. ++struct mesh_path_update_cfm { ++ /// Confirmation status ++ u8_l status; ++ /// VIF Index ++ u8_l vif_idx; ++}; ++ ++/// Structure containing the parameters of the @ref MESH_PROXY_ADD_REQ message. ++struct mesh_proxy_add_req { ++ /// VIF Index ++ u8_l vif_idx; ++ /// MAC Address of the External STA ++ struct mac_addr ext_sta_addr; ++}; ++ ++/// Structure containing the parameters of the @ref MESH_PROXY_UPDATE_IND ++struct mesh_proxy_update_ind { ++ /// Indicate if proxy information has been added or deleted ++ bool_l delete; ++ /// Indicate if we are a proxy for the external STA ++ bool_l local; ++ /// VIF Index ++ u8_l vif_idx; ++ /// MAC Address of the External STA ++ struct mac_addr ext_sta_addr; ++ /// MAC Address of the proxy (only valid if local is false) ++ struct mac_addr proxy_mac_addr; ++}; ++ ++/// Structure containing the parameters of the @ref MESH_PEER_UPDATE_IND message. ++struct mesh_peer_update_ind { ++ /// Indicate if connection has been established or lost ++ bool_l estab; ++ /// VIF Index ++ u8_l vif_idx; ++ /// STA Index ++ u8_l sta_idx; ++ /// Peer MAC Address ++ struct mac_addr peer_addr; ++}; ++ ++/// Structure containing the parameters of the @ref MESH_PEER_UPDATE_NTF message. ++struct mesh_peer_update_ntf { ++ /// VIF Index ++ u8_l vif_idx; ++ /// STA Index ++ u8_l sta_idx; ++ /// Mesh Link State ++ u8_l state; ++}; ++ ++/// Structure containing the parameters of the @ref MESH_PATH_UPDATE_IND message. ++struct mesh_path_update_ind { ++ /// Indicate if path is deleted or not ++ bool_l delete; ++ /// Indicate if path is towards an external STA (not part of MBSS) ++ bool_l ext_sta; ++ /// VIF Index ++ u8_l vif_idx; ++ /// Path Index ++ u8_l path_idx; ++ /// Target MAC Address ++ struct mac_addr tgt_mac_addr; ++ /// External STA MAC Address (only if ext_sta is true) ++ struct mac_addr ext_sta_mac_addr; ++ /// Next Hop STA Index ++ u8_l nhop_sta_idx; ++}; ++ ++/////////////////////////////////////////////////////////////////////////////// ++/////////// For Debug messages ++/////////////////////////////////////////////////////////////////////////////// ++ ++/// Messages related to Debug Task ++enum dbg_msg_tag { ++ /// Memory read request ++ DBG_MEM_READ_REQ = LMAC_FIRST_MSG(TASK_DBG), ++ /// Memory read confirm ++ DBG_MEM_READ_CFM, ++ /// Memory write request ++ DBG_MEM_WRITE_REQ, ++ /// Memory write confirm ++ DBG_MEM_WRITE_CFM, ++ /// Module filter request ++ DBG_SET_MOD_FILTER_REQ, ++ /// Module filter confirm ++ DBG_SET_MOD_FILTER_CFM, ++ /// Severity filter request ++ DBG_SET_SEV_FILTER_REQ, ++ /// Severity filter confirm ++ DBG_SET_SEV_FILTER_CFM, ++ /// LMAC/MAC HW fatal error indication ++ DBG_ERROR_IND, ++ /// Request to get system statistics ++ DBG_GET_SYS_STAT_REQ, ++ /// COnfirmation of system statistics ++ DBG_GET_SYS_STAT_CFM, ++ /// Memory block write request ++ DBG_MEM_BLOCK_WRITE_REQ, ++ /// Memory block write confirm ++ DBG_MEM_BLOCK_WRITE_CFM, ++ /// Start app request ++ DBG_START_APP_REQ, ++ /// Start app confirm ++ DBG_START_APP_CFM, ++ /// Start npc request ++ DBG_START_NPC_REQ, ++ /// Start npc confirm ++ DBG_START_NPC_CFM, ++ /// Memory mask write request ++ 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, ++ ++ DBG_CUSTOM_MSG_REQ, ++ DBG_CUSTOM_MSG_CFM, ++ DBG_CUSTOM_MSG_IND, ++ ++ DBG_GPIO_WRITE_REQ, ++ DBG_GPIO_WRITE_CFM, ++ DBG_GPIO_READ_REQ, ++ DBG_GPIO_READ_CFM, ++ DBG_GPIO_INIT_REQ, ++ DBG_GPIO_INIT_CFM, ++ ++ /// EF usrdata read request ++ DBG_EF_USRDATA_READ_REQ, ++ /// EF usrdata read confirm ++ DBG_EF_USRDATA_READ_CFM, ++ /// Memory block read request ++ DBG_MEM_BLOCK_READ_REQ, ++ /// Memory block read confirm ++ DBG_MEM_BLOCK_READ_CFM, ++ ++ DBG_PWM_INIT_REQ, ++ DBG_PWM_INIT_CFM, ++ DBG_PWM_DEINIT_REQ, ++ DBG_PWM_DEINIT_CFM, ++ ++ /// Max number of Debug messages ++ DBG_MAX, ++}; ++ ++/// Structure containing the parameters of the @ref DBG_MEM_READ_REQ message. ++struct dbg_mem_read_req { ++ u32_l memaddr; ++}; ++ ++/// Structure containing the parameters of the @ref DBG_MEM_READ_CFM message. ++struct dbg_mem_read_cfm { ++ u32_l memaddr; ++ u32_l memdata; ++}; ++ ++/// Structure containing the parameters of the @ref DBG_MEM_WRITE_REQ message. ++struct dbg_mem_write_req { ++ u32_l memaddr; ++ u32_l memdata; ++}; ++ ++/// Structure containing the parameters of the @ref DBG_MEM_WRITE_CFM message. ++struct dbg_mem_write_cfm { ++ u32_l memaddr; ++ u32_l memdata; ++}; ++ ++/// Structure containing the parameters of the @ref DBG_MEM_MASK_WRITE_REQ message. ++struct dbg_mem_mask_write_req { ++ u32_l memaddr; ++ u32_l memmask; ++ u32_l memdata; ++}; ++ ++/// Structure containing the parameters of the @ref DBG_MEM_MASK_WRITE_CFM message. ++struct dbg_mem_mask_write_cfm { ++ u32_l memaddr; ++ u32_l memdata; ++}; ++ ++struct dbg_rftest_cmd_req { ++ u32_l cmd; ++ u32_l argc; ++ u8_l argv[10]; ++}; ++ ++struct dbg_rftest_cmd_cfm { ++ u32_l rftest_result[32]; ++}; ++ ++struct dbg_gpio_write_req { ++ uint8_t gpio_idx; ++ uint8_t gpio_val; ++}; ++ ++struct dbg_gpio_read_req { ++ uint8_t gpio_idx; ++}; ++ ++struct dbg_gpio_read_cfm { ++ uint8_t gpio_idx; ++ uint8_t gpio_val; ++}; ++ ++struct dbg_gpio_init_req { ++ uint8_t gpio_idx; ++ uint8_t gpio_dir; //1 output, 0 input; ++ uint8_t gpio_val; //for output, 1 high, 0 low; ++}; ++ ++#ifdef CONFIG_MCU_MESSAGE ++/// Structure containing the parameters of the @ref DBG_CUSTOM_MSG_REQ message. ++struct dbg_custom_msg_req { ++ u32_l cmd; ++ u32_l len; ++ u32_l flags; ++ u32_l buf[1]; ++}; ++ ++/// Structure containing the parameters of the @ref DBG_CUSTOM_MSG_CFM message. ++struct dbg_custom_msg_cfm { ++ u32_l cmd; ++ u32_l len; ++ u32_l status; ++ u32_l buf[1]; ++}; ++ ++typedef struct dbg_custom_msg_cfm dbg_custom_msg_ind_t; ++#endif ++ ++/// Structure containing the parameters of the @ref DBG_SET_MOD_FILTER_REQ message. ++struct dbg_set_mod_filter_req { ++ /// Bit field indicating for each module if the traces are enabled or not ++ u32_l mod_filter; ++}; ++ ++/// Structure containing the parameters of the @ref DBG_SEV_MOD_FILTER_REQ message. ++struct dbg_set_sev_filter_req { ++ /// Bit field indicating the severity threshold for the traces ++ u32_l sev_filter; ++}; ++ ++/// Structure containing the parameters of the @ref DBG_GET_SYS_STAT_CFM message. ++struct dbg_get_sys_stat_cfm { ++ /// Time spent in CPU sleep since last reset of the system statistics ++ u32_l cpu_sleep_time; ++ /// Time spent in DOZE since last reset of the system statistics ++ u32_l doze_time; ++ /// Total time spent since last reset of the system statistics ++ u32_l stats_time; ++}; ++ ++/// Structure containing the parameters of the @ref DBG_MEM_BLOCK_WRITE_REQ message. ++struct dbg_mem_block_write_req { ++ u32_l memaddr; ++ u32_l memsize; ++ u32_l memdata[1024 / sizeof(u32_l)]; ++}; ++ ++/// Structure containing the parameters of the @ref DBG_MEM_BLOCK_WRITE_CFM message. ++struct dbg_mem_block_write_cfm { ++ u32_l wstatus; ++}; ++ ++/// Structure containing the parameters of the @ref DBG_MEM_BLOCK_READ_REQ message. ++struct dbg_mem_block_read_req { ++ u32_l memaddr; ++ u32_l memsize; ++}; ++ ++/// Structure containing the parameters of the @ref DBG_MEM_BLOCK_READ_CFM message. ++struct dbg_mem_block_read_cfm { ++ u32_l memaddr; ++ u32_l memsize; ++ u32_l memdata[1024 / sizeof(u32_l)]; ++}; ++ ++/// Structure containing the parameters of the @ref DBG_START_APP_REQ message. ++struct dbg_start_app_req { ++ u32_l bootaddr; ++ u32_l boottype; ++}; ++ ++/// Structure containing the parameters of the @ref DBG_START_APP_CFM message. ++struct dbg_start_app_cfm { ++ u32_l bootstatus; ++}; ++ ++enum { ++ HOST_START_APP_AUTO = 1, ++ HOST_START_APP_CUSTOM, ++ HOST_START_APP_FNCALL = 4, ++ HOST_START_APP_DUMMY = 5, ++}; ++ ++/////////////////////////////////////////////////////////////////////////////// ++/////////// For TDLS messages ++/////////////////////////////////////////////////////////////////////////////// ++ ++/// List of messages related to the task. ++enum tdls_msg_tag { ++ /// TDLS channel Switch Request. ++ TDLS_CHAN_SWITCH_REQ = LMAC_FIRST_MSG(TASK_TDLS), ++ /// TDLS channel switch confirmation. ++ TDLS_CHAN_SWITCH_CFM, ++ /// TDLS channel switch indication. ++ TDLS_CHAN_SWITCH_IND, ++ /// TDLS channel switch to base channel indication. ++ TDLS_CHAN_SWITCH_BASE_IND, ++ /// TDLS cancel channel switch request. ++ TDLS_CANCEL_CHAN_SWITCH_REQ, ++ /// TDLS cancel channel switch confirmation. ++ TDLS_CANCEL_CHAN_SWITCH_CFM, ++ /// TDLS peer power save indication. ++ TDLS_PEER_PS_IND, ++ /// TDLS peer traffic indication request. ++ TDLS_PEER_TRAFFIC_IND_REQ, ++ /// TDLS peer traffic indication confirmation. ++ TDLS_PEER_TRAFFIC_IND_CFM, ++ ++#ifdef CONFIG_SDIO_BT ++ TDLS_SDIO_BT_SEND_REQ = LMAC_FIRST_MSG(TASK_TDLS) + 16, ++ TDLS_SDIO_BT_SEND_CFM, ++ TDLS_SDIO_BT_RECV_IND, ++#endif ++ /// MAX number of messages ++ TDLS_MAX ++}; ++ ++/// Structure containing the parameters of the @ref TDLS_CHAN_SWITCH_REQ message ++struct tdls_chan_switch_req { ++ /// Index of the VIF ++ u8_l vif_index; ++ /// STA Index ++ u8_l sta_idx; ++ /// MAC address of the TDLS station ++ struct mac_addr peer_mac_addr; ++ bool_l initiator; ++ /// Band (2.4GHz or 5GHz) ++ u8_l band; ++ /// Channel type: 20,40,80,160 or 80+80 MHz ++ u8_l type; ++ /// Frequency for Primary 20MHz channel (in MHz) ++ u16_l prim20_freq; ++ /// Frequency for Center of the contiguous channel or center of Primary 80+80 ++ u16_l center1_freq; ++ /// Frequency for Center of the non-contiguous secondary 80+80 ++ u16_l center2_freq; ++ /// TX power (in dBm) ++ s8_l tx_power; ++ /// Operating class ++ u8_l op_class; ++}; ++ ++/// Structure containing the parameters of the @ref TDLS_CANCEL_CHAN_SWITCH_REQ message ++struct tdls_cancel_chan_switch_req { ++ /// Index of the VIF ++ u8_l vif_index; ++ /// STA Index ++ u8_l sta_idx; ++ /// MAC address of the TDLS station ++ struct mac_addr peer_mac_addr; ++}; ++ ++/// Structure containing the parameters of the @ref TDLS_CHAN_SWITCH_CFM message ++struct tdls_chan_switch_cfm { ++ /// Status of the operation ++ u8_l status; ++}; ++ ++/// Structure containing the parameters of the @ref TDLS_CANCEL_CHAN_SWITCH_CFM message ++struct tdls_cancel_chan_switch_cfm { ++ /// Status of the operation ++ u8_l status; ++}; ++ ++/// Structure containing the parameters of the @ref TDLS_CHAN_SWITCH_IND message ++struct tdls_chan_switch_ind { ++ /// VIF Index ++ u8_l vif_index; ++ /// Channel Context Index ++ u8_l chan_ctxt_index; ++ /// Status of the operation ++ u8_l status; ++}; ++ ++/// Structure containing the parameters of the @ref TDLS_CHAN_SWITCH_BASE_IND message ++struct tdls_chan_switch_base_ind { ++ /// VIF Index ++ u8_l vif_index; ++ /// Channel Context index ++ u8_l chan_ctxt_index; ++}; ++ ++/// Structure containing the parameters of the @ref TDLS_PEER_PS_IND message ++struct tdls_peer_ps_ind { ++ /// VIF Index ++ u8_l vif_index; ++ /// STA Index ++ u8_l sta_idx; ++ /// MAC ADDR of the TDLS STA ++ struct mac_addr peer_mac_addr; ++ /// Flag to indicate if the TDLS peer is going to sleep ++ bool ps_on; ++}; ++ ++/// Structure containing the parameters of the @ref TDLS_PEER_TRAFFIC_IND_REQ message ++struct tdls_peer_traffic_ind_req { ++ /// VIF Index ++ u8_l vif_index; ++ /// STA Index ++ u8_l sta_idx; ++ // MAC ADDR of the TDLS STA ++ struct mac_addr peer_mac_addr; ++ /// Dialog token ++ u8_l dialog_token; ++ /// TID of the latest MPDU transmitted over the TDLS direct link to the TDLS STA ++ u8_l last_tid; ++ /// Sequence number of the latest MPDU transmitted over the TDLS direct link ++ /// to the TDLS STA ++ u16_l last_sn; ++}; ++ ++/// Structure containing the parameters of the @ref TDLS_PEER_TRAFFIC_IND_CFM message ++struct tdls_peer_traffic_ind_cfm { ++ /// Status of the operation ++ u8_l status; ++}; ++ ++#endif // LMAC_MSG_H_ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/lmac_types.h b/drivers/net/wireless/aic8800/aic8800_fdrv/lmac_types.h +new file mode 100755 +index 000000000..eb90d08d5 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/lmac_types.h +@@ -0,0 +1,58 @@ ++/** ++ **************************************************************************************** ++ * ++ * @file co_types.h ++ * ++ * @brief This file replaces the need to include stdint or stdbool typical headers, ++ * which may not be available in all toolchains, and adds new types ++ * ++ * Copyright (C) RivieraWaves 2009-2019 ++ * ++ * $Rev: $ ++ * ++ **************************************************************************************** ++ */ ++ ++#ifndef _LMAC_INT_H_ ++#define _LMAC_INT_H_ ++ ++/** ++ **************************************************************************************** ++ * @addtogroup CO_INT ++ * @ingroup COMMON ++ * @brief Common integer standard types (removes use of stdint) ++ * ++ * @{ ++ **************************************************************************************** ++ */ ++ ++/* ++ * DEFINES ++ **************************************************************************************** ++ */ ++ ++#include ++#include ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) ++#include ++#else ++#include ++#endif ++ ++#ifdef CONFIG_RWNX_TL4 ++typedef uint16_t u8_l; ++typedef int16_t s8_l; ++typedef uint16_t bool_l; ++#else ++typedef uint8_t u8_l; ++typedef int8_t s8_l; ++typedef bool bool_l; ++#endif ++typedef uint16_t u16_l; ++typedef int16_t s16_l; ++typedef uint32_t u32_l; ++typedef int32_t s32_l; ++typedef uint64_t u64_l; ++ ++/// @} CO_INT ++#endif // _LMAC_INT_H_ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/md5.c b/drivers/net/wireless/aic8800/aic8800_fdrv/md5.c +new file mode 100755 +index 000000000..f21eba9a3 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/md5.c +@@ -0,0 +1,154 @@ ++#include ++#include "md5.h" ++ ++unsigned char PADDING[] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; ++ ++void MD5Init(MD5_CTX *context) ++{ ++ context->count[0] = 0; ++ context->count[1] = 0; ++ context->state[0] = 0x67452301; ++ context->state[1] = 0xEFCDAB89; ++ context->state[2] = 0x98BADCFE; ++ context->state[3] = 0x10325476; ++} ++void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int inputlen) ++{ ++ unsigned int i = 0, index = 0, partlen = 0; ++ index = (context->count[0] >> 3) & 0x3F; ++ partlen = 64 - index; ++ context->count[0] += inputlen << 3; ++ if (context->count[0] < (inputlen << 3)) ++ context->count[1]++; ++ context->count[1] += inputlen >> 29; ++ ++ if (inputlen >= partlen) { ++ memcpy(&context->buffer[index], input, partlen); ++ MD5Transform(context->state, context->buffer); ++ for (i = partlen; i + 64 <= inputlen; i += 64) ++ MD5Transform(context->state, &input[i]); ++ index = 0; ++ } else { ++ i = 0; ++ } ++ memcpy(&context->buffer[index], &input[i], inputlen - i); ++} ++void MD5Final(MD5_CTX *context, unsigned char digest[16]) ++{ ++ unsigned int index = 0, padlen = 0; ++ unsigned char bits[8]; ++ index = (context->count[0] >> 3) & 0x3F; ++ padlen = (index < 56) ? (56 - index) : (120 - index); ++ MD5Encode(bits, context->count, 8); ++ MD5Update(context, PADDING, padlen); ++ MD5Update(context, bits, 8); ++ MD5Encode(digest, context->state, 16); ++} ++void MD5Encode(unsigned char *output, unsigned int *input, unsigned int len) ++{ ++ unsigned int i = 0, j = 0; ++ while (j < len) { ++ output[j] = input[i] & 0xFF; ++ output[j + 1] = (input[i] >> 8) & 0xFF; ++ output[j + 2] = (input[i] >> 16) & 0xFF; ++ output[j + 3] = (input[i] >> 24) & 0xFF; ++ i++; ++ j += 4; ++ } ++} ++void MD5Decode(unsigned int *output, unsigned char *input, unsigned int len) ++{ ++ unsigned int i = 0, j = 0; ++ while (j < len) { ++ output[i] = (input[j]) | (input[j + 1] << 8) | ++ (input[j + 2] << 16) | (input[j + 3] << 24); ++ i++; ++ j += 4; ++ } ++} ++void MD5Transform(unsigned int state[4], unsigned char block[64]) ++{ ++ unsigned int a = state[0]; ++ unsigned int b = state[1]; ++ unsigned int c = state[2]; ++ unsigned int d = state[3]; ++ unsigned int x[64]; ++ MD5Decode(x, block, 64); ++ FF(a, b, c, d, x[0], 7, 0xd76aa478); /* 1 */ ++ FF(d, a, b, c, x[1], 12, 0xe8c7b756); /* 2 */ ++ FF(c, d, a, b, x[2], 17, 0x242070db); /* 3 */ ++ FF(b, c, d, a, x[3], 22, 0xc1bdceee); /* 4 */ ++ FF(a, b, c, d, x[4], 7, 0xf57c0faf); /* 5 */ ++ FF(d, a, b, c, x[5], 12, 0x4787c62a); /* 6 */ ++ FF(c, d, a, b, x[6], 17, 0xa8304613); /* 7 */ ++ FF(b, c, d, a, x[7], 22, 0xfd469501); /* 8 */ ++ FF(a, b, c, d, x[8], 7, 0x698098d8); /* 9 */ ++ FF(d, a, b, c, x[9], 12, 0x8b44f7af); /* 10 */ ++ FF(c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */ ++ FF(b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */ ++ FF(a, b, c, d, x[12], 7, 0x6b901122); /* 13 */ ++ FF(d, a, b, c, x[13], 12, 0xfd987193); /* 14 */ ++ FF(c, d, a, b, x[14], 17, 0xa679438e); /* 15 */ ++ FF(b, c, d, a, x[15], 22, 0x49b40821); /* 16 */ ++ ++ /* Round 2 */ ++ GG(a, b, c, d, x[1], 5, 0xf61e2562); /* 17 */ ++ GG(d, a, b, c, x[6], 9, 0xc040b340); /* 18 */ ++ GG(c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */ ++ GG(b, c, d, a, x[0], 20, 0xe9b6c7aa); /* 20 */ ++ GG(a, b, c, d, x[5], 5, 0xd62f105d); /* 21 */ ++ GG(d, a, b, c, x[10], 9, 0x2441453); /* 22 */ ++ GG(c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */ ++ GG(b, c, d, a, x[4], 20, 0xe7d3fbc8); /* 24 */ ++ GG(a, b, c, d, x[9], 5, 0x21e1cde6); /* 25 */ ++ GG(d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */ ++ GG(c, d, a, b, x[3], 14, 0xf4d50d87); /* 27 */ ++ GG(b, c, d, a, x[8], 20, 0x455a14ed); /* 28 */ ++ GG(a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */ ++ GG(d, a, b, c, x[2], 9, 0xfcefa3f8); /* 30 */ ++ GG(c, d, a, b, x[7], 14, 0x676f02d9); /* 31 */ ++ GG(b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */ ++ ++ /* Round 3 */ ++ HH(a, b, c, d, x[5], 4, 0xfffa3942); /* 33 */ ++ HH(d, a, b, c, x[8], 11, 0x8771f681); /* 34 */ ++ HH(c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */ ++ HH(b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */ ++ HH(a, b, c, d, x[1], 4, 0xa4beea44); /* 37 */ ++ HH(d, a, b, c, x[4], 11, 0x4bdecfa9); /* 38 */ ++ HH(c, d, a, b, x[7], 16, 0xf6bb4b60); /* 39 */ ++ HH(b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */ ++ HH(a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */ ++ HH(d, a, b, c, x[0], 11, 0xeaa127fa); /* 42 */ ++ HH(c, d, a, b, x[3], 16, 0xd4ef3085); /* 43 */ ++ HH(b, c, d, a, x[6], 23, 0x4881d05); /* 44 */ ++ HH(a, b, c, d, x[9], 4, 0xd9d4d039); /* 45 */ ++ HH(d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */ ++ HH(c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */ ++ HH(b, c, d, a, x[2], 23, 0xc4ac5665); /* 48 */ ++ ++ /* Round 4 */ ++ II(a, b, c, d, x[0], 6, 0xf4292244); /* 49 */ ++ II(d, a, b, c, x[7], 10, 0x432aff97); /* 50 */ ++ II(c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */ ++ II(b, c, d, a, x[5], 21, 0xfc93a039); /* 52 */ ++ II(a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */ ++ II(d, a, b, c, x[3], 10, 0x8f0ccc92); /* 54 */ ++ II(c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */ ++ II(b, c, d, a, x[1], 21, 0x85845dd1); /* 56 */ ++ II(a, b, c, d, x[8], 6, 0x6fa87e4f); /* 57 */ ++ II(d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */ ++ II(c, d, a, b, x[6], 15, 0xa3014314); /* 59 */ ++ II(b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */ ++ II(a, b, c, d, x[4], 6, 0xf7537e82); /* 61 */ ++ II(d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */ ++ II(c, d, a, b, x[2], 15, 0x2ad7d2bb); /* 63 */ ++ II(b, c, d, a, x[9], 21, 0xeb86d391); /* 64 */ ++ state[0] += a; ++ state[1] += b; ++ state[2] += c; ++ state[3] += d; ++} +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/md5.h b/drivers/net/wireless/aic8800/aic8800_fdrv/md5.h +new file mode 100755 +index 000000000..9b2c52eed +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/md5.h +@@ -0,0 +1,46 @@ ++#ifndef MD5_H ++#define MD5_H ++ ++typedef struct { ++ unsigned int count[2]; ++ unsigned int state[4]; ++ unsigned char buffer[64]; ++} MD5_CTX; ++ ++#define F(x, y, z) ((x & y) | (~x & z)) ++#define G(x, y, z) ((x & z) | (y & ~z)) ++#define H(x, y, z) (x ^ y ^ z) ++#define I(x, y, z) (y ^ (x | ~z)) ++#define ROTATE_LEFT(x, n) ((x << n) | (x >> (32 - n))) ++#define FF(a, b, c, d, x, s, ac) \ ++ { \ ++ a += F(b, c, d) + x + ac; \ ++ a = ROTATE_LEFT(a, s); \ ++ a += b; \ ++ } ++#define GG(a, b, c, d, x, s, ac) \ ++ { \ ++ a += G(b, c, d) + x + ac; \ ++ a = ROTATE_LEFT(a, s); \ ++ a += b; \ ++ } ++#define HH(a, b, c, d, x, s, ac) \ ++ { \ ++ a += H(b, c, d) + x + ac; \ ++ a = ROTATE_LEFT(a, s); \ ++ a += b; \ ++ } ++#define II(a, b, c, d, x, s, ac) \ ++ { \ ++ a += I(b, c, d) + x + ac; \ ++ a = ROTATE_LEFT(a, s); \ ++ a += b; \ ++ } ++void MD5Init(MD5_CTX *context); ++void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int inputlen); ++void MD5Final(MD5_CTX *context, unsigned char digest[16]); ++void MD5Transform(unsigned int state[4], unsigned char block[64]); ++void MD5Encode(unsigned char *output, unsigned int *input, unsigned int len); ++void MD5Decode(unsigned int *output, unsigned char *input, unsigned int len); ++ ++#endif +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/reg_access.h b/drivers/net/wireless/aic8800/aic8800_fdrv/reg_access.h +new file mode 100755 +index 000000000..4ba497655 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/reg_access.h +@@ -0,0 +1,148 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file reg_access.h ++ * ++ * @brief Definitions and macros for MAC HW and platform register accesses ++ * ++ * Copyright (C) RivieraWaves 2011-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++#ifndef REG_ACCESS_H_ ++#define REG_ACCESS_H_ ++ ++/***************************************************************************** ++ * Addresses within RWNX_ADDR_SYSTEM ++ *****************************************************************************/ ++/* Shard RAM */ ++#define SHARED_RAM_START_ADDR 0x00000000 ++ ++/* IPC registers */ ++#define IPC_REG_BASE_ADDR 0x00800000 ++ ++/* System Controller Registers */ ++#define SYSCTRL_SIGNATURE_ADDR 0x00900000 ++// old diag register name ++#define SYSCTRL_DIAG_CONF_ADDR 0x00900068 ++#define SYSCTRL_PHYDIAG_CONF_ADDR 0x00900074 ++#define SYSCTRL_RIUDIAG_CONF_ADDR 0x00900078 ++// new diag register name ++#define SYSCTRL_DIAG_CONF0 0x00900064 ++#define SYSCTRL_DIAG_CONF1 0x00900068 ++#define SYSCTRL_DIAG_CONF2 0x00900074 ++#define SYSCTRL_DIAG_CONF3 0x00900078 ++#define SYSCTRL_MISC_CNTL_ADDR 0x009000E0 ++#define BOOTROM_ENABLE BIT(4) ++#define FPGA_B_RESET BIT(1) ++#define SOFT_RESET BIT(0) ++ ++/* MAC platform */ ++#define NXMAC_VERSION_1_ADDR 0x00B00004 ++#define NXMAC_MU_MIMO_TX_BIT BIT(19) ++#define NXMAC_BFMER_BIT BIT(18) ++#define NXMAC_BFMEE_BIT BIT(17) ++#define NXMAC_MAC_80211MH_FORMAT_BIT BIT(16) ++#define NXMAC_COEX_BIT BIT(14) ++#define NXMAC_WAPI_BIT BIT(13) ++#define NXMAC_TPC_BIT BIT(12) ++#define NXMAC_VHT_BIT BIT(11) ++#define NXMAC_HT_BIT BIT(10) ++#define NXMAC_RCE_BIT BIT(8) ++#define NXMAC_CCMP_BIT BIT(7) ++#define NXMAC_TKIP_BIT BIT(6) ++#define NXMAC_WEP_BIT BIT(5) ++#define NXMAC_SECURITY_BIT BIT(4) ++#define NXMAC_SME_BIT BIT(3) ++#define NXMAC_HCCA_BIT BIT(2) ++#define NXMAC_EDCA_BIT BIT(1) ++#define NXMAC_QOS_BIT BIT(0) ++ ++#define NXMAC_RX_CNTRL_ADDR 0x00B00060 ++#define NXMAC_EN_DUPLICATE_DETECTION_BIT BIT(31) ++#define NXMAC_ACCEPT_UNKNOWN_BIT BIT(30) ++#define NXMAC_ACCEPT_OTHER_DATA_FRAMES_BIT BIT(29) ++#define NXMAC_ACCEPT_QO_S_NULL_BIT BIT(28) ++#define NXMAC_ACCEPT_QCFWO_DATA_BIT BIT(27) ++#define NXMAC_ACCEPT_Q_DATA_BIT BIT(26) ++#define NXMAC_ACCEPT_CFWO_DATA_BIT BIT(25) ++#define NXMAC_ACCEPT_DATA_BIT BIT(24) ++#define NXMAC_ACCEPT_OTHER_CNTRL_FRAMES_BIT BIT(23) ++#define NXMAC_ACCEPT_CF_END_BIT BIT(22) ++#define NXMAC_ACCEPT_ACK_BIT BIT(21) ++#define NXMAC_ACCEPT_CTS_BIT BIT(20) ++#define NXMAC_ACCEPT_RTS_BIT BIT(19) ++#define NXMAC_ACCEPT_PS_POLL_BIT BIT(18) ++#define NXMAC_ACCEPT_BA_BIT BIT(17) ++#define NXMAC_ACCEPT_BAR_BIT BIT(16) ++#define NXMAC_ACCEPT_OTHER_MGMT_FRAMES_BIT BIT(15) ++#define NXMAC_ACCEPT_BFMEE_FRAMES_BIT BIT(14) ++#define NXMAC_ACCEPT_ALL_BEACON_BIT BIT(13) ++#define NXMAC_ACCEPT_NOT_EXPECTED_BA_BIT BIT(12) ++#define NXMAC_ACCEPT_DECRYPT_ERROR_FRAMES_BIT BIT(11) ++#define NXMAC_ACCEPT_BEACON_BIT BIT(10) ++#define NXMAC_ACCEPT_PROBE_RESP_BIT BIT(9) ++#define NXMAC_ACCEPT_PROBE_REQ_BIT BIT(8) ++#define NXMAC_ACCEPT_MY_UNICAST_BIT BIT(7) ++#define NXMAC_ACCEPT_UNICAST_BIT BIT(6) ++#define NXMAC_ACCEPT_ERROR_FRAMES_BIT BIT(5) ++#define NXMAC_ACCEPT_OTHER_BSSID_BIT BIT(4) ++#define NXMAC_ACCEPT_BROADCAST_BIT BIT(3) ++#define NXMAC_ACCEPT_MULTICAST_BIT BIT(2) ++#define NXMAC_DONT_DECRYPT_BIT BIT(1) ++#define NXMAC_EXC_UNENCRYPTED_BIT BIT(0) ++ ++#define NXMAC_DEBUG_PORT_SEL_ADDR 0x00B00510 ++#define NXMAC_SW_SET_PROFILING_ADDR 0x00B08564 ++#define NXMAC_SW_CLEAR_PROFILING_ADDR 0x00B08568 ++ ++/* Modem Status */ ++#define MDM_HDMCONFIG_ADDR 0x00C00000 ++ ++/* Clock gating configuration */ ++#define MDM_MEMCLKCTRL0_ADDR 0x00C00848 ++#define MDM_CLKGATEFCTRL0_ADDR 0x00C00874 ++#define CRM_CLKGATEFCTRL0_ADDR 0x00940010 ++ ++/* AGC (trident) */ ++#define AGC_RWNXAGCCNTL_ADDR 0x00C02060 ++ ++/* LDPC RAM*/ ++#define PHY_LDPC_RAM_ADDR 0x00C09000 ++ ++/* FCU (elma )*/ ++#define FCU_RWNXFCAGCCNTL_ADDR 0x00C09034 ++ ++/* AGC RAM */ ++#define PHY_AGC_UCODE_ADDR 0x00C0A000 ++ ++/* RIU */ ++#define RIU_RWNXVERSION_ADDR 0x00C0B000 ++#define RIU_RWNXDYNAMICCONFIG_ADDR 0x00C0B008 ++#define RIU_AGCMEMBISTSTAT_ADDR 0x00C0B238 ++#define RIU_AGCMEMSIGNATURESTAT_ADDR 0x00C0B23C ++#define RIU_RWNXAGCCNTL_ADDR 0x00C0B390 ++ ++/* FCU RAM */ ++#define PHY_FCU_UCODE_ADDR 0x00C0E000 ++ ++/* RF ITF */ ++#define FPGAB_MPIF_SEL_ADDR 0x00C10030 ++#define RF_V6_DIAGPORT_CONF1_ADDR 0x00C10010 ++#define RF_v6_PHYDIAG_CONF1_ADDR 0x00C10018 ++ ++#define RF_V7_DIAGPORT_CONF1_ADDR 0x00F10010 ++#define RF_v7_PHYDIAG_CONF1_ADDR 0x00F10018 ++ ++/***************************************************************************** ++ * Macros for generated register files ++ *****************************************************************************/ ++/* Macros for IPC registers access (used in reg_ipc_app.h) */ ++#define REG_IPC_APP_RD(env, INDEX) \ ++ (*(volatile u32 *)((u8 *)env + IPC_REG_BASE_ADDR + 4 * (INDEX))) ++ ++#define REG_IPC_APP_WR(env, INDEX, value) \ ++ (*(volatile u32 *)((u8 *)env + IPC_REG_BASE_ADDR + 4 * (INDEX)) = value) ++ ++#endif /* REG_ACCESS_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/regdb.c b/drivers/net/wireless/aic8800/aic8800_fdrv/regdb.c +new file mode 100755 +index 000000000..dda8dc67f +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/regdb.c +@@ -0,0 +1,2768 @@ ++#include ++#include ++#include ++ ++//#include "regdb.h" ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0) ++#define REG_RULE_EXT(start, end, bw, gain, eirp, dfs_cac, reg_flags) \ ++ { \ ++ .freq_range.start_freq_khz = MHZ_TO_KHZ(start), \ ++ .freq_range.end_freq_khz = MHZ_TO_KHZ(end), \ ++ .freq_range.max_bandwidth_khz = MHZ_TO_KHZ(bw), \ ++ .power_rule.max_antenna_gain = DBI_TO_MBI(gain), \ ++ .power_rule.max_eirp = DBM_TO_MBM(eirp), .flags = reg_flags, \ ++ } ++#define NL80211_RRF_AUTO_BW 0 ++#endif ++ ++static const struct ieee80211_regdomain regdom_00 = { ++ .n_reg_rules = 2, ++ .alpha2 = "00", ++ .reg_rules = { ++ // 1...14 ++ REG_RULE(2390 - 10, 2510 + 10, 40, 0, 20, 0), ++ // 36...165 ++ REG_RULE(5150 - 10, 5970 + 10, 80, 0, 20, 0), ++ } ++ ++#if 0 ++ .alpha2 = "00", ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2472, 40, 0, 20, 0, 0), ++ //REG_RULE_EXT(2457, 2482, 40, 0, 20, 0, ++ // NL80211_RRF_NO_IR | 0), ++ REG_RULE_EXT(2474, 2494, 20, 0, 20, 0, ++ NL80211_RRF_NO_IR | ++ NL80211_RRF_NO_OFDM | 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_NO_IR | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_NO_IR | ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 20, 0, ++ NL80211_RRF_NO_IR | ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 20, 0, ++ NL80211_RRF_NO_IR | 0), ++ }, ++ .n_reg_rules = 6 ++#endif ++}; ++ ++static const struct ieee80211_regdomain regdom_AD = { ++ .alpha2 = "AD", ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5490, 5710, 80, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_AE = { ++ .alpha2 = "AE", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ //REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_AF = { ++ .alpha2 = "AF", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_AI = { ++ .alpha2 = "AI", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_AL = { ++ .alpha2 = "AL", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_AM = { ++ .alpha2 = "AM", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 18, 0, 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 18, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 3 ++}; ++ ++static const struct ieee80211_regdomain regdom_AN = { ++ .alpha2 = "AN", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_AR = { ++ .alpha2 = "AR", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ //REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ // NL80211_RRF_AUTO_BW | 0), ++ //REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ // NL80211_RRF_DFS | ++ // NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5270, 5330, 40, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ //REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ // NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5815, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 3 ++}; ++ ++static const struct ieee80211_regdomain regdom_AS = { ++ .alpha2 = "AS", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2472, 40, 0, 30, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 24, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_AT = { ++ .alpha2 = "AT", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_AU = { ++ .alpha2 = "AU", ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_AW = { ++ .alpha2 = "AW", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_AZ = { ++ .alpha2 = "AZ", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 18, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 18, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ }, ++ .n_reg_rules = 3 ++}; ++ ++static const struct ieee80211_regdomain regdom_BA = { ++ .alpha2 = "BA", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_BB = { ++ .alpha2 = "BB", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 23, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 23, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_BD = { ++ .alpha2 = "BD", ++ .dfs_region = NL80211_DFS_JP, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 2 ++}; ++ ++static const struct ieee80211_regdomain regdom_BE = { ++ .alpha2 = "BE", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_BF = { ++ .alpha2 = "BF", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_BG = { ++ .alpha2 = "BG", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_BH = { ++ .alpha2 = "BH", ++ .dfs_region = NL80211_DFS_JP, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 20, 0, 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_BL = { ++ .alpha2 = "BL", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_BM = { ++ .alpha2 = "BM", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2472, 40, 0, 30, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 24, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_BN = { ++ .alpha2 = "BN", ++ .dfs_region = NL80211_DFS_JP, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 20, 0, 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_BO = { ++ .alpha2 = "BO", ++ .dfs_region = NL80211_DFS_JP, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 30, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 3 ++}; ++ ++static const struct ieee80211_regdomain regdom_BR = { ++ .alpha2 = "BR", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_BS = { ++ .alpha2 = "BS", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 24, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_BT = { ++ .alpha2 = "BT", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_BY = { ++ .alpha2 = "BY", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_BZ = { ++ .alpha2 = "BZ", ++ .dfs_region = NL80211_DFS_JP, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 30, 0, 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 2 ++}; ++ ++static const struct ieee80211_regdomain regdom_CA = { ++ .alpha2 = "CA", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2472, 40, 0, 30, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_CF = { ++ .alpha2 = "CF", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 40, 0, 17, 0, 0), ++ REG_RULE_EXT(5250, 5330, 40, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5490, 5730, 40, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 40, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_CH = { ++ .alpha2 = "CH", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_CI = { ++ .alpha2 = "CI", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_CL = { ++ .alpha2 = "CL", ++ .dfs_region = NL80211_DFS_JP, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 20, 0, 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_CN = { ++ .alpha2 = "CN", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 23, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 23, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ REG_RULE_EXT(57240, 59400, 2160, 0, 28, 0, 0), ++ REG_RULE_EXT(59400, 63720, 2160, 0, 44, 0, 0), ++ REG_RULE_EXT(63720, 65880, 2160, 0, 28, 0, 0), ++ }, ++ .n_reg_rules = 7 ++}; ++ ++static const struct ieee80211_regdomain regdom_CO = { ++ .alpha2 = "CO", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_CR = { ++ .alpha2 = "CR", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5490, 5730, 80, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_CX = { ++ .alpha2 = "CX", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 24, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_CY = { ++ .alpha2 = "CY", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_CZ = { ++ .alpha2 = "CZ", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2400, 2483, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5150, 5250, 80, 0, 23, 0, ++ NL80211_RRF_NO_OUTDOOR | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5350, 80, 0, 20, 0, ++ NL80211_RRF_NO_OUTDOOR | ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5470, 5725, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_DE = { ++ .alpha2 = "DE", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2400, 2483, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5150, 5250, 80, 0, 20, 0, NL80211_RRF_AUTO_BW| ++ NL80211_RRF_NO_OUTDOOR| ++ 0), ++ REG_RULE_EXT(5250, 5350, 80, 0, 20, 0, NL80211_RRF_AUTO_BW| ++ NL80211_RRF_DFS| ++ NL80211_RRF_NO_OUTDOOR| ++ 0), ++ REG_RULE_EXT(5470, 5725, 160, 0, 20, 0, NL80211_RRF_DFS| ++ 0), ++ REG_RULE_EXT(5725, 5875, 80, 0, 20, 0, 0), ++ REG_RULE_EXT(5945, 6425, 160, 0, 20, 0, NL80211_RRF_NO_OUTDOOR| ++ 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 20, 0, 0), ++ }, ++ .n_reg_rules = 7 ++}; ++ ++static const struct ieee80211_regdomain regdom_DK = { ++ .alpha2 = "DK", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_DM = { ++ .alpha2 = "DM", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2472, 40, 0, 30, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 23, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_DO = { ++ .alpha2 = "DO", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2472, 40, 0, 30, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 23, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_DZ = { ++ .alpha2 = "DZ", ++ .dfs_region = NL80211_DFS_JP, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 23, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 23, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5670, 160, 0, 23, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_EC = { ++ .alpha2 = "EC", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5490, 5730, 80, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_EE = { ++ .alpha2 = "EE", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_EG = { ++ .alpha2 = "EG", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 3 ++}; ++ ++static const struct ieee80211_regdomain regdom_ES = { ++ .alpha2 = "ES", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2400, 2483, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5150, 5250, 80, 0, 23, 0, ++ NL80211_RRF_NO_OUTDOOR | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5350, 80, 0, 20, 0, ++ NL80211_RRF_NO_OUTDOOR | ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5470, 5725, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_ET = { ++ .alpha2 = "ET", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_FI = { ++ .alpha2 = "FI", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_FM = { ++ .alpha2 = "FM", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2472, 40, 0, 30, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 24, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_FR = { ++ .alpha2 = "FR", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5695, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_GB = { ++ .alpha2 = "GB", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_GD = { ++ .alpha2 = "GD", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2472, 40, 0, 30, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_GE = { ++ .alpha2 = "GE", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 18, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 18, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_GF = { ++ .alpha2 = "GF", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_GH = { ++ .alpha2 = "GH", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_GL = { ++ .alpha2 = "GL", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5490, 5710, 80, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_GP = { ++ .alpha2 = "GP", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_GR = { ++ .alpha2 = "GR", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_GT = { ++ .alpha2 = "GT", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2472, 40, 0, 30, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 23, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_GU = { ++ .alpha2 = "GU", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2472, 40, 0, 30, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5490, 5730, 80, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_GY = { ++ .alpha2 = "GY", ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 30, 0, 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 2 ++}; ++ ++static const struct ieee80211_regdomain regdom_HK = { ++ .alpha2 = "HK", ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_HN = { ++ .alpha2 = "HN", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_HR = { ++ .alpha2 = "HR", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_HT = { ++ .alpha2 = "HT", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2472, 40, 0, 30, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 24, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_HU = { ++ .alpha2 = "HU", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_ID = { ++ .alpha2 = "ID", ++ .dfs_region = NL80211_DFS_JP, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5735, 5815, 80, 0, 23, 0, 0), ++ }, ++ .n_reg_rules = 2 ++}; ++ ++static const struct ieee80211_regdomain regdom_IE = { ++ .alpha2 = "IE", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_IL = { ++ .alpha2 = "IL", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5150, 5250, 80, 0, 23, 0, ++ NL80211_RRF_NO_OUTDOOR | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5350, 80, 0, 23, 0, ++ NL80211_RRF_NO_OUTDOOR | ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ }, ++ .n_reg_rules = 3 ++}; ++ ++static const struct ieee80211_regdomain regdom_IN = { ++ .alpha2 = "IN", ++ .dfs_region = NL80211_DFS_JP, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 20, 0, 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_IR = { ++ .alpha2 = "IR", ++ .dfs_region = NL80211_DFS_JP, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 2 ++}; ++ ++static const struct ieee80211_regdomain regdom_IS = { ++ .alpha2 = "IS", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_IT = { ++ .alpha2 = "IT", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_JM = { ++ .alpha2 = "JM", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_JO = { ++ .alpha2 = "JO", ++ .dfs_region = NL80211_DFS_JP, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 23, 0, 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 23, 0, 0), ++ }, ++ .n_reg_rules = 3 ++}; ++ ++static const struct ieee80211_regdomain regdom_JP = { ++ .alpha2 = "JP", ++ .dfs_region = NL80211_DFS_JP, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(2474, 2494, 20, 0, 20, 0, ++ NL80211_RRF_NO_OFDM | 0), ++ REG_RULE_EXT(4910, 4990, 40, 0, 23, 0, 0), ++ REG_RULE_EXT(5030, 5090, 40, 0, 23, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 23, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 7 ++}; ++ ++static const struct ieee80211_regdomain regdom_KE = { ++ .alpha2 = "KE", ++ .dfs_region = NL80211_DFS_JP, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 23, 0, 0), ++ REG_RULE_EXT(5490, 5570, 80, 0, 30, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5775, 40, 0, 23, 0, 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_KH = { ++ .alpha2 = "KH", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_KN = { ++ .alpha2 = "KN", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 30, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5815, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_KP = { ++ .alpha2 = "KP", ++ .dfs_region = NL80211_DFS_JP, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5630, 80, 0, 30, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5815, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_KR = { ++ .alpha2 = "KR", ++ .dfs_region = NL80211_DFS_JP, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 30, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_KW = { ++ .alpha2 = "KW", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ }, ++ .n_reg_rules = 3 ++}; ++ ++static const struct ieee80211_regdomain regdom_KY = { ++ .alpha2 = "KY", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 24, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_KZ = { ++ .alpha2 = "KZ", ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ }, ++ .n_reg_rules = 1 ++}; ++ ++static const struct ieee80211_regdomain regdom_LB = { ++ .alpha2 = "LB", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_LC = { ++ .alpha2 = "LC", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 30, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5815, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_LI = { ++ .alpha2 = "LI", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_LK = { ++ .alpha2 = "LK", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5490, 5730, 80, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_LS = { ++ .alpha2 = "LS", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_LT = { ++ .alpha2 = "LT", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_LU = { ++ .alpha2 = "LU", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_LV = { ++ .alpha2 = "LV", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_MA = { ++ .alpha2 = "MA", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ }, ++ .n_reg_rules = 3 ++}; ++ ++static const struct ieee80211_regdomain regdom_MC = { ++ .alpha2 = "MC", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_MD = { ++ .alpha2 = "MD", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_ME = { ++ .alpha2 = "ME", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_MF = { ++ .alpha2 = "MF", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_MH = { ++ .alpha2 = "MH", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2472, 40, 0, 30, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 24, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_MK = { ++ .alpha2 = "MK", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_MN = { ++ .alpha2 = "MN", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 24, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_MO = { ++ .alpha2 = "MO", ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 40, 0, 23, 0, 0), ++ REG_RULE_EXT(5250, 5330, 40, 0, 23, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 40, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_MP = { ++ .alpha2 = "MP", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2472, 40, 0, 30, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 24, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_MQ = { ++ .alpha2 = "MQ", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_MR = { ++ .alpha2 = "MR", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_MT = { ++ .alpha2 = "MT", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_MU = { ++ .alpha2 = "MU", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 24, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_MW = { ++ .alpha2 = "MW", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_MX = { ++ .alpha2 = "MX", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_MY = { ++ .alpha2 = "MY", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 23, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_NG = { ++ .alpha2 = "NG", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, NL80211_RRF_DFS| ++ 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 20, 0, 0), ++ }, ++ .n_reg_rules = 3 ++}; ++ ++static const struct ieee80211_regdomain regdom_NI = { ++ .alpha2 = "NI", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2472, 40, 0, 30, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 24, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_NL = { ++ .alpha2 = "NL", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_NO_OUTDOOR | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_NO_OUTDOOR | ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_NO = { ++ .alpha2 = "NO", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2400, 2483, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5150, 5250, 80, 0, 23, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5350, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5470, 5795, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5815, 5850, 35, 0, 33, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(17100, 17300, 200, 0, 20, 0, 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 7 ++}; ++ ++static const struct ieee80211_regdomain regdom_NP = { ++ .alpha2 = "NP", ++ .dfs_region = NL80211_DFS_JP, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 20, 0, 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_NZ = { ++ .alpha2 = "NZ", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 30, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_OM = { ++ .alpha2 = "OM", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_PA = { ++ .alpha2 = "PA", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2472, 40, 0, 30, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 23, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_PE = { ++ .alpha2 = "PE", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_PF = { ++ .alpha2 = "PF", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_PG = { ++ .alpha2 = "PG", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_PH = { ++ .alpha2 = "PH", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_PK = { ++ .alpha2 = "PK", ++ .dfs_region = NL80211_DFS_JP, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 2 ++}; ++ ++static const struct ieee80211_regdomain regdom_PL = { ++ .alpha2 = "PL", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_PM = { ++ .alpha2 = "PM", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_PR = { ++ .alpha2 = "PR", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2472, 40, 0, 30, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_PT = { ++ .alpha2 = "PT", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_PW = { ++ .alpha2 = "PW", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2472, 40, 0, 30, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 24, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_PY = { ++ .alpha2 = "PY", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 24, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_QA = { ++ .alpha2 = "QA", ++ .dfs_region = NL80211_DFS_JP, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 2 ++}; ++ ++static const struct ieee80211_regdomain regdom_RE = { ++ .alpha2 = "RE", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_RO = { ++ .alpha2 = "RO", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_RS = { ++ .alpha2 = "RS", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2400, 2483, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5150, 5350, 40, 0, 23, 0, ++ NL80211_RRF_NO_OUTDOOR | 0), ++ REG_RULE_EXT(5470, 5725, 20, 0, 30, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_RU = { ++ .alpha2 = "RU", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5650, 5730, 80, 0, 30, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_RW = { ++ .alpha2 = "RW", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_SA = { ++ .alpha2 = "SA", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_SE = { ++ .alpha2 = "SE", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_SG = { ++ .alpha2 = "SG", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_SI = { ++ .alpha2 = "SI", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_SK = { ++ .alpha2 = "SK", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_SN = { ++ .alpha2 = "SN", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_SR = { ++ .alpha2 = "SR", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_SV = { ++ .alpha2 = "SV", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 23, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_SY = { ++ .alpha2 = "SY", ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ }, ++ .n_reg_rules = 1 ++}; ++ ++static const struct ieee80211_regdomain regdom_TC = { ++ .alpha2 = "TC", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 24, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_TD = { ++ .alpha2 = "TD", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_TG = { ++ .alpha2 = "TG", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5250, 5330, 40, 0, 20, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5490, 5710, 40, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_TH = { ++ .alpha2 = "TH", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_TN = { ++ .alpha2 = "TN", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ }, ++ .n_reg_rules = 3 ++}; ++ ++static const struct ieee80211_regdomain regdom_TR = { ++ .alpha2 = "TR", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_TT = { ++ .alpha2 = "TT", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_TW = { ++ .alpha2 = "TW", ++ .dfs_region = NL80211_DFS_JP, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2472, 40, 0, 30, 0, 0), ++ REG_RULE_EXT(5270, 5330, 40, 0, 17, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5490, 5590, 80, 0, 30, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5650, 5710, 40, 0, 30, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_UA = { ++ .alpha2 = "UA", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2400, 2483, 40, 0, 20, 0, ++ NL80211_RRF_NO_OUTDOOR | 0), ++ REG_RULE_EXT(5150, 5350, 40, 0, 20, 0, ++ NL80211_RRF_NO_OUTDOOR | 0), ++ REG_RULE_EXT(5490, 5670, 80, 0, 20, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 20, 0, 0), ++ REG_RULE_EXT(57000, 66000, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_UG = { ++ .alpha2 = "UG", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 24, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_US = { ++ .alpha2 = "US", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ // 1...13 ++ REG_RULE_EXT(2402, 2472, 40, 0, 30, 0, 0), ++ // 36 40 44 48 ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ // 52 56 60 64 ++ REG_RULE_EXT(5250, 5330, 80, 0, 23, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ // 100 104 108 112 116 120 124 ++ REG_RULE_EXT(5490, 5650, 80, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ // 128 132 136 140 ++ REG_RULE_EXT(5650, 5710, 40, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ // 149 153 157 161 165 ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ REG_RULE_EXT(57240, 63720, 2160, 0, 40, 0, 0), ++ }, ++ .n_reg_rules = 7 ++}; ++ ++static const struct ieee80211_regdomain regdom_UY = { ++ .alpha2 = "UY", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_UZ = { ++ .alpha2 = "UZ", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ }, ++ .n_reg_rules = 3 ++}; ++ ++static const struct ieee80211_regdomain regdom_VC = { ++ .alpha2 = "VC", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_VE = { ++ .alpha2 = "VE", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 30, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 23, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 23, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_VI = { ++ .alpha2 = "VI", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2472, 40, 0, 30, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 24, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_VN = { ++ .alpha2 = "VN", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5490, 5730, 80, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_VU = { ++ .alpha2 = "VU", ++ .dfs_region = NL80211_DFS_FCC, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 17, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 24, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5730, 160, 0, 24, 0, ++ NL80211_RRF_DFS | 0), ++ REG_RULE_EXT(5735, 5835, 80, 0, 30, 0, 0), ++ }, ++ .n_reg_rules = 5 ++}; ++ ++static const struct ieee80211_regdomain regdom_WF = { ++ .alpha2 = "WF", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_YE = { ++ .alpha2 = "YE", ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ }, ++ .n_reg_rules = 1 ++}; ++ ++static const struct ieee80211_regdomain regdom_YT = { ++ .alpha2 = "YT", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_ZA = { ++ .alpha2 = "ZA", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5695, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ /*REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0),*/ ++ }, ++ .n_reg_rules = 4 ++}; ++ ++static const struct ieee80211_regdomain regdom_ZW = { ++ .alpha2 = "ZW", ++ .dfs_region = NL80211_DFS_ETSI, ++ .reg_rules = { ++ REG_RULE_EXT(2402, 2482, 40, 0, 20, 0, 0), ++ REG_RULE_EXT(5170, 5250, 80, 0, 20, 0, ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5250, 5330, 80, 0, 20, 0, ++ NL80211_RRF_DFS | ++ NL80211_RRF_AUTO_BW | 0), ++ REG_RULE_EXT(5490, 5710, 160, 0, 27, 0, ++ NL80211_RRF_DFS | 0), ++ }, ++ .n_reg_rules = 4 ++}; ++ ++const struct ieee80211_regdomain *reg_regdb[] = { ++ ®dom_00, ®dom_AD, ®dom_AE, ®dom_AF, ®dom_AI, ®dom_AL, ++ ®dom_AM, ®dom_AN, ®dom_AR, ®dom_AS, ®dom_AT, ®dom_AU, ++ ®dom_AW, ®dom_AZ, ®dom_BA, ®dom_BB, ®dom_BD, ®dom_BE, ++ ®dom_BF, ®dom_BG, ®dom_BH, ®dom_BL, ®dom_BM, ®dom_BN, ++ ®dom_BO, ®dom_BR, ®dom_BS, ®dom_BT, ®dom_BY, ®dom_BZ, ++ ®dom_CA, ®dom_CF, ®dom_CH, ®dom_CI, ®dom_CL, ®dom_CN, ++ ®dom_CO, ®dom_CR, ®dom_CX, ®dom_CY, ®dom_CZ, ®dom_DE, ++ ®dom_DK, ®dom_DM, ®dom_DO, ®dom_DZ, ®dom_EC, ®dom_EE, ++ ®dom_EG, ®dom_ES, ®dom_ET, ®dom_FI, ®dom_FM, ®dom_FR, ++ ®dom_GB, ®dom_GD, ®dom_GE, ®dom_GF, ®dom_GH, ®dom_GL, ++ ®dom_GP, ®dom_GR, ®dom_GT, ®dom_GU, ®dom_GY, ®dom_HK, ++ ®dom_HN, ®dom_HR, ®dom_HT, ®dom_HU, ®dom_ID, ®dom_IE, ++ ®dom_IL, ®dom_IN, ®dom_IR, ®dom_IS, ®dom_IT, ®dom_JM, ++ ®dom_JO, ®dom_JP, ®dom_KE, ®dom_KH, ®dom_KN, ®dom_KP, ++ ®dom_KR, ®dom_KW, ®dom_KY, ®dom_KZ, ®dom_LB, ®dom_LC, ++ ®dom_LI, ®dom_LK, ®dom_LS, ®dom_LT, ®dom_LU, ®dom_LV, ++ ®dom_MA, ®dom_MC, ®dom_MD, ®dom_ME, ®dom_MF, ®dom_MH, ++ ®dom_MK, ®dom_MN, ®dom_MO, ®dom_MP, ®dom_MQ, ®dom_MR, ++ ®dom_MT, ®dom_MU, ®dom_MW, ®dom_MX, ®dom_MY, ®dom_NG, ++ ®dom_NI, ®dom_NL, ®dom_NO, ®dom_NP, ®dom_NZ, ®dom_OM, ++ ®dom_PA, ®dom_PE, ®dom_PF, ®dom_PG, ®dom_PH, ®dom_PK, ++ ®dom_PL, ®dom_PM, ®dom_PR, ®dom_PT, ®dom_PW, ®dom_PY, ++ ®dom_QA, ®dom_RE, ®dom_RO, ®dom_RS, ®dom_RU, ®dom_RW, ++ ®dom_SA, ®dom_SE, ®dom_SG, ®dom_SI, ®dom_SK, ®dom_SN, ++ ®dom_SR, ®dom_SV, ®dom_SY, ®dom_TC, ®dom_TD, ®dom_TG, ++ ®dom_TH, ®dom_TN, ®dom_TR, ®dom_TT, ®dom_TW, ®dom_UA, ++ ®dom_UG, ®dom_US, ®dom_UY, ®dom_UZ, ®dom_VC, ®dom_VE, ++ ®dom_VI, ®dom_VN, ®dom_VU, ®dom_WF, ®dom_YE, ®dom_YT, ++ ®dom_ZA, ®dom_ZW, NULL, ++}; ++ ++int reg_regdb_size = ARRAY_SIZE(reg_regdb); +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_bfmer.c b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_bfmer.c +new file mode 100755 +index 000000000..5e8a4af9b +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_bfmer.c +@@ -0,0 +1,104 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_bfmer.c ++ * ++ * @brief VHT Beamformer function definitions ++ * ++ * Copyright (C) RivieraWaves 2016-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++/** ++ * INCLUDE FILES ++ ****************************************************************************** ++ */ ++ ++#include ++#include "rwnx_bfmer.h" ++ ++/** ++ * FUNCTION DEFINITIONS ++ ****************************************************************************** ++ */ ++ ++int rwnx_bfmer_report_add(struct rwnx_hw *rwnx_hw, struct rwnx_sta *rwnx_sta, ++ unsigned int length) ++{ ++ gfp_t flags; ++ struct rwnx_bfmer_report *bfm_report; ++ ++ if (in_softirq()) ++ flags = GFP_ATOMIC; ++ else ++ flags = GFP_KERNEL; ++ ++ /* Allocate a structure that will contain the beamforming report */ ++ bfm_report = kmalloc(sizeof(*bfm_report) + length, flags); ++ ++ /* Check report allocation */ ++ if (!bfm_report) { ++ /* Do not use beamforming */ ++ return -1; ++ } ++ ++ /* Store report length */ ++ bfm_report->length = length; ++ ++ /* ++ * Need to provide a Virtual Address to the MAC so that it can ++ * upload the received Beamforming Report in driver memory ++ */ ++ bfm_report->dma_addr = dma_map_single( ++ rwnx_hw->dev, &bfm_report->report[0], length, DMA_FROM_DEVICE); ++ ++ /* Check DMA mapping result */ ++ if (dma_mapping_error(rwnx_hw->dev, bfm_report->dma_addr)) { ++ /* Free allocated report */ ++ kfree(bfm_report); ++ /* And leave */ ++ return -1; ++ } ++ ++ /* Store report structure */ ++ rwnx_sta->bfm_report = bfm_report; ++ ++ return 0; ++} ++ ++void rwnx_bfmer_report_del(struct rwnx_hw *rwnx_hw, struct rwnx_sta *rwnx_sta) ++{ ++ /* Verify if a report has been allocated */ ++ if (rwnx_sta->bfm_report) { ++ struct rwnx_bfmer_report *bfm_report = rwnx_sta->bfm_report; ++ ++ /* Unmap DMA region */ ++ dma_unmap_single(rwnx_hw->dev, bfm_report->dma_addr, ++ bfm_report->length, DMA_BIDIRECTIONAL); ++ ++ /* Free allocated report structure and clean the pointer */ ++ kfree(bfm_report); ++ rwnx_sta->bfm_report = NULL; ++ } ++} ++ ++#ifdef CONFIG_RWNX_FULLMAC ++u8 rwnx_bfmer_get_rx_nss(const struct ieee80211_vht_cap *vht_capa) ++{ ++ int i; ++ u8 rx_nss = 0; ++ u16 rx_mcs_map = le16_to_cpu(vht_capa->supp_mcs.rx_mcs_map); ++ ++ for (i = 7; i >= 0; i--) { ++ u8 mcs = (rx_mcs_map >> (2 * i)) & 3; ++ ++ if (mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED) { ++ rx_nss = i + 1; ++ break; ++ } ++ } ++ ++ return rx_nss; ++} ++#endif /* CONFIG_RWNX_FULLMAC */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_bfmer.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_bfmer.h +new file mode 100755 +index 000000000..8191946ce +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_bfmer.h +@@ -0,0 +1,100 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_bfmer.h ++ * ++ * @brief VHT Beamformer function declarations ++ * ++ * Copyright (C) RivieraWaves 2016-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++#ifndef _RWNX_BFMER_H_ ++#define _RWNX_BFMER_H_ ++ ++/** ++ * INCLUDE FILES ++ ****************************************************************************** ++ */ ++ ++#include "rwnx_defs.h" ++ ++/** ++ * DEFINES ++ ****************************************************************************** ++ */ ++ ++/// Maximal supported report length (in bytes) ++#define RWNX_BFMER_REPORT_MAX_LEN 2048 ++ ++/// Size of the allocated report space (twice the maximum report length) ++#define RWNX_BFMER_REPORT_SPACE_SIZE (RWNX_BFMER_REPORT_MAX_LEN * 2) ++ ++/** ++ * TYPE DEFINITIONS ++ ****************************************************************************** ++ */ ++ ++/* ++ * Structure used to store a beamforming report. ++ */ ++struct rwnx_bfmer_report { ++ dma_addr_t dma_addr; /* Virtual address provided to MAC for ++ DMA transfer of the Beamforming Report */ ++ unsigned int length; /* Report Length */ ++ u8 report[1]; /* Report to be used for VHT TX Beamforming */ ++}; ++ ++/** ++ * FUNCTION DECLARATIONS ++ ****************************************************************************** ++ */ ++ ++/** ++ ****************************************************************************** ++ * @brief Allocate memory aiming to contains the Beamforming Report received ++ * from a Beamformee capable capable. ++ * The providing length shall be large enough to contain the VHT Compressed ++ * Beaforming Report and the MU Exclusive part. ++ * It also perform a DMA Mapping providing an address to be provided to the HW ++ * responsible for the DMA transfer of the report. ++ * If successful a struct rwnx_bfmer_report object is allocated, it's address ++ * is stored in rwnx_sta->bfm_report. ++ * ++ * @param[in] rwnx_hw PHY Information ++ * @param[in] rwnx_sta Peer STA Information ++ * @param[in] length Memory size to be allocated ++ * ++ * @return 0 if operation is successful, else -1. ++ ****************************************************************************** ++ */ ++int rwnx_bfmer_report_add(struct rwnx_hw *rwnx_hw, struct rwnx_sta *rwnx_sta, ++ unsigned int length); ++ ++/** ++ ****************************************************************************** ++ * @brief Free a previously allocated memory intended to be used for ++ * Beamforming Reports. ++ * ++ * @param[in] rwnx_hw PHY Information ++ * @param[in] rwnx_sta Peer STA Information ++ * ++ ****************************************************************************** ++ */ ++void rwnx_bfmer_report_del(struct rwnx_hw *rwnx_hw, struct rwnx_sta *rwnx_sta); ++ ++#ifdef CONFIG_RWNX_FULLMAC ++/** ++ ****************************************************************************** ++ * @brief Parse a Rx VHT-MCS map in order to deduce the maximum number of ++ * Spatial Streams supported by a beamformee. ++ * ++ * @param[in] vht_capa Received VHT Capability field. ++ * ++ ****************************************************************************** ++ */ ++u8 rwnx_bfmer_get_rx_nss(const struct ieee80211_vht_cap *vht_capa); ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++#endif /* _RWNX_BFMER_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_cfgfile.c b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_cfgfile.c +new file mode 100755 +index 000000000..492c798bc +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_cfgfile.c +@@ -0,0 +1,265 @@ ++/** ++ **************************************************************************************** ++ * ++ * @file rwnx_configparse.c ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ **************************************************************************************** ++ */ ++#include ++#include ++ ++#include "rwnx_defs.h" ++#include "rwnx_cfgfile.h" ++ ++/** ++ * ++ */ ++static const char *rwnx_find_tag(const u8 *file_data, unsigned int file_size, ++ const char *tag_name, unsigned int tag_len) ++{ ++ unsigned int curr, line_start = 0, line_size; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Walk through all the lines of the configuration file */ ++ while (line_start < file_size) { ++ /* Search the end of the current line (or the end of the file) */ ++ for (curr = line_start; curr < file_size; curr++) ++ if (file_data[curr] == '\n') ++ break; ++ ++ /* Compute the line size */ ++ line_size = curr - line_start; ++ ++ /* Check if this line contains the expected tag */ ++ if ((line_size == (strlen(tag_name) + tag_len)) && ++ (!strncmp(&file_data[line_start], tag_name, ++ strlen(tag_name)))) ++ return &file_data[line_start + strlen(tag_name)]; ++ ++ /* Move to next line */ ++ line_start = curr + 1; ++ } ++ ++ /* Tag not found */ ++ return NULL; ++} ++ ++/** ++ * Parse the Config file used at init time ++ */ ++int rwnx_parse_configfile(struct rwnx_hw *rwnx_hw, const char *filename, ++ struct rwnx_conf_file *config) ++{ ++ const struct firmware *config_fw; ++ u8 dflt_mac[ETH_ALEN] = { 0, 111, 111, 111, 111, 0 }; ++ int ret; ++ const u8 *tag_ptr; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ ret = request_firmware(&config_fw, filename, rwnx_hw->dev); ++ if (ret) { ++ printk(KERN_CRIT "%s: Failed to get %s (%d)\n", __func__, ++ filename, ret); ++ return ret; ++ } ++ ++ /* Get MAC Address */ ++ tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size, ++ "MAC_ADDR=", strlen("00:00:00:00:00:00")); ++ if (tag_ptr != NULL) { ++ u8 *addr = config->mac_addr; ++ if (sscanf(tag_ptr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", addr + 0, ++ addr + 1, addr + 2, addr + 3, addr + 4, ++ addr + 5) != ETH_ALEN) ++ memcpy(config->mac_addr, dflt_mac, ETH_ALEN); ++ } else ++ memcpy(config->mac_addr, dflt_mac, ETH_ALEN); ++ ++ RWNX_DBG("MAC Address is:\n%pM\n", config->mac_addr); ++ ++ /* Release the configuration file */ ++ release_firmware(config_fw); ++ ++ return 0; ++} ++ ++/** ++ * Parse the Config file used at init time ++ */ ++int rwnx_parse_phy_configfile(struct rwnx_hw *rwnx_hw, const char *filename, ++ struct rwnx_phy_conf_file *config, int path) ++{ ++ const struct firmware *config_fw; ++ int ret; ++ const u8 *tag_ptr; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ ret = request_firmware(&config_fw, filename, rwnx_hw->dev); ++ if (ret) { ++ printk(KERN_CRIT "%s: Failed to get %s (%d)\n", __func__, ++ filename, ret); ++ return ret; ++ } ++ ++ /* Get Trident path mapping */ ++ tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size, ++ "TRD_PATH_MAPPING=", strlen("00")); ++ if (tag_ptr != NULL) { ++ u8 val; ++ if (sscanf(tag_ptr, "%hhx", &val) == 1) ++ config->trd.path_mapping = val; ++ else ++ config->trd.path_mapping = path; ++ } else ++ config->trd.path_mapping = path; ++ ++ RWNX_DBG("Trident path mapping is: %d\n", config->trd.path_mapping); ++ ++ /* Get DC offset compensation */ ++ tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size, ++ "TX_DC_OFF_COMP=", strlen("00000000")); ++ if (tag_ptr != NULL) { ++ if (sscanf(tag_ptr, "%08x", &config->trd.tx_dc_off_comp) != 1) ++ config->trd.tx_dc_off_comp = 0; ++ } else ++ config->trd.tx_dc_off_comp = 0; ++ ++ RWNX_DBG("TX DC offset compensation is: %08X\n", ++ config->trd.tx_dc_off_comp); ++ ++ /* Get Karst TX IQ compensation value for path0 on 2.4GHz */ ++ tag_ptr = rwnx_find_tag( ++ config_fw->data, config_fw->size, ++ "KARST_TX_IQ_COMP_2_4G_PATH_0=", strlen("00000000")); ++ if (tag_ptr != NULL) { ++ if (sscanf(tag_ptr, "%08x", ++ &config->karst.tx_iq_comp_2_4G[0]) != 1) ++ config->karst.tx_iq_comp_2_4G[0] = 0x01000000; ++ } else ++ config->karst.tx_iq_comp_2_4G[0] = 0x01000000; ++ ++ RWNX_DBG("Karst TX IQ compensation for path 0 on 2.4GHz is: %08X\n", ++ config->karst.tx_iq_comp_2_4G[0]); ++ ++ /* Get Karst TX IQ compensation value for path1 on 2.4GHz */ ++ tag_ptr = rwnx_find_tag( ++ config_fw->data, config_fw->size, ++ "KARST_TX_IQ_COMP_2_4G_PATH_1=", strlen("00000000")); ++ if (tag_ptr != NULL) { ++ if (sscanf(tag_ptr, "%08x", ++ &config->karst.tx_iq_comp_2_4G[1]) != 1) ++ config->karst.tx_iq_comp_2_4G[1] = 0x01000000; ++ } else ++ config->karst.tx_iq_comp_2_4G[1] = 0x01000000; ++ ++ RWNX_DBG("Karst TX IQ compensation for path 1 on 2.4GHz is: %08X\n", ++ config->karst.tx_iq_comp_2_4G[1]); ++ ++ /* Get Karst RX IQ compensation value for path0 on 2.4GHz */ ++ tag_ptr = rwnx_find_tag( ++ config_fw->data, config_fw->size, ++ "KARST_RX_IQ_COMP_2_4G_PATH_0=", strlen("00000000")); ++ if (tag_ptr != NULL) { ++ if (sscanf(tag_ptr, "%08x", ++ &config->karst.rx_iq_comp_2_4G[0]) != 1) ++ config->karst.rx_iq_comp_2_4G[0] = 0x01000000; ++ } else ++ config->karst.rx_iq_comp_2_4G[0] = 0x01000000; ++ ++ RWNX_DBG("Karst RX IQ compensation for path 0 on 2.4GHz is: %08X\n", ++ config->karst.rx_iq_comp_2_4G[0]); ++ ++ /* Get Karst RX IQ compensation value for path1 on 2.4GHz */ ++ tag_ptr = rwnx_find_tag( ++ config_fw->data, config_fw->size, ++ "KARST_RX_IQ_COMP_2_4G_PATH_1=", strlen("00000000")); ++ if (tag_ptr != NULL) { ++ if (sscanf(tag_ptr, "%08x", ++ &config->karst.rx_iq_comp_2_4G[1]) != 1) ++ config->karst.rx_iq_comp_2_4G[1] = 0x01000000; ++ } else ++ config->karst.rx_iq_comp_2_4G[1] = 0x01000000; ++ ++ RWNX_DBG("Karst RX IQ compensation for path 1 on 2.4GHz is: %08X\n", ++ config->karst.rx_iq_comp_2_4G[1]); ++ ++ /* Get Karst TX IQ compensation value for path0 on 5GHz */ ++ tag_ptr = rwnx_find_tag( ++ config_fw->data, config_fw->size, ++ "KARST_TX_IQ_COMP_5G_PATH_0=", strlen("00000000")); ++ if (tag_ptr != NULL) { ++ if (sscanf(tag_ptr, "%08x", &config->karst.tx_iq_comp_5G[0]) != ++ 1) ++ config->karst.tx_iq_comp_5G[0] = 0x01000000; ++ } else ++ config->karst.tx_iq_comp_5G[0] = 0x01000000; ++ ++ RWNX_DBG("Karst TX IQ compensation for path 0 on 5GHz is: %08X\n", ++ config->karst.tx_iq_comp_5G[0]); ++ ++ /* Get Karst TX IQ compensation value for path1 on 5GHz */ ++ tag_ptr = rwnx_find_tag( ++ config_fw->data, config_fw->size, ++ "KARST_TX_IQ_COMP_5G_PATH_1=", strlen("00000000")); ++ if (tag_ptr != NULL) { ++ if (sscanf(tag_ptr, "%08x", &config->karst.tx_iq_comp_5G[1]) != ++ 1) ++ config->karst.tx_iq_comp_5G[1] = 0x01000000; ++ } else ++ config->karst.tx_iq_comp_5G[1] = 0x01000000; ++ ++ RWNX_DBG("Karst TX IQ compensation for path 1 on 5GHz is: %08X\n", ++ config->karst.tx_iq_comp_5G[1]); ++ ++ /* Get Karst RX IQ compensation value for path0 on 5GHz */ ++ tag_ptr = rwnx_find_tag( ++ config_fw->data, config_fw->size, ++ "KARST_RX_IQ_COMP_5G_PATH_0=", strlen("00000000")); ++ if (tag_ptr != NULL) { ++ if (sscanf(tag_ptr, "%08x", &config->karst.rx_iq_comp_5G[0]) != ++ 1) ++ config->karst.rx_iq_comp_5G[0] = 0x01000000; ++ } else ++ config->karst.rx_iq_comp_5G[0] = 0x01000000; ++ ++ RWNX_DBG("Karst RX IQ compensation for path 0 on 5GHz is: %08X\n", ++ config->karst.rx_iq_comp_5G[0]); ++ ++ /* Get Karst RX IQ compensation value for path1 on 5GHz */ ++ tag_ptr = rwnx_find_tag( ++ config_fw->data, config_fw->size, ++ "KARST_RX_IQ_COMP_5G_PATH_1=", strlen("00000000")); ++ if (tag_ptr != NULL) { ++ if (sscanf(tag_ptr, "%08x", &config->karst.rx_iq_comp_5G[1]) != ++ 1) ++ config->karst.rx_iq_comp_5G[1] = 0x01000000; ++ } else ++ config->karst.rx_iq_comp_5G[1] = 0x01000000; ++ ++ RWNX_DBG("Karst RX IQ compensation for path 1 on 5GHz is: %08X\n", ++ config->karst.rx_iq_comp_5G[1]); ++ ++ /* Get Karst default path */ ++ tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size, ++ "KARST_DEFAULT_PATH=", strlen("00")); ++ if (tag_ptr != NULL) { ++ u8 val; ++ if (sscanf(tag_ptr, "%hhx", &val) == 1) ++ config->karst.path_used = val; ++ else ++ config->karst.path_used = path; ++ } else ++ config->karst.path_used = path; ++ ++ RWNX_DBG("Karst default path is: %d\n", config->karst.path_used); ++ ++ /* Release the configuration file */ ++ release_firmware(config_fw); ++ ++ return 0; ++} +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_cfgfile.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_cfgfile.h +new file mode 100755 +index 000000000..219b21f5e +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_cfgfile.h +@@ -0,0 +1,35 @@ ++/** ++ **************************************************************************************** ++ * ++ * @file rwnx_cfgfile.h ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ **************************************************************************************** ++ */ ++ ++#ifndef _RWNX_CFGFILE_H_ ++#define _RWNX_CFGFILE_H_ ++ ++/* ++ * Structure used to retrieve information from the Config file used at Initialization time ++ */ ++struct rwnx_conf_file { ++ u8 mac_addr[ETH_ALEN]; ++}; ++ ++/* ++ * Structure used to retrieve information from the PHY Config file used at Initialization time ++ */ ++struct rwnx_phy_conf_file { ++ struct phy_trd_cfg_tag trd; ++ struct phy_karst_cfg_tag karst; ++}; ++ ++int rwnx_parse_configfile(struct rwnx_hw *rwnx_hw, const char *filename, ++ struct rwnx_conf_file *config); ++ ++int rwnx_parse_phy_configfile(struct rwnx_hw *rwnx_hw, const char *filename, ++ struct rwnx_phy_conf_file *config, int path); ++ ++#endif /* _RWNX_CFGFILE_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_cmds.c b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_cmds.c +new file mode 100755 +index 000000000..b9a66c416 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_cmds.c +@@ -0,0 +1,627 @@ ++/** ++ ****************************************************************************** ++ * ++ * rwnx_cmds.c ++ * ++ * Handles queueing (push to IPC, ack/cfm from IPC) of commands issued to ++ * LMAC FW ++ * ++ * Copyright (C) RivieraWaves 2014-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++#include ++ ++#include "rwnx_cmds.h" ++#include "rwnx_defs.h" ++#include "rwnx_strs.h" ++//#define CREATE_TRACE_POINTS ++#include "rwnx_events.h" ++#include "aicwf_txrxif.h" ++#ifdef AICWF_SDIO_SUPPORT ++#include "aicwf_sdio.h" ++#else ++#include "aicwf_usb.h" ++#endif ++/** ++ * ++ */ ++extern int aicwf_sdio_writeb(struct aic_sdio_dev *sdiodev, uint regaddr, ++ u8 val); ++ ++void rwnx_cmd_free(struct rwnx_cmd *cmd); ++ ++static void cmd_dump(const struct rwnx_cmd *cmd) ++{ ++ printk(KERN_CRIT ++ "tkn[%d] flags:%04x result:%3d cmd:%4d-%-24s - reqcfm(%4d-%-s)\n", ++ cmd->tkn, cmd->flags, cmd->result, cmd->id, RWNX_ID2STR(cmd->id), ++ cmd->reqid, ++ cmd->reqid != (lmac_msg_id_t)-1 ? RWNX_ID2STR(cmd->reqid) : ++ "none"); ++} ++ ++/** ++ * ++ */ ++static void cmd_complete(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd) ++{ ++ //RWNX_DBG(RWNX_FN_ENTRY_STR); ++ lockdep_assert_held(&cmd_mgr->lock); ++ ++ //list_del(&cmd->list); ++ //cmd_mgr->queue_sz--; ++ ++ cmd->flags |= RWNX_CMD_FLAG_DONE; ++ if (cmd->flags & RWNX_CMD_FLAG_NONBLOCK) { ++ rwnx_cmd_free(cmd); //kfree(cmd); ++ } else { ++ if (RWNX_CMD_WAIT_COMPLETE(cmd->flags)) { ++ cmd->result = 0; ++ complete(&cmd->complete); ++ } ++ } ++} ++ ++int cmd_mgr_queue_force_defer(struct rwnx_cmd_mgr *cmd_mgr, ++ struct rwnx_cmd *cmd) ++{ ++ 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) { ++ printk_ratelimited(KERN_CRIT "cmd queue crashed\n"); ++ cmd->result = -EPIPE; ++ spin_unlock_bh(&cmd_mgr->lock); ++ return -EPIPE; ++ } ++ ++#ifndef CONFIG_RWNX_FHOST ++ if (!list_empty(&cmd_mgr->cmds)) { ++ if (cmd_mgr->queue_sz == cmd_mgr->max_queue_sz) { ++ printk(KERN_CRIT "Too many cmds (%d) already queued\n", ++ cmd_mgr->max_queue_sz); ++ cmd->result = -ENOMEM; ++ spin_unlock_bh(&cmd_mgr->lock); ++ return -ENOMEM; ++ } ++ } ++#endif ++ ++ cmd->flags |= RWNX_CMD_FLAG_WAIT_PUSH; ++ defer_push = true; ++ ++ if (cmd->flags & RWNX_CMD_FLAG_REQ_CFM) ++ cmd->flags |= RWNX_CMD_FLAG_WAIT_CFM; ++ ++ cmd->tkn = cmd_mgr->next_tkn++; ++ cmd->result = -EINTR; ++ ++ if (!(cmd->flags & RWNX_CMD_FLAG_NONBLOCK)) ++ init_completion(&cmd->complete); ++ ++ list_add_tail(&cmd->list, &cmd_mgr->cmds); ++ cmd_mgr->queue_sz++; ++ spin_unlock_bh(&cmd_mgr->lock); ++ ++ WAKE_CMD_WORK(cmd_mgr); ++ return 0; ++} ++ ++#if 1 ++static void aic8800_start_system_reset_flow(struct aic_sdio_dev *aic) ++{ ++ int ret = 0; ++ char *event_string = "DHDISDOWN=1"; ++ char *envp[] = { event_string, NULL }; ++ printk(KERN_ERR "wlan error reset flow.\n"); ++ printk(KERN_ERR "send event.\n"); ++ ret = kobject_uevent_env(&aic->dev->kobj, KOBJ_CHANGE, envp); ++ if (!ret) ++ printk(KERN_ERR "wlan error event send.\n"); ++} ++#endif ++ ++static int cmd_mgr_queue(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd) ++{ ++#ifdef AICWF_SDIO_SUPPORT ++ int ret; ++ struct aic_sdio_dev *sdiodev = ++ container_of(cmd_mgr, struct aic_sdio_dev, cmd_mgr); ++#endif ++#ifdef AICWF_USB_SUPPORT ++ struct aic_usb_dev *usbdev = ++ container_of(cmd_mgr, struct aic_usb_dev, cmd_mgr); ++#endif ++ bool defer_push = false; ++ u8_l empty = 0; ++ ++ //RWNX_DBG(RWNX_FN_ENTRY_STR); ++#ifdef CREATE_TRACE_POINTS ++ trace_msg_send(cmd->id); ++#endif ++ if (cmd->e2a_msg != NULL) { ++ do { ++ if (cmd_mgr->state == RWNX_CMD_MGR_STATE_CRASHED) ++ break; ++ spin_lock_bh(&cmd_mgr->lock); ++ empty = list_empty(&cmd_mgr->cmds); ++ if (!empty) { ++ spin_unlock_bh(&cmd_mgr->lock); ++ 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 ++ } else { ++ spin_lock_bh(&cmd_mgr->lock); ++ } ++ ++ if (cmd_mgr->state == RWNX_CMD_MGR_STATE_CRASHED) { ++ printk_ratelimited(KERN_CRIT "cmd queue crashed\n"); ++ cmd->result = -EPIPE; ++ spin_unlock_bh(&cmd_mgr->lock); ++ return -EPIPE; ++ } ++ ++#ifndef CONFIG_RWNX_FHOST ++ if (!list_empty(&cmd_mgr->cmds)) { ++ struct rwnx_cmd *last; ++ ++ if (cmd_mgr->queue_sz == cmd_mgr->max_queue_sz) { ++ printk(KERN_CRIT "Too many cmds (%d) already queued\n", ++ cmd_mgr->max_queue_sz); ++ cmd->result = -ENOMEM; ++ spin_unlock_bh(&cmd_mgr->lock); ++ return -ENOMEM; ++ } ++ last = list_entry(cmd_mgr->cmds.prev, struct rwnx_cmd, list); ++ if (last->flags & ++ (RWNX_CMD_FLAG_WAIT_ACK | RWNX_CMD_FLAG_WAIT_PUSH | ++ RWNX_CMD_FLAG_WAIT_CFM)) { ++#if 0 // queue even NONBLOCK command. ++ if (cmd->flags & RWNX_CMD_FLAG_NONBLOCK) { ++ printk(KERN_CRIT"cmd queue busy\n"); ++ cmd->result = -EBUSY; ++ spin_unlock_bh(&cmd_mgr->lock); ++ return -EBUSY; ++ } ++#endif ++ cmd->flags |= RWNX_CMD_FLAG_WAIT_PUSH; ++ defer_push = true; ++ } ++ } ++#endif ++ ++#if 0 ++ cmd->flags |= RWNX_CMD_FLAG_WAIT_ACK; ++#endif ++ if (cmd->flags & RWNX_CMD_FLAG_REQ_CFM) ++ cmd->flags |= RWNX_CMD_FLAG_WAIT_CFM; ++ ++ cmd->tkn = cmd_mgr->next_tkn++; ++ cmd->result = -EINTR; ++ ++ if (!(cmd->flags & RWNX_CMD_FLAG_NONBLOCK)) ++ init_completion(&cmd->complete); ++ ++ list_add_tail(&cmd->list, &cmd_mgr->cmds); ++ cmd_mgr->queue_sz++; ++ ++ if (cmd->a2e_msg->id == ME_TRAFFIC_IND_REQ ++#ifdef AICWF_ARP_OFFLOAD ++ || cmd->a2e_msg->id == MM_SET_ARPOFFLOAD_REQ ++#endif ++ ) { ++ defer_push = true; ++ cmd->flags |= RWNX_CMD_FLAG_WAIT_PUSH; ++ //printk("defer push: tkn=%d\r\n", cmd->tkn); ++ } ++ ++ spin_unlock_bh(&cmd_mgr->lock); ++ if (!defer_push) { ++//printk("queue:id=%x, param_len=%u\n",cmd->a2e_msg->id, cmd->a2e_msg->param_len); ++#ifdef AICWF_SDIO_SUPPORT ++ aicwf_set_cmd_tx((void *)(sdiodev), cmd->a2e_msg, ++ sizeof(struct lmac_msg) + ++ cmd->a2e_msg->param_len); ++#else ++ aicwf_set_cmd_tx((void *)(usbdev), cmd->a2e_msg, ++ sizeof(struct lmac_msg) + ++ cmd->a2e_msg->param_len); ++#endif ++ //rwnx_ipc_msg_push(rwnx_hw, cmd, RWNX_CMD_A2EMSG_LEN(cmd->a2e_msg)); ++ ++ kfree(cmd->a2e_msg); ++ } else { ++ if (cmd_mgr->queue_sz <= 1) { ++ WAKE_CMD_WORK(cmd_mgr); ++ } ++ return 0; ++ } ++ ++ if (!(cmd->flags & RWNX_CMD_FLAG_NONBLOCK)) { ++#ifdef CONFIG_RWNX_FHOST ++ if (wait_for_completion_killable(&cmd->complete)) { ++ cmd->result = -EINTR; ++ spin_lock_bh(&cmd_mgr->lock); ++ cmd_complete(cmd_mgr, cmd); ++ spin_unlock_bh(&cmd_mgr->lock); ++ /* TODO: kill the cmd at fw level */ ++ } ++#else ++ /* flare-edge: queue_sz must never scale this to zero. A zero ++ * timeout makes wait_for_completion_timeout() return ++ * immediately, so the "timeout" path runs without ever ++ * waiting -- measured as ~2000 "cmd timed-out" per second ++ * (668349 in 319s), which saturates the console and takes the ++ * whole system down with it. Clamp to at least one. */ ++ unsigned long tout = msecs_to_jiffies( ++ RWNX_80211_CMD_TIMEOUT_MS * ++ max_t(u32, cmd_mgr->queue_sz, 1)); ++ if (!wait_for_completion_timeout(&cmd->complete, tout)) { ++ printk_ratelimited(KERN_CRIT "cmd timed-out\n"); ++#ifdef AICWF_SDIO_SUPPORT ++ ret = aicwf_sdio_writeb( ++ sdiodev, sdiodev->sdio_reg.wakeup_reg, 2); ++ if (ret < 0) { ++ sdio_err("reg:%d write failed!\n", ++ sdiodev->sdio_reg.wakeup_reg); ++ } ++#endif ++ ++ aic8800_start_system_reset_flow(sdiodev); ++ ++ cmd_dump(cmd); ++ spin_lock_bh(&cmd_mgr->lock); ++ cmd_mgr->state = RWNX_CMD_MGR_STATE_CRASHED; ++ if (!(cmd->flags & RWNX_CMD_FLAG_DONE)) { ++ cmd->result = -ETIMEDOUT; ++ cmd_complete(cmd_mgr, cmd); ++ } ++ spin_unlock_bh(&cmd_mgr->lock); ++ } else { ++ spin_lock_bh(&cmd_mgr->lock); ++ list_del(&cmd->list); ++ cmd_mgr->queue_sz--; ++ spin_unlock_bh(&cmd_mgr->lock); ++ rwnx_cmd_free(cmd); //kfree(cmd); ++ if (!list_empty(&cmd_mgr->cmds)) ++ WAKE_CMD_WORK(cmd_mgr); ++ } ++#endif ++ } else { ++ cmd->result = 0; ++ } ++ ++ return 0; ++} ++ ++/** ++ * ++ */ ++static int cmd_mgr_llind(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd) ++{ ++ struct rwnx_cmd *cur, *acked = NULL, *next = NULL; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ spin_lock_bh(&cmd_mgr->lock); ++ list_for_each_entry (cur, &cmd_mgr->cmds, list) { ++ if (!acked) { ++ if (cur->tkn == cmd->tkn) { ++ if (WARN_ON_ONCE(cur != cmd)) { ++ cmd_dump(cmd); ++ } ++ acked = cur; ++ continue; ++ } ++ } ++ if (cur->flags & RWNX_CMD_FLAG_WAIT_PUSH) { ++ next = cur; ++ break; ++ } ++ } ++ if (!acked) { ++ printk(KERN_CRIT "Error: acked cmd not found\n"); ++ } else { ++ cmd->flags &= ~RWNX_CMD_FLAG_WAIT_ACK; ++ if (RWNX_CMD_WAIT_COMPLETE(cmd->flags)) ++ cmd_complete(cmd_mgr, cmd); ++ } ++ ++ if (next) { ++#if 0 //there is no ack ++ struct rwnx_hw *rwnx_hw = container_of(cmd_mgr, struct rwnx_hw, cmd_mgr); ++ next->flags &= ~RWNX_CMD_FLAG_WAIT_PUSH; ++ rwnx_ipc_msg_push(rwnx_hw, next, RWNX_CMD_A2EMSG_LEN(next->a2e_msg)); ++ kfree(next->a2e_msg); ++#endif ++ } ++ spin_unlock(&cmd_mgr->lock); ++ ++ return 0; ++} ++ ++void cmd_mgr_task_process(struct work_struct *work) ++{ ++ struct rwnx_cmd_mgr *cmd_mgr = ++ container_of(work, struct rwnx_cmd_mgr, cmdWork); ++ struct rwnx_cmd *cur, *next = NULL; ++ unsigned long tout; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ while (1) { ++ next = NULL; ++ spin_lock_bh(&cmd_mgr->lock); ++ ++ list_for_each_entry (cur, &cmd_mgr->cmds, list) { ++ if (cur->flags & ++ RWNX_CMD_FLAG_WAIT_PUSH) { //just judge the first ++ next = cur; ++ } ++ break; ++ } ++ spin_unlock_bh(&cmd_mgr->lock); ++ ++ if (next == NULL) ++ break; ++ ++ if (next) { ++#ifdef AICWF_SDIO_SUPPORT ++ struct aic_sdio_dev *sdiodev = container_of( ++ cmd_mgr, struct aic_sdio_dev, cmd_mgr); ++#endif ++#ifdef AICWF_USB_SUPPORT ++ struct aic_usb_dev *usbdev = container_of( ++ cmd_mgr, struct aic_usb_dev, cmd_mgr); ++#endif ++ next->flags &= ~RWNX_CMD_FLAG_WAIT_PUSH; ++ ++ //printk("cmd_process, cmd->id=%d, tkn=%d\r\n",next->reqid, next->tkn); ++ //rwnx_ipc_msg_push(rwnx_hw, next, RWNX_CMD_A2EMSG_LEN(next->a2e_msg)); ++#ifdef AICWF_SDIO_SUPPORT ++ aicwf_set_cmd_tx((void *)(sdiodev), next->a2e_msg, ++ sizeof(struct lmac_msg) + ++ next->a2e_msg->param_len); ++#else ++ aicwf_set_cmd_tx((void *)(usbdev), next->a2e_msg, ++ sizeof(struct lmac_msg) + ++ next->a2e_msg->param_len); ++#endif ++ kfree(next->a2e_msg); ++ ++ /* flare-edge: see above -- never a zero timeout */ ++ tout = msecs_to_jiffies(RWNX_80211_CMD_TIMEOUT_MS * ++ max_t(u32, cmd_mgr->queue_sz, 1)); ++ if (!wait_for_completion_timeout(&next->complete, ++ tout)) { ++ printk_ratelimited(KERN_CRIT "cmd timed-out\n"); ++#ifdef AICWF_SDIO_SUPPORT ++ if (aicwf_sdio_writeb( ++ sdiodev, ++ sdiodev->sdio_reg.wakeup_reg, ++ 2) < 0) { ++ sdio_err("reg:%d write failed!\n", ++ sdiodev->sdio_reg.wakeup_reg); ++ } ++#endif ++ aic8800_start_system_reset_flow(sdiodev); ++ ++ cmd_dump(next); ++ spin_lock_bh(&cmd_mgr->lock); ++ cmd_mgr->state = RWNX_CMD_MGR_STATE_CRASHED; ++ if (!(next->flags & RWNX_CMD_FLAG_DONE)) { ++ next->result = -ETIMEDOUT; ++ cmd_complete(cmd_mgr, next); ++ } ++ spin_unlock_bh(&cmd_mgr->lock); ++ } else { ++ spin_lock_bh(&cmd_mgr->lock); ++ list_del(&next->list); ++ cmd_mgr->queue_sz--; ++ spin_unlock_bh(&cmd_mgr->lock); ++ rwnx_cmd_free(next); //kfree(next); ++ } ++ } ++ } ++} ++ ++static int cmd_mgr_run_callback(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, ++ struct rwnx_cmd_e2amsg *msg, msg_cb_fct cb) ++{ ++ int res; ++ ++ if (!cb) { ++ return 0; ++ } ++ //RWNX_DBG(RWNX_FN_ENTRY_STR); ++ //spin_lock_bh(&rwnx_hw->cb_lock); ++ res = cb(rwnx_hw, cmd, msg); ++ //spin_unlock_bh(&rwnx_hw->cb_lock); ++ ++ return res; ++} ++ ++/** ++ * ++ ++ */ ++static int cmd_mgr_msgind(struct rwnx_cmd_mgr *cmd_mgr, ++ struct rwnx_cmd_e2amsg *msg, msg_cb_fct cb) ++{ ++#ifdef AICWF_SDIO_SUPPORT ++ struct aic_sdio_dev *sdiodev = ++ container_of(cmd_mgr, struct aic_sdio_dev, cmd_mgr); ++ struct rwnx_hw *rwnx_hw = sdiodev->rwnx_hw; ++#endif ++#ifdef AICWF_USB_SUPPORT ++ struct aic_usb_dev *usbdev = ++ container_of(cmd_mgr, struct aic_usb_dev, cmd_mgr); ++ struct rwnx_hw *rwnx_hw = usbdev->rwnx_hw; ++#endif ++ struct rwnx_cmd *cmd, *pos; ++ 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_safe (cmd, pos, &cmd_mgr->cmds, list) { ++ if (cmd->reqid == msg->id && ++ (cmd->flags & RWNX_CMD_FLAG_WAIT_CFM)) { ++ if (!cmd_mgr_run_callback(rwnx_hw, cmd, msg, cb)) { ++ found = true; ++ cmd->flags &= ~RWNX_CMD_FLAG_WAIT_CFM; ++ ++ if (WARN((msg->param_len > ++ RWNX_CMD_E2AMSG_LEN_MAX), ++ "Unexpect E2A msg len %d > %d\n", ++ msg->param_len, ++ RWNX_CMD_E2AMSG_LEN_MAX)) { ++ msg->param_len = ++ RWNX_CMD_E2AMSG_LEN_MAX; ++ } ++ ++ if (cmd->e2a_msg && msg->param_len) ++ memcpy(cmd->e2a_msg, &msg->param, ++ msg->param_len); ++ ++ if (RWNX_CMD_WAIT_COMPLETE(cmd->flags)) ++ cmd_complete(cmd_mgr, cmd); ++ ++ break; ++ } ++ } ++ } ++ spin_unlock_bh(&cmd_mgr->lock); ++ ++ if (!found) ++ cmd_mgr_run_callback(rwnx_hw, NULL, msg, cb); ++ ++ return 0; ++} ++ ++/** ++ * ++ */ ++static void cmd_mgr_print(struct rwnx_cmd_mgr *cmd_mgr) ++{ ++ struct rwnx_cmd *cur; ++ ++ spin_lock_bh(&cmd_mgr->lock); ++ RWNX_DBG("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); ++ } ++ spin_unlock_bh(&cmd_mgr->lock); ++} ++ ++static void cmd_mgr_drain(struct rwnx_cmd_mgr *cmd_mgr) ++{ ++ struct rwnx_cmd *cur, *nxt; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ spin_lock_bh(&cmd_mgr->lock); ++ list_for_each_entry_safe (cur, nxt, &cmd_mgr->cmds, list) { ++ list_del(&cur->list); ++ cmd_mgr->queue_sz--; ++ if (!(cur->flags & RWNX_CMD_FLAG_NONBLOCK)) ++ complete(&cur->complete); ++ } ++ spin_unlock_bh(&cmd_mgr->lock); ++} ++ ++void rwnx_cmd_mgr_init(struct rwnx_cmd_mgr *cmd_mgr) ++{ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ INIT_LIST_HEAD(&cmd_mgr->cmds); ++ cmd_mgr->state = RWNX_CMD_MGR_STATE_INITED; ++ spin_lock_init(&cmd_mgr->lock); ++ cmd_mgr->max_queue_sz = RWNX_CMD_MAX_QUEUED; ++ cmd_mgr->queue = &cmd_mgr_queue; ++ cmd_mgr->print = &cmd_mgr_print; ++ cmd_mgr->drain = &cmd_mgr_drain; ++ cmd_mgr->llind = &cmd_mgr_llind; ++ cmd_mgr->msgind = &cmd_mgr_msgind; ++ ++ INIT_WORK(&cmd_mgr->cmdWork, cmd_mgr_task_process); ++ cmd_mgr->cmd_wq = create_singlethread_workqueue("cmd_wq"); ++ if (!cmd_mgr->cmd_wq) { ++ txrx_err("insufficient memory to create cmd workqueue.\n"); ++ return; ++ } ++} ++ ++void rwnx_cmd_mgr_deinit(struct rwnx_cmd_mgr *cmd_mgr) ++{ ++ 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)); ++} ++ ++void aicwf_set_cmd_tx(void *dev, struct lmac_msg *msg, uint len) ++{ ++ u8 *buffer = NULL; ++ u16 index = 0; ++#ifdef AICWF_SDIO_SUPPORT ++ struct aic_sdio_dev *sdiodev = (struct aic_sdio_dev *)dev; ++ struct aicwf_bus *bus = sdiodev->bus_if; ++#else ++ struct aic_usb_dev *usbdev = (struct aic_usb_dev *)dev; ++ struct aicwf_bus *bus = NULL; ++ if (!usbdev->state) { ++ printk("down msg \n"); ++ return; ++ } ++ bus = usbdev->bus_if; ++#endif ++ buffer = bus->cmd_buf; ++ ++ memset(buffer, 0, CMD_BUF_MAX); ++ buffer[0] = (len + 4) & 0x00ff; ++ buffer[1] = ((len + 4) >> 8) & 0x0f; ++ buffer[2] = 0x11; ++ if (sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ sdiodev->chipid == PRODUCT_ID_AIC8800DW) ++ buffer[3] = 0x0; ++ else if (sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) ++ buffer[3] = crc8_ponl_107(&buffer[0], 3); // crc8 ++ index += 4; ++ //there is a dummy word ++ index += 4; ++ ++ //make sure little endian ++ put_u16(&buffer[index], msg->id); ++ index += 2; ++ put_u16(&buffer[index], msg->dest_id); ++ index += 2; ++ put_u16(&buffer[index], msg->src_id); ++ index += 2; ++ put_u16(&buffer[index], msg->param_len); ++ index += 2; ++ memcpy(&buffer[index], (u8 *)msg->param, msg->param_len); ++ ++ aicwf_bus_txmsg(bus, buffer, len + 8); ++} +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_cmds.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_cmds.h +new file mode 100755 +index 000000000..69724f9a4 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_cmds.h +@@ -0,0 +1,126 @@ ++/** ++ ****************************************************************************** ++ * ++ * rwnx_cmds.h ++ * ++ * Copyright (C) RivieraWaves 2014-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++#ifndef _RWNX_CMDS_H_ ++#define _RWNX_CMDS_H_ ++ ++#include ++#include ++#include ++#include "lmac_msg.h" ++ ++#ifdef CONFIG_RWNX_SDM ++#define RWNX_80211_CMD_TIMEOUT_MS (20 * 300) ++#elif defined(CONFIG_RWNX_FHOST) ++#define RWNX_80211_CMD_TIMEOUT_MS (10000) ++#else ++#ifdef AICWF_USB_SUPPORT ++#define RWNX_80211_CMD_TIMEOUT_MS 2000 //300 ++#else ++#define RWNX_80211_CMD_TIMEOUT_MS 6000 //500//300 ++#endif ++#endif ++ ++#define RWNX_CMD_FLAG_NONBLOCK BIT(0) ++#define RWNX_CMD_FLAG_REQ_CFM BIT(1) ++#define RWNX_CMD_FLAG_WAIT_PUSH BIT(2) ++#define RWNX_CMD_FLAG_WAIT_ACK BIT(3) ++#define RWNX_CMD_FLAG_WAIT_CFM BIT(4) ++#define RWNX_CMD_FLAG_DONE BIT(5) ++/* ATM IPC design makes it possible to get the CFM before the ACK, ++ * otherwise this could have simply been a state enum */ ++#define RWNX_CMD_WAIT_COMPLETE(flags) \ ++ (!(flags & (RWNX_CMD_FLAG_WAIT_ACK | RWNX_CMD_FLAG_WAIT_CFM))) ++ ++#define RWNX_CMD_MAX_QUEUED 16 ++ ++#ifdef CONFIG_RWNX_FHOST ++#include "ipc_fhost.h" ++#define rwnx_cmd_e2amsg ipc_fhost_msg ++#define rwnx_cmd_a2emsg ipc_fhost_msg ++#define RWNX_CMD_A2EMSG_LEN(m) (m->param_len) ++#define RWNX_CMD_E2AMSG_LEN_MAX IPC_FHOST_MSG_BUF_SIZE ++struct rwnx_term_stream; ++ ++#else /* !CONFIG_RWNX_FHOST*/ ++#include "ipc_shared.h" ++#define rwnx_cmd_e2amsg ipc_e2a_msg ++#define rwnx_cmd_a2emsg lmac_msg ++#define RWNX_CMD_A2EMSG_LEN(m) (sizeof(struct lmac_msg) + m->param_len) ++#define RWNX_CMD_E2AMSG_LEN_MAX (IPC_E2A_MSG_PARAM_SIZE * 4) ++ ++#endif /* CONFIG_RWNX_FHOST*/ ++ ++struct rwnx_hw; ++struct rwnx_cmd; ++typedef int (*msg_cb_fct)(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd, ++ struct rwnx_cmd_e2amsg *msg); ++static inline void put_u16(u8 *buf, u16 data) ++{ ++ buf[0] = (u8)(data & 0x00ff); ++ buf[1] = (u8)((data >> 8) & 0x00ff); ++} ++ ++enum rwnx_cmd_mgr_state { ++ RWNX_CMD_MGR_STATE_DEINIT, ++ RWNX_CMD_MGR_STATE_INITED, ++ RWNX_CMD_MGR_STATE_CRASHED, ++}; ++ ++struct rwnx_cmd { ++ struct list_head list; ++ lmac_msg_id_t id; ++ lmac_msg_id_t reqid; ++ struct rwnx_cmd_a2emsg *a2e_msg; ++ char *e2a_msg; ++ u32 tkn; ++ u16 flags; ++ ++ struct completion complete; ++ u32 result; ++ u8 used; ++ int array_id; ++#ifdef CONFIG_RWNX_FHOST ++ struct rwnx_term_stream *stream; ++#endif ++}; ++ ++struct rwnx_cmd_mgr { ++ enum rwnx_cmd_mgr_state state; ++ spinlock_t lock; ++ u32 next_tkn; ++ u32 queue_sz; ++ u32 max_queue_sz; ++ ++ struct list_head cmds; ++ ++ int (*queue)(struct rwnx_cmd_mgr *, struct rwnx_cmd *); ++ int (*llind)(struct rwnx_cmd_mgr *, struct rwnx_cmd *); ++ int (*msgind)(struct rwnx_cmd_mgr *, struct rwnx_cmd_e2amsg *, ++ msg_cb_fct); ++ void (*print)(struct rwnx_cmd_mgr *); ++ void (*drain)(struct rwnx_cmd_mgr *); ++ ++ struct work_struct cmdWork; ++ struct workqueue_struct *cmd_wq; ++}; ++ ++#define WAKE_CMD_WORK(cmd_mgr) \ ++ do { \ ++ queue_work((cmd_mgr)->cmd_wq, &cmd_mgr->cmdWork); \ ++ } while (0) ++ ++void rwnx_cmd_mgr_init(struct rwnx_cmd_mgr *cmd_mgr); ++void rwnx_cmd_mgr_deinit(struct rwnx_cmd_mgr *cmd_mgr); ++int cmd_mgr_queue_force_defer(struct rwnx_cmd_mgr *cmd_mgr, ++ struct rwnx_cmd *cmd); ++void aicwf_set_cmd_tx(void *dev, struct lmac_msg *msg, uint len); ++ ++#endif /* _RWNX_CMDS_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_compat.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_compat.h +new file mode 100755 +index 000000000..4b0ce1d2e +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_compat.h +@@ -0,0 +1,464 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_compat.h ++ * ++ * Ensure driver compilation for linux 3.16 to 3.19 ++ * ++ * To avoid too many #if LINUX_VERSION_CODE if the code, when prototype change ++ * between different kernel version: ++ * - For external function, define a macro whose name is the function name with ++ * _compat suffix and prototype (actually the number of parameter) of the ++ * latest version. Then latest version this macro simply call the function ++ * and for older kernel version it call the function adapting the api. ++ * - For internal function (e.g. cfg80211_ops) do the same but the macro name ++ * doesn't need to have the _compat suffix when the function is not used ++ * directly by the driver ++ * ++ * Copyright (C) RivieraWaves 2018 ++ * ++ ****************************************************************************** ++ */ ++#ifndef _RWNX_COMPAT_H_ ++#define _RWNX_COMPAT_H_ ++#include ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0) ++#error "Minimum kernel version supported is 3.10" ++#endif ++ ++/* Generic */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) ++#define __bf_shf(x) (__builtin_ffsll(x) - 1) ++#define FIELD_PREP(_mask, _val) \ ++ (((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask)) ++#else ++#include ++#endif ++ ++/* CFG80211 */ ++ ++//because android kernel 5.15 uses kernel 6.0 or 6.1 kernel api ++#ifdef ANDROID_PLATFORM ++#define HIGH_KERNEL_VERSION KERNEL_VERSION(5, 15, 41) ++#define HIGH_KERNEL_VERSION2 KERNEL_VERSION(5, 15, 41) ++#define HIGH_KERNEL_VERSION3 KERNEL_VERSION(5, 15, 104) ++#define HIGH_KERNEL_VERSION4 KERNEL_VERSION(6, 1, 0) ++#else ++#define HIGH_KERNEL_VERSION KERNEL_VERSION(6, 0, 0) ++#define HIGH_KERNEL_VERSION2 KERNEL_VERSION(6, 1, 0) ++#define HIGH_KERNEL_VERSION3 KERNEL_VERSION(6, 3, 0) ++#define HIGH_KERNEL_VERSION4 KERNEL_VERSION(6, 3, 0) ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 60) ++#define IEEE80211_MAX_AMPDU_BUF IEEE80211_MAX_AMPDU_BUF_HE ++#define IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB \ ++ IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB ++#define IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB \ ++ IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB ++#define IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA \ ++ IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 20, 0) ++#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK \ ++ IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_MASK ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0) ++#define IEEE80211_RADIOTAP_HE 23 ++#define IEEE80211_RADIOTAP_HE_MU 24 ++ ++struct ieee80211_radiotap_he { ++ __le16 data1, data2, data3, data4, data5, data6; ++}; ++ ++enum ieee80211_radiotap_he_bits { ++ IEEE80211_RADIOTAP_HE_DATA1_FORMAT_MASK = 3, ++ IEEE80211_RADIOTAP_HE_DATA1_FORMAT_SU = 0, ++ IEEE80211_RADIOTAP_HE_DATA1_FORMAT_EXT_SU = 1, ++ IEEE80211_RADIOTAP_HE_DATA1_FORMAT_MU = 2, ++ IEEE80211_RADIOTAP_HE_DATA1_FORMAT_TRIG = 3, ++ ++ IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN = 0x0004, ++ IEEE80211_RADIOTAP_HE_DATA1_BEAM_CHANGE_KNOWN = 0x0008, ++ IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN = 0x0010, ++ IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN = 0x0020, ++ IEEE80211_RADIOTAP_HE_DATA1_DATA_DCM_KNOWN = 0x0040, ++ IEEE80211_RADIOTAP_HE_DATA1_CODING_KNOWN = 0x0080, ++ IEEE80211_RADIOTAP_HE_DATA1_LDPC_XSYMSEG_KNOWN = 0x0100, ++ IEEE80211_RADIOTAP_HE_DATA1_STBC_KNOWN = 0x0200, ++ IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE_KNOWN = 0x0400, ++ IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE2_KNOWN = 0x0800, ++ IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE3_KNOWN = 0x1000, ++ IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE4_KNOWN = 0x2000, ++ IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN = 0x4000, ++ IEEE80211_RADIOTAP_HE_DATA1_DOPPLER_KNOWN = 0x8000, ++ ++ IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_KNOWN = 0x0001, ++ IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN = 0x0002, ++ IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN = 0x0004, ++ IEEE80211_RADIOTAP_HE_DATA2_PRE_FEC_PAD_KNOWN = 0x0008, ++ IEEE80211_RADIOTAP_HE_DATA2_TXBF_KNOWN = 0x0010, ++ IEEE80211_RADIOTAP_HE_DATA2_PE_DISAMBIG_KNOWN = 0x0020, ++ IEEE80211_RADIOTAP_HE_DATA2_TXOP_KNOWN = 0x0040, ++ IEEE80211_RADIOTAP_HE_DATA2_MIDAMBLE_KNOWN = 0x0080, ++ IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET = 0x3f00, ++ IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET_KNOWN = 0x4000, ++ IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_SEC = 0x8000, ++ ++ IEEE80211_RADIOTAP_HE_DATA3_BSS_COLOR = 0x003f, ++ IEEE80211_RADIOTAP_HE_DATA3_BEAM_CHANGE = 0x0040, ++ IEEE80211_RADIOTAP_HE_DATA3_UL_DL = 0x0080, ++ IEEE80211_RADIOTAP_HE_DATA3_DATA_MCS = 0x0f00, ++ IEEE80211_RADIOTAP_HE_DATA3_DATA_DCM = 0x1000, ++ IEEE80211_RADIOTAP_HE_DATA3_CODING = 0x2000, ++ IEEE80211_RADIOTAP_HE_DATA3_LDPC_XSYMSEG = 0x4000, ++ IEEE80211_RADIOTAP_HE_DATA3_STBC = 0x8000, ++ ++ IEEE80211_RADIOTAP_HE_DATA4_SU_MU_SPTL_REUSE = 0x000f, ++ IEEE80211_RADIOTAP_HE_DATA4_MU_STA_ID = 0x7ff0, ++ IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE1 = 0x000f, ++ IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE2 = 0x00f0, ++ IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE3 = 0x0f00, ++ IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE4 = 0xf000, ++ ++ IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC = 0x000f, ++ IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_20MHZ = 0, ++ IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_40MHZ = 1, ++ IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_80MHZ = 2, ++ IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_160MHZ = 3, ++ IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_26T = 4, ++ IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_52T = 5, ++ IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_106T = 6, ++ IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_242T = 7, ++ IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_484T = 8, ++ IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_996T = 9, ++ IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_2x996T = 10, ++ ++ IEEE80211_RADIOTAP_HE_DATA5_GI = 0x0030, ++ IEEE80211_RADIOTAP_HE_DATA5_GI_0_8 = 0, ++ IEEE80211_RADIOTAP_HE_DATA5_GI_1_6 = 1, ++ IEEE80211_RADIOTAP_HE_DATA5_GI_3_2 = 2, ++ ++ IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE = 0x00c0, ++ IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_UNKNOWN = 0, ++ IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_1X = 1, ++ IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_2X = 2, ++ IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X = 3, ++ IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS = 0x0700, ++ IEEE80211_RADIOTAP_HE_DATA5_PRE_FEC_PAD = 0x3000, ++ IEEE80211_RADIOTAP_HE_DATA5_TXBF = 0x4000, ++ IEEE80211_RADIOTAP_HE_DATA5_PE_DISAMBIG = 0x8000, ++ ++ IEEE80211_RADIOTAP_HE_DATA6_NSTS = 0x000f, ++ IEEE80211_RADIOTAP_HE_DATA6_DOPPLER = 0x0010, ++ IEEE80211_RADIOTAP_HE_DATA6_TXOP = 0x7f00, ++ IEEE80211_RADIOTAP_HE_DATA6_MIDAMBLE_PDCTY = 0x8000, ++}; ++ ++struct ieee80211_radiotap_he_mu { ++ __le16 flags1, flags2; ++ u8 ru_ch1[4]; ++ u8 ru_ch2[4]; ++}; ++ ++enum ieee80211_radiotap_he_mu_bits { ++ IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS = 0x000f, ++ IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS_KNOWN = 0x0010, ++ IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM = 0x0020, ++ IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM_KNOWN = 0x0040, ++ IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH2_CTR_26T_RU_KNOWN = 0x0080, ++ IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_RU_KNOWN = 0x0100, ++ IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH2_RU_KNOWN = 0x0200, ++ IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_CTR_26T_RU_KNOWN = 0x1000, ++ IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_CTR_26T_RU = 0x2000, ++ IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_COMP_KNOWN = 0x4000, ++ IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN = 0x8000, ++ ++ IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW = 0x0003, ++ IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_20MHZ = 0x0000, ++ IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_40MHZ = 0x0001, ++ IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_80MHZ = 0x0002, ++ IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_160MHZ = 0x0003, ++ IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN = 0x0004, ++ IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_COMP = 0x0008, ++ IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_SYMS_USERS = 0x00f0, ++ IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW = 0x0300, ++ IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN = 0x0400, ++ IEEE80211_RADIOTAP_HE_MU_FLAGS2_CH2_CTR_26T_RU = 0x0800, ++}; ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0) ++#define rwnx_cfg80211_add_iface(wiphy, name, name_assign_type, type, params) \ ++ rwnx_cfg80211_add_iface(wiphy, name, type, u32 *flags, params) ++#else ++#define rwnx_cfg80211_add_iface(wiphy, name, name_assign_type, type, params) \ ++ rwnx_cfg80211_add_iface(wiphy, name, name_assign_type, type, \ ++ u32 *flags, params) ++#endif ++ ++#define rwnx_cfg80211_change_iface(wiphy, dev, type, params) \ ++ rwnx_cfg80211_change_iface(wiphy, dev, type, u32 *flags, params) ++ ++#define CCFS0(vht) vht->center_freq_seg1_idx ++#define CCFS1(vht) vht->center_freq_seg2_idx ++ ++#else ++#define CCFS0(vht) vht->center_freq_seg0_idx ++#define CCFS1(vht) vht->center_freq_seg1_idx ++ ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) ++#define cfg80211_cqm_rssi_notify(dev, event, level, gfp) \ ++ cfg80211_cqm_rssi_notify(dev, event, gfp) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) ++#define ieee80211_amsdu_to_8023s(skb, list, addr, iftype, extra_headroom, \ ++ check_da, check_sa) \ ++ ieee80211_amsdu_to_8023s(skb, list, addr, iftype, extra_headroom, false) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) ++#define NUM_NL80211_BANDS IEEE80211_NUM_BANDS ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) ++#define cfg80211_disconnected(dev, reason, ie, len, local, gfp) \ ++ cfg80211_disconnected(dev, reason, ie, len, gfp) ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)) && \ ++ !(defined CONFIG_VENDOR_RWNX) ++#define ieee80211_chandef_to_operating_class(chan_def, op_class) 0 ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0) ++#define SURVEY_INFO_TIME SURVEY_INFO_CHANNEL_TIME ++#define SURVEY_INFO_TIME_BUSY SURVEY_INFO_CHANNEL_TIME_BUSY ++#define SURVEY_INFO_TIME_EXT_BUSY SURVEY_INFO_CHANNEL_TIME_EXT_BUSY ++#define SURVEY_INFO_TIME_RX SURVEY_INFO_CHANNEL_TIME_RX ++#define SURVEY_INFO_TIME_TX SURVEY_INFO_CHANNEL_TIME_TX ++ ++#define SURVEY_TIME(s) s->channel_time ++#define SURVEY_TIME_BUSY(s) s->channel_time_busy ++#else ++#define SURVEY_TIME(s) s->time ++#define SURVEY_TIME_BUSY(s) s->time_busy ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) ++#define cfg80211_ch_switch_started_notify(dev, chandef, count) ++ ++#define WLAN_BSS_COEX_INFORMATION_REQUEST BIT(0) ++#define WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING BIT(2) ++#define WLAN_EXT_CAPA4_TDLS_BUFFER_STA BIT(4) ++#define WLAN_EXT_CAPA4_TDLS_PEER_PSM BIT(5) ++#define WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH BIT(6) ++#define WLAN_EXT_CAPA5_TDLS_CH_SW_PROHIBITED BIT(7) ++#define NL80211_FEATURE_TDLS_CHANNEL_SWITCH 0 ++ ++#define STA_TDLS_INITIATOR(sta) 0 ++ ++#else ++#define STA_TDLS_INITIATOR(sta) sta->tdls_initiator ++#endif ++ ++#ifndef REGULATORY_IGNORE_STALE_KICKOFF ++#define REGULATORY_IGNORE_STALE_KICKOFF 0 ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)) && \ ++ (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) ++#define cfg80211_rx_mgmt(wdev, freq, rssi, buf, len, flags) \ ++ cfg80211_rx_mgmt(wdev, freq, rssi, buf, len, flags, GFP_ATOMIC) ++#elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0) ++#define cfg80211_rx_mgmt(wdev, freq, rssi, buf, len, flags) \ ++ cfg80211_rx_mgmt(wdev, freq, rssi, buf, len, GFP_ATOMIC) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) ++#if 0 ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) ++#define rwnx_cfg80211_tdls_mgmt(wiphy, dev, peer, act, tok, status, \ ++ peer_capability, initiator, buf, len) \ ++ rwnx_cfg80211_tdls_mgmt(wiphy, dev, peer, act, tok, status, \ ++ peer_capability, buf, len) ++#else ++#define rwnx_cfg80211_tdls_mgmt(wiphy, dev, peer, act, tok, status, \ ++ peer_capability, initiator, buf, len) \ ++ rwnx_cfg80211_tdls_mgmt(wiphy, dev, peer, act, tok, status, buf, len) ++#endif ++#endif ++ ++#include ++ ++struct ieee80211_wmm_ac_param { ++ u8 aci_aifsn; /* AIFSN, ACM, ACI */ ++ u8 cw; /* ECWmin, ECWmax (CW = 2^ECW - 1) */ ++ __le16 txop_limit; ++} __packed; ++ ++struct ieee80211_wmm_param_ie { ++ u8 element_id; /* Element ID: 221 (0xdd); */ ++ u8 len; /* Length: 24 */ ++ /* required fields for WMM version 1 */ ++ u8 oui[3]; /* 00:50:f2 */ ++ u8 oui_type; /* 2 */ ++ u8 oui_subtype; /* 1 */ ++ u8 version; /* 1 for WMM version 1.0 */ ++ u8 qos_info; /* AP/STA specific QoS info */ ++ u8 reserved; /* 0 */ ++ /* AC_BE, AC_BK, AC_VI, AC_VO */ ++ struct ieee80211_wmm_ac_param ac[4]; ++} __packed; ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0) ++enum { ++ IEEE80211_HE_MCS_SUPPORT_0_7 = 0, ++ IEEE80211_HE_MCS_SUPPORT_0_9 = 1, ++ IEEE80211_HE_MCS_SUPPORT_0_11 = 2, ++ IEEE80211_HE_MCS_NOT_SUPPORTED = 3, ++}; ++#endif ++ ++/* MAC80211 */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0) ++#define rwnx_ops_mgd_prepare_tx(hw, vif, duration) \ ++ rwnx_ops_mgd_prepare_tx(hw, vif) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) ++ ++#define RX_ENC_HT(s) (s->flag |= RX_FLAG_HT) ++#define RX_ENC_HT_GF(s) (s->flag |= (RX_FLAG_HT | RX_FLAG_HT_GF)) ++#define RX_ENC_VHT(s) (s->flag |= RX_FLAG_HT) ++#define RX_ENC_HE(s) (s->flag |= RX_FLAG_HT) ++#define RX_ENC_FLAG_SHORT_GI(s) (s->flag |= RX_FLAG_SHORT_GI) ++#define RX_ENC_FLAG_SHORT_PRE(s) (s->flag |= RX_FLAG_SHORTPRE) ++#define RX_ENC_FLAG_LDPC(s) (s->flag |= RX_FLAG_LDPC) ++#define RX_BW_40MHZ(s) (s->flag |= RX_FLAG_40MHZ) ++#define RX_BW_80MHZ(s) (s->vht_flag |= RX_VHT_FLAG_80MHZ) ++#define RX_BW_160MHZ(s) (s->vht_flag |= RX_VHT_FLAG_160MHZ) ++#define RX_NSS(s) s->vht_nss ++ ++#else ++#define RX_ENC_HT(s) (s->encoding = RX_ENC_HT) ++#define RX_ENC_HT_GF(s) \ ++ { \ ++ s->encoding = RX_ENC_HT; \ ++ s->enc_flags |= RX_ENC_FLAG_HT_GF; \ ++ } ++#define RX_ENC_VHT(s) (s->encoding = RX_ENC_VHT) ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0) ++#define RX_ENC_HE(s) (s->encoding = RX_ENC_VHT) ++#else ++#define RX_ENC_HE(s) (s->encoding = RX_ENC_HE) ++#endif ++#define RX_ENC_FLAG_SHORT_GI(s) (s->enc_flags |= RX_ENC_FLAG_SHORT_GI) ++#define RX_ENC_FLAG_SHORT_PRE(s) (s->enc_flags |= RX_ENC_FLAG_SHORTPRE) ++#define RX_ENC_FLAG_LDPC(s) (s->enc_flags |= RX_ENC_FLAG_LDPC) ++#define RX_BW_40MHZ(s) (s->bw = RATE_INFO_BW_40) ++#define RX_BW_80MHZ(s) (s->bw = RATE_INFO_BW_80) ++#define RX_BW_160MHZ(s) (s->bw = RATE_INFO_BW_160) ++#define RX_NSS(s) s->nss ++ ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) ++#define ieee80211_cqm_rssi_notify(vif, event, level, gfp) \ ++ ieee80211_cqm_rssi_notify(vif, event, gfp) ++#endif ++ ++#ifndef CONFIG_VENDOR_RWNX_AMSDUS_TX ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0)) ++#define rwnx_ops_ampdu_action(hw, vif, params) \ ++ rwnx_ops_ampdu_action(hw, vif, \ ++ enum ieee80211_ampdu_mlme_action action, \ ++ struct ieee80211_sta *sta, u16 tid, u16 *ssn, \ ++ u8 buf_size) ++#elif (LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)) ++#define rwnx_ops_ampdu_action(hw, vif, params) \ ++ rwnx_ops_ampdu_action(hw, vif, \ ++ enum ieee80211_ampdu_mlme_action action, \ ++ struct ieee80211_sta *sta, u16 tid, u16 *ssn, \ ++ u8 buf_size, bool amsdu) ++#endif ++#endif /* CONFIG_VENDOR_RWNX_AMSDUS_TX */ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) ++#define IEEE80211_HW_SUPPORT_FAST_XMIT 0 ++#define ieee80211_hw_check(hw, feat) (hw->flags & IEEE80211_HW_##feat) ++#define ieee80211_hw_set(hw, feat) \ ++ { \ ++ hw->flags |= IEEE80211_HW_##feat; \ ++ } ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) ++#define rwnx_ops_sw_scan_start(hw, vif, mac_addr) rwnx_ops_sw_scan_start(hw) ++#define rwnx_ops_sw_scan_complete(hw, vif) rwnx_ops_sw_scan_complete(hw) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) ++#define rwnx_ops_hw_scan(hw, vif, hw_req) \ ++ rwnx_ops_hw_scan(hw, vif, struct cfg80211_scan_request *req) ++#endif ++ ++/* NET */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) ++#define rwnx_select_queue(dev, skb, sb_dev) rwnx_select_queue(dev, skb) ++#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0) ++#define rwnx_select_queue(dev, skb, sb_dev) \ ++ rwnx_select_queue(dev, skb, void *accel_priv, \ ++ select_queue_fallback_t fallback) ++#elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0) ++#define rwnx_select_queue(dev, skb, sb_dev) \ ++ rwnx_select_queue(dev, skb, sb_dev, select_queue_fallback_t fallback) ++#else ++#define rwnx_select_queue(dev, skb, sb_dev) rwnx_select_queue(dev, skb, sb_dev) ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0)) && \ ++ !(defined CONFIG_VENDOR_RWNX) ++#define sk_pacing_shift_update(sk, shift) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) ++#define alloc_netdev_mqs(size, name, assign, setup, txqs, rxqs) \ ++ alloc_netdev_mqs(size, name, setup, txqs, rxqs) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) ++#define NET_NAME_UNKNOWN 0 ++#endif ++ ++/* TRACE */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) ++#define trace_print_symbols_seq ftrace_print_symbols_seq ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) ++#define trace_seq_buffer_ptr(p) (p->buffer + p->len) ++#endif ++ ++/* TIME */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0) ++#define time64_to_tm(t, o, tm) time_to_tm((time_t)t, o, tm) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) ++#define ktime_get_real_seconds get_seconds ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) ++typedef __s64 time64_t; ++#endif ++ ++#endif /* _RWNX_COMPAT_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_debugfs.c b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_debugfs.c +new file mode 100755 +index 000000000..968a1293c +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_debugfs.c +@@ -0,0 +1,2575 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_debugfs.c ++ * ++ * @brief Definition of debugfs entries ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rwnx_debugfs.h" ++#include "rwnx_msg_tx.h" ++#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, ++ size_t count, loff_t *ppos) ++{ ++ struct rwnx_hw *priv = file->private_data; ++ char *buf; ++ int ret; ++ int i, skipped; ++ ssize_t read; ++ int bufsz = (NX_TXQ_CNT)*20 + ++ (ARRAY_SIZE(priv->stats.amsdus_rx) + 1) * 40 + ++ (ARRAY_SIZE(priv->stats.ampdus_tx) * 30); ++ ++ if (*ppos) ++ return 0; ++ ++ buf = kmalloc(bufsz, GFP_ATOMIC); ++ if (buf == NULL) ++ return 0; ++ ++ ret = scnprintf(buf, bufsz, "TXQs CFM balances "); ++ for (i = 0; i < NX_TXQ_CNT; i++) ++ ret += scnprintf(&buf[ret], bufsz - ret, " [%1d]:%3d", i, ++ priv->stats.cfm_balance[i]); ++ ++ ret += scnprintf(&buf[ret], bufsz - ret, "\n"); ++ ++#ifdef CONFIG_RWNX_SPLIT_TX_BUF ++ ret += scnprintf(&buf[ret], bufsz - ret, ++ "\nAMSDU[len] done failed received\n"); ++ for (i = skipped = 0; i < NX_TX_PAYLOAD_MAX; i++) { ++ if (priv->stats.amsdus[i].done) { ++ per = DIV_ROUND_UP((priv->stats.amsdus[i].failed) * 100, ++ priv->stats.amsdus[i].done); ++ } else if (priv->stats.amsdus_rx[i]) { ++ per = 0; ++ } else { ++ per = 0; ++ skipped = 1; ++ continue; ++ } ++ if (skipped) { ++ ret += scnprintf(&buf[ret], bufsz - ret, " ...\n"); ++ skipped = 0; ++ } ++ ++ ret += scnprintf(&buf[ret], bufsz - ret, ++ " [%2d] %10d %8d(%3d%%) %10d\n", ++ i ? i + 1 : i, priv->stats.amsdus[i].done, ++ priv->stats.amsdus[i].failed, per, ++ priv->stats.amsdus_rx[i]); ++ } ++ ++ for (; i < ARRAY_SIZE(priv->stats.amsdus_rx); i++) { ++ if (!priv->stats.amsdus_rx[i]) { ++ skipped = 1; ++ continue; ++ } ++ if (skipped) { ++ ret += scnprintf(&buf[ret], bufsz - ret, " ...\n"); ++ skipped = 0; ++ } ++ ++ ret += scnprintf(&buf[ret], bufsz - ret, ++ " [%2d] %10d\n", ++ i + 1, priv->stats.amsdus_rx[i]); ++ } ++#else ++ ret += scnprintf(&buf[ret], bufsz - ret, "\nAMSDU[len] received\n"); ++ for (i = skipped = 0; i < ARRAY_SIZE(priv->stats.amsdus_rx); i++) { ++ if (!priv->stats.amsdus_rx[i]) { ++ skipped = 1; ++ continue; ++ } ++ if (skipped) { ++ ret += scnprintf(&buf[ret], bufsz - ret, " ...\n"); ++ skipped = 0; ++ } ++ ++ ret += scnprintf(&buf[ret], bufsz - ret, " [%2d] %10d\n", ++ i + 1, priv->stats.amsdus_rx[i]); ++ } ++ ++#endif /* CONFIG_RWNX_SPLIT_TX_BUF */ ++ ++ ret += scnprintf(&buf[ret], bufsz - ret, ++ "\nAMPDU[len] done received\n"); ++ for (i = skipped = 0; i < ARRAY_SIZE(priv->stats.ampdus_tx); i++) { ++ if (!priv->stats.ampdus_tx[i] && !priv->stats.ampdus_rx[i]) { ++ skipped = 1; ++ continue; ++ } ++ if (skipped) { ++ ret += scnprintf(&buf[ret], bufsz - ret, " ...\n"); ++ skipped = 0; ++ } ++ ++ ret += scnprintf(&buf[ret], bufsz - ret, " [%2d] %9d %9d\n", ++ i ? i + 1 : i, priv->stats.ampdus_tx[i], ++ priv->stats.ampdus_rx[i]); ++ } ++ ++ ret += scnprintf(&buf[ret], bufsz - ret, "#mpdu missed %9d\n", ++ priv->stats.ampdus_rx_miss); ++ read = simple_read_from_buffer(user_buf, count, ppos, buf, ret); ++ ++ kfree(buf); ++ ++ return read; ++} ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++static ssize_t rwnx_dbgfs_stats_write(struct file *file, ++ const char __user *user_buf, size_t count, ++ loff_t *ppos) ++{ ++ struct rwnx_hw *priv = file->private_data; ++ ++ /* Prevent from interrupt preemption as these statistics are updated under ++ * interrupt */ ++ spin_lock_bh(&priv->tx_lock); ++ ++ memset(&priv->stats, 0, sizeof(priv->stats)); ++ ++ spin_unlock_bh(&priv->tx_lock); ++ ++ return count; ++} ++ ++DEBUGFS_READ_WRITE_FILE_OPS(stats); ++ ++#define TXQ_STA_PREF "tid|" ++#define TXQ_STA_PREF_FMT "%3d|" ++ ++#ifdef CONFIG_RWNX_FULLMAC ++#define TXQ_VIF_PREF "type|" ++#define TXQ_VIF_PREF_FMT "%4s|" ++#else ++#define TXQ_VIF_PREF "AC|" ++#define TXQ_VIF_PREF_FMT "%2s|" ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++#define TXQ_HDR "idx| status|credit|ready|retry" ++#define TXQ_HDR_FMT "%3d|%s%s%s%s%s%s%s|%6d|%5d|%5d" ++ ++#ifdef CONFIG_RWNX_AMSDUS_TX ++#ifdef CONFIG_RWNX_FULLMAC ++#define TXQ_HDR_SUFF "|amsdu" ++#define TXQ_HDR_SUFF_FMT "|%5d" ++#else ++#define TXQ_HDR_SUFF "|amsdu-ht|amdsu-vht" ++#define TXQ_HDR_SUFF_FMT "|%8d|%9d" ++#endif /* CONFIG_RWNX_FULLMAC */ ++#else ++#define TXQ_HDR_SUFF "" ++#define TXQ_HDR_SUF_FMT "" ++#endif /* CONFIG_RWNX_AMSDUS_TX */ ++ ++#define TXQ_HDR_MAX_LEN \ ++ (sizeof(TXQ_STA_PREF) + sizeof(TXQ_HDR) + sizeof(TXQ_HDR_SUFF) + 1) ++ ++#ifdef CONFIG_RWNX_FULLMAC ++#define PS_HDR "Legacy PS: ready=%d, sp=%d / UAPSD: ready=%d, sp=%d" ++#define PS_HDR_LEGACY "Legacy PS: ready=%d, sp=%d" ++#define PS_HDR_UAPSD "UAPSD: ready=%d, sp=%d" ++#define PS_HDR_MAX_LEN \ ++ sizeof("Legacy PS: ready=xxx, sp=xxx / UAPSD: ready=xxx, sp=xxx\n") ++#else ++#define PS_HDR "" ++#define PS_HDR_MAX_LEN 0 ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++#define STA_HDR "** STA %d (%pM)\n" ++#define STA_HDR_MAX_LEN \ ++ (sizeof("- STA xx (xx:xx:xx:xx:xx:xx)\n") + PS_HDR_MAX_LEN) ++ ++#ifdef CONFIG_RWNX_FULLMAC ++#define VIF_HDR "* VIF [%d] %s\n" ++#define VIF_HDR_MAX_LEN (sizeof(VIF_HDR) + IFNAMSIZ) ++#else ++#define VIF_HDR "* VIF [%d]\n" ++#define VIF_HDR_MAX_LEN sizeof(VIF_HDR) ++#endif ++ ++#ifdef CONFIG_RWNX_AMSDUS_TX ++ ++#ifdef CONFIG_RWNX_FULLMAC ++#define VIF_SEP "---------------------------------------\n" ++#else ++#define VIF_SEP "----------------------------------------------------\n" ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++#else /* ! CONFIG_RWNX_AMSDUS_TX */ ++#define VIF_SEP "---------------------------------\n" ++#endif /* CONFIG_RWNX_AMSDUS_TX*/ ++ ++#define VIF_SEP_LEN sizeof(VIF_SEP) ++ ++#define CAPTION \ ++ "status: L=in hwq list, F=stop full, P=stop sta PS, V=stop vif PS, C=stop channel, S=stop CSA, M=stop MU" ++#define CAPTION_LEN sizeof(CAPTION) ++ ++#define STA_TXQ 0 ++#define VIF_TXQ 1 ++ ++static int rwnx_dbgfs_txq(char *buf, size_t size, struct rwnx_txq *txq, ++ int type, int tid, char *name) ++{ ++ int res, idx = 0; ++ ++ if (type == STA_TXQ) { ++ res = scnprintf(&buf[idx], size, TXQ_STA_PREF_FMT, tid); ++ idx += res; ++ size -= res; ++ } else { ++ res = scnprintf(&buf[idx], size, TXQ_VIF_PREF_FMT, name); ++ idx += res; ++ size -= res; ++ } ++ ++ res = scnprintf(&buf[idx], size, TXQ_HDR_FMT, txq->idx, ++ (txq->status & RWNX_TXQ_IN_HWQ_LIST) ? "L" : " ", ++ (txq->status & RWNX_TXQ_STOP_FULL) ? "F" : " ", ++ (txq->status & RWNX_TXQ_STOP_STA_PS) ? "P" : " ", ++ (txq->status & RWNX_TXQ_STOP_VIF_PS) ? "V" : " ", ++ (txq->status & RWNX_TXQ_STOP_CHAN) ? "C" : " ", ++ (txq->status & RWNX_TXQ_STOP_CSA) ? "S" : " ", ++ (txq->status & RWNX_TXQ_STOP_MU_POS) ? "M" : " ", ++ txq->credits, skb_queue_len(&txq->sk_list), ++ txq->nb_retry); ++ idx += res; ++ size -= res; ++ ++#ifdef CONFIG_RWNX_AMSDUS_TX ++ if (type == STA_TXQ) { ++ res = scnprintf(&buf[idx], size, TXQ_HDR_SUFF_FMT, ++#ifdef CONFIG_RWNX_FULLMAC ++ txq->amsdu_len ++#else ++ txq->amsdu_ht_len_cap, txq->amsdu_vht_len_cap ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ); ++ idx += res; ++ size -= res; ++ } ++#endif ++ ++ res = scnprintf(&buf[idx], size, "\n"); ++ idx += res; ++ size -= res; ++ ++ return idx; ++} ++ ++static int rwnx_dbgfs_txq_sta(char *buf, size_t size, struct rwnx_sta *rwnx_sta, ++ struct rwnx_hw *rwnx_hw) ++{ ++ int tid, res, idx = 0; ++ struct rwnx_txq *txq; ++ ++ res = scnprintf(&buf[idx], size, "\n" STA_HDR, rwnx_sta->sta_idx, ++#ifdef CONFIG_RWNX_FULLMAC ++ rwnx_sta->mac_addr ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ); ++ idx += res; ++ size -= res; ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ if (rwnx_sta->ps.active) { ++ if (rwnx_sta->uapsd_tids && ++ (rwnx_sta->uapsd_tids == ((1 << NX_NB_TXQ_PER_STA) - 1))) ++ res = scnprintf(&buf[idx], size, PS_HDR_UAPSD "\n", ++ rwnx_sta->ps.pkt_ready[UAPSD_ID], ++ rwnx_sta->ps.sp_cnt[UAPSD_ID]); ++ else if (rwnx_sta->uapsd_tids) ++ res = scnprintf(&buf[idx], size, PS_HDR "\n", ++ rwnx_sta->ps.pkt_ready[LEGACY_PS_ID], ++ rwnx_sta->ps.sp_cnt[LEGACY_PS_ID], ++ rwnx_sta->ps.pkt_ready[UAPSD_ID], ++ rwnx_sta->ps.sp_cnt[UAPSD_ID]); ++ else ++ res = scnprintf(&buf[idx], size, PS_HDR_LEGACY "\n", ++ rwnx_sta->ps.pkt_ready[LEGACY_PS_ID], ++ rwnx_sta->ps.sp_cnt[LEGACY_PS_ID]); ++ idx += res; ++ size -= res; ++ } else { ++ res = scnprintf(&buf[idx], size, "\n"); ++ idx += res; ++ size -= res; ++ } ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++ res = scnprintf(&buf[idx], size, ++ TXQ_STA_PREF TXQ_HDR TXQ_HDR_SUFF "\n"); ++ idx += res; ++ size -= res; ++ ++ foreach_sta_txq(rwnx_sta, txq, tid, rwnx_hw) ++ { ++ res = rwnx_dbgfs_txq(&buf[idx], size, txq, STA_TXQ, tid, NULL); ++ idx += res; ++ size -= res; ++ } ++ ++ return idx; ++} ++ ++static int rwnx_dbgfs_txq_vif(char *buf, size_t size, struct rwnx_vif *rwnx_vif, ++ struct rwnx_hw *rwnx_hw) ++{ ++ int res, idx = 0; ++ struct rwnx_txq *txq; ++ struct rwnx_sta *rwnx_sta; ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ res = scnprintf(&buf[idx], size, VIF_HDR, rwnx_vif->vif_index, ++ rwnx_vif->ndev->name); ++ idx += res; ++ size -= res; ++ if (!rwnx_vif->up || rwnx_vif->ndev == NULL) ++ return idx; ++ ++#else ++ int ac; ++ char ac_name[2] = { '0', '\0' }; ++ ++ res = scnprintf(&buf[idx], size, VIF_HDR, rwnx_vif->vif_index); ++ idx += res; ++ size -= res; ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ if (RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_AP || ++ RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_P2P_GO || ++ RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_MESH_POINT) { ++ res = scnprintf(&buf[idx], size, TXQ_VIF_PREF TXQ_HDR "\n"); ++ idx += res; ++ size -= res; ++ txq = rwnx_txq_vif_get(rwnx_vif, NX_UNK_TXQ_TYPE); ++ res = rwnx_dbgfs_txq(&buf[idx], size, txq, VIF_TXQ, 0, "UNK"); ++ idx += res; ++ size -= res; ++ txq = rwnx_txq_vif_get(rwnx_vif, NX_BCMC_TXQ_TYPE); ++ res = rwnx_dbgfs_txq(&buf[idx], size, txq, VIF_TXQ, 0, "BCMC"); ++ idx += res; ++ size -= res; ++ rwnx_sta = &rwnx_hw->sta_table[rwnx_vif->ap.bcmc_index]; ++ if (rwnx_sta->ps.active) { ++ res = scnprintf(&buf[idx], size, PS_HDR_LEGACY "\n", ++ rwnx_sta->ps.sp_cnt[LEGACY_PS_ID], ++ rwnx_sta->ps.sp_cnt[LEGACY_PS_ID]); ++ idx += res; ++ size -= res; ++ } else { ++ res = scnprintf(&buf[idx], size, "\n"); ++ idx += res; ++ size -= res; ++ } ++ ++ list_for_each_entry (rwnx_sta, &rwnx_vif->ap.sta_list, list) { ++ res = rwnx_dbgfs_txq_sta(&buf[idx], size, rwnx_sta, ++ rwnx_hw); ++ idx += res; ++ size -= res; ++ } ++ } else if (RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_STATION || ++ RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_P2P_CLIENT) { ++ if (rwnx_vif->sta.ap) { ++ res = rwnx_dbgfs_txq_sta(&buf[idx], size, ++ rwnx_vif->sta.ap, rwnx_hw); ++ idx += res; ++ size -= res; ++ } ++ } ++ ++#else ++ res = scnprintf(&buf[idx], size, TXQ_VIF_PREF TXQ_HDR "\n"); ++ idx += res; ++ size -= res; ++ ++ foreach_vif_txq(rwnx_vif, txq, ac) ++ { ++ ac_name[0]++; ++ res = rwnx_dbgfs_txq(&buf[idx], size, txq, VIF_TXQ, 0, ac_name); ++ idx += res; ++ size -= res; ++ } ++ ++ list_for_each_entry (rwnx_sta, &rwnx_vif->stations, list) { ++ res = rwnx_dbgfs_txq_sta(&buf[idx], size, rwnx_sta, rwnx_hw); ++ idx += res; ++ size -= res; ++ } ++#endif /* CONFIG_RWNX_FULLMAC */ ++ return idx; ++} ++ ++static ssize_t rwnx_dbgfs_txq_read(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct rwnx_hw *rwnx_hw = file->private_data; ++ struct rwnx_vif *vif; ++ char *buf; ++ int idx, res; ++ ssize_t read; ++ size_t bufsz = ++ ((NX_VIRT_DEV_MAX * (VIF_HDR_MAX_LEN + 2 * VIF_SEP_LEN)) + ++ (NX_REMOTE_STA_MAX * STA_HDR_MAX_LEN) + ++ ((NX_REMOTE_STA_MAX + NX_VIRT_DEV_MAX + NX_NB_TXQ) * ++ TXQ_HDR_MAX_LEN) + ++ CAPTION_LEN); ++ ++ /* everything is read in one go */ ++ if (*ppos) ++ return 0; ++ ++ bufsz = min_t(size_t, bufsz, count); ++ buf = kmalloc(bufsz, GFP_ATOMIC); ++ if (buf == NULL) ++ return 0; ++ ++ bufsz--; ++ idx = 0; ++ ++ res = scnprintf(&buf[idx], bufsz, CAPTION); ++ idx += res; ++ bufsz -= res; ++ ++ //spin_lock_bh(&rwnx_hw->tx_lock); ++ list_for_each_entry (vif, &rwnx_hw->vifs, list) { ++ res = scnprintf(&buf[idx], bufsz, "\n" VIF_SEP); ++ idx += res; ++ bufsz -= res; ++ res = rwnx_dbgfs_txq_vif(&buf[idx], bufsz, vif, rwnx_hw); ++ idx += res; ++ bufsz -= res; ++ res = scnprintf(&buf[idx], bufsz, VIF_SEP); ++ idx += res; ++ bufsz -= res; ++ } ++ //spin_unlock_bh(&rwnx_hw->tx_lock); ++ ++ read = simple_read_from_buffer(user_buf, count, ppos, buf, idx); ++ kfree(buf); ++ ++ return read; ++} ++DEBUGFS_READ_FILE_OPS(txq); ++ ++static ssize_t rwnx_dbgfs_acsinfo_read(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct rwnx_hw *priv = file->private_data; ++#ifdef CONFIG_RWNX_FULLMAC ++ struct wiphy *wiphy = priv->wiphy; ++#endif //CONFIG_RWNX_FULLMAC ++ 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; ++ ++ mutex_lock(&priv->dbgdump_elem.mutex); ++ ++ len += scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count), ++ "FREQ TIME(ms) BUSY(ms) NOISE(dBm)\n"); ++ ++ for (band = NL80211_BAND_2GHZ; band < band_max; band++) { ++ for (chan_cnt = 0; chan_cnt < wiphy->bands[band]->n_channels; ++ chan_cnt++) { ++ struct rwnx_survey_info *p_survey_info = ++ &priv->survey[survey_cnt]; ++ struct ieee80211_channel *p_chan = ++ &wiphy->bands[band]->channels[chan_cnt]; ++ ++ if (p_survey_info->filled) { ++ len += scnprintf( ++ &buf[len], ++ min_t(size_t, sizeof(buf) - len - 1, ++ count), ++ "%d %03d %03d %d\n", ++ p_chan->center_freq, ++ p_survey_info->chan_time_ms, ++ p_survey_info->chan_time_busy_ms, ++ p_survey_info->noise_dbm); ++ } else { ++ len += scnprintf(&buf[len], ++ min_t(size_t, ++ sizeof(buf) - len - 1, ++ count), ++ "%d NOT AVAILABLE\n", ++ p_chan->center_freq); ++ } ++ ++ survey_cnt++; ++ } ++ } ++ ++ mutex_unlock(&priv->dbgdump_elem.mutex); ++ ++ size = simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ vfree(buf); ++ ++ return size; ++} ++ ++DEBUGFS_READ_FILE_OPS(acsinfo); ++ ++static ssize_t rwnx_dbgfs_fw_dbg_read(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ char help[] = "usage: [MOD:]* " ++ "[DBG:]\n"; ++ ++ return simple_read_from_buffer(user_buf, count, ppos, help, ++ sizeof(help)); ++} ++ ++static ssize_t rwnx_dbgfs_fw_dbg_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]; ++ int idx = 0; ++ u32 mod = 0; ++ size_t len = min_t(size_t, count, sizeof(buf) - 1); ++ ++ if (copy_from_user(buf, user_buf, len)) ++ return -EFAULT; ++ buf[len] = '\0'; ++ ++#define RWNX_MOD_TOKEN(str, val) \ ++ do { \ ++ if (strncmp(&buf[idx], str, sizeof(str) - 1) == 0) { \ ++ idx += sizeof(str) - 1; \ ++ mod |= val; \ ++ continue; \ ++ } \ ++ } while (0) ++ ++#define RWNX_DBG_TOKEN(str, val) \ ++ do { \ ++ if (strncmp(&buf[idx], str, sizeof(str) - 1) == 0) { \ ++ idx += sizeof(str) - 1; \ ++ dbg = val; \ ++ goto dbg_done; \ ++ } \ ++ } while (0) ++ ++ while ((idx + 4) < len) { ++ if (strncmp(&buf[idx], "MOD:", 4) == 0) { ++ idx += 4; ++ RWNX_MOD_TOKEN("ALL", 0xffffffff); ++ RWNX_MOD_TOKEN("KE", BIT(0)); ++ RWNX_MOD_TOKEN("DBG", BIT(1)); ++ RWNX_MOD_TOKEN("IPC", BIT(2)); ++ RWNX_MOD_TOKEN("DMA", BIT(3)); ++ RWNX_MOD_TOKEN("MM", BIT(4)); ++ RWNX_MOD_TOKEN("TX", BIT(5)); ++ RWNX_MOD_TOKEN("RX", BIT(6)); ++ RWNX_MOD_TOKEN("PHY", BIT(7)); ++ idx++; ++ } else if (strncmp(&buf[idx], "DBG:", 4) == 0) { ++ u32 dbg = 0; ++ idx += 4; ++ RWNX_DBG_TOKEN("NONE", 0); ++ RWNX_DBG_TOKEN("CRT", 1); ++ RWNX_DBG_TOKEN("ERR", 2); ++ RWNX_DBG_TOKEN("WRN", 3); ++ RWNX_DBG_TOKEN("INF", 4); ++ RWNX_DBG_TOKEN("VRB", 5); ++ idx++; ++ continue; ++ dbg_done: ++ rwnx_send_dbg_set_sev_filter_req(priv, dbg); ++ } else { ++ idx++; ++ } ++ } ++ ++ if (mod) { ++ rwnx_send_dbg_set_mod_filter_req(priv, mod); ++ } ++ ++ return count; ++} ++ ++DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg); ++ ++static ssize_t rwnx_dbgfs_sys_stats_read(struct file *file, ++ char __user *user_buf, size_t count, ++ loff_t *ppos) ++{ ++ struct rwnx_hw *priv = file->private_data; ++ char buf[3 * 64]; ++ int len = 0; ++ ssize_t read; ++ int error = 0; ++ struct dbg_get_sys_stat_cfm cfm; ++ u32 sleep_int, sleep_frac, doze_int, doze_frac; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Get the information from the FW */ ++ error = rwnx_send_dbg_get_sys_stat_req(priv, &cfm); ++ if (error) ++ return error; ++ ++ if (cfm.stats_time == 0) ++ return 0; ++ ++ sleep_int = ((cfm.cpu_sleep_time * 100) / cfm.stats_time); ++ sleep_frac = (((cfm.cpu_sleep_time * 100) % cfm.stats_time) * 10) / ++ cfm.stats_time; ++ doze_int = ((cfm.doze_time * 100) / cfm.stats_time); ++ doze_frac = (((cfm.doze_time * 100) % cfm.stats_time) * 10) / ++ cfm.stats_time; ++ ++ len += scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count), ++ "\nSystem statistics:\n"); ++ len += scnprintf(&buf[len], min_t(size_t, sizeof(buf) - 1, count), ++ " CPU sleep [%%]: %d.%d\n", sleep_int, sleep_frac); ++ len += scnprintf(&buf[len], min_t(size_t, sizeof(buf) - 1, count), ++ " Doze [%%]: %d.%d\n", doze_int, doze_frac); ++ ++ read = simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ ++ return read; ++} ++ ++DEBUGFS_READ_FILE_OPS(sys_stats); ++ ++#ifdef CONFIG_RWNX_MUMIMO_TX ++static ssize_t rwnx_dbgfs_mu_group_read(struct file *file, ++ char __user *user_buf, size_t count, ++ loff_t *ppos) ++{ ++ struct rwnx_hw *rwnx_hw = file->private_data; ++ struct rwnx_mu_info *mu = &rwnx_hw->mu; ++ struct rwnx_mu_group *group; ++ size_t bufsz = ++ NX_MU_GROUP_MAX * sizeof("xx = (xx - xx - xx - xx)\n") + 50; ++ char *buf; ++ int j, res, idx = 0; ++ ++ if (*ppos) ++ return 0; ++ ++ buf = kmalloc(bufsz, GFP_ATOMIC); ++ if (buf == NULL) ++ return 0; ++ ++ res = scnprintf(&buf[idx], bufsz, ++ "MU Group list (%d groups, %d users max)\n", ++ NX_MU_GROUP_MAX, CONFIG_USER_MAX); ++ idx += res; ++ bufsz -= res; ++ ++ list_for_each_entry (group, &mu->active_groups, list) { ++ if (group->user_cnt) { ++ res = scnprintf(&buf[idx], bufsz, "%2d = (", ++ group->group_id); ++ idx += res; ++ bufsz -= res; ++ for (j = 0; j < (CONFIG_USER_MAX - 1); j++) { ++ if (group->users[j]) ++ res = scnprintf( ++ &buf[idx], bufsz, "%2d - ", ++ group->users[j]->sta_idx); ++ else ++ res = scnprintf(&buf[idx], bufsz, ++ ".. - "); ++ ++ idx += res; ++ bufsz -= res; ++ } ++ ++ if (group->users[j]) ++ res = scnprintf(&buf[idx], bufsz, "%2d)\n", ++ group->users[j]->sta_idx); ++ else ++ res = scnprintf(&buf[idx], bufsz, "..)\n"); ++ ++ idx += res; ++ bufsz -= res; ++ } ++ } ++ ++ res = simple_read_from_buffer(user_buf, count, ppos, buf, idx); ++ kfree(buf); ++ ++ return res; ++} ++ ++DEBUGFS_READ_FILE_OPS(mu_group); ++#endif ++ ++#ifdef CONFIG_RWNX_P2P_DEBUGFS ++static ssize_t rwnx_dbgfs_oppps_write(struct file *file, ++ const char __user *user_buf, size_t count, ++ loff_t *ppos) ++{ ++ struct rwnx_hw *rw_hw = file->private_data; ++ struct rwnx_vif *rw_vif; ++ char buf[32]; ++ size_t len = min_t(size_t, count, sizeof(buf) - 1); ++ int ctw; ++ ++ if (copy_from_user(buf, user_buf, len)) ++ return -EFAULT; ++ buf[len] = '\0'; ++ ++ /* Read the written CT Window (provided in ms) value */ ++ if (sscanf(buf, "ctw=%d", &ctw) > 0) { ++ /* Check if at least one VIF is configured as P2P GO */ ++ list_for_each_entry (rw_vif, &rw_hw->vifs, list) { ++#ifdef CONFIG_RWNX_FULLMAC ++ if (RWNX_VIF_TYPE(rw_vif) == NL80211_IFTYPE_P2P_GO) { ++#endif /* CONFIG_RWNX_FULLMAC */ ++ struct mm_set_p2p_oppps_cfm cfm; ++ ++ /* Forward request to the embedded and wait for confirmation */ ++ rwnx_send_p2p_oppps_req(rw_hw, rw_vif, (u8)ctw, ++ &cfm); ++ ++ break; ++ } ++ } ++ } ++ ++ return count; ++} ++ ++DEBUGFS_WRITE_FILE_OPS(oppps); ++ ++static ssize_t rwnx_dbgfs_noa_write(struct file *file, ++ const char __user *user_buf, size_t count, ++ loff_t *ppos) ++{ ++ struct rwnx_hw *rw_hw = file->private_data; ++ struct rwnx_vif *rw_vif; ++ char buf[64]; ++ size_t len = min_t(size_t, count, sizeof(buf) - 1); ++ int noa_count, interval, duration, dyn_noa; ++ ++ if (copy_from_user(buf, user_buf, len)) ++ return -EFAULT; ++ buf[len] = '\0'; ++ ++ /* Read the written NOA information */ ++ if (sscanf(buf, "count=%d interval=%d duration=%d dyn=%d", &noa_count, ++ &interval, &duration, &dyn_noa) > 0) { ++ /* Check if at least one VIF is configured as P2P GO */ ++ list_for_each_entry (rw_vif, &rw_hw->vifs, list) { ++#ifdef CONFIG_RWNX_FULLMAC ++ if (RWNX_VIF_TYPE(rw_vif) == NL80211_IFTYPE_P2P_GO) { ++#endif /* CONFIG_RWNX_FULLMAC */ ++ struct mm_set_p2p_noa_cfm cfm; ++ ++ /* Forward request to the embedded and wait for confirmation */ ++ rwnx_send_p2p_noa_req(rw_hw, rw_vif, noa_count, ++ interval, duration, ++ (dyn_noa > 0), &cfm); ++ ++ break; ++ } ++ } ++ } ++ ++ return count; ++} ++ ++DEBUGFS_WRITE_FILE_OPS(noa); ++#endif /* CONFIG_RWNX_P2P_DEBUGFS */ ++ ++static char fw_log_buffer[FW_LOG_SIZE]; ++ ++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; ++ 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=%lu, not_cpy=%lu, start=%p, end=%p\n", ++ (long unsigned int)nb_cpy, (long unsigned int)not_cpy, ++ priv->debugfs.fw_log.buf.start, priv->debugfs.fw_log.buf.end); ++ return nb_cpy; ++} ++ ++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; ++ ++ 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, char __user *user_buf, ++ size_t count, loff_t *ppos, int rd_idx) ++{ ++ struct rwnx_hw *priv = file->private_data; ++ char *buf; ++ int len = 0; ++ int bufsz; ++ int i; ++ int index; ++ struct rwnx_radar_pulses *p = &priv->radar.pulses[rd_idx]; ++ ssize_t read; ++ ++ if (*ppos != 0) ++ return 0; ++ ++ /* Prevent from interrupt preemption */ ++ spin_lock_bh(&priv->radar.lock); ++ bufsz = p->count * 34 + 51; ++ bufsz += ++ rwnx_radar_dump_pattern_detector(NULL, 0, &priv->radar, rd_idx); ++ buf = kmalloc(bufsz, GFP_ATOMIC); ++ if (buf == NULL) { ++ spin_unlock_bh(&priv->radar.lock); ++ return 0; ++ } ++ ++ if (p->count) { ++ len += scnprintf(&buf[len], bufsz - len, ++ " PRI WIDTH FOM FREQ\n"); ++ index = p->index; ++ for (i = 0; i < p->count; i++) { ++ struct radar_pulse *pulse; ++ ++ if (index > 0) ++ index--; ++ else ++ index = RWNX_RADAR_PULSE_MAX - 1; ++ ++ pulse = (struct radar_pulse *)&p->buffer[index]; ++ ++ len += scnprintf( ++ &buf[len], bufsz - len, ++ "%05dus %03dus %2d%% %+3dMHz\n", ++ pulse->rep, 2 * pulse->len, 6 * pulse->fom, ++ 2 * pulse->freq); ++ } ++ } ++ ++ len += rwnx_radar_dump_pattern_detector(&buf[len], bufsz - len, ++ &priv->radar, rd_idx); ++ ++ spin_unlock_bh(&priv->radar.lock); ++ ++ read = simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ ++ kfree(buf); ++ ++ return read; ++} ++ ++static ssize_t rwnx_dbgfs_pulses_prim_read(struct file *file, ++ char __user *user_buf, size_t count, ++ loff_t *ppos) ++{ ++ return rwnx_dbgfs_pulses_read(file, user_buf, count, ppos, 0); ++} ++ ++DEBUGFS_READ_FILE_OPS(pulses_prim); ++ ++static ssize_t rwnx_dbgfs_pulses_sec_read(struct file *file, ++ char __user *user_buf, size_t count, ++ loff_t *ppos) ++{ ++ return rwnx_dbgfs_pulses_read(file, user_buf, count, ppos, 1); ++} ++ ++DEBUGFS_READ_FILE_OPS(pulses_sec); ++ ++static ssize_t rwnx_dbgfs_detected_read(struct file *file, ++ char __user *user_buf, size_t count, ++ loff_t *ppos) ++{ ++ struct rwnx_hw *priv = file->private_data; ++ char *buf; ++ int bufsz, len = 0; ++ ssize_t read; ++ ++ if (*ppos != 0) ++ return 0; ++ ++ bufsz = 5; // RIU:\n ++ bufsz += rwnx_radar_dump_radar_detected(NULL, 0, &priv->radar, ++ RWNX_RADAR_RIU); ++ ++ if (priv->phy.cnt > 1) { ++ bufsz += 5; // FCU:\n ++ bufsz += rwnx_radar_dump_radar_detected(NULL, 0, &priv->radar, ++ RWNX_RADAR_FCU); ++ } ++ ++ buf = kmalloc(bufsz, GFP_KERNEL); ++ if (buf == NULL) { ++ return 0; ++ } ++ ++ len = scnprintf(&buf[len], bufsz, "RIU:\n"); ++ len += rwnx_radar_dump_radar_detected(&buf[len], bufsz - len, ++ &priv->radar, RWNX_RADAR_RIU); ++ ++ if (priv->phy.cnt > 1) { ++ len += scnprintf(&buf[len], bufsz - len, "FCU:\n"); ++ len += rwnx_radar_dump_radar_detected( ++ &buf[len], bufsz - len, &priv->radar, RWNX_RADAR_FCU); ++ } ++ ++ read = simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ ++ kfree(buf); ++ ++ return read; ++} ++ ++DEBUGFS_READ_FILE_OPS(detected); ++ ++static ssize_t rwnx_dbgfs_enable_read(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct rwnx_hw *priv = file->private_data; ++ char buf[32]; ++ int ret; ++ ssize_t read; ++ ++ ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count), ++ "RIU=%d FCU=%d\n", ++ priv->radar.dpd[RWNX_RADAR_RIU]->enabled, ++ priv->radar.dpd[RWNX_RADAR_FCU]->enabled); ++ ++ read = simple_read_from_buffer(user_buf, count, ppos, buf, ret); ++ ++ return read; ++} ++ ++static ssize_t rwnx_dbgfs_enable_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]; ++ int val; ++ size_t len = min_t(size_t, count, sizeof(buf) - 1); ++ ++ if (copy_from_user(buf, user_buf, len)) ++ return -EFAULT; ++ ++ buf[len] = '\0'; ++ ++ if (sscanf(buf, "RIU=%d", &val) > 0) ++ rwnx_radar_detection_enable(&priv->radar, val, RWNX_RADAR_RIU); ++ ++ if (sscanf(buf, "FCU=%d", &val) > 0) ++ rwnx_radar_detection_enable(&priv->radar, val, RWNX_RADAR_FCU); ++ ++ return count; ++} ++ ++DEBUGFS_READ_WRITE_FILE_OPS(enable); ++ ++static ssize_t rwnx_dbgfs_band_read(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct rwnx_hw *priv = file->private_data; ++ char buf[32]; ++ int ret; ++ ssize_t read; ++ ++ ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count), "BAND=%d\n", ++ priv->phy.sec_chan.band); ++ ++ read = simple_read_from_buffer(user_buf, count, ppos, buf, ret); ++ ++ return read; ++} ++ ++static ssize_t rwnx_dbgfs_band_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]; ++ int val; ++ size_t len = min_t(size_t, count, sizeof(buf) - 1); ++ int band_max = NL80211_BAND_5GHZ; ++ ++ if (priv->band_5g_support) ++ band_max = NL80211_BAND_5GHZ + 1; ++ ++ if (copy_from_user(buf, user_buf, len)) ++ return -EFAULT; ++ ++ buf[len] = '\0'; ++ ++ if ((sscanf(buf, "%d", &val) > 0) && (val >= 0) && (val < band_max)) ++ priv->phy.sec_chan.band = val; ++ ++ return count; ++} ++ ++DEBUGFS_READ_WRITE_FILE_OPS(band); ++ ++static ssize_t rwnx_dbgfs_type_read(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct rwnx_hw *priv = file->private_data; ++ char buf[32]; ++ int ret; ++ ssize_t read; ++ ++ ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count), "TYPE=%d\n", ++ priv->phy.sec_chan.type); ++ ++ read = simple_read_from_buffer(user_buf, count, ppos, buf, ret); ++ ++ return read; ++} ++ ++static ssize_t rwnx_dbgfs_type_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]; ++ int val; ++ size_t len = min_t(size_t, count, sizeof(buf) - 1); ++ ++ if (copy_from_user(buf, user_buf, len)) ++ return -EFAULT; ++ ++ buf[len] = '\0'; ++ ++ if ((sscanf(buf, "%d", &val) > 0) && (val >= PHY_CHNL_BW_20) && ++ (val <= PHY_CHNL_BW_80P80)) ++ priv->phy.sec_chan.type = val; ++ ++ return count; ++} ++ ++DEBUGFS_READ_WRITE_FILE_OPS(type); ++ ++static ssize_t rwnx_dbgfs_prim20_read(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct rwnx_hw *priv = file->private_data; ++ char buf[32]; ++ int ret; ++ ssize_t read; ++ ++ ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count), ++ "PRIM20=%dMHz\n", priv->phy.sec_chan.prim20_freq); ++ ++ read = simple_read_from_buffer(user_buf, count, ppos, buf, ret); ++ ++ return read; ++} ++ ++static ssize_t rwnx_dbgfs_prim20_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]; ++ int val; ++ size_t len = min_t(size_t, count, sizeof(buf) - 1); ++ ++ if (copy_from_user(buf, user_buf, len)) ++ return -EFAULT; ++ ++ buf[len] = '\0'; ++ ++ if (sscanf(buf, "%d", &val) > 0) ++ priv->phy.sec_chan.prim20_freq = val; ++ ++ return count; ++} ++ ++DEBUGFS_READ_WRITE_FILE_OPS(prim20); ++ ++static ssize_t rwnx_dbgfs_center1_read(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct rwnx_hw *priv = file->private_data; ++ char buf[32]; ++ int ret; ++ ssize_t read; ++ ++ ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count), ++ "CENTER1=%dMHz\n", priv->phy.sec_chan.center_freq1); ++ ++ read = simple_read_from_buffer(user_buf, count, ppos, buf, ret); ++ ++ return read; ++} ++ ++static ssize_t rwnx_dbgfs_center1_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]; ++ int val; ++ size_t len = min_t(size_t, count, sizeof(buf) - 1); ++ ++ if (copy_from_user(buf, user_buf, len)) ++ return -EFAULT; ++ ++ buf[len] = '\0'; ++ ++ if (sscanf(buf, "%d", &val) > 0) ++ priv->phy.sec_chan.center_freq1 = val; ++ ++ return count; ++} ++ ++DEBUGFS_READ_WRITE_FILE_OPS(center1); ++ ++static ssize_t rwnx_dbgfs_center2_read(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct rwnx_hw *priv = file->private_data; ++ char buf[32]; ++ int ret; ++ ssize_t read; ++ ++ ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count), ++ "CENTER2=%dMHz\n", priv->phy.sec_chan.center_freq2); ++ ++ read = simple_read_from_buffer(user_buf, count, ppos, buf, ret); ++ ++ return read; ++} ++ ++static ssize_t rwnx_dbgfs_center2_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]; ++ int val; ++ size_t len = min_t(size_t, count, sizeof(buf) - 1); ++ ++ if (copy_from_user(buf, user_buf, len)) ++ return -EFAULT; ++ ++ buf[len] = '\0'; ++ ++ if (sscanf(buf, "%d", &val) > 0) ++ priv->phy.sec_chan.center_freq2 = val; ++ ++ return count; ++} ++ ++DEBUGFS_READ_WRITE_FILE_OPS(center2); ++ ++static ssize_t rwnx_dbgfs_set_read(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ return 0; ++} ++ ++static ssize_t rwnx_dbgfs_set_write(struct file *file, ++ const char __user *user_buf, size_t count, ++ loff_t *ppos) ++{ ++ struct rwnx_hw *priv = file->private_data; ++ ++ rwnx_send_set_channel(priv, 1, NULL); ++ rwnx_radar_detection_enable(&priv->radar, RWNX_RADAR_DETECT_ENABLE, ++ RWNX_RADAR_FCU); ++ ++ return count; ++} ++ ++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); ++ } else if (oper == 1) { ++ ret = rwnx_send_dbg_mem_read_req(priv, addr, &mem_read_cfm); ++ printk("before write : [0x%x] = [0x%x]\n", mem_read_cfm.memaddr, ++ mem_read_cfm.memdata); ++ ret = rwnx_send_dbg_mem_block_write_req(priv, addr, 4, &val); ++ ret = rwnx_send_dbg_mem_read_req(priv, addr, &mem_read_cfm); ++ printk("after write : [0x%x] = [0x%x]\n", mem_read_cfm.memaddr, ++ mem_read_cfm.memdata); ++ } ++ ++ return count; ++} ++ ++DEBUGFS_WRITE_FILE_OPS(regdbg); ++ ++static ssize_t rwnx_dbgfs_vendor_hwconfig_write(struct file *file, ++ const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct rwnx_hw *priv = file->private_data; ++ char buf[64]; ++ int32_t addr[14]; ++ int32_t addr_out[12]; ++ u32_l hwconfig_id; ++ size_t len = min_t(size_t, count, sizeof(buf) - 1); ++ int ret; ++ printk("%s\n", __func__); ++ //choose the type of write info by struct ++ //struct mm_set_vendor_trx_param_req trx_param; ++ ++ if (copy_from_user(buf, user_buf, len)) { ++ return -EFAULT; ++ } ++ ++ buf[len] = '\0'; ++ ret = sscanf(buf, "%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", ++ &hwconfig_id, &addr[0], &addr[1], &addr[2], &addr[3], ++ &addr[4], &addr[5], &addr[6], &addr[7], &addr[8], &addr[9], ++ &addr[10], &addr[11], &addr[12], &addr[13]); ++ if (ret > 15) { ++ printk("param error > 15\n"); ++ } else { ++ switch (hwconfig_id) { ++ case 0: ++ if (ret != 5) { ++ printk("param error != 5\n"); ++ break; ++ } ++ ret = rwnx_send_vendor_hwconfig_req(priv, hwconfig_id, ++ addr, NULL); ++ printk("ACS_TXOP_REQ bk:0x%x be:0x%x vi:0x%x vo:0x%x\n", ++ addr[0], addr[1], addr[2], addr[3]); ++ break; ++ case 1: ++ if (ret != 15) { ++ printk("param error != 15\n"); ++ break; ++ } ++ addr[12] = ~addr[12] + 1; ++ ret = rwnx_send_vendor_hwconfig_req(priv, hwconfig_id, ++ addr, NULL); ++ printk("CHANNEL_ACCESS_REQ edca:%x,%x,%x,%x, vif:%x, retry_cnt:%x, rts:%x, long_nav:%x, cfe:%x, rc_retry_cnt:%x:%x:%x ccademod_th %x, remove_1m2m %x\n", ++ addr[0], addr[1], addr[2], addr[3], addr[4], ++ addr[5], addr[6], addr[7], addr[8], addr[9], ++ addr[10], addr[11], addr[12], addr[13]); ++ break; ++ case 2: ++ if (ret != 7) { ++ printk("param error != 7\n"); ++ break; ++ } ++ ret = rwnx_send_vendor_hwconfig_req(priv, hwconfig_id, ++ addr, NULL); ++ printk("MAC_TIMESCALE_REQ sifsA:%x,sifsB:%x,slot:%x,ofdm_delay:%x,long_delay:%x,short_delay:%x\n", ++ addr[0], addr[1], addr[2], addr[3], addr[4], ++ addr[5]); ++ break; ++ case 3: ++ if (ret != 6) { ++ printk("param error != 6\n"); ++ break; ++ } ++ addr[1] = ~addr[1] + 1; ++ addr[2] = ~addr[2] + 1; ++ addr[3] = ~addr[3] + 1; ++ addr[4] = ~addr[4] + 1; ++ ret = rwnx_send_vendor_hwconfig_req(priv, hwconfig_id, ++ addr, NULL); ++ printk("CCA_THRESHOLD_REQ auto_cca:%d, cca20p_rise:%d cca20s_rise:%d cca20p_fail:%d cca20s_fail:%d\n", ++ addr[0], addr[1], addr[2], addr[3], addr[4]); ++ break; ++ case 4: // BWMODE_REQ ++ if (ret != 2) { ++ printk("param error != 2\n"); ++ } else { ++ ret = rwnx_send_vendor_hwconfig_req( ++ priv, hwconfig_id, addr, NULL); ++ printk("BWMODE_REQ md=%d\n", addr[0]); ++ } ++ break; ++ case 5: // CHIP_TEMP_GET_REQ ++ if (ret != 1) { ++ printk("param error != 1\n"); ++ } else { ++ ret = rwnx_send_vendor_hwconfig_req( ++ priv, hwconfig_id, addr, addr_out); ++ printk("CHIP_TEMP_GET_REQ degree=%d\n", ++ addr_out[0]); ++ } ++ break; ++ case 6: //AP_PS_LEVEL_SET_REQ ++ if (ret != 2) { ++ printk("param error != 2\n"); ++ } else { ++ ret = rwnx_send_vendor_hwconfig_req( ++ priv, hwconfig_id, addr, NULL); ++ printk("AP_PS_LEVEL_SET_REQ lvl=%d\n", addr[0]); ++ } ++ break; ++ default: ++ printk("param error\n"); ++ break; ++ } ++ if (ret) { ++ printk("rwnx_send_vendor_hwconfig_req fail: %x\n", ret); ++ } ++ } ++ ++ return count; ++} ++ ++DEBUGFS_WRITE_FILE_OPS(vendor_hwconfig); ++ ++static ssize_t rwnx_dbgfs_vendor_swconfig_write(struct file *file, ++ const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct rwnx_hw *priv = file->private_data; ++ char buf[64]; ++ int32_t addr[12]; ++ int32_t addr_out[12]; ++ u32_l swconfig_id; ++ size_t len = min_t(size_t, count, sizeof(buf) - 1); ++ int ret; ++ printk("%s\n", __func__); ++ ++ if (copy_from_user(buf, user_buf, len)) { ++ return -EFAULT; ++ } ++ ++ buf[len] = '\0'; ++ ret = sscanf(buf, "%x %x %x", &swconfig_id, &addr[0], &addr[1]); ++ if (ret > 3) { ++ printk("param error > 3\n"); ++ } else { ++ switch (swconfig_id) { ++ case 0: // BCN_CFG_REQ ++ if (ret != 2) { ++ printk("param error != 2\n"); ++ } else { ++ ret = rwnx_send_vendor_swconfig_req( ++ priv, swconfig_id, addr, addr_out); ++ printk("BCN_CFG_REQ set_en=%d, get_en=%d\n", ++ addr[0], addr_out[0]); ++ } ++ break; ++ ++ case 1: // TEMP_COMP_SET_REQ ++ if (ret != 3) { ++ printk("param error != 3\n"); ++ } else { ++ ret = rwnx_send_vendor_swconfig_req( ++ priv, swconfig_id, addr, addr_out); ++ printk("TEMP_COMP_SET_REQ set_en=%d, tmr=%dms, get_st=%d\n", ++ addr[0], addr[1], addr_out[0]); ++ } ++ break; ++ ++ case 2: // TEMP_COMP_GET_REQ ++ if (ret != 1) { ++ printk("param error != 1\n"); ++ } else { ++ ret = rwnx_send_vendor_swconfig_req( ++ priv, swconfig_id, addr, addr_out); ++ printk("TEMP_COMP_GET_REQ get_st=%d, degree=%d\n", ++ addr_out[0], addr_out[1]); ++ } ++ break; ++ ++ case 3: // EXT_FLAGS_SET_REQ ++ if (ret != 2) { ++ printk("param error != 2\n"); ++ } else { ++ ret = rwnx_send_vendor_swconfig_req( ++ priv, swconfig_id, addr, addr_out); ++ printk("EXT_FLAGS_SET_REQ set ext_flags=0x%x, get ext_flags=0x%x\n", ++ addr[0], addr_out[0]); ++ } ++ break; ++ ++ case 4: // EXT_FLAGS_GET_REQ ++ if (ret != 1) { ++ printk("param error != 1\n"); ++ } else { ++ ret = rwnx_send_vendor_swconfig_req( ++ priv, swconfig_id, addr, addr_out); ++ printk("EXT_FLAGS_GET_REQ get ext_flags=0x%x\n", ++ addr_out[0]); ++ } ++ break; ++ ++ case 5: // EXT_FLAGS_MASK_SET_REQ ++ if (ret != 3) { ++ printk("param error != 3\n"); ++ } else { ++ ret = rwnx_send_vendor_swconfig_req( ++ priv, swconfig_id, addr, addr_out); ++ printk("EXT_FLAGS_MASK_SET_REQ set ext_flags mask=0x%x, val=0x%x, get ext_flags=0x%x\n", ++ addr[0], addr[1], addr_out[0]); ++ } ++ break; ++ ++ default: ++ printk("param error\n"); ++ break; ++ } ++ ++ if (ret) { ++ printk("rwnx_send_vendor_swconfig_req fail: %x\n", ret); ++ } ++ } ++ ++ return count; ++} ++ ++DEBUGFS_WRITE_FILE_OPS(vendor_swconfig); ++ ++static ssize_t rwnx_dbgfs_agg_disable_write(struct file *file, ++ const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct rwnx_hw *priv = file->private_data; ++ char buf[64]; ++ int agg_disable, agg_disable_rx, sta_idx; ++ size_t len = min_t(size_t, count, sizeof(buf) - 1); ++ int ret; ++ printk("%s\n", __func__); ++ ++ if (copy_from_user(buf, user_buf, len)) { ++ return -EFAULT; ++ } ++ ++ buf[len] = '\0'; ++ ret = sscanf(buf, "%d %d %d", &agg_disable, &agg_disable_rx, &sta_idx); ++ if ((ret > 3) || (ret < 2)) { ++ printk("param error: cnt=%d\n", ret); ++ } else { ++ if (ret < 3) { ++ sta_idx = RWNX_INVALID_STA; ++ } ++ printk("disable_agg: T=%d, R=%d, staidx=%d\n", agg_disable, ++ agg_disable_rx, sta_idx); ++ ret = rwnx_send_disable_agg_req(priv, (u8_l)agg_disable, ++ (u8_l)agg_disable_rx, ++ (u8_l)sta_idx); ++ if (ret) { ++ printk("rwnx_send_disable_agg_req fail: %d\n", ret); ++ } ++ } ++ ++ return count; ++} ++ ++DEBUGFS_WRITE_FILE_OPS(agg_disable); ++ ++static ssize_t rwnx_dbgfs_set_roc_write(struct file *file, ++ const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct rwnx_hw *priv = file->private_data; ++ struct rwnx_vif *vif = NULL; ++ char buf[64]; ++ int roc_start, chan_freq, duration; ++ size_t len = min_t(size_t, count, sizeof(buf) - 1); ++ int ret; ++ int if_type = NL80211_IFTYPE_STATION; ++ printk("%s\n", __func__); ++ ++ if (copy_from_user(buf, user_buf, len)) { ++ return -EFAULT; ++ } ++ ++ buf[len] = '\0'; ++ ret = sscanf(buf, "%d %d %d", &roc_start, &chan_freq, &duration); ++ ++ list_for_each_entry (vif, &priv->vifs, list) { ++ if (RWNX_VIF_TYPE(vif) == if_type) { ++ break; ++ } ++ } ++ if ((ret > 3) || (ret < 1)) { ++ printk("param error: cnt=%d\n", ret); ++ } else if (vif) { ++ struct ieee80211_channel chan_entry = { ++ 0, ++ }; ++ struct ieee80211_channel *chan = &chan_entry; ++ struct mm_remain_on_channel_cfm roc_cfm; ++ if (ret < 3) { ++ duration = 2000; ++ if (ret < 2) { ++ chan_freq = 2412; ++ } ++ } ++ printk("set_roc: start=%d, freq=%d\n", roc_start, chan_freq); ++ if (roc_start) { ++ if (chan_freq <= 2484) { ++ chan->band = NL80211_BAND_2GHZ; ++ } else { ++ chan->band = NL80211_BAND_5GHZ; ++ } ++ chan->center_freq = chan_freq; ++ chan->max_power = 18; ++ ret = rwnx_send_roc(priv, vif, chan, duration, ++ &roc_cfm); ++ if (ret) { ++ printk("rwnx_send_roc fail: %d\n", ret); ++ } else { ++ printk("roc_cfm: opcode=%x, st=%d, idx=%d\n", ++ roc_cfm.op_code, roc_cfm.status, ++ roc_cfm.chan_ctxt_index); ++ } ++ } else { ++ ret = rwnx_send_cancel_roc(priv); ++ if (ret) { ++ printk("rwnx_send_cancel_roc fail: %d\n", ret); ++ } ++ } ++ } ++ ++ return count; ++} ++ ++DEBUGFS_WRITE_FILE_OPS(set_roc); ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ ++#define LINE_MAX_SZ 150 ++ ++struct st { ++ char line[LINE_MAX_SZ + 1]; ++ unsigned int r_idx; ++}; ++ ++static int compare_idx(const void *st1, const void *st2) ++{ ++ int index1 = ((struct st *)st1)->r_idx; ++ int index2 = ((struct st *)st2)->r_idx; ++ ++ if (index1 > index2) ++ return 1; ++ if (index1 < index2) ++ return -1; ++ ++ return 0; ++} ++ ++static const int ru_size[] = { 26, 52, 106, 242, 484, 996 }; ++ ++static int print_rate(char *buf, int size, int format, int nss, int mcs, int bw, ++ int sgi, int pre, int *r_idx) ++{ ++ int res = 0; ++ int bitrates_cck[4] = { 10, 20, 55, 110 }; ++ int bitrates_ofdm[8] = { 6, 9, 12, 18, 24, 36, 48, 54 }; ++ char he_gi[3][4] = { "0.8", "1.6", "3.2" }; ++ ++ if (format < FORMATMOD_HT_MF) { ++ if (mcs < 4) { ++ if (r_idx) { ++ *r_idx = (mcs * 2) + pre; ++ res = scnprintf(buf, size - res, "%3d ", ++ *r_idx); ++ } ++ res += scnprintf(&buf[res], size - res, ++ "L-CCK/%cP %2u.%1uM ", ++ pre > 0 ? 'L' : 'S', ++ bitrates_cck[mcs] / 10, ++ bitrates_cck[mcs] % 10); ++ } else { ++ mcs -= 4; ++ if (r_idx) { ++ *r_idx = N_CCK + mcs; ++ res = scnprintf(buf, size - res, "%3d ", ++ *r_idx); ++ } ++ res += scnprintf(&buf[res], size - res, ++ "L-OFDM %2u.0M ", ++ bitrates_ofdm[mcs]); ++ } ++ } else if (format < FORMATMOD_VHT) { ++ if (r_idx) { ++ *r_idx = N_CCK + N_OFDM + nss * 32 + mcs * 4 + bw * 2 + ++ sgi; ++ res = scnprintf(buf, size - res, "%3d ", *r_idx); ++ } ++ mcs += nss * 8; ++ res += scnprintf(&buf[res], size - res, ++ "HT%d/%cGI MCS%-2d ", 20 * (1 << bw), ++ sgi ? 'S' : 'L', mcs); ++ } else if (format == FORMATMOD_VHT) { ++ if (r_idx) { ++ *r_idx = N_CCK + N_OFDM + N_HT + nss * 80 + mcs * 8 + ++ bw * 2 + sgi; ++ res = scnprintf(buf, size - res, "%3d ", *r_idx); ++ } ++ res += scnprintf(&buf[res], size - res, ++ "VHT%d/%cGI%*cMCS%d/%1d ", 20 * (1 << bw), ++ sgi ? 'S' : 'L', bw > 2 ? 5 : 6, ' ', mcs, ++ nss + 1); ++ } else if (format == FORMATMOD_HE_SU) { ++ if (r_idx) { ++ *r_idx = N_CCK + N_OFDM + N_HT + N_VHT + nss * 144 + ++ mcs * 12 + bw * 3 + sgi; ++ res = scnprintf(buf, size - res, "%3d ", *r_idx); ++ } ++ res += scnprintf(&buf[res], size - res, ++ "HE%d/GI%s%*cMCS%d/%1d%*c", 20 * (1 << bw), ++ he_gi[sgi], bw > 2 ? 4 : 5, ' ', mcs, nss + 1, ++ mcs > 9 ? 1 : 2, ' '); ++ } else { ++ if (r_idx) { ++ *r_idx = N_CCK + N_OFDM + N_HT + N_VHT + N_HE_SU + ++ nss * 216 + mcs * 18 + bw * 3 + sgi; ++ res = scnprintf(buf, size - res, "%3d ", *r_idx); ++ } ++ res += scnprintf(&buf[res], size - res, ++ "HEMU-%d/GI%s%*cMCS%d/%1d%*c", ru_size[bw], ++ he_gi[sgi], bw > 1 ? 1 : 2, ' ', mcs, nss + 1, ++ mcs > 9 ? 1 : 2, ' '); ++ } ++ ++ return res; ++} ++ ++static int print_rate_from_cfg(char *buf, int size, u32 rate_config, int *r_idx, ++ int ru_size) ++{ ++ union rwnx_rate_ctrl_info *r_cfg = ++ (union rwnx_rate_ctrl_info *)&rate_config; ++ union rwnx_mcs_index *mcs_index = (union rwnx_mcs_index *)&rate_config; ++ unsigned int ft, pre, gi, bw, nss, mcs, len; ++ ++ ft = r_cfg->formatModTx; ++ pre = r_cfg->giAndPreTypeTx >> 1; ++ gi = r_cfg->giAndPreTypeTx; ++ bw = r_cfg->bwTx; ++ if (ft == FORMATMOD_HE_MU) { ++ mcs = mcs_index->he.mcs; ++ nss = mcs_index->he.nss; ++ bw = ru_size; ++ } else if (ft == FORMATMOD_HE_SU) { ++ mcs = mcs_index->he.mcs; ++ nss = mcs_index->he.nss; ++ } else if (ft == FORMATMOD_VHT) { ++ mcs = mcs_index->vht.mcs; ++ nss = mcs_index->vht.nss; ++ } else if (ft >= FORMATMOD_HT_MF) { ++ mcs = mcs_index->ht.mcs; ++ nss = mcs_index->ht.nss; ++ } else { ++ mcs = mcs_index->legacy; ++ nss = 0; ++ } ++ ++ len = print_rate(buf, size, ft, nss, mcs, bw, gi, pre, r_idx); ++ return len; ++} ++ ++static void idx_to_rate_cfg(int idx, union rwnx_rate_ctrl_info *r_cfg, ++ int *ru_size) ++{ ++ r_cfg->value = 0; ++ if (idx < N_CCK) { ++ r_cfg->formatModTx = FORMATMOD_NON_HT; ++ r_cfg->giAndPreTypeTx = (idx & 1) << 1; ++ r_cfg->mcsIndexTx = idx / 2; ++ } else if (idx < (N_CCK + N_OFDM)) { ++ r_cfg->formatModTx = FORMATMOD_NON_HT; ++ r_cfg->mcsIndexTx = idx - N_CCK + 4; ++ } else if (idx < (N_CCK + N_OFDM + N_HT)) { ++ union rwnx_mcs_index *r = (union rwnx_mcs_index *)r_cfg; ++ ++ idx -= (N_CCK + N_OFDM); ++ r_cfg->formatModTx = FORMATMOD_HT_MF; ++ r->ht.nss = idx / (8 * 2 * 2); ++ r->ht.mcs = (idx % (8 * 2 * 2)) / (2 * 2); ++ r_cfg->bwTx = ((idx % (8 * 2 * 2)) % (2 * 2)) / 2; ++ r_cfg->giAndPreTypeTx = idx & 1; ++ } else if (idx < (N_CCK + N_OFDM + N_HT + N_VHT)) { ++ union rwnx_mcs_index *r = (union rwnx_mcs_index *)r_cfg; ++ ++ idx -= (N_CCK + N_OFDM + N_HT); ++ r_cfg->formatModTx = FORMATMOD_VHT; ++ r->vht.nss = idx / (10 * 4 * 2); ++ r->vht.mcs = (idx % (10 * 4 * 2)) / (4 * 2); ++ r_cfg->bwTx = ((idx % (10 * 4 * 2)) % (4 * 2)) / 2; ++ r_cfg->giAndPreTypeTx = idx & 1; ++ } else if (idx < (N_CCK + N_OFDM + N_HT + N_VHT + N_HE_SU)) { ++ union rwnx_mcs_index *r = (union rwnx_mcs_index *)r_cfg; ++ ++ idx -= (N_CCK + N_OFDM + N_HT + N_VHT); ++ r_cfg->formatModTx = FORMATMOD_HE_SU; ++ r->vht.nss = idx / (12 * 4 * 3); ++ r->vht.mcs = (idx % (12 * 4 * 3)) / (4 * 3); ++ r_cfg->bwTx = ((idx % (12 * 4 * 3)) % (4 * 3)) / 3; ++ r_cfg->giAndPreTypeTx = idx % 3; ++ } else { ++ union rwnx_mcs_index *r = (union rwnx_mcs_index *)r_cfg; ++ ++ BUG_ON(ru_size == NULL); ++ ++ idx -= (N_CCK + N_OFDM + N_HT + N_VHT + N_HE_SU); ++ r_cfg->formatModTx = FORMATMOD_HE_MU; ++ r->vht.nss = idx / (12 * 6 * 3); ++ r->vht.mcs = (idx % (12 * 6 * 3)) / (6 * 3); ++ *ru_size = ((idx % (12 * 6 * 3)) % (6 * 3)) / 3; ++ r_cfg->giAndPreTypeTx = idx % 3; ++ r_cfg->bwTx = 0; ++ } ++} ++ ++static void idx_to_rate_cfg1(unsigned int formatmod, unsigned int mcs, ++ unsigned int nss, unsigned int bwTx, ++ unsigned int gi, union rwnx_rate_ctrl_info *r_cfg, ++ int *ru_size) ++{ ++ r_cfg->value = 0; ++ ++ switch (formatmod) { ++ case FORMATMOD_NON_HT: { ++ r_cfg->formatModTx = formatmod; ++ r_cfg->giAndPreTypeTx = 1; ++ r_cfg->mcsIndexTx = mcs; ++ break; ++ } ++ case FORMATMOD_NON_HT_DUP_OFDM: { ++ r_cfg->formatModTx = formatmod; ++ r_cfg->giAndPreTypeTx = gi; ++ r_cfg->mcsIndexTx = mcs; ++ break; ++ } ++ case FORMATMOD_HT_MF: { ++ union rwnx_mcs_index *r = (union rwnx_mcs_index *)r_cfg; ++ ++ r_cfg->formatModTx = formatmod; ++ r->ht.nss = nss; ++ r->ht.mcs = mcs; ++ r_cfg->bwTx = bwTx; ++ r_cfg->giAndPreTypeTx = gi; ++ break; ++ } ++ case FORMATMOD_VHT: ++ case FORMATMOD_HE_SU: { ++ union rwnx_mcs_index *r = (union rwnx_mcs_index *)r_cfg; ++ ++ r_cfg->formatModTx = formatmod; ++ r->vht.nss = nss; ++ r->vht.mcs = mcs; ++ r_cfg->bwTx = bwTx; ++ r_cfg->giAndPreTypeTx = gi; ++ break; ++ } ++ case FORMATMOD_HE_MU: { ++ union rwnx_mcs_index *r = (union rwnx_mcs_index *)r_cfg; ++ ++ r_cfg->formatModTx = formatmod; ++ r->he.nss = nss; ++ r->he.mcs = mcs; ++ r_cfg->bwTx = 0; ++ r_cfg->giAndPreTypeTx = gi; ++ break; ++ } ++ default: ++ printk("Don't have the formatmod"); ++ } ++} ++ ++static ssize_t rwnx_dbgfs_rc_stats_read(struct file *file, ++ char __user *user_buf, size_t count, ++ loff_t *ppos) ++{ ++ struct rwnx_sta *sta = NULL; ++ struct rwnx_hw *priv = file->private_data; ++ char *buf; ++ int bufsz, len = 0; ++ ssize_t read; ++ int i = 0; ++ int error = 0; ++ struct me_rc_stats_cfm me_rc_stats_cfm; ++ unsigned int no_samples; ++ struct st *st; ++ u8 mac[6]; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* everything should fit in one call */ ++ if (*ppos) ++ return 0; ++ ++ /* Get the station index from MAC address */ ++ sscanf(file->f_path.dentry->d_parent->d_iname, ++ "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mac[0], &mac[1], &mac[2], ++ &mac[3], &mac[4], &mac[5]); ++ //if (mac == NULL) ++ // return 0; ++ sta = rwnx_get_sta(priv, mac); ++ if (sta == NULL) ++ return 0; ++ ++ /* Forward the information to the LMAC */ ++ error = rwnx_send_me_rc_stats(priv, sta->sta_idx, &me_rc_stats_cfm); ++ if (error) ++ return error; ++ ++ no_samples = me_rc_stats_cfm.no_samples; ++ if (no_samples == 0) ++ return 0; ++ ++ bufsz = no_samples * LINE_MAX_SZ + 500; ++ ++ buf = kmalloc(bufsz + 1, GFP_ATOMIC); ++ if (buf == NULL) ++ return 0; ++ ++ st = kmalloc(sizeof(struct st) * no_samples, GFP_ATOMIC); ++ if (st == NULL) { ++ kfree(buf); ++ return 0; ++ } ++ ++ for (i = 0; i < no_samples; i++) { ++ unsigned int tp, eprob; ++ len = print_rate_from_cfg( ++ st[i].line, LINE_MAX_SZ, ++ me_rc_stats_cfm.rate_stats[i].rate_config, &st[i].r_idx, ++ 0); ++ ++ if (me_rc_stats_cfm.sw_retry_step != 0) { ++ len += scnprintf( ++ &st[i].line[len], LINE_MAX_SZ - len, "%c", ++ me_rc_stats_cfm.retry_step_idx ++ [me_rc_stats_cfm ++ .sw_retry_step] == ++ i ? ++ '*' : ++ ' '); ++ } else { ++ len += scnprintf(&st[i].line[len], LINE_MAX_SZ - len, ++ " "); ++ } ++ len += scnprintf(&st[i].line[len], LINE_MAX_SZ - len, "%c", ++ me_rc_stats_cfm.retry_step_idx[0] == i ? 'T' : ++ ' '); ++ len += scnprintf(&st[i].line[len], LINE_MAX_SZ - len, "%c", ++ me_rc_stats_cfm.retry_step_idx[1] == i ? 't' : ++ ' '); ++ len += scnprintf(&st[i].line[len], LINE_MAX_SZ - len, "%c ", ++ me_rc_stats_cfm.retry_step_idx[2] == i ? 'P' : ++ ' '); ++ ++ tp = me_rc_stats_cfm.tp[i] / 10; ++ len += scnprintf(&st[i].line[len], LINE_MAX_SZ - len, ++ " %4u.%1u", tp / 10, tp % 10); ++ ++ eprob = ((me_rc_stats_cfm.rate_stats[i].probability * 1000) >> ++ 16) + ++ 1; ++ len += scnprintf(&st[i].line[len], LINE_MAX_SZ - len, ++ " %4u.%1u %5u(%6u) %6u", eprob / 10, ++ eprob % 10, ++ me_rc_stats_cfm.rate_stats[i].success, ++ me_rc_stats_cfm.rate_stats[i].attempts, ++ me_rc_stats_cfm.rate_stats[i].sample_skipped); ++ } ++ len = scnprintf(buf, bufsz, ++ "\nTX rate info for %02X:%02X:%02X:%02X:%02X:%02X:\n", ++ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); ++ ++ len += scnprintf( ++ &buf[len], bufsz - len, ++ " # type rate tpt eprob ok( tot) skipped\n"); ++ ++ // add sorted statistics to the buffer ++ sort(st, no_samples, sizeof(st[0]), compare_idx, NULL); ++ for (i = 0; i < no_samples; i++) { ++ len += scnprintf(&buf[len], bufsz - len, "%s\n", st[i].line); ++ } ++ ++ // display HE TB statistics if any ++ if (me_rc_stats_cfm.rate_stats[RC_HE_STATS_IDX].rate_config != 0) { ++ unsigned int tp, eprob; ++ struct rc_rate_stats *rate_stats = ++ &me_rc_stats_cfm.rate_stats[RC_HE_STATS_IDX]; ++ int ru_index = rate_stats->ru_and_length & 0x07; ++ int ul_length = rate_stats->ru_and_length >> 3; ++ ++ len += scnprintf(&buf[len], bufsz - len, ++ "\nHE TB rate info:\n"); ++ ++ len += scnprintf( ++ &buf[len], bufsz - len, ++ " type rate tpt eprob ok( tot) ul_length\n "); ++ len += print_rate_from_cfg(&buf[len], bufsz - len, ++ rate_stats->rate_config, NULL, ++ ru_index); ++ ++ tp = me_rc_stats_cfm.tp[RC_HE_STATS_IDX] / 10; ++ len += scnprintf(&buf[len], bufsz - len, " %4u.%1u", ++ tp / 10, tp % 10); ++ ++ eprob = ((rate_stats->probability * 1000) >> 16) + 1; ++ len += scnprintf(&buf[len], bufsz - len, ++ " %4u.%1u %5u(%6u) %6u\n", eprob / 10, ++ eprob % 10, rate_stats->success, ++ rate_stats->attempts, ul_length); ++ } ++ ++ len += scnprintf(&buf[len], bufsz - len, ++ "\n MPDUs AMPDUs AvLen trialP"); ++ len += scnprintf(&buf[len], bufsz - len, "\n%6u %6u %3d.%1d %6u\n", ++ me_rc_stats_cfm.ampdu_len, ++ me_rc_stats_cfm.ampdu_packets, ++ me_rc_stats_cfm.avg_ampdu_len >> 16, ++ ((me_rc_stats_cfm.avg_ampdu_len * 10) >> 16) % 10, ++ me_rc_stats_cfm.sample_wait); ++ ++ read = simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ ++ kfree(buf); ++ kfree(st); ++ ++ return read; ++} ++ ++DEBUGFS_READ_FILE_OPS(rc_stats); ++ ++static ssize_t rwnx_dbgfs_rc_fixed_rate_idx_write(struct file *file, ++ const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct rwnx_sta *sta = NULL; ++ struct rwnx_hw *priv = file->private_data; ++ u8 mac[6]; ++ char buf[20]; ++ int fixed_rate_idx = 1; ++ unsigned int formatmod, mcs, nss, bwTx, gi; ++ union rwnx_rate_ctrl_info rate_config; ++ union rwnx_rate_ctrl_info *r_cfg = &rate_config; ++ int error = 0; ++ size_t len = min_t(size_t, count, sizeof(buf) - 1); ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Get the station index from MAC address */ ++ sscanf(file->f_path.dentry->d_parent->d_iname, ++ "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mac[0], &mac[1], &mac[2], ++ &mac[3], &mac[4], &mac[5]); ++ //if (mac == NULL) ++ // return 0; ++ sta = rwnx_get_sta(priv, mac); ++ if (sta == NULL) ++ return 0; ++ ++ /* Get the content of the file */ ++ if (copy_from_user(buf, user_buf, len)) ++ return -EFAULT; ++ buf[len] = '\0'; ++ //sscanf(buf, "%i\n", &fixed_rate_idx); ++ sscanf(buf, "%u %u %u %u %u", &formatmod, &mcs, &nss, &bwTx, &gi); ++ printk("%u %u %u %u %u\n", formatmod, mcs, nss, bwTx, gi); ++ ++ if ((formatmod > 6) || (mcs > 11) || (nss > 8) || (bwTx > 6) || ++ (gi > 3)) { ++ printk("error parameter"); ++ return len; ++ } ++ ++ /* Convert rate index into rate configuration */ ++ if ((fixed_rate_idx < 0) || ++ (fixed_rate_idx >= (N_CCK + N_OFDM + N_HT + N_VHT + N_HE_SU))) { ++ // disable fixed rate ++ rate_config.value = (u32)-1; ++ } else { ++ //idx_to_rate_cfg(fixed_rate_idx, &rate_config, NULL); ++ idx_to_rate_cfg1(formatmod, mcs, nss, bwTx, gi, &rate_config, ++ NULL); ++ } ++ ++ printk("formatModTx=%u mcsIndexTx=%u bwTx=%u giAndPreTypeTx=%u\n", ++ r_cfg->formatModTx, r_cfg->mcsIndexTx, r_cfg->bwTx, ++ r_cfg->giAndPreTypeTx); ++ // Forward the request to the LMAC ++ if ((error = rwnx_send_me_rc_set_rate(priv, sta->sta_idx, ++ (u16)rate_config.value)) != 0) { ++ return error; ++ } ++ ++ printk("send success \n"); ++ priv->debugfs.rc_config[sta->sta_idx] = (int)rate_config.value; ++ return len; ++} ++ ++DEBUGFS_WRITE_FILE_OPS(rc_fixed_rate_idx); ++ ++static ssize_t rwnx_dbgfs_last_rx_read(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct rwnx_sta *sta = NULL; ++ struct rwnx_hw *priv = file->private_data; ++ struct rwnx_rx_rate_stats *rate_stats; ++ char *buf; ++ int bufsz, i, len = 0; ++ ssize_t read; ++ unsigned int fmt, pre, bw, nss, mcs, gi; ++ u8 mac[6]; ++ struct rx_vector_1 *last_rx; ++ char hist[] = "##################################################"; ++ int hist_len = sizeof(hist) - 1; ++ u8 nrx; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* everything should fit in one call */ ++ if (*ppos) ++ return 0; ++ ++ /* Get the station index from MAC address */ ++ sscanf(file->f_path.dentry->d_parent->d_iname, ++ "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mac[0], &mac[1], &mac[2], ++ &mac[3], &mac[4], &mac[5]); ++ // if (mac == NULL) ++ // return 0; ++ sta = rwnx_get_sta(priv, mac); ++ if (sta == NULL) ++ return 0; ++ ++ rate_stats = &sta->stats.rx_rate; ++ bufsz = (rate_stats->rate_cnt * (50 + hist_len) + 200); ++ buf = kmalloc(bufsz + 1, GFP_ATOMIC); ++ if (buf == NULL) ++ return 0; ++ ++ // Get number of RX paths ++ nrx = (priv->version_cfm.version_phy_1 & MDM_NRX_MASK) >> MDM_NRX_LSB; ++ ++ len += scnprintf(buf, bufsz, ++ "\nRX rate info for %02X:%02X:%02X:%02X:%02X:%02X:\n", ++ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); ++ ++ // Display Statistics ++ for (i = 0; i < rate_stats->size; i++) { ++ if (rate_stats->table[i]) { ++ union rwnx_rate_ctrl_info rate_config; ++ int percent = ++ (rate_stats->table[i] * 1000) / rate_stats->cpt; ++ int p = 0; ++ int ru_size = 0; ++ ++ idx_to_rate_cfg(i, &rate_config, &ru_size); ++ len += print_rate_from_cfg(&buf[len], bufsz - len, ++ rate_config.value, NULL, ++ ru_size); ++ p = (percent * hist_len) / 1000; ++ len += scnprintf(&buf[len], bufsz - len, ++ ": %6d(%3d.%1d%%)%.*s\n", ++ rate_stats->table[i], percent / 10, ++ percent % 10, p, hist); ++ } ++ } ++ ++ // Display detailed info of the last received rate ++ last_rx = &sta->stats.last_rx.rx_vect1; ++ ++ len += scnprintf( ++ &buf[len], bufsz - len, ++ "\nLast received rate\n" ++ " type rate LDPC STBC BEAMFM DCM DOPPLER %s\n", ++ (nrx > 1) ? "rssi1(dBm) rssi2(dBm)" : "rssi(dBm)"); ++ ++ fmt = last_rx->format_mod; ++ bw = last_rx->ch_bw; ++ pre = last_rx->pre_type; ++ if (fmt >= FORMATMOD_HE_SU) { ++ mcs = last_rx->he.mcs; ++ nss = last_rx->he.nss; ++ gi = last_rx->he.gi_type; ++ if (fmt == FORMATMOD_HE_MU) ++ bw = last_rx->he.ru_size; ++ } else if (fmt == FORMATMOD_VHT) { ++ mcs = last_rx->vht.mcs; ++ nss = last_rx->vht.nss; ++ gi = last_rx->vht.short_gi; ++ } else if (fmt >= FORMATMOD_HT_MF) { ++ mcs = last_rx->ht.mcs % 8; ++ nss = last_rx->ht.mcs / 8; ++ ; ++ gi = last_rx->ht.short_gi; ++ } else { ++ BUG_ON((mcs = legrates_lut[last_rx->leg_rate].idx) == -1); ++ nss = 0; ++ gi = 0; ++ } ++ ++ len += print_rate(&buf[len], bufsz - len, fmt, nss, mcs, bw, gi, pre, ++ NULL); ++ ++ /* flags for HT/VHT/HE */ ++ if (fmt >= FORMATMOD_HE_SU) { ++ len += scnprintf(&buf[len], bufsz - len, ++ " %c %c %c %c %c", ++ last_rx->he.fec ? 'L' : ' ', ++ last_rx->he.stbc ? 'S' : ' ', ++ last_rx->he.beamformed ? 'B' : ' ', ++ last_rx->he.dcm ? 'D' : ' ', ++ last_rx->he.doppler ? 'D' : ' '); ++ } else if (fmt == FORMATMOD_VHT) { ++ len += scnprintf(&buf[len], bufsz - len, ++ " %c %c %c ", ++ last_rx->vht.fec ? 'L' : ' ', ++ last_rx->vht.stbc ? 'S' : ' ', ++ last_rx->vht.beamformed ? 'B' : ' '); ++ } else if (fmt >= FORMATMOD_HT_MF) { ++ len += scnprintf(&buf[len], bufsz - len, ++ " %c %c ", ++ last_rx->ht.fec ? 'L' : ' ', ++ last_rx->ht.stbc ? 'S' : ' '); ++ } else { ++ len += scnprintf(&buf[len], bufsz - len, ++ " "); ++ } ++ if (nrx > 1) { ++ len += scnprintf(&buf[len], bufsz - len, ++ " %-4d %d\n", last_rx->rssi1, ++ last_rx->rssi1); ++ } else { ++ len += scnprintf(&buf[len], bufsz - len, " %d\n", ++ last_rx->rssi1); ++ } ++ ++ read = simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ ++ kfree(buf); ++ return read; ++} ++ ++static ssize_t rwnx_dbgfs_last_rx_write(struct file *file, ++ const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct rwnx_sta *sta = NULL; ++ struct rwnx_hw *priv = file->private_data; ++ u8 mac[6]; ++ ++ /* Get the station index from MAC address */ ++ sscanf(file->f_path.dentry->d_parent->d_iname, ++ "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mac[0], &mac[1], &mac[2], ++ &mac[3], &mac[4], &mac[5]); ++ // if (mac == NULL) ++ // return 0; ++ sta = rwnx_get_sta(priv, mac); ++ if (sta == NULL) ++ return 0; ++ ++ /* Prevent from interrupt preemption as these statistics are updated under ++ * interrupt */ ++ spin_lock_bh(&priv->tx_lock); ++ memset(sta->stats.rx_rate.table, 0, ++ sta->stats.rx_rate.size * sizeof(sta->stats.rx_rate.table[0])); ++ sta->stats.rx_rate.cpt = 0; ++ sta->stats.rx_rate.rate_cnt = 0; ++ spin_unlock_bh(&priv->tx_lock); ++ ++ return count; ++} ++ ++DEBUGFS_READ_WRITE_FILE_OPS(last_rx); ++ ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++#ifdef CONFIG_RWNX_FULLMAC ++static void rwnx_rc_stat_work(struct work_struct *ws) ++{ ++ struct rwnx_debugfs *rwnx_debugfs = ++ container_of(ws, struct rwnx_debugfs, rc_stat_work); ++ struct rwnx_hw *rwnx_hw = ++ container_of(rwnx_debugfs, struct rwnx_hw, debugfs); ++ struct rwnx_sta *sta; ++ uint8_t ridx, sta_idx; ++ ++ ridx = rwnx_debugfs->rc_read; ++ sta_idx = rwnx_debugfs->rc_sta[ridx]; ++ if (sta_idx > (NX_REMOTE_STA_MAX + NX_VIRT_DEV_MAX)) { ++ WARN(1, "Invalid sta index %d", sta_idx); ++ return; ++ } ++ ++ rwnx_debugfs->rc_sta[ridx] = 0xFF; ++ ridx = (ridx + 1) % ARRAY_SIZE(rwnx_debugfs->rc_sta); ++ rwnx_debugfs->rc_read = ridx; ++ sta = &rwnx_hw->sta_table[sta_idx]; ++ if (!sta) { ++ WARN(1, "Invalid sta %d", sta_idx); ++ return; ++ } ++ ++ if (rwnx_debugfs->dir_sta[sta_idx] == NULL) { ++ /* register the sta */ ++ struct dentry *dir_rc = rwnx_debugfs->dir_rc; ++ struct dentry *dir_sta; ++ struct dentry *file; ++ char sta_name[18]; ++ struct rwnx_rx_rate_stats *rate_stats = &sta->stats.rx_rate; ++ int nb_rx_rate = N_CCK + N_OFDM; ++ struct rwnx_rc_config_save *rc_cfg, *next; ++ ++ if (sta->sta_idx >= NX_REMOTE_STA_MAX) { ++ scnprintf(sta_name, sizeof(sta_name), "bc_mc"); ++ } else { ++ scnprintf(sta_name, sizeof(sta_name), "%pM", ++ sta->mac_addr); ++ } ++ ++ dir_sta = debugfs_create_dir(sta_name, dir_rc); ++ if (!dir_sta) ++ goto error; ++ ++ rwnx_debugfs->dir_sta[sta->sta_idx] = dir_sta; ++ ++ file = debugfs_create_file("stats", S_IRUSR, dir_sta, rwnx_hw, ++ &rwnx_dbgfs_rc_stats_ops); ++ if (IS_ERR_OR_NULL(file)) ++ goto error_after_dir; ++ ++ file = debugfs_create_file("fixed_rate_idx", S_IWUSR, dir_sta, ++ rwnx_hw, ++ &rwnx_dbgfs_rc_fixed_rate_idx_ops); ++ if (IS_ERR_OR_NULL(file)) ++ goto error_after_dir; ++ ++ file = debugfs_create_file("rx_rate", S_IRUSR | S_IWUSR, ++ dir_sta, rwnx_hw, ++ &rwnx_dbgfs_last_rx_ops); ++ if (IS_ERR_OR_NULL(file)) ++ goto error_after_dir; ++ ++ if (rwnx_hw->mod_params->ht_on) ++ nb_rx_rate += N_HT; ++ ++ if (rwnx_hw->mod_params->vht_on) ++ nb_rx_rate += N_VHT; ++ ++ if (rwnx_hw->mod_params->he_on) ++ nb_rx_rate += N_HE_SU + N_HE_MU; ++ ++ rate_stats->table = kzalloc( ++ nb_rx_rate * sizeof(rate_stats->table[0]), GFP_KERNEL); ++ if (!rate_stats->table) ++ goto error_after_dir; ++ ++ rate_stats->size = nb_rx_rate; ++ rate_stats->cpt = 0; ++ rate_stats->rate_cnt = 0; ++ ++ /* By default enable rate contoller */ ++ rwnx_debugfs->rc_config[sta_idx] = -1; ++ ++ /* Unless we already fix the rate for this station */ ++ list_for_each_entry_safe (rc_cfg, next, ++ &rwnx_debugfs->rc_config_save, list) { ++ if (jiffies_to_msecs(jiffies - rc_cfg->timestamp) > ++ RC_CONFIG_DUR) { ++ list_del(&rc_cfg->list); ++ kfree(rc_cfg); ++ } else if (!memcmp(rc_cfg->mac_addr, sta->mac_addr, ++ ETH_ALEN)) { ++ rwnx_debugfs->rc_config[sta_idx] = rc_cfg->rate; ++ list_del(&rc_cfg->list); ++ kfree(rc_cfg); ++ break; ++ } ++ } ++ ++ if ((rwnx_debugfs->rc_config[sta_idx] >= 0) && ++ rwnx_send_me_rc_set_rate( ++ rwnx_hw, sta_idx, ++ (u16)rwnx_debugfs->rc_config[sta_idx])) ++ rwnx_debugfs->rc_config[sta_idx] = -1; ++ ++ } else { ++ /* unregister the sta */ ++ if (sta->stats.rx_rate.table) { ++ kfree(sta->stats.rx_rate.table); ++ sta->stats.rx_rate.table = NULL; ++ } ++ sta->stats.rx_rate.size = 0; ++ sta->stats.rx_rate.cpt = 0; ++ sta->stats.rx_rate.rate_cnt = 0; ++ ++ /* If fix rate was set for this station, save the configuration in case ++ we reconnect to this station within RC_CONFIG_DUR msec */ ++ if (rwnx_debugfs->rc_config[sta_idx] >= 0) { ++ struct rwnx_rc_config_save *rc_cfg; ++ rc_cfg = kmalloc(sizeof(*rc_cfg), GFP_KERNEL); ++ if (rc_cfg) { ++ rc_cfg->rate = rwnx_debugfs->rc_config[sta_idx]; ++ rc_cfg->timestamp = jiffies; ++ memcpy(rc_cfg->mac_addr, sta->mac_addr, ++ ETH_ALEN); ++ list_add_tail(&rc_cfg->list, ++ &rwnx_debugfs->rc_config_save); ++ } ++ } ++ ++ debugfs_remove_recursive(rwnx_debugfs->dir_sta[sta_idx]); ++ rwnx_debugfs->dir_sta[sta->sta_idx] = NULL; ++ } ++ ++ return; ++ ++error_after_dir: ++ debugfs_remove_recursive(rwnx_debugfs->dir_sta[sta_idx]); ++ rwnx_debugfs->dir_sta[sta->sta_idx] = NULL; ++error: ++ dev_err(rwnx_hw->dev, ++ "Error while (un)registering debug entry for sta %d\n", ++ sta_idx); ++} ++ ++void _rwnx_dbgfs_rc_stat_write(struct rwnx_debugfs *rwnx_debugfs, ++ uint8_t sta_idx) ++{ ++ uint8_t widx = rwnx_debugfs->rc_write; ++ if (rwnx_debugfs->rc_sta[widx] != 0XFF) { ++ WARN(1, "Overlap in debugfs rc_sta table\n"); ++ } ++ ++ if (rwnx_debugfs->unregistering) ++ return; ++ ++ rwnx_debugfs->rc_sta[widx] = sta_idx; ++ widx = (widx + 1) % ARRAY_SIZE(rwnx_debugfs->rc_sta); ++ rwnx_debugfs->rc_write = widx; ++ ++ schedule_work(&rwnx_debugfs->rc_stat_work); ++} ++ ++void rwnx_dbgfs_register_rc_stat(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta) ++{ ++ _rwnx_dbgfs_rc_stat_write(&rwnx_hw->debugfs, sta->sta_idx); ++} ++ ++void rwnx_dbgfs_unregister_rc_stat(struct rwnx_hw *rwnx_hw, ++ struct rwnx_sta *sta) ++{ ++ _rwnx_dbgfs_rc_stat_write(&rwnx_hw->debugfs, sta->sta_idx); ++} ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++int rwnx_dbgfs_register(struct rwnx_hw *rwnx_hw, const char *name) ++{ ++#ifdef CONFIG_RWNX_FULLMAC ++ struct dentry *phyd = rwnx_hw->wiphy->debugfsdir; ++ struct dentry *dir_rc; ++#endif /* CONFIG_RWNX_FULLMAC */ ++ 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; ++ ++ rwnx_debugfs->dir = dir_drv; ++ rwnx_debugfs->unregistering = false; ++ ++ dir_diags = debugfs_create_dir("diags", dir_drv); ++ if (!dir_diags) ++ goto err; ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ dir_rc = debugfs_create_dir("rc", dir_drv); ++ if (!dir_rc) ++ goto err; ++ rwnx_debugfs->dir_rc = dir_rc; ++ INIT_WORK(&rwnx_debugfs->rc_stat_work, rwnx_rc_stat_work); ++ INIT_LIST_HEAD(&rwnx_debugfs->rc_config_save); ++ rwnx_debugfs->rc_write = rwnx_debugfs->rc_read = 0; ++ memset(rwnx_debugfs->rc_sta, 0xFF, sizeof(rwnx_debugfs->rc_sta)); ++#endif ++ ++ DEBUGFS_ADD_U32(tcp_pacing_shift, dir_drv, &rwnx_hw->tcp_pacing_shift, ++ S_IWUSR | S_IRUSR); ++ DEBUGFS_ADD_FILE(stats, dir_drv, S_IWUSR | S_IRUSR); ++ DEBUGFS_ADD_FILE(sys_stats, dir_drv, S_IRUSR); ++ DEBUGFS_ADD_FILE(txq, dir_drv, S_IRUSR); ++ DEBUGFS_ADD_FILE(acsinfo, dir_drv, S_IRUSR); ++#ifdef CONFIG_RWNX_MUMIMO_TX ++ DEBUGFS_ADD_FILE(mu_group, dir_drv, S_IRUSR); ++#endif ++ DEBUGFS_ADD_FILE(regdbg, dir_drv, S_IWUSR); ++ DEBUGFS_ADD_FILE(vendor_hwconfig, dir_drv, S_IWUSR); ++ DEBUGFS_ADD_FILE(vendor_swconfig, dir_drv, S_IWUSR); ++ DEBUGFS_ADD_FILE(agg_disable, dir_drv, S_IWUSR); ++ DEBUGFS_ADD_FILE(set_roc, dir_drv, S_IWUSR); ++ ++#ifdef CONFIG_RWNX_P2P_DEBUGFS ++ { ++ /* Create a p2p directory */ ++ struct dentry *dir_p2p; ++ dir_p2p = debugfs_create_dir("p2p", dir_drv); ++ if (!dir_p2p) ++ goto err; ++ ++ /* Add file allowing to control Opportunistic PS */ ++ DEBUGFS_ADD_FILE(oppps, dir_p2p, S_IRUSR); ++ /* Add file allowing to control Notice of Absence */ ++ DEBUGFS_ADD_FILE(noa, dir_p2p, S_IRUSR); ++ } ++#endif /* CONFIG_RWNX_P2P_DEBUGFS */ ++ ++ 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; ++ dir_radar = debugfs_create_dir("radar", dir_drv); ++ if (!dir_radar) ++ goto err; ++ ++ DEBUGFS_ADD_FILE(pulses_prim, dir_radar, S_IRUSR); ++ DEBUGFS_ADD_FILE(detected, dir_radar, S_IRUSR); ++ DEBUGFS_ADD_FILE(enable, dir_radar, S_IRUSR); ++ ++ if (rwnx_hw->phy.cnt == 2) { ++ DEBUGFS_ADD_FILE(pulses_sec, dir_radar, S_IRUSR); ++ ++ dir_sec = debugfs_create_dir("sec", dir_radar); ++ if (!dir_sec) ++ goto err; ++ ++ DEBUGFS_ADD_FILE(band, dir_sec, S_IWUSR | S_IRUSR); ++ DEBUGFS_ADD_FILE(type, dir_sec, S_IWUSR | S_IRUSR); ++ DEBUGFS_ADD_FILE(prim20, dir_sec, S_IWUSR | S_IRUSR); ++ DEBUGFS_ADD_FILE(center1, dir_sec, S_IWUSR | S_IRUSR); ++ DEBUGFS_ADD_FILE(center2, dir_sec, S_IWUSR | S_IRUSR); ++ DEBUGFS_ADD_FILE(set, dir_sec, S_IWUSR | S_IRUSR); ++ } ++ } ++#endif /* CONFIG_RWNX_RADAR */ ++ return 0; ++ ++err: ++ rwnx_dbgfs_unregister(rwnx_hw); ++ return -ENOMEM; ++} ++ ++void rwnx_dbgfs_unregister(struct rwnx_hw *rwnx_hw) ++{ ++ struct rwnx_debugfs *rwnx_debugfs = &rwnx_hw->debugfs; ++#ifdef CONFIG_RWNX_FULLMAC ++ struct rwnx_rc_config_save *cfg, *next; ++#endif ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ list_for_each_entry_safe (cfg, next, &rwnx_debugfs->rc_config_save, ++ list) { ++ list_del(&cfg->list); ++ kfree(cfg); ++ } ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++ if (rwnx_hw->fwlog_en) ++ rwnx_fw_log_deinit(&rwnx_hw->debugfs.fw_log); ++ ++ if (!rwnx_hw->debugfs.dir) ++ return; ++ ++ rwnx_debugfs->unregistering = true; ++#ifdef CONFIG_RWNX_FULLMAC ++ flush_work(&rwnx_debugfs->rc_stat_work); ++#endif ++ debugfs_remove_recursive(rwnx_hw->debugfs.dir); ++ rwnx_hw->debugfs.dir = NULL; ++} ++ ++#endif /* CONFIG_DEBUG_FS */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_debugfs.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_debugfs.h +new file mode 100755 +index 000000000..4889f2457 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_debugfs.h +@@ -0,0 +1,212 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_debugfs.h ++ * ++ * @brief Miscellaneous utility function definitions ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++#ifndef _RWNX_DEBUGFS_H_ ++#define _RWNX_DEBUGFS_H_ ++#include ++ ++#include ++#include ++#include "rwnx_fw_trace.h" ++ ++struct rwnx_hw; ++struct rwnx_sta; ++ ++/* some macros taken from iwlwifi */ ++/* TODO: replace with generic read and fill read buffer in open to avoid double ++ * reads */ ++#define DEBUGFS_ADD_FILE(name, parent, mode) \ ++ do { \ ++ if (!debugfs_create_file(#name, mode, parent, rwnx_hw, \ ++ &rwnx_dbgfs_##name##_ops)) \ ++ goto err; \ ++ } while (0) ++ ++#define DEBUGFS_ADD_BOOL(name, parent, ptr) \ ++ do { \ ++ struct dentry *__tmp; \ ++ __tmp = debugfs_create_bool(#name, S_IWUSR | S_IRUSR, parent, \ ++ ptr); \ ++ if (IS_ERR(__tmp) || !__tmp) \ ++ goto err; \ ++ } while (0) ++ ++#define DEBUGFS_ADD_X64(name, parent, ptr) \ ++ do { \ ++ struct dentry *__tmp; \ ++ __tmp = debugfs_create_x64(#name, S_IWUSR | S_IRUSR, parent, \ ++ ptr); \ ++ if (IS_ERR(__tmp) || !__tmp) \ ++ goto err; \ ++ } while (0) ++ ++#define DEBUGFS_ADD_U64(name, parent, ptr, mode) \ ++ do { \ ++ struct dentry *__tmp; \ ++ __tmp = debugfs_create_u64(#name, mode, parent, ptr); \ ++ if (IS_ERR(__tmp) || !__tmp) \ ++ goto err; \ ++ } while (0) ++ ++#define DEBUGFS_ADD_X32(name, parent, ptr) \ ++ do { \ ++ struct dentry *__tmp; \ ++ __tmp = debugfs_create_x32(#name, S_IWUSR | S_IRUSR, parent, \ ++ ptr); \ ++ if (IS_ERR(__tmp) || !__tmp) \ ++ 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, parent, ptr); \ ++ if (IS_ERR(__tmp) || !__tmp) \ ++ goto err; \ ++ } while (0) ++#endif ++ ++/* file operation */ ++#define DEBUGFS_READ_FUNC(name) \ ++ static ssize_t rwnx_dbgfs_##name##_read(struct file *file, \ ++ char __user *user_buf, \ ++ size_t count, loff_t *ppos); ++ ++#define DEBUGFS_WRITE_FUNC(name) \ ++ static ssize_t rwnx_dbgfs_##name##_write(struct file *file, \ ++ const char __user *user_buf, \ ++ size_t count, loff_t *ppos); ++ ++#define DEBUGFS_OPEN_FUNC(name) \ ++ static int rwnx_dbgfs_##name##_open(struct inode *inode, \ ++ struct file *file); ++ ++#define DEBUGFS_RELEASE_FUNC(name) \ ++ static int rwnx_dbgfs_##name##_release(struct inode *inode, \ ++ struct file *file); ++ ++#define DEBUGFS_READ_FILE_OPS(name) \ ++ DEBUGFS_READ_FUNC(name); \ ++ static const struct file_operations rwnx_dbgfs_##name##_ops = { \ ++ .read = rwnx_dbgfs_##name##_read, \ ++ .open = simple_open, \ ++ .llseek = generic_file_llseek, \ ++ }; ++ ++#define DEBUGFS_WRITE_FILE_OPS(name) \ ++ DEBUGFS_WRITE_FUNC(name); \ ++ static const struct file_operations rwnx_dbgfs_##name##_ops = { \ ++ .write = rwnx_dbgfs_##name##_write, \ ++ .open = simple_open, \ ++ .llseek = generic_file_llseek, \ ++ }; ++ ++#define DEBUGFS_READ_WRITE_FILE_OPS(name) \ ++ DEBUGFS_READ_FUNC(name); \ ++ DEBUGFS_WRITE_FUNC(name); \ ++ static const struct file_operations rwnx_dbgfs_##name##_ops = { \ ++ .write = rwnx_dbgfs_##name##_write, \ ++ .read = rwnx_dbgfs_##name##_read, \ ++ .open = simple_open, \ ++ .llseek = generic_file_llseek, \ ++ }; ++ ++#define DEBUGFS_READ_WRITE_OPEN_RELEASE_FILE_OPS(name) \ ++ DEBUGFS_READ_FUNC(name); \ ++ DEBUGFS_WRITE_FUNC(name); \ ++ DEBUGFS_OPEN_FUNC(name); \ ++ DEBUGFS_RELEASE_FUNC(name); \ ++ static const struct file_operations rwnx_dbgfs_##name##_ops = { \ ++ .write = rwnx_dbgfs_##name##_write, \ ++ .read = rwnx_dbgfs_##name##_read, \ ++ .open = rwnx_dbgfs_##name##_open, \ ++ .release = rwnx_dbgfs_##name##_release, \ ++ .llseek = generic_file_llseek, \ ++ }; ++ ++#ifdef CONFIG_RWNX_DEBUGFS ++ ++struct rwnx_debugfs { ++ unsigned long long rateidx; ++ struct dentry *dir; ++ bool trace_prst; ++ ++ char helper_cmd[64]; ++ //struct work_struct helper_work; ++ bool helper_scheduled; ++ spinlock_t umh_lock; ++ bool unregistering; ++ ++#ifndef CONFIG_RWNX_FHOST ++ struct rwnx_fw_log fw_log; ++#endif /* CONFIG_RWNX_FHOST */ ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ struct work_struct rc_stat_work; ++ uint8_t rc_sta[NX_REMOTE_STA_MAX]; ++ uint8_t rc_write; ++ uint8_t rc_read; ++ struct dentry *dir_rc; ++ struct dentry *dir_sta[NX_REMOTE_STA_MAX]; ++ int rc_config[NX_REMOTE_STA_MAX]; ++ struct list_head rc_config_save; ++#endif ++}; ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ ++// Max duration in msecs to save rate config for a sta after disconnection ++#define RC_CONFIG_DUR 600000 ++ ++struct rwnx_rc_config_save { ++ struct list_head list; ++ unsigned long timestamp; ++ int rate; ++ u8 mac_addr[ETH_ALEN]; ++}; ++#endif ++ ++int rwnx_dbgfs_register(struct rwnx_hw *rwnx_hw, const char *name); ++void rwnx_dbgfs_unregister(struct rwnx_hw *rwnx_hw); ++#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 ++#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) ++{ ++} ++#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 ++#endif /* CONFIG_RWNX_DEBUGFS */ ++ ++#endif /* _RWNX_DEBUGFS_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_defs.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_defs.h +new file mode 100755 +index 000000000..0a302771e +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_defs.h +@@ -0,0 +1,779 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_defs.h ++ * ++ * @brief Main driver structure declarations for fullmac driver ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++#ifndef _RWNX_DEFS_H_ ++#define _RWNX_DEFS_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rwnx_mod_params.h" ++#include "rwnx_debugfs.h" ++#include "rwnx_tx.h" ++#include "rwnx_rx.h" ++#include "rwnx_radar.h" ++#include "rwnx_utils.h" ++#include "rwnx_mu_group.h" ++#include "rwnx_platform.h" ++#include "rwnx_cmds.h" ++#ifdef CONFIG_GKI ++#include "rwnx_gki.h" ++#endif ++#include "rwnx_compat.h" ++#ifdef CONFIG_FILTER_TCP_ACK ++#include "aicwf_tcp_ack.h" ++#endif ++ ++#ifdef AICWF_SDIO_SUPPORT ++#include "aicwf_sdio.h" ++#include "sdio_host.h" ++#endif ++ ++#ifdef AICWF_USB_SUPPORT ++#include "usb_host.h" ++#endif ++ ++#ifdef CONFIG_BR_SUPPORT ++#include "aic_br_ext.h" ++#endif /* CONFIG_BR_SUPPORT */ ++ ++#define WPI_HDR_LEN 18 ++#define WPI_PN_LEN 16 ++#define WPI_PN_OFST 2 ++#define WPI_MIC_LEN 16 ++#define WPI_KEY_LEN 32 ++#define WPI_SUBKEY_LEN 16 // WPI key is actually two 16bytes key ++ ++#define LEGACY_PS_ID 0 ++#define UAPSD_ID 1 ++ ++#define PS_SP_INTERRUPTED 255 ++#define MAC_ADDR_LEN 6 ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0) || \ ++ defined(CONFIG_VHT_FOR_OLD_KERNEL) ++enum nl80211_ac { ++ NL80211_AC_VO, ++ NL80211_AC_VI, ++ NL80211_AC_BE, ++ NL80211_AC_BK, ++ NL80211_NUM_ACS ++}; ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0) || \ ++ defined(CONFIG_VHT_FOR_OLD_KERNEL) ++struct ieee80211_vht_operation { ++ u8 vht_op_info_chwidth; ++ u8 vht_op_info_chan_center_freq_seg1_idx; ++ u8 vht_op_info_chan_center_freq_seg2_idx; ++ __le16 vht_basic_mcs_set; ++} __packed; ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0) || \ ++ defined(CONFIG_VHT_FOR_OLD_KERNEL) ++#define IEEE80211_RADIOTAP_VHT 21 ++#define IEEE80211_RADIOTAP_VHT_KNOWN_GI 0x0004 ++#define IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH 0x0040 ++ ++#define IEEE80211_RADIOTAP_VHT_FLAG_STBC 0x01 ++#define IEEE80211_RADIOTAP_VHT_FLAG_SGI 0x04 ++ ++#define NL80211_FEATURE_CELL_BASE_REG_HINTS 1 << 3 ++#define NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL 1 << 4 ++#define NL80211_FEATURE_SAE 1 << 5 ++#define NL80211_FEATURE_LOW_PRIORITY_SCAN 1 << 6 ++#define NL80211_FEATURE_SCAN_FLUSH 1 << 7 ++#define NL80211_FEATURE_AP_SCAN 1 << 8 ++#define NL80211_FEATURE_VIF_TXPOWER 1 << 9 ++#define NL80211_FEATURE_NEED_OBSS_SCAN 1 << 10 ++#define NL80211_FEATURE_P2P_GO_CTWIN 1 << 11 ++#define NL80211_FEATURE_P2P_GO_OPPPS 1 << 12 ++ ++/* 802.11ac VHT Capabilities */ ++#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 0x00000000 ++#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 0x00000001 ++#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 0x00000002 ++#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ 0x00000004 ++#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ 0x00000008 ++#define IEEE80211_VHT_CAP_RXLDPC 0x00000010 ++#define IEEE80211_VHT_CAP_SHORT_GI_80 0x00000020 ++#define IEEE80211_VHT_CAP_SHORT_GI_160 0x00000040 ++#define IEEE80211_VHT_CAP_TXSTBC 0x00000080 ++#define IEEE80211_VHT_CAP_RXSTBC_1 0x00000100 ++#define IEEE80211_VHT_CAP_RXSTBC_2 0x00000200 ++#define IEEE80211_VHT_CAP_RXSTBC_3 0x00000300 ++#define IEEE80211_VHT_CAP_RXSTBC_4 0x00000400 ++#define IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE 0x00000800 ++#define IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE 0x00001000 ++#define IEEE80211_VHT_CAP_BEAMFORMER_ANTENNAS_MAX 0x00006000 ++#define IEEE80211_VHT_CAP_SOUNDING_DIMENTION_MAX 0x00030000 ++#define IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE 0x00080000 ++#define IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE 0x00100000 ++#define IEEE80211_VHT_CAP_VHT_TXOP_PS 0x00200000 ++#define IEEE80211_VHT_CAP_HTC_VHT 0x00400000 ++#define IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT 23 ++#define IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK \ ++ (7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT) ++#define IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB 0x08000000 ++#define IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB 0x0c000000 ++#define IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN 0x10000000 ++#define IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN 0x20000000 ++ ++enum ieee80211_vht_mcs_support { ++ IEEE80211_VHT_MCS_SUPPORT_0_7 = 0, ++ IEEE80211_VHT_MCS_SUPPORT_0_8 = 1, ++ IEEE80211_VHT_MCS_SUPPORT_0_9 = 2, ++ IEEE80211_VHT_MCS_NOT_SUPPORTED = 3, ++}; ++ ++enum nl80211_chan_width { ++ NL80211_CHAN_WIDTH_20_NOHT, ++ NL80211_CHAN_WIDTH_20, ++ NL80211_CHAN_WIDTH_40, ++ NL80211_CHAN_WIDTH_80, ++ NL80211_CHAN_WIDTH_80P80, ++ NL80211_CHAN_WIDTH_160, ++}; ++ ++struct cfg80211_chan_def { ++ struct ieee80211_channel *chan; ++ enum nl80211_chan_width width; ++ u32 center_freq1; ++ u32 center_freq2; ++}; ++ ++enum nl80211_mesh_power_mode { ++ NL80211_MESH_POWER_UNKNOWN, ++ NL80211_MESH_POWER_ACTIVE, ++ NL80211_MESH_POWER_LIGHT_SLEEP, ++ NL80211_MESH_POWER_DEEP_SLEEP, ++ __NL80211_MESH_POWER_AFTER_LAST, ++ NL80211_MESH_POWER_MAX = __NL80211_MESH_POWER_AFTER_LAST - 1 ++}; ++#endif ++ ++/** ++ * struct rwnx_bcn - Information of the beacon in used (AP mode) ++ * ++ * @head: head portion of beacon (before TIM IE) ++ * @tail: tail portion of beacon (after TIM IE) ++ * @ies: extra IEs (not used ?) ++ * @head_len: length of head data ++ * @tail_len: length of tail data ++ * @ies_len: length of extra IEs data ++ * @tim_len: length of TIM IE ++ * @len: Total beacon len (head + tim + tail + extra) ++ * @dtim: dtim period ++ */ ++struct rwnx_bcn { ++ u8 *head; ++ u8 *tail; ++ u8 *ies; ++ size_t head_len; ++ size_t tail_len; ++ size_t ies_len; ++ size_t tim_len; ++ size_t len; ++ u8 dtim; ++}; ++ ++/** ++ * struct rwnx_key - Key information ++ * ++ * @hw_idx: Idx of the key from hardware point of view ++ */ ++struct rwnx_key { ++ u8 hw_idx; ++}; ++ ++/** ++ * Structure containing information about a Mesh Path ++ */ ++struct rwnx_mesh_path { ++ struct list_head list; /* For rwnx_vif.mesh_paths */ ++ u8 path_idx; /* Path Index */ ++ struct mac_addr tgt_mac_addr; /* Target MAC Address */ ++ struct rwnx_sta *p_nhop_sta; /* Pointer to the Next Hop STA */ ++}; ++ ++struct rwnx_mesh_proxy { ++ struct list_head list; /* For rwnx_vif.mesh_proxy */ ++ struct mac_addr ext_sta_addr; /* Address of the External STA */ ++ struct mac_addr proxy_addr; /* Proxy MAC Address */ ++ bool local; /* Indicate if interface is a proxy for the device */ ++}; ++ ++/** ++ * struct rwnx_csa - Information for CSA (Channel Switch Announcement) ++ * ++ * @vif: Pointer to the vif doing the CSA ++ * @bcn: Beacon to use after CSA ++ * @elem: IPC buffer to send the new beacon to the fw ++ * @chandef: defines the channel to use after the switch ++ * @count: Current csa counter ++ * @status: Status of the CSA at fw level ++ * @ch_idx: Index of the new channel context ++ * @work: work scheduled at the end of CSA ++ */ ++struct rwnx_csa { ++ struct rwnx_vif *vif; ++ struct rwnx_bcn bcn; ++ struct rwnx_ipc_elem_var elem; ++ struct cfg80211_chan_def chandef; ++ int count; ++ int status; ++ int ch_idx; ++ 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) ++ TDLS_LINK_IDLE, ++ /// TDLS Setup Request transmitted ++ TDLS_SETUP_REQ_TX, ++ /// TDLS Setup Response transmitted ++ TDLS_SETUP_RSP_TX, ++ /// TDLS link is active (TDLS peer connected) ++ TDLS_LINK_ACTIVE, ++ /// TDLS Max Number of states. ++ TDLS_STATE_MAX ++}; ++ ++/* ++ * Structure used to save information relative to the TDLS peer. ++ * This is also linked within the rwnx_hw vifs list. ++ * ++ */ ++struct rwnx_tdls { ++ bool active; /* Indicate if TDLS link is active */ ++ bool initiator; /* Indicate if TDLS peer is the TDLS initiator */ ++ bool chsw_en; /* Indicate if channel switch is enabled */ ++ u8 last_tid; /* TID of the latest MPDU transmitted over the ++ TDLS direct link to the TDLS STA */ ++ u16 last_sn; /* Sequence number of the latest MPDU transmitted ++ over the TDLS direct link to the TDLS STA */ ++ bool ps_on; /* Indicate if the power save is enabled on the ++ TDLS STA */ ++ bool chsw_allowed; /* Indicate if TDLS channel switch is allowed */ ++}; ++ ++/** ++ * enum rwnx_ap_flags - AP flags ++ * ++ * @RWNX_AP_ISOLATE Isolate clients (i.e. Don't brige packets transmitted by ++ * one client for another one) ++ */ ++enum rwnx_ap_flags { ++ RWNX_AP_ISOLATE = BIT(0), ++}; ++ ++/* ++ * Structure used to save information relative to the managed interfaces. ++ * This is also linked within the rwnx_hw vifs list. ++ * ++ */ ++struct rwnx_vif { ++ struct list_head list; ++ struct rwnx_hw *rwnx_hw; ++ struct wireless_dev wdev; ++ struct net_device *ndev; ++ struct net_device_stats net_stats; ++ struct rwnx_key key[6]; ++ unsigned long drv_flags; ++ atomic_t drv_conn_state; ++ u8 drv_vif_index; /* Identifier of the VIF in driver */ ++ u8 vif_index; /* Identifier of the station in FW */ ++ u8 ch_index; /* Channel context identifier */ ++ bool up; /* Indicate if associated netdev is up ++ (i.e. Interface is created at fw level) */ ++ bool use_4addr; /* Should we use 4addresses mode */ ++ bool is_resending; /* Indicate if a frame is being resent on this interface */ ++ bool user_mpm; /* In case of Mesh Point VIF, indicate if MPM is handled by userspace */ ++ bool roc_tdls; /* Indicate if the ROC has been called by a ++ TDLS station */ ++ u8 tdls_status; /* Status of the TDLS link */ ++ bool tdls_chsw_prohibited; /* Indicate if TDLS Channel Switch is prohibited */ ++ bool wep_enabled; /* 1 if WEP is enabled */ ++ bool wep_auth_err; /* 1 if auth status code is not supported auth alg when WEP enabled */ ++ enum nl80211_auth_type ++ last_auth_type; /* Authentication type (algorithm) sent in the last connection ++ when WEP enabled */ ++ union { ++ struct { ++ struct rwnx_sta * ++ ap; /* Pointer to the peer STA entry allocated for ++ the AP */ ++ struct rwnx_sta ++ *tdls_sta; /* Pointer to the TDLS station */ ++ bool external_auth; /* Indicate if external authentication is in progress */ ++ u32 group_cipher_type; ++ u32 paired_cipher_type; ++ //connected network info start ++ char ssid[33]; //ssid max is 32, but this has one spare for '\0' ++ int ssid_len; ++ u8 bssid[ETH_ALEN]; ++ u32 conn_owner_nlportid; ++ bool is_roam; ++ //connected network info end ++ } sta; ++ struct { ++ u16 flags; /* see rwnx_ap_flags */ ++ struct list_head ++ sta_list; /* List of STA connected to the AP */ ++ struct rwnx_bcn bcn; /* beacon */ ++ u8 bcmc_index; /* Index of the BCMC sta to use */ ++#if (defined CONFIG_HE_FOR_OLD_KERNEL) || (defined CONFIG_VHT_FOR_OLD_KERNEL) ++ u8 aic_index; ++#endif ++ struct rwnx_csa *csa; ++ ++ struct list_head ++ mpath_list; /* List of Mesh Paths used on this interface */ ++ struct list_head ++ proxy_list; /* List of Proxies Information used on this interface */ ++ bool create_path; /* Indicate if we are waiting for a MESH_CREATE_PATH_CFM ++ message */ ++ int generation; /* Increased each time the list of Mesh Paths is updated */ ++ enum nl80211_mesh_power_mode ++ mesh_pm; /* mesh power save mode currently set in firmware */ ++ enum nl80211_mesh_power_mode ++ next_mesh_pm; /* mesh power save mode for next peer */ ++ } ap; ++ struct { ++ struct rwnx_vif *master; /* pointer on master interface */ ++ struct rwnx_sta *sta_4a; ++ } ap_vlan; ++ }; ++ ++ u8_l key_has_add; ++ u8_l is_p2p_vif; ++ struct apm_probe_sta sta_probe; ++ ++#ifdef CONFIG_BR_SUPPORT ++ spinlock_t br_ext_lock; ++ /* unsigned int macclone_completed; */ ++ struct nat25_network_db_entry *nethash[NAT25_HASH_SIZE]; ++ int pppoe_connection_in_progress; ++ unsigned char pppoe_addr[MACADDRLEN]; ++ unsigned char scdb_mac[MACADDRLEN]; ++ unsigned char scdb_ip[4]; ++ struct nat25_network_db_entry *scdb_entry; ++ unsigned char br_mac[MACADDRLEN]; ++ unsigned char br_ip[4]; ++ ++ struct br_ext_info ethBrExtInfo; ++#endif /* CONFIG_BR_SUPPORT */ ++}; ++ ++#define RWNX_VIF_TYPE(rwnx_vif) (rwnx_vif->wdev.iftype) ++ ++/** ++ * Structure used to store information relative to PS mode. ++ * ++ * @active: True when the sta is in PS mode. ++ * If false, other values should be ignored ++ * @pkt_ready: Number of packets buffered for the sta in drv's txq ++ * (1 counter for Legacy PS and 1 for U-APSD) ++ * @sp_cnt: Number of packets that remain to be pushed in the service period. ++ * 0 means that no service period is in progress ++ * (1 counter for Legacy PS and 1 for U-APSD) ++ */ ++struct rwnx_sta_ps { ++ bool active; ++ u16 pkt_ready[2]; ++ u16 sp_cnt[2]; ++}; ++ ++/** ++ * struct rwnx_rx_rate_stats - Store statistics for RX rates ++ * ++ * @table: Table indicating how many frame has been receive which each ++ * rate index. Rate index is the same as the one used by RC algo for TX ++ * @size: Size of the table array ++ * @cpt: number of frames received ++ */ ++struct rwnx_rx_rate_stats { ++ int *table; ++ int size; ++ int cpt; ++ int rate_cnt; ++}; ++ ++/** ++ * struct rwnx_sta_stats - Structure Used to store statistics specific to a STA ++ * ++ * @last_rx: Hardware vector of the last received frame ++ * @rx_rate: Statistics of the received rates ++ */ ++struct rwnx_sta_stats { ++ struct hw_vect last_rx; ++ struct rwnx_rx_rate_stats rx_rate; ++}; ++ ++#if (defined CONFIG_HE_FOR_OLD_KERNEL) || (defined CONFIG_VHT_FOR_OLD_KERNEL) ++struct aic_sta { ++ u8 sta_idx; /* Identifier of the station */ ++ bool he; /* Flag indicating if the station supports HE */ ++ bool vht; /* Flag indicating if the station supports VHT */ ++ ++ struct ieee80211_he_cap_elem he_cap_elem; ++ struct ieee80211_he_mcs_nss_supp he_mcs_nss_supp; ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0) || \ ++ defined(CONFIG_VHT_FOR_OLD_KERNEL) ++ __le32 vht_cap_info; ++ struct ieee80211_vht_mcs_info supp_mcs; ++#endif ++}; ++#endif ++ ++/* ++ * Structure used to save information relative to the managed stations. ++ */ ++struct rwnx_sta { ++ struct list_head list; ++ u16 aid; /* association ID */ ++ u8 sta_idx; /* Identifier of the station */ ++ u8 vif_idx; /* Identifier of the VIF (fw id) the station ++ belongs to */ ++ u8 vlan_idx; /* Identifier of the VLAN VIF (fw id) the station ++ belongs to (= vif_idx if no vlan in used) */ ++ enum nl80211_band band; /* Band */ ++ enum nl80211_chan_width width; /* Channel width */ ++ u16 center_freq; /* Center frequency */ ++ u32 center_freq1; /* Center frequency 1 */ ++ u32 center_freq2; /* Center frequency 2 */ ++ u8 ch_idx; /* Identifier of the channel ++ context the station belongs to */ ++ bool qos; /* Flag indicating if the station ++ supports QoS */ ++ u8 acm; /* Bitfield indicating which queues ++ have AC mandatory */ ++ u16 uapsd_tids; /* Bitfield indicating which tids are subject to ++ UAPSD */ ++ u8 mac_addr[ETH_ALEN]; /* MAC address of the station */ ++ struct rwnx_key key; ++ bool valid; /* Flag indicating if the entry is valid */ ++ struct rwnx_sta_ps ps; /* Information when STA is in PS (AP only) */ ++#ifdef CONFIG_RWNX_BFMER ++ struct rwnx_bfmer_report *bfm_report; /* Beamforming report to be used for ++ VHT TX Beamforming */ ++#ifdef CONFIG_RWNX_MUMIMO_TX ++ struct rwnx_sta_group_info ++ group_info; /* MU grouping information for the STA */ ++#endif /* CONFIG_RWNX_MUMIMO_TX */ ++#endif /* CONFIG_RWNX_BFMER */ ++ ++ bool ht; /* Flag indicating if the station ++ supports HT */ ++ bool vht; /* Flag indicating if the station ++ supports VHT */ ++ u32 ac_param[AC_MAX]; /* EDCA parameters */ ++ struct rwnx_tdls tdls; /* TDLS station information */ ++ struct rwnx_sta_stats stats; ++ enum nl80211_mesh_power_mode ++ mesh_pm; /* link-specific mesh power save mode */ ++}; ++ ++static inline const u8 *rwnx_sta_addr(struct rwnx_sta *rwnx_sta) ++{ ++ return rwnx_sta->mac_addr; ++} ++ ++#ifdef CONFIG_RWNX_SPLIT_TX_BUF ++struct rwnx_amsdu_stats { ++ int done; ++ int failed; ++}; ++#endif ++ ++struct rwnx_stats { ++ int cfm_balance[NX_TXQ_CNT]; ++ unsigned long last_rx, last_tx; /* jiffies */ ++ int ampdus_tx[IEEE80211_MAX_AMPDU_BUF]; ++ int ampdus_rx[IEEE80211_MAX_AMPDU_BUF]; ++ int ampdus_rx_map[4]; ++ int ampdus_rx_miss; ++#ifdef CONFIG_RWNX_SPLIT_TX_BUF ++ struct rwnx_amsdu_stats amsdus[NX_TX_PAYLOAD_MAX]; ++#endif ++ int amsdus_rx[64]; ++}; ++ ++struct rwnx_sec_phy_chan { ++ u16 prim20_freq; ++ u16 center_freq1; ++ u16 center_freq2; ++ enum nl80211_band band; ++ u8 type; ++}; ++ ++/* Structure that will contains all RoC information received from cfg80211 */ ++struct rwnx_roc_elem { ++ struct wireless_dev *wdev; ++ struct ieee80211_channel *chan; ++ unsigned int duration; ++ /* Used to avoid call of CFG80211 callback upon expiration of RoC */ ++ bool mgmt_roc; ++ /* Indicate if we have switch on the RoC channel */ ++ bool on_chan; ++}; ++ ++/* Structure containing channel survey information received from MAC */ ++struct rwnx_survey_info { ++ // Filled ++ u32 filled; ++ // Amount of time in ms the radio spent on the channel ++ u32 chan_time_ms; ++ // Amount of time the primary channel was sensed busy ++ u32 chan_time_busy_ms; ++ // Noise in dbm ++ s8 noise_dbm; ++}; ++ ++#define RWNX_CH_NOT_SET 0xFF ++#define RWNX_INVALID_VIF 0xFF ++#define RWNX_INVALID_STA 0xFF ++ ++/* Structure containing channel context information */ ++struct rwnx_chanctx { ++ struct cfg80211_chan_def chan_def; /* channel description */ ++ u8 count; /* number of vif using this ctxt */ ++}; ++ ++/** ++ * rwnx_phy_info - Phy information ++ * ++ * @phy_cnt: Number of phy interface ++ * @cfg: Configuration send to firmware ++ * @sec_chan: Channel configuration of the second phy interface (if phy_cnt > 1) ++ * @limit_bw: Set to true to limit BW on requested channel. Only set to use ++ * VHT with old radio that don't support 80MHz (deprecated) ++ */ ++struct rwnx_phy_info { ++ u8 cnt; ++ struct phy_cfg_tag cfg; ++ struct rwnx_sec_phy_chan sec_chan; ++ 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 rwnx_hw *rwnx_hw; ++}; ++ ++struct amsdu_subframe_hdr { ++ u8 da[6]; ++ u8 sa[6]; ++ u16 sublen; ++}; ++ ++/* rwnx driver status */ ++void rwnx_set_conn_state(atomic_t *drv_conn_state, int state); ++ ++enum rwnx_drv_connect_status { ++ RWNX_DRV_STATUS_DISCONNECTED = 0, ++ RWNX_DRV_STATUS_DISCONNECTING, ++ RWNX_DRV_STATUS_CONNECTING, ++ RWNX_DRV_STATUS_CONNECTED, ++ RWNX_DRV_STATUS_ROAMING, ++}; ++ ++static const char *const s_conn_state[] = { ++ "RWNX_DRV_STATUS_DISCONNECTED", "RWNX_DRV_STATUS_DISCONNECTING", ++ "RWNX_DRV_STATUS_CONNECTING", "RWNX_DRV_STATUS_CONNECTED", ++ "RWNX_DRV_STATUS_ROAMING", ++}; ++ ++struct rwnx_hw { ++ struct rwnx_mod_params *mod_params; ++ struct device *dev; ++#ifdef AICWF_SDIO_SUPPORT ++ struct aic_sdio_dev *sdiodev; ++#endif ++#ifdef AICWF_USB_SUPPORT ++ struct aic_usb_dev *usbdev; ++#endif ++ struct wiphy *wiphy; ++ struct list_head vifs; ++ struct rwnx_vif *vif_table[NX_VIRT_DEV_MAX + ++ NX_REMOTE_STA_MAX]; /* indexed with fw id */ ++ struct rwnx_sta sta_table[NX_REMOTE_STA_MAX + NX_VIRT_DEV_MAX]; ++#if (defined CONFIG_HE_FOR_OLD_KERNEL) || (defined CONFIG_VHT_FOR_OLD_KERNEL) ++ struct aic_sta aic_table[NX_REMOTE_STA_MAX + NX_VIRT_DEV_MAX]; ++#endif ++ struct rwnx_survey_info survey[SCAN_CHANNEL_MAX]; ++ struct cfg80211_scan_request *scan_request; ++#ifdef CONFIG_SCHED_SCAN ++ struct cfg80211_sched_scan_request *sched_scan_req; ++#endif ++ struct rwnx_chanctx chanctx_table[NX_CHAN_CTXT_CNT]; ++ u8 cur_chanctx; ++ ++ u8 monitor_vif; /* FW id of the monitor interface, RWNX_INVALID_VIF if no monitor vif at fw level */ ++ ++#ifdef CONFIG_FILTER_TCP_ACK ++ /* tcp ack management */ ++ struct tcp_ack_manage ack_m; ++#endif ++ ++ /* RoC Management */ ++ struct rwnx_roc_elem * ++ roc_elem; /* Information provided by cfg80211 in its remain on channel request */ ++ u32 roc_cookie_cnt; /* Counter used to identify RoC request sent by cfg80211 */ ++ ++ struct rwnx_cmd_mgr *cmd_mgr; ++ ++ struct rwnx_plat *plat; ++ ++ spinlock_t tx_lock; ++ spinlock_t cb_lock; ++ struct mutex mutex; /* per-device perimeter lock */ ++ ++ struct tasklet_struct task; ++ struct mm_version_cfm ++ version_cfm; /* Lower layers versions - obtained via MM_VERSION_REQ */ ++ ++ u32 tcp_pacing_shift; ++ ++ /* IPC */ ++ struct ipc_host_env_tag *ipc_env; ++#ifdef AICWF_SDIO_SUPPORT ++ struct sdio_host_env_tag sdio_env; ++#endif ++#ifdef AICWF_USB_SUPPORT ++ struct usb_host_env_tag usb_env; ++#endif ++ ++ struct rwnx_ipc_elem_pool e2amsgs_pool; ++ struct rwnx_ipc_elem_pool dbgmsgs_pool; ++ struct rwnx_ipc_elem_pool e2aradars_pool; ++ struct rwnx_ipc_elem_var pattern_elem; ++ struct rwnx_ipc_dbgdump_elem dbgdump_elem; ++ struct rwnx_ipc_elem_pool e2arxdesc_pool; ++ struct rwnx_ipc_skb_elem *e2aunsuprxvec_elems; ++ //struct rwnx_ipc_rxbuf_elems rxbuf_elems; ++ struct rwnx_ipc_elem_var scan_ie; ++ ++ struct kmem_cache *sw_txhdr_cache; ++ ++ struct rwnx_debugfs debugfs; ++ struct rwnx_stats stats; ++ ++#ifdef CONFIG_PREALLOC_TXQ ++ struct rwnx_txq *txq; ++#else ++ struct rwnx_txq txq[NX_NB_TXQ]; ++#endif ++ ++ struct rwnx_hwq hwq[NX_TXQ_CNT]; ++ ++ u64 avail_idx_map; ++ u8 vif_started; ++ bool adding_sta; ++ struct rwnx_phy_info phy; ++ ++ struct rwnx_radar radar; ++ ++ /* extended capabilities supported */ ++ u8 ext_capa[8]; ++ ++#ifdef CONFIG_RWNX_MUMIMO_TX ++ struct rwnx_mu_info mu; ++#endif ++ u8 is_p2p_alive; ++ u8 is_p2p_connected; ++ struct timer_list p2p_alive_timer; ++ 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_irqrx; ++ struct wakeup_source *ws_tx; ++ struct wakeup_source *ws_pwrctrl; ++ ++#ifdef CONFIG_SCHED_SCAN ++ bool is_sched_scan; ++#endif //CONFIG_SCHED_SCAN ++#ifdef CONFIG_TEMP_CONTROL ++ unsigned long started_jiffies; ++ s8_l temp; ++#endif ++}; ++ ++u8 *rwnx_build_bcn(struct rwnx_bcn *bcn, struct cfg80211_beacon_data *new); ++ ++void rwnx_chanctx_link(struct rwnx_vif *vif, u8 idx, ++ struct cfg80211_chan_def *chandef); ++void rwnx_chanctx_unlink(struct rwnx_vif *vif); ++int rwnx_chanctx_valid(struct rwnx_hw *rwnx_hw, u8 idx); ++ ++extern u8 chip_id; ++ ++static inline bool is_multicast_sta(int sta_idx) ++{ ++ if ((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8801) || ++ ((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DW) && ++ chip_id < 3)) { ++ return (sta_idx >= NX_REMOTE_STA_MAX_FOR_OLD_IC); ++ } else { ++ return (sta_idx >= NX_REMOTE_STA_MAX); ++ } ++} ++struct rwnx_sta *rwnx_get_sta(struct rwnx_hw *rwnx_hw, const u8 *mac_addr); ++ ++static inline uint8_t master_vif_idx(struct rwnx_vif *vif) ++{ ++ if (unlikely(vif->wdev.iftype == NL80211_IFTYPE_AP_VLAN)) { ++ return vif->ap_vlan.master->vif_index; ++ } else { ++ return vif->vif_index; ++ } ++} ++ ++void rwnx_external_auth_enable(struct rwnx_vif *vif); ++void rwnx_external_auth_disable(struct rwnx_vif *vif); ++ ++#endif /* _RWNX_DEFS_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_dini.c b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_dini.c +new file mode 100755 +index 000000000..fc2cbd5cb +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_dini.c +@@ -0,0 +1,299 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_dini.c - Add support for dini platform ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++#include "rwnx_dini.h" ++#include "rwnx_defs.h" ++#include "rwnx_irqs.h" ++#include "reg_access.h" ++ ++/* Config FPGA is accessed via bar0 */ ++#define CFPGA_DMA0_CTRL_REG 0x02C ++#define CFPGA_DMA1_CTRL_REG 0x04C ++#define CFPGA_DMA2_CTRL_REG 0x06C ++#define CFPGA_UINTR_SRC_REG 0x0E8 ++#define CFPGA_UINTR_MASK_REG 0x0EC ++#define CFPGA_BAR4_HIADDR_REG 0x100 ++#define CFPGA_BAR4_LOADDR_REG 0x104 ++#define CFPGA_BAR4_LOADDR_MASK_REG 0x110 ++#define CFPGA_BAR_TOUT 0x120 ++ ++#define CFPGA_DMA_CTRL_ENABLE 0x00001400 ++#define CFPGA_DMA_CTRL_DISABLE 0x00001000 ++#define CFPGA_DMA_CTRL_CLEAR 0x00001800 ++#define CFPGA_DMA_CTRL_REREAD_TIME_MASK (BIT(10) - 1) ++ ++#define CFPGA_BAR4_LOADDR_MASK_MAX 0xFF000000 ++ ++#define CFPGA_PCIEX_IT 0x00000001 ++#define CFPGA_ALL_ITS 0x0000000F ++ ++/* Programmable BAR4 Window start address */ ++#define CPU_RAM_WINDOW_HIGH 0x00000000 ++#define CPU_RAM_WINDOW_LOW 0x00000000 ++#define AHB_BRIDGE_WINDOW_HIGH 0x00000000 ++#define AHB_BRIDGE_WINDOW_LOW 0x60000000 ++ ++struct rwnx_dini { ++ u8 *pci_bar0_vaddr; ++ u8 *pci_bar4_vaddr; ++}; ++ ++static const u32 mv_cfg_fpga_dma_ctrl_regs[] = { CFPGA_DMA0_CTRL_REG, ++ CFPGA_DMA1_CTRL_REG, ++ CFPGA_DMA2_CTRL_REG }; ++ ++/* This also clears running transactions */ ++static void dini_dma_on(struct rwnx_dini *rwnx_dini) ++{ ++ int i; ++ u32 reread_time; ++ volatile void *reg; ++ ++ for (i = 0; i < ARRAY_SIZE(mv_cfg_fpga_dma_ctrl_regs); i++) { ++ reg = rwnx_dini->pci_bar0_vaddr + mv_cfg_fpga_dma_ctrl_regs[i]; ++ reread_time = readl(reg) & CFPGA_DMA_CTRL_REREAD_TIME_MASK; ++ ++ writel(CFPGA_DMA_CTRL_CLEAR | reread_time, reg); ++ writel(CFPGA_DMA_CTRL_ENABLE | reread_time, reg); ++ } ++} ++ ++/* This also clears running transactions */ ++static void dini_dma_off(struct rwnx_dini *rwnx_dini) ++{ ++ int i; ++ u32 reread_time; ++ volatile void *reg; ++ ++ for (i = 0; i < ARRAY_SIZE(mv_cfg_fpga_dma_ctrl_regs); i++) { ++ reg = rwnx_dini->pci_bar0_vaddr + mv_cfg_fpga_dma_ctrl_regs[i]; ++ reread_time = readl(reg) & CFPGA_DMA_CTRL_REREAD_TIME_MASK; ++ ++ writel(CFPGA_DMA_CTRL_DISABLE | reread_time, reg); ++ writel(CFPGA_DMA_CTRL_CLEAR | reread_time, reg); ++ } ++} ++ ++/* Configure address range for BAR4. ++ * By default BAR4_LOADDR_MASK value is 0xFF000000, then there is no need to ++ * change it because the addresses we need to access are covered by this mask ++ */ ++static void dini_set_bar4_win(u32 low, u32 high, struct rwnx_dini *rwnx_dini) ++{ ++ writel(low, rwnx_dini->pci_bar0_vaddr + CFPGA_BAR4_LOADDR_REG); ++ writel(high, rwnx_dini->pci_bar0_vaddr + CFPGA_BAR4_HIADDR_REG); ++ writel(CFPGA_BAR4_LOADDR_MASK_MAX, ++ rwnx_dini->pci_bar0_vaddr + CFPGA_BAR4_LOADDR_MASK_REG); ++} ++ ++/** ++ * Enable User Interrupts of CFPGA that trigger PCIe IRQs on PCIE_10 ++ * and request the corresponding IRQ line ++ */ ++int rwnx_cfpga_irq_enable(struct rwnx_hw *rwnx_hw) ++{ ++ struct rwnx_plat *rwnx_plat = rwnx_hw->plat; ++ struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv; ++ unsigned int cfpga_uintr_mask; ++ volatile void *reg; ++ int ret; ++ ++ /* sched_setscheduler on ONESHOT threaded irq handler for BCNs ? */ ++ ret = request_irq(rwnx_hw->plat->pci_dev->irq, rwnx_irq_hdlr, 0, "rwnx", ++ rwnx_hw); ++ if (ret) ++ return ret; ++ ++ reg = rwnx_dini->pci_bar0_vaddr + CFPGA_UINTR_MASK_REG; ++ cfpga_uintr_mask = readl(reg); ++ writel(cfpga_uintr_mask | CFPGA_PCIEX_IT, reg); ++ ++ return ret; ++} ++ ++/** ++ * Disable User Interrupts of CFPGA that trigger PCIe IRQs on PCIE_10 ++ * and free the corresponding IRQ line ++ */ ++int rwnx_cfpga_irq_disable(struct rwnx_hw *rwnx_hw) ++{ ++ struct rwnx_plat *rwnx_plat = rwnx_hw->plat; ++ struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv; ++ unsigned int cfpga_uintr_mask; ++ volatile void *reg; ++ ++ reg = rwnx_dini->pci_bar0_vaddr + CFPGA_UINTR_MASK_REG; ++ cfpga_uintr_mask = readl(reg); ++ writel(cfpga_uintr_mask & ~CFPGA_PCIEX_IT, reg); ++ ++ free_irq(rwnx_hw->plat->pci_dev->irq, rwnx_hw); ++ ++ return 0; ++} ++ ++static int rwnx_dini_platform_enable(struct rwnx_hw *rwnx_hw) ++{ ++ struct rwnx_plat *rwnx_plat = rwnx_hw->plat; ++ struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv; ++ ++#ifdef CONFIG_RWNX_SDM ++ writel(0x0000FFFF, rwnx_dini->pci_bar0_vaddr + CFPGA_BAR_TOUT); ++#endif ++ ++ dini_dma_on(rwnx_dini); ++ return rwnx_cfpga_irq_enable(rwnx_hw); ++} ++ ++static int rwnx_dini_platform_disable(struct rwnx_hw *rwnx_hw) ++{ ++ struct rwnx_plat *rwnx_plat = rwnx_hw->plat; ++ struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv; ++ int ret; ++ ++ ret = rwnx_cfpga_irq_disable(rwnx_hw); ++ dini_dma_off(rwnx_dini); ++ return ret; ++} ++ ++static void rwnx_dini_platform_deinit(struct rwnx_plat *rwnx_plat) ++{ ++ struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv; ++ ++ pci_disable_device(rwnx_plat->pci_dev); ++ iounmap(rwnx_dini->pci_bar0_vaddr); ++ iounmap(rwnx_dini->pci_bar4_vaddr); ++ pci_release_regions(rwnx_plat->pci_dev); ++ ++ kfree(rwnx_plat); ++} ++ ++static u8 *rwnx_dini_get_address(struct rwnx_plat *rwnx_plat, int addr_name, ++ unsigned int offset) ++{ ++ struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv; ++ ++ if (WARN(addr_name >= RWNX_ADDR_MAX, "Invalid address %d", addr_name)) ++ return NULL; ++ ++ if (addr_name == RWNX_ADDR_CPU) ++ dini_set_bar4_win(CPU_RAM_WINDOW_LOW, CPU_RAM_WINDOW_HIGH, ++ rwnx_dini); ++ else ++ dini_set_bar4_win(AHB_BRIDGE_WINDOW_LOW, AHB_BRIDGE_WINDOW_HIGH, ++ rwnx_dini); ++ ++ return rwnx_dini->pci_bar4_vaddr + offset; ++} ++ ++static void rwnx_dini_ack_irq(struct rwnx_plat *rwnx_plat) ++{ ++ struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv; ++ ++ writel(CFPGA_ALL_ITS, rwnx_dini->pci_bar0_vaddr + CFPGA_UINTR_SRC_REG); ++} ++ ++static const u32 rwnx_dini_config_reg[] = { ++ NXMAC_DEBUG_PORT_SEL_ADDR, ++ SYSCTRL_DIAG_CONF_ADDR, ++ RF_V6_DIAGPORT_CONF1_ADDR, ++ RF_v6_PHYDIAG_CONF1_ADDR, ++}; ++ ++static int rwnx_dini_get_config_reg(struct rwnx_plat *rwnx_plat, ++ const u32 **list) ++{ ++ if (!list) ++ return 0; ++ ++ *list = rwnx_dini_config_reg; ++ return ARRAY_SIZE(rwnx_dini_config_reg); ++} ++ ++/** ++ * rwnx_dini_platform_init - Initialize the DINI platform ++ * ++ * @pci_dev PCI device ++ * @rwnx_plat Pointer on struct rwnx_stat * to be populated ++ * ++ * @return 0 on success, < 0 otherwise ++ * ++ * Allocate and initialize a rwnx_plat structure for the dini platform. ++ */ ++int rwnx_dini_platform_init(struct pci_dev *pci_dev, ++ struct rwnx_plat **rwnx_plat) ++{ ++ struct rwnx_dini *rwnx_dini; ++ u16 pci_cmd; ++ int ret = 0; ++ ++ *rwnx_plat = ++ kzalloc(sizeof(struct rwnx_plat) + sizeof(struct rwnx_dini), ++ GFP_KERNEL); ++ if (!*rwnx_plat) ++ return -ENOMEM; ++ ++ rwnx_dini = (struct rwnx_dini *)(*rwnx_plat)->priv; ++ ++ /* Hotplug fixups */ ++ pci_read_config_word(pci_dev, PCI_COMMAND, &pci_cmd); ++ pci_cmd |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR; ++ pci_write_config_word(pci_dev, PCI_COMMAND, pci_cmd); ++ //pci_write_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES >> 2); ++ ++ ret = pci_enable_device(pci_dev); ++ if (ret) { ++ dev_err(&(pci_dev->dev), "pci_enable_device failed\n"); ++ goto out_enable; ++ } ++ ++ pci_set_master(pci_dev); ++#if 0 ++ ret = pci_request_regions(pci_dev, KBUILD_MODNAME); ++ if (ret) { ++ dev_err(&(pci_dev->dev), "pci_request_regions failed\n"); ++ goto out_request; ++ } ++#endif ++ rwnx_dini->pci_bar0_vaddr = (u8 *)pci_ioremap_bar(pci_dev, 0); ++ if (!rwnx_dini->pci_bar0_vaddr) { ++ dev_err(&(pci_dev->dev), "pci_ioremap_bar(%d) failed\n", 0); ++ ret = -ENOMEM; ++ goto out_bar0; ++ } ++ rwnx_dini->pci_bar4_vaddr = (u8 *)pci_ioremap_bar(pci_dev, 4); ++ if (!rwnx_dini->pci_bar4_vaddr) { ++ dev_err(&(pci_dev->dev), "pci_ioremap_bar(%d) failed\n", 4); ++ ret = -ENOMEM; ++ goto out_bar4; ++ } ++ ++ (*rwnx_plat)->enable = rwnx_dini_platform_enable; ++ (*rwnx_plat)->disable = rwnx_dini_platform_disable; ++ (*rwnx_plat)->deinit = rwnx_dini_platform_deinit; ++ (*rwnx_plat)->get_address = rwnx_dini_get_address; ++ (*rwnx_plat)->ack_irq = rwnx_dini_ack_irq; ++ (*rwnx_plat)->get_config_reg = rwnx_dini_get_config_reg; ++ ++#ifdef CONFIG_RWNX_SDM ++ writel(0x0000FFFF, rwnx_dini->pci_bar0_vaddr + CFPGA_BAR_TOUT); ++#endif ++ ++ return 0; ++ ++out_bar4: ++ iounmap(rwnx_dini->pci_bar0_vaddr); ++out_bar0: ++ pci_release_regions(pci_dev); ++ //out_request: ++ pci_disable_device(pci_dev); ++out_enable: ++ kfree(*rwnx_plat); ++ return ret; ++} +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_dini.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_dini.h +new file mode 100755 +index 000000000..fe2afd019 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_dini.h +@@ -0,0 +1,20 @@ ++/** ++ **************************************************************************************** ++ * ++ * @file rwnx_dini.h ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++#ifndef _RWNX_DINI_H_ ++#define _RWNX_DINI_H_ ++ ++#include ++#include "rwnx_platform.h" ++ ++int rwnx_dini_platform_init(struct pci_dev *pci_dev, ++ struct rwnx_plat **rwnx_plat); ++ ++#endif /* _RWNX_DINI_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_events.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_events.h +new file mode 100755 +index 000000000..aed044574 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_events.h +@@ -0,0 +1,1035 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_events.h ++ * ++ * @brief Trace events definition ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ ****************************************************************************** ++ */ ++#undef TRACE_SYSTEM ++#define TRACE_SYSTEM rwnx ++ ++#if !defined(_RWNX_EVENTS_H) || defined(TRACE_HEADER_MULTI_READ) ++#define _RWNX_EVENTS_H ++ ++#include ++#ifndef CONFIG_RWNX_FHOST ++#include "rwnx_tx.h" ++#endif ++#include "rwnx_compat.h" ++ ++/***************************************************************************** ++ * TRACE function for MGMT TX (FULLMAC) ++ ****************************************************************************/ ++#ifdef CONFIG_RWNX_FULLMAC ++#include "linux/ieee80211.h" ++#if defined(CONFIG_TRACEPOINTS) && defined(CREATE_TRACE_POINTS) ++#include ++ ++/* P2P Public Action Frames Definitions (see WiFi P2P Technical Specification, section 4.2.8) */ ++/* IEEE 802.11 Public Action Usage Category - Define P2P public action frames */ ++#define MGMT_ACTION_PUBLIC_CAT (0x04) ++/* Offset of OUI Subtype field in P2P Action Frame format */ ++#define MGMT_ACTION_OUI_SUBTYPE_OFFSET (6) ++/* P2P Public Action Frame Types */ ++enum p2p_action_type { ++ P2P_ACTION_GO_NEG_REQ = 0, /* GO Negociation Request */ ++ P2P_ACTION_GO_NEG_RSP, /* GO Negociation Response */ ++ P2P_ACTION_GO_NEG_CFM, /* GO Negociation Confirmation */ ++ P2P_ACTION_INVIT_REQ, /* P2P Invitation Request */ ++ P2P_ACTION_INVIT_RSP, /* P2P Invitation Response */ ++ P2P_ACTION_DEV_DISC_REQ, /* Device Discoverability Request */ ++ P2P_ACTION_DEV_DISC_RSP, /* Device Discoverability Response */ ++ P2P_ACTION_PROV_DISC_REQ, /* Provision Discovery Request */ ++ P2P_ACTION_PROV_DISC_RSP, /* Provision Discovery Response */ ++}; ++ ++const char *ftrace_print_mgmt_info(struct trace_seq *p, u16 frame_control, ++ u8 cat, u8 type, u8 p2p) ++{ ++ const char *ret = trace_seq_buffer_ptr(p); ++ ++ switch (frame_control & IEEE80211_FCTL_STYPE) { ++ case (IEEE80211_STYPE_ASSOC_REQ): ++ trace_seq_printf(p, "Association Request"); ++ break; ++ case (IEEE80211_STYPE_ASSOC_RESP): ++ trace_seq_printf(p, "Association Response"); ++ break; ++ case (IEEE80211_STYPE_REASSOC_REQ): ++ trace_seq_printf(p, "Reassociation Request"); ++ break; ++ case (IEEE80211_STYPE_REASSOC_RESP): ++ trace_seq_printf(p, "Reassociation Response"); ++ break; ++ case (IEEE80211_STYPE_PROBE_REQ): ++ trace_seq_printf(p, "Probe Request"); ++ break; ++ case (IEEE80211_STYPE_PROBE_RESP): ++ trace_seq_printf(p, "Probe Response"); ++ break; ++ case (IEEE80211_STYPE_BEACON): ++ trace_seq_printf(p, "Beacon"); ++ break; ++ case (IEEE80211_STYPE_ATIM): ++ trace_seq_printf(p, "ATIM"); ++ break; ++ case (IEEE80211_STYPE_DISASSOC): ++ trace_seq_printf(p, "Disassociation"); ++ break; ++ case (IEEE80211_STYPE_AUTH): ++ trace_seq_printf(p, "Authentication"); ++ break; ++ case (IEEE80211_STYPE_DEAUTH): ++ trace_seq_printf(p, "Deauthentication"); ++ break; ++ case (IEEE80211_STYPE_ACTION): ++ trace_seq_printf(p, "Action"); ++ if (cat == MGMT_ACTION_PUBLIC_CAT && type == 0x9) { ++ switch (p2p) { ++ case (P2P_ACTION_GO_NEG_REQ): ++ trace_seq_printf(p, ": GO Negociation Request"); ++ break; ++ case (P2P_ACTION_GO_NEG_RSP): ++ trace_seq_printf(p, ++ ": GO Negociation Response"); ++ break; ++ case (P2P_ACTION_GO_NEG_CFM): ++ trace_seq_printf( ++ p, ": GO Negociation Confirmation"); ++ break; ++ case (P2P_ACTION_INVIT_REQ): ++ trace_seq_printf(p, ": P2P Invitation Request"); ++ break; ++ case (P2P_ACTION_INVIT_RSP): ++ trace_seq_printf(p, ++ ": P2P Invitation Response"); ++ break; ++ case (P2P_ACTION_DEV_DISC_REQ): ++ trace_seq_printf( ++ p, ": Device Discoverability Request"); ++ break; ++ case (P2P_ACTION_DEV_DISC_RSP): ++ trace_seq_printf( ++ p, ": Device Discoverability Response"); ++ break; ++ case (P2P_ACTION_PROV_DISC_REQ): ++ trace_seq_printf( ++ p, ": Provision Discovery Request"); ++ break; ++ case (P2P_ACTION_PROV_DISC_RSP): ++ trace_seq_printf( ++ p, ": Provision Discovery Response"); ++ break; ++ default: ++ trace_seq_printf(p, "Unknown p2p %d", p2p); ++ break; ++ } ++ } else { ++ switch (cat) { ++ case 0: ++ trace_seq_printf(p, ":Spectrum %d", type); ++ break; ++ case 1: ++ trace_seq_printf(p, ":QOS %d", type); ++ break; ++ case 2: ++ trace_seq_printf(p, ":DLS %d", type); ++ break; ++ case 3: ++ trace_seq_printf(p, ":BA %d", type); ++ break; ++ case 4: ++ trace_seq_printf(p, ":Public %d", type); ++ break; ++ case 5: ++ trace_seq_printf(p, ":Radio Measure %d", type); ++ break; ++ case 6: ++ trace_seq_printf(p, ":Fast BSS %d", type); ++ break; ++ case 7: ++ trace_seq_printf(p, ":HT Action %d", type); ++ break; ++ case 8: ++ trace_seq_printf(p, ":SA Query %d", type); ++ break; ++ case 9: ++ trace_seq_printf(p, ":Protected Public %d", ++ type); ++ break; ++ case 10: ++ trace_seq_printf(p, ":WNM %d", type); ++ break; ++ case 11: ++ trace_seq_printf(p, ":Unprotected WNM %d", ++ type); ++ break; ++ case 12: ++ trace_seq_printf(p, ":TDLS %d", type); ++ break; ++ case 13: ++ trace_seq_printf(p, ":Mesh %d", type); ++ break; ++ case 14: ++ trace_seq_printf(p, ":MultiHop %d", type); ++ break; ++ case 15: ++ trace_seq_printf(p, ":Self Protected %d", type); ++ break; ++ case 126: ++ trace_seq_printf(p, ":Vendor protected"); ++ break; ++ case 127: ++ trace_seq_printf(p, ":Vendor"); ++ break; ++ default: ++ trace_seq_printf(p, ":Unknown category %d", ++ cat); ++ break; ++ } ++ } ++ break; ++ default: ++ trace_seq_printf(p, "Unknown subtype %d", ++ frame_control & IEEE80211_FCTL_STYPE); ++ break; ++ } ++ ++ trace_seq_putc(p, 0); ++ ++ return ret; ++} ++#endif /* defined(CONFIG_TRACEPOINTS) && defined(CREATE_TRACE_POINTS) */ ++ ++#undef __print_mgmt_info ++#define __print_mgmt_info(frame_control, cat, type, p2p) \ ++ ftrace_print_mgmt_info(p, frame_control, cat, type, p2p) ++ ++TRACE_EVENT(roc, TP_PROTO(u8 vif_idx, u16 freq, unsigned int duration), ++ TP_ARGS(vif_idx, freq, duration), ++ TP_STRUCT__entry(__field(u8, vif_idx) __field(u16, freq) ++ __field(unsigned int, duration)), ++ TP_fast_assign(__entry->vif_idx = vif_idx; __entry->freq = freq; ++ __entry->duration = duration;), ++ TP_printk("f=%d vif=%d dur=%d", __entry->freq, __entry->vif_idx, ++ __entry->duration)); ++ ++TRACE_EVENT(cancel_roc, TP_PROTO(u8 vif_idx), TP_ARGS(vif_idx), ++ TP_STRUCT__entry(__field(u8, vif_idx)), ++ TP_fast_assign(__entry->vif_idx = vif_idx;), ++ TP_printk("vif=%d", __entry->vif_idx)); ++ ++TRACE_EVENT(roc_exp, TP_PROTO(u8 vif_idx), TP_ARGS(vif_idx), ++ TP_STRUCT__entry(__field(u8, vif_idx)), ++ TP_fast_assign(__entry->vif_idx = vif_idx;), ++ TP_printk("vif=%d", __entry->vif_idx)); ++ ++TRACE_EVENT(switch_roc, TP_PROTO(u8 vif_idx), TP_ARGS(vif_idx), ++ TP_STRUCT__entry(__field(u8, vif_idx)), ++ TP_fast_assign(__entry->vif_idx = vif_idx;), ++ TP_printk("vif=%d", __entry->vif_idx)); ++ ++DECLARE_EVENT_CLASS( ++ mgmt_template, ++ TP_PROTO(u16 freq, u8 vif_idx, u8 sta_idx, struct ieee80211_mgmt *mgmt), ++ TP_ARGS(freq, vif_idx, sta_idx, mgmt), ++ TP_STRUCT__entry(__field(u16, freq) __field(u8, vif_idx) __field( ++ u8, sta_idx) __field(u16, frame_control) __field(u8, action_cat) ++ __field(u8, action_type) ++ __field(u8, action_p2p)), ++ TP_fast_assign( ++ __entry->freq = freq; __entry->vif_idx = vif_idx; ++ __entry->sta_idx = sta_idx; ++ __entry->frame_control = mgmt->frame_control; ++ __entry->action_cat = mgmt->u.action.category; ++ __entry->action_type = mgmt->u.action.u.wme_action.action_code; ++ __entry->action_p2p = *((u8 *)&mgmt->u.action.category + ++ MGMT_ACTION_OUI_SUBTYPE_OFFSET);), ++ TP_printk("f=%d vif=%d sta=%d -> %s", __entry->freq, __entry->vif_idx, ++ __entry->sta_idx, ++ __print_mgmt_info(__entry->frame_control, __entry->action_cat, ++ __entry->action_type, ++ __entry->action_p2p))); ++ ++DEFINE_EVENT(mgmt_template, mgmt_tx, ++ TP_PROTO(u16 freq, u8 vif_idx, u8 sta_idx, ++ struct ieee80211_mgmt *mgmt), ++ TP_ARGS(freq, vif_idx, sta_idx, mgmt)); ++ ++DEFINE_EVENT(mgmt_template, mgmt_rx, ++ TP_PROTO(u16 freq, u8 vif_idx, u8 sta_idx, ++ struct ieee80211_mgmt *mgmt), ++ TP_ARGS(freq, vif_idx, sta_idx, mgmt)); ++ ++TRACE_EVENT(mgmt_cfm, TP_PROTO(u8 vif_idx, u8 sta_idx, bool acked), ++ TP_ARGS(vif_idx, sta_idx, acked), ++ TP_STRUCT__entry(__field(u8, vif_idx) __field(u8, sta_idx) ++ __field(bool, acked)), ++ TP_fast_assign(__entry->vif_idx = vif_idx; ++ __entry->sta_idx = sta_idx; __entry->acked = acked;), ++ TP_printk("vif=%d sta=%d ack=%d", __entry->vif_idx, ++ __entry->sta_idx, __entry->acked)); ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++/***************************************************************************** ++ * TRACE function for TXQ ++ ****************************************************************************/ ++#ifndef CONFIG_RWNX_FHOST ++#if defined(CONFIG_TRACEPOINTS) && defined(CREATE_TRACE_POINTS) ++ ++#include ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) ++#include ++#else ++#include ++#endif ++ ++const char *ftrace_print_txq(struct trace_seq *p, int txq_idx) ++{ ++ const char *ret = trace_seq_buffer_ptr(p); ++ ++ if (txq_idx == TXQ_INACTIVE) { ++ trace_seq_printf(p, "[INACTIVE]"); ++ } else if (txq_idx < NX_FIRST_VIF_TXQ_IDX) { ++ trace_seq_printf(p, "[STA %d/%d]", txq_idx / NX_NB_TXQ_PER_STA, ++ txq_idx % NX_NB_TXQ_PER_STA); ++#ifdef CONFIG_RWNX_FULLMAC ++ } else if (txq_idx < NX_FIRST_UNK_TXQ_IDX) { ++ trace_seq_printf(p, "[BC/MC %d]", ++ txq_idx - NX_FIRST_BCMC_TXQ_IDX); ++ } else if (txq_idx < NX_OFF_CHAN_TXQ_IDX) { ++ trace_seq_printf(p, "[UNKNOWN %d]", ++ txq_idx - NX_FIRST_UNK_TXQ_IDX); ++ } else if (txq_idx == NX_OFF_CHAN_TXQ_IDX) { ++ trace_seq_printf(p, "[OFFCHAN]"); ++#else ++ } else if (txq_idx < NX_NB_TXQ) { ++ txq_idx -= NX_FIRST_VIF_TXQ_IDX; ++ trace_seq_printf(p, "[VIF %d/%d]", txq_idx / NX_NB_TXQ_PER_VIF, ++ txq_idx % NX_NB_TXQ_PER_VIF); ++#endif ++ } else { ++ trace_seq_printf(p, "[ERROR %d]", txq_idx); ++ } ++ ++ trace_seq_putc(p, 0); ++ ++ return ret; ++} ++ ++const char *ftrace_print_sta(struct trace_seq *p, int sta_idx) ++{ ++ const char *ret = trace_seq_buffer_ptr(p); ++ ++ if (sta_idx < NX_REMOTE_STA_MAX) { ++ trace_seq_printf(p, "[STA %d]", sta_idx); ++ } else { ++ trace_seq_printf(p, "[BC/MC %d]", sta_idx - NX_REMOTE_STA_MAX); ++ } ++ ++ trace_seq_putc(p, 0); ++ ++ return ret; ++} ++ ++const char *ftrace_print_hwq(struct trace_seq *p, int hwq_idx) ++{ ++ static const struct trace_print_flags symbols[] = { ++ { RWNX_HWQ_BK, "BK" }, ++ { RWNX_HWQ_BE, "BE" }, ++ { RWNX_HWQ_VI, "VI" }, ++ { RWNX_HWQ_VO, "VO" }, ++#ifdef CONFIG_RWNX_FULLMAC ++ { RWNX_HWQ_BCMC, "BCMC" }, ++#else ++ { RWNX_HWQ_BCN, "BCN" }, ++#endif ++ { -1, NULL } ++ }; ++ return trace_print_symbols_seq(p, hwq_idx, symbols); ++} ++ ++const char *ftrace_print_hwq_cred(struct trace_seq *p, u8 *cred) ++{ ++ const char *ret = trace_seq_buffer_ptr(p); ++ ++#if CONFIG_USER_MAX == 1 ++ trace_seq_printf(p, "%d", cred[0]); ++#else ++ int i; ++ ++ for (i = 0; i < CONFIG_USER_MAX - 1; i++) ++ trace_seq_printf(p, "%d-", cred[i]); ++ trace_seq_printf(p, "%d", cred[i]); ++#endif ++ ++ trace_seq_putc(p, 0); ++ return ret; ++} ++ ++const char *ftrace_print_mu_info(struct trace_seq *p, u8 mu_info) ++{ ++ const char *ret = trace_seq_buffer_ptr(p); ++ ++ if (mu_info) ++ trace_seq_printf(p, "MU: %d-%d", (mu_info & 0x3f), ++ (mu_info >> 6)); ++ ++ trace_seq_putc(p, 0); ++ return ret; ++} ++ ++const char *ftrace_print_mu_group(struct trace_seq *p, int nb_user, u8 *users) ++{ ++ const char *ret = trace_seq_buffer_ptr(p); ++ int i; ++ ++ if (users[0] != 0xff) ++ trace_seq_printf(p, "(%d", users[0]); ++ else ++ trace_seq_printf(p, "(-"); ++ for (i = 1; i < CONFIG_USER_MAX; i++) { ++ if (users[i] != 0xff) ++ trace_seq_printf(p, ",%d", users[i]); ++ else ++ trace_seq_printf(p, ",-"); ++ } ++ ++ trace_seq_printf(p, ")"); ++ trace_seq_putc(p, 0); ++ return ret; ++} ++ ++const char *ftrace_print_amsdu(struct trace_seq *p, u16 nb_pkt) ++{ ++ const char *ret = trace_seq_buffer_ptr(p); ++ ++ if (nb_pkt > 1) ++ trace_seq_printf(p, "(AMSDU %d)", nb_pkt); ++ ++ trace_seq_putc(p, 0); ++ return ret; ++} ++#endif /* defined(CONFIG_TRACEPOINTS) && defined(CREATE_TRACE_POINTS) */ ++ ++#undef __print_txq ++#define __print_txq(txq_idx) ftrace_print_txq(p, txq_idx) ++ ++#undef __print_sta ++#define __print_sta(sta_idx) ftrace_print_sta(p, sta_idx) ++ ++#undef __print_hwq ++#define __print_hwq(hwq) ftrace_print_hwq(p, hwq) ++ ++#undef __print_hwq_cred ++#define __print_hwq_cred(cred) ftrace_print_hwq_cred(p, cred) ++ ++#undef __print_mu_info ++#define __print_mu_info(mu_info) ftrace_print_mu_info(p, mu_info) ++ ++#undef __print_mu_group ++#define __print_mu_group(nb, users) ftrace_print_mu_group(p, nb, users) ++ ++#undef __print_amsdu ++#define __print_amsdu(nb_pkt) ftrace_print_amsdu(p, nb_pkt) ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ ++TRACE_EVENT(txq_select, ++ TP_PROTO(int txq_idx, u16 pkt_ready_up, struct sk_buff *skb), ++ TP_ARGS(txq_idx, pkt_ready_up, skb), ++ TP_STRUCT__entry(__field(u16, txq_idx) __field(u16, pkt_ready) ++ __field(struct sk_buff *, skb)), ++ TP_fast_assign(__entry->txq_idx = txq_idx; ++ __entry->pkt_ready = pkt_ready_up; ++ __entry->skb = skb;), ++ TP_printk("%s pkt_ready_up=%d skb=%p", ++ __print_txq(__entry->txq_idx), __entry->pkt_ready, ++ __entry->skb)); ++ ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++DECLARE_EVENT_CLASS(hwq_template, TP_PROTO(u8 hwq_idx), TP_ARGS(hwq_idx), ++ TP_STRUCT__entry(__field(u8, hwq_idx)), ++ TP_fast_assign(__entry->hwq_idx = hwq_idx;), ++ TP_printk("%s", __print_hwq(__entry->hwq_idx))); ++ ++DEFINE_EVENT(hwq_template, hwq_flowctrl_stop, TP_PROTO(u8 hwq_idx), ++ TP_ARGS(hwq_idx)); ++ ++DEFINE_EVENT(hwq_template, hwq_flowctrl_start, TP_PROTO(u8 hwq_idx), ++ TP_ARGS(hwq_idx)); ++ ++DECLARE_EVENT_CLASS(txq_template, TP_PROTO(struct rwnx_txq *txq), TP_ARGS(txq), ++ TP_STRUCT__entry(__field(u16, txq_idx)), ++ TP_fast_assign(__entry->txq_idx = txq->idx;), ++ TP_printk("%s", __print_txq(__entry->txq_idx))); ++ ++DEFINE_EVENT(txq_template, txq_add_to_hw, TP_PROTO(struct rwnx_txq *txq), ++ TP_ARGS(txq)); ++ ++DEFINE_EVENT(txq_template, txq_del_from_hw, TP_PROTO(struct rwnx_txq *txq), ++ TP_ARGS(txq)); ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ ++DEFINE_EVENT(txq_template, txq_flowctrl_stop, TP_PROTO(struct rwnx_txq *txq), ++ TP_ARGS(txq)); ++ ++DEFINE_EVENT(txq_template, txq_flowctrl_restart, TP_PROTO(struct rwnx_txq *txq), ++ TP_ARGS(txq)); ++ ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++TRACE_EVENT(process_txq, TP_PROTO(struct rwnx_txq *txq), TP_ARGS(txq), ++ TP_STRUCT__entry(__field(u16, txq_idx) __field(u16, len) ++ __field(u16, len_retry) __field(s8, credit) ++#ifdef CONFIG_RWNX_FULLMAC ++ __field(u16, limit) ++#endif /* CONFIG_RWNX_FULLMAC*/ ++ ), ++ TP_fast_assign(__entry->txq_idx = txq->idx; ++ __entry->len = skb_queue_len(&txq->sk_list); ++#ifdef CONFIG_MAC80211_TXQ ++ __entry->len += txq->nb_ready_mac80211; ++#endif ++ __entry->len_retry = txq->nb_retry; ++ __entry->credit = txq->credits; ++#ifdef CONFIG_RWNX_FULLMAC ++ __entry->limit = txq->push_limit; ++#endif /* CONFIG_RWNX_FULLMAC*/ ++ ), ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ TP_printk("%s txq_credits=%d, len=%d, retry_len=%d, push_limit=%d", ++ __print_txq(__entry->txq_idx), __entry->credit, ++ __entry->len, __entry->len_retry, __entry->limit) ++#else ++ TP_printk("%s txq_credits=%d, len=%d, retry_len=%d", ++ __print_txq(__entry->txq_idx), __entry->credit, ++ __entry->len, __entry->len_retry) ++#endif /* CONFIG_RWNX_FULLMAC*/ ++); ++ ++DECLARE_EVENT_CLASS( ++ txq_reason_template, TP_PROTO(struct rwnx_txq *txq, u16 reason), ++ TP_ARGS(txq, reason), ++ TP_STRUCT__entry(__field(u16, txq_idx) __field(u16, reason) ++ __field(u16, status)), ++ TP_fast_assign(__entry->txq_idx = txq->idx; __entry->reason = reason; ++ __entry->status = txq->status;), ++ TP_printk("%s reason=%s status=%s", __print_txq(__entry->txq_idx), ++ __print_symbolic(__entry->reason, ++ { RWNX_TXQ_STOP_FULL, "FULL" }, ++ { RWNX_TXQ_STOP_CSA, "CSA" }, ++ { RWNX_TXQ_STOP_STA_PS, "PS" }, ++ { RWNX_TXQ_STOP_VIF_PS, "VPS" }, ++ { RWNX_TXQ_STOP_CHAN, "CHAN" }, ++ { RWNX_TXQ_STOP_MU_POS, "MU" }), ++ __print_flags(__entry->status, "|", ++ { RWNX_TXQ_IN_HWQ_LIST, "IN LIST" }, ++ { RWNX_TXQ_STOP_FULL, "FULL" }, ++ { RWNX_TXQ_STOP_CSA, "CSA" }, ++ { RWNX_TXQ_STOP_STA_PS, "PS" }, ++ { RWNX_TXQ_STOP_VIF_PS, "VPS" }, ++ { RWNX_TXQ_STOP_CHAN, "CHAN" }, ++ { RWNX_TXQ_STOP_MU_POS, "MU" }, ++ { RWNX_TXQ_NDEV_FLOW_CTRL, "FLW_CTRL" }))); ++ ++DEFINE_EVENT(txq_reason_template, txq_start, ++ TP_PROTO(struct rwnx_txq *txq, u16 reason), TP_ARGS(txq, reason)); ++ ++DEFINE_EVENT(txq_reason_template, txq_stop, ++ TP_PROTO(struct rwnx_txq *txq, u16 reason), TP_ARGS(txq, reason)); ++ ++TRACE_EVENT( ++ push_desc, ++ TP_PROTO(struct sk_buff *skb, struct rwnx_sw_txhdr *sw_txhdr, ++ int push_flags), ++ ++ TP_ARGS(skb, sw_txhdr, push_flags), ++ ++ TP_STRUCT__entry(__field(struct sk_buff *, skb) __field( ++ unsigned int, len) __field(u16, tx_queue) __field(u8, hw_queue) ++ __field(u8, push_flag) __field(u32, flag) ++ __field(s8, txq_cred) __field(u8, ++ hwq_cred) ++ __field(u16, pkt_cnt) ++ __field(u8, mu_info)), ++ TP_fast_assign(__entry->skb = skb; ++ __entry->tx_queue = sw_txhdr->txq->idx; ++ __entry->push_flag = push_flags; ++ __entry->hw_queue = sw_txhdr->txq->hwq->id; ++ __entry->txq_cred = sw_txhdr->txq->credits; ++#ifdef CONFIG_RWNX_SPLIT_TX_BUF ++ __entry->pkt_cnt = sw_txhdr->desc.host.packet_cnt; ++#endif ++#ifdef CONFIG_RWNX_FULLMAC ++ __entry->flag = sw_txhdr->desc.host.flags; ++#ifdef CONFIG_RWNX_SPLIT_TX_BUF ++#ifdef CONFIG_RWNX_AMSDUS_TX ++ if (sw_txhdr->amsdu.len) ++ __entry->len = sw_txhdr->amsdu.len; ++ else ++#endif /* CONFIG_RWNX_AMSDUS_TX */ ++ __entry->len = sw_txhdr->desc.host.packet_len[0]; ++#else ++ __entry->len = sw_txhdr->desc.host.packet_len; ++#endif /* CONFIG_RWNX_SPLIT_TX_BUF */ ++ ++#else /* !CONFIG_RWNX_FULLMAC */ ++ __entry->flag = sw_txhdr->desc.umac.flags; ++ __entry->len = sw_txhdr->frame_len; ++ __entry->sn = sw_txhdr->sn; ++#endif /* CONFIG_RWNX_FULLMAC */ ++#ifdef CONFIG_RWNX_MUMIMO_TX ++ __entry->mu_info = sw_txhdr->desc.host.mumimo_info; ++#else ++ __entry->mu_info = 0; ++#endif ++ ), ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ TP_printk( ++ "%s skb=%p (len=%d) hw_queue=%s cred_txq=%d cred_hwq=%d %s flag=%s %s%s%s", ++ __print_txq(__entry->tx_queue), __entry->skb, __entry->len, ++ __print_hwq(__entry->hw_queue), __entry->txq_cred, ++ __entry->hwq_cred, __print_mu_info(__entry->mu_info), ++ __print_flags(__entry->flag, "|", { TXU_CNTRL_RETRY, "RETRY" }, ++ { TXU_CNTRL_MORE_DATA, "MOREDATA" }, ++ { TXU_CNTRL_MGMT, "MGMT" }, ++ { TXU_CNTRL_MGMT_NO_CCK, "NO_CCK" }, ++ { TXU_CNTRL_MGMT_ROBUST, "ROBUST" }, ++ { TXU_CNTRL_AMSDU, "AMSDU" }, ++ { TXU_CNTRL_USE_4ADDR, "4ADDR" }, ++ { TXU_CNTRL_EOSP, "EOSP" }, ++ { TXU_CNTRL_MESH_FWD, "MESH_FWD" }, ++ { TXU_CNTRL_TDLS, "TDLS" }), ++ (__entry->push_flag & RWNX_PUSH_IMMEDIATE) ? "(IMMEDIATE)" : "", ++ (!(__entry->flag & TXU_CNTRL_RETRY) && ++ (__entry->push_flag & RWNX_PUSH_RETRY)) ? ++ "(SW_RETRY)" : ++ "", ++ __print_amsdu(__entry->pkt_cnt)) ++#else ++ TP_printk( ++ "%s skb=%p (len=%d) hw_queue=%s cred_txq=%d cred_hwq=%d %s flag=%x (%s) sn=%d %s", ++ __print_txq(__entry->tx_queue), __entry->skb, __entry->len, ++ __print_hwq(__entry->hw_queue), __entry->txq_cred, ++ __entry->hwq_cred, __print_mu_info(__entry->mu_info), ++ __entry->flag, ++ __print_flags(__entry->push_flag, "|", ++ { RWNX_PUSH_RETRY, "RETRY" }, ++ { RWNX_PUSH_IMMEDIATE, "IMMEDIATE" }), ++ __entry->sn, __print_amsdu(__entry->pkt_cnt)) ++#endif /* CONFIG_RWNX_FULLMAC */ ++); ++ ++TRACE_EVENT( ++ txq_queue_skb, ++ TP_PROTO(struct sk_buff *skb, struct rwnx_txq *txq, bool retry), ++ TP_ARGS(skb, txq, retry), ++ TP_STRUCT__entry(__field(struct sk_buff *, skb) __field(u16, txq_idx) ++ __field(s8, credit) __field(u16, q_len) ++ __field(u16, q_len_retry) ++ __field(bool, retry)), ++ TP_fast_assign(__entry->skb = skb; __entry->txq_idx = txq->idx; ++ __entry->credit = txq->credits; ++ __entry->q_len = skb_queue_len(&txq->sk_list); ++ __entry->q_len_retry = txq->nb_retry; ++ __entry->retry = retry;), ++ ++ TP_printk("%s skb=%p retry=%d txq_credits=%d queue_len=%d (retry = %d)", ++ __print_txq(__entry->txq_idx), __entry->skb, __entry->retry, ++ __entry->credit, __entry->q_len, __entry->q_len_retry)); ++ ++#ifdef CONFIG_MAC80211_TXQ ++TRACE_EVENT(txq_wake, TP_PROTO(struct rwnx_txq *txq), TP_ARGS(txq), ++ TP_STRUCT__entry(__field(u16, txq_idx) __field(u16, q_len)), ++ TP_fast_assign(__entry->txq_idx = txq->idx; ++ __entry->q_len = txq->nb_ready_mac80211;), ++ ++ TP_printk("%s mac80211_queue_len=%d", __print_txq(__entry->txq_idx), ++ __entry->q_len)); ++ ++TRACE_EVENT(txq_drop, TP_PROTO(struct rwnx_txq *txq, unsigned long nb_drop), ++ TP_ARGS(txq, nb_drop), ++ TP_STRUCT__entry(__field(u16, txq_idx) __field(u16, nb_drop)), ++ TP_fast_assign(__entry->txq_idx = txq->idx; ++ __entry->nb_drop = nb_drop;), ++ ++ TP_printk("%s %u pkt have been dropped by codel in mac80211 txq", ++ __print_txq(__entry->txq_idx), __entry->nb_drop)); ++ ++#endif ++ ++DECLARE_EVENT_CLASS(idx_template, TP_PROTO(u16 idx), TP_ARGS(idx), ++ TP_STRUCT__entry(__field(u16, idx)), ++ TP_fast_assign(__entry->idx = idx;), ++ TP_printk("idx=%d", __entry->idx)); ++ ++DEFINE_EVENT(idx_template, txq_vif_start, TP_PROTO(u16 idx), TP_ARGS(idx)); ++ ++DEFINE_EVENT(idx_template, txq_vif_stop, TP_PROTO(u16 idx), TP_ARGS(idx)); ++ ++TRACE_EVENT(process_hw_queue, TP_PROTO(struct rwnx_hwq *hwq), TP_ARGS(hwq), ++ TP_STRUCT__entry(__field(u16, hwq) ++ __array(u8, credits, CONFIG_USER_MAX)), ++ TP_fast_assign(__entry->hwq = hwq->id;), ++ TP_printk("hw_queue=%s hw_credits=%s", __print_hwq(__entry->hwq), ++ __print_hwq_cred(__entry->credits))); ++ ++DECLARE_EVENT_CLASS(sta_idx_template, TP_PROTO(u16 idx), TP_ARGS(idx), ++ TP_STRUCT__entry(__field(u16, idx)), ++ TP_fast_assign(__entry->idx = idx;), ++ TP_printk("%s", __print_sta(__entry->idx))); ++ ++DEFINE_EVENT(sta_idx_template, txq_sta_start, TP_PROTO(u16 idx), TP_ARGS(idx)); ++ ++DEFINE_EVENT(sta_idx_template, txq_sta_stop, TP_PROTO(u16 idx), TP_ARGS(idx)); ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ ++DEFINE_EVENT(sta_idx_template, ps_disable, TP_PROTO(u16 idx), TP_ARGS(idx)); ++ ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++TRACE_EVENT( ++ skb_confirm, ++ TP_PROTO(struct sk_buff *skb, struct rwnx_txq *txq, ++ struct rwnx_hwq *hwq, ++#ifdef CONFIG_RWNX_FULLMAC ++ struct tx_cfm_tag *cfm ++#else ++ u8 cfm ++#endif ++ ), ++ ++ TP_ARGS(skb, txq, hwq, cfm), ++ ++ TP_STRUCT__entry( ++ __field(struct sk_buff *, skb) __field(u16, txq_idx) ++ __field(u8, hw_queue) __array(u8, hw_credit, ++ CONFIG_USER_MAX) ++ __field(s8, sw_credit) __field(s8, sw_credit_up) ++#ifdef CONFIG_RWNX_FULLMAC ++ __field(u8, ampdu_size) ++#ifdef CONFIG_RWNX_SPLIT_TX_BUF ++ __field(u16, amsdu) ++#endif /* CONFIG_RWNX_SPLIT_TX_BUF */ ++ __field(u16, sn) ++#endif /* CONFIG_RWNX_FULLMAC*/ ++ ), ++ ++ TP_fast_assign(__entry->skb = skb; __entry->txq_idx = txq->idx; ++ __entry->hw_queue = hwq->id; ++ __entry->sw_credit = txq->credits; ++#if defined CONFIG_RWNX_FULLMAC ++ __entry->sw_credit_up = cfm->credits; ++ __entry->ampdu_size = cfm->ampdu_size; ++#ifdef CONFIG_RWNX_SPLIT_TX_BUF ++ __entry->amsdu = cfm->amsdu_size; __entry->sn = cfm->sn; ++#endif ++#else ++ __entry->sw_credit_up = cfm ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ), ++ ++ TP_printk("%s skb=%p hw_queue=%s, hw_credits=%s, txq_credits=%d (+%d)" ++#ifdef CONFIG_RWNX_FULLMAC ++ " sn=%u ampdu=%d" ++#ifdef CONFIG_RWNX_SPLIT_TX_BUF ++ " amsdu=%u" ++#endif ++#endif ++ , ++ __print_txq(__entry->txq_idx), __entry->skb, ++ __print_hwq(__entry->hw_queue), ++ __print_hwq_cred(__entry->hw_credit), __entry->sw_credit, ++ __entry->sw_credit_up ++#ifdef CONFIG_RWNX_FULLMAC ++ , ++ __entry->sn, __entry->ampdu_size ++#ifdef CONFIG_RWNX_SPLIT_TX_BUF ++ , ++ __entry->amsdu ++#endif ++#endif ++ )); ++ ++TRACE_EVENT(credit_update, TP_PROTO(struct rwnx_txq *txq, s8_l cred_up), ++ ++ TP_ARGS(txq, cred_up), ++ ++ TP_STRUCT__entry(__field(struct sk_buff *, skb) ++ __field(u16, txq_idx) ++ __field(s8, sw_credit) ++ __field(s8, sw_credit_up)), ++ ++ TP_fast_assign(__entry->txq_idx = txq->idx; ++ __entry->sw_credit = txq->credits; ++ __entry->sw_credit_up = cred_up;), ++ ++ TP_printk("%s txq_credits=%d (%+d)", __print_txq(__entry->txq_idx), ++ __entry->sw_credit, __entry->sw_credit_up)) ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ ++DECLARE_EVENT_CLASS( ++ ps_template, TP_PROTO(struct rwnx_sta *sta), TP_ARGS(sta), ++ TP_STRUCT__entry(__field(u16, idx) __field(u16, ready_ps) ++ __field(u16, sp_ps) __field(u16, ready_uapsd) ++ __field(u16, sp_uapsd)), ++ TP_fast_assign(__entry->idx = sta->sta_idx; ++ __entry->ready_ps = sta->ps.pkt_ready[LEGACY_PS_ID]; ++ __entry->sp_ps = sta->ps.sp_cnt[LEGACY_PS_ID]; ++ __entry->ready_uapsd = sta->ps.pkt_ready[UAPSD_ID]; ++ __entry->sp_uapsd = sta->ps.sp_cnt[UAPSD_ID];), ++ ++ TP_printk("%s [PS] ready=%d sp=%d [UAPSD] ready=%d sp=%d", ++ __print_sta(__entry->idx), __entry->ready_ps, __entry->sp_ps, ++ __entry->ready_uapsd, __entry->sp_uapsd)); ++ ++DEFINE_EVENT(ps_template, ps_queue, TP_PROTO(struct rwnx_sta *sta), ++ TP_ARGS(sta)); ++ ++DEFINE_EVENT(ps_template, ps_push, TP_PROTO(struct rwnx_sta *sta), ++ TP_ARGS(sta)); ++ ++DEFINE_EVENT(ps_template, ps_enable, TP_PROTO(struct rwnx_sta *sta), ++ TP_ARGS(sta)); ++ ++TRACE_EVENT(ps_traffic_update, TP_PROTO(u16 sta_idx, u8 traffic, bool uapsd), ++ ++ TP_ARGS(sta_idx, traffic, uapsd), ++ ++ TP_STRUCT__entry(__field(u16, sta_idx) __field(u8, traffic) ++ __field(bool, uapsd)), ++ ++ TP_fast_assign(__entry->sta_idx = sta_idx; ++ __entry->traffic = traffic; __entry->uapsd = uapsd;), ++ ++ TP_printk("%s %s%s traffic available ", ++ __print_sta(__entry->sta_idx), ++ __entry->traffic ? "" : "no more ", ++ __entry->uapsd ? "U-APSD" : "legacy PS")); ++ ++TRACE_EVENT(ps_traffic_req, ++ TP_PROTO(struct rwnx_sta *sta, u16 pkt_req, u8 ps_id), ++ TP_ARGS(sta, pkt_req, ps_id), ++ TP_STRUCT__entry(__field(u16, idx) __field(u16, pkt_req) ++ __field(u8, ps_id) __field(u16, ready) ++ __field(u16, sp)), ++ TP_fast_assign(__entry->idx = sta->sta_idx; ++ __entry->pkt_req = pkt_req; __entry->ps_id = ps_id; ++ __entry->ready = sta->ps.pkt_ready[ps_id]; ++ __entry->sp = sta->ps.sp_cnt[ps_id];), ++ ++ TP_printk("%s %s traffic request %d pkt (ready=%d, sp=%d)", ++ __print_sta(__entry->idx), ++ __entry->ps_id == UAPSD_ID ? "U-APSD" : "legacy PS", ++ __entry->pkt_req, __entry->ready, __entry->sp)); ++ ++#ifdef CONFIG_RWNX_AMSDUS_TX ++TRACE_EVENT(amsdu_subframe, TP_PROTO(struct rwnx_sw_txhdr *sw_txhdr), ++ TP_ARGS(sw_txhdr), ++ TP_STRUCT__entry(__field(struct sk_buff *, skb) ++ __field(u16, txq_idx) __field(u8, nb) ++ __field(u32, len)), ++ TP_fast_assign(__entry->skb = sw_txhdr->skb; ++ __entry->nb = sw_txhdr->amsdu.nb; ++ __entry->len = sw_txhdr->amsdu.len; ++ __entry->txq_idx = sw_txhdr->txq->idx;), ++ ++ TP_printk("%s skb=%p %s nb_subframe=%d, len=%u", ++ __print_txq(__entry->txq_idx), __entry->skb, ++ (__entry->nb == 2) ? "Start new AMSDU" : "Add subframe", ++ __entry->nb, __entry->len)); ++#endif ++ ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++#ifdef CONFIG_RWNX_MUMIMO_TX ++TRACE_EVENT(mu_group_update, TP_PROTO(struct rwnx_mu_group *group), ++ TP_ARGS(group), ++ TP_STRUCT__entry(__field(u8, nb_user) __field(u8, group_id) ++ __array(u8, users, CONFIG_USER_MAX)), ++ TP_fast_assign(int i; __entry->nb_user = group->user_cnt; ++ for (i = 0; i < CONFIG_USER_MAX; i++) { ++ if (group->users[i]) { ++ __entry->users[i] = ++ group->users[i]->sta_idx; ++ } else { ++ __entry->users[i] = 0xff; ++ } ++ } ++ ++ __entry->group_id = group->group_id;), ++ ++ TP_printk("Group-id = %d, Users = %s", __entry->group_id, ++ __print_mu_group(__entry->nb_user, __entry->users))); ++ ++TRACE_EVENT(mu_group_delete, TP_PROTO(int group_id), TP_ARGS(group_id), ++ TP_STRUCT__entry(__field(u8, group_id)), ++ TP_fast_assign(__entry->group_id = group_id;), ++ ++ TP_printk("Group-id = %d", __entry->group_id)); ++ ++TRACE_EVENT(mu_group_selection, TP_PROTO(struct rwnx_sta *sta, int group_id), ++ TP_ARGS(sta, group_id), ++ TP_STRUCT__entry(__field(u8, sta_idx) __field(u8, group_id)), ++ TP_fast_assign(__entry->sta_idx = sta->sta_idx; ++ __entry->group_id = group_id;), ++ ++ TP_printk("[Sta %d] Group-id = %d", __entry->sta_idx, ++ __entry->group_id)); ++ ++TRACE_EVENT(txq_select_mu_group, ++ TP_PROTO(struct rwnx_txq *txq, int group_id, int pos), ++ ++ TP_ARGS(txq, group_id, pos), ++ ++ TP_STRUCT__entry(__field(u16, txq_idx) __field(u8, group_id) ++ __field(u8, pos)), ++ TP_fast_assign(__entry->txq_idx = txq->idx; ++ __entry->group_id = group_id; __entry->pos = pos;), ++ ++ TP_printk("%s: group=%d pos=%d", __print_txq(__entry->txq_idx), ++ __entry->group_id, __entry->pos)); ++ ++#endif /* CONFIG_RWNX_MUMIMO_TX */ ++#endif /* ! CONFIG_RWNX_FHOST */ ++ ++/***************************************************************************** ++ * TRACE functions for MESH ++ ****************************************************************************/ ++#ifdef CONFIG_RWNX_FULLMAC ++DECLARE_EVENT_CLASS( ++ mesh_path_template, TP_PROTO(struct rwnx_mesh_path *mesh_path), ++ TP_ARGS(mesh_path), ++ TP_STRUCT__entry(__field(u8, idx) __field(u8, next_hop_sta) ++ __array(u8, tgt_mac, ETH_ALEN)), ++ ++ TP_fast_assign( ++ __entry->idx = mesh_path->path_idx; ++ memcpy(__entry->tgt_mac, &mesh_path->tgt_mac_addr, ETH_ALEN); ++ if (mesh_path->p_nhop_sta) ++ __entry->next_hop_sta = mesh_path->p_nhop_sta->sta_idx; ++ else __entry->next_hop_sta = 0xff;), ++ ++ TP_printk("Mpath(%d): target=%pM next_hop=STA-%d", __entry->idx, ++ __entry->tgt_mac, __entry->next_hop_sta)); ++ ++DEFINE_EVENT(mesh_path_template, mesh_create_path, ++ TP_PROTO(struct rwnx_mesh_path *mesh_path), TP_ARGS(mesh_path)); ++ ++DEFINE_EVENT(mesh_path_template, mesh_delete_path, ++ TP_PROTO(struct rwnx_mesh_path *mesh_path), TP_ARGS(mesh_path)); ++ ++DEFINE_EVENT(mesh_path_template, mesh_update_path, ++ TP_PROTO(struct rwnx_mesh_path *mesh_path), TP_ARGS(mesh_path)); ++ ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++/***************************************************************************** ++ * TRACE functions for RADAR ++ ****************************************************************************/ ++#ifdef CONFIG_RWNX_RADAR ++TRACE_EVENT(radar_pulse, TP_PROTO(u8 chain, struct radar_pulse *pulse), ++ TP_ARGS(chain, pulse), ++ TP_STRUCT__entry(__field(u8, chain) __field(s16, freq) ++ __field(u16, pri) __field(u8, len) ++ __field(u8, fom)), ++ TP_fast_assign(__entry->freq = pulse->freq * 2; ++ __entry->len = pulse->len * 2; ++ __entry->fom = pulse->fom * 6; ++ __entry->pri = pulse->rep; __entry->chain = chain;), ++ ++ TP_printk("%s: PRI=%.5d LEN=%.3d FOM=%.2d%% freq=%dMHz ", ++ __print_symbolic(__entry->chain, ++ { RWNX_RADAR_RIU, "RIU" }, ++ { RWNX_RADAR_FCU, "FCU" }), ++ __entry->pri, __entry->len, __entry->fom, __entry->freq)); ++ ++TRACE_EVENT(radar_detected, ++ TP_PROTO(u8 chain, u8 region, s16 freq, u8 type, u16 pri), ++ TP_ARGS(chain, region, freq, type, pri), ++ TP_STRUCT__entry(__field(u8, chain) __field(u8, region) ++ __field(s16, freq) __field(u8, type) ++ __field(u16, pri)), ++ TP_fast_assign(__entry->chain = chain; __entry->region = region; ++ __entry->freq = freq; __entry->type = type; ++ __entry->pri = pri;), ++ TP_printk("%s: region=%s type=%d freq=%dMHz (pri=%dus)", ++ __print_symbolic(__entry->chain, ++ { RWNX_RADAR_RIU, "RIU" }, ++ { RWNX_RADAR_FCU, "FCU" }), ++ __print_symbolic(__entry->region, ++ { NL80211_DFS_UNSET, "UNSET" }, ++ { NL80211_DFS_FCC, "FCC" }, ++ { NL80211_DFS_ETSI, "ETSI" }, ++ { NL80211_DFS_JP, "JP" }), ++ __entry->type, __entry->freq, __entry->pri)); ++ ++TRACE_EVENT(radar_set_region, TP_PROTO(u8 region), TP_ARGS(region), ++ TP_STRUCT__entry(__field(u8, region)), ++ TP_fast_assign(__entry->region = region;), ++ TP_printk("region=%s", ++ __print_symbolic(__entry->region, ++ { NL80211_DFS_UNSET, "UNSET" }, ++ { NL80211_DFS_FCC, "FCC" }, ++ { NL80211_DFS_ETSI, "ETSI" }, ++ { NL80211_DFS_JP, "JP" }))); ++ ++TRACE_EVENT(radar_enable_detection, TP_PROTO(u8 region, u8 enable, u8 chain), ++ TP_ARGS(region, enable, chain), ++ TP_STRUCT__entry(__field(u8, region) __field(u8, chain) ++ __field(u8, enable)), ++ TP_fast_assign(__entry->chain = chain; __entry->enable = enable; ++ __entry->region = region;), ++ TP_printk("%s: %s radar detection %s", ++ __print_symbolic(__entry->chain, ++ { RWNX_RADAR_RIU, "RIU" }, ++ { RWNX_RADAR_FCU, "FCU" }), ++ __print_symbolic(__entry->enable, ++ { RWNX_RADAR_DETECT_DISABLE, "Disable" }, ++ { RWNX_RADAR_DETECT_ENABLE, ++ "Enable (no report)" }, ++ { RWNX_RADAR_DETECT_REPORT, "Enable" }), ++ __entry->enable == RWNX_RADAR_DETECT_DISABLE ? ++ "" : ++ __print_symbolic(__entry->region, ++ { NL80211_DFS_UNSET, "UNSET" }, ++ { NL80211_DFS_FCC, "FCC" }, ++ { NL80211_DFS_ETSI, "ETSI" }, ++ { NL80211_DFS_JP, "JP" }))); ++#endif /* CONFIG_RWNX_RADAR */ ++ ++/***************************************************************************** ++ * TRACE functions for IPC message ++ ****************************************************************************/ ++#include "rwnx_strs.h" ++ ++DECLARE_EVENT_CLASS(ipc_msg_template, TP_PROTO(u16 id), TP_ARGS(id), ++ TP_STRUCT__entry(__field(u16, id)), ++ TP_fast_assign(__entry->id = id;), ++ ++ TP_printk("%s (%d - %d)", RWNX_ID2STR(__entry->id), ++ MSG_T(__entry->id), MSG_I(__entry->id))); ++ ++DEFINE_EVENT(ipc_msg_template, msg_send, TP_PROTO(u16 id), TP_ARGS(id)); ++ ++DEFINE_EVENT(ipc_msg_template, msg_recv, TP_PROTO(u16 id), TP_ARGS(id)); ++ ++#endif /* !defined(_RWNX_EVENTS_H) || defined(TRACE_HEADER_MULTI_READ) */ ++ ++#undef TRACE_INCLUDE_PATH ++#undef TRACE_INCLUDE_FILE ++//#define TRACE_INCLUDE_PATH . ++#define TRACE_INCLUDE_PATH AIC_TRACE_INCLUDE_PATH ++#define TRACE_INCLUDE_FILE rwnx_events ++#include +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_fw_trace.c b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_fw_trace.c +new file mode 100755 +index 000000000..2b7517be7 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_fw_trace.c +@@ -0,0 +1,49 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_fw_trace.c ++ * ++ * Copyright (C) RivieraWaves 2017-2019 ++ * ++ ****************************************************************************** ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "rwnx_fw_trace.h" ++#include "aicwf_debug.h" ++ ++int rwnx_fw_log_init(struct rwnx_fw_log *fw_log) ++{ ++ u8 *buf = kmalloc(FW_LOG_SIZE, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ 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); ++ ++ AICWFDBG(LOGINFO, "fw_log_init: %lx, %lx\n", ++ (unsigned long)fw_log->buf.start, ++ (unsigned long)(fw_log->buf.dataend)); ++ return 0; ++} ++ ++void rwnx_fw_log_deinit(struct rwnx_fw_log *fw_log) ++{ ++ if (!fw_log) ++ return; ++ ++ 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/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_fw_trace.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_fw_trace.h +new file mode 100755 +index 000000000..795679095 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_fw_trace.h +@@ -0,0 +1,35 @@ ++/** ++ ****************************************************************************** ++ * ++ * rwnx_fw_trace.h ++ * ++ * Copyright (C) RivieraWaves 2017-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++#ifndef _RWNX_FW_TRACE_H_ ++#define _RWNX_FW_TRACE_H_ ++ ++#include ++#include ++#include ++ ++#define FW_LOG_SIZE (10240) ++ ++struct rwnx_fw_log_buf { ++ uint8_t *data; ++ uint8_t *start; ++ uint8_t *end; ++ uint8_t *dataend; ++ uint32_t size; ++}; ++ ++struct rwnx_fw_log { ++ struct rwnx_fw_log_buf buf; ++ spinlock_t lock; ++}; ++ ++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/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_gki.c b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_gki.c +new file mode 100755 +index 000000000..44eaf3f75 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_gki.c +@@ -0,0 +1,408 @@ ++#include ++#ifdef ANDROID_PLATFORM ++#include "net/wireless/core.h" ++#endif ++#include ++ ++#undef NL80211_MCGRP_MLME ++#define NL80211_MCGRP_MLME 3 ++//#if IS_ENABLED(CONFIG_GKI_OPT_FEATURES) && IS_ENABLED(CONFIG_ANDROID) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)) ++ ++static struct genl_family rwnx_nl80211_fam; ++ ++static bool __rwnx_cfg80211_unexpected_frame(struct net_device *dev, u8 cmd, ++ const u8 *addr, gfp_t gfp) ++{ ++ struct wireless_dev *wdev = dev->ieee80211_ptr; ++ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); ++ struct sk_buff *msg; ++ void *hdr; ++ u32 nlportid = READ_ONCE(wdev->ap_unexpected_nlportid); ++ ++ if (!nlportid) ++ return false; ++ ++ msg = nlmsg_new(100, gfp); ++ if (!msg) ++ return true; ++ ++ hdr = genlmsg_put(msg, 0, 0, &rwnx_nl80211_fam, 0, cmd); ++ if (!hdr) { ++ nlmsg_free(msg); ++ return true; ++ } ++ ++ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || ++ nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || ++ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ++ goto nla_put_failure; ++ ++ genlmsg_end(msg, hdr); ++ genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid); ++ return true; ++ ++nla_put_failure: ++ nlmsg_free(msg); ++ return true; ++} ++ ++bool rwnx_cfg80211_rx_spurious_frame(struct net_device *dev, const u8 *addr, ++ gfp_t gfp) ++{ ++ struct wireless_dev *wdev = dev->ieee80211_ptr; ++ bool ret; ++ ++ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && ++ wdev->iftype != NL80211_IFTYPE_P2P_GO)) { ++ return false; ++ } ++ ret = __rwnx_cfg80211_unexpected_frame( ++ dev, NL80211_CMD_UNEXPECTED_FRAME, addr, gfp); ++ return ret; ++} ++ ++bool rwnx_cfg80211_rx_unexpected_4addr_frame(struct net_device *dev, ++ const u8 *addr, gfp_t gfp) ++{ ++ struct wireless_dev *wdev = dev->ieee80211_ptr; ++ bool ret; ++ ++ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && ++ wdev->iftype != NL80211_IFTYPE_P2P_GO && ++ wdev->iftype != NL80211_IFTYPE_AP_VLAN)) { ++ return false; ++ } ++ ret = __rwnx_cfg80211_unexpected_frame( ++ dev, NL80211_CMD_UNEXPECTED_4ADDR_FRAME, addr, gfp); ++ return ret; ++} ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)) ++void rwnx_cfg80211_notify_new_peer_candidate(struct net_device *dev, ++ const u8 *addr, const u8 *ie, ++ u8 ie_len, int sig_dbm, gfp_t gfp) ++{ ++ struct wireless_dev *wdev = dev->ieee80211_ptr; ++ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); ++ struct sk_buff *msg; ++ void *hdr; ++ ++ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT)) ++ return; ++ ++ msg = nlmsg_new(100 + ie_len, gfp); ++ if (!msg) ++ return; ++ ++ hdr = genlmsg_put(msg, 0, 0, &rwnx_nl80211_fam, 0, ++ NL80211_CMD_NEW_PEER_CANDIDATE); ++ if (!hdr) { ++ nlmsg_free(msg); ++ return; ++ } ++ ++ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || ++ nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || ++ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) || ++ (ie_len && ie && nla_put(msg, NL80211_ATTR_IE, ie_len, ie)) || ++ (sig_dbm && nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm))) ++ goto nla_put_failure; ++ ++ genlmsg_end(msg, hdr); ++ ++#define NL80211_MCGRP_MLME 3 ++ genlmsg_multicast_netns(&rwnx_nl80211_fam, wiphy_net(&rdev->wiphy), msg, ++ 0, NL80211_MCGRP_MLME, gfp); ++ return; ++ ++nla_put_failure: ++ nlmsg_free(msg); ++} ++#endif ++ ++void rwnx_cfg80211_report_obss_beacon(struct wiphy *wiphy, const u8 *frame, ++ size_t len, int freq, int sig_dbm) ++{ ++ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); ++ struct sk_buff *msg; ++ void *hdr; ++ struct cfg80211_beacon_registration *reg; ++ ++ spin_lock_bh(&rdev->beacon_registrations_lock); ++ list_for_each_entry (reg, &rdev->beacon_registrations, list) { ++ msg = nlmsg_new(len + 100, GFP_ATOMIC); ++ if (!msg) { ++ spin_unlock_bh(&rdev->beacon_registrations_lock); ++ return; ++ } ++ ++ hdr = genlmsg_put(msg, 0, 0, &rwnx_nl80211_fam, 0, ++ NL80211_CMD_FRAME); ++ if (!hdr) ++ goto nla_put_failure; ++ ++ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || ++ (freq && nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) || ++ (sig_dbm && ++ nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || ++ nla_put(msg, NL80211_ATTR_FRAME, len, frame)) ++ goto nla_put_failure; ++ ++ genlmsg_end(msg, hdr); ++ ++ genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, reg->nlportid); ++ } ++ spin_unlock_bh(&rdev->beacon_registrations_lock); ++ return; ++ ++nla_put_failure: ++ spin_unlock_bh(&rdev->beacon_registrations_lock); ++ nlmsg_free(msg); ++} ++ ++static int rwnx_nl80211_send_chandef(struct sk_buff *msg, ++ const struct cfg80211_chan_def *chandef) ++{ ++ if (WARN_ON(!cfg80211_chandef_valid(chandef))) ++ return -EINVAL; ++ ++ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, ++ chandef->chan->center_freq)) ++ return -ENOBUFS; ++ switch (chandef->width) { ++ case NL80211_CHAN_WIDTH_20_NOHT: ++ case NL80211_CHAN_WIDTH_20: ++ case NL80211_CHAN_WIDTH_40: ++ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ++ cfg80211_get_chandef_type(chandef))) ++ return -ENOBUFS; ++ break; ++ default: ++ break; ++ } ++ if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, chandef->width)) ++ return -ENOBUFS; ++ if (nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1, chandef->center_freq1)) ++ return -ENOBUFS; ++ if (chandef->center_freq2 && ++ nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2, chandef->center_freq2)) ++ return -ENOBUFS; ++ return 0; ++} ++ ++void rwnx_cfg80211_ch_switch_notify(struct cfg80211_registered_device *rdev, ++ struct net_device *netdev, ++ struct cfg80211_chan_def *chandef, ++ gfp_t gfp, enum nl80211_commands notif, ++ u8 count) ++{ ++ struct sk_buff *msg; ++ void *hdr; ++ ++ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); ++ if (!msg) ++ return; ++ ++ hdr = genlmsg_put(msg, 0, 0, &rwnx_nl80211_fam, 0, notif); ++ if (!hdr) { ++ nlmsg_free(msg); ++ return; ++ } ++ ++ if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex)) ++ goto nla_put_failure; ++ ++ if (rwnx_nl80211_send_chandef(msg, chandef)) ++ goto nla_put_failure; ++ ++ if ((notif == NL80211_CMD_CH_SWITCH_STARTED_NOTIFY) && ++ (nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT, count))) ++ goto nla_put_failure; ++ ++ genlmsg_end(msg, hdr); ++ ++ genlmsg_multicast_netns(&rwnx_nl80211_fam, wiphy_net(&rdev->wiphy), msg, ++ 0, NL80211_MCGRP_MLME, gfp); ++ return; ++ ++nla_put_failure: ++ nlmsg_free(msg); ++} ++ ++void rwnx_cfg80211_ch_switch_started_notify(struct net_device *dev, ++ struct cfg80211_chan_def *chandef, ++ u8 count ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) ++ , ++ bool quiet ++#endif ++) ++{ ++ struct wireless_dev *wdev = dev->ieee80211_ptr; ++ struct wiphy *wiphy = wdev->wiphy; ++ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); ++ ++ rwnx_cfg80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL, ++ NL80211_CMD_CH_SWITCH_STARTED_NOTIFY, ++ count); ++} ++ ++int rwnx_regulatory_set_wiphy_regd_sync_rtnl(struct wiphy *wiphy, ++ struct ieee80211_regdomain *rd) ++{ ++ wiphy_apply_custom_regulatory(wiphy, rd); ++ return 0; ++} ++ ++void rwnx_skb_append(struct sk_buff *old, struct sk_buff *newsk, ++ struct sk_buff_head *list) ++{ ++ unsigned long flags; ++ struct sk_buff *prev = old; ++ struct sk_buff *next = prev->next; ++ spin_lock_irqsave(&list->lock, flags); ++ WRITE_ONCE(newsk->next, next); ++ WRITE_ONCE(newsk->prev, prev); ++ WRITE_ONCE(next->prev, newsk); ++ WRITE_ONCE(prev->next, newsk); ++ list->qlen++; ++ spin_unlock_irqrestore(&list->lock, flags); ++} ++ ++bool rwnx_ieee80211_chandef_to_operating_class( ++ struct cfg80211_chan_def *chandef, u8 *op_class) ++{ ++ u8 vht_opclass; ++ u32 freq = chandef->center_freq1; ++ ++ if (freq >= 2412 && freq <= 2472) { ++ if (chandef->width > NL80211_CHAN_WIDTH_40) ++ return false; ++ ++ /* 2.407 GHz, channels 1..13 */ ++ if (chandef->width == NL80211_CHAN_WIDTH_40) { ++ if (freq > chandef->chan->center_freq) ++ *op_class = 83; /* HT40+ */ ++ else ++ *op_class = 84; /* HT40- */ ++ } else { ++ *op_class = 81; ++ } ++ ++ return true; ++ } ++ ++ if (freq == 2484) { ++ /* channel 14 is only for IEEE 802.11b */ ++ if (chandef->width != NL80211_CHAN_WIDTH_20_NOHT) ++ return false; ++ ++ *op_class = 82; /* channel 14 */ ++ return true; ++ } ++ ++ switch (chandef->width) { ++ case NL80211_CHAN_WIDTH_80: ++ vht_opclass = 128; ++ break; ++ case NL80211_CHAN_WIDTH_160: ++ vht_opclass = 129; ++ break; ++ case NL80211_CHAN_WIDTH_80P80: ++ vht_opclass = 130; ++ break; ++ case NL80211_CHAN_WIDTH_10: ++ case NL80211_CHAN_WIDTH_5: ++ return false; /* unsupported for now */ ++ default: ++ vht_opclass = 0; ++ break; ++ } ++ ++ /* 5 GHz, channels 36..48 */ ++ if (freq >= 5180 && freq <= 5240) { ++ if (vht_opclass) { ++ *op_class = vht_opclass; ++ } else if (chandef->width == NL80211_CHAN_WIDTH_40) { ++ if (freq > chandef->chan->center_freq) ++ *op_class = 116; ++ else ++ *op_class = 117; ++ } else { ++ *op_class = 115; ++ } ++ ++ return true; ++ } ++ ++ /* 5 GHz, channels 52..64 */ ++ if (freq >= 5260 && freq <= 5320) { ++ if (vht_opclass) { ++ *op_class = vht_opclass; ++ } else if (chandef->width == NL80211_CHAN_WIDTH_40) { ++ if (freq > chandef->chan->center_freq) ++ *op_class = 119; ++ else ++ *op_class = 120; ++ } else { ++ *op_class = 118; ++ } ++ ++ return true; ++ } ++ ++ /* 5 GHz, channels 100..144 */ ++ if (freq >= 5500 && freq <= 5720) { ++ if (vht_opclass) { ++ *op_class = vht_opclass; ++ } else if (chandef->width == NL80211_CHAN_WIDTH_40) { ++ if (freq > chandef->chan->center_freq) ++ *op_class = 122; ++ else ++ *op_class = 123; ++ } else { ++ *op_class = 121; ++ } ++ ++ return true; ++ } ++ ++ /* 5 GHz, channels 149..169 */ ++ if (freq >= 5745 && freq <= 5845) { ++ if (vht_opclass) { ++ *op_class = vht_opclass; ++ } else if (chandef->width == NL80211_CHAN_WIDTH_40) { ++ if (freq > chandef->chan->center_freq) ++ *op_class = 126; ++ else ++ *op_class = 127; ++ } else if (freq <= 5805) { ++ *op_class = 124; ++ } else { ++ *op_class = 125; ++ } ++ ++ return true; ++ } ++ ++ /* 56.16 GHz, channel 1..4 */ ++ if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 6) { ++ if (chandef->width >= NL80211_CHAN_WIDTH_40) ++ return false; ++ ++ *op_class = 180; ++ return true; ++ } ++ ++ /* not supported yet */ ++ return false; ++} ++ ++int rwnx_call_usermodehelper(const char *path, char **argv, char **envp, ++ int wait) ++{ ++ return -1; ++} ++ ++#endif +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_gki.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_gki.h +new file mode 100755 +index 000000000..630ee0305 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_gki.h +@@ -0,0 +1,76 @@ ++#ifndef __RWNX_GKI_H ++#define __RWNX_GKI_H ++ ++#ifdef ANDROID_PLATFORM ++#include "net/wireless/core.h" ++#endif ++ ++//#if IS_ENABLED(CONFIG_GKI_OPT_FEATURES) && IS_ENABLED(CONFIG_ANDROID) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)) ++ ++bool rwnx_cfg80211_rx_spurious_frame(struct net_device *dev, const u8 *addr, ++ gfp_t gfp); ++ ++bool rwnx_cfg80211_rx_unexpected_4addr_frame(struct net_device *dev, ++ const u8 *addr, gfp_t gfp); ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)) ++void rwnx_cfg80211_notify_new_peer_candidate(struct net_device *dev, ++ const u8 *addr, const u8 *ie, ++ u8 ie_len, int sig_dbm, gfp_t gfp); ++#endif ++ ++void rwnx_cfg80211_report_obss_beacon(struct wiphy *wiphy, const u8 *frame, ++ size_t len, int freq, int sig_dbm); ++ ++void rwnx_cfg80211_ch_switch_notify(struct cfg80211_registered_device *rdev, ++ struct net_device *netdev, ++ struct cfg80211_chan_def *chandef, ++ gfp_t gfp, enum nl80211_commands notif, ++ u8 count); ++ ++void rwnx_cfg80211_ch_switch_started_notify(struct net_device *dev, ++ struct cfg80211_chan_def *chandef, ++ u8 count ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) ++ , ++ bool quiet ++#endif ++); ++ ++int rwnx_regulatory_set_wiphy_regd_sync_rtnl(struct wiphy *wiphy, ++ struct ieee80211_regdomain *rd); ++ ++void rwnx_skb_append(struct sk_buff *old, struct sk_buff *newsk, ++ struct sk_buff_head *list); ++ ++bool rwnx_ieee80211_chandef_to_operating_class( ++ struct cfg80211_chan_def *chandef, u8 *op_class); ++ ++int rwnx_call_usermodehelper(const char *path, char **argv, char **envp, ++ int wait); ++ ++#else ++ ++#define rwnx_cfg80211_rx_spurious_frame cfg80211_rx_spurious_frame ++#define rwnx_cfg80211_rx_unexpected_4addr_frame \ ++ cfg80211_rx_unexpected_4addr_frame ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)) ++#define rwnx_cfg80211_notify_new_peer_candidate \ ++ cfg80211_notify_new_peer_candidate ++#endif ++ ++#define rwnx_cfg80211_report_obss_beacon cfg80211_report_obss_beacon ++#define rwnx_cfg80211_ch_switch_notify cfg80211_ch_switch_notify ++#define rwnx_cfg80211_ch_switch_started_notify cfg80211_ch_switch_started_notify ++#define rwnx_regulatory_set_wiphy_regd_sync_rtnl \ ++ regulatory_set_wiphy_regd_sync_rtnl ++#define rwnx_skb_append skb_append ++#define rwnx_ieee80211_chandef_to_operating_class \ ++ ieee80211_chandef_to_operating_class ++#define rwnx_call_usermodehelper call_usermodehelper ++ ++#endif ++ ++#endif +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_irqs.c b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_irqs.c +new file mode 100755 +index 000000000..8ba95b703 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_irqs.c +@@ -0,0 +1,65 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_irqs.c ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ ****************************************************************************** ++ */ ++#include ++ ++#include "rwnx_defs.h" ++#include "ipc_host.h" ++#include "rwnx_prof.h" ++ ++/** ++ * rwnx_irq_hdlr - IRQ handler ++ * ++ * Handler registerd by the platform driver ++ */ ++irqreturn_t rwnx_irq_hdlr(int irq, void *dev_id) ++{ ++ struct rwnx_hw *rwnx_hw = (struct rwnx_hw *)dev_id; ++ disable_irq_nosync(irq); ++ tasklet_schedule(&rwnx_hw->task); ++ return IRQ_HANDLED; ++} ++ ++/** ++ * rwnx_task - Bottom half for IRQ handler ++ * ++ * Read irq status and process accordingly ++ */ ++void rwnx_task(unsigned long data) ++{ ++ struct rwnx_hw *rwnx_hw = (struct rwnx_hw *)data; ++ ++#if 0 ++ struct rwnx_plat *rwnx_plat = rwnx_hw->plat; ++ u32 status, statuses = 0; ++ ++ /* Ack unconditionnally in case ipc_host_get_status does not see the irq */ ++ rwnx_plat->ack_irq(rwnx_plat); ++ ++ while ((status = ipc_host_get_status(rwnx_hw->ipc_env))) { ++ statuses |= status; ++ /* All kinds of IRQs will be handled in one shot (RX, MSG, DBG, ...) ++ * this will ack IPC irqs not the cfpga irqs */ ++ ipc_host_irq(rwnx_hw->ipc_env, status); ++ ++ rwnx_plat->ack_irq(rwnx_plat); ++ } ++#endif ++ //if (statuses & IPC_IRQ_E2A_RXDESC) ++ // rwnx_hw->stats.last_rx = now; ++ //if (statuses & IPC_IRQ_E2A_TXCFM) ++ // rwnx_hw->stats.last_tx = now; ++ ++ 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 ++} +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_irqs.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_irqs.h +new file mode 100755 +index 000000000..d3fb4519c +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_irqs.h +@@ -0,0 +1,20 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_irqs.h ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ ****************************************************************************** ++ */ ++#ifndef _RWNX_IRQS_H_ ++#define _RWNX_IRQS_H_ ++ ++#include ++ ++/* IRQ handler to be registered by platform driver */ ++irqreturn_t rwnx_irq_hdlr(int irq, void *dev_id); ++ ++void rwnx_task(unsigned long data); ++ ++#endif /* _RWNX_IRQS_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_main.c b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_main.c +new file mode 100755 +index 000000000..97988cd0a +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_main.c +@@ -0,0 +1,6369 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_main.c ++ * ++ * @brief Entry point of the RWNX driver ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "rwnx_defs.h" ++#include "rwnx_dini.h" ++#include "rwnx_msg_tx.h" ++#include "reg_access.h" ++#include "hal_desc.h" ++#include "rwnx_debugfs.h" ++#include "rwnx_cfgfile.h" ++#include "rwnx_irqs.h" ++#include "rwnx_radar.h" ++#include "rwnx_version.h" ++#ifdef CONFIG_RWNX_BFMER ++#include "rwnx_bfmer.h" ++#endif //(CONFIG_RWNX_BFMER) ++#include "rwnx_tdls.h" ++#include "rwnx_events.h" ++#include "rwnx_compat.h" ++#include "rwnx_version.h" ++#include "rwnx_main.h" ++#include "aicwf_txrxif.h" ++#ifdef AICWF_SDIO_SUPPORT ++#include "aicwf_sdio.h" ++#endif ++#ifdef AICWF_USB_SUPPORT ++#include "aicwf_usb.h" ++#endif ++#include "aic_bsp_export.h" ++#include "aicwf_compat_8800dc.h" ++#include "aicwf_compat_8800d80.h" ++#include "rwnx_wakelock.h" ++#ifdef CONFIG_SDIO_BT ++#include "aic_btsdio.h" ++#endif ++#include "aic_priv_cmd.h" ++ ++#define RW_DRV_DESCRIPTION "RivieraWaves 11nac driver for Linux cfg80211" ++#define RW_DRV_COPYRIGHT "Copyright(c) 2015-2017 RivieraWaves" ++#define RW_DRV_AUTHOR "RivieraWaves S.A.S" ++ ++#define RWNX_PRINT_CFM_ERR(req) \ ++ printk(KERN_CRIT "%s: Status Error(%d)\n", #req, (&req##_cfm)->status) ++ ++extern char country_code[]; ++ ++#define RWNX_HT_CAPABILITIES \ ++ { \ ++ .ht_supported = true, \ ++ .cap = 0, \ ++ .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, \ ++ .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, \ ++ .mcs = { \ ++ .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \ ++ .rx_highest = cpu_to_le16(65), \ ++ .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \ ++ }, \ ++ } ++ ++#define RWNX_VHT_CAPABILITIES \ ++ { \ ++ .vht_supported = false, \ ++ .cap = (7 \ ++ << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT), \ ++ .vht_mcs = { \ ++ .rx_mcs_map = cpu_to_le16( \ ++ IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | \ ++ IEEE80211_VHT_MCS_NOT_SUPPORTED << 2 | \ ++ IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 | \ ++ IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 | \ ++ IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 | \ ++ IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 | \ ++ IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | \ ++ IEEE80211_VHT_MCS_NOT_SUPPORTED << 14), \ ++ .tx_mcs_map = cpu_to_le16( \ ++ IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | \ ++ IEEE80211_VHT_MCS_NOT_SUPPORTED << 2 | \ ++ IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 | \ ++ IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 | \ ++ IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 | \ ++ IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 | \ ++ IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | \ ++ IEEE80211_VHT_MCS_NOT_SUPPORTED << 14), \ ++ } \ ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0) || \ ++ defined(CONFIG_HE_FOR_OLD_KERNEL) ++#define RWNX_HE_CAPABILITIES \ ++ { \ ++ .has_he = false, \ ++ .he_cap_elem = { \ ++ .mac_cap_info[0] = 0, \ ++ .mac_cap_info[1] = 0, \ ++ .mac_cap_info[2] = 0, \ ++ .mac_cap_info[3] = 0, \ ++ .mac_cap_info[4] = 0, \ ++ .mac_cap_info[5] = 0, \ ++ .phy_cap_info[0] = 0, \ ++ .phy_cap_info[1] = 0, \ ++ .phy_cap_info[2] = 0, \ ++ .phy_cap_info[3] = 0, \ ++ .phy_cap_info[4] = 0, \ ++ .phy_cap_info[5] = 0, \ ++ .phy_cap_info[6] = 0, \ ++ .phy_cap_info[7] = 0, \ ++ .phy_cap_info[8] = 0, \ ++ .phy_cap_info[9] = 0, \ ++ .phy_cap_info[10] = 0, \ ++ }, \ ++ .he_mcs_nss_supp = { \ ++ .rx_mcs_80 = cpu_to_le16(0xfffa), \ ++ .tx_mcs_80 = cpu_to_le16(0xfffa), \ ++ .rx_mcs_160 = cpu_to_le16(0xffff), \ ++ .tx_mcs_160 = cpu_to_le16(0xffff), \ ++ .rx_mcs_80p80 = cpu_to_le16(0xffff), \ ++ .tx_mcs_80p80 = cpu_to_le16(0xffff), \ ++ }, \ ++ .ppe_thres = {0x08, 0x1c, 0x07}, \ ++ } ++#else ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) ++#define RWNX_HE_CAPABILITIES \ ++ { \ ++ .has_he = false, \ ++ .he_cap_elem = { \ ++ .mac_cap_info[0] = 0, \ ++ .mac_cap_info[1] = 0, \ ++ .mac_cap_info[2] = 0, \ ++ .mac_cap_info[3] = 0, \ ++ .mac_cap_info[4] = 0, \ ++ .phy_cap_info[0] = 0, \ ++ .phy_cap_info[1] = 0, \ ++ .phy_cap_info[2] = 0, \ ++ .phy_cap_info[3] = 0, \ ++ .phy_cap_info[4] = 0, \ ++ .phy_cap_info[5] = 0, \ ++ .phy_cap_info[6] = 0, \ ++ .phy_cap_info[7] = 0, \ ++ .phy_cap_info[8] = 0, \ ++ }, \ ++ .he_mcs_nss_supp = { \ ++ .rx_mcs_80 = cpu_to_le16(0xfffa), \ ++ .tx_mcs_80 = cpu_to_le16(0xfffa), \ ++ .rx_mcs_160 = cpu_to_le16(0xffff), \ ++ .tx_mcs_160 = cpu_to_le16(0xffff), \ ++ .rx_mcs_80p80 = cpu_to_le16(0xffff), \ ++ .tx_mcs_80p80 = cpu_to_le16(0xffff), \ ++ }, \ ++ .ppe_thres = {0x08, 0x1c, 0x07}, \ ++ } ++#endif ++#endif ++ ++#define RATE(_bitrate, _hw_rate, _flags) \ ++ { \ ++ .bitrate = (_bitrate), .flags = (_flags), \ ++ .hw_value = (_hw_rate), \ ++ } ++ ++#define CHAN(_freq) \ ++ { \ ++ .center_freq = (_freq), .max_power = 30, /* FIXME */ \ ++ } ++ ++static struct ieee80211_rate rwnx_ratetable[] = { ++ RATE(10, 0x00, 0), ++ RATE(20, 0x01, IEEE80211_RATE_SHORT_PREAMBLE), ++ RATE(55, 0x02, IEEE80211_RATE_SHORT_PREAMBLE), ++ RATE(110, 0x03, IEEE80211_RATE_SHORT_PREAMBLE), ++ RATE(60, 0x04, 0), ++ RATE(90, 0x05, 0), ++ RATE(120, 0x06, 0), ++ RATE(180, 0x07, 0), ++ RATE(240, 0x08, 0), ++ RATE(360, 0x09, 0), ++ RATE(480, 0x0A, 0), ++ RATE(540, 0x0B, 0), ++}; ++ ++/* The channels indexes here are not used anymore */ ++static struct ieee80211_channel rwnx_2ghz_channels[] = { ++ CHAN(2412), ++ CHAN(2417), ++ CHAN(2422), ++ CHAN(2427), ++ CHAN(2432), ++ CHAN(2437), ++ CHAN(2442), ++ CHAN(2447), ++ CHAN(2452), ++ CHAN(2457), ++ CHAN(2462), ++ CHAN(2467), ++ CHAN(2472), ++ CHAN(2484), ++ // Extra channels defined only to be used for PHY measures. ++ // Enabled only if custregd and custchan parameters are set ++ CHAN(2390), ++ CHAN(2400), ++ CHAN(2410), ++ CHAN(2420), ++ CHAN(2430), ++ CHAN(2440), ++ CHAN(2450), ++ CHAN(2460), ++ CHAN(2470), ++ CHAN(2480), ++ CHAN(2490), ++ CHAN(2500), ++ CHAN(2510), ++}; ++ ++static struct ieee80211_channel rwnx_5ghz_channels[] = { ++ CHAN(5180), // 36 - 20MHz ++ CHAN(5200), // 40 - 20MHz ++ CHAN(5220), // 44 - 20MHz ++ CHAN(5240), // 48 - 20MHz ++ CHAN(5260), // 52 - 20MHz ++ CHAN(5280), // 56 - 20MHz ++ CHAN(5300), // 60 - 20MHz ++ CHAN(5320), // 64 - 20MHz ++ CHAN(5500), // 100 - 20MHz ++ CHAN(5520), // 104 - 20MHz ++ CHAN(5540), // 108 - 20MHz ++ CHAN(5560), // 112 - 20MHz ++ CHAN(5580), // 116 - 20MHz ++ CHAN(5600), // 120 - 20MHz ++ CHAN(5620), // 124 - 20MHz ++ CHAN(5640), // 128 - 20MHz ++ CHAN(5660), // 132 - 20MHz ++ CHAN(5680), // 136 - 20MHz ++ CHAN(5700), // 140 - 20MHz ++ CHAN(5720), // 144 - 20MHz ++ CHAN(5745), // 149 - 20MHz ++ CHAN(5765), // 153 - 20MHz ++ CHAN(5785), // 157 - 20MHz ++ CHAN(5805), // 161 - 20MHz ++ CHAN(5825), // 165 - 20MHz ++ // Extra channels defined only to be used for PHY measures. ++ // Enabled only if custregd and custchan parameters are set ++ CHAN(5190), ++ CHAN(5210), ++ CHAN(5230), ++ CHAN(5250), ++ CHAN(5270), ++ CHAN(5290), ++ CHAN(5310), ++ CHAN(5330), ++ CHAN(5340), ++ CHAN(5350), ++ CHAN(5360), ++ CHAN(5370), ++ CHAN(5380), ++ CHAN(5390), ++ CHAN(5400), ++ CHAN(5410), ++ CHAN(5420), ++ CHAN(5430), ++ CHAN(5440), ++ CHAN(5450), ++ CHAN(5460), ++ CHAN(5470), ++ CHAN(5480), ++ CHAN(5490), ++ CHAN(5510), ++ CHAN(5530), ++ CHAN(5550), ++ CHAN(5570), ++ CHAN(5590), ++ CHAN(5610), ++ CHAN(5630), ++ CHAN(5650), ++ CHAN(5670), ++ CHAN(5690), ++ CHAN(5710), ++ CHAN(5730), ++ CHAN(5750), ++ CHAN(5760), ++ CHAN(5770), ++ CHAN(5780), ++ CHAN(5790), ++ CHAN(5800), ++ CHAN(5810), ++ CHAN(5820), ++ CHAN(5830), ++ CHAN(5840), ++ CHAN(5850), ++ CHAN(5860), ++ CHAN(5870), ++ CHAN(5880), ++ CHAN(5890), ++ CHAN(5900), ++ CHAN(5910), ++ CHAN(5920), ++ CHAN(5930), ++ CHAN(5940), ++ CHAN(5950), ++ CHAN(5960), ++ CHAN(5970), ++}; ++ ++#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) | BIT(NL80211_IFTYPE_AP), ++ .he_cap = RWNX_HE_CAPABILITIES, ++}; ++#endif ++ ++static struct ieee80211_supported_band rwnx_band_2GHz = { ++ .channels = rwnx_2ghz_channels, ++ .n_channels = ARRAY_SIZE(rwnx_2ghz_channels) - ++ 13, // -13 to exclude extra channels ++ .bitrates = rwnx_ratetable, ++ .n_bitrates = ARRAY_SIZE(rwnx_ratetable), ++ .ht_cap = RWNX_HT_CAPABILITIES, ++ .vht_cap = RWNX_VHT_CAPABILITIES, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) ++ .iftype_data = &rwnx_he_capa, ++ .n_iftype_data = 1, ++#endif ++}; ++ ++static struct ieee80211_supported_band rwnx_band_5GHz = { ++ .channels = rwnx_5ghz_channels, ++ .n_channels = ARRAY_SIZE(rwnx_5ghz_channels) - ++ 59, // -59 to exclude extra channels ++ .bitrates = &rwnx_ratetable[4], ++ .n_bitrates = ARRAY_SIZE(rwnx_ratetable) - 4, ++ .ht_cap = RWNX_HT_CAPABILITIES, ++ .vht_cap = RWNX_VHT_CAPABILITIES, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) ++ .iftype_data = &rwnx_he_capa, ++ .n_iftype_data = 1, ++#endif ++}; ++ ++static struct ieee80211_iface_limit rwnx_limits[] = { ++ { .max = 1, .types = BIT(NL80211_IFTYPE_STATION) }, ++ { .max = 1, .types = BIT(NL80211_IFTYPE_AP) }, ++#ifdef CONFIG_USE_P2P0 ++ { .max = 2, ++#else ++ { .max = 1, ++#endif ++ .types = ++ BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) }, ++#ifndef CONFIG_USE_P2P0 ++ { ++ .max = 1, ++ .types = BIT(NL80211_IFTYPE_P2P_DEVICE), ++ } ++#endif ++}; ++ ++static struct ieee80211_iface_limit rwnx_limits_dfs[] = { ++ { .max = NX_VIRT_DEV_MAX, .types = BIT(NL80211_IFTYPE_AP) } ++}; ++ ++static const struct ieee80211_iface_combination rwnx_combinations[] = { ++ { ++ .limits = rwnx_limits, ++ .n_limits = ARRAY_SIZE(rwnx_limits), ++#ifdef CONFIG_MCC ++ .num_different_channels = NX_CHAN_CTXT_CNT, ++#else ++ .num_different_channels = 1, ++#endif ++ .max_interfaces = NX_VIRT_DEV_MAX, ++ }, ++ /* Keep this combination as the last one */ ++ { ++ .limits = rwnx_limits_dfs, ++ .n_limits = ARRAY_SIZE(rwnx_limits_dfs), ++ .num_different_channels = 1, ++ .max_interfaces = NX_VIRT_DEV_MAX, ++ .radar_detect_widths = (BIT(NL80211_CHAN_WIDTH_20_NOHT) | ++ BIT(NL80211_CHAN_WIDTH_20) | ++ BIT(NL80211_CHAN_WIDTH_40) | ++ BIT(NL80211_CHAN_WIDTH_80)), ++ } ++}; ++ ++/* There isn't a lot of sense in it, but you can transmit anything you like */ ++static struct ieee80211_txrx_stypes ++rwnx_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { ++ [NL80211_IFTYPE_STATION] = { ++ .tx = 0xffff, ++ .rx = (BIT(IEEE80211_STYPE_ACTION >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ++ BIT(IEEE80211_STYPE_AUTH >> 4)), ++ }, ++ [NL80211_IFTYPE_AP] = { ++ .tx = 0xffff, ++ .rx = (BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ++ BIT(IEEE80211_STYPE_DISASSOC >> 4) | ++ BIT(IEEE80211_STYPE_AUTH >> 4) | ++ BIT(IEEE80211_STYPE_DEAUTH >> 4) | ++ BIT(IEEE80211_STYPE_ACTION >> 4)), ++ }, ++ [NL80211_IFTYPE_AP_VLAN] = { ++ /* copy AP */ ++ .tx = 0xffff, ++ .rx = (BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ++ BIT(IEEE80211_STYPE_DISASSOC >> 4) | ++ BIT(IEEE80211_STYPE_AUTH >> 4) | ++ BIT(IEEE80211_STYPE_DEAUTH >> 4) | ++ BIT(IEEE80211_STYPE_ACTION >> 4)), ++ }, ++ [NL80211_IFTYPE_P2P_CLIENT] = { ++ .tx = 0xffff, ++ .rx = (BIT(IEEE80211_STYPE_ACTION >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)), ++ }, ++ [NL80211_IFTYPE_P2P_GO] = { ++ .tx = 0xffff, ++ .rx = (BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ++ BIT(IEEE80211_STYPE_DISASSOC >> 4) | ++ BIT(IEEE80211_STYPE_AUTH >> 4) | ++ BIT(IEEE80211_STYPE_DEAUTH >> 4) | ++ BIT(IEEE80211_STYPE_ACTION >> 4)), ++ }, ++ [NL80211_IFTYPE_P2P_DEVICE] = { ++ .tx = 0xffff, ++ .rx = (BIT(IEEE80211_STYPE_ACTION >> 4) | ++ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)), ++ }, ++ [NL80211_IFTYPE_MESH_POINT] = { ++ .tx = 0xffff, ++ .rx = (BIT(IEEE80211_STYPE_ACTION >> 4) | ++ BIT(IEEE80211_STYPE_AUTH >> 4) | ++ BIT(IEEE80211_STYPE_DEAUTH >> 4)), ++ }, ++}; ++ ++static u32 cipher_suites[] = { ++ WLAN_CIPHER_SUITE_WEP40, WLAN_CIPHER_SUITE_WEP104, ++ WLAN_CIPHER_SUITE_TKIP, WLAN_CIPHER_SUITE_CCMP, ++ WLAN_CIPHER_SUITE_AES_CMAC, // reserved entries to enable AES-CMAC and/or SMS4 ++ WLAN_CIPHER_SUITE_SMS4, 0, ++}; ++#define NB_RESERVED_CIPHER 1; ++ ++static const int rwnx_ac2hwq[1][NL80211_NUM_ACS] = { ++ { [NL80211_TXQ_Q_VO] = RWNX_HWQ_VO, ++ [NL80211_TXQ_Q_VI] = RWNX_HWQ_VI, ++ [NL80211_TXQ_Q_BE] = RWNX_HWQ_BE, ++ [NL80211_TXQ_Q_BK] = RWNX_HWQ_BK } ++}; ++ ++const int rwnx_tid2hwq[IEEE80211_NUM_TIDS] = { ++ RWNX_HWQ_BE, ++ RWNX_HWQ_BK, ++ RWNX_HWQ_BK, ++ RWNX_HWQ_BE, ++ RWNX_HWQ_VI, ++ RWNX_HWQ_VI, ++ RWNX_HWQ_VO, ++ RWNX_HWQ_VO, ++ /* TID_8 is used for management frames */ ++ RWNX_HWQ_VO, ++ /* At the moment, all others TID are mapped to BE */ ++ RWNX_HWQ_BE, ++ RWNX_HWQ_BE, ++ RWNX_HWQ_BE, ++ RWNX_HWQ_BE, ++ RWNX_HWQ_BE, ++ RWNX_HWQ_BE, ++ RWNX_HWQ_BE, ++}; ++ ++static const int rwnx_hwq2uapsd[NL80211_NUM_ACS] = { ++ [RWNX_HWQ_VO] = IEEE80211_WMM_IE_STA_QOSINFO_AC_VO, ++ [RWNX_HWQ_VI] = IEEE80211_WMM_IE_STA_QOSINFO_AC_VI, ++ [RWNX_HWQ_BE] = IEEE80211_WMM_IE_STA_QOSINFO_AC_BE, ++ [RWNX_HWQ_BK] = IEEE80211_WMM_IE_STA_QOSINFO_AC_BK, ++}; ++ ++#define P2P_ALIVE_TIME_MS (1 * 1000) ++#define P2P_ALIVE_TIME_COUNT 200 ++ ++extern uint8_t scanning; ++int aicwf_dbg_level = LOGERROR | LOGINFO | LOGDEBUG | LOGTRACE; ++module_param(aicwf_dbg_level, int, 0660); ++int testmode = 0; ++char aic_fw_path[200]; ++u8 chip_sub_id = 0; ++u8 chip_mcu_id = 0; ++u8 chip_id = 0; ++ ++int rwnx_init_cmd_array(void); ++void rwnx_free_cmd_array(void); ++ ++/********************************************************************* ++ * helper ++ *********************************************************************/ ++struct rwnx_sta *rwnx_get_sta(struct rwnx_hw *rwnx_hw, const u8 *mac_addr) ++{ ++ int i; ++ ++ for (i = 0; i < NX_REMOTE_STA_MAX; i++) { ++ struct rwnx_sta *sta = &rwnx_hw->sta_table[i]; ++ if (sta->valid && (memcmp(mac_addr, &sta->mac_addr, 6) == 0)) ++ return sta; ++ } ++ ++ return NULL; ++} ++ ++void rwnx_enable_wapi(struct rwnx_hw *rwnx_hw) ++{ ++ //cipher_suites[rwnx_hw->wiphy->n_cipher_suites] = WLAN_CIPHER_SUITE_SMS4; ++ rwnx_hw->wiphy->n_cipher_suites++; ++ rwnx_hw->wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL; ++} ++ ++void rwnx_enable_mfp(struct rwnx_hw *rwnx_hw) ++{ ++ cipher_suites[rwnx_hw->wiphy->n_cipher_suites] = ++ WLAN_CIPHER_SUITE_AES_CMAC; ++ rwnx_hw->wiphy->n_cipher_suites++; ++} ++ ++u8 *rwnx_build_bcn(struct rwnx_bcn *bcn, struct cfg80211_beacon_data *new) ++{ ++ u8 *buf, *pos; ++ ++ if (new->head) { ++ u8 *head = kmalloc(new->head_len, GFP_KERNEL); ++ ++ if (!head) ++ return NULL; ++ ++ if (bcn->head) ++ kfree(bcn->head); ++ ++ bcn->head = head; ++ bcn->head_len = new->head_len; ++ memcpy(bcn->head, new->head, new->head_len); ++ } ++ if (new->tail) { ++ u8 *tail = kmalloc(new->tail_len, GFP_KERNEL); ++ ++ if (!tail) ++ return NULL; ++ ++ if (bcn->tail) ++ kfree(bcn->tail); ++ ++ bcn->tail = tail; ++ bcn->tail_len = new->tail_len; ++ memcpy(bcn->tail, new->tail, new->tail_len); ++ } ++ ++ if (!bcn->head) ++ return NULL; ++ ++ bcn->tim_len = 6; ++ bcn->len = bcn->head_len + bcn->tail_len + bcn->ies_len + bcn->tim_len; ++ ++ buf = kmalloc(bcn->len, GFP_KERNEL); ++ if (!buf) ++ return NULL; ++ ++ // Build the beacon buffer ++ pos = buf; ++ memcpy(pos, bcn->head, bcn->head_len); ++ pos += bcn->head_len; ++ *pos++ = WLAN_EID_TIM; ++ *pos++ = 4; ++ *pos++ = 0; ++ *pos++ = bcn->dtim; ++ *pos++ = 0; ++ *pos++ = 0; ++ if (bcn->tail) { ++ memcpy(pos, bcn->tail, bcn->tail_len); ++ pos += bcn->tail_len; ++ } ++ if (bcn->ies) { ++ memcpy(pos, bcn->ies, bcn->ies_len); ++ } ++ ++ return buf; ++} ++ ++static void rwnx_del_bcn(struct rwnx_bcn *bcn) ++{ ++ if (bcn->head) { ++ kfree(bcn->head); ++ bcn->head = NULL; ++ } ++ bcn->head_len = 0; ++ ++ if (bcn->tail) { ++ kfree(bcn->tail); ++ bcn->tail = NULL; ++ } ++ bcn->tail_len = 0; ++ ++ if (bcn->ies) { ++ kfree(bcn->ies); ++ bcn->ies = NULL; ++ } ++ bcn->ies_len = 0; ++ bcn->tim_len = 0; ++ bcn->dtim = 0; ++ bcn->len = 0; ++} ++ ++/** ++ * Link channel ctxt to a vif and thus increments count for this context. ++ */ ++void rwnx_chanctx_link(struct rwnx_vif *vif, u8 ch_idx, ++ struct cfg80211_chan_def *chandef) ++{ ++ struct rwnx_chanctx *ctxt; ++ ++ if (ch_idx >= NX_CHAN_CTXT_CNT) { ++ WARN(1, "Invalid channel ctxt id %d", ch_idx); ++ return; ++ } ++ ++ vif->ch_index = ch_idx; ++ ctxt = &vif->rwnx_hw->chanctx_table[ch_idx]; ++ ctxt->count++; ++ ++ // For now chandef is NULL for STATION interface ++ if (chandef) { ++ if (!ctxt->chan_def.chan) ++ ctxt->chan_def = *chandef; ++ else { ++ // TODO. check that chandef is the same as the one already ++ // set for this ctxt ++ } ++ } ++} ++ ++/** ++ * Unlink channel ctxt from a vif and thus decrements count for this context ++ */ ++void rwnx_chanctx_unlink(struct rwnx_vif *vif) ++{ ++ struct rwnx_chanctx *ctxt; ++ ++ if (vif->ch_index == RWNX_CH_NOT_SET) ++ return; ++ ++ ctxt = &vif->rwnx_hw->chanctx_table[vif->ch_index]; ++ ++ if (ctxt->count == 0) { ++ WARN(1, "Chan ctxt ref count is already 0"); ++ } else { ++ ctxt->count--; ++ } ++ ++ if (ctxt->count == 0) { ++ if (vif->ch_index == vif->rwnx_hw->cur_chanctx) { ++ /* If current chan ctxt is no longer linked to a vif ++ disable radar detection (no need to check if it was activated) */ ++ rwnx_radar_detection_enable(&vif->rwnx_hw->radar, ++ RWNX_RADAR_DETECT_DISABLE, ++ RWNX_RADAR_RIU); ++ } ++ /* set chan to null, so that if this ctxt is relinked to a vif that ++ don't have channel information, don't use wrong information */ ++ ctxt->chan_def.chan = NULL; ++ } ++ vif->ch_index = RWNX_CH_NOT_SET; ++} ++ ++int rwnx_chanctx_valid(struct rwnx_hw *rwnx_hw, u8 ch_idx) ++{ ++ if (ch_idx >= NX_CHAN_CTXT_CNT || ++ rwnx_hw->chanctx_table[ch_idx].chan_def.chan == NULL) { ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static void rwnx_del_csa(struct rwnx_vif *vif) ++{ ++ struct rwnx_csa *csa = vif->ap.csa; ++ ++ if (!csa) ++ return; ++ ++ 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; ++ ++ 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)) ++ cfg80211_stop_iface(rwnx_hw->wiphy, &vif->wdev, GFP_KERNEL); ++#else ++ cfg80211_disconnected(vif->ndev, 0, NULL, 0, 0, GFP_KERNEL); ++#endif ++ } else { ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) ++ wiphy_lock(rwnx_hw->wiphy); ++#else ++ mutex_lock(&vif->wdev.mtx); ++ __acquire(&vif->wdev.mtx); ++#endif ++ spin_lock_bh(&rwnx_hw->cb_lock); ++ rwnx_chanctx_unlink(vif); ++ rwnx_chanctx_link(vif, csa->ch_idx, &csa->chandef); ++ if (rwnx_hw->cur_chanctx == csa->ch_idx) { ++ rwnx_radar_detection_enable_on_cur_channel(rwnx_hw); ++ rwnx_txq_vif_start(vif, RWNX_TXQ_STOP_CHAN, rwnx_hw); ++ } else ++ rwnx_txq_vif_stop(vif, RWNX_TXQ_STOP_CHAN, rwnx_hw); ++ spin_unlock_bh(&rwnx_hw->cb_lock); ++/* flare-edge (6.18 port): cfg80211_ch_switch_notify() dropped back to ++ * (dev, chandef, link_id) by 6.18 (link_id must be 0 for non-MLO) — the ++ * vendor compat shim's HIGH_KERNEL_VERSION3 tier (6.3.0) still assumed an ++ * older 4-arg (dev, chandef, count, quiet) form. Add a tier for our exact ++ * target ahead of it rather than touch the historical shim. */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0)) ++ cfg80211_ch_switch_notify(vif->ndev, &csa->chandef, 0); ++#elif (LINUX_VERSION_CODE >= HIGH_KERNEL_VERSION3) ++ cfg80211_ch_switch_notify(vif->ndev, &csa->chandef, 0, 0); ++#elif (LINUX_VERSION_CODE >= HIGH_KERNEL_VERSION) ++ cfg80211_ch_switch_notify(vif->ndev, &csa->chandef, 0); ++#else ++ cfg80211_ch_switch_notify(vif->ndev, &csa->chandef); ++#endif ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) ++ wiphy_unlock(rwnx_hw->wiphy); ++#else ++ mutex_unlock(&vif->wdev.mtx); ++ __release(&vif->wdev.mtx); ++#endif ++ } ++ rwnx_del_csa(vif); ++} ++#endif ++ ++/** ++ * rwnx_external_auth_enable - Enable external authentication on a vif ++ * ++ * @vif: VIF on which external authentication must be enabled ++ * ++ * External authentication requires to start TXQ for unknown STA in ++ * order to send auth frame pusehd by user space. ++ * Note: It is assumed that fw is on the correct channel. ++ */ ++void rwnx_external_auth_enable(struct rwnx_vif *vif) ++{ ++ vif->sta.external_auth = true; ++ rwnx_txq_unk_vif_init(vif); ++ rwnx_txq_start(rwnx_txq_vif_get(vif, NX_UNK_TXQ_TYPE), 0); ++} ++ ++/** ++ * rwnx_external_auth_disable - Disable external authentication on a vif ++ * ++ * @vif: VIF on which external authentication must be disabled ++ */ ++void rwnx_external_auth_disable(struct rwnx_vif *vif) ++{ ++ if (!vif->sta.external_auth) ++ return; ++ ++ vif->sta.external_auth = false; ++ rwnx_txq_unk_vif_deinit(vif); ++} ++ ++/** ++ * rwnx_update_mesh_power_mode - ++ * ++ * @vif: mesh VIF for which power mode is updated ++ * ++ * Does nothing if vif is not a mesh point interface. ++ * Since firmware doesn't support one power save mode per link select the ++ * most "active" power mode among all mesh links. ++ * Indeed as soon as we have to be active on one link we might as well be ++ * active on all links. ++ * ++ * If there is no link then the power mode for next peer is used; ++ */ ++void rwnx_update_mesh_power_mode(struct rwnx_vif *vif) ++{ ++ enum nl80211_mesh_power_mode mesh_pm; ++ struct rwnx_sta *sta; ++ struct mesh_config mesh_conf; ++ struct mesh_update_cfm cfm; ++ u32 mask; ++ ++ if (RWNX_VIF_TYPE(vif) != NL80211_IFTYPE_MESH_POINT) ++ return; ++ ++ if (list_empty(&vif->ap.sta_list)) { ++ mesh_pm = vif->ap.next_mesh_pm; ++ } else { ++ mesh_pm = NL80211_MESH_POWER_DEEP_SLEEP; ++ list_for_each_entry (sta, &vif->ap.sta_list, list) { ++ if (sta->valid && (sta->mesh_pm < mesh_pm)) { ++ mesh_pm = sta->mesh_pm; ++ } ++ } ++ } ++ ++ if (mesh_pm == vif->ap.mesh_pm) ++ return; ++ ++ mask = BIT(NL80211_MESHCONF_POWER_MODE - 1); ++ mesh_conf.power_mode = mesh_pm; ++ if (rwnx_send_mesh_update_req(vif->rwnx_hw, vif, mask, &mesh_conf, ++ &cfm) || ++ cfm.status) ++ return; ++ ++ vif->ap.mesh_pm = mesh_pm; ++} ++ ++#ifdef CONFIG_BR_SUPPORT ++void netdev_br_init(struct net_device *netdev) ++{ ++ struct rwnx_vif *rwnx_vif = netdev_priv(netdev); ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35)) ++ rcu_read_lock(); ++#endif ++ ++ /* if(check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE) == _TRUE) */ ++ { ++/* struct net_bridge *br = netdev->br_port->br; */ /* ->dev->dev_addr; */ ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) ++ if (netdev->br_port) ++#else ++ if (rcu_dereference(rwnx_vif->ndev->rx_handler_data)) ++#endif ++ { ++ struct net_device *br_netdev; ++ ++ br_netdev = dev_get_by_name(&init_net, ++ CONFIG_BR_SUPPORT_BRNAME); ++ if (br_netdev) { ++ memcpy(rwnx_vif->br_mac, br_netdev->dev_addr, ++ ETH_ALEN); ++ dev_put(br_netdev); ++ printk(FUNC_NDEV_FMT ++ " bind bridge dev " NDEV_FMT "(" MAC_FMT ++ ")\n", ++ FUNC_NDEV_ARG(netdev), ++ NDEV_ARG(br_netdev), ++ MAC_ARG(br_netdev->dev_addr)); ++ } else { ++ printk(FUNC_NDEV_FMT ++ " can't get bridge dev by name \"%s\"\n", ++ FUNC_NDEV_ARG(netdev), ++ CONFIG_BR_SUPPORT_BRNAME); ++ } ++ } ++ ++ rwnx_vif->ethBrExtInfo.addPPPoETag = 1; ++ } ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35)) ++ rcu_read_unlock(); ++#endif ++} ++#endif /* CONFIG_BR_SUPPORT */ ++ ++void rwnx_set_conn_state(atomic_t *drv_conn_state, int state) ++{ ++ if ((int)atomic_read(drv_conn_state) != state) { ++ AICWFDBG(LOGDEBUG, "%s drv_conn_state:%p %s --> %s \r\n", ++ __func__, drv_conn_state, ++ s_conn_state[(int)atomic_read(drv_conn_state)], ++ s_conn_state[state]); ++ ++ atomic_set(drv_conn_state, state); ++ } ++} ++ ++/********************************************************************* ++ * netdev callbacks ++ ********************************************************************/ ++/** ++ * int (*ndo_open)(struct net_device *dev); ++ * This function is called when network device transistions to the up ++ * state. ++ * ++ * - Start FW if this is the first interface opened ++ * - Add interface at fw level ++ */ ++static int rwnx_open(struct net_device *dev) ++{ ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ struct rwnx_hw *rwnx_hw = rwnx_vif->rwnx_hw; ++ struct mm_add_if_cfm add_if_cfm; ++ int error = 0; ++ u8 rwnx_rx_gain = 0x0E; ++ int err = 0; ++ int waiting_counter = 10; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ while (test_bit(RWNX_DEV_STARTED, &rwnx_vif->drv_flags)) { ++ msleep(100); ++ AICWFDBG(LOGDEBUG, "%s waiting for rwnx_close \r\n", __func__); ++ waiting_counter--; ++ if (waiting_counter == 0) { ++ AICWFDBG(LOGERROR, ++ "%s error waiting for close time out \r\n", ++ __func__); ++ break; ++ } ++ } ++ ++#ifdef AICWF_LATENCY_MODE ++ if ((testmode == 0) && ++ (RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_STATION || ++ RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_P2P_CLIENT)) { ++ rwnx_send_me_set_lp_level(rwnx_hw, 1, 1); ++ } ++#endif ++ ++#ifdef CONFIG_GPIO_WAKEUP ++//close lp mode ++// rwnx_send_me_set_lp_level(g_rwnx_plat->sdiodev->rwnx_hw, 0); ++#endif //CONFIG_GPIO_WAKEUP ++ ++ // Check if it is the first opened VIF ++ if (rwnx_hw->vif_started == 0) { ++ // Start the FW ++ error = rwnx_send_start(rwnx_hw); ++ if (error) ++ return error; ++ ++ if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ error = rwnx_send_dbg_mem_mask_write_req( ++ rwnx_hw, 0x4033b300, 0xFF, rwnx_rx_gain); ++ if (error) { ++ return error; ++ } ++ } ++ ++#ifdef CONFIG_COEX ++ if (testmode == 0) { ++ rwnx_send_coex_req(rwnx_hw, 0, 1); ++ } ++#endif ++ ++ /* Device is now started */ ++ } ++ ++ set_bit(RWNX_DEV_STARTED, &rwnx_vif->drv_flags); ++ rwnx_set_conn_state(&rwnx_vif->drv_conn_state, ++ RWNX_DRV_STATUS_DISCONNECTED); ++ AICWFDBG(LOGDEBUG, "%s rwnx_vif->drv_flags:%d\r\n", __func__, ++ (int)rwnx_vif->drv_flags); ++ ++ if (RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_P2P_CLIENT || ++ RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_P2P_GO) { ++ if (!rwnx_hw->is_p2p_alive) { ++ if (rwnx_hw->p2p_dev_vif && !rwnx_hw->p2p_dev_vif->up) { ++ err = rwnx_send_add_if( ++ rwnx_hw, ++ rwnx_hw->p2p_dev_vif->wdev.address, ++ RWNX_VIF_TYPE(rwnx_hw->p2p_dev_vif), ++ false, &add_if_cfm); ++ if (err) { ++ return -EIO; ++ } ++ ++ if (add_if_cfm.status != 0) { ++ return -EIO; ++ } ++ ++ /* Save the index retrieved from LMAC */ ++ spin_lock_bh(&rwnx_hw->cb_lock); ++ rwnx_hw->p2p_dev_vif->vif_index = ++ add_if_cfm.inst_nbr; ++ rwnx_hw->p2p_dev_vif->up = true; ++ rwnx_hw->vif_started++; ++ rwnx_hw->vif_table[add_if_cfm.inst_nbr] = ++ rwnx_hw->p2p_dev_vif; ++ spin_unlock_bh(&rwnx_hw->cb_lock); ++ } ++ rwnx_hw->is_p2p_alive = 1; ++#ifndef CONFIG_USE_P2P0 ++ mod_timer(&rwnx_hw->p2p_alive_timer, ++ jiffies + msecs_to_jiffies(1000)); ++ atomic_set(&rwnx_hw->p2p_alive_timer_count, 0); ++#endif ++ } ++ } ++ ++ if (RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_AP_VLAN) { ++ /* For AP_vlan use same fw and drv indexes. We ensure that this index ++ will not be used by fw for another vif by taking index >= NX_VIRT_DEV_MAX */ ++ add_if_cfm.inst_nbr = rwnx_vif->drv_vif_index; ++ netif_tx_stop_all_queues(dev); ++ ++ /* Save the index retrieved from LMAC */ ++ spin_lock_bh(&rwnx_hw->cb_lock); ++ rwnx_vif->vif_index = add_if_cfm.inst_nbr; ++ rwnx_vif->up = true; ++ rwnx_hw->vif_started++; ++ rwnx_hw->vif_table[add_if_cfm.inst_nbr] = rwnx_vif; ++ AICWFDBG(LOGDEBUG, ++ "%s ap create vif in rwnx_hw->vif_table[%d] \r\n", ++ __func__, rwnx_vif->vif_index); ++ spin_unlock_bh(&rwnx_hw->cb_lock); ++ } else { ++ /* Forward the information to the LMAC, ++ * p2p value not used in FMAC configuration, iftype is sufficient */ ++ error = rwnx_send_add_if(rwnx_hw, rwnx_vif->wdev.address, ++ RWNX_VIF_TYPE(rwnx_vif), false, ++ &add_if_cfm); ++ if (error) { ++ printk("add if fail\n"); ++ return error; ++ } ++ ++ if (add_if_cfm.status != 0) { ++ RWNX_PRINT_CFM_ERR(add_if); ++ return -EIO; ++ } ++ ++ /* Save the index retrieved from LMAC */ ++ spin_lock_bh(&rwnx_hw->cb_lock); ++ rwnx_vif->vif_index = add_if_cfm.inst_nbr; ++ rwnx_vif->up = true; ++ rwnx_hw->vif_started++; ++ rwnx_hw->vif_table[add_if_cfm.inst_nbr] = rwnx_vif; ++ AICWFDBG(LOGDEBUG, ++ "%s sta create vif in rwnx_hw->vif_table[%d] \r\n", ++ __func__, rwnx_vif->vif_index); ++ spin_unlock_bh(&rwnx_hw->cb_lock); ++ ++#ifdef CONFIG_USE_P2P0 ++ if (rwnx_vif->is_p2p_vif) { ++ rwnx_hw->p2p_dev_vif = rwnx_vif; ++ rwnx_hw->is_p2p_alive = 1; ++ } ++#endif ++ } ++ ++ if (RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_MONITOR) { ++ rwnx_hw->monitor_vif = rwnx_vif->vif_index; ++ if (rwnx_vif->ch_index != RWNX_CH_NOT_SET) { ++ //Configure the monitor channel ++ error = rwnx_send_config_monitor_req( ++ rwnx_hw, ++ &rwnx_hw->chanctx_table[rwnx_vif->ch_index] ++ .chan_def, ++ NULL); ++ } ++#if defined(CONFIG_RWNX_MON_XMIT) ++ rwnx_txq_unk_vif_init(rwnx_vif); ++#endif ++#if defined(CONFIG_RWNX_MON_RXFILTER) ++ rwnx_send_set_filter(rwnx_hw, ++ (FIF_BCN_PRBRESP_PROMISC | FIF_OTHER_BSS | ++ FIF_PSPOLL | FIF_PROBE_REQ)); ++#endif ++ } ++ ++#if defined(CONFIG_RWNX_MON_XMIT) ++ netif_carrier_on(dev); ++ AICWFDBG(LOGINFO, "monitor xmit: netif_carrier_on\n"); ++#endif ++ ++#ifdef CONFIG_BR_SUPPORT ++ netdev_br_init(dev); ++#endif /* CONFIG_BR_SUPPORT */ ++ ++ //netif_carrier_off(dev); ++ netif_start_queue(dev); ++ ++ return error; ++} ++ ++/** ++ * int (*ndo_stop)(struct net_device *dev); ++ * This function is called when network device transistions to the down ++ * state. ++ * ++ * - Remove interface at fw level ++ * - Reset FW if this is the last interface opened ++ */ ++static int rwnx_close(struct net_device *dev) ++{ ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ struct rwnx_hw *rwnx_hw = rwnx_vif->rwnx_hw; ++ int ret; ++#if defined(AICWF_USB_SUPPORT) ++ struct aicwf_bus *bus_if = NULL; ++ struct aic_usb_dev *usbdev = NULL; ++ bus_if = dev_get_drvdata(rwnx_hw->dev); ++ usbdev = bus_if->bus_priv.usb; ++#elif defined(AICWF_SDIO_SUPPORT) ++ struct aicwf_bus *bus_if = NULL; ++ struct aic_sdio_dev *sdiodev = NULL; ++#else ++#endif ++ int waiting_counter = 20; ++ int test_counter = 0; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ test_counter = waiting_counter; ++ while (atomic_read(&rwnx_vif->drv_conn_state) == ++ (int)RWNX_DRV_STATUS_DISCONNECTING || ++ atomic_read(&rwnx_vif->drv_conn_state) == ++ (int)RWNX_DRV_STATUS_CONNECTING) { ++ AICWFDBG( ++ LOGDEBUG, ++ "%s wifi is connecting or disconnecting, waiting 200ms for state to stable\r\n", ++ __func__); ++ msleep(200); ++ test_counter--; ++ if (test_counter == 0) { ++ AICWFDBG( ++ LOGERROR, ++ "%s connecting or disconnecting, not finish\r\n", ++ __func__); ++ WARN_ON(1); ++ break; ++ } ++ } ++ ++#if defined(AICWF_USB_SUPPORT) || defined(AICWF_SDIO_SUPPORT) ++ if (scanning) { ++ scanning = false; ++ } ++#endif ++ ++ netdev_info(dev, "CLOSE"); ++ ++ rwnx_radar_cancel_cac(&rwnx_hw->radar); ++ ++ /* Abort scan request on the vif */ ++ if (rwnx_hw->scan_request && ++ rwnx_hw->scan_request->wdev == &rwnx_vif->wdev) { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0) ++ struct cfg80211_scan_info info = { ++ .aborted = true, ++ }; ++ ++ cfg80211_scan_done(rwnx_hw->scan_request, &info); ++#else ++ cfg80211_scan_done(rwnx_hw->scan_request, true); ++#endif ++ 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; ++ AICWFDBG(LOGDEBUG, "%s rwnx_vif[%d] down \r\n", __func__, ++ rwnx_vif->vif_index); ++ ++ 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"); ++ } ++ ++#ifdef CONFIG_BR_SUPPORT ++ /* if (OPMODE & (WIFI_STATION_STATE | WIFI_ADHOC_STATE)) */ ++ { ++ /* void nat25_db_cleanup(_adapter *priv); */ ++ nat25_db_cleanup(rwnx_vif); ++ } ++#endif /* CONFIG_BR_SUPPORT */ ++ } ++ ++#if defined(AICWF_USB_SUPPORT) ++ if (usbdev != NULL) { ++ if (usbdev->state != USB_DOWN_ST) ++ rwnx_send_remove_if(rwnx_hw, rwnx_vif->vif_index, ++ false); ++ } ++#endif ++#if defined(AICWF_SDIO_SUPPORT) ++ bus_if = dev_get_drvdata(rwnx_hw->dev); ++ if (bus_if) { ++ sdiodev = bus_if->bus_priv.sdio; ++ } ++ if (sdiodev != NULL) { ++ if (sdiodev->bus_if->state != BUS_DOWN_ST) { ++ if (RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_STATION || ++ RWNX_VIF_TYPE(rwnx_vif) == ++ NL80211_IFTYPE_P2P_CLIENT) { ++ test_counter = waiting_counter; ++ if (atomic_read(&rwnx_vif->drv_conn_state) == ++ (int)RWNX_DRV_STATUS_CONNECTED) { ++ rwnx_set_conn_state( ++ &rwnx_vif->drv_conn_state, ++ RWNX_DRV_STATUS_DISCONNECTING); ++ rwnx_send_sm_disconnect_req( ++ rwnx_hw, rwnx_vif, 3); ++ while (atomic_read( ++ &rwnx_vif->drv_conn_state) == ++ (int)RWNX_DRV_STATUS_DISCONNECTING) { ++ AICWFDBG( ++ LOGDEBUG, ++ "%s wifi is disconnecting, waiting 100ms for state to stable\r\n", ++ __func__); ++ msleep(100); ++ test_counter--; ++ if (test_counter == 0) ++ break; ++ } ++ } ++ } ++#ifdef CONFIG_USE_P2P0 ++ if (!rwnx_vif->is_p2p_vif || ++ (rwnx_vif->is_p2p_vif && rwnx_hw->is_p2p_alive)) { ++ if (rwnx_vif->is_p2p_vif) ++ rwnx_hw->is_p2p_alive = 0; ++#endif ++ rwnx_send_remove_if(rwnx_hw, ++ rwnx_vif->vif_index, false); ++#ifdef CONFIG_USE_P2P0 ++ } ++#endif ++ } ++ } ++#endif ++ /* Ensure that we won't process disconnect ind */ ++ spin_lock_bh(&rwnx_hw->cb_lock); ++ ++ rwnx_hw->vif_table[rwnx_vif->vif_index] = NULL; ++ ++ rwnx_chanctx_unlink(rwnx_vif); ++ ++ if (RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_MONITOR) ++ 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 ++ rwnx_ipc_tx_drain(rwnx_hw); ++#else ++#ifdef AICWF_USB_SUPPORT ++ if (usbdev->bus_if->state != BUS_DOWN_ST) { ++#else ++ if (sdiodev->bus_if->state != BUS_DOWN_ST) { ++#endif ++ rwnx_send_reset(rwnx_hw); ++ // Set parameters to firmware ++ if (testmode == 0) { ++ rwnx_send_me_config_req(rwnx_hw); ++ // Set channel parameters to firmware ++ rwnx_send_me_chan_config_req(rwnx_hw, ++ country_code); ++ } ++ } ++#endif ++ } ++ clear_bit(RWNX_DEV_STARTED, &rwnx_vif->drv_flags); ++ AICWFDBG(LOGDEBUG, "%s rwnx_vif->drv_flags:%d\r\n", __func__, ++ (int)rwnx_vif->drv_flags); ++ ++ return 0; ++} ++ ++#if defined(CONFIG_PLATFORM_ROCKCHIP) || defined(CONFIG_PLATFORM_ROCKCHIP2) ++#ifdef CONFIG_SHUTDOWN_CALLBACK ++int rwnx_close_(struct net_device *dev) ++{ ++ return rwnx_close(dev); ++} ++#endif ++#endif ++ ++#define IOCTL_HOSTAPD (SIOCIWFIRSTPRIV + 28) ++#define IOCTL_WPAS (SIOCIWFIRSTPRIV + 30) ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0) ++static int rwnx_do_ioctl(struct net_device *net, struct ifreq *req, int cmd) ++#else ++static int rwnx_do_ioctl(struct net_device *net, struct ifreq *req, ++ void __user *data, int cmd) ++#endif ++{ ++ int ret = 0; ++ ///TODO: add ioctl command handler later ++ switch (cmd) { ++ case IOCTL_HOSTAPD: ++ printk("IOCTL_HOSTAPD\n"); ++ break; ++ case IOCTL_WPAS: ++ AICWFDBG(LOGINFO, "IOCTL_WPAS\n"); ++ break; ++ case SIOCDEVPRIVATE: ++ AICWFDBG(LOGINFO, "IOCTL SIOCDEVPRIVATE\n"); ++ break; ++ case (SIOCDEVPRIVATE + 1): ++ AICWFDBG(LOGINFO, "IOCTL PRIVATE\n"); ++ ret = android_priv_cmd(net, req, cmd); ++ break; ++ case (SIOCDEVPRIVATE + 2): ++ AICWFDBG(LOGINFO, "IOCTL PRIVATE+2\n"); ++#ifdef CONFIG_MCU_MESSAGE ++ devipc_cust_msg(net, req, cmd); ++#endif ++ break; ++ default: ++ ret = -EOPNOTSUPP; ++ } ++ return ret; ++} ++ ++/** ++ * struct net_device_stats* (*ndo_get_stats)(struct net_device *dev); ++ * Called when a user wants to get the network device usage ++ * statistics. Drivers must do one of the following: ++ * 1. Define @ndo_get_stats64 to fill in a zero-initialised ++ * rtnl_link_stats64 structure passed by the caller. ++ * 2. Define @ndo_get_stats to update a net_device_stats structure ++ * (which should normally be dev->stats) and return a pointer to ++ * it. The structure may be changed asynchronously only if each ++ * field is written atomically. ++ * 3. Update dev->stats asynchronously and atomically, and define ++ * neither operation. ++ */ ++static struct net_device_stats *rwnx_get_stats(struct net_device *dev) ++{ ++ struct rwnx_vif *vif = netdev_priv(dev); ++ ++ return &vif->net_stats; ++} ++ ++/** ++ * u16 (*ndo_select_queue)(struct net_device *dev, struct sk_buff *skb, ++ * struct net_device *sb_dev); ++ * Called to decide which queue to when device supports multiple ++ * transmit queues. ++ */ ++u16 rwnx_select_queue(struct net_device *dev, struct sk_buff *skb, ++ struct net_device *sb_dev) ++{ ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ return rwnx_select_txq(rwnx_vif, skb); ++} ++ ++/** ++ * int (*ndo_set_mac_address)(struct net_device *dev, void *addr); ++ * This function is called when the Media Access Control address ++ * needs to be changed. If this interface is not defined, the ++ * mac address can not be changed. ++ */ ++static int rwnx_set_mac_address(struct net_device *dev, void *addr) ++{ ++ struct sockaddr *sa = addr; ++ int ret = 0; ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ AICWFDBG(LOGTRACE, "%s enter \r\n", __func__); ++ ++ ret = eth_mac_addr(dev, sa); ++ AICWFDBG(LOGINFO, "%s set %02X:%02X:%02X:%02X:%02X:%02X\r\n", __func__, ++ dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], ++ dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); ++ memcpy(rwnx_vif->wdev.address, dev->dev_addr, 6); ++ ++ return ret; ++} ++ ++static const struct net_device_ops rwnx_netdev_ops = { ++ .ndo_open = rwnx_open, ++ .ndo_stop = rwnx_close, ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0) ++ .ndo_do_ioctl = rwnx_do_ioctl, ++#else ++ .ndo_siocdevprivate = rwnx_do_ioctl, ++#endif ++ .ndo_start_xmit = rwnx_start_xmit, ++ .ndo_get_stats = rwnx_get_stats, ++#ifndef CONFIG_ONE_TXQ ++ .ndo_select_queue = rwnx_select_queue, ++#endif ++#ifdef CONFIG_SUPPORT_REALTIME_CHANGE_MAC ++ .ndo_set_mac_address = rwnx_set_mac_address ++#endif ++ // .ndo_set_features = rwnx_set_features, ++ // .ndo_set_rx_mode = rwnx_set_multicast_list, ++}; ++ ++static const struct net_device_ops rwnx_netdev_monitor_ops = { ++ .ndo_open = rwnx_open, ++ .ndo_stop = rwnx_close, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) ++ .ndo_siocdevprivate = rwnx_do_ioctl, ++#else ++ .ndo_do_ioctl = rwnx_do_ioctl, ++#endif ++#ifdef CONFIG_RWNX_MON_XMIT ++ .ndo_start_xmit = rwnx_start_monitor_if_xmit, ++ .ndo_select_queue = rwnx_select_queue, ++#endif ++ .ndo_get_stats = rwnx_get_stats, ++ .ndo_set_mac_address = rwnx_set_mac_address, ++}; ++ ++static void rwnx_netdev_setup(struct net_device *dev) ++{ ++ ether_setup(dev); ++ dev->priv_flags &= ~IFF_TX_SKB_SHARING; ++ dev->netdev_ops = &rwnx_netdev_ops; ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) ++ dev->destructor = free_netdev; ++#else ++ dev->needs_free_netdev = true; ++#endif ++ dev->watchdog_timeo = RWNX_TX_LIFETIME_MS; ++ ++ dev->needed_headroom = ++ sizeof(struct rwnx_txhdr) + RWNX_SWTXHDR_ALIGN_SZ; ++#ifdef CONFIG_RWNX_AMSDUS_TX ++ dev->needed_headroom = ++ max(dev->needed_headroom, ++ (unsigned short)(sizeof(struct rwnx_amsdu_txhdr) + ++ sizeof(struct ethhdr) + 4 + ++ sizeof(rfc1042_header) + 2)); ++#endif /* CONFIG_RWNX_AMSDUS_TX */ ++ ++ dev->hw_features = 0; ++} ++ ++/********************************************************************* ++ * Cfg80211 callbacks (and helper) ++ *********************************************************************/ ++static struct rwnx_vif *rwnx_interface_add(struct rwnx_hw *rwnx_hw, ++ const char *name, ++ unsigned char name_assign_type, ++ enum nl80211_iftype type, ++ struct vif_params *params) ++{ ++ struct net_device *ndev; ++ struct rwnx_vif *vif; ++ int min_idx, max_idx; ++ int vif_idx = -1; ++ int i; ++ int nx_nb_ndev_txq = NX_NB_NDEV_TXQ; ++ ++ if ((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8801) || ++ ((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DW) && ++ chip_id < 3)) { ++ nx_nb_ndev_txq = NX_NB_NDEV_TXQ_FOR_OLD_IC; ++ } ++ ++ AICWFDBG(LOGINFO, "rwnx_interface_add: %s, %d, %d\r\n", name, type, ++ NL80211_IFTYPE_P2P_DEVICE); ++ // Look for an available VIF ++ if (type == NL80211_IFTYPE_AP_VLAN) { ++ min_idx = NX_VIRT_DEV_MAX; ++ max_idx = NX_VIRT_DEV_MAX + NX_REMOTE_STA_MAX; ++ } else { ++ min_idx = 0; ++ max_idx = NX_VIRT_DEV_MAX; ++ } ++ ++ for (i = min_idx; i < max_idx; i++) { ++ if ((rwnx_hw->avail_idx_map) & BIT(i)) { ++ vif_idx = i; ++ break; ++ } ++ } ++ if (vif_idx < 0) ++ return NULL; ++ ++#ifndef CONFIG_RWNX_MON_DATA ++ list_for_each_entry (vif, &rwnx_hw->vifs, list) { ++ // Check if monitor interface already exists or type is monitor ++ if ((RWNX_VIF_TYPE(vif) == NL80211_IFTYPE_MONITOR) || ++ (type == NL80211_IFTYPE_MONITOR)) { ++ wiphy_err( ++ rwnx_hw->wiphy, ++ "Monitor+Data interface support (MON_DATA) disabled\n"); ++ return NULL; ++ } ++ } ++#endif ++ ++#ifndef CONFIG_ONE_TXQ ++ ndev = alloc_netdev_mqs(sizeof(*vif), name, name_assign_type, ++ rwnx_netdev_setup, nx_nb_ndev_txq, 1); ++#else ++ ndev = alloc_netdev_mqs(sizeof(*vif), name, name_assign_type, ++ rwnx_netdev_setup, 1, 1); ++#endif ++ ++ if (!ndev) ++ return NULL; ++ ++ vif = netdev_priv(ndev); ++ vif->key_has_add = 0; ++ ndev->ieee80211_ptr = &vif->wdev; ++ vif->wdev.wiphy = rwnx_hw->wiphy; ++ vif->rwnx_hw = rwnx_hw; ++ vif->ndev = ndev; ++ vif->drv_vif_index = vif_idx; ++ SET_NETDEV_DEV(ndev, wiphy_dev(vif->wdev.wiphy)); ++ vif->wdev.netdev = ndev; ++ vif->wdev.iftype = type; ++ vif->up = false; ++ vif->ch_index = RWNX_CH_NOT_SET; ++ memset(&vif->net_stats, 0, sizeof(vif->net_stats)); ++ vif->is_p2p_vif = 0; ++ ++#ifdef CONFIG_BR_SUPPORT ++ spin_lock_init(&vif->br_ext_lock); ++#endif /* CONFIG_BR_SUPPORT */ ++ ++ switch (type) { ++ case NL80211_IFTYPE_STATION: ++ vif->sta.ap = NULL; ++ vif->sta.tdls_sta = NULL; ++ vif->sta.external_auth = false; ++ break; ++ case NL80211_IFTYPE_P2P_CLIENT: ++ vif->sta.ap = NULL; ++ vif->sta.tdls_sta = NULL; ++ vif->sta.external_auth = false; ++ vif->is_p2p_vif = 1; ++ break; ++ case NL80211_IFTYPE_MESH_POINT: ++ INIT_LIST_HEAD(&vif->ap.mpath_list); ++ INIT_LIST_HEAD(&vif->ap.proxy_list); ++ vif->ap.create_path = false; ++ vif->ap.generation = 0; ++ vif->ap.mesh_pm = NL80211_MESH_POWER_ACTIVE; ++ vif->ap.next_mesh_pm = NL80211_MESH_POWER_ACTIVE; ++ // no break ++ case NL80211_IFTYPE_AP: ++ INIT_LIST_HEAD(&vif->ap.sta_list); ++ memset(&vif->ap.bcn, 0, sizeof(vif->ap.bcn)); ++ break; ++ case NL80211_IFTYPE_P2P_GO: ++ INIT_LIST_HEAD(&vif->ap.sta_list); ++ memset(&vif->ap.bcn, 0, sizeof(vif->ap.bcn)); ++ vif->is_p2p_vif = 1; ++ break; ++ case NL80211_IFTYPE_AP_VLAN: { ++ struct rwnx_vif *master_vif; ++ bool found = false; ++ list_for_each_entry (master_vif, &rwnx_hw->vifs, list) { ++ if ((RWNX_VIF_TYPE(master_vif) == NL80211_IFTYPE_AP) && ++ !(!memcmp(master_vif->ndev->dev_addr, ++ params->macaddr, ETH_ALEN))) { ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) ++ goto err; ++ ++ vif->ap_vlan.master = master_vif; ++ vif->ap_vlan.sta_4a = NULL; ++ break; ++ } ++ case NL80211_IFTYPE_MONITOR: ++ ndev->type = ARPHRD_IEEE80211_RADIOTAP; ++ ndev->netdev_ops = &rwnx_netdev_monitor_ops; ++ break; ++ default: ++ break; ++ } ++ ++ if (type == NL80211_IFTYPE_AP_VLAN) { ++ memcpy((void *)ndev->dev_addr, (const void *)params->macaddr, ++ ETH_ALEN); ++ memcpy((void *)vif->wdev.address, (const void *)params->macaddr, ++ ETH_ALEN); ++ } else { ++#if LINUX_VERSION_CODE > KERNEL_VERSION(5, 17, 0) ++ unsigned char mac_addr[6]; ++ memcpy(mac_addr, rwnx_hw->wiphy->perm_addr, ETH_ALEN); ++ mac_addr[5] ^= vif_idx; ++ //memcpy(ndev->dev_addr, mac_addr, ETH_ALEN); ++ eth_hw_addr_set(ndev, mac_addr); ++ memcpy(vif->wdev.address, mac_addr, ETH_ALEN); ++#else ++ memcpy(ndev->dev_addr, rwnx_hw->wiphy->perm_addr, ETH_ALEN); ++ ndev->dev_addr[5] ^= vif_idx; ++ memcpy(vif->wdev.address, ndev->dev_addr, ETH_ALEN); ++#endif ++ } ++ ++ AICWFDBG(LOGINFO, "interface add:%x %x %x %x %x %x\n", ++ vif->wdev.address[0], vif->wdev.address[1], ++ vif->wdev.address[2], vif->wdev.address[3], ++ vif->wdev.address[4], vif->wdev.address[5]); ++ ++ if (params) { ++ vif->use_4addr = params->use_4addr; ++ ndev->ieee80211_ptr->use_4addr = params->use_4addr; ++ } else ++ vif->use_4addr = false; ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0) ++ if (cfg80211_register_netdevice(ndev)) ++#else ++ if (register_netdevice(ndev)) ++#endif ++ goto err; ++ ++ spin_lock_bh(&rwnx_hw->cb_lock); ++ list_add_tail(&vif->list, &rwnx_hw->vifs); ++ spin_unlock_bh(&rwnx_hw->cb_lock); ++ rwnx_hw->avail_idx_map &= ~BIT(vif_idx); ++ ++ return vif; ++ ++err: ++ free_netdev(ndev); ++ return NULL; ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) ++void aicwf_p2p_alive_timeout(ulong data) ++#else ++void aicwf_p2p_alive_timeout(struct timer_list *t) ++#endif ++{ ++ struct rwnx_hw *rwnx_hw; ++ struct rwnx_vif *rwnx_vif; ++ struct rwnx_vif *rwnx_vif1, *tmp; ++ u8_l p2p = 0; ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) ++ rwnx_vif = (struct rwnx_vif *)data; ++ rwnx_hw = rwnx_vif->rwnx_hw; ++#else ++ rwnx_hw = timer_container_of(rwnx_hw, t, p2p_alive_timer); ++ rwnx_vif = rwnx_hw->p2p_dev_vif; ++#endif ++ ++ list_for_each_entry_safe (rwnx_vif1, tmp, &rwnx_hw->vifs, list) { ++ if ((rwnx_hw->avail_idx_map & BIT(rwnx_vif1->drv_vif_index)) == ++ 0) { ++ switch (RWNX_VIF_TYPE(rwnx_vif1)) { ++ case NL80211_IFTYPE_P2P_CLIENT: ++ case NL80211_IFTYPE_P2P_GO: ++ rwnx_hw->is_p2p_alive = 1; ++ p2p = 1; ++ break; ++ default: ++ break; ++ } ++ } ++ } ++ ++ if (p2p) ++ atomic_set(&rwnx_hw->p2p_alive_timer_count, 0); ++ else ++ atomic_inc(&rwnx_hw->p2p_alive_timer_count); ++ ++ if (atomic_read(&rwnx_hw->p2p_alive_timer_count) < ++ P2P_ALIVE_TIME_COUNT) { ++ mod_timer(&rwnx_hw->p2p_alive_timer, ++ jiffies + msecs_to_jiffies(P2P_ALIVE_TIME_MS)); ++ return; ++ } else ++ atomic_set(&rwnx_hw->p2p_alive_timer_count, 0); ++ ++ rwnx_hw->is_p2p_alive = 0; ++ 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; ++ AICWFDBG(LOGDEBUG, "%s rwnx_vif[%d] down \r\n", __func__, ++ rwnx_vif->vif_index); ++ rwnx_hw->vif_started--; ++ spin_unlock_bh(&rwnx_hw->cb_lock); ++ } ++} ++ ++/********************************************************************* ++ * Cfg80211 callbacks (and helper) ++ *********************************************************************/ ++static struct wireless_dev * ++rwnx_virtual_interface_add(struct rwnx_hw *rwnx_hw, const char *name, ++ unsigned char name_assign_type, ++ enum nl80211_iftype type, struct vif_params *params) ++{ ++ struct wireless_dev *wdev = NULL; ++ struct rwnx_vif *vif; ++ int min_idx, max_idx; ++ int vif_idx = -1; ++ int i; ++ ++ printk("rwnx_virtual_interface_add: %d, %s\n", type, name); ++ ++ if (type == NL80211_IFTYPE_AP_VLAN) { ++ min_idx = NX_VIRT_DEV_MAX; ++ max_idx = NX_VIRT_DEV_MAX + NX_REMOTE_STA_MAX; ++ } else { ++ min_idx = 0; ++ max_idx = NX_VIRT_DEV_MAX; ++ } ++ ++ for (i = min_idx; i < max_idx; i++) { ++ if ((rwnx_hw->avail_idx_map) & BIT(i)) { ++ vif_idx = i; ++ break; ++ } ++ } ++ ++ if (vif_idx < 0) { ++ printk("virtual_interface_add %s fail\n", name); ++ return NULL; ++ } ++ ++ vif = kzalloc(sizeof(struct rwnx_vif), GFP_KERNEL); ++ if (unlikely(!vif)) { ++ printk("Could not allocate wireless device\n"); ++ return NULL; ++ } ++ wdev = &vif->wdev; ++ wdev->wiphy = rwnx_hw->wiphy; ++ wdev->iftype = type; ++ ++ printk("rwnx_virtual_interface_add, ifname=%s, wdev=%p, vif_idx=%d\n", ++ name, wdev, vif_idx); ++ ++#ifndef CONFIG_USE_P2P0 ++ vif->is_p2p_vif = 1; ++ vif->rwnx_hw = rwnx_hw; ++ vif->vif_index = vif_idx; ++ vif->wdev.wiphy = rwnx_hw->wiphy; ++ vif->drv_vif_index = vif_idx; ++ vif->up = false; ++ vif->ch_index = RWNX_CH_NOT_SET; ++ memset(&vif->net_stats, 0, sizeof(vif->net_stats)); ++ vif->use_4addr = false; ++ ++ spin_lock_bh(&rwnx_hw->cb_lock); ++ list_add_tail(&vif->list, &rwnx_hw->vifs); ++ spin_unlock_bh(&rwnx_hw->cb_lock); ++ ++ if (rwnx_hw->is_p2p_alive == 0) { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) ++ init_timer(&rwnx_hw->p2p_alive_timer); ++ rwnx_hw->p2p_alive_timer.data = (unsigned long)vif; ++ rwnx_hw->p2p_alive_timer.function = aicwf_p2p_alive_timeout; ++#else ++ timer_setup(&rwnx_hw->p2p_alive_timer, aicwf_p2p_alive_timeout, ++ 0); ++#endif ++ rwnx_hw->is_p2p_alive = 0; ++ rwnx_hw->is_p2p_connected = 0; ++ rwnx_hw->p2p_dev_vif = vif; ++ atomic_set(&rwnx_hw->p2p_alive_timer_count, 0); ++ } ++#endif ++ rwnx_hw->avail_idx_map &= ~BIT(vif_idx); ++ ++ memcpy(vif->wdev.address, rwnx_hw->wiphy->perm_addr, ETH_ALEN); ++ vif->wdev.address[5] ^= vif_idx; ++ printk("p2p dev addr=%x %x %x %x %x %x\n", vif->wdev.address[0], ++ vif->wdev.address[1], vif->wdev.address[2], vif->wdev.address[3], ++ vif->wdev.address[4], vif->wdev.address[5]); ++ ++ return wdev; ++} ++ ++/* ++ * @brief Retrieve the rwnx_sta object allocated for a given MAC address ++ * and a given role. ++ */ ++static struct rwnx_sta *rwnx_retrieve_sta(struct rwnx_hw *rwnx_hw, ++ struct rwnx_vif *rwnx_vif, u8 *addr, ++ __le16 fc, bool ap) ++{ ++ if (ap) { ++ /* only deauth, disassoc and action are bufferable MMPDUs */ ++ bool bufferable = ieee80211_is_deauth(fc) || ++ ieee80211_is_disassoc(fc) || ++ ieee80211_is_action(fc); ++ ++ /* Check if the packet is bufferable or not */ ++ if (bufferable) { ++ /* Check if address is a broadcast or a multicast address */ ++ if (is_broadcast_ether_addr(addr) || ++ is_multicast_ether_addr(addr)) { ++ /* Returned STA pointer */ ++ struct rwnx_sta *rwnx_sta = ++ &rwnx_hw->sta_table[rwnx_vif->ap ++ .bcmc_index]; ++ ++ if (rwnx_sta->valid) ++ return rwnx_sta; ++ } else { ++ /* Returned STA pointer */ ++ struct rwnx_sta *rwnx_sta; ++ ++ /* Go through list of STAs linked with the provided VIF */ ++ spin_lock_bh(&rwnx_vif->rwnx_hw->cb_lock); ++ list_for_each_entry (rwnx_sta, ++ &rwnx_vif->ap.sta_list, ++ list) { ++ if (rwnx_sta->valid && ++ ether_addr_equal(rwnx_sta->mac_addr, ++ addr)) { ++ /* Return the found STA */ ++ spin_unlock_bh( ++ &rwnx_vif->rwnx_hw ++ ->cb_lock); ++ return rwnx_sta; ++ } ++ } ++ spin_unlock_bh(&rwnx_vif->rwnx_hw->cb_lock); ++ } ++ } ++ } else { ++ return rwnx_vif->sta.ap; ++ } ++ ++ return NULL; ++} ++ ++/** ++ * @add_virtual_intf: create a new virtual interface with the given name, ++ * must set the struct wireless_dev's iftype. Beware: You must create ++ * the new netdev in the wiphy's network namespace! Returns the struct ++ * wireless_dev, or an ERR_PTR. For P2P device wdevs, the driver must ++ * also set the address member in the wdev. ++ */ ++static struct wireless_dev * ++rwnx_cfg80211_add_iface(struct wiphy *wiphy, const char *name, ++ unsigned char name_assign_type, ++ enum nl80211_iftype type, struct vif_params *params) ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct wireless_dev *wdev; ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)) ++ unsigned char name_assign_type = NET_NAME_UNKNOWN; ++#endif ++ ++ if (type != NL80211_IFTYPE_P2P_DEVICE) { ++ struct rwnx_vif *vif = rwnx_interface_add( ++ rwnx_hw, name, name_assign_type, type, params); ++ if (!vif) ++ return ERR_PTR(-EINVAL); ++ return &vif->wdev; ++ ++ } else { ++ wdev = rwnx_virtual_interface_add( ++ rwnx_hw, name, name_assign_type, type, params); ++ if (!wdev) ++ return ERR_PTR(-EINVAL); ++ return wdev; ++ } ++} ++ ++/** ++ * @del_virtual_intf: remove the virtual interface ++ */ ++static int rwnx_cfg80211_del_iface(struct wiphy *wiphy, ++ struct wireless_dev *wdev) ++{ ++ struct net_device *dev = wdev->netdev; ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *rwnx_vif = container_of(wdev, struct rwnx_vif, wdev); ++ ++ AICWFDBG(LOGINFO, "del_iface: %p, %x\n", wdev, wdev->address[5]); ++ ++ if (!dev || !rwnx_vif->ndev) { ++ cfg80211_unregister_wdev(wdev); ++ spin_lock_bh(&rwnx_hw->cb_lock); ++ list_del(&rwnx_vif->list); ++ spin_unlock_bh(&rwnx_hw->cb_lock); ++ rwnx_hw->avail_idx_map |= BIT(rwnx_vif->drv_vif_index); ++ rwnx_vif->ndev = NULL; ++ kfree(rwnx_vif); ++ return 0; ++ } ++ ++ netdev_info(dev, "Remove Interface"); ++ ++ if (dev->reg_state == NETREG_REGISTERED) { ++ /* Will call rwnx_close if interface is UP */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0) ++ cfg80211_unregister_netdevice(dev); ++#else ++ unregister_netdevice(dev); ++#endif ++ } ++ ++ spin_lock_bh(&rwnx_hw->cb_lock); ++ list_del(&rwnx_vif->list); ++ spin_unlock_bh(&rwnx_hw->cb_lock); ++ rwnx_hw->avail_idx_map |= BIT(rwnx_vif->drv_vif_index); ++ rwnx_vif->ndev = NULL; ++ ++ /* Clear the priv in adapter */ ++ dev->ieee80211_ptr = NULL; ++ ++ return 0; ++} ++ ++/** ++ * @change_virtual_intf: change type/configuration of virtual interface, ++ * keep the struct wireless_dev's iftype updated. ++ */ ++static int rwnx_cfg80211_change_iface(struct wiphy *wiphy, ++ struct net_device *dev, ++ enum nl80211_iftype type, ++ struct vif_params *params) ++{ ++#ifndef CONFIG_RWNX_MON_DATA ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++#endif ++ struct rwnx_vif *vif = netdev_priv(dev); ++ struct mm_add_if_cfm add_if_cfm; ++ bool_l p2p = false; ++ int ret; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ printk("change_if: %d to %d, %d, %d", vif->wdev.iftype, type, ++ NL80211_IFTYPE_P2P_CLIENT, NL80211_IFTYPE_STATION); ++ ++#ifndef CONFIG_RWNX_MON_DATA ++ if ((type == NL80211_IFTYPE_MONITOR) && ++ (RWNX_VIF_TYPE(vif) != NL80211_IFTYPE_MONITOR)) { ++ struct rwnx_vif *vif_el; ++ list_for_each_entry (vif_el, &rwnx_hw->vifs, list) { ++ // Check if data interface already exists ++ if ((vif_el != vif) && ++ (RWNX_VIF_TYPE(vif) != NL80211_IFTYPE_MONITOR)) { ++ wiphy_err( ++ rwnx_hw->wiphy, ++ "Monitor+Data interface support (MON_DATA) disabled\n"); ++ return -EIO; ++ } ++ } ++ } ++#endif ++ ++ // Reset to default case (i.e. not monitor) ++ dev->type = ARPHRD_ETHER; ++ dev->netdev_ops = &rwnx_netdev_ops; ++ ++ switch (type) { ++ case NL80211_IFTYPE_STATION: ++ case NL80211_IFTYPE_P2P_CLIENT: ++ vif->sta.ap = NULL; ++ vif->sta.tdls_sta = NULL; ++ vif->sta.external_auth = false; ++ break; ++ case NL80211_IFTYPE_MESH_POINT: ++ INIT_LIST_HEAD(&vif->ap.mpath_list); ++ INIT_LIST_HEAD(&vif->ap.proxy_list); ++ vif->ap.create_path = false; ++ vif->ap.generation = 0; ++ // no break ++ case NL80211_IFTYPE_AP: ++ case NL80211_IFTYPE_P2P_GO: ++ INIT_LIST_HEAD(&vif->ap.sta_list); ++ memset(&vif->ap.bcn, 0, sizeof(vif->ap.bcn)); ++ break; ++ case NL80211_IFTYPE_AP_VLAN: ++ return -EPERM; ++ case NL80211_IFTYPE_MONITOR: ++ dev->type = ARPHRD_IEEE80211_RADIOTAP; ++ dev->netdev_ops = &rwnx_netdev_monitor_ops; ++ break; ++ default: ++ break; ++ } ++ ++ vif->wdev.iftype = type; ++ if (params->use_4addr != -1) ++ vif->use_4addr = params->use_4addr; ++ if (type == NL80211_IFTYPE_P2P_CLIENT || type == NL80211_IFTYPE_P2P_GO) ++ p2p = true; ++ ++ if (vif->up) { ++ /* Abort scan request on the vif */ ++ if (vif->rwnx_hw->scan_request && ++ vif->rwnx_hw->scan_request->wdev == &vif->wdev) { ++#if 0 ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0) ++ struct cfg80211_scan_info info = { ++ .aborted = true, ++ }; ++ ++ cfg80211_scan_done(vif->rwnx_hw->scan_request, &info); ++#else ++ cfg80211_scan_done(vif->rwnx_hw->scan_request, true); ++#endif ++ ret = rwnx_send_scanu_cancel_req(vif->rwnx_hw, NULL); ++ if (ret) { ++ printk("scanu_cancel fail\n"); ++ return ret; ++ } ++ vif->rwnx_hw->scan_request = NULL; ++#else ++ if ((ret = rwnx_send_scanu_cancel_req(vif->rwnx_hw, ++ NULL))) { ++ AICWFDBG(LOGERROR, "scanu_cancel fail\n"); ++ return ret; ++ } ++#endif ++ } ++ ret = rwnx_send_remove_if(vif->rwnx_hw, vif->vif_index, false); ++ if (ret) { ++ printk("remove_if fail\n"); ++ return ret; ++ } ++ vif->rwnx_hw->vif_table[vif->vif_index] = NULL; ++ printk("change_if from %d \n", vif->vif_index); ++ ret = rwnx_send_add_if(vif->rwnx_hw, vif->wdev.address, ++ RWNX_VIF_TYPE(vif), p2p, &add_if_cfm); ++ if (ret) { ++ printk("add if fail\n"); ++ return ret; ++ } ++ if (add_if_cfm.status != 0) { ++ printk("add if status fail\n"); ++ return -EIO; ++ } ++ ++ printk("change_if to %d \n", add_if_cfm.inst_nbr); ++ /* Save the index retrieved from LMAC */ ++ spin_lock_bh(&vif->rwnx_hw->cb_lock); ++ 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); ++ } ++ ++ if (type == NL80211_IFTYPE_MONITOR) { ++ vif->rwnx_hw->monitor_vif = vif->vif_index; ++#if defined(CONFIG_RWNX_MON_XMIT) ++ rwnx_txq_unk_vif_init(vif); ++#endif ++#if defined(CONFIG_RWNX_MON_RXFILTER) ++ rwnx_send_set_filter(vif->rwnx_hw, ++ (FIF_BCN_PRBRESP_PROMISC | FIF_OTHER_BSS | ++ FIF_PSPOLL | FIF_PROBE_REQ)); ++#endif ++ } else { ++ vif->rwnx_hw->monitor_vif = RWNX_INVALID_VIF; ++ } ++ ++ return 0; ++} ++ ++static int rwnx_cfgp2p_start_p2p_device(struct wiphy *wiphy, ++ struct wireless_dev *wdev) ++{ ++ int ret = 0; ++ ++ //do nothing ++ printk("P2P interface started\n"); ++ ++ return ret; ++} ++ ++static void rwnx_cfgp2p_stop_p2p_device(struct wiphy *wiphy, ++ struct wireless_dev *wdev) ++{ ++ int ret = 0; ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *rwnx_vif = container_of(wdev, struct rwnx_vif, wdev); ++ /* Abort scan request on the vif */ ++ if (rwnx_hw->scan_request && ++ rwnx_hw->scan_request->wdev == &rwnx_vif->wdev) { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0) ++ struct cfg80211_scan_info info = { ++ .aborted = true, ++ }; ++ ++ cfg80211_scan_done(rwnx_hw->scan_request, &info); ++#else ++ cfg80211_scan_done(rwnx_hw->scan_request, true); ++#endif ++ rwnx_hw->scan_request = NULL; ++ ret = rwnx_send_scanu_cancel_req(rwnx_hw, NULL); ++ 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)) { ++ timer_delete_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; ++ AICWFDBG(LOGDEBUG, "%s rwnx_vif[%d] down \r\n", ++ __func__, rwnx_vif->vif_index); ++ rwnx_hw->vif_started--; ++ spin_unlock_bh(&rwnx_hw->cb_lock); ++ } ++ } ++ ++ printk("Exit. P2P interface stopped\n"); ++ ++ return; ++} ++ ++/** ++ * @scan: Request to do a scan. If returning zero, the scan request is given ++ * the driver, and will be valid until passed to cfg80211_scan_done(). ++ * For scan results, call cfg80211_inform_bss(); you can call this outside ++ * the scan/scan_done bracket too. ++ */ ++static int rwnx_cfg80211_scan(struct wiphy *wiphy, ++ struct cfg80211_scan_request *request) ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *rwnx_vif = ++ container_of(request->wdev, struct rwnx_vif, wdev); ++ int error; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ if (testmode) { ++ return -EBUSY; ++ } ++ ++ if ((int)atomic_read(&rwnx_vif->drv_conn_state) == ++ (int)RWNX_DRV_STATUS_CONNECTING) { ++ AICWFDBG(LOGERROR, "%s wifi is connecting, return it\r\n", ++ __func__); ++ return -EBUSY; ++ } ++ ++ if (scanning) { ++ AICWFDBG(LOGERROR, "%s is scanning, abort\n", __func__); ++#if 0 ++ error = rwnx_send_scanu_cancel_req(rwnx_hw, NULL); ++ if (error) ++ return error; ++ msleep(150); ++#endif ++ return -EBUSY; ++ } ++ ++ if ((RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_STATION || ++ RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_P2P_CLIENT) && ++ rwnx_vif->sta.external_auth) { ++ AICWFDBG(LOGERROR, "scan about: external auth\r\n"); ++ return -EBUSY; ++ } ++ ++ rwnx_hw->scan_request = request; ++ error = rwnx_send_scanu_req(rwnx_hw, rwnx_vif, request); ++ if (error) ++ return error; ++ ++ return 0; ++} ++ ++bool key_flag = false; ++/** ++ * @add_key: add a key with the given parameters. @mac_addr will be %NULL ++ * when adding a group key. ++ */ ++static int rwnx_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev, ++#if (LINUX_VERSION_CODE >= HIGH_KERNEL_VERSION2) ++ int link_id, ++#endif ++ u8 key_index, bool pairwise, ++ const u8 *mac_addr, struct key_params *params) ++ ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *vif = netdev_priv(netdev); ++ int i, error = 0; ++ struct mm_key_add_cfm key_add_cfm; ++ u8_l cipher = 0; ++ struct rwnx_sta *sta = NULL; ++ struct rwnx_key *rwnx_key; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ if (mac_addr) { ++ sta = rwnx_get_sta(rwnx_hw, mac_addr); ++ if (!sta) ++ return -EINVAL; ++ rwnx_key = &sta->key; ++ if (vif->wdev.iftype == NL80211_IFTYPE_STATION || ++ vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ++ vif->sta.paired_cipher_type = params->cipher; ++ } else { ++ rwnx_key = &vif->key[key_index]; ++ vif->key_has_add = 1; ++ if (vif->wdev.iftype == NL80211_IFTYPE_STATION || ++ vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ++ vif->sta.group_cipher_type = params->cipher; ++ } ++ ++ /* Retrieve the cipher suite selector */ ++ switch (params->cipher) { ++ case WLAN_CIPHER_SUITE_WEP40: ++ cipher = MAC_CIPHER_WEP40; ++ break; ++ case WLAN_CIPHER_SUITE_WEP104: ++ cipher = MAC_CIPHER_WEP104; ++ break; ++ case WLAN_CIPHER_SUITE_TKIP: ++ cipher = MAC_CIPHER_TKIP; ++ break; ++ case WLAN_CIPHER_SUITE_CCMP: ++ cipher = MAC_CIPHER_CCMP; ++ break; ++ case WLAN_CIPHER_SUITE_AES_CMAC: ++ cipher = MAC_CIPHER_BIP_CMAC_128; ++ break; ++ case WLAN_CIPHER_SUITE_SMS4: { ++ // Need to reverse key order ++ u8 tmp, *key = (u8 *)params->key; ++ cipher = MAC_CIPHER_WPI_SMS4; ++ for (i = 0; i < WPI_SUBKEY_LEN / 2; i++) { ++ tmp = key[i]; ++ key[i] = key[WPI_SUBKEY_LEN - 1 - i]; ++ key[WPI_SUBKEY_LEN - 1 - i] = tmp; ++ } ++ for (i = 0; i < WPI_SUBKEY_LEN / 2; i++) { ++ tmp = key[i + WPI_SUBKEY_LEN]; ++ key[i + WPI_SUBKEY_LEN] = key[WPI_KEY_LEN - 1 - i]; ++ key[WPI_KEY_LEN - 1 - i] = tmp; ++ } ++ break; ++ } ++ default: ++ return -EINVAL; ++ } ++ ++ key_flag = false; ++ error = rwnx_send_key_add(rwnx_hw, vif->vif_index, ++ (sta ? sta->sta_idx : 0xFF), pairwise, ++ (u8 *)params->key, params->key_len, key_index, ++ cipher, &key_add_cfm); ++ if (error) ++ return error; ++ ++ if (key_add_cfm.status != 0) { ++ RWNX_PRINT_CFM_ERR(key_add); ++ return -EIO; ++ } ++ ++ /* Save the index retrieved from LMAC */ ++ rwnx_key->hw_idx = key_add_cfm.hw_key_idx; ++ ++ return 0; ++} ++ ++/** ++ * @get_key: get information about the key with the given parameters. ++ * @mac_addr will be %NULL when requesting information for a group ++ * key. All pointers given to the @callback function need not be valid ++ * after it returns. This function should return an error if it is ++ * not possible to retrieve the key, -ENOENT if it doesn't exist. ++ * ++ */ ++static int rwnx_cfg80211_get_key(struct wiphy *wiphy, struct net_device *netdev, ++#if (LINUX_VERSION_CODE >= HIGH_KERNEL_VERSION2) ++ int link_id, ++#endif ++ u8 key_index, bool pairwise, ++ const u8 *mac_addr, void *cookie, ++ void (*callback)(void *cookie, ++ struct key_params *)) ++{ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ return -1; ++} ++ ++/** ++ * @del_key: remove a key given the @mac_addr (%NULL for a group key) ++ * and @key_index, return -ENOENT if the key doesn't exist. ++ */ ++static int rwnx_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev, ++#if (LINUX_VERSION_CODE >= HIGH_KERNEL_VERSION2) ++ int link_id, ++#endif ++ u8 key_index, bool pairwise, ++ const u8 *mac_addr) ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *vif = netdev_priv(netdev); ++ int error; ++ struct rwnx_sta *sta = NULL; ++ struct rwnx_key *rwnx_key; ++ if (!key_flag && vif->wdev.iftype == NL80211_IFTYPE_STATION) ++ return 0; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ if (mac_addr) { ++ sta = rwnx_get_sta(rwnx_hw, mac_addr); ++ if (!sta) ++ return -EINVAL; ++ rwnx_key = &sta->key; ++ if (vif->wdev.iftype == NL80211_IFTYPE_STATION || ++ vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ++ vif->sta.paired_cipher_type = 0xff; ++ } else { ++ rwnx_key = &vif->key[key_index]; ++ vif->key_has_add = 0; ++ if (vif->wdev.iftype == NL80211_IFTYPE_STATION || ++ vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ++ vif->sta.group_cipher_type = 0xff; ++ } ++ ++ error = rwnx_send_key_del(rwnx_hw, rwnx_key->hw_idx); ++ ++ rwnx_key->hw_idx = 0; ++ return error; ++} ++ ++/** ++ * @set_default_key: set the default key on an interface ++ */ ++static int rwnx_cfg80211_set_default_key(struct wiphy *wiphy, ++ struct net_device *netdev, ++#if (LINUX_VERSION_CODE >= HIGH_KERNEL_VERSION2) ++ int link_id, ++#endif ++ u8 key_index, bool unicast, ++ bool multicast) ++{ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ return 0; ++} ++ ++/** ++ * @set_default_mgmt_key: set the default management frame key on an interface ++ */ ++static int rwnx_cfg80211_set_default_mgmt_key(struct wiphy *wiphy, ++ struct net_device *netdev, ++#if (LINUX_VERSION_CODE >= HIGH_KERNEL_VERSION2) ++ int link_id, ++#endif ++ u8 key_index) ++{ ++ return 0; ++} ++ ++/** ++ * @connect: Connect to the ESS with the specified parameters. When connected, ++ * call cfg80211_connect_result() with status code %WLAN_STATUS_SUCCESS. ++ * If the connection fails for some reason, call cfg80211_connect_result() ++ * with the status from the AP. ++ * (invoked with the wireless_dev mutex held) ++ */ ++static int rwnx_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_connect_params *sme) ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ 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 1 ++ if ((int)atomic_read(&rwnx_vif->drv_conn_state) == ++ (int)RWNX_DRV_STATUS_CONNECTED) { ++ AICWFDBG(LOGDEBUG, "%s this connection is roam \r\n", __func__); ++ rwnx_vif->sta.is_roam = true; ++ } else { ++ rwnx_vif->sta.is_roam = false; ++ } ++ ++ if ((int)atomic_read(&rwnx_vif->drv_conn_state) == ++ (int)RWNX_DRV_STATUS_DISCONNECTING || ++ (int)atomic_read(&rwnx_vif->drv_conn_state) == ++ (int)RWNX_DRV_STATUS_CONNECTING) { ++ AICWFDBG( ++ LOGERROR, ++ "%s driver is disconnecting or connecting ,return it \r\n", ++ __func__); ++ return 0; ++ } ++#endif ++ ++ if (rwnx_vif->sta.is_roam) { ++ rwnx_set_conn_state(&rwnx_vif->drv_conn_state, ++ (int)RWNX_DRV_STATUS_ROAMING); ++ } else { ++ rwnx_set_conn_state(&rwnx_vif->drv_conn_state, ++ (int)RWNX_DRV_STATUS_CONNECTING); ++ } ++ ++ 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"); ++ } ++ } ++ } ++ } ++ ++ /* For SHARED-KEY authentication, must install key first */ ++ if (sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY && sme->key) { ++ struct key_params key_params; ++ key_params.key = (u8 *)sme->key; ++ key_params.seq = NULL; ++ key_params.key_len = sme->key_len; ++ key_params.seq_len = 0; ++ key_params.cipher = sme->crypto.cipher_group; ++ rwnx_cfg80211_add_key(wiphy, dev, ++#if (LINUX_VERSION_CODE >= HIGH_KERNEL_VERSION2) ++ 0, ++#endif ++ sme->key_idx, false, NULL, &key_params); ++ } ++#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"); ++ return -EINVAL; ++ } ++#endif ++ ++ if (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) { ++ rwnx_hw->is_p2p_connected = 1; ++ } ++ ++ if (rwnx_vif->wdev.iftype == NL80211_IFTYPE_STATION || ++ rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) { ++ rwnx_vif->sta.paired_cipher_type = 0xff; ++ rwnx_vif->sta.group_cipher_type = 0xff; ++ } ++ ++ /* Forward the information to the LMAC */ ++ error = rwnx_send_sm_connect_req(rwnx_hw, rwnx_vif, sme, ++ &sm_connect_cfm); ++ if (error) ++ return error; ++ ++ // Check the status ++ switch (sm_connect_cfm.status) { ++ case CO_OK: ++ error = 0; ++ break; ++ case CO_BUSY: ++ error = -EINPROGRESS; ++ break; ++ case CO_OP_IN_PROGRESS: ++ error = -EALREADY; ++ break; ++ default: ++ error = -EIO; ++ break; ++ } ++ ++ return error; ++} ++ ++/** ++ * @disconnect: Disconnect from the BSS/ESS. ++ * (invoked with the wireless_dev mutex held) ++ */ ++static int rwnx_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, ++ u16 reason_code) ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ int ret = 0; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ AICWFDBG(LOGINFO, "%s drv_vif_index:%d disconnect reason:%d \r\n", ++ __func__, rwnx_vif->drv_vif_index, reason_code); ++ ++ if (atomic_read(&rwnx_vif->drv_conn_state) == ++ RWNX_DRV_STATUS_DISCONNECTED) { ++ AICWFDBG(LOGERROR, "%s this\r\n", __func__); ++ WARN_ON(1); ++ return -EBUSY; ++ } ++ ++ if (atomic_read(&rwnx_vif->drv_conn_state) == ++ RWNX_DRV_STATUS_DISCONNECTING) { ++ AICWFDBG(LOGERROR, ++ "%s wifi is disconnecting, return it:%d \r\n", ++ __func__, reason_code); ++ return -EBUSY; ++ } ++ ++ if (atomic_read(&rwnx_vif->drv_conn_state) == ++ RWNX_DRV_STATUS_CONNECTED || ++ atomic_read(&rwnx_vif->drv_conn_state) == ++ RWNX_DRV_STATUS_CONNECTING || ++ atomic_read(&rwnx_vif->drv_conn_state) == RWNX_DRV_STATUS_ROAMING) { ++ rwnx_set_conn_state(&rwnx_vif->drv_conn_state, ++ RWNX_DRV_STATUS_DISCONNECTING); ++ key_flag = true; ++ ret = rwnx_send_sm_disconnect_req(rwnx_hw, rwnx_vif, ++ reason_code); ++#ifdef AICWF_SDIO_SUPPORT ++ if (rwnx_hw->sdiodev->bus_if->state == BUS_DOWN_ST) { ++ AICWFDBG(LOGINFO, "%s bus is down %d\n", __func__, ret); ++ rwnx_set_conn_state(&rwnx_vif->drv_conn_state, ++ RWNX_DRV_STATUS_DISCONNECTED); ++ } ++#endif ++ return ret; ++ } ++#if 0 ++ else { ++ cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0, ++ reason_code?reason_code:WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_ATOMIC); ++ rwnx_set_conn_state(&rwnx_vif->drv_conn_state, RWNX_DRV_STATUS_DISCONNECTED); ++ rwnx_external_auth_disable(rwnx_vif); ++ return 0; ++ } ++#endif ++ return 0; ++} ++ ++#ifdef CONFIG_SCHED_SCAN ++ ++static int rwnx_cfg80211_sched_scan_stop(struct wiphy *wiphy, ++ struct net_device *ndev ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) ++ , ++ u64 reqid) ++#else ++) ++#endif ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ //struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ AICWFDBG(LOGINFO, "%s enter wiphy:%p\r\n", __func__, wiphy); ++ ++ if (rwnx_hw->scan_request) { ++ AICWFDBG(LOGINFO, "%s rwnx_send_scanu_cancel_req\r\n", ++ __func__); ++ return rwnx_send_scanu_cancel_req(rwnx_hw, NULL); ++ } else { ++ return 0; ++ } ++} ++ ++static int ++rwnx_cfg80211_sched_scan_start(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_sched_scan_request *request) ++ ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ struct cfg80211_scan_request *scan_request = NULL; ++ ++ int ret = 0; ++ int index = 0; ++ ++ AICWFDBG(LOGINFO, "%s enter wiphy:%p\r\n", __func__, wiphy); ++ ++ if (rwnx_hw->is_sched_scan || scanning) { ++ AICWFDBG(LOGERROR, "%s is_sched_scanning and scanning, busy", ++ __func__); ++ return -EBUSY; ++ } ++ ++ scan_request = (struct cfg80211_scan_request *)kmalloc( ++ sizeof(struct cfg80211_scan_request), GFP_KERNEL); ++ ++ scan_request->ssids = request->ssids; ++ scan_request->n_channels = request->n_channels; ++ scan_request->n_ssids = request->n_match_sets; ++ scan_request->no_cck = false; ++ scan_request->ie = request->ie; ++ scan_request->ie_len = request->ie_len; ++ scan_request->flags = request->flags; ++ ++ scan_request->wiphy = wiphy; ++ scan_request->scan_start = request->scan_start; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) ++ memcpy(scan_request->mac_addr, request->mac_addr, ETH_ALEN); ++ memcpy(scan_request->mac_addr_mask, request->mac_addr_mask, ETH_ALEN); ++#endif ++ rwnx_hw->sched_scan_req = request; ++ scan_request->wdev = &rwnx_vif->wdev; ++ AICWFDBG(LOGDEBUG, "%s scan_request->n_channels:%d \r\n", __func__, ++ scan_request->n_channels); ++ AICWFDBG(LOGDEBUG, "%s scan_request->n_ssids:%d \r\n", __func__, ++ scan_request->n_ssids); ++ ++ for (index = 0; index < scan_request->n_ssids; index++) { ++ memset(scan_request->ssids[index].ssid, 0, ++ IEEE80211_MAX_SSID_LEN); ++ ++ memcpy(scan_request->ssids[index].ssid, ++ request->match_sets[index].ssid.ssid, ++ IEEE80211_MAX_SSID_LEN); ++ ++ scan_request->ssids[index].ssid_len = ++ request->match_sets[index].ssid.ssid_len; ++ ++ AICWFDBG(LOGDEBUG, "%s request ssid:%s len:%d \r\n", __func__, ++ scan_request->ssids[index].ssid, ++ scan_request->ssids[index].ssid_len); ++ } ++ ++ for (index = 0; index < scan_request->n_channels; index++) { ++ scan_request->channels[index] = request->channels[index]; ++ ++ AICWFDBG(LOGDEBUG, "%s scan_request->channels[%d]:%d \r\n", ++ __func__, index, ++ scan_request->channels[index]->center_freq); ++ ++ if (scan_request->channels[index] == NULL) { ++ AICWFDBG(LOGERROR, "%s ERROR!!! channels is NULL", ++ __func__); ++ continue; ++ } ++ } ++ ++ rwnx_hw->is_sched_scan = true; ++ ++ if (scanning) { ++ AICWFDBG(LOGERROR, "%s scanning, about it", __func__); ++ kfree(scan_request); ++ return -EBUSY; ++ } else { ++ ret = rwnx_cfg80211_scan(wiphy, scan_request); ++ } ++ ++ return ret; ++} ++#endif //CONFIG_SCHED_SCAN ++ ++#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 ++ */ ++static int ++rwnx_cfg80211_external_auth(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_external_auth_params *params) ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ ++ if (!rwnx_vif->sta.external_auth) ++ return -EINVAL; ++ ++ rwnx_external_auth_disable(rwnx_vif); ++ return rwnx_send_sm_external_auth_required_rsp(rwnx_hw, rwnx_vif, ++ params->status); ++} ++#endif ++ ++/** ++ * @add_station: Add a new station. ++ */ ++static int rwnx_cfg80211_add_station(struct wiphy *wiphy, ++ struct net_device *dev, ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0)) ++ u8 *mac, ++#else ++ const u8 *mac, ++#endif ++ struct station_parameters *params) ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ struct me_sta_add_cfm me_sta_add_cfm; ++ int error = 0; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ WARN_ON(RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_AP_VLAN); ++ ++ /* Do not add TDLS station */ ++ if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ++ return 0; ++ ++ /* Indicate we are in a STA addition process - This will allow handling ++ * potential PS mode change indications correctly ++ */ ++ rwnx_hw->adding_sta = true; ++ ++ /* Forward the information to the LMAC */ ++ error = rwnx_send_me_sta_add(rwnx_hw, params, mac, rwnx_vif->vif_index, ++ &me_sta_add_cfm); ++ if (error) ++ return error; ++ ++ // Check the status ++ switch (me_sta_add_cfm.status) { ++ case CO_OK: { ++ struct rwnx_sta *sta = ++ &rwnx_hw->sta_table[me_sta_add_cfm.sta_idx]; ++ int tid; ++ sta->aid = params->aid; ++ ++ sta->sta_idx = me_sta_add_cfm.sta_idx; ++ sta->ch_idx = rwnx_vif->ch_index; ++ sta->vif_idx = rwnx_vif->vif_index; ++ sta->vlan_idx = sta->vif_idx; ++ sta->qos = (params->sta_flags_set & ++ BIT(NL80211_STA_FLAG_WME)) != 0; ++#if LINUX_VERSION_CODE >= HIGH_KERNEL_VERSION ++ sta->ht = params->link_sta_params.ht_capa ? 1 : 0; ++ sta->vht = params->link_sta_params.vht_capa ? 1 : 0; ++#else ++ sta->ht = params->ht_capa ? 1 : 0; ++ sta->vht = params->vht_capa ? 1 : 0; ++#endif ++ sta->acm = 0; ++ sta->key.hw_idx = 0; ++ ++ if (params->local_pm != NL80211_MESH_POWER_UNKNOWN) ++ sta->mesh_pm = params->local_pm; ++ else ++ sta->mesh_pm = rwnx_vif->ap.next_mesh_pm; ++ rwnx_update_mesh_power_mode(rwnx_vif); ++ ++ for (tid = 0; tid < NX_NB_TXQ_PER_STA; tid++) { ++ int uapsd_bit = rwnx_hwq2uapsd[rwnx_tid2hwq[tid]]; ++ if (params->uapsd_queues & uapsd_bit) ++ sta->uapsd_tids |= 1 << tid; ++ else ++ 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)); ++ list_add_tail(&sta->list, &rwnx_vif->ap.sta_list); ++ sta->valid = true; ++ rwnx_ps_bh_enable(rwnx_hw, sta, ++ sta->ps.active || me_sta_add_cfm.pm_state); ++ spin_unlock_bh(&rwnx_hw->cb_lock); ++ ++ error = 0; ++ ++ if (rwnx_vif->wdev.iftype == NL80211_IFTYPE_AP || ++ rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) { ++ struct station_info sinfo; ++ 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, 0, 0) ++ sinfo.filled |= STATION_INFO_ASSOC_REQ_IES; ++#endif ++ cfg80211_new_sta(rwnx_vif->ndev, sta->mac_addr, &sinfo, ++ GFP_KERNEL); ++ } ++#ifdef CONFIG_RWNX_BFMER ++ if (rwnx_hw->mod_params->bfmer) ++ rwnx_send_bfmer_enable(rwnx_hw, sta, params->vht_capa); ++ ++ rwnx_mu_group_sta_init(sta, params->vht_capa); ++#endif /* CONFIG_RWNX_BFMER */ ++ ++#define PRINT_STA_FLAG(f) \ ++ (params->sta_flags_set & BIT(NL80211_STA_FLAG_##f) ? "[" #f "]" : "") ++ ++ netdev_info(dev, "Add sta %d (%pM) flags=%s%s%s%s%s%s%s", ++ sta->sta_idx, mac, PRINT_STA_FLAG(AUTHORIZED), ++ PRINT_STA_FLAG(SHORT_PREAMBLE), PRINT_STA_FLAG(WME), ++ PRINT_STA_FLAG(MFP), PRINT_STA_FLAG(AUTHENTICATED), ++ PRINT_STA_FLAG(TDLS_PEER), ++ PRINT_STA_FLAG(ASSOCIATED)); ++#undef PRINT_STA_FLAG ++ break; ++ } ++ default: ++ error = -EBUSY; ++ break; ++ } ++ ++ rwnx_hw->adding_sta = false; ++ ++ return error; ++} ++ ++/** ++ * @del_station: Remove a station ++ */ ++static int rwnx_cfg80211_del_station_compat(struct wiphy *wiphy, ++ struct net_device *dev, ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0)) ++ u8 *mac ++#elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)) ++ const u8 *mac ++#else ++ struct station_del_parameters *params ++#endif ++ ++) ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ struct rwnx_sta *cur, *tmp; ++ int error = 0, found = 0; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) ++ const u8 *mac = NULL; ++#endif ++#ifdef AICWF_RX_REORDER ++ struct reord_ctrl_info *reord_info, *reord_tmp; ++ u8 *macaddr; ++ struct aicwf_rx_priv *rx_priv; ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) ++ if (params) ++ mac = params->mac; ++#endif ++ printk("%s: %pM\n", __func__, mac); ++ ++ do { ++ spin_lock_bh(&rwnx_hw->cb_lock); ++ if (list_empty(&rwnx_vif->ap.sta_list)) { ++ spin_unlock_bh(&rwnx_hw->cb_lock); ++ break; ++ } ++ ++ list_for_each_entry_safe (cur, tmp, &rwnx_vif->ap.sta_list, ++ list) { ++ if ((!mac) || (!memcmp(cur->mac_addr, mac, ETH_ALEN))) { ++ found = 1; ++ break; ++ } ++ } ++ ++ if (found) { ++ cur->ps.active = false; ++ cur->valid = false; ++ list_del(&cur->list); ++ } ++ spin_unlock_bh(&rwnx_hw->cb_lock); ++ ++ if (found) { ++ netdev_info(dev, "Del sta %d (%pM)", cur->sta_idx, ++ cur->mac_addr); ++ if (cur->vif_idx != cur->vlan_idx) { ++ struct rwnx_vif *vlan_vif; ++ vlan_vif = rwnx_hw->vif_table[cur->vlan_idx]; ++ if (vlan_vif->up) { ++ if ((RWNX_VIF_TYPE(vlan_vif) == ++ NL80211_IFTYPE_AP_VLAN) && ++ (vlan_vif->use_4addr)) { ++ vlan_vif->ap_vlan.sta_4a = NULL; ++ } else { ++ WARN(1, ++ "Deleting sta belonging to VLAN other than AP_VLAN 4A"); ++ } ++ } ++ } ++ if (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]); ++ 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; ++ } ++ } ++ } ++#endif ++ ++ rwnx_txq_sta_deinit(rwnx_hw, cur); ++ error = rwnx_send_me_sta_del(rwnx_hw, cur->sta_idx, ++ false); ++ if ((error != 0) && (error != -EPIPE)) ++ return error; ++ ++#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 */ ++ ++#ifdef CONFIG_DEBUG_FS_AIC ++ rwnx_dbgfs_unregister_rc_stat(rwnx_hw, cur); ++#endif ++ } ++ ++ if (mac) ++ break; ++ } while (1); ++ ++ rwnx_update_mesh_power_mode(rwnx_vif); ++ ++ if (!found && mac != NULL) ++ return -ENOENT; ++ else ++ 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; ++ } ++ ++ found = false; ++ spin_lock_bh(&rwnx_hw->cb_lock); ++ list_for_each_entry_safe (cur, tmp, &rwnx_vif->ap.sta_list, list) { ++ if ((mac) && (!memcmp(cur->mac_addr, mac, ETH_ALEN))) { ++ found = true; ++ break; ++ } ++ } ++ if (found) { ++ cur->ps.active = false; ++ cur->valid = false; ++ list_del(&cur->list); ++ } ++ spin_unlock_bh(&rwnx_hw->cb_lock); ++ ++ if (found) { ++ netdev_info(rwnx_vif->ndev, "Del sta %d (%pM)", cur->sta_idx, ++ cur->mac_addr); ++ if (cur->vif_idx != cur->vlan_idx) { ++ struct rwnx_vif *vlan_vif; ++ vlan_vif = rwnx_hw->vif_table[cur->vlan_idx]; ++ if (vlan_vif->up) { ++ if ((RWNX_VIF_TYPE(vlan_vif) == ++ NL80211_IFTYPE_AP_VLAN) && ++ (vlan_vif->use_4addr)) { ++ vlan_vif->ap_vlan.sta_4a = NULL; ++ } else { ++ WARN(1, ++ "Deleting sta belonging to VLAN other than AP_VLAN 4A"); ++ } ++ } ++ } ++ ++#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]); ++ 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; ++ } ++ } ++ } ++#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 */ ++ ++#ifdef CONFIG_DEBUG_FS_AIC ++ rwnx_dbgfs_unregister_rc_stat(rwnx_hw, cur); ++#endif ++ } else { ++ printk("sta not found: %pM\n", mac); ++ 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); ++ ++ spin_lock_bh(&rwnx_vif->rwnx_hw->cb_lock); ++ list_for_each_entry_safe (cur, tmp, &rwnx_vif->ap.sta_list, list) { ++ if (!memcmp(cur->mac_addr, mac, ETH_ALEN)) { ++ found = true; ++ break; ++ } ++ } ++ spin_unlock_bh(&rwnx_vif->rwnx_hw->cb_lock); ++ ++ 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 ++ * might come to the driver in invalid combinations -- make sure to check ++ * them, also against the existing state! Drivers must call ++ * cfg80211_check_station_change() to validate the information. ++ */ ++static int rwnx_cfg80211_change_station(struct wiphy *wiphy, ++ struct net_device *dev, ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0)) ++ u8 *mac, ++#else ++ const u8 *mac, ++#endif ++ struct station_parameters *params) ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *vif = netdev_priv(dev); ++ struct rwnx_sta *sta; ++ ++ sta = rwnx_get_sta(rwnx_hw, mac); ++ if (!sta) { ++ /* Add the TDLS station */ ++ if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) { ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ struct me_sta_add_cfm me_sta_add_cfm; ++ int error = 0; ++ ++ /* Indicate we are in a STA addition process - This will allow handling ++ * potential PS mode change indications correctly ++ */ ++ rwnx_hw->adding_sta = true; ++ ++ /* Forward the information to the LMAC */ ++ error = rwnx_send_me_sta_add(rwnx_hw, params, mac, ++ rwnx_vif->vif_index, ++ &me_sta_add_cfm); ++ if (error) ++ return error; ++ ++ // Check the status ++ switch (me_sta_add_cfm.status) { ++ case CO_OK: { ++ int tid; ++ sta = &rwnx_hw->sta_table[me_sta_add_cfm.sta_idx]; ++ sta->aid = params->aid; ++ sta->sta_idx = me_sta_add_cfm.sta_idx; ++ sta->ch_idx = rwnx_vif->ch_index; ++ sta->vif_idx = rwnx_vif->vif_index; ++ sta->vlan_idx = sta->vif_idx; ++ sta->qos = (params->sta_flags_set & ++ BIT(NL80211_STA_FLAG_WME)) != 0; ++#if LINUX_VERSION_CODE >= HIGH_KERNEL_VERSION ++ sta->ht = ++ params->link_sta_params.ht_capa ? 1 : 0; ++ sta->vht = params->link_sta_params.vht_capa ? ++ 1 : ++ 0; ++#else ++ sta->ht = params->ht_capa ? 1 : 0; ++ sta->vht = params->vht_capa ? 1 : 0; ++#endif ++ sta->acm = 0; ++ for (tid = 0; tid < NX_NB_TXQ_PER_STA; tid++) { ++ int uapsd_bit = ++ rwnx_hwq2uapsd[rwnx_tid2hwq[tid]]; ++ if (params->uapsd_queues & uapsd_bit) ++ sta->uapsd_tids |= 1 << tid; ++ else ++ 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)); ++ if (rwnx_vif->tdls_status == ++ TDLS_SETUP_RSP_TX) { ++ rwnx_vif->tdls_status = ++ TDLS_LINK_ACTIVE; ++ sta->tdls.initiator = true; ++ sta->tdls.active = true; ++ } ++ /* Set TDLS channel switch capability */ ++ if ((params->ext_capab[3] & ++ WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH) && ++ !rwnx_vif->tdls_chsw_prohibited) ++ sta->tdls.chsw_allowed = true; ++ rwnx_vif->sta.tdls_sta = sta; ++ sta->valid = true; ++ spin_unlock_bh(&rwnx_hw->cb_lock); ++#ifdef CONFIG_RWNX_BFMER ++ if (rwnx_hw->mod_params->bfmer) ++ rwnx_send_bfmer_enable( ++ rwnx_hw, sta, params->vht_capa); ++ ++ rwnx_mu_group_sta_init(sta, NULL); ++#endif /* CONFIG_RWNX_BFMER */ ++ ++#define PRINT_STA_FLAG(f) \ ++ (params->sta_flags_set & BIT(NL80211_STA_FLAG_##f) ? "[" #f "]" : "") ++ ++ netdev_info( ++ dev, ++ "Add %s TDLS sta %d (%pM) flags=%s%s%s%s%s%s%s", ++ sta->tdls.initiator ? "initiator" : ++ "responder", ++ sta->sta_idx, mac, ++ PRINT_STA_FLAG(AUTHORIZED), ++ PRINT_STA_FLAG(SHORT_PREAMBLE), ++ PRINT_STA_FLAG(WME), ++ PRINT_STA_FLAG(MFP), ++ PRINT_STA_FLAG(AUTHENTICATED), ++ PRINT_STA_FLAG(TDLS_PEER), ++ PRINT_STA_FLAG(ASSOCIATED)); ++#undef PRINT_STA_FLAG ++ ++ break; ++ } ++ default: ++ error = -EBUSY; ++ break; ++ } ++ ++ rwnx_hw->adding_sta = false; ++ } else { ++ return -EINVAL; ++ } ++ } ++ ++ if (params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) ++ rwnx_send_me_set_control_port_req( ++ rwnx_hw, ++ (params->sta_flags_set & ++ BIT(NL80211_STA_FLAG_AUTHORIZED)) != 0, ++ sta->sta_idx); ++ ++ if (RWNX_VIF_TYPE(vif) == NL80211_IFTYPE_MESH_POINT) { ++ if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE) { ++ if (params->plink_state < NUM_NL80211_PLINK_STATES) { ++ rwnx_send_mesh_peer_update_ntf( ++ rwnx_hw, vif, sta->sta_idx, ++ params->plink_state); ++ } ++ } ++ ++ if (params->local_pm != NL80211_MESH_POWER_UNKNOWN) { ++ sta->mesh_pm = params->local_pm; ++ rwnx_update_mesh_power_mode(vif); ++ } ++ } ++ ++ if (params->vlan) { ++ uint8_t vlan_idx; ++ ++ vif = netdev_priv(params->vlan); ++ vlan_idx = vif->vif_index; ++ ++ if (sta->vlan_idx != vlan_idx) { ++ struct rwnx_vif *old_vif; ++ old_vif = rwnx_hw->vif_table[sta->vlan_idx]; ++ rwnx_txq_sta_switch_vif(sta, old_vif, vif); ++ sta->vlan_idx = vlan_idx; ++ ++ if ((RWNX_VIF_TYPE(vif) == NL80211_IFTYPE_AP_VLAN) && ++ (vif->use_4addr)) { ++ WARN((vif->ap_vlan.sta_4a), ++ "4A AP_VLAN interface with more than one sta"); ++ vif->ap_vlan.sta_4a = sta; ++ } ++ ++ if ((RWNX_VIF_TYPE(old_vif) == ++ NL80211_IFTYPE_AP_VLAN) && ++ (old_vif->use_4addr)) { ++ old_vif->ap_vlan.sta_4a = NULL; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++/** ++ * @start_ap: Start acting in AP mode defined by the parameters. ++ */ ++static int rwnx_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_ap_settings *settings) ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ struct apm_start_cfm apm_start_cfm; ++ struct rwnx_ipc_elem_var elem; ++ struct rwnx_sta *sta; ++ int error = 0; ++ ++ 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 */ ++ error = rwnx_send_apm_start_req(rwnx_hw, rwnx_vif, settings, ++ &apm_start_cfm, &elem); ++ if (error) ++ goto end; ++ ++ // Check the status ++ switch (apm_start_cfm.status) { ++ case CO_OK: { ++ u8 txq_status = 0; ++ rwnx_vif->ap.bcmc_index = apm_start_cfm.bcmc_idx; ++ rwnx_vif->ap.flags = 0; ++#if (defined CONFIG_HE_FOR_OLD_KERNEL) || (defined CONFIG_VHT_FOR_OLD_KERNEL) ++ rwnx_vif->ap.aic_index = 0; ++#endif ++ rwnx_vif->ap.csa = NULL; ++ sta = &rwnx_hw->sta_table[apm_start_cfm.bcmc_idx]; ++ sta->valid = true; ++ sta->aid = 0; ++ sta->sta_idx = apm_start_cfm.bcmc_idx; ++ sta->ch_idx = apm_start_cfm.ch_idx; ++ sta->vif_idx = rwnx_vif->vif_index; ++ sta->qos = false; ++ sta->acm = 0; ++ sta->ps.active = false; ++ rwnx_mu_group_sta_init(sta, NULL); ++ spin_lock_bh(&rwnx_hw->cb_lock); ++ rwnx_chanctx_link(rwnx_vif, apm_start_cfm.ch_idx, ++ &settings->chandef); ++ if (rwnx_hw->cur_chanctx != apm_start_cfm.ch_idx) { ++ txq_status = RWNX_TXQ_STOP_CHAN; ++ } ++ rwnx_txq_vif_init(rwnx_hw, rwnx_vif, txq_status); ++ spin_unlock_bh(&rwnx_hw->cb_lock); ++ ++ netif_tx_start_all_queues(dev); ++ netif_carrier_on(dev); ++ error = 0; ++ /* If the AP channel is already the active, we probably skip radar ++ activation on MM_CHANNEL_SWITCH_IND (unless another vif use this ++ ctxt). In anycase retest if radar detection must be activated ++ */ ++ if (txq_status == 0) { ++ rwnx_radar_detection_enable_on_cur_channel(rwnx_hw); ++ } ++ break; ++ } ++ case CO_BUSY: ++ error = -EINPROGRESS; ++ break; ++ case CO_OP_IN_PROGRESS: ++ error = -EALREADY; ++ break; ++ default: ++ error = -EIO; ++ break; ++ } ++ ++ if (error) { ++ netdev_info(dev, "Failed to start AP (%d)", error); ++ } else { ++ netdev_info(dev, ++ "AP started: ch=%d, bcmc_idx=%d channel=%d bw=%d", ++ rwnx_vif->ch_index, rwnx_vif->ap.bcmc_index, ++ ((settings->chandef).chan)->center_freq, ++ ((settings->chandef).width)); ++ } ++ ++end: ++ //rwnx_ipc_elem_var_deallocs(rwnx_hw, &elem); ++ ++ return error; ++} ++ ++/** ++ * @change_beacon: Change the beacon parameters for an access point mode ++ * interface. This should reject the call when AP mode wasn't started. ++ */ ++/* flare-edge (6.18 port): cfg80211_ops.change_beacon now passes ++ * struct cfg80211_ap_update *, which wraps the old ++ * struct cfg80211_beacon_data as its .beacon member (plus FILS/S1G/unsol ++ * fields this driver doesn't use) — unwrap to keep rwnx_build_bcn()'s ++ * signature (and every other caller of it) unchanged. */ ++static int rwnx_cfg80211_change_beacon(struct wiphy *wiphy, ++ struct net_device *dev, ++ struct cfg80211_ap_update *update) ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *vif = netdev_priv(dev); ++ struct rwnx_bcn *bcn = &vif->ap.bcn; ++ struct rwnx_ipc_elem_var elem; ++ struct cfg80211_beacon_data *info = &update->beacon; ++ u8 *buf; ++ int error = 0; ++ elem.dma_addr = 0; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ // Build the beacon ++ buf = rwnx_build_bcn(bcn, info); ++ if (!buf) ++ return -ENOMEM; ++ ++ rwnx_send_bcn(rwnx_hw, buf, vif->vif_index, bcn->len); ++ ++ // Forward the information to the LMAC ++ error = rwnx_send_bcn_change(rwnx_hw, vif->vif_index, 0, bcn->len, ++ bcn->head_len, bcn->tim_len, NULL); ++ ++ return error; ++} ++ ++/** ++ * * @stop_ap: Stop being an AP, including stopping beaconing. ++ */ ++#if (LINUX_VERSION_CODE >= HIGH_KERNEL_VERSION) ++static int rwnx_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, ++ unsigned int link_id) ++#else ++static int rwnx_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) ++#endif ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ struct rwnx_sta *sta; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ netif_tx_stop_all_queues(dev); ++ netif_carrier_off(dev); ++ ++ /* delete any remaining STA*/ ++ while (!list_empty(&rwnx_vif->ap.sta_list)) { ++ rwnx_cfg80211_del_station_compat(wiphy, dev, NULL); ++ } ++ ++ if (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) ++ rwnx_hw->is_p2p_connected = 0; ++ rwnx_radar_cancel_cac(&rwnx_hw->radar); ++ rwnx_send_apm_stop_req(rwnx_hw, rwnx_vif); ++ spin_lock_bh(&rwnx_hw->cb_lock); ++ rwnx_chanctx_unlink(rwnx_vif); ++ spin_unlock_bh(&rwnx_hw->cb_lock); ++ ++ /* delete BC/MC STA */ ++ sta = &rwnx_hw->sta_table[rwnx_vif->ap.bcmc_index]; ++ 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); ++ ++ netdev_info(dev, "AP Stopped"); ++ ++ return 0; ++} ++ ++/** ++ * @set_monitor_channel: Set the monitor mode channel for the device. If other ++ * interfaces are active this callback should reject the configuration. ++ * If no interfaces are active or the device is down, the channel should ++ * be stored for when a monitor interface becomes active. ++ * ++ * Also called internaly with chandef set to NULL simply to retrieve the channel ++ * configured at firmware level. ++ */ ++static int rwnx_cfg80211_set_monitor_channel(struct wiphy *wiphy, ++ struct cfg80211_chan_def *chandef) ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *rwnx_vif; ++ struct me_config_monitor_cfm cfm; ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ if (rwnx_hw->monitor_vif == RWNX_INVALID_VIF) ++ return -EINVAL; ++ ++ rwnx_vif = rwnx_hw->vif_table[rwnx_hw->monitor_vif]; ++ ++ // Do nothing if monitor interface is already configured with the requested channel ++ if (rwnx_chanctx_valid(rwnx_hw, rwnx_vif->ch_index)) { ++ struct rwnx_chanctx *ctxt; ++ ctxt = &rwnx_vif->rwnx_hw->chanctx_table[rwnx_vif->ch_index]; ++ if (chandef && ++ cfg80211_chandef_identical(&ctxt->chan_def, chandef)) ++ return 0; ++ } ++ ++ // Always send command to firmware. It allows to retrieve channel context index ++ // and its configuration. ++ if (rwnx_send_config_monitor_req(rwnx_hw, chandef, &cfm)) ++ return -EIO; ++ ++ // Always re-set channel context info ++ rwnx_chanctx_unlink(rwnx_vif); ++ ++ // If there is also a STA interface not yet connected then monitor interface ++ // will only have a channel context after the connection of the STA interface. ++ if (cfm.chan_index != RWNX_CH_NOT_SET) { ++ struct cfg80211_chan_def mon_chandef; ++ ++ if (rwnx_hw->vif_started > 1) { ++ // In this case we just want to update the channel context index not ++ // the channel configuration ++ rwnx_chanctx_link(rwnx_vif, cfm.chan_index, NULL); ++ return -EBUSY; ++ } ++ ++ mon_chandef.chan = ++ ieee80211_get_channel(wiphy, cfm.chan.prim20_freq); ++ mon_chandef.center_freq1 = cfm.chan.center1_freq; ++ mon_chandef.center_freq2 = cfm.chan.center2_freq; ++ mon_chandef.width = chnl2bw[cfm.chan.type]; ++ rwnx_chanctx_link(rwnx_vif, cfm.chan_index, &mon_chandef); ++ } ++ ++ return 0; ++} ++ ++int rwnx_cfg80211_set_monitor_channel_(struct wiphy *wiphy, ++ struct cfg80211_chan_def *chandef) ++{ ++ return rwnx_cfg80211_set_monitor_channel(wiphy, chandef); ++} ++ ++/* flare-edge (6.18 port): cfg80211_ops.set_monitor_channel gained a ++ * struct net_device *dev parameter; this driver's monitor-channel logic ++ * doesn't need it (it looks up the monitor vif from rwnx_hw itself), so ++ * just adapt the ops-table entry rather than thread an unused dev param ++ * through the existing internal callers. */ ++static int rwnx_cfg80211_set_monitor_channel_ops(struct wiphy *wiphy, ++ struct net_device *dev, ++ struct cfg80211_chan_def *chandef) ++{ ++ return rwnx_cfg80211_set_monitor_channel(wiphy, chandef); ++} ++ ++/** ++ * @probe_client: probe an associated client, must return a cookie that it ++ * later passes to cfg80211_probe_status(). ++ */ ++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; ++ spin_lock_bh(&vif->rwnx_hw->cb_lock); ++ list_for_each_entry (sta, &vif->ap.sta_list, list) { ++ if (sta->valid && ether_addr_equal(sta->mac_addr, peer)) ++ break; ++ } ++ spin_unlock_bh(&vif->rwnx_hw->cb_lock); ++ ++ 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; ++} ++ ++/** ++ * @mgmt_frame_register: Notify driver that a management frame type was ++ * registered. Note that this callback may not sleep, and cannot run ++ * concurrently with itself. ++ */ ++void rwnx_cfg80211_mgmt_frame_register(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ u16 frame_type, bool reg) ++{ ++} ++ ++/** ++ * @set_wiphy_params: Notify that wiphy parameters have changed; ++ * @changed bitfield (see &enum wiphy_params_flags) describes which values ++ * have changed. The actual parameter values are available in ++ * struct wiphy. If returning an error, no value should be changed. ++ */ ++/* flare-edge (6.18 port): cfg80211_ops.set_wiphy_params gained an ++ * int radio_idx param (multi-radio wiphy support); this driver is ++ * single-radio and the function body already ignores "changed", so just ++ * accept and ignore radio_idx too. */ ++static int rwnx_cfg80211_set_wiphy_params(struct wiphy *wiphy, int radio_idx, ++ u32 changed) ++{ ++ return 0; ++} ++ ++/** ++ * @set_tx_power: set the transmit power according to the parameters, ++ * the power passed is in mBm, to get dBm use MBM_TO_DBM(). The ++ * wdev may be %NULL if power was set for the wiphy, and will ++ * always be %NULL unless the driver supports per-vif TX power ++ * (as advertised by the nl80211 feature flag.) ++ */ ++/* flare-edge (6.18 port): cfg80211_ops.set_tx_power gained an int ++ * radio_idx param (multi-radio wiphy support); ignore it, single-radio. */ ++static int rwnx_cfg80211_set_tx_power(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ int radio_idx, ++ enum nl80211_tx_power_setting type, ++ int mbm) ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *vif; ++ s8 pwr; ++ int res = 0; ++ ++ if (type == NL80211_TX_POWER_AUTOMATIC) { ++ pwr = 0x7f; ++ } else { ++ pwr = MBM_TO_DBM(mbm); ++ } ++ ++ if (wdev) { ++ vif = container_of(wdev, struct rwnx_vif, wdev); ++ res = rwnx_send_set_power(rwnx_hw, vif->vif_index, pwr, NULL); ++ } else { ++ list_for_each_entry (vif, &rwnx_hw->vifs, list) { ++ res = rwnx_send_set_power(rwnx_hw, vif->vif_index, pwr, ++ NULL); ++ if (res) ++ break; ++ } ++ } ++ ++ return res; ++} ++ ++/* flare-edge (6.18 port): cfg80211_ops.get_tx_power gained int radio_idx ++ * and unsigned int link_id params (multi-radio/MLO support); ignore both, ++ * single-radio non-MLO. */ ++static int rwnx_cfg80211_get_tx_power(struct wiphy *wiphy, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) ++ struct wireless_dev *wdev, ++#endif ++ int radio_idx, unsigned int link_id, ++ int *mbm) ++{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0) ++ struct wireless_dev *wdev = NULL; ++#endif ++ //struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ //struct rwnx_vif *vif; ++ s8 pwr = 0; ++ int res = 0; ++ ++ *mbm = get_txpwr_max(pwr); ++ ++ return res; ++} ++ ++/** ++ * @set_power_mgmt: set the power save to one of those two modes: ++ * Power-save off ++ * Power-save on - Dynamic mode ++ */ ++static int rwnx_cfg80211_set_power_mgmt(struct wiphy *wiphy, ++ struct net_device *dev, bool enabled, ++ int timeout) ++{ ++#if 0 ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ u8 ps_mode; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ if (timeout >= 0) ++ netdev_info(dev, "Ignore timeout value %d", timeout); ++ ++ if (!(rwnx_hw->version_cfm.features & BIT(MM_FEAT_PS_BIT))) ++ enabled = false; ++ ++ if (enabled) { ++ /* Switch to Dynamic Power Save */ ++ ps_mode = MM_PS_MODE_ON_DYN; ++ } else { ++ /* Exit Power Save */ ++ ps_mode = MM_PS_MODE_OFF; ++ } ++ ++ 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) ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ u8 hw_queue, aifs, cwmin, cwmax; ++ u32 param; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ hw_queue = rwnx_ac2hwq[0][params->ac]; ++ ++ aifs = params->aifs; ++ cwmin = fls(params->cwmin); ++ cwmax = fls(params->cwmax); ++ ++ /* Store queue information in general structure */ ++ param = (u32)(aifs << 0); ++ param |= (u32)(cwmin << 4); ++ param |= (u32)(cwmax << 8); ++ param |= (u32)(params->txop) << 12; ++ ++ /* Send the MM_SET_EDCA_REQ message to the FW */ ++ return rwnx_send_set_edca(rwnx_hw, hw_queue, param, false, ++ rwnx_vif->vif_index); ++} ++ ++/** ++ * @remain_on_channel: Request the driver to remain awake on the specified ++ * channel for the specified duration to complete an off-channel ++ * operation (e.g., public action frame exchange). When the driver is ++ * ready on the requested channel, it must indicate this with an event ++ * notification by calling cfg80211_ready_on_channel(). ++ */ ++static int rwnx_cfg80211_remain_on_channel_(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct ieee80211_channel *chan, ++ unsigned int duration, u64 *cookie, ++ bool mgmt_roc_flag) ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ //struct rwnx_vif *rwnx_vif = netdev_priv(wdev->netdev); ++ 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); ++ if (rwnx_hw->roc_elem) { ++ printk("remain_on_channel fail\n"); ++ return -EBUSY; ++ } ++ } ++ ++ printk("remain:%d,%d,%d\n", rwnx_vif->vif_index, rwnx_vif->is_p2p_vif, ++ rwnx_hw->is_p2p_alive); ++#ifdef CONFIG_USE_P2P0 ++ if (rwnx_vif->is_p2p_vif) { ++#else ++ if (rwnx_vif == rwnx_hw->p2p_dev_vif && !rwnx_vif->up) { ++#endif ++ 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); ++ if (error) ++ return -EIO; ++ ++ if (add_if_cfm.status != 0) { ++ return -EIO; ++ } ++ ++ /* Save the index retrieved from LMAC */ ++ spin_lock_bh(&rwnx_hw->cb_lock); ++ rwnx_vif->vif_index = add_if_cfm.inst_nbr; ++ rwnx_vif->up = true; ++ rwnx_hw->vif_started++; ++ rwnx_hw->vif_table[add_if_cfm.inst_nbr] = rwnx_vif; ++ spin_unlock_bh(&rwnx_hw->cb_lock); ++ rwnx_hw->is_p2p_alive = 1; ++#ifndef CONFIG_USE_P2P0 ++ mod_timer(&rwnx_hw->p2p_alive_timer, ++ jiffies + msecs_to_jiffies(1000)); ++ atomic_set(&rwnx_hw->p2p_alive_timer_count, 0); ++#endif ++ } else { ++#ifndef CONFIG_USE_P2P0 ++ mod_timer(&rwnx_hw->p2p_alive_timer, ++ jiffies + msecs_to_jiffies(1000)); ++ atomic_set(&rwnx_hw->p2p_alive_timer_count, 0); ++#endif ++ } ++ } ++ ++ /* Allocate a temporary RoC element */ ++ roc_elem = kmalloc(sizeof(struct rwnx_roc_elem), GFP_KERNEL); ++ ++ /* Verify that element has well been allocated */ ++ if (!roc_elem) { ++ return -ENOMEM; ++ } ++ ++ /* Initialize the RoC information element */ ++ roc_elem->wdev = wdev; ++ roc_elem->chan = chan; ++ roc_elem->duration = duration; ++ roc_elem->mgmt_roc = mgmt_roc_flag; ++ roc_elem->on_chan = false; ++ ++ /* Initialize the OFFCHAN TX queue to allow off-channel transmissions */ ++ rwnx_txq_offchan_init(rwnx_vif); ++ ++ /* Forward the information to the FMAC */ ++ rwnx_hw->roc_elem = roc_elem; ++ 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; ++ kfree(roc_elem); ++ rwnx_txq_offchan_deinit(rwnx_vif); ++ } ++ ++ return error; ++} ++ ++static int rwnx_cfg80211_remain_on_channel(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ struct ieee80211_channel *chan, ++ unsigned int duration, u64 *cookie) ++{ ++ return rwnx_cfg80211_remain_on_channel_(wiphy, wdev, chan, duration, ++ cookie, false); ++} ++ ++/** ++ * @cancel_remain_on_channel: Cancel an on-going remain-on-channel operation. ++ * This allows the operation to be terminated prior to timeout based on ++ * the duration value. ++ */ ++static int rwnx_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++ 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; ++ } ++ ++ /* Forward the information to the FMAC */ ++ return rwnx_send_cancel_roc(rwnx_hw); ++} ++ ++#define IS_2P4GHZ(n) (n >= 2412 && n <= 2484) ++#define IS_5GHZ(n) (n >= 4000 && n <= 5895) ++#define DEFAULT_NOISE_FLOOR_2GHZ (-89) ++#define DEFAULT_NOISE_FLOOR_5GHZ (-92) ++ ++/** ++ * @dump_survey: get site survey information. ++ */ ++static int rwnx_cfg80211_dump_survey(struct wiphy *wiphy, ++ struct net_device *netdev, int idx, ++ struct survey_info *info) ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct ieee80211_supported_band *sband; ++ struct rwnx_survey_info *rwnx_survey; ++ ++ //RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ if (idx >= ARRAY_SIZE(rwnx_hw->survey)) ++ return -ENOENT; ++ ++ rwnx_survey = &rwnx_hw->survey[idx]; ++ ++ // Check if provided index matches with a supported 2.4GHz channel ++ sband = wiphy->bands[NL80211_BAND_2GHZ]; ++ if (sband && idx >= sband->n_channels) { ++ idx -= sband->n_channels; ++ sband = NULL; ++ } ++ ++ if (rwnx_hw->band_5g_support) { ++ if (!sband) { ++ // Check if provided index matches with a supported 5GHz channel ++ sband = wiphy->bands[NL80211_BAND_5GHZ]; ++ ++ if (!sband || idx >= sband->n_channels) ++ return -ENOENT; ++ } ++ } else { ++ if (!sband || idx >= sband->n_channels) ++ return -ENOENT; ++ } ++ ++ // Fill the survey ++ info->channel = &sband->channels[idx]; ++ info->filled = rwnx_survey->filled; ++ ++ if (rwnx_survey->filled != 0) { ++ SURVEY_TIME(info) = (u64)rwnx_survey->chan_time_ms; ++ SURVEY_TIME_BUSY(info) = (u64)rwnx_survey->chan_time_busy_ms; ++ //info->noise = rwnx_survey->noise_dbm; ++ info->noise = ((IS_2P4GHZ(info->channel->center_freq)) ? ++ DEFAULT_NOISE_FLOOR_2GHZ : ++ (IS_5GHZ(info->channel->center_freq)) ? ++ DEFAULT_NOISE_FLOOR_5GHZ : ++ DEFAULT_NOISE_FLOOR_5GHZ); ++ ++ // Set the survey report as not used ++ if (info->noise == 0) { ++ rwnx_survey->filled = 0; ++ } else { ++ rwnx_survey->filled |= SURVEY_INFO_NOISE_DBM; ++ } ++ } ++ ++ return 0; ++} ++ ++/** ++ * @get_channel: Get the current operating channel for the virtual interface. ++ * For monitor interfaces, it should return %NULL unless there's a single ++ * current monitoring channel. ++ */ ++static int rwnx_cfg80211_get_channel(struct wiphy *wiphy, ++ struct wireless_dev *wdev, ++#if LINUX_VERSION_CODE >= HIGH_KERNEL_VERSION ++ unsigned int link_id, ++#endif ++ struct cfg80211_chan_def *chandef) ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *rwnx_vif = container_of(wdev, struct rwnx_vif, wdev); ++ struct rwnx_chanctx *ctxt; ++ ++ if (!rwnx_vif->up) { ++ return -ENODATA; ++ } ++ ++ if (rwnx_vif->vif_index == rwnx_hw->monitor_vif) { ++ //retrieve channel from firmware ++ rwnx_cfg80211_set_monitor_channel(wiphy, NULL); ++ } ++ ++ //Check if channel context is valid ++ if (!rwnx_chanctx_valid(rwnx_hw, rwnx_vif->ch_index)) { ++ return -ENODATA; ++ } ++ ++ ctxt = &rwnx_hw->chanctx_table[rwnx_vif->ch_index]; ++ *chandef = ctxt->chan_def; ++ ++ return 0; ++} ++ ++/** ++ * @mgmt_tx: Transmit a management frame. ++ */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) ++static int rwnx_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, ++ struct cfg80211_mgmt_tx_params *params, ++ u64 *cookie) ++#else ++static int rwnx_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, ++ struct ieee80211_channel *channel, ++ bool offchan, unsigned int wait, const u8 *buf, ++ size_t len, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) ++ bool no_cck, ++#endif ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) ++ bool dont_wait_for_ack, ++#endif ++ u64 *cookie) ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *rwnx_vif = container_of( ++ wdev, struct rwnx_vif, wdev); //netdev_priv(wdev->netdev); ++ struct rwnx_sta *rwnx_sta; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) ++ struct ieee80211_channel *channel = params->chan; ++ const u8 *buf = params->buf; ++//size_t len = params->len; ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ ++ struct ieee80211_mgmt *mgmt = (void *)buf; ++ bool ap = false; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) ++ bool offchan = false; ++#endif ++ ++ /* Check if provided VIF is an AP or a STA one */ ++ switch (RWNX_VIF_TYPE(rwnx_vif)) { ++ case NL80211_IFTYPE_AP_VLAN: ++ rwnx_vif = rwnx_vif->ap_vlan.master; ++ case NL80211_IFTYPE_AP: ++ case NL80211_IFTYPE_P2P_GO: ++ case NL80211_IFTYPE_MESH_POINT: ++ ap = true; ++ break; ++ case NL80211_IFTYPE_STATION: ++ case NL80211_IFTYPE_P2P_CLIENT: ++ default: ++ break; ++ } ++ ++ /* 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; ++ ++ /* Not an AP interface sending frame to unknown STA: ++ * This is allowed for external authetication */ ++ if (rwnx_vif->sta.external_auth && ++ ieee80211_is_auth(mgmt->frame_control)) ++ goto send_frame; ++ ++ /* Otherwise ROC is needed */ ++ if (!channel) { ++ printk("mgmt_tx fail since channel\n"); ++ return -EINVAL; ++ } ++ ++ /* Check that a RoC is already pending */ ++ if (rwnx_hw->roc_elem) { ++ /* Get VIF used for current ROC */ ++ struct rwnx_vif *rwnx_roc_vif = container_of( ++ rwnx_hw->roc_elem->wdev, struct rwnx_vif, ++ wdev); //netdev_priv(rwnx_hw->roc_elem->wdev->netdev); ++ ++ /* Check if RoC channel is the same than the required one */ ++ if ((rwnx_hw->roc_elem->chan->center_freq != ++ channel->center_freq) || ++ (rwnx_vif->vif_index != rwnx_roc_vif->vif_index)) { ++ printk("mgmt rx chan invalid: %d, %d", ++ rwnx_hw->roc_elem->chan->center_freq, ++ channel->center_freq); ++ return -EINVAL; ++ } ++ } else { ++ u64 cookie; ++ int error; ++ ++ printk("mgmt rx remain on chan\n"); ++ ++ /* Start a ROC procedure for 30ms */ ++ error = rwnx_cfg80211_remain_on_channel_(wiphy, wdev, channel, ++ 30, &cookie, true); ++ if (error) { ++ printk("mgmt rx chan err\n"); ++ return error; ++ } ++ /* Need to keep in mind that RoC has been launched internally in order to ++ * avoid to call the cfg80211 callback once expired */ ++ //rwnx_hw->roc_elem->mgmt_roc = true; ++ } ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) ++ offchan = true; ++#endif ++ ++send_frame: ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) ++ return rwnx_start_mgmt_xmit(rwnx_vif, rwnx_sta, params, offchan, ++ cookie); ++#else ++ return rwnx_start_mgmt_xmit(rwnx_vif, rwnx_sta, channel, offchan, wait, ++ buf, len, no_cck, dont_wait_for_ack, ++ cookie); ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ ++} ++ ++/** ++ * @start_radar_detection: Start radar detection in the driver. ++ */ ++/* flare-edge (6.18 port): cfg80211_ops.start_radar_detection gained a ++ * trailing int link_id param (MLO); this driver has no MLO, ignore it. */ ++static int rwnx_cfg80211_start_radar_detection(struct wiphy *wiphy, ++ struct net_device *dev, ++ struct cfg80211_chan_def *chandef ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) ++ , ++ u32 cac_time_ms ++#endif ++ , ++ int link_id ++) ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ struct apm_start_cac_cfm cfm; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) ++ rwnx_radar_start_cac(&rwnx_hw->radar, cac_time_ms, rwnx_vif); ++#endif ++ rwnx_send_apm_start_cac_req(rwnx_hw, rwnx_vif, chandef, &cfm); ++ ++ if (cfm.status == CO_OK) { ++ spin_lock_bh(&rwnx_hw->cb_lock); ++ rwnx_chanctx_link(rwnx_vif, cfm.ch_idx, chandef); ++ if (rwnx_hw->cur_chanctx == rwnx_vif->ch_index) ++ rwnx_radar_detection_enable(&rwnx_hw->radar, ++ RWNX_RADAR_DETECT_REPORT, ++ RWNX_RADAR_RIU); ++ spin_unlock_bh(&rwnx_hw->cb_lock); ++ } else { ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++/** ++ * @update_ft_ies: Provide updated Fast BSS Transition information to the ++ * driver. If the SME is in the driver/firmware, this information can be ++ * used in building Authentication and Reassociation Request frames. ++ */ ++static int ++rwnx_cfg80211_update_ft_ies(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_update_ft_ies_params *ftie) ++{ ++ printk("%s\n", __func__); ++ return 0; ++} ++ ++/** ++ * @set_cqm_rssi_config: Configure connection quality monitor RSSI threshold. ++ */ ++static int rwnx_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy, ++ struct net_device *dev, ++ int32_t rssi_thold, ++ uint32_t rssi_hyst) ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ ++ return rwnx_send_cfg_rssi_req(rwnx_hw, rwnx_vif->vif_index, rssi_thold, ++ rssi_hyst); ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) ++/** ++ * ++ * @channel_switch: initiate channel-switch procedure (with CSA). Driver is ++ * responsible for veryfing if the switch is possible. Since this is ++ * inherently tricky driver may decide to disconnect an interface later ++ * with cfg80211_stop_iface(). This doesn't mean driver can accept ++ * everything. It should do it's best to verify requests and reject them ++ * as soon as possible. ++ */ ++int rwnx_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_csa_settings *params) ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *vif = netdev_priv(dev); ++ struct rwnx_bcn *bcn, *bcn_after; ++ struct rwnx_csa *csa; ++ u16 csa_oft[BCN_MAX_CSA_CPT]; ++ u8 *buf; ++ int i, error = 0; ++ ++ if (vif->ap.csa) ++ return -EBUSY; ++ ++ if (params->n_counter_offsets_beacon > BCN_MAX_CSA_CPT) ++ return -EINVAL; ++ ++ /* Build the new beacon with CSA IE */ ++ bcn = &vif->ap.bcn; ++ buf = rwnx_build_bcn(bcn, ¶ms->beacon_csa); ++ if (!buf) ++ return -ENOMEM; ++ ++ memset(csa_oft, 0, sizeof(csa_oft)); ++ for (i = 0; i < params->n_counter_offsets_beacon; i++) { ++ csa_oft[i] = params->counter_offsets_beacon[i] + bcn->head_len + ++ bcn->tim_len; ++ } ++ ++ /* If count is set to 0 (i.e anytime after this beacon) force it to 2 */ ++ if (params->count == 0) { ++ params->count = 2; ++ for (i = 0; i < params->n_counter_offsets_beacon; i++) { ++ buf[csa_oft[i]] = 2; ++ } ++ } ++ ++ error = rwnx_send_bcn(rwnx_hw, buf, vif->vif_index, bcn->len); ++ if (error) { ++ goto end; ++ } ++ ++ /* Build the beacon to use after CSA. It will only be sent to fw once ++ CSA is over, but do it before sending the beacon as it must be ready ++ when CSA is finished. */ ++ csa = kzalloc(sizeof(struct rwnx_csa), GFP_KERNEL); ++ if (!csa) { ++ error = -ENOMEM; ++ goto end; ++ } ++ ++ bcn_after = &csa->bcn; ++ buf = rwnx_build_bcn(bcn_after, ¶ms->beacon_after); ++ if (!buf) { ++ error = -ENOMEM; ++ rwnx_del_csa(vif); ++ goto end; ++ } ++ ++ vif->ap.csa = csa; ++ csa->vif = vif; ++ 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, 0, bcn->len, ++ bcn->head_len, bcn->tim_len, csa_oft); ++ ++ if (error) { ++ rwnx_del_csa(vif); ++ goto end; ++ } else { ++ INIT_WORK(&csa->work, rwnx_csa_finish); ++/* flare-edge (6.18 port): cfg80211_ch_switch_started_notify() is ++ * (dev, chandef, link_id, count, quiet) by 6.18 — 5 args, no trailing ++ * mode/reserved arg. The vendor shim's HIGH_KERNEL_VERSION4 tier (6.3.0) ++ * still assumed a 6-arg form. Add a tier for our exact target ahead of it. */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0) ++ cfg80211_ch_switch_started_notify(dev, &csa->chandef, 0, ++ params->count, false); ++#elif LINUX_VERSION_CODE >= HIGH_KERNEL_VERSION4 ++ cfg80211_ch_switch_started_notify(dev, &csa->chandef, 0, ++ params->count, false, 0); ++#elif LINUX_VERSION_CODE >= HIGH_KERNEL_VERSION2 ++ cfg80211_ch_switch_started_notify(dev, &csa->chandef, 0, ++ params->count, false); ++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) ++ cfg80211_ch_switch_started_notify( ++ dev, &csa->chandef, params->count, params->block_tx); ++#else ++ cfg80211_ch_switch_started_notify(dev, &csa->chandef, ++ params->count); ++#endif ++ } ++ ++end: ++ return error; ++} ++#endif ++ ++/* ++ * @tdls_mgmt: prepare TDLS action frame packets and forward them to FW ++ */ ++/* flare-edge (6.18 port): cfg80211_ops.tdls_mgmt gained an int link_id ++ * param (MLO) right after peer; this driver has no MLO, ignore it. */ ++static int rwnx_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) ++ const u8 *peer, ++#else ++ u8 *peer, ++#endif ++ int link_id, ++ u8 action_code, u8 dialog_token, ++ u16 status_code, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) ++ u32 peer_capability, ++#endif ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0) ++ bool initiator, ++#endif ++ const u8 *buf, size_t len) ++ ++{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0) ++ u32 peer_capability = 0; ++#endif ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) ++ bool initiator = false; ++#endif ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ int ret = 0; ++ ++ /* make sure we support TDLS */ ++ if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) ++ return -ENOTSUPP; ++ ++ /* make sure we are in station mode (and connected) */ ++ if ((RWNX_VIF_TYPE(rwnx_vif) != NL80211_IFTYPE_STATION) || ++ (!rwnx_vif->up) || (!rwnx_vif->sta.ap)) ++ return -ENOTSUPP; ++ ++ /* only one TDLS link is supported */ ++ if ((action_code == WLAN_TDLS_SETUP_REQUEST) && ++ (rwnx_vif->sta.tdls_sta) && ++ (rwnx_vif->tdls_status == TDLS_LINK_ACTIVE)) { ++ printk("%s: only one TDLS link is supported!\n", __func__); ++ return -ENOTSUPP; ++ } ++ ++ if ((action_code == WLAN_TDLS_DISCOVERY_REQUEST) && ++ (rwnx_hw->mod_params->ps_on)) { ++ printk("%s: discovery request is not supported when " ++ "power-save is enabled!\n", ++ __func__); ++ return -ENOTSUPP; ++ } ++ ++ switch (action_code) { ++ case WLAN_TDLS_SETUP_RESPONSE: ++ /* only one TDLS link is supported */ ++ if ((status_code == 0) && (rwnx_vif->sta.tdls_sta) && ++ (rwnx_vif->tdls_status == TDLS_LINK_ACTIVE)) { ++ printk("%s: only one TDLS link is supported!\n", ++ __func__); ++ status_code = WLAN_STATUS_REQUEST_DECLINED; ++ } ++ /* fall-through */ ++ case WLAN_TDLS_SETUP_REQUEST: ++ case WLAN_TDLS_TEARDOWN: ++ case WLAN_TDLS_DISCOVERY_REQUEST: ++ case WLAN_TDLS_SETUP_CONFIRM: ++ case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: ++ ret = rwnx_tdls_send_mgmt_packet_data( ++ rwnx_hw, rwnx_vif, peer, action_code, dialog_token, ++ status_code, peer_capability, initiator, buf, len, 0, ++ NULL); ++ break; ++ ++ default: ++ printk("%s: Unknown TDLS mgmt/action frame %pM\n", __func__, ++ peer); ++ ret = -EOPNOTSUPP; ++ break; ++ } ++ ++ if (action_code == WLAN_TDLS_SETUP_REQUEST) { ++ rwnx_vif->tdls_status = TDLS_SETUP_REQ_TX; ++ } else if (action_code == WLAN_TDLS_SETUP_RESPONSE) { ++ rwnx_vif->tdls_status = TDLS_SETUP_RSP_TX; ++ } else if ((action_code == WLAN_TDLS_SETUP_CONFIRM) && (ret == CO_OK)) { ++ rwnx_vif->tdls_status = TDLS_LINK_ACTIVE; ++ /* Set TDLS active */ ++ rwnx_vif->sta.tdls_sta->tdls.active = true; ++ } ++ ++ return ret; ++} ++ ++/* ++ * @tdls_oper: execute TDLS operation ++ */ ++static int rwnx_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) ++ const u8 *peer, ++#else ++ u8 *peer, ++#endif ++ enum nl80211_tdls_operation oper) ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ int error; ++ ++ if (oper != NL80211_TDLS_DISABLE_LINK) ++ return 0; ++ ++ if (!rwnx_vif->sta.tdls_sta) { ++ printk("%s: TDLS station %pM does not exist\n", __func__, peer); ++ return -ENOLINK; ++ } ++ ++ if (memcmp(rwnx_vif->sta.tdls_sta->mac_addr, peer, ETH_ALEN) == 0) { ++ /* Disable Channel Switch */ ++ if (!rwnx_send_tdls_cancel_chan_switch_req( ++ rwnx_hw, rwnx_vif, rwnx_vif->sta.tdls_sta, NULL)) ++ rwnx_vif->sta.tdls_sta->tdls.chsw_en = false; ++ ++ netdev_info(dev, "Del TDLS sta %d (%pM)", ++ rwnx_vif->sta.tdls_sta->sta_idx, ++ rwnx_vif->sta.tdls_sta->mac_addr); ++ /* Ensure that we won't process PS change ind */ ++ spin_lock_bh(&rwnx_hw->cb_lock); ++ rwnx_vif->sta.tdls_sta->ps.active = false; ++ rwnx_vif->sta.tdls_sta->valid = false; ++ spin_unlock_bh(&rwnx_hw->cb_lock); ++ rwnx_txq_sta_deinit(rwnx_hw, rwnx_vif->sta.tdls_sta); ++ error = rwnx_send_me_sta_del( ++ rwnx_hw, rwnx_vif->sta.tdls_sta->sta_idx, true); ++ if ((error != 0) && (error != -EPIPE)) ++ return error; ++ ++#ifdef CONFIG_RWNX_BFMER ++ // Disable Beamformer if supported ++ rwnx_bfmer_report_del(rwnx_hw, rwnx_vif->sta.tdls_sta); ++ rwnx_mu_group_sta_del(rwnx_hw, rwnx_vif->sta.tdls_sta); ++#endif /* CONFIG_RWNX_BFMER */ ++ ++ /* 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; ++ } ++ ++ return 0; ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) ++/* ++ * @tdls_channel_switch: enable TDLS channel switch ++ */ ++static int rwnx_cfg80211_tdls_channel_switch(struct wiphy *wiphy, ++ struct net_device *dev, ++ const u8 *addr, u8 oper_class, ++ struct cfg80211_chan_def *chandef) ++{ ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_sta *rwnx_sta = rwnx_vif->sta.tdls_sta; ++ struct tdls_chan_switch_cfm cfm; ++ int error; ++ ++ if ((!rwnx_sta) || (memcmp(addr, rwnx_sta->mac_addr, ETH_ALEN))) { ++ printk("%s: TDLS station %pM doesn't exist\n", __func__, addr); ++ return -ENOLINK; ++ } ++ ++ if (!rwnx_sta->tdls.chsw_allowed) { ++ printk("%s: TDLS station %pM does not support TDLS channel switch\n", ++ __func__, addr); ++ return -ENOTSUPP; ++ } ++ ++ error = rwnx_send_tdls_chan_switch_req(rwnx_hw, rwnx_vif, rwnx_sta, ++ rwnx_sta->tdls.initiator, ++ oper_class, chandef, &cfm); ++ if (error) ++ return error; ++ ++ if (!cfm.status) { ++ rwnx_sta->tdls.chsw_en = true; ++ return 0; ++ } else { ++ printk("%s: TDLS channel switch already enabled and only one is supported\n", ++ __func__); ++ return -EALREADY; ++ } ++} ++ ++/* ++ * @tdls_cancel_channel_switch: disable TDLS channel switch ++ */ ++static void rwnx_cfg80211_tdls_cancel_channel_switch(struct wiphy *wiphy, ++ struct net_device *dev, ++ const u8 *addr) ++{ ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_sta *rwnx_sta = rwnx_vif->sta.tdls_sta; ++ struct tdls_cancel_chan_switch_cfm cfm; ++ ++ if (!rwnx_sta) ++ return; ++ ++ if (!rwnx_send_tdls_cancel_chan_switch_req(rwnx_hw, rwnx_vif, rwnx_sta, ++ &cfm)) ++ rwnx_sta->tdls.chsw_en = false; ++} ++#endif /* version >= 3.19 */ ++ ++/** ++ * @change_bss: Modify parameters for a given BSS (mainly for AP mode). ++ */ ++int rwnx_cfg80211_change_bss(struct wiphy *wiphy, struct net_device *dev, ++ struct bss_parameters *params) ++{ ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ int res = -EOPNOTSUPP; ++ ++ if (((RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_AP) || ++ (RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_P2P_GO)) && ++ (params->ap_isolate > -1)) { ++ if (params->ap_isolate) ++ rwnx_vif->ap.flags |= RWNX_AP_ISOLATE; ++ else ++ rwnx_vif->ap.flags &= ~RWNX_AP_ISOLATE; ++ ++ res = 0; ++ } ++ ++ return res; ++} ++ ++static int rwnx_fill_station_info(struct rwnx_sta *sta, struct rwnx_vif *vif, ++ struct station_info *sinfo) ++{ ++ 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_info_cfm 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; ++ ++ AICWFDBG( ++ LOGDEBUG, ++ "%s ModTx(%d):%d TxIndex:%d ModRx(%d):%d RxHTIndex:%d RxVHTIndex:%d RxHEIndex:%d RSSI:%d \r\n", ++ __func__, rate_info->bwTx, rate_info->formatModTx, ++ rate_info->mcsIndexTx, rx_vect1->ch_bw, rx_vect1->format_mod, ++ rx_vect1->ht.mcs, rx_vect1->vht.mcs, rx_vect1->he.mcs, ++ (s8)cfm.rssi); ++ ++ switch (rate_info->formatModTx) { ++ case FORMATMOD_NON_HT: ++ case FORMATMOD_NON_HT_DUP_OFDM: ++ sinfo->txrate.flags = 0; ++ sinfo->txrate.legacy = ++ tx_legrates_lut_rate[rate_info->mcsIndexTx]; ++ sinfo->txrate.nss = 1; ++ break; ++ case FORMATMOD_HT_MF: ++ case FORMATMOD_HT_GF: ++ sinfo->txrate.flags = RATE_INFO_FLAGS_MCS; ++ sinfo->txrate.mcs = rate_info->mcsIndexTx & 0x7; ++ sinfo->txrate.nss = ((rate_info->mcsIndexTx >> 3) & 0x7) + 1; ++ if (rate_info->giAndPreTypeTx) ++ sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; ++ break; ++ case FORMATMOD_VHT: ++ sinfo->txrate.flags = RATE_INFO_FLAGS_VHT_MCS; ++ sinfo->txrate.mcs = rate_info->mcsIndexTx & 0xF; ++ sinfo->txrate.nss = ((rate_info->mcsIndexTx >> 4) & 0x7) + 1; ++ break; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) ++ case FORMATMOD_HE_MU: ++ case FORMATMOD_HE_SU: ++ case FORMATMOD_HE_ER: ++ sinfo->txrate.flags = RATE_INFO_FLAGS_HE_MCS; ++ sinfo->txrate.mcs = rate_info->mcsIndexTx & 0xF; ++ sinfo->txrate.nss = ((rate_info->mcsIndexTx >> 4) & 0x7) + 1; ++ break; ++#else ++ case FORMATMOD_HE_MU: ++ case FORMATMOD_HE_SU: ++ case FORMATMOD_HE_ER: ++ sinfo->txrate.flags = RATE_INFO_FLAGS_VHT_MCS; ++ sinfo->txrate.mcs = ((rate_info->mcsIndexTx & 0xF) > 9 ? ++ 9 : ++ (rate_info->mcsIndexTx & 0xF)); ++ sinfo->txrate.nss = ((rate_info->mcsIndexTx >> 4) & 0x7) + 1; ++ break; ++#endif ++ default: ++ return -EINVAL; ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) ++ switch (rate_info->bwTx) { ++ case PHY_CHNL_BW_20: ++ sinfo->txrate.bw = RATE_INFO_BW_20; ++ break; ++ case PHY_CHNL_BW_40: ++ sinfo->txrate.bw = RATE_INFO_BW_40; ++ break; ++ case PHY_CHNL_BW_80: ++ sinfo->txrate.bw = RATE_INFO_BW_80; ++ break; ++ case PHY_CHNL_BW_160: ++ sinfo->txrate.bw = RATE_INFO_BW_160; ++ break; ++ default: ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) ++ sinfo->txrate.bw = RATE_INFO_BW_HE_RU; ++#else ++ sinfo->txrate.bw = RATE_INFO_BW_20; ++#endif ++ break; ++ } ++#endif ++ ++ sinfo->filled |= (BIT(NL80211_STA_INFO_TX_BITRATE) | ++ BIT(NL80211_STA_INFO_TX_FAILED)); ++ ++ 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; ++ ++#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[rx_vect1->leg_rate].rate; ++ sinfo->rxrate.nss = 1; ++ 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; ++ sinfo->rxrate.nss = rx_vect1->ht.num_extn_ss + 1; ++ 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 + 1; ++ 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; ++ sinfo->rxrate.nss = rx_vect1->he.nss + 1; ++ 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; ++ if (rx_vect1->he.mcs > 9) { ++ sinfo->rxrate.mcs = 9; ++ } else { ++ sinfo->rxrate.mcs = rx_vect1->he.mcs; ++ } ++ sinfo->rxrate.mcs = ++ (rx_vect1->he.mcs > 9 ? 9 : rx_vect1->he.mcs); ++ sinfo->rxrate.nss = rx_vect1->he.nss + 1; ++ 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; ++} ++ ++/** ++ * @get_station: get station information for the station identified by @mac ++ */ ++static int rwnx_cfg80211_get_station(struct wiphy *wiphy, ++ struct net_device *dev, ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0)) ++ u8 *mac, ++#else ++ const u8 *mac, ++#endif ++ struct station_info *sinfo) ++{ ++ struct rwnx_vif *vif = netdev_priv(dev); ++ struct rwnx_sta *sta = NULL; ++ ++ if (RWNX_VIF_TYPE(vif) == NL80211_IFTYPE_MONITOR) ++ return -EINVAL; ++ else if ((RWNX_VIF_TYPE(vif) == NL80211_IFTYPE_STATION) || ++ (RWNX_VIF_TYPE(vif) == NL80211_IFTYPE_P2P_CLIENT)) { ++ if (vif->sta.ap && ether_addr_equal(vif->sta.ap->mac_addr, mac)) ++ sta = vif->sta.ap; ++ } else { ++ struct rwnx_sta *sta_iter; ++ spin_lock_bh(&vif->rwnx_hw->cb_lock); ++ list_for_each_entry (sta_iter, &vif->ap.sta_list, list) { ++ if (sta_iter->valid && ++ ether_addr_equal(sta_iter->mac_addr, mac)) { ++ sta = sta_iter; ++ break; ++ } ++ } ++ spin_unlock_bh(&vif->rwnx_hw->cb_lock); ++ } ++ ++ if (sta) ++ return rwnx_fill_station_info(sta, vif, sinfo); ++ ++ return -ENOENT; ++} ++ ++/** ++ * @dump_station: dump station callback -- resume dump at index @idx ++ */ ++static int rwnx_cfg80211_dump_station(struct wiphy *wiphy, ++ struct net_device *dev, int idx, u8 *mac, ++ struct station_info *sinfo) ++{ ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ //struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_sta *sta_iter, *sta = NULL; ++ //struct mesh_peer_info_cfm peer_info_cfm; ++ int i = 0; ++ ++#if 0 ++ if (RWNX_VIF_TYPE(rwnx_vif) != NL80211_IFTYPE_MESH_POINT) ++ return -ENOTSUPP; ++#endif ++ ++ list_for_each_entry (sta_iter, &rwnx_vif->ap.sta_list, list) { ++ if (i < idx) { ++ i++; ++ continue; ++ } ++ ++ sta = sta_iter; ++ break; ++ } ++ ++ if (sta == NULL) ++ return -ENOENT; ++ ++ /* Copy peer MAC address */ ++ memcpy(mac, &sta->mac_addr, ETH_ALEN); ++ ++#if 0 ++ /* Forward the information to the UMAC */ ++ if (rwnx_send_mesh_peer_info_req(rwnx_hw, rwnx_vif, sta->sta_idx, ++ &peer_info_cfm)) ++ return -ENOMEM; ++ ++ /* Copy peer MAC address */ ++ memcpy(mac, &sta->mac_addr, ETH_ALEN); ++ ++ /* Fill station information */ ++ 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 ++#endif ++ ++ if (sta) { ++ rwnx_fill_station_info(sta, rwnx_vif, sinfo); ++ } ++ ++ return 0; ++} ++ ++/** ++ * @add_mpath: add a fixed mesh path ++ */ ++static int rwnx_cfg80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0)) ++ u8 *dst, u8 *next_hop ++#else ++ const u8 *dst, const u8 *next_hop ++#endif ++) ++{ ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct mesh_path_update_cfm cfm; ++ ++ if (RWNX_VIF_TYPE(rwnx_vif) != NL80211_IFTYPE_MESH_POINT) ++ return -ENOTSUPP; ++ ++ return rwnx_send_mesh_path_update_req(rwnx_hw, rwnx_vif, dst, next_hop, ++ &cfm); ++} ++ ++/** ++ * @del_mpath: delete a given mesh path ++ */ ++static int rwnx_cfg80211_del_mpath(struct wiphy *wiphy, struct net_device *dev, ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0)) ++ u8 *dst ++#else ++ const u8 *dst ++#endif ++) ++{ ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct mesh_path_update_cfm cfm; ++ ++ if (RWNX_VIF_TYPE(rwnx_vif) != NL80211_IFTYPE_MESH_POINT) ++ return -ENOTSUPP; ++ ++ return rwnx_send_mesh_path_update_req(rwnx_hw, rwnx_vif, dst, NULL, ++ &cfm); ++} ++ ++/** ++ * @change_mpath: change a given mesh path ++ */ ++static int rwnx_cfg80211_change_mpath(struct wiphy *wiphy, ++ struct net_device *dev, ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0)) ++ u8 *dst, u8 *next_hop ++#else ++ const u8 *dst, const u8 *next_hop ++#endif ++) ++{ ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct mesh_path_update_cfm cfm; ++ ++ if (RWNX_VIF_TYPE(rwnx_vif) != NL80211_IFTYPE_MESH_POINT) ++ return -ENOTSUPP; ++ ++ return rwnx_send_mesh_path_update_req(rwnx_hw, rwnx_vif, dst, next_hop, ++ &cfm); ++} ++ ++/** ++ * @get_mpath: get a mesh path for the given parameters ++ */ ++static int rwnx_cfg80211_get_mpath(struct wiphy *wiphy, struct net_device *dev, ++ u8 *dst, u8 *next_hop, ++ struct mpath_info *pinfo) ++{ ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ struct rwnx_mesh_path *mesh_path = NULL; ++ struct rwnx_mesh_path *cur; ++ ++ if (RWNX_VIF_TYPE(rwnx_vif) != NL80211_IFTYPE_MESH_POINT) ++ return -ENOTSUPP; ++ ++ list_for_each_entry (cur, &rwnx_vif->ap.mpath_list, list) { ++ /* Compare the path target address and the provided destination address */ ++ if (memcmp(dst, &cur->tgt_mac_addr, ETH_ALEN)) { ++ continue; ++ } ++ ++ mesh_path = cur; ++ break; ++ } ++ ++ if (mesh_path == NULL) ++ return -ENOENT; ++ ++ /* Copy next HOP MAC address */ ++ if (mesh_path->p_nhop_sta) ++ memcpy(next_hop, &mesh_path->p_nhop_sta->mac_addr, ETH_ALEN); ++ ++ /* Fill path information */ ++ pinfo->filled = 0; ++ pinfo->generation = rwnx_vif->ap.generation; ++ ++ return 0; ++} ++ ++/** ++ * @dump_mpath: dump mesh path callback -- resume dump at index @idx ++ */ ++static int rwnx_cfg80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev, ++ int idx, u8 *dst, u8 *next_hop, ++ struct mpath_info *pinfo) ++{ ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ struct rwnx_mesh_path *mesh_path = NULL; ++ struct rwnx_mesh_path *cur; ++ int i = 0; ++ ++ if (RWNX_VIF_TYPE(rwnx_vif) != NL80211_IFTYPE_MESH_POINT) ++ return -ENOTSUPP; ++ ++ list_for_each_entry (cur, &rwnx_vif->ap.mpath_list, list) { ++ if (i < idx) { ++ i++; ++ continue; ++ } ++ ++ mesh_path = cur; ++ break; ++ } ++ ++ if (mesh_path == NULL) ++ return -ENOENT; ++ ++ /* Copy target and next hop MAC address */ ++ memcpy(dst, &mesh_path->tgt_mac_addr, ETH_ALEN); ++ if (mesh_path->p_nhop_sta) ++ memcpy(next_hop, &mesh_path->p_nhop_sta->mac_addr, ETH_ALEN); ++ ++ /* Fill path information */ ++ pinfo->filled = 0; ++ pinfo->generation = rwnx_vif->ap.generation; ++ ++ return 0; ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) ++/** ++ * @get_mpp: get a mesh proxy path for the given parameters ++ */ ++static int rwnx_cfg80211_get_mpp(struct wiphy *wiphy, struct net_device *dev, ++ u8 *dst, u8 *mpp, struct mpath_info *pinfo) ++{ ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ struct rwnx_mesh_proxy *mesh_proxy = NULL; ++ struct rwnx_mesh_proxy *cur; ++ ++ if (RWNX_VIF_TYPE(rwnx_vif) != NL80211_IFTYPE_MESH_POINT) ++ return -ENOTSUPP; ++ ++ list_for_each_entry (cur, &rwnx_vif->ap.proxy_list, list) { ++ if (cur->local) { ++ continue; ++ } ++ ++ /* Compare the path target address and the provided destination address */ ++ if (memcmp(dst, &cur->ext_sta_addr, ETH_ALEN)) { ++ continue; ++ } ++ ++ mesh_proxy = cur; ++ break; ++ } ++ ++ if (mesh_proxy == NULL) ++ return -ENOENT; ++ ++ memcpy(mpp, &mesh_proxy->proxy_addr, ETH_ALEN); ++ ++ /* Fill path information */ ++ pinfo->filled = 0; ++ pinfo->generation = rwnx_vif->ap.generation; ++ ++ return 0; ++} ++ ++/** ++ * @dump_mpp: dump mesh proxy path callback -- resume dump at index @idx ++ */ ++static int rwnx_cfg80211_dump_mpp(struct wiphy *wiphy, struct net_device *dev, ++ int idx, u8 *dst, u8 *mpp, ++ struct mpath_info *pinfo) ++{ ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ struct rwnx_mesh_proxy *mesh_proxy = NULL; ++ struct rwnx_mesh_proxy *cur; ++ int i = 0; ++ ++ if (RWNX_VIF_TYPE(rwnx_vif) != NL80211_IFTYPE_MESH_POINT) ++ return -ENOTSUPP; ++ ++ list_for_each_entry (cur, &rwnx_vif->ap.proxy_list, list) { ++ if (cur->local) { ++ continue; ++ } ++ ++ if (i < idx) { ++ i++; ++ continue; ++ } ++ ++ mesh_proxy = cur; ++ break; ++ } ++ ++ if (mesh_proxy == NULL) ++ return -ENOENT; ++ ++ /* Copy target MAC address */ ++ memcpy(dst, &mesh_proxy->ext_sta_addr, ETH_ALEN); ++ memcpy(mpp, &mesh_proxy->proxy_addr, ETH_ALEN); ++ ++ /* Fill path information */ ++ pinfo->filled = 0; ++ pinfo->generation = rwnx_vif->ap.generation; ++ ++ return 0; ++} ++#endif /* version >= 3.19 */ ++ ++/** ++ * @get_mesh_config: Get the current mesh configuration ++ */ ++static int rwnx_cfg80211_get_mesh_config(struct wiphy *wiphy, ++ struct net_device *dev, ++ struct mesh_config *conf) ++{ ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ ++ if (RWNX_VIF_TYPE(rwnx_vif) != NL80211_IFTYPE_MESH_POINT) ++ return -ENOTSUPP; ++ ++ return 0; ++} ++ ++/** ++ * @update_mesh_config: Update mesh parameters on a running mesh. ++ */ ++static int rwnx_cfg80211_update_mesh_config(struct wiphy *wiphy, ++ struct net_device *dev, u32 mask, ++ const struct mesh_config *nconf) ++{ ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct mesh_update_cfm cfm; ++ int status; ++ ++ if (RWNX_VIF_TYPE(rwnx_vif) != NL80211_IFTYPE_MESH_POINT) ++ return -ENOTSUPP; ++ ++ if (mask & CO_BIT(NL80211_MESHCONF_POWER_MODE - 1)) { ++ rwnx_vif->ap.next_mesh_pm = nconf->power_mode; ++ ++ if (!list_empty(&rwnx_vif->ap.sta_list)) { ++ // If there are mesh links we don't want to update the power mode ++ // It will be updated with rwnx_update_mesh_power_mode() when the ++ // ps mode of a link is updated or when a new link is added/removed ++ mask &= ~BIT(NL80211_MESHCONF_POWER_MODE - 1); ++ ++ if (!mask) ++ return 0; ++ } ++ } ++ ++ status = ++ rwnx_send_mesh_update_req(rwnx_hw, rwnx_vif, mask, nconf, &cfm); ++ ++ if (!status && (cfm.status != 0)) ++ status = -EINVAL; ++ ++ return status; ++} ++ ++/** ++ * @join_mesh: join the mesh network with the specified parameters ++ * (invoked with the wireless_dev mutex held) ++ */ ++static int rwnx_cfg80211_join_mesh(struct wiphy *wiphy, struct net_device *dev, ++ const struct mesh_config *conf, ++ const struct mesh_setup *setup) ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ struct mesh_start_cfm mesh_start_cfm; ++ int error = 0; ++ u8 txq_status = 0; ++ /* STA for BC/MC traffic */ ++ struct rwnx_sta *sta; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ if (RWNX_VIF_TYPE(rwnx_vif) != NL80211_IFTYPE_MESH_POINT) ++ return -ENOTSUPP; ++ ++ /* Forward the information to the UMAC */ ++ error = rwnx_send_mesh_start_req(rwnx_hw, rwnx_vif, conf, setup, ++ &mesh_start_cfm); ++ if (error) { ++ return error; ++ } ++ ++ /* Check the status */ ++ switch (mesh_start_cfm.status) { ++ case CO_OK: ++ rwnx_vif->ap.bcmc_index = mesh_start_cfm.bcmc_idx; ++ rwnx_vif->ap.flags = 0; ++ rwnx_vif->use_4addr = true; ++ rwnx_vif->user_mpm = setup->user_mpm; ++ ++ sta = &rwnx_hw->sta_table[mesh_start_cfm.bcmc_idx]; ++ sta->valid = true; ++ sta->aid = 0; ++ sta->sta_idx = mesh_start_cfm.bcmc_idx; ++ sta->ch_idx = mesh_start_cfm.ch_idx; ++ sta->vif_idx = rwnx_vif->vif_index; ++ sta->qos = true; ++ sta->acm = 0; ++ sta->ps.active = false; ++ rwnx_mu_group_sta_init(sta, NULL); ++ spin_lock_bh(&rwnx_hw->cb_lock); ++ rwnx_chanctx_link( ++ rwnx_vif, mesh_start_cfm.ch_idx, ++ (struct cfg80211_chan_def *)(&setup->chandef)); ++ if (rwnx_hw->cur_chanctx != mesh_start_cfm.ch_idx) { ++ txq_status = RWNX_TXQ_STOP_CHAN; ++ } ++ rwnx_txq_vif_init(rwnx_hw, rwnx_vif, txq_status); ++ spin_unlock_bh(&rwnx_hw->cb_lock); ++ ++ netif_tx_start_all_queues(dev); ++ netif_carrier_on(dev); ++ ++ /* If the AP channel is already the active, we probably skip radar ++ activation on MM_CHANNEL_SWITCH_IND (unless another vif use this ++ ctxt). In anycase retest if radar detection must be activated ++ */ ++ if (rwnx_hw->cur_chanctx == mesh_start_cfm.ch_idx) { ++ rwnx_radar_detection_enable_on_cur_channel(rwnx_hw); ++ } ++ break; ++ ++ case CO_BUSY: ++ error = -EINPROGRESS; ++ break; ++ ++ default: ++ error = -EIO; ++ break; ++ } ++ ++ /* Print information about the operation */ ++ if (error) { ++ netdev_info(dev, "Failed to start MP (%d)", error); ++ } else { ++ netdev_info(dev, "MP started: ch=%d, bcmc_idx=%d", ++ rwnx_vif->ch_index, rwnx_vif->ap.bcmc_index); ++ } ++ ++ return error; ++} ++ ++/** ++ * @leave_mesh: leave the current mesh network ++ * (invoked with the wireless_dev mutex held) ++ */ ++static int rwnx_cfg80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev) ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ struct mesh_stop_cfm mesh_stop_cfm; ++ int error = 0; ++ ++ error = rwnx_send_mesh_stop_req(rwnx_hw, rwnx_vif, &mesh_stop_cfm); ++ ++ if (error == 0) { ++ /* Check the status */ ++ switch (mesh_stop_cfm.status) { ++ case CO_OK: ++ spin_lock_bh(&rwnx_hw->cb_lock); ++ rwnx_chanctx_unlink(rwnx_vif); ++ rwnx_radar_cancel_cac(&rwnx_hw->radar); ++ spin_unlock_bh(&rwnx_hw->cb_lock); ++ /* delete BC/MC STA */ ++ rwnx_txq_vif_deinit(rwnx_hw, rwnx_vif); ++ rwnx_del_bcn(&rwnx_vif->ap.bcn); ++ ++ netif_tx_stop_all_queues(dev); ++ netif_carrier_off(dev); ++ ++ break; ++ ++ default: ++ error = -EIO; ++ break; ++ } ++ } ++ ++ if (error) { ++ netdev_info(dev, "Failed to stop MP"); ++ } else { ++ netdev_info(dev, "MP Stopped"); ++ } ++ ++ return 0; ++} ++ ++static struct cfg80211_ops rwnx_cfg80211_ops = { ++ .add_virtual_intf = rwnx_cfg80211_add_iface, ++ .del_virtual_intf = rwnx_cfg80211_del_iface, ++ .change_virtual_intf = rwnx_cfg80211_change_iface, ++ .start_p2p_device = rwnx_cfgp2p_start_p2p_device, ++ .stop_p2p_device = rwnx_cfgp2p_stop_p2p_device, ++ .scan = rwnx_cfg80211_scan, ++ .connect = rwnx_cfg80211_connect, ++ .disconnect = rwnx_cfg80211_disconnect, ++ .add_key = rwnx_cfg80211_add_key, ++ .get_key = rwnx_cfg80211_get_key, ++ .del_key = rwnx_cfg80211_del_key, ++ .set_default_key = rwnx_cfg80211_set_default_key, ++ .set_default_mgmt_key = rwnx_cfg80211_set_default_mgmt_key, ++ .add_station = rwnx_cfg80211_add_station, ++ .del_station = rwnx_cfg80211_del_station_compat, ++ .change_station = rwnx_cfg80211_change_station, ++ .mgmt_tx = rwnx_cfg80211_mgmt_tx, ++ .start_ap = rwnx_cfg80211_start_ap, ++ .change_beacon = rwnx_cfg80211_change_beacon, ++ .stop_ap = rwnx_cfg80211_stop_ap, ++ .set_monitor_channel = rwnx_cfg80211_set_monitor_channel_ops, ++ .probe_client = rwnx_cfg80211_probe_client, ++ // .mgmt_frame_register = rwnx_cfg80211_mgmt_frame_register, ++ .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, ++ .get_station = rwnx_cfg80211_get_station, ++ .remain_on_channel = rwnx_cfg80211_remain_on_channel, ++ .cancel_remain_on_channel = rwnx_cfg80211_cancel_remain_on_channel, ++ .dump_survey = rwnx_cfg80211_dump_survey, ++ .get_channel = rwnx_cfg80211_get_channel, ++ .start_radar_detection = rwnx_cfg80211_start_radar_detection, ++ .update_ft_ies = rwnx_cfg80211_update_ft_ies, ++ .set_cqm_rssi_config = rwnx_cfg80211_set_cqm_rssi_config, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) ++ .channel_switch = rwnx_cfg80211_channel_switch, ++#endif ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) ++ .tdls_channel_switch = rwnx_cfg80211_tdls_channel_switch, ++ .tdls_cancel_channel_switch = rwnx_cfg80211_tdls_cancel_channel_switch, ++#endif ++ .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) || \ ++ defined(CONFIG_WPA3_FOR_OLD_KERNEL) ++ .external_auth = rwnx_cfg80211_external_auth, ++#endif ++#ifdef CONFIG_SCHED_SCAN ++ .sched_scan_start = rwnx_cfg80211_sched_scan_start, ++ .sched_scan_stop = rwnx_cfg80211_sched_scan_stop, ++#endif ++}; ++ ++/********************************************************************* ++ * Init/Exit functions ++ *********************************************************************/ ++static void rwnx_wdev_unregister(struct rwnx_hw *rwnx_hw) ++{ ++ struct rwnx_vif *rwnx_vif, *tmp; ++ ++ rtnl_lock(); ++ list_for_each_entry_safe (rwnx_vif, tmp, &rwnx_hw->vifs, list) { ++ rwnx_cfg80211_del_iface(rwnx_hw->wiphy, &rwnx_vif->wdev); ++ } ++ rtnl_unlock(); ++} ++ ++static void rwnx_set_vers(struct rwnx_hw *rwnx_hw) ++{ ++ u32 vers = rwnx_hw->version_cfm.version_lmac; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ snprintf(rwnx_hw->wiphy->fw_version, sizeof(rwnx_hw->wiphy->fw_version), ++ "%d.%d.%d.%d", (vers & (0xff << 24)) >> 24, ++ (vers & (0xff << 16)) >> 16, (vers & (0xff << 8)) >> 8, ++ (vers & (0xff << 0)) >> 0); ++} ++ ++static void rwnx_reg_notifier(struct wiphy *wiphy, ++ struct regulatory_request *request) ++{ ++ struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); ++ ++ // For now trust all initiator ++#ifdef CONFIG_RADAR_OR_IR_DETECT ++ if (request->dfs_region != 0) ++ rwnx_radar_set_domain(&rwnx_hw->radar, request->dfs_region); ++#else ++ rwnx_radar_set_domain(&rwnx_hw->radar, request->dfs_region); ++#endif ++ if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ ((rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DW || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) && ++ testmode == 0)) { ++ rwnx_send_me_chan_config_req(rwnx_hw, &request->alpha2[0]); ++ } ++} ++ ++static void rwnx_enable_mesh(struct rwnx_hw *rwnx_hw) ++{ ++ struct wiphy *wiphy = rwnx_hw->wiphy; ++ ++ if (!rwnx_mod_params.mesh) ++ return; ++ ++ rwnx_cfg80211_ops.get_station = rwnx_cfg80211_get_station; ++ rwnx_cfg80211_ops.dump_station = rwnx_cfg80211_dump_station; ++ rwnx_cfg80211_ops.add_mpath = rwnx_cfg80211_add_mpath; ++ rwnx_cfg80211_ops.del_mpath = rwnx_cfg80211_del_mpath; ++ rwnx_cfg80211_ops.change_mpath = rwnx_cfg80211_change_mpath; ++ rwnx_cfg80211_ops.get_mpath = rwnx_cfg80211_get_mpath; ++ rwnx_cfg80211_ops.dump_mpath = rwnx_cfg80211_dump_mpath; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) ++ rwnx_cfg80211_ops.get_mpp = rwnx_cfg80211_get_mpp; ++ rwnx_cfg80211_ops.dump_mpp = rwnx_cfg80211_dump_mpp; ++#endif ++ rwnx_cfg80211_ops.get_mesh_config = rwnx_cfg80211_get_mesh_config; ++ rwnx_cfg80211_ops.update_mesh_config = rwnx_cfg80211_update_mesh_config; ++ rwnx_cfg80211_ops.join_mesh = rwnx_cfg80211_join_mesh; ++ rwnx_cfg80211_ops.leave_mesh = rwnx_cfg80211_leave_mesh; ++ ++ wiphy->flags |= (WIPHY_FLAG_MESH_AUTH | WIPHY_FLAG_IBSS_RSN); ++ wiphy->features |= NL80211_FEATURE_USERSPACE_MPM; ++ wiphy->interface_modes |= BIT(NL80211_IFTYPE_MESH_POINT); ++ ++ rwnx_limits[0].types |= BIT(NL80211_IFTYPE_MESH_POINT); ++ rwnx_limits_dfs[0].types |= BIT(NL80211_IFTYPE_MESH_POINT); ++} ++ ++extern int rwnx_init_aic(struct rwnx_hw *rwnx_hw); ++ ++#if IS_ENABLED(CONFIG_SUNXI_ADDR_MGT) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0) ++extern int get_custom_mac_address(int fmt, char *name, char *addr); ++#else ++extern int get_wifi_custom_mac_address(char *addr_str); ++#endif ++#endif ++#if IS_ENABLED(CONFIG_PM) ++static const struct wiphy_wowlan_support aic_wowlan_support = { ++ .flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_MAGIC_PKT, ++}; ++#endif ++/** ++ * ++ */ ++extern int aicwf_vendor_init(struct wiphy *wiphy); ++extern txpwr_idx_conf_t nvram_txpwr_idx; ++ ++int rwnx_ic_system_init(struct rwnx_hw *rwnx_hw) ++{ ++ u32 mem_addr; ++ struct dbg_mem_read_cfm rd_mem_addr_cfm; ++ ++ mem_addr = 0x40500000; ++ ++ // if(rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ // rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DW){ ++ if (rwnx_send_dbg_mem_read_req(rwnx_hw, mem_addr, &rd_mem_addr_cfm)) { ++ return -1; ++ } ++ ++ chip_id = (u8)(rd_mem_addr_cfm.memdata >> 16); ++ ++ if (rwnx_send_dbg_mem_read_req(rwnx_hw, 0x00000020, &rd_mem_addr_cfm)) { ++ AICWFDBG(LOGERROR, "[0x00000020] rd fail\n"); ++ return -1; ++ } ++ chip_sub_id = (u8)(rd_mem_addr_cfm.memdata); ++ ++ AICWFDBG(LOGINFO, "FDRV chip_id=%x, chip_sub_id=%x!!\n", chip_id, ++ chip_sub_id); ++ ++#ifdef CONFIG_OOB ++ if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ u32 memdata_temp = 0x00000006; ++ int ret; ++ ret = rwnx_send_dbg_mem_block_write_req(rwnx_hw, 0x40504084, 4, ++ &memdata_temp); ++ if (ret) { ++ AICWFDBG(LOGERROR, "[0x40504084] write fail: %d\n", ++ ret); ++ return -1; ++ } ++ ++ ret = rwnx_send_dbg_mem_read_req(rwnx_hw, 0x40504084, ++ &rd_mem_addr_cfm); ++ if (ret) { ++ AICWFDBG(LOGERROR, "[0x40504084] rd fail\n"); ++ return -1; ++ } ++ AICWFDBG(LOGINFO, "rd [0x40504084] = %x\n", ++ rd_mem_addr_cfm.memdata); ++ } ++#endif ++ ++ if (rwnx_platform_on(rwnx_hw, NULL)) ++ return -1; ++#if defined(CONFIG_START_FROM_BOOTROM) ++ //if (start_from_bootrom(rwnx_hw)) ++ // return -1; ++#endif ++ // } ++ return 0; ++} ++ ++int rwnx_ic_rf_init(struct rwnx_hw *rwnx_hw) ++{ ++ struct mm_set_rf_calib_cfm cfm; ++ int ret = 0; ++ ++ if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8801) { ++ if ((ret = rwnx_send_txpwr_idx_req(rwnx_hw))) { ++ return -1; ++ } ++ ++ if ((ret = rwnx_send_txpwr_ofst_req(rwnx_hw))) { ++ return -1; ++ } ++ ++ if (testmode == 0) { ++ if ((ret = rwnx_send_rf_calib_req(rwnx_hw, &cfm))) ++ return -1; ++ } ++ ++ } else if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ if ((ret = aicwf_set_rf_config_8800dc(rwnx_hw, &cfm))) ++ return -1; ++ ++ } else if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ if ((ret = aicwf_set_rf_config_8800d80(rwnx_hw, &cfm))) ++ return -1; ++ } ++ return 0; ++} ++ ++#ifdef CONFIG_PLATFORM_ALLWINNER ++#ifdef CONFIG_USE_CUSTOMER_MAC ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0) ++extern int get_custom_mac_address(int fmt, char *name, char *addr); ++#else ++extern int get_wifi_custom_mac_address(char *addr_str); ++#endif ++#endif //CONFIG_USE_CUSTOMER_MAC ++#endif //CONFIG_PLATFORM_ALLWINNER ++ ++/* flare-edge (6.18 port, PORT-PLAN.md §3.7): is a ++ * Rockchip-BSP-vendor-only header, not present in mainline. Its only use ++ * below (rockchip_wifi_mac_addr()) is under CONFIG_USE_CUSTOMER_MAC, which ++ * this board's build does not define — do not include it. */ ++ ++#ifdef CONFIG_USE_CUSTOMER_MAC ++int rwnx_get_custom_mac_addr(u8_l *mac_addr_efuse) ++{ ++ int ret = 0; ++ ++#ifdef CONFIG_PLATFORM_ALLWINNER ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0) ++ ret = get_custom_mac_address(1, "wifi", mac_addr_efuse); ++#else ++ ret = get_wifi_custom_mac_address(addr_str); ++ if (ret >= 0) { ++ sscanf(addr_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", ++ &mac_addr_efuse[0], &mac_addr_efuse[1], ++ &mac_addr_efuse[2], &mac_addr_efuse[3], ++ &mac_addr_efuse[4], &mac_addr_efuse[5]); ++ } ++#endif ++ ++#endif //CONFIG_PLATFORM_ALLWINNER ++ ++#ifdef CONFIG_PLATFORM_ROCKCHIP ++ ret = rockchip_wifi_mac_addr(mac_addr_efuse); ++#endif //CONFIG_PLATFORM_ROCKCHIP ++#ifdef CONFIG_PLATFORM_ROCKCHIP2 ++ ret = rockchip_wifi_mac_addr(mac_addr_efuse); ++#endif //CONFIG_PLATFORM_ROCKCHIP ++ ++ if (ret == 0) { ++ AICWFDBG(LOGINFO, "%s %02x:%02x:%02x:%02x:%02x:%02x", __func__, ++ mac_addr_efuse[0], mac_addr_efuse[1], ++ mac_addr_efuse[2], mac_addr_efuse[3], ++ mac_addr_efuse[4], mac_addr_efuse[5]); ++ } ++ ++ return ret; ++} ++#endif ++ ++#ifdef CONFIG_FOR_IPCAM ++void aic_ipc_setting(struct rwnx_vif *rwnx_vif) ++{ ++ struct rwnx_hw *rwnx_hw = rwnx_vif->rwnx_hw; ++ uint32_t hw_edca = 1; ++ uint32_t hw_cca = 3; ++ int32_t param[14]; ++ int32_t cca[5] = { 0x10, 0, 0, 0, 0 }; ++ ++ param[0] = 0xFA522; ++ param[1] = 0xFA522; ++ param[2] = 0xFA522; ++ param[3] = 0xFA522; ++ param[4] = rwnx_vif->vif_index; ++ param[5] = 0x1e; ++ param[6] = 0; ++ param[7] = 0; ++ param[8] = 0; ++ param[9] = 0x2; ++ param[10] = 0x2; ++ param[11] = 0x7; ++ param[12] = 0; ++ param[13] = 1; ++ rwnx_send_vendor_hwconfig_req(rwnx_hw, hw_edca, param, NULL); ++ rwnx_send_vendor_hwconfig_req(rwnx_hw, hw_cca, cca, NULL); ++} ++#endif ++ ++extern void *aicwf_prealloc_txq_alloc(size_t size); ++#ifdef CONFIG_POWER_LIMIT ++extern char default_ccode[]; ++#endif ++int rwnx_cfg80211_init(struct rwnx_plat *rwnx_plat, void **platform_data) ++{ ++ struct rwnx_hw *rwnx_hw; ++ struct rwnx_conf_file init_conf; ++ int ret = 0; ++ struct wiphy *wiphy; ++ struct rwnx_vif *vif; ++ int i; ++ 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; ++#ifdef CONFIG_TEMP_COMP ++ struct mm_set_vendor_swconfig_cfm swconfig_cfm; ++#endif ++ char fw_path[200]; ++ (void)addr_str; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ memset(fw_path, 0, 200); ++ aicbsp_get_feature(&feature, fw_path); ++ ++ get_random_bytes(&dflt_mac[4], 2); ++#ifdef CONFIG_POWER_LIMIT ++ memcpy(country_code, default_ccode, 4); ++#endif ++ ++ /* create a new wiphy for use with cfg80211 */ ++ AICWFDBG(LOGINFO, "%s sizeof(struct rwnx_hw):%d \r\n", __func__, ++ (int)sizeof(struct rwnx_hw)); ++ wiphy = wiphy_new(&rwnx_cfg80211_ops, sizeof(struct rwnx_hw)); ++ ++ if (!wiphy) { ++ dev_err(rwnx_platform_get_dev(rwnx_plat), ++ "Failed to create new wiphy\n"); ++ ret = -ENOMEM; ++ goto err_out; ++ } ++ ++ rwnx_hw = wiphy_priv(wiphy); ++ rwnx_hw->wiphy = wiphy; ++ rwnx_hw->plat = rwnx_plat; ++ rwnx_hw->dev = rwnx_platform_get_dev(rwnx_plat); ++#ifdef AICWF_SDIO_SUPPORT ++ rwnx_hw->sdiodev = rwnx_plat->sdiodev; ++ rwnx_plat->sdiodev->rwnx_hw = rwnx_hw; ++ rwnx_hw->cmd_mgr = &rwnx_plat->sdiodev->cmd_mgr; ++#else ++ rwnx_hw->usbdev = rwnx_plat->usbdev; ++ rwnx_plat->usbdev->rwnx_hw = rwnx_hw; ++ rwnx_hw->cmd_mgr = &rwnx_plat->usbdev->cmd_mgr; ++#endif ++ rwnx_hw->mod_params = &rwnx_mod_params; ++ rwnx_hw->tcp_pacing_shift = 7; ++ ++#ifdef CONFIG_SCHED_SCAN ++ rwnx_hw->is_sched_scan = false; ++#endif //CONFIG_SCHED_SCAN ++ ++ aicwf_wakeup_lock_init(rwnx_hw); ++ rwnx_init_aic(rwnx_hw); ++ /* set device pointer for wiphy */ ++ set_wiphy_dev(wiphy, rwnx_hw->dev); ++ ++ /* Create cache to allocate sw_txhdr */ ++ rwnx_hw->sw_txhdr_cache = KMEM_CACHE(rwnx_sw_txhdr, 0); ++ if (!rwnx_hw->sw_txhdr_cache) { ++ wiphy_err(wiphy, "Cannot allocate cache for sw TX header\n"); ++ ret = -ENOMEM; ++ goto err_cache; ++ } ++ ++#ifdef CONFIG_FILTER_TCP_ACK ++ tcp_ack_init(rwnx_hw); ++#endif ++ ++#if 0 ++ ret = rwnx_parse_configfile(rwnx_hw, RWNX_CONFIG_FW_NAME, &init_conf); ++ if (ret) { ++ wiphy_err(wiphy, "rwnx_parse_configfile failed\n"); ++ goto err_config; ++ } ++#else ++ memcpy(init_conf.mac_addr, dflt_mac, ETH_ALEN); ++#endif ++ ++ rwnx_hw->vif_started = 0; ++ rwnx_hw->monitor_vif = RWNX_INVALID_VIF; ++ rwnx_hw->adding_sta = false; ++ ++ rwnx_hw->scan_ie.addr = NULL; ++ ++ for (i = 0; i < NX_VIRT_DEV_MAX + NX_REMOTE_STA_MAX; i++) ++ rwnx_hw->avail_idx_map |= BIT(i); ++ ++ rwnx_hwq_init(rwnx_hw); ++ ++#ifdef CONFIG_PREALLOC_TXQ ++ rwnx_hw->txq = (struct rwnx_txq *)aicwf_prealloc_txq_alloc( ++ sizeof(struct rwnx_txq) * NX_NB_TXQ); ++#endif ++ ++ for (i = 0; i < NX_NB_TXQ; i++) { ++ rwnx_hw->txq[i].idx = TXQ_INACTIVE; ++ } ++ ++ rwnx_mu_group_init(rwnx_hw); ++ ++ /* Initialize RoC element pointer to NULL, indicate that RoC can be started */ ++ rwnx_hw->roc_elem = NULL; ++ /* 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; ++ ++ //init ic system ++ if ((ret = rwnx_ic_system_init(rwnx_hw))) { ++ goto err_lmac_reqs; ++ } ++ ++ //ret = rwnx_send_set_stack_start_req(rwnx_hw, 1, feature.hwinfo < 0, feature.hwinfo, 0, &set_start_cfm); ++#ifdef USE_5G ++ if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8801) { ++ ret = rwnx_send_set_stack_start_req(rwnx_hw, 1, 0, CO_BIT(5), 0, ++ &set_start_cfm); ++ } ++#else ++ if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8801) { ++ ret = rwnx_send_set_stack_start_req(rwnx_hw, 1, 0, 0, 0, ++ &set_start_cfm); ++ } ++#endif ++ else if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ ret = rwnx_send_set_stack_start_req(rwnx_hw, 1, 0, 0, 0, ++ &set_start_cfm); ++ set_start_cfm.is_5g_support = false; ++ } else { ++ ret = rwnx_send_set_stack_start_req(rwnx_hw, 1, 0, CO_BIT(5), 0, ++ &set_start_cfm); ++ } ++ ++ if (ret) ++ goto err_lmac_reqs; ++ ++ AICWFDBG(LOGINFO, "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); ++ AICWFDBG(LOGINFO, "Firmware Version: %s\r\n", fw_version.fw_version); ++ ++ wiphy->bands[NL80211_BAND_2GHZ] = &rwnx_band_2GHz; ++ if (rwnx_hw->band_5g_support) ++ wiphy->bands[NL80211_BAND_5GHZ] = &rwnx_band_5GHz; ++ ++ wiphy->interface_modes = ++ BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP) | ++ BIT(NL80211_IFTYPE_AP_VLAN) | BIT(NL80211_IFTYPE_P2P_CLIENT) | ++ BIT(NL80211_IFTYPE_P2P_GO) | ++#ifndef CONFIG_USE_P2P0 ++ BIT(NL80211_IFTYPE_P2P_DEVICE) | ++#endif ++ BIT(NL80211_IFTYPE_MONITOR); ++ ++#if IS_ENABLED(CONFIG_PM) ++ /* Set WoWLAN flags */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) ++ wiphy->wowlan = &aic_wowlan_support; ++#else ++ wiphy->wowlan.flags = aic_wowlan_support.flags; ++#endif ++#endif ++ wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) ++ WIPHY_FLAG_HAS_CHANNEL_SWITCH | ++#endif ++ WIPHY_FLAG_4ADDR_STATION | WIPHY_FLAG_4ADDR_AP; ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) ++ wiphy->max_num_csa_counters = BCN_MAX_CSA_CPT; ++#endif ++ ++ wiphy->max_remain_on_channel_duration = ++ rwnx_hw->mod_params->roc_dur_max; ++ ++ wiphy->features |= NL80211_FEATURE_NEED_OBSS_SCAN | ++ NL80211_FEATURE_SK_TX_STATUS | ++ NL80211_FEATURE_VIF_TXPOWER | ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) ++ NL80211_FEATURE_ACTIVE_MONITOR | ++#endif ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) ++ NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | ++#endif ++ 0; ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0) || \ ++ defined(CONFIG_WPA3_FOR_OLD_KERNEL) ++ wiphy->features |= NL80211_FEATURE_SAE; ++#endif ++ ++ if (rwnx_mod_params.tdls) ++ /* TDLS support */ ++ wiphy->features |= NL80211_FEATURE_TDLS_CHANNEL_SWITCH; ++ ++ wiphy->iface_combinations = rwnx_combinations; ++ /* -1 not to include combination with radar detection, will be re-added in ++ rwnx_handle_dynparams if supported */ ++ wiphy->n_iface_combinations = ARRAY_SIZE(rwnx_combinations) - 1; ++ wiphy->reg_notifier = rwnx_reg_notifier; ++ ++ wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; ++ ++ rwnx_enable_wapi(rwnx_hw); ++ ++ wiphy->cipher_suites = cipher_suites; ++ wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites) - NB_RESERVED_CIPHER; ++ ++ rwnx_hw->ext_capa[0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING; ++ rwnx_hw->ext_capa[7] = WLAN_EXT_CAPA8_OPMODE_NOTIF; ++ ++ wiphy->extended_capabilities = rwnx_hw->ext_capa; ++ wiphy->extended_capabilities_mask = rwnx_hw->ext_capa; ++ wiphy->extended_capabilities_len = ARRAY_SIZE(rwnx_hw->ext_capa); ++ ++#ifdef CONFIG_SCHED_SCAN ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) ++ wiphy->max_sched_scan_reqs = 1; ++#endif ++ wiphy->max_sched_scan_ssids = SCAN_SSID_MAX; //16; ++ wiphy->max_match_sets = SCAN_SSID_MAX; //16; ++ wiphy->max_sched_scan_ie_len = 2048; ++#endif //CONFIG_SCHED_SCAN ++ ++ tasklet_init(&rwnx_hw->task, rwnx_task, (unsigned long)rwnx_hw); ++ ++ //init ic rf ++ if ((ret = rwnx_ic_rf_init(rwnx_hw))) { ++ goto err_lmac_reqs; ++ } ++ ++#ifdef CONFIG_USE_CUSTOMER_MAC ++ ret = rwnx_get_custom_mac_addr(mac_addr_efuse); ++ if (ret) { ++ AICWFDBG(LOGERROR, "%s read mac fail use default mac\r\n", ++ __func__); ++ memcpy(init_conf.mac_addr, dflt_mac, ETH_ALEN); ++ } ++#else ++ ret = rwnx_send_get_macaddr_req( ++ rwnx_hw, (struct mm_get_mac_addr_cfm *)mac_addr_efuse); ++ if (ret) ++ goto err_lmac_reqs; ++#endif ++ ++ if (mac_addr_efuse[0] | mac_addr_efuse[1] | mac_addr_efuse[2] | ++ mac_addr_efuse[3]) { ++ memcpy(init_conf.mac_addr, mac_addr_efuse, ETH_ALEN); ++ } else { ++ memcpy(init_conf.mac_addr, dflt_mac, ETH_ALEN); ++ } ++ ++ AICWFDBG(LOGINFO, "get macaddr: %02x:%02x:%02x:%02x:%02x:%02x\r\n", ++ mac_addr_efuse[0], mac_addr_efuse[1], mac_addr_efuse[2], ++ mac_addr_efuse[3], mac_addr_efuse[4], mac_addr_efuse[5]); ++ memcpy(wiphy->perm_addr, init_conf.mac_addr, ETH_ALEN); ++ ++ /* Reset FW */ ++ ret = rwnx_send_reset(rwnx_hw); ++ if (ret) ++ goto err_lmac_reqs; ++ ++#ifdef CONFIG_TEMP_COMP ++ rwnx_send_set_temp_comp_req(rwnx_hw, &swconfig_cfm); ++#endif ++ ++ ret = rwnx_send_version_req(rwnx_hw, &rwnx_hw->version_cfm); ++ if (ret) ++ goto err_lmac_reqs; ++ rwnx_set_vers(rwnx_hw); ++ ++ ret = rwnx_handle_dynparams(rwnx_hw, rwnx_hw->wiphy); ++ if (ret) ++ goto err_lmac_reqs; ++ ++ rwnx_enable_mesh(rwnx_hw); ++ rwnx_radar_detection_init(&rwnx_hw->radar); ++ ++#ifdef CONFIG_RADAR_OR_IR_DETECT ++ rwnx_radar_set_domain(&rwnx_hw->radar, NL80211_DFS_FCC); ++#endif ++ ++ /* Set parameters to firmware */ ++ if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ ((rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DW || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) && ++ testmode == 0)) { ++ rwnx_send_me_config_req(rwnx_hw); ++ } ++ ++ /* Only monitor mode supported when custom channels are enabled */ ++ if (rwnx_mod_params.custchan) { ++ rwnx_limits[0].types = BIT(NL80211_IFTYPE_MONITOR); ++ rwnx_limits_dfs[0].types = BIT(NL80211_IFTYPE_MONITOR); ++ } ++ ++ aicwf_vendor_init(wiphy); ++ ++ ret = wiphy_register(wiphy); ++ if (ret) { ++ wiphy_err(wiphy, "Could not register wiphy device\n"); ++ goto err_register_wiphy; ++ } ++ ++ /* Update regulatory (if needed) and set channel parameters to firmware ++ (must be done after WiPHY registration) */ ++ rwnx_custregd(rwnx_hw, wiphy); ++ ++ if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ ((rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DW || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) && ++ testmode == 0)) { ++ rwnx_send_me_chan_config_req(rwnx_hw, "00"); ++ } ++ ++ *platform_data = rwnx_hw; ++ ++#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 */ ++ vif = rwnx_interface_add(rwnx_hw, "wlan%d", NET_NAME_UNKNOWN, ++ NL80211_IFTYPE_STATION, NULL); ++ ++#ifdef CONFIG_RWNX_MON_DATA ++ /* Add an initial station interface */ ++ vif = rwnx_interface_add(rwnx_hw, "wlan%d", 1, NL80211_IFTYPE_MONITOR, ++ NULL); ++#endif ++ ++ rtnl_unlock(); ++ ++ if (!vif) { ++ wiphy_err(wiphy, "Failed to instantiate a network device\n"); ++ ret = -ENOMEM; ++ goto err_add_interface; ++ } ++ ++ //wiphy_info(wiphy, "New interface create %s", vif->ndev->name); ++ AICWFDBG(LOGINFO, "New interface create %s \r\n", vif->ndev->name); ++ ++#ifdef CONFIG_SDIO_BT ++#if CONFIG_BLUEDROID ++ btchr_init(); ++ hdev_init(); ++#else ++ btsdio_init(); ++#endif ++#endif ++ ++#ifdef CONFIG_USE_P2P0 ++ ++ rtnl_lock(); ++ /* Add an initial p2p0 interface */ ++ vif = rwnx_interface_add(rwnx_hw, "p2p%d", NET_NAME_UNKNOWN, ++ NL80211_IFTYPE_STATION, NULL); ++ vif->is_p2p_vif = 1; ++ rtnl_unlock(); ++ ++ if (!vif) { ++ wiphy_err(wiphy, "Failed to instantiate a network device\n"); ++ ret = -ENOMEM; ++ goto err_add_interface; ++ } ++ ++ //wiphy_info(wiphy, "New interface create %s", vif->ndev->name); ++ AICWFDBG(LOGINFO, "New interface create %s \r\n", vif->ndev->name); ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) ++ init_timer(&rwnx_hw->p2p_alive_timer); ++ rwnx_hw->p2p_alive_timer.data = (unsigned long)vif; ++ rwnx_hw->p2p_alive_timer.function = aicwf_p2p_alive_timeout; ++#else ++ timer_setup(&rwnx_hw->p2p_alive_timer, aicwf_p2p_alive_timeout, 0); ++#endif ++ rwnx_hw->is_p2p_alive = 0; ++ rwnx_hw->is_p2p_connected = 0; ++ atomic_set(&rwnx_hw->p2p_alive_timer_count, 0); ++#endif ++ ++#ifdef CONFIG_FOR_IPCAM ++ if (!testmode && !adap_test) { ++ aic_ipc_setting(vif); ++ } ++#endif ++ ++ return 0; ++ ++err_add_interface: ++#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_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; ++} ++ ++/** ++ * ++ */ ++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)) ++ timer_delete_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 ++ ++#ifdef CONFIG_SDIO_BT ++#if CONFIG_BLUEDROID ++ btchr_exit(); ++ hdev_exit(); ++#else ++ btsdio_remove(); ++#endif ++#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); ++#ifdef CONFIG_FILTER_TCP_ACK ++ tcp_ack_deinit(rwnx_hw); ++#endif ++ aicwf_wakeup_lock_deinit(rwnx_hw); ++ wiphy_free(rwnx_hw->wiphy); ++} ++ ++static void aicsmac_driver_register(void) ++{ ++#ifdef AICWF_SDIO_SUPPORT ++ aicwf_sdio_register(); ++#endif ++#ifdef AICWF_USB_SUPPORT ++ aicwf_usb_register(); ++#endif ++#ifdef AICWF_PCIE_SUPPORT ++ aicwf_pcie_register(); ++#endif ++} ++ ++//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; ++ g_rwnx_plat->enabled = true; ++ complete(&hostif_register_done); ++} ++ ++void aicwf_hostif_fail(void) ++{ ++ rwnx_driver_err = 1; ++ complete(&hostif_register_done); ++} ++ ++static int __init rwnx_mod_init(void) ++{ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ rwnx_print_version(); ++ rwnx_init_cmd_array(); ++ ++ //#ifndef CONFIG_PLATFORM_ROCKCHIP ++ if (aicbsp_set_subsys(AIC_WIFI, AIC_PWR_ON) < 0) { ++ AICWFDBG(LOGERROR, "%s, set power on fail!\n", __func__); ++ if (!aicbsp_get_load_fw_in_fdrv()) { ++ return -ENODEV; ++ } ++ } ++ //#endif ++ ++ init_completion(&hostif_register_done); ++ aicsmac_driver_register(); ++ ++ if ((wait_for_completion_timeout( ++ &hostif_register_done, ++ msecs_to_jiffies(REGISTRATION_TIMEOUT)) == 0) || ++ rwnx_driver_err) { ++ AICWFDBG(LOGERROR, "register_driver timeout or error\n"); ++#ifdef AICWF_SDIO_SUPPORT ++ aicwf_sdio_exit(); ++#endif /* AICWF_SDIO_SUPPORT */ ++#ifdef AICWF_USB_SUPPORT ++ aicwf_usb_exit(); ++#endif /*AICWF_USB_SUPPORT */ ++ aicbsp_set_subsys(AIC_WIFI, AIC_PWR_OFF); ++ return -ENODEV; ++ } ++ ++#ifdef AICWF_PCIE_SUPPORT ++ return rwnx_platform_register_drv(); ++#else ++ return 0; ++#endif ++} ++ ++/** ++ * ++ */ ++static void __exit rwnx_mod_exit(void) ++{ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++#ifdef AICWF_PCIE_SUPPORT ++ rwnx_platform_unregister_drv(); ++#endif ++ ++#ifdef AICWF_SDIO_SUPPORT ++ aicwf_sdio_exit(); ++#endif ++ ++#ifdef AICWF_USB_SUPPORT ++ aicwf_usb_exit(); ++#endif ++ //#ifndef CONFIG_PLATFORM_ROCKCHIP ++ aicbsp_set_subsys(AIC_WIFI, AIC_PWR_OFF); ++ //#endif ++ rwnx_free_cmd_array(); ++} ++ ++#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 ++ ++module_init(rwnx_mod_init); ++module_exit(rwnx_mod_exit); ++ ++MODULE_FIRMWARE(RWNX_CONFIG_FW_NAME); ++ ++MODULE_DESCRIPTION(RW_DRV_DESCRIPTION); ++MODULE_VERSION(RWNX_VERS_MOD); ++MODULE_AUTHOR(RW_DRV_COPYRIGHT " " RW_DRV_AUTHOR); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_main.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_main.h +new file mode 100755 +index 000000000..78dd422ba +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_main.h +@@ -0,0 +1,26 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_main.h ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++#ifndef _RWNX_MAIN_H_ ++#define _RWNX_MAIN_H_ ++ ++#include "rwnx_defs.h" ++ ++int rwnx_cfg80211_init(struct rwnx_plat *rwnx_plat, void **platform_data); ++void rwnx_cfg80211_deinit(struct rwnx_hw *rwnx_hw); ++extern int testmode; ++extern u8 chip_sub_id; ++extern u8 chip_mcu_id; ++extern u8 chip_id; ++ ++#define CHIP_ID_H_MASK 0xC0 ++#define IS_CHIP_ID_H() ((chip_id & CHIP_ID_H_MASK) == CHIP_ID_H_MASK) ++ ++#endif /* _RWNX_MAIN_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mesh.c b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mesh.c +new file mode 100755 +index 000000000..96d5ee270 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mesh.c +@@ -0,0 +1,43 @@ ++/** ++ **************************************************************************************** ++ * ++ * @file rwnx_mesh.c ++ * ++ * Copyright (C) RivieraWaves 2016-2019 ++ * ++ **************************************************************************************** ++ */ ++ ++/** ++ * INCLUDE FILES ++ **************************************************************************************** ++ */ ++ ++#include "rwnx_mesh.h" ++ ++/** ++ * FUNCTION DEFINITIONS ++ **************************************************************************************** ++ */ ++ ++struct rwnx_mesh_proxy *rwnx_get_mesh_proxy_info(struct rwnx_vif *p_rwnx_vif, ++ u8 *p_sta_addr, bool local) ++{ ++ struct rwnx_mesh_proxy *p_mesh_proxy = NULL; ++ struct rwnx_mesh_proxy *p_cur_proxy; ++ ++ /* Look for proxied devices with provided address */ ++ list_for_each_entry (p_cur_proxy, &p_rwnx_vif->ap.proxy_list, list) { ++ if (p_cur_proxy->local != local) { ++ continue; ++ } ++ ++ if (!memcmp(&p_cur_proxy->ext_sta_addr, p_sta_addr, ETH_ALEN)) { ++ p_mesh_proxy = p_cur_proxy; ++ break; ++ } ++ } ++ ++ /* Return the found information */ ++ return p_mesh_proxy; ++} +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mesh.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mesh.h +new file mode 100755 +index 000000000..73cff04a5 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mesh.h +@@ -0,0 +1,46 @@ ++/** ++ **************************************************************************************** ++ * ++ * @file rwnx_mesh.h ++ * ++ * @brief VHT Beamformer function declarations ++ * ++ * Copyright (C) RivieraWaves 2016-2019 ++ * ++ **************************************************************************************** ++ */ ++ ++#ifndef _RWNX_MESH_H_ ++#define _RWNX_MESH_H_ ++ ++/** ++ * INCLUDE FILES ++ **************************************************************************************** ++ */ ++ ++#include "rwnx_defs.h" ++ ++/** ++ * DEFINES ++ **************************************************************************************** ++ */ ++ ++/** ++ * TYPE DEFINITIONS ++ **************************************************************************************** ++ */ ++ ++/** ++ * FUNCTION DECLARATIONS ++ **************************************************************************************** ++ */ ++ ++/** ++ **************************************************************************************** ++ * @brief TODO [LT] ++ **************************************************************************************** ++ */ ++struct rwnx_mesh_proxy *rwnx_get_mesh_proxy_info(struct rwnx_vif *p_rwnx_vif, ++ u8 *p_sta_addr, bool local); ++ ++#endif /* _RWNX_MESH_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mod_params.c b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mod_params.c +new file mode 100755 +index 000000000..ad7e68b05 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mod_params.c +@@ -0,0 +1,1978 @@ ++/** ++****************************************************************************** ++* ++* @file rwnx_mod_params.c ++* ++* @brief Set configuration according to modules parameters ++* ++* Copyright (C) RivieraWaves 2012-2019 ++* ++****************************************************************************** ++*/ ++#include ++#include ++ ++#include "rwnx_defs.h" ++#include "rwnx_tx.h" ++#include "hal_desc.h" ++#include "rwnx_cfgfile.h" ++#include "rwnx_dini.h" ++#include "reg_access.h" ++#include "rwnx_compat.h" ++ ++#ifdef CONFIG_RWNX_FULLMAC ++#define COMMON_PARAM(name, default_softmac, default_fullmac) \ ++ .name = default_fullmac, ++#define SOFTMAC_PARAM(name, default) ++#define FULLMAC_PARAM(name, default) .name = default, ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++struct rwnx_mod_params rwnx_mod_params = { ++ /* common parameters */ ++ COMMON_PARAM(ht_on, true, true) 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_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) COMMON_PARAM(gf_rx_on, false, ++ false) COMMON_PARAM(phy_cfg, ++ 2, ++ 2) ++ COMMON_PARAM(uapsd_timeout, 300, 300) COMMON_PARAM( ++ ap_uapsd_on, true, ++ true) COMMON_PARAM(sgi, true, ++ true) COMMON_PARAM(sgi80, ++ false, ++ false) ++ COMMON_PARAM(use_2040, 1, 1) COMMON_PARAM(nss, 2, 2) COMMON_PARAM( ++ amsdu_rx_max, ++ 1, 1) COMMON_PARAM(bfmee, ++ true, true) COMMON_PARAM(bfmer, false, false) ++ COMMON_PARAM(mesh, true, true) COMMON_PARAM( ++ murx, true, ++ true) COMMON_PARAM(mutx, ++ true, true) ++ COMMON_PARAM(mutx_on, true, true) COMMON_PARAM( ++ use_80, ++ false, ++ false) COMMON_PARAM(custregd, ++ true, ++ true) ++ COMMON_PARAM(custchan, false, false) COMMON_PARAM( ++ roc_dur_max, ++ 500, ++ 500) COMMON_PARAM(listen_itv, ++ 0, ++ 0) ++ COMMON_PARAM(listen_bcmc, true, true) COMMON_PARAM( ++ lp_clk_ppm, ++ 20, ++ 20) COMMON_PARAM(ps_on, ++ true, ++ true) ++ COMMON_PARAM( ++ tx_lft, ++ RWNX_TX_LIFETIME_MS, ++ RWNX_TX_LIFETIME_MS) ++ 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, false, false) COMMON_PARAM(uf, false, false) ++ COMMON_PARAM(auto_reply, false, false) ++ COMMON_PARAM(ftl, "", "") ++ COMMON_PARAM(dpsm, false, false) ++ ++ /* SOFTMAC only parameters */ ++ SOFTMAC_PARAM(mfp_on, false) SOFTMAC_PARAM(gf_on, false) SOFTMAC_PARAM( ++ bwsig_on, true) SOFTMAC_PARAM(dynbw_on, ++ true) SOFTMAC_PARAM(agg_tx, true) ++ SOFTMAC_PARAM(amsdu_force, 2) SOFTMAC_PARAM(rc_probes_on, false) ++ SOFTMAC_PARAM(cmon, true) SOFTMAC_PARAM(hwscan, true) ++ SOFTMAC_PARAM(autobcn, true) ++ SOFTMAC_PARAM(dpsm, true) ++ ++ /* FULLMAC only parameters */ ++ FULLMAC_PARAM(ant_div, true) ++}; ++ ++#ifdef CONFIG_RWNX_FULLMAC ++/* FULLMAC specific parameters*/ ++module_param_named(ant_div, rwnx_mod_params.ant_div, bool, S_IRUGO); ++MODULE_PARM_DESC(ant_div, "Enable Antenna Diversity (Default: 1)"); ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++module_param_named(ht_on, rwnx_mod_params.ht_on, bool, S_IRUGO); ++MODULE_PARM_DESC(ht_on, "Enable HT (Default: 1)"); ++ ++module_param_named(vht_on, rwnx_mod_params.vht_on, bool, S_IRUGO); ++MODULE_PARM_DESC(vht_on, "Enable VHT (Default: 1)"); ++ ++module_param_named(he_on, rwnx_mod_params.he_on, bool, S_IRUGO); ++MODULE_PARM_DESC(he_on, "Enable HE (Default: 1)"); ++ ++module_param_named(mcs_map, rwnx_mod_params.mcs_map, int, S_IRUGO); ++MODULE_PARM_DESC(mcs_map, "VHT MCS map value 0: MCS0_7, 1: MCS0_8, 2: MCS0_9" ++ " (Default: 2)"); ++ ++module_param_named(he_mcs_map, rwnx_mod_params.he_mcs_map, int, S_IRUGO); ++MODULE_PARM_DESC(he_mcs_map, ++ "HE MCS map value 0: MCS0_7, 1: MCS0_9, 2: MCS0_11" ++ " (Default: 2)"); ++ ++module_param_named(he_ul_on, rwnx_mod_params.he_ul_on, bool, S_IRUGO); ++MODULE_PARM_DESC(he_ul_on, "Enable HE OFDMA UL (Default: 0)"); ++ ++module_param_named(amsdu_maxnb, rwnx_mod_params.amsdu_maxnb, int, ++ S_IRUGO | S_IWUSR); ++MODULE_PARM_DESC( ++ amsdu_maxnb, ++ "Maximum number of MSDUs inside an A-MSDU in TX: (Default: NX_TX_PAYLOAD_MAX)"); ++ ++module_param_named(ps_on, rwnx_mod_params.ps_on, bool, S_IRUGO); ++MODULE_PARM_DESC(ps_on, "Enable PowerSaving (Default: 1-Enabled)"); ++ ++module_param_named(tx_lft, rwnx_mod_params.tx_lft, int, 0644); ++MODULE_PARM_DESC(tx_lft, "Tx lifetime (ms) - setting it to 0 disables retries " ++ "(Default: " __stringify(RWNX_TX_LIFETIME_MS) ")"); ++ ++module_param_named(ldpc_on, rwnx_mod_params.ldpc_on, bool, S_IRUGO); ++MODULE_PARM_DESC(ldpc_on, "Enable LDPC (Default: 1)"); ++ ++module_param_named(stbc_on, rwnx_mod_params.stbc_on, bool, S_IRUGO); ++MODULE_PARM_DESC(stbc_on, "Enable STBC in RX (Default: 1)"); ++ ++module_param_named(gf_rx_on, rwnx_mod_params.gf_rx_on, bool, S_IRUGO); ++MODULE_PARM_DESC(gf_rx_on, "Enable HT greenfield in reception (Default: 1)"); ++ ++module_param_named(phycfg, rwnx_mod_params.phy_cfg, int, S_IRUGO); ++MODULE_PARM_DESC(phycfg, ++ "0 <= phycfg <= 5 : RF Channel Conf (Default: 2(C0-A1-B2))"); ++ ++module_param_named(uapsd_timeout, rwnx_mod_params.uapsd_timeout, int, ++ S_IRUGO | S_IWUSR); ++MODULE_PARM_DESC( ++ uapsd_timeout, ++ "UAPSD Timer timeout, in ms (Default: 300). If 0, UAPSD is disabled"); ++ ++module_param_named(uapsd_queues, rwnx_mod_params.uapsd_queues, int, ++ S_IRUGO | S_IWUSR); ++MODULE_PARM_DESC( ++ uapsd_queues, ++ "UAPSD Queues, integer value, must be seen as a bitfield\n" ++ " Bit 0 = VO\n" ++ " Bit 1 = VI\n" ++ " Bit 2 = BK\n" ++ " Bit 3 = BE\n" ++ " -> uapsd_queues=7 will enable uapsd for VO, VI and BK queues"); ++ ++module_param_named(ap_uapsd_on, rwnx_mod_params.ap_uapsd_on, bool, S_IRUGO); ++MODULE_PARM_DESC(ap_uapsd_on, "Enable UAPSD in AP mode (Default: 1)"); ++ ++module_param_named(sgi, rwnx_mod_params.sgi, bool, S_IRUGO); ++MODULE_PARM_DESC(sgi, "Advertise Short Guard Interval support (Default: 1)"); ++ ++module_param_named(sgi80, rwnx_mod_params.sgi80, bool, S_IRUGO); ++MODULE_PARM_DESC( ++ sgi80, "Advertise Short Guard Interval support for 80MHz (Default: 1)"); ++ ++module_param_named(use_2040, rwnx_mod_params.use_2040, bool, S_IRUGO); ++MODULE_PARM_DESC(use_2040, "Use tweaked 20-40MHz mode (Default: 1)"); ++ ++module_param_named(use_80, rwnx_mod_params.use_80, bool, S_IRUGO); ++MODULE_PARM_DESC(use_80, "Enable 80MHz (Default: 1)"); ++ ++module_param_named(custregd, rwnx_mod_params.custregd, bool, S_IRUGO); ++MODULE_PARM_DESC( ++ custregd, ++ "Use permissive custom regulatory rules (for testing ONLY) (Default: 0)"); ++ ++module_param_named(custchan, rwnx_mod_params.custchan, bool, S_IRUGO); ++MODULE_PARM_DESC( ++ custchan, ++ "Extend channel set to non-standard channels (for testing ONLY) (Default: 0)"); ++ ++module_param_named(nss, rwnx_mod_params.nss, int, S_IRUGO); ++MODULE_PARM_DESC( ++ nss, ++ "1 <= nss <= 2 : Supported number of Spatial Streams (Default: 1)"); ++ ++module_param_named(amsdu_rx_max, rwnx_mod_params.amsdu_rx_max, int, S_IRUGO); ++MODULE_PARM_DESC( ++ amsdu_rx_max, ++ "0 <= amsdu_rx_max <= 2 : Maximum A-MSDU size supported in RX\n" ++ " 0: 3895 bytes\n" ++ " 1: 7991 bytes\n" ++ " 2: 11454 bytes\n" ++ " This value might be reduced according to the FW capabilities.\n" ++ " Default: 2"); ++ ++module_param_named(bfmee, rwnx_mod_params.bfmee, bool, S_IRUGO); ++MODULE_PARM_DESC(bfmee, "Enable Beamformee Capability (Default: 1-Enabled)"); ++ ++module_param_named(bfmer, rwnx_mod_params.bfmer, bool, S_IRUGO); ++MODULE_PARM_DESC(bfmer, "Enable Beamformer Capability (Default: 0-Disabled)"); ++ ++module_param_named(mesh, rwnx_mod_params.mesh, bool, S_IRUGO); ++MODULE_PARM_DESC(mesh, "Enable Meshing Capability (Default: 1-Enabled)"); ++ ++module_param_named(murx, rwnx_mod_params.murx, bool, S_IRUGO); ++MODULE_PARM_DESC(murx, "Enable MU-MIMO RX Capability (Default: 1-Enabled)"); ++ ++module_param_named(mutx, rwnx_mod_params.mutx, bool, S_IRUGO); ++MODULE_PARM_DESC(mutx, "Enable MU-MIMO TX Capability (Default: 1-Enabled)"); ++ ++module_param_named(mutx_on, rwnx_mod_params.mutx_on, bool, S_IRUGO | S_IWUSR); ++MODULE_PARM_DESC(mutx_on, "Enable MU-MIMO transmissions (Default: 1-Enabled)"); ++ ++module_param_named(roc_dur_max, rwnx_mod_params.roc_dur_max, int, S_IRUGO); ++MODULE_PARM_DESC(roc_dur_max, "Maximum Remain on Channel duration"); ++ ++module_param_named(listen_itv, rwnx_mod_params.listen_itv, int, S_IRUGO); ++MODULE_PARM_DESC(listen_itv, "Maximum listen interval"); ++ ++module_param_named(listen_bcmc, rwnx_mod_params.listen_bcmc, bool, S_IRUGO); ++MODULE_PARM_DESC(listen_bcmc, "Wait for BC/MC traffic following DTIM beacon"); ++ ++module_param_named(lp_clk_ppm, rwnx_mod_params.lp_clk_ppm, int, S_IRUGO); ++MODULE_PARM_DESC(lp_clk_ppm, "Low Power Clock accuracy of the local device"); ++ ++module_param_named(tdls, rwnx_mod_params.tdls, bool, S_IRUGO); ++MODULE_PARM_DESC(tdls, "Enable TDLS (Default: 1-Enabled)"); ++ ++module_param_named(uf, rwnx_mod_params.uf, bool, S_IRUGO | S_IWUSR); ++MODULE_PARM_DESC(uf, ++ "Enable Unsupported HT Frame Logging (Default: 0-Disabled)"); ++ ++module_param_named(auto_reply, rwnx_mod_params.auto_reply, bool, ++ S_IRUGO | S_IWUSR); ++MODULE_PARM_DESC(auto_reply, ++ "Enable Monitor MacAddr Auto-Reply (Default: 0-Disabled)"); ++ ++module_param_named(ftl, rwnx_mod_params.ftl, charp, S_IRUGO); ++MODULE_PARM_DESC(ftl, "Firmware trace level (Default: \"\")"); ++ ++module_param_named(dpsm, rwnx_mod_params.dpsm, bool, S_IRUGO); ++MODULE_PARM_DESC(dpsm, "Enable Dynamic PowerSaving (Default: 1-Enabled)"); ++ ++#ifdef DEFAULT_COUNTRY_CODE ++char default_ccode[4] = DEFAULT_COUNTRY_CODE; ++#else ++char default_ccode[4] = "00"; ++#endif ++ ++char country_code[4]; ++module_param_string(country_code, country_code, 4, 0600); ++ ++#if 0 ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) ++/* Regulatory rules */ ++static struct ieee80211_regdomain rwnx_regdom = { ++ .n_reg_rules = 2, ++ .alpha2 = "99", ++ .reg_rules = { ++ REG_RULE(2390 - 10, 2510 + 10, 40, 0, 1000, 0), ++ REG_RULE(5150 - 10, 5970 + 10, 80, 0, 1000, 0), ++ } ++}; ++#endif ++#endif ++ ++static const int mcs_map_to_rate[4][3] = { ++ [PHY_CHNL_BW_20][IEEE80211_VHT_MCS_SUPPORT_0_7] = 65, ++ [PHY_CHNL_BW_20][IEEE80211_VHT_MCS_SUPPORT_0_8] = 78, ++ [PHY_CHNL_BW_20][IEEE80211_VHT_MCS_SUPPORT_0_9] = 78, ++ [PHY_CHNL_BW_40][IEEE80211_VHT_MCS_SUPPORT_0_7] = 135, ++ [PHY_CHNL_BW_40][IEEE80211_VHT_MCS_SUPPORT_0_8] = 162, ++ [PHY_CHNL_BW_40][IEEE80211_VHT_MCS_SUPPORT_0_9] = 180, ++ [PHY_CHNL_BW_80][IEEE80211_VHT_MCS_SUPPORT_0_7] = 292, ++ [PHY_CHNL_BW_80][IEEE80211_VHT_MCS_SUPPORT_0_8] = 351, ++ [PHY_CHNL_BW_80][IEEE80211_VHT_MCS_SUPPORT_0_9] = 390, ++ [PHY_CHNL_BW_160][IEEE80211_VHT_MCS_SUPPORT_0_7] = 585, ++ [PHY_CHNL_BW_160][IEEE80211_VHT_MCS_SUPPORT_0_8] = 702, ++ [PHY_CHNL_BW_160][IEEE80211_VHT_MCS_SUPPORT_0_9] = 780, ++}; ++ ++#define MAX_VHT_RATE(map, nss, bw) (mcs_map_to_rate[bw][map] * (nss)) ++ ++extern struct ieee80211_regdomain *reg_regdb[]; ++extern int reg_regdb_size; ++ ++char ccode_channels[200]; ++int index_for_channel_list = 0; ++module_param_string(ccode_channels, ccode_channels, 200, 0600); ++ ++void rwnx_get_countrycode_channels(struct wiphy *wiphy, ++ struct ieee80211_regdomain *regdomain) ++{ ++ enum nl80211_band band; ++ struct ieee80211_supported_band *sband; ++ int channel_index; ++ int rule_index; ++ int band_num = 0; ++ int rule_num = regdomain->n_reg_rules; ++ int start_freq = 0; ++ int end_freq = 0; ++ int center_freq = 0; ++ char channel[4]; ++ ++ band_num = NUM_NL80211_BANDS; ++ ++ memset(ccode_channels, 0, 200); ++ index_for_channel_list = 0; ++ ++ for (band = 0; band < band_num; band++) { ++ sband = wiphy->bands[band]; // bands: 0:2.4G 1:5G 2:60G ++ if (!sband) ++ continue; ++ ++ for (channel_index = 0; channel_index < sband->n_channels; ++ channel_index++) { ++ for (rule_index = 0; rule_index < rule_num; ++ rule_index++) { ++ start_freq = ++ regdomain->reg_rules[rule_index] ++ .freq_range.start_freq_khz / ++ 1000; ++ end_freq = regdomain->reg_rules[rule_index] ++ .freq_range.end_freq_khz / ++ 1000; ++ center_freq = sband->channels[channel_index] ++ .center_freq; ++ if ((center_freq - 10) >= start_freq && ++ (center_freq + 10) <= end_freq) { ++ sprintf(channel, "%d", ++ ieee80211_frequency_to_channel( ++ center_freq)); ++ memcpy(ccode_channels + ++ index_for_channel_list, ++ channel, strlen(channel)); ++ index_for_channel_list += ++ strlen(channel); ++ memcpy(ccode_channels + ++ index_for_channel_list, ++ " ", 1); ++ index_for_channel_list += 1; ++ break; ++ } ++ } ++ } ++ } ++ AICWFDBG(LOGINFO, "%s support channel:%s\r\n", __func__, ++ ccode_channels); ++} ++ ++struct ieee80211_regdomain *getRegdomainFromRwnxDBIndex(struct wiphy *wiphy, ++ int index) ++{ ++ u8 idx; ++ ++ idx = index; ++ ++ memset(country_code, 0, 4); ++ country_code[0] = reg_regdb[idx]->alpha2[0]; ++ country_code[1] = reg_regdb[idx]->alpha2[1]; ++ ++ printk("%s set ccode:%s \r\n", __func__, country_code); ++ ++ rwnx_get_countrycode_channels(wiphy, reg_regdb[idx]); ++ ++ return reg_regdb[idx]; ++} ++ ++struct ieee80211_regdomain *getRegdomainFromRwnxDB(struct wiphy *wiphy, ++ char *alpha2) ++{ ++ u8 idx; ++ ++ memset(country_code, 0, 4); ++ ++ AICWFDBG(LOGINFO, "%s set ccode:%s \r\n", __func__, alpha2); ++ idx = 0; ++ ++ while (reg_regdb[idx]) { ++ if ((reg_regdb[idx]->alpha2[0] == alpha2[0]) && ++ (reg_regdb[idx]->alpha2[1] == alpha2[1])) { ++ memcpy(country_code, alpha2, 2); ++ rwnx_get_countrycode_channels(wiphy, reg_regdb[idx]); ++ return reg_regdb[idx]; ++ } ++ idx++; ++ } ++ ++ AICWFDBG(LOGERROR, "%s(): Error, wrong country = %s\n", __func__, ++ alpha2); ++ AICWFDBG(LOGINFO, "Set as default 00\n"); ++ memcpy(country_code, default_ccode, sizeof(default_ccode)); ++ rwnx_get_countrycode_channels(wiphy, reg_regdb[0]); ++ ++ return reg_regdb[0]; ++} ++ ++/** ++ * Do some sanity check ++ * ++ */ ++#if 0 ++static int rwnx_check_fw_hw_feature(struct rwnx_hw *rwnx_hw, ++ struct wiphy *wiphy) ++{ ++ u32_l sys_feat = rwnx_hw->version_cfm.features; ++ u32_l mac_feat = rwnx_hw->version_cfm.version_machw_1; ++ u32_l phy_feat = rwnx_hw->version_cfm.version_phy_1; ++ u32_l phy_vers = rwnx_hw->version_cfm.version_phy_2; ++ u16_l max_sta_nb = rwnx_hw->version_cfm.max_sta_nb; ++ u8_l max_vif_nb = rwnx_hw->version_cfm.max_vif_nb; ++ int bw, res = 0; ++ int amsdu_rx; ++ ++ if (!rwnx_hw->mod_params->custregd) ++ rwnx_hw->mod_params->custchan = false; ++ ++ if (rwnx_hw->mod_params->custchan) { ++ rwnx_hw->mod_params->mesh = false; ++ rwnx_hw->mod_params->tdls = false; ++ } ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ ++ if (!(sys_feat & BIT(MM_FEAT_UMAC_BIT))) { ++ wiphy_err(wiphy, ++ "Loading softmac firmware with fullmac driver\n"); ++ res = -1; ++ } ++ ++ if (!(sys_feat & BIT(MM_FEAT_ANT_DIV_BIT))) { ++ rwnx_hw->mod_params->ant_div = false; ++ } ++ ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++ if (!(sys_feat & BIT(MM_FEAT_VHT_BIT))) { ++ rwnx_hw->mod_params->vht_on = false; ++ } ++ ++ // Check if HE is supported ++ if (!(sys_feat & BIT(MM_FEAT_HE_BIT))) { ++ rwnx_hw->mod_params->he_on = false; ++ rwnx_hw->mod_params->he_ul_on = false; ++ } ++ ++ if (!(sys_feat & BIT(MM_FEAT_PS_BIT))) { ++ rwnx_hw->mod_params->ps_on = false; ++ } ++ ++ /* AMSDU (non)support implies different shared structure definition ++ so insure that fw and drv have consistent compilation option */ ++ if (sys_feat & BIT(MM_FEAT_AMSDU_BIT)) { ++#ifndef CONFIG_RWNX_SPLIT_TX_BUF ++ wiphy_err(wiphy, ++ "AMSDU enabled in firmware but support not compiled in driver\n"); ++ res = -1; ++#else ++ if (rwnx_hw->mod_params->amsdu_maxnb > NX_TX_PAYLOAD_MAX) ++ rwnx_hw->mod_params->amsdu_maxnb = NX_TX_PAYLOAD_MAX; ++#endif /* CONFIG_RWNX_SPLIT_TX_BUF */ ++ } else { ++#ifdef CONFIG_RWNX_SPLIT_TX_BUF ++ wiphy_err(wiphy, ++ "AMSDU disabled in firmware but support compiled in driver\n"); ++ res = -1; ++#endif /* CONFIG_RWNX_SPLIT_TX_BUF */ ++ } ++ ++ if (!(sys_feat & BIT(MM_FEAT_UAPSD_BIT))) { ++ rwnx_hw->mod_params->uapsd_timeout = 0; ++ } ++ ++ if (!(sys_feat & BIT(MM_FEAT_BFMEE_BIT))) { ++ rwnx_hw->mod_params->bfmee = false; ++ } ++ ++ if ((sys_feat & BIT(MM_FEAT_BFMER_BIT))) { ++#ifndef CONFIG_RWNX_BFMER ++ wiphy_err(wiphy, ++ "BFMER enabled in firmware but support not compiled in driver\n"); ++ res = -1; ++#endif /* CONFIG_RWNX_BFMER */ ++ // Check PHY and MAC HW BFMER support and update parameter accordingly ++ if (!(phy_feat & MDM_BFMER_BIT) || !(mac_feat & NXMAC_BFMER_BIT)) { ++ rwnx_hw->mod_params->bfmer = false; ++ // Disable the feature in the bitfield so that it won't be displayed ++ sys_feat &= ~BIT(MM_FEAT_BFMER_BIT); ++ } ++ } else { ++#ifdef CONFIG_RWNX_BFMER ++ wiphy_err(wiphy, ++ "BFMER disabled in firmware but support compiled in driver\n"); ++ res = -1; ++#else ++ rwnx_hw->mod_params->bfmer = false; ++#endif /* CONFIG_RWNX_BFMER */ ++ } ++ ++ if (!(sys_feat & BIT(MM_FEAT_MESH_BIT))) { ++ rwnx_hw->mod_params->mesh = false; ++ } ++ ++ if (!(sys_feat & BIT(MM_FEAT_TDLS_BIT))) { ++ rwnx_hw->mod_params->tdls = false; ++ } ++ ++ if (!(sys_feat & BIT(MM_FEAT_UF_BIT))) { ++ rwnx_hw->mod_params->uf = false; ++ } ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ if ((sys_feat & BIT(MM_FEAT_MON_DATA_BIT))) { ++#ifndef CONFIG_RWNX_MON_DATA ++ wiphy_err(wiphy, ++ "Monitor+Data interface support (MON_DATA) is enabled in firmware but support not compiled in driver\n"); ++ res = -1; ++#endif /* CONFIG_RWNX_MON_DATA */ ++ } else { ++#ifdef CONFIG_RWNX_MON_DATA ++ wiphy_err(wiphy, ++ "Monitor+Data interface support (MON_DATA) disabled in firmware but support compiled in driver\n"); ++ res = -1; ++#endif /* CONFIG_RWNX_MON_DATA */ ++ } ++#endif ++ ++ // Check supported AMSDU RX size ++ amsdu_rx = (sys_feat >> MM_AMSDU_MAX_SIZE_BIT0) & 0x03; ++ if (amsdu_rx < rwnx_hw->mod_params->amsdu_rx_max) { ++ rwnx_hw->mod_params->amsdu_rx_max = amsdu_rx; ++ } ++ ++ // Check supported BW ++ bw = (phy_feat & MDM_CHBW_MASK) >> MDM_CHBW_LSB; ++ // Check if 80MHz BW is supported ++ if (bw < 2) { ++ rwnx_hw->mod_params->use_80 = false; ++ } ++ // Check if 40MHz BW is supported ++ if (bw < 1) ++ rwnx_hw->mod_params->use_2040 = false; ++ ++ // 80MHz BW shall be disabled if 40MHz is not enabled ++ if (!rwnx_hw->mod_params->use_2040) ++ rwnx_hw->mod_params->use_80 = false; ++ ++ // Check if HT is supposed to be supported. If not, disable VHT/HE too ++ if (!rwnx_hw->mod_params->ht_on) { ++ rwnx_hw->mod_params->vht_on = false; ++ rwnx_hw->mod_params->he_on = false; ++ rwnx_hw->mod_params->he_ul_on = false; ++ rwnx_hw->mod_params->use_80 = false; ++ rwnx_hw->mod_params->use_2040 = false; ++ } ++ ++ // LDPC is mandatory for HE40 and above, so if LDPC is not supported, then disable ++ // HE to use HT/VHT only ++ if (rwnx_hw->mod_params->use_2040 && !rwnx_hw->mod_params->ldpc_on) { ++ rwnx_hw->mod_params->he_on = false; ++ rwnx_hw->mod_params->he_ul_on = false; ++ } ++ ++ // HT greenfield is not supported in modem >= 3.0 ++ if (__MDM_MAJOR_VERSION(phy_vers) > 0) { ++ rwnx_hw->mod_params->gf_rx_on = false; ++ } ++ ++ if (!(sys_feat & BIT(MM_FEAT_MU_MIMO_RX_BIT)) || ++ !rwnx_hw->mod_params->bfmee) { ++ rwnx_hw->mod_params->murx = false; ++ } ++ ++ if ((sys_feat & BIT(MM_FEAT_MU_MIMO_TX_BIT))) { ++#ifndef CONFIG_RWNX_MUMIMO_TX ++ wiphy_err(wiphy, ++ "MU-MIMO TX enabled in firmware but support not compiled in driver\n"); ++ res = -1; ++#endif /* CONFIG_RWNX_MUMIMO_TX */ ++ if (!rwnx_hw->mod_params->bfmer) ++ rwnx_hw->mod_params->mutx = false; ++ // Check PHY and MAC HW MU-MIMO TX support and update parameter accordingly ++ else if (!(phy_feat & MDM_MUMIMOTX_BIT) || !(mac_feat & NXMAC_MU_MIMO_TX_BIT)) { ++ rwnx_hw->mod_params->mutx = false; ++ // Disable the feature in the bitfield so that it won't be displayed ++ sys_feat &= ~BIT(MM_FEAT_MU_MIMO_TX_BIT); ++ } ++ } else { ++#ifdef CONFIG_RWNX_MUMIMO_TX ++ wiphy_err(wiphy, ++ "MU-MIMO TX disabled in firmware but support compiled in driver\n"); ++ res = -1; ++#else ++ rwnx_hw->mod_params->mutx = false; ++#endif /* CONFIG_RWNX_MUMIMO_TX */ ++ } ++ ++ if (sys_feat & BIT(MM_FEAT_WAPI_BIT)) { ++ rwnx_enable_wapi(rwnx_hw); ++ } ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ if (sys_feat & BIT(MM_FEAT_MFP_BIT)) { ++ rwnx_enable_mfp(rwnx_hw); ++ } ++#endif ++ ++#ifdef CONFIG_RWNX_FULLMAC ++#define QUEUE_NAME "Broadcast/Multicast queue " ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++ if (sys_feat & BIT(MM_FEAT_BCN_BIT)) { ++#if NX_TXQ_CNT == 4 ++ wiphy_err(wiphy, QUEUE_NAME ++ "enabled in firmware but support not compiled in driver\n"); ++ res = -1; ++#endif /* NX_TXQ_CNT == 4 */ ++ } else { ++#if NX_TXQ_CNT == 5 ++ wiphy_err(wiphy, QUEUE_NAME ++ "disabled in firmware but support compiled in driver\n"); ++ res = -1; ++#endif /* NX_TXQ_CNT == 5 */ ++ } ++#undef QUEUE_NAME ++ ++#ifdef CONFIG_RWNX_RADAR ++ if (sys_feat & BIT(MM_FEAT_RADAR_BIT)) { ++ /* Enable combination with radar detection */ ++ wiphy->n_iface_combinations++; ++ } ++#endif /* CONFIG_RWNX_RADAR */ ++ ++#ifndef CONFIG_RWNX_SDM ++ switch (__MDM_PHYCFG_FROM_VERS(phy_feat)) { ++ case MDM_PHY_CONFIG_TRIDENT: ++ case MDM_PHY_CONFIG_ELMA: ++ rwnx_hw->mod_params->nss = 1; ++ break; ++ case MDM_PHY_CONFIG_KARST: ++ { ++ int nss_supp = (phy_feat & MDM_NSS_MASK) >> MDM_NSS_LSB; ++ if (rwnx_hw->mod_params->nss > nss_supp) ++ rwnx_hw->mod_params->nss = nss_supp; ++ } ++ break; ++ default: ++ WARN_ON(1); ++ break; ++ } ++#endif /* CONFIG_RWNX_SDM */ ++ ++ if (rwnx_hw->mod_params->nss < 1 || rwnx_hw->mod_params->nss > 2) ++ rwnx_hw->mod_params->nss = 1; ++ ++ if (rwnx_hw->mod_params->phy_cfg < 0 || rwnx_hw->mod_params->phy_cfg > 5) ++ rwnx_hw->mod_params->phy_cfg = 2; ++ ++ if (rwnx_hw->mod_params->mcs_map < 0 || rwnx_hw->mod_params->mcs_map > 2) ++ rwnx_hw->mod_params->mcs_map = 0; ++ ++ wiphy_info(wiphy, "PHY features: [NSS=%d][CHBW=%d]%s%s\n", ++ rwnx_hw->mod_params->nss, ++ 20 * (1 << ((phy_feat & MDM_CHBW_MASK) >> MDM_CHBW_LSB)), ++ rwnx_hw->mod_params->ldpc_on ? "[LDPC]" : "", ++ rwnx_hw->mod_params->he_on ? "[HE]" : ""); ++ ++#define PRINT_RWNX_FEAT(feat) \ ++ (sys_feat & BIT(MM_FEAT_##feat##_BIT) ? "[" #feat "]" : "") ++ ++ wiphy_info(wiphy, "FW features: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", ++ PRINT_RWNX_FEAT(BCN), ++ PRINT_RWNX_FEAT(AUTOBCN), ++ PRINT_RWNX_FEAT(HWSCAN), ++ PRINT_RWNX_FEAT(CMON), ++ PRINT_RWNX_FEAT(MROLE), ++ PRINT_RWNX_FEAT(RADAR), ++ PRINT_RWNX_FEAT(PS), ++ PRINT_RWNX_FEAT(UAPSD), ++ PRINT_RWNX_FEAT(DPSM), ++ PRINT_RWNX_FEAT(AMPDU), ++ PRINT_RWNX_FEAT(AMSDU), ++ PRINT_RWNX_FEAT(CHNL_CTXT), ++ PRINT_RWNX_FEAT(REORD), ++ PRINT_RWNX_FEAT(P2P), ++ PRINT_RWNX_FEAT(P2P_GO), ++ PRINT_RWNX_FEAT(UMAC), ++ PRINT_RWNX_FEAT(VHT), ++ PRINT_RWNX_FEAT(HE), ++ PRINT_RWNX_FEAT(BFMEE), ++ PRINT_RWNX_FEAT(BFMER), ++ PRINT_RWNX_FEAT(WAPI), ++ PRINT_RWNX_FEAT(MFP), ++ PRINT_RWNX_FEAT(MU_MIMO_RX), ++ PRINT_RWNX_FEAT(MU_MIMO_TX), ++ PRINT_RWNX_FEAT(MESH), ++ PRINT_RWNX_FEAT(TDLS), ++ PRINT_RWNX_FEAT(ANT_DIV)); ++#undef PRINT_RWNX_FEAT ++ ++ if (max_sta_nb != NX_REMOTE_STA_MAX) { ++ wiphy_err(wiphy, "Different number of supported stations between driver and FW (%d != %d)\n", ++ NX_REMOTE_STA_MAX, max_sta_nb); ++ res = -1; ++ } ++ ++ if (max_vif_nb != NX_VIRT_DEV_MAX) { ++ wiphy_err(wiphy, "Different number of supported virtual interfaces between driver and FW (%d != %d)\n", ++ NX_VIRT_DEV_MAX, max_vif_nb); ++ res = -1; ++ } ++ ++ return res; ++} ++#endif ++ ++static void rwnx_set_vht_capa(struct rwnx_hw *rwnx_hw, struct wiphy *wiphy) ++{ ++#ifdef CONFIG_VHT_FOR_OLD_KERNEL ++#ifdef USE_5G ++ struct ieee80211_supported_band *band_5GHz = ++ wiphy->bands[NL80211_BAND_5GHZ]; ++#endif ++ struct ieee80211_supported_band *band_2GHz = ++ wiphy->bands[NL80211_BAND_2GHZ]; ++ ++ int i; ++ int nss = rwnx_hw->mod_params->nss; ++ int mcs_map; ++ int mcs_map_max; ++ int bw_max; ++ ++ if (!rwnx_hw->mod_params->vht_on) { ++ return; ++ } ++ ++ if (rwnx_hw->sdiodev->chipid <= PRODUCT_ID_AIC8800D80) ++ nss = 1; ++ ++ rwnx_hw->vht_cap_2G.vht_supported = true; ++ if (rwnx_hw->mod_params->sgi80) ++ rwnx_hw->vht_cap_2G.cap |= IEEE80211_VHT_CAP_SHORT_GI_80; ++ if (rwnx_hw->mod_params->stbc_on) ++ rwnx_hw->vht_cap_2G.cap |= IEEE80211_VHT_CAP_RXSTBC_1; ++ if (rwnx_hw->mod_params->ldpc_on) ++ rwnx_hw->vht_cap_2G.cap |= IEEE80211_VHT_CAP_RXLDPC; ++ if (rwnx_hw->mod_params->bfmee) { ++ rwnx_hw->vht_cap_2G.cap |= ++ IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) ++ rwnx_hw->vht_cap_2G.cap |= ++ 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT; ++#else ++ rwnx_hw->vht_cap_2G.cap |= 3 << 13; ++#endif ++ } ++ if (nss > 1) ++ rwnx_hw->vht_cap_2G.cap |= IEEE80211_VHT_CAP_TXSTBC; ++ ++ // Update the AMSDU max RX size (not shifted as located at offset 0 of the VHT cap) ++ rwnx_hw->vht_cap_2G.cap |= rwnx_hw->mod_params->amsdu_rx_max; ++ ++ if (rwnx_hw->mod_params->bfmer) { ++ rwnx_hw->vht_cap_2G.cap |= ++ IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE; ++ /* Set number of sounding dimensions */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) ++ rwnx_hw->vht_cap_2G.cap |= ++ (nss - 1) ++ << IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT; ++#else ++ rwnx_hw->vht_cap_2G.cap |= (nss - 1) << 16; ++#endif ++ } ++ if (rwnx_hw->mod_params->murx) ++ rwnx_hw->vht_cap_2G.cap |= ++ IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; ++ if (rwnx_hw->mod_params->mutx) ++ rwnx_hw->vht_cap_2G.cap |= ++ IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE; ++ ++ /* ++ * MCS map: ++ * This capabilities are filled according to the mcs_map module parameter. ++ * However currently we have some limitations due to FPGA clock constraints ++ * that prevent always using the range of MCS that is defined by the ++ * parameter: ++ * - in RX, 2SS, we support up to MCS7 ++ * - in TX, 2SS, we support up to MCS8 ++ */ ++ // Get max supported BW ++ if (rwnx_hw->mod_params->use_80) ++ bw_max = PHY_CHNL_BW_80; ++ else if (rwnx_hw->mod_params->use_2040) ++ bw_max = PHY_CHNL_BW_40; ++ else ++ bw_max = PHY_CHNL_BW_20; ++ ++ // Check if MCS map should be limited to MCS0_8 due to the standard. Indeed in BW20, ++ // MCS9 is not supported in 1 and 2 SS ++ if (rwnx_hw->mod_params->use_2040) ++ mcs_map_max = IEEE80211_VHT_MCS_SUPPORT_0_9; ++ else ++ mcs_map_max = IEEE80211_VHT_MCS_SUPPORT_0_8; ++ ++ mcs_map = min_t(int, rwnx_hw->mod_params->mcs_map, mcs_map_max); ++ rwnx_hw->vht_cap_2G.vht_mcs.rx_mcs_map = cpu_to_le16(0); ++ for (i = 0; i < nss; i++) { ++ rwnx_hw->vht_cap_2G.vht_mcs.rx_mcs_map |= ++ cpu_to_le16(mcs_map << (i * 2)); ++ rwnx_hw->vht_cap_2G.vht_mcs.rx_highest = ++ MAX_VHT_RATE(mcs_map, nss, bw_max); ++ //mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_7; ++ } ++ for (; i < 8; i++) { ++ rwnx_hw->vht_cap_2G.vht_mcs.rx_mcs_map |= ++ cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2)); ++ } ++ ++ mcs_map = min_t(int, rwnx_hw->mod_params->mcs_map, mcs_map_max); ++ rwnx_hw->vht_cap_2G.vht_mcs.tx_mcs_map = cpu_to_le16(0); ++ for (i = 0; i < nss; i++) { ++ rwnx_hw->vht_cap_2G.vht_mcs.tx_mcs_map |= ++ cpu_to_le16(mcs_map << (i * 2)); ++ rwnx_hw->vht_cap_2G.vht_mcs.tx_highest = ++ MAX_VHT_RATE(mcs_map, nss, bw_max); ++ //mcs_map = min_t(int, rwnx_hw->mod_params->mcs_map, ++ // IEEE80211_VHT_MCS_SUPPORT_0_8); ++ } ++ for (; i < 8; i++) { ++ rwnx_hw->vht_cap_2G.vht_mcs.tx_mcs_map |= ++ cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2)); ++ } ++ ++ if (!rwnx_hw->mod_params->use_80) { ++#ifdef CONFIG_VENDOR_RWNX_VHT_NO80 ++ rwnx_hw->vht_cap_2G.cap |= IEEE80211_VHT_CAP_NOT_SUP_WIDTH_80; ++#endif //CONFIG_VENDOR_RWNX_VHT_NO80 ++ rwnx_hw->vht_cap_2G.cap &= ~IEEE80211_VHT_CAP_SHORT_GI_80; ++ } ++ ++ rwnx_hw->vht_cap_2G.cap |= ++ IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; ++ printk("%s, vht_capa_info=0x%x\n", __func__, rwnx_hw->vht_cap_2G.cap); ++#ifdef USE_5G ++ if (rwnx_hw->band_5g_support) { ++ rwnx_hw->vht_cap_5G.vht_supported = true; ++ if (rwnx_hw->mod_params->sgi80) ++ rwnx_hw->vht_cap_5G.cap |= ++ IEEE80211_VHT_CAP_SHORT_GI_80; ++ if (rwnx_hw->mod_params->stbc_on) ++ rwnx_hw->vht_cap_5G.cap |= IEEE80211_VHT_CAP_RXSTBC_1; ++ if (rwnx_hw->mod_params->ldpc_on) ++ rwnx_hw->vht_cap_5G.cap |= IEEE80211_VHT_CAP_RXLDPC; ++ if (rwnx_hw->mod_params->bfmee) { ++ rwnx_hw->vht_cap_5G.cap |= ++ IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) ++ rwnx_hw->vht_cap_5G.cap |= ++ 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT; ++#else ++ rwnx_hw->vht_cap_5G.cap |= 3 << 13; ++#endif ++ } ++ if (nss > 1) ++ rwnx_hw->vht_cap_5G.cap |= IEEE80211_VHT_CAP_TXSTBC; ++ ++ // Update the AMSDU max RX size (not shifted as located at offset 0 of the VHT cap) ++ rwnx_hw->vht_cap_5G.cap |= rwnx_hw->mod_params->amsdu_rx_max; ++ ++ if (rwnx_hw->mod_params->bfmer) { ++ rwnx_hw->vht_cap_5G.cap |= ++ IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE; ++/* Set number of sounding dimensions */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) ++ rwnx_hw->vht_cap_5G.cap |= ++ (nss - 1) ++ << IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT; ++#else ++ rwnx_hw->vht_cap_5G.cap |= (nss - 1) << 16; ++#endif ++ } ++ if (rwnx_hw->mod_params->murx) ++ rwnx_hw->vht_cap_5G.cap |= ++ IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; ++ if (rwnx_hw->mod_params->mutx) ++ rwnx_hw->vht_cap_5G.cap |= ++ IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE; ++ ++ /* ++ * MCS map: ++ * This capabilities are filled according to the mcs_map module parameter. ++ * However currently we have some limitations due to FPGA clock constraints ++ * that prevent always using the range of MCS that is defined by the ++ * parameter: ++ * - in RX, 2SS, we support up to MCS7 ++ * - in TX, 2SS, we support up to MCS8 ++ */ ++ // Get max supported BW ++ if (rwnx_hw->mod_params->use_80) ++ bw_max = PHY_CHNL_BW_80; ++ else if (rwnx_hw->mod_params->use_2040) ++ bw_max = PHY_CHNL_BW_40; ++ else ++ bw_max = PHY_CHNL_BW_20; ++ ++ // Check if MCS map should be limited to MCS0_8 due to the standard. Indeed in BW20, ++ // MCS9 is not supported in 1 and 2 SS ++ if (rwnx_hw->mod_params->use_2040) ++ mcs_map_max = IEEE80211_VHT_MCS_SUPPORT_0_9; ++ else ++ mcs_map_max = IEEE80211_VHT_MCS_SUPPORT_0_8; ++ ++ mcs_map = min_t(int, rwnx_hw->mod_params->mcs_map, mcs_map_max); ++ rwnx_hw->vht_cap_5G.vht_mcs.rx_mcs_map = cpu_to_le16(0); ++ for (i = 0; i < nss; i++) { ++ rwnx_hw->vht_cap_5G.vht_mcs.rx_mcs_map |= ++ cpu_to_le16(mcs_map << (i * 2)); ++ rwnx_hw->vht_cap_5G.vht_mcs.rx_highest = ++ MAX_VHT_RATE(mcs_map, nss, bw_max); ++ //mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_7; ++ } ++ for (; i < 8; i++) { ++ rwnx_hw->vht_cap_5G.vht_mcs.rx_mcs_map |= cpu_to_le16( ++ IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2)); ++ } ++ ++ mcs_map = min_t(int, rwnx_hw->mod_params->mcs_map, mcs_map_max); ++ rwnx_hw->vht_cap_5G.vht_mcs.tx_mcs_map = cpu_to_le16(0); ++ for (i = 0; i < nss; i++) { ++ rwnx_hw->vht_cap_5G.vht_mcs.tx_mcs_map |= ++ cpu_to_le16(mcs_map << (i * 2)); ++ rwnx_hw->vht_cap_5G.vht_mcs.tx_highest = ++ MAX_VHT_RATE(mcs_map, nss, bw_max); ++ //mcs_map = min_t(int, rwnx_hw->mod_params->mcs_map, ++ // IEEE80211_VHT_MCS_SUPPORT_0_8); ++ } ++ for (; i < 8; i++) { ++ rwnx_hw->vht_cap_5G.vht_mcs.tx_mcs_map |= cpu_to_le16( ++ IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2)); ++ } ++ ++ if (!rwnx_hw->mod_params->use_80) { ++#ifdef CONFIG_VENDOR_RWNX_VHT_NO80 ++ rwnx_hw->vht_cap_5G.cap |= ++ IEEE80211_VHT_CAP_NOT_SUP_WIDTH_80; ++#endif //CONFIG_VENDOR_RWNX_VHT_NO80 ++ rwnx_hw->vht_cap_5G.cap &= ++ ~IEEE80211_VHT_CAP_SHORT_GI_80; ++ } ++ ++ rwnx_hw->vht_cap_5G.cap |= ++ IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; ++ } ++#endif //USE_5G ++ return; ++#else ++ struct ieee80211_supported_band *band_5GHz = ++ wiphy->bands[NL80211_BAND_5GHZ]; ++ struct ieee80211_supported_band *band_2GHz = ++ wiphy->bands[NL80211_BAND_2GHZ]; ++ ++ int i; ++ int nss = rwnx_hw->mod_params->nss; ++ int mcs_map; ++ int mcs_map_max; ++ int bw_max; ++#endif //CONFIG_VHT_FOR_OLD_KERNEL ++ ++ if (!rwnx_hw->mod_params->vht_on) { ++ return; ++ } ++ ++ if (rwnx_hw->sdiodev->chipid <= PRODUCT_ID_AIC8800D80) ++ nss = 1; ++ ++ band_2GHz->vht_cap.vht_supported = true; ++ if (rwnx_hw->mod_params->sgi80) ++ band_2GHz->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80; ++ if (rwnx_hw->mod_params->stbc_on) ++ band_2GHz->vht_cap.cap |= IEEE80211_VHT_CAP_RXSTBC_1; ++ if (rwnx_hw->mod_params->ldpc_on) ++ band_2GHz->vht_cap.cap |= IEEE80211_VHT_CAP_RXLDPC; ++ if (rwnx_hw->mod_params->bfmee) { ++ band_2GHz->vht_cap.cap |= ++ IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) ++ band_2GHz->vht_cap.cap |= ++ 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT; ++#else ++ band_2GHz->vht_cap.cap |= 3 << 13; ++#endif ++ } ++ if (nss > 1) ++ band_2GHz->vht_cap.cap |= IEEE80211_VHT_CAP_TXSTBC; ++ ++ // Update the AMSDU max RX size (not shifted as located at offset 0 of the VHT cap) ++ band_2GHz->vht_cap.cap |= rwnx_hw->mod_params->amsdu_rx_max; ++ ++ if (rwnx_hw->mod_params->bfmer) { ++ band_2GHz->vht_cap.cap |= ++ IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE; ++ /* Set number of sounding dimensions */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) ++ band_2GHz->vht_cap.cap |= ++ (nss - 1) ++ << IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT; ++#else ++ band_2GHz->vht_cap.cap |= (nss - 1) << 16; ++#endif ++ } ++ if (rwnx_hw->mod_params->murx) ++ band_2GHz->vht_cap.cap |= ++ IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; ++ if (rwnx_hw->mod_params->mutx) ++ band_2GHz->vht_cap.cap |= ++ IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE; ++ ++ /* ++ * MCS map: ++ * This capabilities are filled according to the mcs_map module parameter. ++ * However currently we have some limitations due to FPGA clock constraints ++ * that prevent always using the range of MCS that is defined by the ++ * parameter: ++ * - in RX, 2SS, we support up to MCS7 ++ * - in TX, 2SS, we support up to MCS8 ++ */ ++ // Get max supported BW ++ if (rwnx_hw->mod_params->use_80) ++ bw_max = PHY_CHNL_BW_80; ++ else if (rwnx_hw->mod_params->use_2040) ++ bw_max = PHY_CHNL_BW_40; ++ else ++ bw_max = PHY_CHNL_BW_20; ++ ++ // Check if MCS map should be limited to MCS0_8 due to the standard. Indeed in BW20, ++ // MCS9 is not supported in 1 and 2 SS ++ if (rwnx_hw->mod_params->use_2040) ++ mcs_map_max = IEEE80211_VHT_MCS_SUPPORT_0_9; ++ else ++ mcs_map_max = IEEE80211_VHT_MCS_SUPPORT_0_8; ++ ++ mcs_map = min_t(int, rwnx_hw->mod_params->mcs_map, mcs_map_max); ++ band_2GHz->vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(0); ++ for (i = 0; i < nss; i++) { ++ band_2GHz->vht_cap.vht_mcs.rx_mcs_map |= ++ cpu_to_le16(mcs_map << (i * 2)); ++ band_2GHz->vht_cap.vht_mcs.rx_highest = ++ MAX_VHT_RATE(mcs_map, nss, bw_max); ++ //mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_7; ++ } ++ for (; i < 8; i++) { ++ band_2GHz->vht_cap.vht_mcs.rx_mcs_map |= ++ cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2)); ++ } ++ ++ mcs_map = min_t(int, rwnx_hw->mod_params->mcs_map, mcs_map_max); ++ band_2GHz->vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(0); ++ for (i = 0; i < nss; i++) { ++ band_2GHz->vht_cap.vht_mcs.tx_mcs_map |= ++ cpu_to_le16(mcs_map << (i * 2)); ++ band_2GHz->vht_cap.vht_mcs.tx_highest = ++ MAX_VHT_RATE(mcs_map, nss, bw_max); ++ //mcs_map = min_t(int, rwnx_hw->mod_params->mcs_map, ++ // IEEE80211_VHT_MCS_SUPPORT_0_8); ++ } ++ for (; i < 8; i++) { ++ band_2GHz->vht_cap.vht_mcs.tx_mcs_map |= ++ cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2)); ++ } ++ ++ if (!rwnx_hw->mod_params->use_80) { ++#ifdef CONFIG_VENDOR_RWNX_VHT_NO80 ++ band_2GHz->vht_cap.cap |= IEEE80211_VHT_CAP_NOT_SUP_WIDTH_80; ++#endif ++ band_2GHz->vht_cap.cap &= ~IEEE80211_VHT_CAP_SHORT_GI_80; ++ } ++ ++ if (rwnx_hw->band_5g_support) { ++ band_5GHz->vht_cap.vht_supported = true; ++ if (rwnx_hw->mod_params->sgi80) ++ band_5GHz->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80; ++ if (rwnx_hw->mod_params->stbc_on) ++ band_5GHz->vht_cap.cap |= IEEE80211_VHT_CAP_RXSTBC_1; ++ if (rwnx_hw->mod_params->ldpc_on) ++ band_5GHz->vht_cap.cap |= IEEE80211_VHT_CAP_RXLDPC; ++ if (rwnx_hw->mod_params->bfmee) { ++ band_5GHz->vht_cap.cap |= ++ IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) ++ band_5GHz->vht_cap.cap |= ++ 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT; ++#else ++ band_5GHz->vht_cap.cap |= 3 << 13; ++#endif ++ } ++ if (nss > 1) ++ band_5GHz->vht_cap.cap |= IEEE80211_VHT_CAP_TXSTBC; ++ ++ // Update the AMSDU max RX size (not shifted as located at offset 0 of the VHT cap) ++ band_5GHz->vht_cap.cap |= rwnx_hw->mod_params->amsdu_rx_max; ++ ++ if (rwnx_hw->mod_params->bfmer) { ++ band_5GHz->vht_cap.cap |= ++ IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE; ++/* Set number of sounding dimensions */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) ++ band_5GHz->vht_cap.cap |= ++ (nss - 1) ++ << IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT; ++#else ++ band_5GHz->vht_cap.cap |= (nss - 1) << 16; ++#endif ++ } ++ if (rwnx_hw->mod_params->murx) ++ band_5GHz->vht_cap.cap |= ++ IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; ++ if (rwnx_hw->mod_params->mutx) ++ band_5GHz->vht_cap.cap |= ++ IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE; ++ ++ /* ++ * MCS map: ++ * This capabilities are filled according to the mcs_map module parameter. ++ * However currently we have some limitations due to FPGA clock constraints ++ * that prevent always using the range of MCS that is defined by the ++ * parameter: ++ * - in RX, 2SS, we support up to MCS7 ++ * - in TX, 2SS, we support up to MCS8 ++ */ ++ // Get max supported BW ++ if (rwnx_hw->mod_params->use_80) ++ bw_max = PHY_CHNL_BW_80; ++ else if (rwnx_hw->mod_params->use_2040) ++ bw_max = PHY_CHNL_BW_40; ++ else ++ bw_max = PHY_CHNL_BW_20; ++ ++ // Check if MCS map should be limited to MCS0_8 due to the standard. Indeed in BW20, ++ // MCS9 is not supported in 1 and 2 SS ++ if (rwnx_hw->mod_params->use_2040) ++ mcs_map_max = IEEE80211_VHT_MCS_SUPPORT_0_9; ++ else ++ mcs_map_max = IEEE80211_VHT_MCS_SUPPORT_0_8; ++ ++ mcs_map = min_t(int, rwnx_hw->mod_params->mcs_map, mcs_map_max); ++ band_5GHz->vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(0); ++ for (i = 0; i < nss; i++) { ++ band_5GHz->vht_cap.vht_mcs.rx_mcs_map |= ++ cpu_to_le16(mcs_map << (i * 2)); ++ band_5GHz->vht_cap.vht_mcs.rx_highest = ++ MAX_VHT_RATE(mcs_map, nss, bw_max); ++ //mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_7; ++ } ++ for (; i < 8; i++) { ++ band_5GHz->vht_cap.vht_mcs.rx_mcs_map |= cpu_to_le16( ++ IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2)); ++ } ++ ++ mcs_map = min_t(int, rwnx_hw->mod_params->mcs_map, mcs_map_max); ++ band_5GHz->vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(0); ++ for (i = 0; i < nss; i++) { ++ band_5GHz->vht_cap.vht_mcs.tx_mcs_map |= ++ cpu_to_le16(mcs_map << (i * 2)); ++ band_5GHz->vht_cap.vht_mcs.tx_highest = ++ MAX_VHT_RATE(mcs_map, nss, bw_max); ++ //mcs_map = min_t(int, rwnx_hw->mod_params->mcs_map, ++ // IEEE80211_VHT_MCS_SUPPORT_0_8); ++ } ++ for (; i < 8; i++) { ++ band_5GHz->vht_cap.vht_mcs.tx_mcs_map |= cpu_to_le16( ++ IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2)); ++ } ++ ++ if (!rwnx_hw->mod_params->use_80) { ++#ifdef CONFIG_VENDOR_RWNX_VHT_NO80 ++ band_5GHz->vht_cap.cap |= ++ IEEE80211_VHT_CAP_NOT_SUP_WIDTH_80; ++#endif ++ band_5GHz->vht_cap.cap &= ++ ~IEEE80211_VHT_CAP_SHORT_GI_80; ++ } ++ } ++} ++ ++static void rwnx_set_ht_capa(struct rwnx_hw *rwnx_hw, struct wiphy *wiphy) ++{ ++ struct ieee80211_supported_band *band_5GHz = ++ wiphy->bands[NL80211_BAND_5GHZ]; ++ struct ieee80211_supported_band *band_2GHz = ++ wiphy->bands[NL80211_BAND_2GHZ]; ++ int i; ++ int nss = rwnx_hw->mod_params->nss; ++ ++ if (!rwnx_hw->mod_params->ht_on) { ++ band_2GHz->ht_cap.ht_supported = false; ++ if (rwnx_hw->band_5g_support) ++ band_5GHz->ht_cap.ht_supported = false; ++ return; ++ } ++ ++ if (rwnx_hw->sdiodev->chipid <= PRODUCT_ID_AIC8800D80) ++ nss = 1; ++ ++ if (rwnx_hw->mod_params->stbc_on) ++ band_2GHz->ht_cap.cap |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT; ++ if (rwnx_hw->mod_params->ldpc_on) ++ band_2GHz->ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; ++ if (rwnx_hw->mod_params->use_2040) { ++ band_2GHz->ht_cap.mcs.rx_mask[4] = 0x1; /* MCS32 */ ++ band_2GHz->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; ++ band_2GHz->ht_cap.mcs.rx_highest = cpu_to_le16(135 * nss); ++ } else { ++ band_2GHz->ht_cap.mcs.rx_highest = cpu_to_le16(65 * nss); ++ } ++ if (nss > 1) ++ band_2GHz->ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC; ++ ++ // Update the AMSDU max RX size ++ if (rwnx_hw->mod_params->amsdu_rx_max) ++ band_2GHz->ht_cap.cap |= IEEE80211_HT_CAP_MAX_AMSDU; ++ ++ if (rwnx_hw->mod_params->sgi) { ++ band_2GHz->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20; ++ if (rwnx_hw->mod_params->use_2040) { ++ band_2GHz->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; ++ band_2GHz->ht_cap.mcs.rx_highest = ++ cpu_to_le16(150 * nss); ++ } else ++ band_2GHz->ht_cap.mcs.rx_highest = ++ cpu_to_le16(72 * nss); ++ } ++ if (rwnx_hw->mod_params->gf_rx_on) ++ band_2GHz->ht_cap.cap |= IEEE80211_HT_CAP_GRN_FLD; ++ ++ for (i = 0; i < nss; i++) { ++ band_2GHz->ht_cap.mcs.rx_mask[i] = 0xFF; ++ } ++ ++ if (rwnx_hw->band_5g_support) ++ band_5GHz->ht_cap = band_2GHz->ht_cap; ++} ++ ++#ifdef CONFIG_HE_FOR_OLD_KERNEL ++extern struct ieee80211_sband_iftype_data rwnx_he_capa; ++#endif ++static void rwnx_set_he_capa(struct rwnx_hw *rwnx_hw, struct wiphy *wiphy) ++{ ++#ifdef CONFIG_HE_FOR_OLD_KERNEL ++ struct ieee80211_sta_he_cap *he_cap; ++ int i; ++ int nss = rwnx_hw->mod_params->nss; ++ int mcs_map; ++ ++ if (rwnx_hw->sdiodev->chipid <= PRODUCT_ID_AIC8800D80) ++ nss = 1; ++ ++ he_cap = (struct ieee80211_sta_he_cap *)&rwnx_he_capa.he_cap; ++ he_cap->has_he = true; ++ he_cap->he_cap_elem.mac_cap_info[2] |= IEEE80211_HE_MAC_CAP2_ALL_ACK; ++ if (rwnx_hw->mod_params->use_2040) { ++ he_cap->he_cap_elem.phy_cap_info[0] |= ++ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G; ++ he_cap->ppe_thres[0] |= 0x10; ++ } ++ if (rwnx_hw->mod_params->use_80) { ++ he_cap->ppe_thres[0] |= 0x20; ++ he_cap->ppe_thres[2] |= 0xc0; ++ he_cap->ppe_thres[3] |= 0x01; ++ } ++ if (nss == 2) { ++ he_cap->ppe_thres[0] |= 0x01; ++ he_cap->ppe_thres[3] |= 0x70; ++ he_cap->ppe_thres[4] |= 0x1c; ++ he_cap->ppe_thres[5] |= 0x07; ++ } ++ //if (rwnx_hw->mod_params->use_80) ++ { ++ he_cap->he_cap_elem.phy_cap_info[0] |= ++ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G; ++ } ++ if (rwnx_hw->mod_params->ldpc_on) { ++ he_cap->he_cap_elem.phy_cap_info[1] |= ++ IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD; ++ } else { ++ // If no LDPC is supported, we have to limit to MCS0_9, as LDPC is mandatory ++ // for MCS 10 and 11 ++ rwnx_hw->mod_params->he_mcs_map = ++ min_t(int, rwnx_hw->mod_params->mcs_map, ++ IEEE80211_HE_MCS_SUPPORT_0_9); ++ } ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0) ++ he_cap->he_cap_elem.phy_cap_info[1] |= ++ IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US | ++ IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS; ++ ++ he_cap->he_cap_elem.phy_cap_info[2] |= ++ IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS | ++ IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | ++ IEEE80211_HE_PHY_CAP2_DOPPLER_RX; ++#else ++ he_cap->he_cap_elem.phy_cap_info[1] |= ++ IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US; ++ he_cap->he_cap_elem.phy_cap_info[2] |= ++ IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | ++ IEEE80211_HE_PHY_CAP2_DOPPLER_RX; ++#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; ++ 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; ++ 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] |= ++ IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4; ++ } ++ he_cap->he_cap_elem.phy_cap_info[5] |= ++ IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK | ++ IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK; ++ 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; ++ //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; ++ he_cap->he_cap_elem.phy_cap_info[9] |= ++ IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | ++ IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB; ++ if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) ++ mcs_map = rwnx_hw->mod_params->he_mcs_map; ++ else if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DW) ++ mcs_map = min_t(int, rwnx_hw->mod_params->he_mcs_map, ++ IEEE80211_HE_MCS_SUPPORT_0_9); ++ memset(&he_cap->he_mcs_nss_supp, 0, sizeof(he_cap->he_mcs_nss_supp)); ++ for (i = 0; i < nss; i++) { ++ __le16 unsup_for_ss = ++ cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2)); ++ he_cap->he_mcs_nss_supp.rx_mcs_80 |= ++ cpu_to_le16(mcs_map << (i * 2)); ++ he_cap->he_mcs_nss_supp.rx_mcs_160 |= unsup_for_ss; ++ he_cap->he_mcs_nss_supp.rx_mcs_80p80 |= unsup_for_ss; ++ //mcs_map = IEEE80211_HE_MCS_SUPPORT_0_7; ++ } ++ for (; i < 8; i++) { ++ __le16 unsup_for_ss = ++ cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2)); ++ he_cap->he_mcs_nss_supp.rx_mcs_80 |= unsup_for_ss; ++ he_cap->he_mcs_nss_supp.rx_mcs_160 |= unsup_for_ss; ++ he_cap->he_mcs_nss_supp.rx_mcs_80p80 |= unsup_for_ss; ++ } ++ mcs_map = rwnx_hw->mod_params->he_mcs_map; ++ for (i = 0; i < nss; i++) { ++ __le16 unsup_for_ss = ++ cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2)); ++ he_cap->he_mcs_nss_supp.tx_mcs_80 |= ++ cpu_to_le16(mcs_map << (i * 2)); ++ he_cap->he_mcs_nss_supp.tx_mcs_160 |= unsup_for_ss; ++ he_cap->he_mcs_nss_supp.tx_mcs_80p80 |= unsup_for_ss; ++ //mcs_map = min_t(int, rwnx_hw->mod_params->he_mcs_map, ++ // IEEE80211_HE_MCS_SUPPORT_0_7); ++ } ++ for (; i < 8; i++) { ++ __le16 unsup_for_ss = ++ cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2)); ++ he_cap->he_mcs_nss_supp.tx_mcs_80 |= unsup_for_ss; ++ he_cap->he_mcs_nss_supp.tx_mcs_160 |= unsup_for_ss; ++ he_cap->he_mcs_nss_supp.tx_mcs_80p80 |= unsup_for_ss; ++ } ++ ++ return; ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) ++ struct ieee80211_supported_band *band_5GHz = ++ wiphy->bands[NL80211_BAND_5GHZ]; ++ struct ieee80211_supported_band *band_2GHz = ++ wiphy->bands[NL80211_BAND_2GHZ]; ++ int i; ++ int nss = rwnx_hw->mod_params->nss; ++ struct ieee80211_sta_he_cap *he_cap; ++ int mcs_map; ++ ++ if (rwnx_hw->sdiodev->chipid <= PRODUCT_ID_AIC8800D80) ++ nss = 1; ++ ++ if (!rwnx_hw->mod_params->he_on) { ++ band_2GHz->iftype_data = NULL; ++ band_2GHz->n_iftype_data = 0; ++ if (rwnx_hw->band_5g_support) { ++ band_5GHz->iftype_data = NULL; ++ band_5GHz->n_iftype_data = 0; ++ } ++ return; ++ } ++ he_cap = (struct ieee80211_sta_he_cap *)&band_2GHz->iftype_data->he_cap; ++ he_cap->has_he = true; ++ he_cap->he_cap_elem.mac_cap_info[2] |= IEEE80211_HE_MAC_CAP2_ALL_ACK; ++ if (rwnx_hw->mod_params->use_2040) { ++ he_cap->he_cap_elem.phy_cap_info[0] |= ++ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G; ++ he_cap->ppe_thres[0] |= 0x10; ++ } ++ if (rwnx_hw->mod_params->use_80) { ++ he_cap->ppe_thres[0] |= 0x20; ++ he_cap->ppe_thres[2] |= 0xc0; ++ he_cap->ppe_thres[3] |= 0x01; ++ } ++ if (nss == 2) { ++ he_cap->ppe_thres[0] |= 0x01; ++ he_cap->ppe_thres[3] |= 0x70; ++ he_cap->ppe_thres[4] |= 0x1c; ++ he_cap->ppe_thres[5] |= 0x07; ++ } ++ //if (rwnx_hw->mod_params->use_80) ++ { ++ he_cap->he_cap_elem.phy_cap_info[0] |= ++ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G; ++ } ++ if (rwnx_hw->mod_params->ldpc_on) { ++ he_cap->he_cap_elem.phy_cap_info[1] |= ++ IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD; ++ } else { ++ // If no LDPC is supported, we have to limit to MCS0_9, as LDPC is mandatory ++ // for MCS 10 and 11 ++ rwnx_hw->mod_params->he_mcs_map = ++ min_t(int, rwnx_hw->mod_params->mcs_map, ++ IEEE80211_HE_MCS_SUPPORT_0_9); ++ } ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0) ++ he_cap->he_cap_elem.phy_cap_info[1] |= ++ IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US | ++ IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS; ++ ++ he_cap->he_cap_elem.phy_cap_info[2] |= ++ IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS | ++ IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | ++ IEEE80211_HE_PHY_CAP2_DOPPLER_RX; ++#else ++ he_cap->he_cap_elem.phy_cap_info[1] |= ++ IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US; ++ he_cap->he_cap_elem.phy_cap_info[2] |= ++ IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | ++ IEEE80211_HE_PHY_CAP2_DOPPLER_RX; ++#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] |= ++ IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4; ++ } ++ 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) ++ he_cap->he_cap_elem.phy_cap_info[9] |= ++ IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | ++ IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB; ++#endif ++ if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ mcs_map = rwnx_hw->mod_params->he_mcs_map; ++ } else if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ mcs_map = min_t(int, rwnx_hw->mod_params->he_mcs_map, ++ IEEE80211_HE_MCS_SUPPORT_0_9); ++ } ++ memset(&he_cap->he_mcs_nss_supp, 0, sizeof(he_cap->he_mcs_nss_supp)); ++ for (i = 0; i < nss; i++) { ++ __le16 unsup_for_ss = ++ cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2)); ++ he_cap->he_mcs_nss_supp.rx_mcs_80 |= ++ cpu_to_le16(mcs_map << (i * 2)); ++ he_cap->he_mcs_nss_supp.rx_mcs_160 |= unsup_for_ss; ++ he_cap->he_mcs_nss_supp.rx_mcs_80p80 |= unsup_for_ss; ++ //mcs_map = IEEE80211_HE_MCS_SUPPORT_0_7; ++ } ++ for (; i < 8; i++) { ++ __le16 unsup_for_ss = ++ cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2)); ++ he_cap->he_mcs_nss_supp.rx_mcs_80 |= unsup_for_ss; ++ he_cap->he_mcs_nss_supp.rx_mcs_160 |= unsup_for_ss; ++ he_cap->he_mcs_nss_supp.rx_mcs_80p80 |= unsup_for_ss; ++ } ++ mcs_map = rwnx_hw->mod_params->he_mcs_map; ++ for (i = 0; i < nss; i++) { ++ __le16 unsup_for_ss = ++ cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2)); ++ he_cap->he_mcs_nss_supp.tx_mcs_80 |= ++ cpu_to_le16(mcs_map << (i * 2)); ++ he_cap->he_mcs_nss_supp.tx_mcs_160 |= unsup_for_ss; ++ he_cap->he_mcs_nss_supp.tx_mcs_80p80 |= unsup_for_ss; ++ //mcs_map = min_t(int, rwnx_hw->mod_params->he_mcs_map, ++ // IEEE80211_HE_MCS_SUPPORT_0_7); ++ } ++ for (; i < 8; i++) { ++ __le16 unsup_for_ss = ++ cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2)); ++ he_cap->he_mcs_nss_supp.tx_mcs_80 |= unsup_for_ss; ++ he_cap->he_mcs_nss_supp.tx_mcs_160 |= unsup_for_ss; ++ he_cap->he_mcs_nss_supp.tx_mcs_80p80 |= unsup_for_ss; ++ } ++ ++ if (rwnx_hw->band_5g_support) { ++ he_cap = (struct ieee80211_sta_he_cap *)&band_5GHz->iftype_data ++ ->he_cap; ++ he_cap->has_he = true; ++ he_cap->he_cap_elem.mac_cap_info[2] |= ++ IEEE80211_HE_MAC_CAP2_ALL_ACK; ++ if (rwnx_hw->mod_params->use_2040) { ++ he_cap->he_cap_elem.phy_cap_info[0] |= ++ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G; ++ he_cap->ppe_thres[0] |= 0x10; ++ } ++ if (rwnx_hw->mod_params->use_80) { ++ he_cap->ppe_thres[0] |= 0x20; ++ he_cap->ppe_thres[2] |= 0xc0; ++ he_cap->ppe_thres[3] |= 0x01; ++ } ++ if (nss == 2) { ++ he_cap->ppe_thres[0] |= 0x01; ++ he_cap->ppe_thres[3] |= 0x70; ++ he_cap->ppe_thres[4] |= 0x1c; ++ he_cap->ppe_thres[5] |= 0x07; ++ } ++ //if (rwnx_hw->mod_params->use_80) ++ { ++ he_cap->he_cap_elem.phy_cap_info[0] |= ++ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G; ++ } ++ if (rwnx_hw->mod_params->ldpc_on) { ++ he_cap->he_cap_elem.phy_cap_info[1] |= ++ IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD; ++ } else { ++ // If no LDPC is supported, we have to limit to MCS0_9, as LDPC is mandatory ++ // for MCS 10 and 11 ++ rwnx_hw->mod_params->he_mcs_map = ++ min_t(int, rwnx_hw->mod_params->mcs_map, ++ IEEE80211_HE_MCS_SUPPORT_0_9); ++ } ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0) ++ he_cap->he_cap_elem.phy_cap_info[1] |= ++ IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US | ++ IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS; ++ he_cap->he_cap_elem.phy_cap_info[2] |= ++ IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS | ++ IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | ++ IEEE80211_HE_PHY_CAP2_DOPPLER_RX; ++#else ++ he_cap->he_cap_elem.phy_cap_info[1] |= ++ IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US; ++ he_cap->he_cap_elem.phy_cap_info[2] |= ++ IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | ++ IEEE80211_HE_PHY_CAP2_DOPPLER_RX; ++#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] |= ++ IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4; ++ } ++ 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) ++ he_cap->he_cap_elem.phy_cap_info[9] |= ++ IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | ++ IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB; ++#endif ++ if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) ++ mcs_map = rwnx_hw->mod_params->he_mcs_map; ++ else if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8801 || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DW) ++ mcs_map = min_t(int, rwnx_hw->mod_params->he_mcs_map, ++ IEEE80211_HE_MCS_SUPPORT_0_9); ++ memset(&he_cap->he_mcs_nss_supp, 0, ++ sizeof(he_cap->he_mcs_nss_supp)); ++ for (i = 0; i < nss; i++) { ++ __le16 unsup_for_ss = cpu_to_le16( ++ IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2)); ++ he_cap->he_mcs_nss_supp.rx_mcs_80 |= ++ cpu_to_le16(mcs_map << (i * 2)); ++ he_cap->he_mcs_nss_supp.rx_mcs_160 |= unsup_for_ss; ++ he_cap->he_mcs_nss_supp.rx_mcs_80p80 |= unsup_for_ss; ++ //mcs_map = IEEE80211_HE_MCS_SUPPORT_0_7; ++ } ++ for (; i < 8; i++) { ++ __le16 unsup_for_ss = cpu_to_le16( ++ IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2)); ++ he_cap->he_mcs_nss_supp.rx_mcs_80 |= unsup_for_ss; ++ he_cap->he_mcs_nss_supp.rx_mcs_160 |= unsup_for_ss; ++ he_cap->he_mcs_nss_supp.rx_mcs_80p80 |= unsup_for_ss; ++ } ++ mcs_map = rwnx_hw->mod_params->he_mcs_map; ++ for (i = 0; i < nss; i++) { ++ __le16 unsup_for_ss = cpu_to_le16( ++ IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2)); ++ he_cap->he_mcs_nss_supp.tx_mcs_80 |= ++ cpu_to_le16(mcs_map << (i * 2)); ++ he_cap->he_mcs_nss_supp.tx_mcs_160 |= unsup_for_ss; ++ he_cap->he_mcs_nss_supp.tx_mcs_80p80 |= unsup_for_ss; ++ //mcs_map = min_t(int, rwnx_hw->mod_params->he_mcs_map, ++ // IEEE80211_HE_MCS_SUPPORT_0_7); ++ } ++ for (; i < 8; i++) { ++ __le16 unsup_for_ss = cpu_to_le16( ++ IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2)); ++ he_cap->he_mcs_nss_supp.tx_mcs_80 |= unsup_for_ss; ++ he_cap->he_mcs_nss_supp.tx_mcs_160 |= unsup_for_ss; ++ he_cap->he_mcs_nss_supp.tx_mcs_80p80 |= unsup_for_ss; ++ } ++ } ++#endif ++} ++ ++static void rwnx_set_wiphy_params(struct rwnx_hw *rwnx_hw, struct wiphy *wiphy) ++{ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) ++ struct ieee80211_regdomain *regdomain; ++#endif ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ /* FULLMAC specific parameters */ ++ wiphy->flags |= WIPHY_FLAG_REPORTS_OBSS; ++ wiphy->max_scan_ssids = SCAN_SSID_MAX; ++ wiphy->max_scan_ie_len = SCANU_MAX_IE_LEN; ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++ if (rwnx_hw->mod_params->tdls) { ++ /* TDLS support */ ++ wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; ++#ifdef CONFIG_RWNX_FULLMAC ++ /* TDLS external setup support */ ++ wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP; ++#endif ++ } ++ ++ if (rwnx_hw->mod_params->ap_uapsd_on) ++ wiphy->flags |= WIPHY_FLAG_AP_UAPSD; ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ if (rwnx_hw->mod_params->ps_on) ++ wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; ++ else ++ wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; ++#endif ++ ++ if (rwnx_hw->mod_params->custregd) { ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && \ ++ (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) ++ // Apply custom regulatory. Note that for recent kernel versions we use instead the ++ // REGULATORY_WIPHY_SELF_MANAGED flag, along with the regulatory_set_wiphy_regd() ++ // function, that needs to be called after wiphy registration ++ memcpy(country_code, default_ccode, sizeof(default_ccode)); ++ regdomain = getRegdomainFromRwnxDB(wiphy, default_ccode); ++ printk(KERN_CRIT ++ "\n\n%s: CAUTION: USING PERMISSIVE CUSTOM REGULATORY RULES\n\n", ++ __func__); ++ wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; ++ wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF; ++ wiphy_apply_custom_regulatory(wiphy, regdomain); ++#elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) ++ memcpy(country_code, default_ccode, sizeof(default_ccode)); ++ regdomain = getRegdomainFromRwnxDB(wiphy, default_ccode); ++ printk(KERN_CRIT "%s: Registering custom regulatory\n", ++ __func__); ++ wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; ++ wiphy_apply_custom_regulatory(wiphy, regdomain); ++#endif ++ // Check if custom channel set shall be enabled. In such case only monitor mode is ++ // supported ++ if (rwnx_hw->mod_params->custchan) { ++ wiphy->interface_modes = BIT(NL80211_IFTYPE_MONITOR); ++ ++ // Enable "extra" channels ++ wiphy->bands[NL80211_BAND_2GHZ]->n_channels += 13; ++ //#ifdef USE_5G ++ if (rwnx_hw->band_5g_support) { ++ wiphy->bands[NL80211_BAND_5GHZ]->n_channels += ++ 59; ++ } ++ //#endif ++ } ++ } ++ ++#if 0 ++ if (rwnx_hw->mod_params->custregd) { ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && \ ++ (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) ++ // Apply custom regulatory. Note that for recent kernel versions we use instead the ++ // REGULATORY_WIPHY_SELF_MANAGED flag, along with the regulatory_set_wiphy_regd() ++ // function, that needs to be called after wiphy registration ++ printk(KERN_CRIT ++ "\n\n%s: CAUTION: USING PERMISSIVE CUSTOM REGULATORY RULES\n\n", ++ __func__); ++ wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; ++ wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF; ++ wiphy_apply_custom_regulatory(wiphy, &rwnx_regdom); ++#endif ++ // Check if custom channel set shall be enabled. In such case only monitor mode is ++ // supported ++ if (rwnx_hw->mod_params->custchan) { ++ wiphy->interface_modes = BIT(NL80211_IFTYPE_MONITOR); ++ ++ // Enable "extra" channels ++ wiphy->bands[NL80211_BAND_2GHZ]->n_channels += 13; ++ if (rwnx_hw->band_5g_support) ++ wiphy->bands[NL80211_BAND_5GHZ]->n_channels += 59; ++ } ++ } ++#endif ++} ++ ++#if 0 ++static void rwnx_set_rf_params(struct rwnx_hw *rwnx_hw, struct wiphy *wiphy) ++{ ++#ifndef CONFIG_RWNX_SDM ++ struct ieee80211_supported_band *band_5GHz = wiphy->bands[NL80211_BAND_5GHZ]; ++ struct ieee80211_supported_band *band_2GHz = wiphy->bands[NL80211_BAND_2GHZ]; ++ u32 mdm_phy_cfg = __MDM_PHYCFG_FROM_VERS(rwnx_hw->version_cfm.version_phy_1); ++ ++ /* ++ * Get configuration file depending on the RF ++ */ ++ if (mdm_phy_cfg == MDM_PHY_CONFIG_TRIDENT) { ++ struct rwnx_phy_conf_file phy_conf; ++ // Retrieve the Trident configuration ++ rwnx_parse_phy_configfile(rwnx_hw, RWNX_PHY_CONFIG_TRD_NAME, ++ &phy_conf, rwnx_hw->mod_params->phy_cfg); ++ memcpy(&rwnx_hw->phy.cfg, &phy_conf.trd, sizeof(phy_conf.trd)); ++ } else if (mdm_phy_cfg == MDM_PHY_CONFIG_ELMA) { ++ } else if (mdm_phy_cfg == MDM_PHY_CONFIG_KARST) { ++ struct rwnx_phy_conf_file phy_conf; ++ // We use the NSS parameter as is ++ // Retrieve the Karst configuration ++ rwnx_parse_phy_configfile(rwnx_hw, RWNX_PHY_CONFIG_KARST_NAME, ++ &phy_conf, rwnx_hw->mod_params->phy_cfg); ++ ++ memcpy(&rwnx_hw->phy.cfg, &phy_conf.karst, sizeof(phy_conf.karst)); ++ } else { ++ WARN_ON(1); ++ } ++ ++ /* ++ * adjust caps depending on the RF ++ */ ++ switch (mdm_phy_cfg) { ++ case MDM_PHY_CONFIG_TRIDENT: ++ { ++ wiphy_dbg(wiphy, "found Trident phy .. limit BW to 40MHz\n"); ++ rwnx_hw->phy.limit_bw = true; ++ if (rwnx_hw->band_5g_support) { ++#ifdef CONFIG_VENDOR_RWNX_VHT_NO80 ++ band_5GHz->vht_cap.cap |= IEEE80211_VHT_CAP_NOT_SUP_WIDTH_80; ++#endif ++ band_5GHz->vht_cap.cap &= ~(IEEE80211_VHT_CAP_SHORT_GI_80 | ++ IEEE80211_VHT_CAP_RXSTBC_MASK); ++ } ++ break; ++ } ++ case MDM_PHY_CONFIG_ELMA: ++ wiphy_dbg(wiphy, "found ELMA phy .. disabling 2.4GHz and greenfield rx\n"); ++ wiphy->bands[NL80211_BAND_2GHZ] = NULL; ++ band_2GHz->ht_cap.cap &= ~IEEE80211_HT_CAP_GRN_FLD; ++ if (rwnx_hw->band_5g_support) { ++ band_5GHz->ht_cap.cap &= ~IEEE80211_HT_CAP_GRN_FLD; ++ band_5GHz->vht_cap.cap &= ~IEEE80211_VHT_CAP_RXSTBC_MASK; ++ } ++ break; ++ case MDM_PHY_CONFIG_KARST: ++ { ++ wiphy_dbg(wiphy, "found KARST phy\n"); ++ break; ++ } ++ default: ++ WARN_ON(1); ++ break; ++ } ++#endif /* CONFIG_RWNX_SDM */ ++} ++#endif ++ ++int rwnx_handle_dynparams(struct rwnx_hw *rwnx_hw, struct wiphy *wiphy) ++{ ++#if 0 ++ /* Check compatibility between requested parameters and HW/SW features */ ++ int ret; ++ ++ ret = rwnx_check_fw_hw_feature(rwnx_hw, wiphy); ++ if (ret) ++ return ret; ++ ++ /* Allocate the RX buffers according to the maximum AMSDU RX size */ ++ ret = rwnx_ipc_rxbuf_init(rwnx_hw, ++ (4 * (rwnx_hw->mod_params->amsdu_rx_max + 1) + 1) * 1024); ++ if (ret) { ++ wiphy_err(wiphy, "Cannot allocate the RX buffers\n"); ++ return ret; ++ } ++#endif ++ ++ if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ rwnx_hw->mod_params->sgi80 = true; ++ rwnx_hw->mod_params->use_80 = true; ++ } ++ ++ if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ rwnx_hw->mod_params->use_80 = true; ++ } ++ ++ if (rwnx_hw->sdiodev->chipid != PRODUCT_ID_AIC8800D80 && ++ rwnx_hw->sdiodev->chipid != PRODUCT_ID_AIC8800D80X2 && ++ rwnx_hw->mod_params->he_mcs_map == IEEE80211_HE_MCS_SUPPORT_0_11) { ++ AICWFDBG(LOGINFO, "%s unsupport mcs11 change to mcs9", ++ __func__); ++ rwnx_hw->mod_params->he_mcs_map = IEEE80211_HE_MCS_SUPPORT_0_9; ++ } ++ ++ /* Set wiphy parameters */ ++ rwnx_set_wiphy_params(rwnx_hw, wiphy); ++ /* Set VHT capabilities */ ++ rwnx_set_vht_capa(rwnx_hw, wiphy); ++ /* Set HE capabilities */ ++ rwnx_set_he_capa(rwnx_hw, wiphy); ++ /* Set HT capabilities */ ++ rwnx_set_ht_capa(rwnx_hw, wiphy); ++ /* Set RF specific parameters (shall be done last as it might change some ++ capabilities previously set) */ ++#if 0 ++ rwnx_set_rf_params(rwnx_hw, wiphy); ++#endif ++ return 0; ++} ++ ++void rwnx_custregd(struct rwnx_hw *rwnx_hw, struct wiphy *wiphy) ++{ ++// For older kernel version, the custom regulatory is applied before the wiphy ++// registration (in rwnx_set_wiphy_params()), so nothing has to be done here ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) ++ if (!rwnx_hw->mod_params->custregd) ++ return; ++ ++ wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF; ++ wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED; ++ ++ rtnl_lock(); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0) ++ if (regulatory_set_wiphy_regd_sync( ++ wiphy, getRegdomainFromRwnxDB(wiphy, default_ccode))) { ++ wiphy_err(wiphy, "Failed to set custom regdomain\n"); ++ } ++#else ++ if (regulatory_set_wiphy_regd_sync_rtnl( ++ wiphy, getRegdomainFromRwnxDB(wiphy, default_ccode))) { ++ wiphy_err(wiphy, "Failed to set custom regdomain\n"); ++ } ++#endif ++ ++ else { ++ wiphy_err( ++ wiphy, ++ "\n" ++ "*******************************************************\n" ++ "** CAUTION: USING PERMISSIVE CUSTOM REGULATORY RULES **\n" ++ "*******************************************************\n"); ++ } ++ rtnl_unlock(); ++#endif ++} +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mod_params.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mod_params.h +new file mode 100755 +index 000000000..35652ab94 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mod_params.h +@@ -0,0 +1,75 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_mod_params.h ++ * ++ * @brief Declaration of module parameters ++ * ++ * Copyright (C) RivieraWaves 2012-2021 ++ * ++ ****************************************************************************** ++ */ ++ ++#ifndef _RWNX_MOD_PARAM_H_ ++#define _RWNX_MOD_PARAM_H_ ++ ++struct rwnx_mod_params { ++ bool ht_on; ++ bool vht_on; ++ bool he_on; ++ int mcs_map; ++ int he_mcs_map; ++ bool he_ul_on; ++ bool ldpc_on; ++ bool stbc_on; ++ bool gf_rx_on; ++ int phy_cfg; ++ int uapsd_timeout; ++ bool ap_uapsd_on; ++ bool sgi; ++ bool sgi80; ++ bool use_2040; ++ bool use_80; ++ bool custregd; ++ bool custchan; ++ int nss; ++ int amsdu_rx_max; ++ bool bfmee; ++ bool bfmer; ++ bool mesh; ++ bool murx; ++ bool mutx; ++ bool mutx_on; ++ unsigned int roc_dur_max; ++ int listen_itv; ++ bool listen_bcmc; ++ int lp_clk_ppm; ++ bool ps_on; ++ int tx_lft; ++ int amsdu_maxnb; ++ int uapsd_queues; ++ bool tdls; ++ bool uf; ++ bool auto_reply; ++ char *ftl; ++ bool dpsm; ++#ifdef CONFIG_RWNX_FULLMAC ++ bool ant_div; ++#endif /* CONFIG_RWNX_FULLMAC */ ++}; ++ ++extern struct rwnx_mod_params rwnx_mod_params; ++ ++struct rwnx_hw; ++struct wiphy; ++int rwnx_handle_dynparams(struct rwnx_hw *rwnx_hw, struct wiphy *wiphy); ++void rwnx_custregd(struct rwnx_hw *rwnx_hw, struct wiphy *wiphy); ++void rwnx_enable_wapi(struct rwnx_hw *rwnx_hw); ++void rwnx_enable_mfp(struct rwnx_hw *rwnx_hw); ++struct ieee80211_regdomain *getRegdomainFromRwnxDB(struct wiphy *wiphy, ++ char *alpha2); ++ ++struct ieee80211_regdomain *getRegdomainFromRwnxDBIndex(struct wiphy *wiphy, ++ int index); ++ ++#endif /* _RWNX_MOD_PARAM_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_rx.c b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_rx.c +new file mode 100755 +index 000000000..94abe2897 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_rx.c +@@ -0,0 +1,1670 @@ ++/** ++ **************************************************************************************** ++ * ++ * @file rwnx_msg_rx.c ++ * ++ * @brief RX function definitions ++ * ++ * Copyright (C) RivieraWaves 2012-2021 ++ * ++ **************************************************************************************** ++ */ ++#include ++#include "rwnx_defs.h" ++#include "rwnx_prof.h" ++#include "rwnx_tx.h" ++#ifdef CONFIG_RWNX_BFMER ++#include "rwnx_bfmer.h" ++#endif //(CONFIG_RWNX_BFMER) ++#ifdef CONFIG_RWNX_FULLMAC ++#include "rwnx_debugfs.h" ++#include "rwnx_msg_tx.h" ++#include "rwnx_tdls.h" ++#endif /* CONFIG_RWNX_FULLMAC */ ++#include "rwnx_events.h" ++#include "rwnx_compat.h" ++#include "aicwf_txrxif.h" ++#include "rwnx_msg_rx.h" ++#ifdef CONFIG_SDIO_BT ++#include "aic_btsdio.h" ++#endif ++void rwnx_cfg80211_unlink_bss(struct rwnx_hw *rwnx_hw, ++ struct rwnx_vif *rwnx_vif); ++ ++static int rwnx_freq_to_idx(struct rwnx_hw *rwnx_hw, int freq) ++{ ++ struct ieee80211_supported_band *sband = NULL; ++ int band, ch, idx = 0; ++ ++ for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; band++) { ++#ifdef CONFIG_RWNX_FULLMAC ++ sband = rwnx_hw->wiphy->bands[band]; ++#endif /* CONFIG_RWNX_FULLMAC */ ++ if (!sband) { ++ continue; ++ } ++ ++ for (ch = 0; ch < sband->n_channels; ch++, idx++) { ++ if (sband->channels[ch].center_freq == freq) { ++ goto exit; ++ } ++ } ++ } ++ ++ BUG_ON(1); ++ ++exit: ++ // Channel has been found, return the index ++ return idx; ++} ++ ++/*************************************************************************** ++ * Messages from MM task ++ **************************************************************************/ ++static inline int rwnx_rx_chan_pre_switch_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ struct rwnx_vif *rwnx_vif; ++ int chan_idx = ++ ((struct mm_channel_pre_switch_ind *)msg->param)->chan_index; ++ ++ 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) { ++ rwnx_txq_vif_stop(rwnx_vif, RWNX_TXQ_STOP_CHAN, ++ rwnx_hw); ++ } ++ } ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++ REG_SW_CLEAR_PROFILING_CHAN(rwnx_hw, SW_PROF_CHAN_CTXT_PSWTCH_BIT); ++ ++ return 0; ++} ++ ++static inline int rwnx_rx_chan_switch_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ struct rwnx_vif *rwnx_vif; ++ int chan_idx = ((struct mm_channel_switch_ind *)msg->param)->chan_index; ++ bool roc = ((struct mm_channel_switch_ind *)msg->param)->roc; ++ bool roc_tdls = ((struct mm_channel_switch_ind *)msg->param)->roc_tdls; ++ ++ REG_SW_SET_PROFILING_CHAN(rwnx_hw, SW_PROF_CHAN_CTXT_SWTCH_BIT); ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ if (roc_tdls) { ++ 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); ++ } ++ } ++ } 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; ++ /* Get VIF on which RoC has been started */ ++ //rwnx_vif = netdev_priv(roc_elem->wdev->netdev); ++ ++ /* For debug purpose (use ftrace kernel option) */ ++ //trace_switch_roc(rwnx_vif->vif_index); ++ ++ 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"); ++ } ++ // Enable traffic on OFF channel queue ++ rwnx_txq_offchan_start(rwnx_hw); ++ } ++ ++ tasklet_schedule(&rwnx_hw->task); ++ ++ rwnx_hw->cur_chanctx = chan_idx; ++ rwnx_radar_detection_enable_on_cur_channel(rwnx_hw); ++ ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++ REG_SW_CLEAR_PROFILING_CHAN(rwnx_hw, SW_PROF_CHAN_CTXT_SWTCH_BIT); ++ ++ return 0; ++} ++ ++static inline int rwnx_rx_tdls_chan_switch_cfm(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ return 0; ++} ++ ++static inline int rwnx_rx_tdls_chan_switch_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++#ifdef CONFIG_RWNX_FULLMAC ++ // Enable traffic on OFF channel queue ++ rwnx_txq_offchan_start(rwnx_hw); ++ ++ return 0; ++#endif ++} ++ ++static inline int rwnx_rx_tdls_chan_switch_base_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ struct rwnx_vif *rwnx_vif; ++ u8 vif_index = ++ ((struct tdls_chan_switch_base_ind *)msg->param)->vif_index; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ list_for_each_entry (rwnx_vif, &rwnx_hw->vifs, list) { ++ if (rwnx_vif->vif_index == vif_index) { ++ rwnx_vif->roc_tdls = false; ++ rwnx_txq_tdls_sta_stop(rwnx_vif, RWNX_TXQ_STOP_CHAN, ++ rwnx_hw); ++ } ++ } ++ return 0; ++#endif ++} ++ ++static inline int rwnx_rx_tdls_peer_ps_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ struct rwnx_vif *rwnx_vif; ++ u8 vif_index = ((struct tdls_peer_ps_ind *)msg->param)->vif_index; ++ bool ps_on = ((struct tdls_peer_ps_ind *)msg->param)->ps_on; ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ list_for_each_entry (rwnx_vif, &rwnx_hw->vifs, list) { ++ if (rwnx_vif->vif_index == vif_index) { ++ rwnx_vif->sta.tdls_sta->tdls.ps_on = ps_on; ++ // Update PS status for the TDLS station ++ rwnx_ps_bh_enable(rwnx_hw, rwnx_vif->sta.tdls_sta, ++ ps_on); ++ } ++ } ++ ++ return 0; ++#endif ++} ++ ++static inline int rwnx_rx_remain_on_channel_exp_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++#ifdef CONFIG_RWNX_FULLMAC ++ /* 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; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ 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) { ++ /* Inform the host that off-channel period has expired */ ++ cfg80211_remain_on_channel_expired( ++ roc_elem->wdev, (u64)(rwnx_hw->roc_cookie_cnt), ++ roc_elem->chan, GFP_ATOMIC); ++ } ++ ++ /* De-init offchannel TX queue */ ++ rwnx_txq_offchan_deinit(rwnx_vif); ++ ++ /* Increase the cookie counter cannot be zero */ ++ rwnx_hw->roc_cookie_cnt++; ++ ++ if (rwnx_hw->roc_cookie_cnt == 0) { ++ rwnx_hw->roc_cookie_cnt = 1; ++ } ++ ++ /* Free the allocated RoC element */ ++ kfree(roc_elem); ++ rwnx_hw->roc_elem = NULL; ++ ++#endif /* CONFIG_RWNX_FULLMAC */ ++ return 0; ++} ++ ++static inline int rwnx_rx_p2p_vif_ps_change_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ int vif_idx = ++ ((struct mm_p2p_vif_ps_change_ind *)msg->param)->vif_index; ++ 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); ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ vif_entry = rwnx_hw->vif_table[vif_idx]; ++ ++ if (vif_entry) { ++ goto found_vif; ++ } ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++ goto exit; ++ ++found_vif: ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ 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); ++ } ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++exit: ++ return 0; ++} ++ ++static inline int rwnx_rx_channel_survey_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ struct mm_channel_survey_ind *ind = ++ (struct mm_channel_survey_ind *)msg->param; ++ // Get the channel index ++ int idx = rwnx_freq_to_idx(rwnx_hw, ind->freq); ++ // Get the survey ++ struct rwnx_survey_info *rwnx_survey; ++ ++ if (idx > ARRAY_SIZE(rwnx_hw->survey)) ++ return 0; ++ ++ rwnx_survey = &rwnx_hw->survey[idx]; ++ ++ // Store the received parameters ++ rwnx_survey->chan_time_ms = ind->chan_time_ms; ++ rwnx_survey->chan_time_busy_ms = ind->chan_time_busy_ms; ++ rwnx_survey->noise_dbm = ind->noise_dbm; ++ rwnx_survey->filled = (SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY); ++ ++ if (ind->noise_dbm != 0) { ++ rwnx_survey->filled |= SURVEY_INFO_NOISE_DBM; ++ } ++ ++ return 0; ++} ++ ++static inline int rwnx_rx_p2p_noa_upd_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ return 0; ++} ++ ++static inline int rwnx_rx_rssi_status_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ struct mm_rssi_status_ind *ind = ++ (struct mm_rssi_status_ind *)msg->param; ++ int vif_idx = ind->vif_index; ++ bool rssi_status = ind->rssi_status; ++ ++ struct rwnx_vif *vif_entry; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ vif_entry = rwnx_hw->vif_table[vif_idx]; ++ if (vif_entry) { ++ cfg80211_cqm_rssi_notify( ++ vif_entry->ndev, ++ rssi_status ? NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW : ++ NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, ++ ind->rssi, GFP_ATOMIC); ++ } ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++ return 0; ++} ++ ++static inline int rwnx_rx_pktloss_notify_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++#ifdef CONFIG_RWNX_FULLMAC ++ struct mm_pktloss_ind *ind = (struct mm_pktloss_ind *)msg->param; ++ struct rwnx_vif *vif_entry; ++ int vif_idx = ind->vif_index; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ vif_entry = rwnx_hw->vif_table[vif_idx]; ++ if (vif_entry) { ++ cfg80211_cqm_pktloss_notify(vif_entry->ndev, ++ (const u8 *)ind->mac_addr.array, ++ ind->num_packets, GFP_ATOMIC); ++ } ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++ return 0; ++} ++ ++static inline int rwnx_radar_detect_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ struct radar_pulse_array_desc *pulses = ++ (struct radar_pulse_array_desc *)msg->param; ++ int i; ++ ++ //RWNX_DBG(RWNX_FN_ENTRY_STR); ++ //printk("%s\n", __func__); ++ ++ if (pulses->cnt == 0) { ++ printk("cnt error\n"); ++ return -1; ++ } ++ ++ if (rwnx_radar_detection_is_enable(&rwnx_hw->radar, pulses->idx)) { ++ 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++; ++ //printk("pulse=%x\n", pulses->pulse[i]); ++ } ++ ++ if (!work_pending(&rwnx_hw->radar.detection_work)) ++ schedule_work(&rwnx_hw->radar.detection_work); ++ } else ++ printk("not enable\n"); ++ ++ 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; ++} ++ ++#ifdef CONFIG_SDIO_BT ++static inline int rwnx_bt_recv_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ struct mm_bt_recv_ind *ind = (struct mm_bt_recv_ind *)msg->param; ++ ++ bt_sdio_recv(ind->bt_data, ind->data_len); ++ return 0; ++} ++#endif ++ ++static inline int rwnx_rx_csa_counter_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ struct mm_csa_counter_ind *ind = ++ (struct mm_csa_counter_ind *)msg->param; ++ struct rwnx_vif *vif; ++ bool found = false; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ // Look for VIF entry ++ list_for_each_entry (vif, &rwnx_hw->vifs, list) { ++ if (vif->vif_index == ind->vif_index) { ++ found = true; ++ break; ++ } ++ } ++ ++ if (found) { ++#ifdef CONFIG_RWNX_FULLMAC ++ if (vif->ap.csa) ++ vif->ap.csa->count = ind->csa_count; ++ else ++ netdev_err(vif->ndev, ++ "CSA counter update but no active CSA"); ++ ++#endif ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_RWNX_FULLMAC ++static inline int rwnx_rx_csa_finish_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ struct mm_csa_finish_ind *ind = (struct mm_csa_finish_ind *)msg->param; ++ struct rwnx_vif *vif; ++ bool found = false; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ // Look for VIF entry ++ list_for_each_entry (vif, &rwnx_hw->vifs, list) { ++ if (vif->vif_index == ind->vif_index) { ++ found = true; ++ break; ++ } ++ } ++ ++ if (found) { ++ if (RWNX_VIF_TYPE(vif) == NL80211_IFTYPE_AP || ++ RWNX_VIF_TYPE(vif) == NL80211_IFTYPE_P2P_GO) { ++ if (vif->ap.csa) { ++ vif->ap.csa->status = ind->status; ++ vif->ap.csa->ch_idx = ind->chan_idx; ++ schedule_work(&vif->ap.csa->work); ++ } else ++ netdev_err( ++ vif->ndev, ++ "CSA finish indication but no active CSA"); ++ } else { ++ if (ind->status == 0) { ++ rwnx_chanctx_unlink(vif); ++ rwnx_chanctx_link(vif, ind->chan_idx, NULL); ++ if (rwnx_hw->cur_chanctx == ind->chan_idx) { ++ rwnx_radar_detection_enable_on_cur_channel( ++ rwnx_hw); ++ rwnx_txq_vif_start(vif, ++ RWNX_TXQ_STOP_CHAN, ++ rwnx_hw); ++ } else ++ rwnx_txq_vif_stop(vif, ++ RWNX_TXQ_STOP_CHAN, ++ rwnx_hw); ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static inline int rwnx_rx_csa_traffic_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ struct mm_csa_traffic_ind *ind = ++ (struct mm_csa_traffic_ind *)msg->param; ++ struct rwnx_vif *vif; ++ bool found = false; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ // Look for VIF entry ++ list_for_each_entry (vif, &rwnx_hw->vifs, list) { ++ if (vif->vif_index == ind->vif_index) { ++ found = true; ++ break; ++ } ++ } ++ ++ if (found) { ++ if (ind->enable) ++ rwnx_txq_vif_start(vif, RWNX_TXQ_STOP_CSA, rwnx_hw); ++ else ++ rwnx_txq_vif_stop(vif, RWNX_TXQ_STOP_CSA, rwnx_hw); ++ } ++ ++ return 0; ++} ++ ++static inline int rwnx_rx_ps_change_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ struct mm_ps_change_ind *ind = (struct mm_ps_change_ind *)msg->param; ++ struct rwnx_sta *sta = &rwnx_hw->sta_table[ind->sta_idx]; ++ ++ 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); ++ return 1; ++ } ++ ++ netdev_dbg(rwnx_hw->vif_table[sta->vif_idx]->ndev, ++ "Sta %d, change PS mode to %s", sta->sta_idx, ++ ind->ps_state ? "ON" : "OFF"); ++ ++ if (sta->valid) { ++ rwnx_ps_bh_enable(rwnx_hw, sta, ind->ps_state); ++ } else if (rwnx_hw->adding_sta) { ++ sta->ps.active = ind->ps_state ? true : false; ++ } else { ++ if (rwnx_hw->vif_table[sta->vif_idx] && ++ 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"); ++ } ++ ++ return 0; ++} ++ ++static inline int rwnx_rx_traffic_req_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ struct mm_traffic_req_ind *ind = ++ (struct mm_traffic_req_ind *)msg->param; ++ struct rwnx_sta *sta = &rwnx_hw->sta_table[ind->sta_idx]; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ netdev_dbg(rwnx_hw->vif_table[sta->vif_idx]->ndev, ++ "Sta %d, asked for %d pkt", sta->sta_idx, ind->pkt_cnt); ++ ++ rwnx_ps_bh_traffic_req(rwnx_hw, sta, ind->pkt_cnt, ++ ind->uapsd ? UAPSD_ID : LEGACY_PS_ID); ++ ++ return 0; ++} ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++/*************************************************************************** ++ * Messages from SCAN task ++ **************************************************************************/ ++#if 0 ++static inline int rwnx_rx_scan_done_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0) ++ struct cfg80211_scan_info info = { ++ .aborted = false, ++ }; ++#endif ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ rwnx_ipc_elem_var_deallocs(rwnx_hw, &rwnx_hw->scan_ie); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0) ++ ieee80211_scan_completed(rwnx_hw->hw, &info); ++#else ++ ieee80211_scan_completed(rwnx_hw->hw, false); ++#endif ++ ++ return 0; ++} ++#endif ++ ++/*************************************************************************** ++ * Messages from SCANU task ++ **************************************************************************/ ++#ifdef CONFIG_RWNX_FULLMAC ++extern uint8_t scanning; ++static inline int rwnx_rx_scanu_start_cfm(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ if (rwnx_hw->scan_request ++#ifdef CONFIG_SCHED_SCAN ++ && !rwnx_hw->is_sched_scan ++#endif //CONFIG_SCHED_SCAN ++ ) { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0) ++ struct cfg80211_scan_info info = { ++ .aborted = false, ++ }; ++ ++ cfg80211_scan_done(rwnx_hw->scan_request, &info); ++#else ++ cfg80211_scan_done(rwnx_hw->scan_request, false); ++#endif ++ } ++ ++#ifdef CONFIG_SCHED_SCAN ++ if (rwnx_hw->is_sched_scan) { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) ++ AICWFDBG(LOGINFO, "%s cfg80211_sched_scan_results \r\n", ++ __func__); ++ cfg80211_sched_scan_results(rwnx_hw->scan_request->wiphy, ++ rwnx_hw->sched_scan_req->reqid); ++#else ++ cfg80211_sched_scan_results(rwnx_hw->sched_scan_req->wiphy); ++#endif ++ kfree(rwnx_hw->scan_request); ++ rwnx_hw->is_sched_scan = false; ++ } ++#endif //CONFIG_SCHED_SCAN ++ ++ rwnx_hw->scan_request = NULL; ++ scanning = 0; ++ ++ return 0; ++} ++ ++static inline int rwnx_rx_scanu_result_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ struct cfg80211_bss *bss = NULL; ++ struct ieee80211_channel *chan; ++ struct scanu_result_ind *ind = (struct scanu_result_ind *)msg->param; ++ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)ind->payload; ++ u64 tsf; ++ u8 *ie; ++ size_t ielen; ++ u16 capability, beacon_interval; ++ u16 len = ind->length; ++ ++ chan = ieee80211_get_channel(rwnx_hw->wiphy, ind->center_freq); ++ ++ if (chan != NULL) { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) ++ struct timespec ts; ++ get_monotonic_boottime(&ts); ++ 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; ++#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 ++ ie = mgmt->u.probe_resp.variable; ++ ielen = len - ++ offsetof(struct ieee80211_mgmt, u.probe_resp.variable); ++ beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); ++ capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); ++ /* framework use system bootup time */ ++ bss = cfg80211_inform_bss(rwnx_hw->wiphy, chan, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) ++ CFG80211_BSS_FTYPE_UNKNOWN, ++#endif ++ mgmt->bssid, tsf, capability, ++ beacon_interval, ie, ielen, ++ ind->rssi * 100, GFP_ATOMIC); ++ } ++ ++ if (bss != NULL) ++ cfg80211_put_bss(rwnx_hw->wiphy, bss); ++ ++ return 0; ++} ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++/*************************************************************************** ++ * Messages from ME task ++ **************************************************************************/ ++#ifdef CONFIG_RWNX_FULLMAC ++static inline int rwnx_rx_me_tkip_mic_failure_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ struct me_tkip_mic_failure_ind *ind = ++ (struct me_tkip_mic_failure_ind *)msg->param; ++ struct rwnx_vif *rwnx_vif = rwnx_hw->vif_table[ind->vif_idx]; ++ struct net_device *dev = rwnx_vif->ndev; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ cfg80211_michael_mic_failure(dev, (u8 *)&ind->addr, ++ (ind->ga ? NL80211_KEYTYPE_GROUP : ++ NL80211_KEYTYPE_PAIRWISE), ++ ind->keyid, (u8 *)&ind->tsc, GFP_ATOMIC); ++ ++ return 0; ++} ++ ++static inline int rwnx_rx_me_tx_credits_update_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ struct me_tx_credits_update_ind *ind = ++ (struct me_tx_credits_update_ind *)msg->param; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ rwnx_txq_credit_update(rwnx_hw, ind->sta_idx, ind->tid, ind->credits); ++ ++ return 0; ++} ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++/*************************************************************************** ++ * Messages from SM task ++ **************************************************************************/ ++#ifdef CONFIG_RWNX_FULLMAC ++static inline int rwnx_rx_sm_connect_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ struct sm_connect_ind *ind = (struct sm_connect_ind *)msg->param; ++ struct rwnx_vif *rwnx_vif = rwnx_hw->vif_table[ind->vif_idx]; ++ struct net_device *dev = rwnx_vif->ndev; ++ const u8 *req_ie, *rsp_ie; ++ const u8 *extcap_ie; ++ const struct ieee_types_extcap *extcap; ++ struct ieee80211_channel *chan; ++ //struct cfg80211_bss *bss = NULL; ++ struct wireless_dev *wdev = NULL; ++ //int retry_counter = 10; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ wdev = dev->ieee80211_ptr; ++ ++ /* Retrieve IE addresses and lengths */ ++ req_ie = (const u8 *)ind->assoc_ie_buf; ++ rsp_ie = req_ie + ind->assoc_req_ie_len; ++ ++ // Fill-in the AP information ++ AICWFDBG(LOGINFO, "%s ind->status_code:%d \r\n", __func__, ++ ind->status_code); ++ ++ if (ind->status_code == 0) { ++ struct rwnx_sta *sta = &rwnx_hw->sta_table[ind->ap_idx]; ++ u8 txq_status; ++ struct cfg80211_chan_def chandef; ++ ++ sta->valid = true; ++ sta->sta_idx = ind->ap_idx; ++ sta->ch_idx = ind->ch_idx; ++ sta->vif_idx = ind->vif_idx; ++ sta->vlan_idx = sta->vif_idx; ++ sta->qos = ind->qos; ++ sta->acm = ind->acm; ++ sta->ps.active = false; ++ sta->aid = ind->aid; ++ sta->band = ind->band; //ind->chan.band; ++ sta->width = ind->width; //ind->chan.type; ++ sta->center_freq = ind->center_freq; //ind->chan.prim20_freq; ++ sta->center_freq1 = ind->center_freq1; //ind->chan.center1_freq; ++ sta->center_freq2 = ind->center_freq2; //ind->chan.center2_freq; ++ rwnx_vif->sta.ap = sta; ++ chan = ieee80211_get_channel( ++ rwnx_hw->wiphy, ++ ind->center_freq); //ind->chan.prim20_freq); ++ cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT); ++ if (!rwnx_hw->mod_params->ht_on) ++ chandef.width = NL80211_CHAN_WIDTH_20_NOHT; ++ else ++ chandef.width = chnl2bw[ind->width]; //[ind->chan.type]; ++ chandef.center_freq1 = ++ ind->center_freq1; //ind->chan.center1_freq; ++ chandef.center_freq2 = ++ ind->center_freq2; //ind->chan.center2_freq; ++ rwnx_chanctx_link(rwnx_vif, ind->ch_idx, &chandef); ++ memcpy(sta->mac_addr, ind->bssid.array, ETH_ALEN); ++ if (ind->ch_idx == rwnx_hw->cur_chanctx) { ++ txq_status = 0; ++ } else { ++ txq_status = RWNX_TXQ_STOP_CHAN; ++ } ++ 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); ++#ifdef CONFIG_DEBUG_FS ++ rwnx_dbgfs_register_rc_stat(rwnx_hw, sta); ++#endif ++ rwnx_mu_group_sta_init(sta, NULL); ++ /* Look for TDLS Channel Switch Prohibited flag in the Extended Capability ++ * Information Element*/ ++ extcap_ie = cfg80211_find_ie(WLAN_EID_EXT_CAPABILITY, rsp_ie, ++ ind->assoc_rsp_ie_len); ++ if (extcap_ie && extcap_ie[1] >= 5) { ++ extcap = (void *)(extcap_ie); ++ rwnx_vif->tdls_chsw_prohibited = ++ extcap->ext_capab[4] & ++ WLAN_EXT_CAPA5_TDLS_CH_SW_PROHIBITED; ++ } ++ ++#ifdef CONFIG_RADAR_OR_IR_DETECT ++ if (chan->flags & IEEE80211_CHAN_RADAR) ++ rwnx_radar_detection_enable(&rwnx_hw->radar, ++ RWNX_RADAR_DETECT_REPORT, ++ RWNX_RADAR_RIU); ++#endif ++ ++ 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 ++ * with the new peer device ++ */ ++ if (rwnx_hw->mod_params->bfmer) { ++ const u8 *vht_capa_ie; ++ const struct ieee80211_vht_cap *vht_cap; ++ ++ do { ++ /* Look for VHT Capability Information Element */ ++ vht_capa_ie = cfg80211_find_ie( ++ WLAN_EID_VHT_CAPABILITY, rsp_ie, ++ ind->assoc_rsp_ie_len); ++ ++ /* Stop here if peer device does not support VHT */ ++ if (!vht_capa_ie) { ++ break; ++ } ++ ++ vht_cap = (const struct ieee80211_vht_cap ++ *)(vht_capa_ie + 2); ++ ++ /* Send MM_BFMER_ENABLE_REQ message if needed */ ++ rwnx_send_bfmer_enable(rwnx_hw, sta, vht_cap); ++ } while (0); ++ } ++#endif //(CONFIG_RWNX_BFMER) ++ ++#ifdef CONFIG_RWNX_MON_DATA ++ // If there are 1 sta and 1 monitor interface active at the same time then ++ // monitor interface channel context is always the same as the STA interface. ++ // This doesn't work with 2 STA interfaces but we don't want to support it. ++ if (rwnx_hw->monitor_vif != RWNX_INVALID_VIF) { ++ struct rwnx_vif *rwnx_mon_vif = ++ rwnx_hw->vif_table[rwnx_hw->monitor_vif]; ++ rwnx_chanctx_unlink(rwnx_mon_vif); ++ rwnx_chanctx_link(rwnx_mon_vif, ind->ch_idx, NULL); ++ } ++#endif ++ //atomic_set(&rwnx_vif->drv_conn_state, (int)RWNX_DRV_STATUS_CONNECTED); ++ } else if (ind->status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) { ++ if (rwnx_vif->wep_enabled) { ++ rwnx_vif->wep_auth_err = true; ++ AICWFDBG(LOGINFO, "con ind wep_auth_err %d\n", ++ rwnx_vif->wep_auth_err); ++ } ++ rwnx_set_conn_state(&rwnx_vif->drv_conn_state, ++ (int)RWNX_DRV_STATUS_DISCONNECTED); ++ } else { ++ rwnx_set_conn_state(&rwnx_vif->drv_conn_state, ++ (int)RWNX_DRV_STATUS_DISCONNECTED); ++ } ++ ++ AICWFDBG( ++ LOGINFO, ++ "%s ind->roamed:%d ind->status_code:%d rwnx_vif->drv_conn_state:%d\r\n", ++ __func__, ind->roamed, ind->status_code, ++ (int)atomic_read(&rwnx_vif->drv_conn_state)); ++ ++ if (ind->status_code == 0 && ++ (int)atomic_read(&rwnx_vif->drv_conn_state) == ++ RWNX_DRV_STATUS_DISCONNECTING) { ++ AICWFDBG( ++ LOGINFO, ++ "%s the disconnection has been requested, return it\r\n", ++ __func__); ++ goto exit; ++ } ++ ++ if (!ind->roamed) { //not roaming ++ cfg80211_connect_result(dev, (const u8 *)ind->bssid.array, ++ req_ie, ind->assoc_req_ie_len, rsp_ie, ++ ind->assoc_rsp_ie_len, ind->status_code, ++ GFP_ATOMIC); ++ if (ind->status_code == 0) { ++ rwnx_set_conn_state(&rwnx_vif->drv_conn_state, ++ (int)RWNX_DRV_STATUS_CONNECTED); ++ AICWFDBG( ++ LOGINFO, ++ "%s cfg80211_connect_result pass, rwnx_vif->drv_conn_state:%d\r\n", ++ __func__, ++ (int)atomic_read(&rwnx_vif->drv_conn_state)); ++ } else { ++ rwnx_set_conn_state(&rwnx_vif->drv_conn_state, ++ (int)RWNX_DRV_STATUS_DISCONNECTED); ++ rwnx_external_auth_disable(rwnx_vif); ++ } ++ ++ } else { //roaming ++ if (ind->status_code != 0) { ++ AICWFDBG(LOGINFO, ++ "%s roaming fail to notify disconnect \r\n", ++ __func__); ++ cfg80211_disconnected(dev, 0, NULL, 0, 1, GFP_ATOMIC); ++ rwnx_set_conn_state(&rwnx_vif->drv_conn_state, ++ (int)RWNX_DRV_STATUS_DISCONNECTED); ++ rwnx_external_auth_disable(rwnx_vif); ++ } else { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) ++ struct cfg80211_roam_info info; ++ memset(&info, 0, sizeof(info)); ++#if LINUX_VERSION_CODE >= HIGH_KERNEL_VERSION ++ if (rwnx_vif->ch_index < NX_CHAN_CTXT_CNT) ++ info.links[0].channel = ++ rwnx_hw->chanctx_table[rwnx_vif->ch_index] ++ .chan_def.chan; ++ info.links[0].bssid = (const u8 *)ind->bssid.array; ++#else ++ if (rwnx_vif->ch_index < NX_CHAN_CTXT_CNT) ++ info.channel = ++ rwnx_hw->chanctx_table[rwnx_vif->ch_index] ++ .chan_def.chan; ++ info.bssid = (const u8 *)ind->bssid.array; ++#endif ++ info.req_ie = req_ie; ++ info.req_ie_len = ind->assoc_req_ie_len; ++ info.resp_ie = rsp_ie; ++ info.resp_ie_len = ind->assoc_rsp_ie_len; ++ cfg80211_roamed(dev, &info, GFP_ATOMIC); ++#else ++ chan = ieee80211_get_channel(rwnx_hw->wiphy, ++ ind->center_freq); ++ cfg80211_roamed(dev ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) || \ ++ defined(COMPAT_KERNEL_RELEASE) ++ , ++ chan ++#endif ++ , ++ (const u8 *)ind->bssid.array, req_ie, ++ ind->assoc_req_ie_len, rsp_ie, ++ ind->assoc_rsp_ie_len, GFP_ATOMIC); ++ ++#endif /*LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)*/ ++ rwnx_set_conn_state(&rwnx_vif->drv_conn_state, ++ (int)RWNX_DRV_STATUS_CONNECTED); ++ } ++ rwnx_vif->sta.is_roam = false; ++ } ++ ++ if (ind->status_code == 0) { ++ netif_tx_start_all_queues(dev); ++ netif_carrier_on(dev); ++ } ++ ++exit: ++ rwnx_vif->sta.is_roam = false; ++ return 0; ++} ++ ++void rwnx_cfg80211_unlink_bss(struct rwnx_hw *rwnx_hw, ++ struct rwnx_vif *rwnx_vif) ++{ ++ struct wiphy *wiphy = rwnx_hw->wiphy; ++ struct cfg80211_bss *bss = NULL; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ bss = cfg80211_get_bss(wiphy, NULL /*notify_channel*/, ++ rwnx_vif->sta.bssid, rwnx_vif->sta.ssid, ++ rwnx_vif->sta.ssid_len, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) ++ IEEE80211_BSS_TYPE_ESS, ++ IEEE80211_PRIVACY(true)); //temp set true ++#else ++ WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); ++#endif ++ ++ if (bss) { ++ cfg80211_unlink_bss(wiphy, bss); ++ AICWFDBG(LOGINFO, "%s(): cfg80211_unlink %s!!\n", __func__, ++ rwnx_vif->sta.ssid); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) ++ cfg80211_put_bss(wiphy, bss); ++#else ++ cfg80211_put_bss(bss); ++#endif ++ } else { ++ AICWFDBG(LOGINFO, "%s(): cfg80211_unlink error %s!!\n", ++ __func__, rwnx_vif->sta.ssid); ++ } ++} ++ ++extern u8 dhcped; ++static inline int rwnx_rx_sm_disconnect_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ 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; ++#ifdef AICWF_RX_REORDER ++ struct reord_ctrl_info *reord_info, *tmp; ++ u8 *macaddr; ++ struct aicwf_rx_priv *rx_priv; ++#endif ++ ++ //RWNX_DBG(RWNX_FN_ENTRY_STR); ++ AICWFDBG(LOGINFO, "%s reason code:%d \r\n", __func__, ind->reason_code); ++ ++ if ((int)atomic_read(&rwnx_vif->drv_conn_state) == ++ (int)RWNX_DRV_STATUS_DISCONNECTED) { ++ AICWFDBG(LOGINFO, ++ "%s, is already disconnected, drop disconnect ind", ++ __func__); ++ return 0; ++ } ++ ++ dhcped = 0; ++ ++ if (!rwnx_vif) ++ return 0; ++ dev = rwnx_vif->ndev; ++ ++ if (rwnx_vif->sta.is_roam == false) { ++ rwnx_cfg80211_unlink_bss(rwnx_hw, rwnx_vif); ++ } else { ++ AICWFDBG(LOGINFO, "%s roaming no rwnx_cfg80211_unlink_bss \r\n", ++ __func__); ++ } ++ ++#ifdef CONFIG_DEBUG_FS ++ rwnx_dbgfs_unregister_rc_stat(rwnx_hw, rwnx_vif->sta.ap); ++#endif ++ ++#ifdef CONFIG_BR_SUPPORT ++ struct rwnx_vif *vif = netdev_priv(dev); ++ /* clear bridge database */ ++ nat25_db_cleanup(rwnx_vif); ++#endif /* CONFIG_BR_SUPPORT */ ++ ++ if (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) ++ rwnx_hw->is_p2p_connected = 0; ++ /* if vif is not up, rwnx_close has already been called */ ++ if (rwnx_vif->up) { ++ if (!ind->ft_over_ds && !ind->reassoc) { ++ cfg80211_disconnected(dev, ind->reason_code, NULL, 0, ++ (ind->reason_code < 1), ++ GFP_ATOMIC); ++ } ++ netif_tx_stop_all_queues(dev); ++ netif_carrier_off(dev); ++ } ++ ++#ifdef CONFIG_RWNX_BFMER ++ /* Disable Beamformer if supported */ ++ rwnx_bfmer_report_del(rwnx_hw, rwnx_vif->sta.ap); ++#endif //(CONFIG_RWNX_BFMER) ++ ++#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)) { ++ macaddr = (u8 *)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 = (u8 *)rwnx_vif->ndev->dev_addr; ++ 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); ++ } else if ((rwnx_vif->wdev.iftype == NL80211_IFTYPE_AP) || ++ (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)) { ++ BUG(); //should be not here: del_sta function ++ } ++#endif ++ ++ rwnx_txq_sta_deinit(rwnx_hw, rwnx_vif->sta.ap); ++ rwnx_txq_tdls_vif_deinit(rwnx_vif); ++#if 0 ++ rwnx_dbgfs_unregister_rc_stat(rwnx_hw, rwnx_vif->sta.ap); ++#endif ++ rwnx_vif->sta.ap->valid = false; ++ rwnx_vif->sta.ap = NULL; ++ rwnx_external_auth_disable(rwnx_vif); ++ rwnx_chanctx_unlink(rwnx_vif); ++ ++ //msleep(200); ++ if (rwnx_vif->sta.is_roam == false) { ++ rwnx_set_conn_state(&rwnx_vif->drv_conn_state, ++ (int)RWNX_DRV_STATUS_DISCONNECTED); ++ } ++ ++ return 0; ++} ++ ++static inline int rwnx_rx_sm_external_auth_required_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ 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) || \ ++ defined(CONFIG_WPA3_FOR_OLD_KERNEL) ++ struct net_device *dev = rwnx_vif->ndev; ++ struct cfg80211_external_auth_params params; ++ int ret = 0; ++ struct wireless_dev *wdev = dev->ieee80211_ptr; ++ int retry_counter = 10; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ memset((void *)¶ms, 0, ++ sizeof(struct cfg80211_external_auth_params)); ++ ++ params.action = NL80211_EXTERNAL_AUTH_START; ++ memcpy(params.bssid, ind->bssid.array, ETH_ALEN); ++ params.ssid.ssid_len = ind->ssid.length; ++ memcpy(params.ssid.ssid, ind->ssid.array, ++ min_t(size_t, ind->ssid.length, sizeof(params.ssid.ssid))); ++ params.key_mgmt_suite = ind->akm; ++ ++ while (wdev->conn_owner_nlportid == 0) { ++ AICWFDBG( ++ LOGINFO, ++ "%s WARNING conn_owner_nlportid = 0, msleep 100ms.\r\n", ++ __func__); ++ msleep(100); ++ retry_counter--; ++ if (retry_counter == 0) { ++ break; ++ } ++ } ++ AICWFDBG(LOGINFO, "%s wdev->conn_owner_nlportid:%d \r\n", __func__, ++ (int)wdev->conn_owner_nlportid); ++ ++ if ((ind->vif_idx > NX_VIRT_DEV_MAX) || !rwnx_vif->up || ++ (RWNX_VIF_TYPE(rwnx_vif) != NL80211_IFTYPE_STATION) || ++ (ret = cfg80211_external_auth_request(dev, ¶ms, GFP_ATOMIC))) { ++ wiphy_err( ++ rwnx_hw->wiphy, ++ "Failed to start external auth on vif %d, rwnx_vif->up %d, iftype:%d, ret %d", ++ ind->vif_idx, rwnx_vif->up, RWNX_VIF_TYPE(rwnx_vif), ++ ret); ++ rwnx_send_sm_external_auth_required_rsp( ++ rwnx_hw, rwnx_vif, WLAN_STATUS_UNSPECIFIED_FAILURE); ++ return 0; ++ } ++ ++ rwnx_external_auth_enable(rwnx_vif); ++#else ++ rwnx_send_sm_external_auth_required_rsp( ++ rwnx_hw, rwnx_vif, WLAN_STATUS_UNSPECIFIED_FAILURE); ++#endif ++ return 0; ++} ++ ++static inline int rwnx_rx_mesh_path_create_cfm(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ struct mesh_path_create_cfm *cfm = ++ (struct mesh_path_create_cfm *)msg->param; ++ struct rwnx_vif *rwnx_vif = rwnx_hw->vif_table[cfm->vif_idx]; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Check we well have a Mesh Point Interface */ ++ if (rwnx_vif && ++ (RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_MESH_POINT)) { ++ rwnx_vif->ap.create_path = false; ++ } ++ ++ return 0; ++} ++ ++static inline int rwnx_rx_mesh_peer_update_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ struct mesh_peer_update_ind *ind = ++ (struct mesh_peer_update_ind *)msg->param; ++ struct rwnx_vif *rwnx_vif = rwnx_hw->vif_table[ind->vif_idx]; ++ struct rwnx_sta *rwnx_sta = &rwnx_hw->sta_table[ind->sta_idx]; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ if ((ind->vif_idx >= (NX_VIRT_DEV_MAX + NX_REMOTE_STA_MAX)) || ++ (rwnx_vif && ++ (RWNX_VIF_TYPE(rwnx_vif) != NL80211_IFTYPE_MESH_POINT)) || ++ (ind->sta_idx >= NX_REMOTE_STA_MAX)) ++ return 1; ++ ++ /* Check we well have a Mesh Point Interface */ ++ if (!rwnx_vif->user_mpm) { ++ /* Check if peer link has been established or lost */ ++ if (ind->estab) { ++ if (!rwnx_sta->valid) { ++ u8 txq_status; ++ ++ rwnx_sta->valid = true; ++ rwnx_sta->sta_idx = ind->sta_idx; ++ rwnx_sta->ch_idx = rwnx_vif->ch_index; ++ rwnx_sta->vif_idx = ind->vif_idx; ++ rwnx_sta->vlan_idx = rwnx_sta->vif_idx; ++ rwnx_sta->ps.active = false; ++ rwnx_sta->qos = true; ++ rwnx_sta->aid = ind->sta_idx + 1; ++ //rwnx_sta->acm = ind->acm; ++ memcpy(rwnx_sta->mac_addr, ind->peer_addr.array, ++ ETH_ALEN); ++ ++ rwnx_chanctx_link(rwnx_vif, rwnx_sta->ch_idx, ++ NULL); ++ ++ /* Add the station in the list of VIF's stations */ ++ INIT_LIST_HEAD(&rwnx_sta->list); ++ list_add_tail(&rwnx_sta->list, ++ &rwnx_vif->ap.sta_list); ++ ++ /* Initialize the TX queues */ ++ if (rwnx_sta->ch_idx == rwnx_hw->cur_chanctx) { ++ txq_status = 0; ++ } else { ++ txq_status = RWNX_TXQ_STOP_CHAN; ++ } ++ ++ 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) ++ rwnx_send_bfmer_enable(rwnx_hw, ++ rwnx_sta, NULL); ++ ++ rwnx_mu_group_sta_init(rwnx_sta, NULL); ++#endif /* CONFIG_RWNX_BFMER */ ++ ++ } else { ++ WARN_ON(0); ++ } ++ } else { ++ if (rwnx_sta->valid) { ++ rwnx_sta->ps.active = false; ++ rwnx_sta->valid = false; ++ ++ /* Remove the station from the list of VIF's station */ ++ 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); ++ } ++ } ++ } else { ++ if (!ind->estab && rwnx_sta->valid) { ++ /* There is no way to inform upper layer for lost of peer, still ++ clean everything in the driver */ ++ rwnx_sta->ps.active = false; ++ rwnx_sta->valid = false; ++ ++ /* Remove the station from the list of VIF's station */ ++ 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); ++ } ++ } ++ ++ return 0; ++} ++ ++static inline int rwnx_rx_mesh_path_update_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ struct mesh_path_update_ind *ind = ++ (struct mesh_path_update_ind *)msg->param; ++ struct rwnx_vif *rwnx_vif = rwnx_hw->vif_table[ind->vif_idx]; ++ struct rwnx_mesh_path *mesh_path; ++ bool found = false; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ if (ind->vif_idx >= (NX_VIRT_DEV_MAX + NX_REMOTE_STA_MAX)) ++ return 1; ++ ++ if (!rwnx_vif || (RWNX_VIF_TYPE(rwnx_vif) != NL80211_IFTYPE_MESH_POINT)) ++ return 0; ++ ++ /* Look for path with provided target address */ ++ list_for_each_entry (mesh_path, &rwnx_vif->ap.mpath_list, list) { ++ if (mesh_path->path_idx == ind->path_idx) { ++ found = true; ++ break; ++ } ++ } ++ ++ /* 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 */ ++ kfree(mesh_path); ++ } ++ } else { ++ 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); ++ ++ if (mesh_path) { ++ INIT_LIST_HEAD(&mesh_path->list); ++ ++ mesh_path->path_idx = ind->path_idx; ++ mesh_path->p_nhop_sta = ++ &rwnx_hw->sta_table[ind->nhop_sta_idx]; ++ memcpy(&mesh_path->tgt_mac_addr, ++ &ind->tgt_mac_addr, MAC_ADDR_LEN); ++ ++ // 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 ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static inline int rwnx_rx_mesh_proxy_update_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ struct mesh_proxy_update_ind *ind = ++ (struct mesh_proxy_update_ind *)msg->param; ++ struct rwnx_vif *rwnx_vif = rwnx_hw->vif_table[ind->vif_idx]; ++ struct rwnx_mesh_proxy *mesh_proxy; ++ bool found = false; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ if (ind->vif_idx >= (NX_VIRT_DEV_MAX + NX_REMOTE_STA_MAX)) ++ return 1; ++ ++ if (!rwnx_vif || (RWNX_VIF_TYPE(rwnx_vif) != NL80211_IFTYPE_MESH_POINT)) ++ return 0; ++ ++ /* Look for path with provided external STA address */ ++ list_for_each_entry (mesh_proxy, &rwnx_vif->ap.proxy_list, list) { ++ if (!memcmp(&ind->ext_sta_addr, &mesh_proxy->ext_sta_addr, ++ ETH_ALEN)) { ++ found = true; ++ break; ++ } ++ } ++ ++ if (ind->delete &&found) { ++ /* Delete mesh path */ ++ list_del_init(&mesh_proxy->list); ++ kfree(mesh_proxy); ++ } else if (!ind->delete &&!found) { ++ /* Allocate a Mesh Path structure */ ++ mesh_proxy = (struct rwnx_mesh_proxy *)kmalloc( ++ sizeof(*mesh_proxy), GFP_ATOMIC); ++ ++ if (mesh_proxy) { ++ INIT_LIST_HEAD(&mesh_proxy->list); ++ ++ memcpy(&mesh_proxy->ext_sta_addr, &ind->ext_sta_addr, ++ MAC_ADDR_LEN); ++ mesh_proxy->local = ind->local; ++ ++ if (!ind->local) { ++ memcpy(&mesh_proxy->proxy_addr, ++ &ind->proxy_mac_addr, MAC_ADDR_LEN); ++ } ++ ++ /* Insert the path in the list of path */ ++ list_add_tail(&mesh_proxy->list, ++ &rwnx_vif->ap.proxy_list); ++ } ++ } ++ ++ return 0; ++} ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++/*************************************************************************** ++ * Messages from APM task ++ **************************************************************************/ ++ ++/*************************************************************************** ++ * Messages from DEBUG task ++ **************************************************************************/ ++static inline int rwnx_rx_dbg_error_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_MCU_MESSAGE ++static inline int rwnx_rx_dbg_custmsg_ind(struct rwnx_hw *rwnx_hw, ++ struct rwnx_cmd *cmd, ++ struct ipc_e2a_msg *msg) ++{ ++ dbg_custom_msg_ind_t *ind; ++ char str_msg[32 + 1]; ++ int str_len; ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ ind = (dbg_custom_msg_ind_t *)msg->param; ++ str_len = (ind->len < 32) ? ind->len : 32; ++ memcpy(str_msg, (char *)ind->buf, str_len); ++ str_msg[str_len] = '\0'; ++ printk("CustMsgInd: cmd=0x%x, len=%d, str=%s\r\n", ind->cmd, ind->len, ++ str_msg); ++ ++ return 0; ++} ++#endif ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ ++static msg_cb_fct mm_hdlrs[MSG_I(MM_MAX)] = { ++ [MSG_I(MM_CHANNEL_SWITCH_IND)] = rwnx_rx_chan_switch_ind, ++ [MSG_I(MM_CHANNEL_PRE_SWITCH_IND)] = rwnx_rx_chan_pre_switch_ind, ++ [MSG_I(MM_REMAIN_ON_CHANNEL_EXP_IND)] = ++ rwnx_rx_remain_on_channel_exp_ind, ++ [MSG_I(MM_PS_CHANGE_IND)] = rwnx_rx_ps_change_ind, ++ [MSG_I(MM_TRAFFIC_REQ_IND)] = rwnx_rx_traffic_req_ind, ++ [MSG_I(MM_P2P_VIF_PS_CHANGE_IND)] = rwnx_rx_p2p_vif_ps_change_ind, ++ [MSG_I(MM_CSA_COUNTER_IND)] = rwnx_rx_csa_counter_ind, ++ [MSG_I(MM_CSA_FINISH_IND)] = rwnx_rx_csa_finish_ind, ++ [MSG_I(MM_CSA_TRAFFIC_IND)] = rwnx_rx_csa_traffic_ind, ++ [MSG_I(MM_CHANNEL_SURVEY_IND)] = rwnx_rx_channel_survey_ind, ++ [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, ++ [MSG_I(MM_RADAR_DETECT_IND)] = rwnx_radar_detect_ind, ++}; ++ ++static msg_cb_fct scan_hdlrs[MSG_I(SCANU_MAX)] = { ++ [MSG_I(SCANU_START_CFM)] = rwnx_rx_scanu_start_cfm, ++ [MSG_I(SCANU_RESULT_IND)] = rwnx_rx_scanu_result_ind, ++}; ++ ++static msg_cb_fct me_hdlrs[MSG_I(ME_MAX)] = { ++ [MSG_I(ME_TKIP_MIC_FAILURE_IND)] = rwnx_rx_me_tkip_mic_failure_ind, ++ [MSG_I(ME_TX_CREDITS_UPDATE_IND)] = rwnx_rx_me_tx_credits_update_ind, ++}; ++ ++static msg_cb_fct sm_hdlrs[MSG_I(SM_MAX)] = { ++ [MSG_I(SM_CONNECT_IND)] = rwnx_rx_sm_connect_ind, ++ [MSG_I(SM_DISCONNECT_IND)] = rwnx_rx_sm_disconnect_ind, ++ [MSG_I(SM_EXTERNAL_AUTH_REQUIRED_IND)] = ++ rwnx_rx_sm_external_auth_required_ind, ++}; ++ ++static msg_cb_fct apm_hdlrs[MSG_I(APM_MAX)] = {}; ++ ++static msg_cb_fct mesh_hdlrs[MSG_I(MESH_MAX)] = { ++ [MSG_I(MESH_PATH_CREATE_CFM)] = rwnx_rx_mesh_path_create_cfm, ++ [MSG_I(MESH_PEER_UPDATE_IND)] = rwnx_rx_mesh_peer_update_ind, ++ [MSG_I(MESH_PATH_UPDATE_IND)] = rwnx_rx_mesh_path_update_ind, ++ [MSG_I(MESH_PROXY_UPDATE_IND)] = rwnx_rx_mesh_proxy_update_ind, ++}; ++ ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++static msg_cb_fct dbg_hdlrs[MSG_I(DBG_MAX)] = { ++ [MSG_I(DBG_ERROR_IND)] = rwnx_rx_dbg_error_ind, ++#ifdef CONFIG_MCU_MESSAGE ++ [MSG_I(DBG_CUSTOM_MSG_IND)] = rwnx_rx_dbg_custmsg_ind, ++#endif ++}; ++ ++static msg_cb_fct tdls_hdlrs[MSG_I(TDLS_MAX)] = { ++ [MSG_I(TDLS_CHAN_SWITCH_CFM)] = rwnx_rx_tdls_chan_switch_cfm, ++ [MSG_I(TDLS_CHAN_SWITCH_IND)] = rwnx_rx_tdls_chan_switch_ind, ++ [MSG_I(TDLS_CHAN_SWITCH_BASE_IND)] = rwnx_rx_tdls_chan_switch_base_ind, ++ [MSG_I(TDLS_PEER_PS_IND)] = rwnx_rx_tdls_peer_ps_ind, ++#ifdef CONFIG_SDIO_BT ++ [MSG_I(TDLS_SDIO_BT_RECV_IND)] = rwnx_bt_recv_ind, ++#endif ++}; ++ ++static msg_cb_fct *msg_hdlrs[] = { ++ [TASK_MM] = mm_hdlrs, [TASK_DBG] = dbg_hdlrs, ++#ifdef CONFIG_RWNX_FULLMAC ++ [TASK_TDLS] = tdls_hdlrs, [TASK_SCANU] = scan_hdlrs, ++ [TASK_ME] = me_hdlrs, [TASK_SM] = sm_hdlrs, ++ [TASK_APM] = apm_hdlrs, [TASK_MESH] = mesh_hdlrs, ++#endif /* CONFIG_RWNX_FULLMAC */ ++}; ++ ++/** ++ * ++ */ ++void rwnx_rx_handle_msg(struct rwnx_hw *rwnx_hw, struct ipc_e2a_msg *msg) ++{ ++ AICWFDBG(LOGDEBUG, "%s msg->id:0x%x \r\n", __func__, msg->id); ++ ++ 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/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_rx.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_rx.h +new file mode 100755 +index 000000000..b5556d160 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_rx.h +@@ -0,0 +1,19 @@ ++/** ++ **************************************************************************************** ++ * ++ * @file rwnx_msg_rx.h ++ * ++ * @brief RX function declarations ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ **************************************************************************************** ++ */ ++ ++#ifndef _RWNX_MSG_RX_H_ ++#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/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_tx.c b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_tx.c +new file mode 100755 +index 000000000..1b318b2f7 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_tx.c +@@ -0,0 +1,4817 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_msg_tx.c ++ * ++ * @brief TX function definitions ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++#include "rwnx_msg_tx.h" ++#include "rwnx_mod_params.h" ++#include "reg_access.h" ++#ifdef CONFIG_RWNX_BFMER ++#include "rwnx_bfmer.h" ++#endif //(CONFIG_RWNX_BFMER) ++#include "rwnx_compat.h" ++#include "rwnx_cmds.h" ++#include "aicwf_txrxif.h" ++#include "rwnx_strs.h" ++#include "rwnx_main.h" ++#include "rwnx_wakelock.h" ++ ++const struct mac_addr mac_addr_bcst = { { 0xFFFF, 0xFFFF, 0xFFFF } }; ++ ++/* Default MAC Rx filters that can be changed by mac80211 ++ * (via the configure_filter() callback) */ ++#define RWNX_MAC80211_CHANGEABLE \ ++ (NXMAC_ACCEPT_BA_BIT | NXMAC_ACCEPT_BAR_BIT | \ ++ NXMAC_ACCEPT_OTHER_DATA_FRAMES_BIT | NXMAC_ACCEPT_PROBE_REQ_BIT | \ ++ NXMAC_ACCEPT_PS_POLL_BIT) ++ ++/* Default MAC Rx filters that cannot be changed by mac80211 */ ++#define RWNX_MAC80211_NOT_CHANGEABLE \ ++ (NXMAC_ACCEPT_QO_S_NULL_BIT | NXMAC_ACCEPT_Q_DATA_BIT | \ ++ NXMAC_ACCEPT_DATA_BIT | NXMAC_ACCEPT_OTHER_MGMT_FRAMES_BIT | \ ++ NXMAC_ACCEPT_MY_UNICAST_BIT | NXMAC_ACCEPT_BROADCAST_BIT | \ ++ NXMAC_ACCEPT_BEACON_BIT | NXMAC_ACCEPT_PROBE_RESP_BIT) ++ ++/* Default MAC Rx filter */ ++#define RWNX_DEFAULT_RX_FILTER \ ++ (RWNX_MAC80211_CHANGEABLE | RWNX_MAC80211_NOT_CHANGEABLE) ++ ++const int bw2chnl[] = { ++ [NL80211_CHAN_WIDTH_20_NOHT] = PHY_CHNL_BW_20, ++ [NL80211_CHAN_WIDTH_20] = PHY_CHNL_BW_20, ++ [NL80211_CHAN_WIDTH_40] = PHY_CHNL_BW_40, ++ [NL80211_CHAN_WIDTH_80] = PHY_CHNL_BW_80, ++ [NL80211_CHAN_WIDTH_160] = PHY_CHNL_BW_160, ++ [NL80211_CHAN_WIDTH_80P80] = PHY_CHNL_BW_80P80, ++}; ++ ++const int chnl2bw[] = { ++ [PHY_CHNL_BW_20] = NL80211_CHAN_WIDTH_20, ++ [PHY_CHNL_BW_40] = NL80211_CHAN_WIDTH_40, ++ [PHY_CHNL_BW_80] = NL80211_CHAN_WIDTH_80, ++ [PHY_CHNL_BW_160] = NL80211_CHAN_WIDTH_160, ++ [PHY_CHNL_BW_80P80] = NL80211_CHAN_WIDTH_80P80, ++}; ++ ++#define RWNX_CMD_ARRAY_SIZE 40 ++#define RWNX_CMD_HIGH_WATER_SIZE RWNX_CMD_ARRAY_SIZE / 2 ++ ++struct rwnx_cmd cmd_array[RWNX_CMD_ARRAY_SIZE]; ++static spinlock_t cmd_array_lock; ++int cmd_array_index = 0; ++ ++/*****************************************************************************/ ++/* ++ * Parse the ampdu density to retrieve the value in usec, according to the ++ * values defined in ieee80211.h ++ */ ++static inline u8 rwnx_ampdudensity2usec(u8 ampdudensity) ++{ ++ switch (ampdudensity) { ++ case IEEE80211_HT_MPDU_DENSITY_NONE: ++ return 0; ++ /* 1 microsecond is our granularity */ ++ case IEEE80211_HT_MPDU_DENSITY_0_25: ++ case IEEE80211_HT_MPDU_DENSITY_0_5: ++ case IEEE80211_HT_MPDU_DENSITY_1: ++ return 1; ++ case IEEE80211_HT_MPDU_DENSITY_2: ++ return 2; ++ case IEEE80211_HT_MPDU_DENSITY_4: ++ return 4; ++ case IEEE80211_HT_MPDU_DENSITY_8: ++ return 8; ++ case IEEE80211_HT_MPDU_DENSITY_16: ++ return 16; ++ default: ++ return 0; ++ } ++} ++ ++static inline bool use_pairwise_key(struct cfg80211_crypto_settings *crypto) ++{ ++ if ((crypto->cipher_group == WLAN_CIPHER_SUITE_WEP40) || ++ (crypto->cipher_group == WLAN_CIPHER_SUITE_WEP104)) ++ return false; ++ ++ return true; ++} ++ ++static inline bool is_non_blocking_msg(int id) ++{ ++ return ((id == MM_TIM_UPDATE_REQ) || (id == ME_RC_SET_RATE_REQ) || ++ (id == MM_BFMER_ENABLE_REQ) || (id == ME_TRAFFIC_IND_REQ) || ++ (id == TDLS_PEER_TRAFFIC_IND_REQ) || ++ (id == MESH_PATH_CREATE_REQ) || (id == MESH_PROXY_ADD_REQ) || ++ (id == SM_EXTERNAL_AUTH_REQUIRED_RSP)); ++} ++ ++static inline u8_l get_chan_flags(uint32_t flags) ++{ ++ u8_l chan_flags = 0; ++#ifdef CONFIG_RADAR_OR_IR_DETECT ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) ++ if (flags & IEEE80211_CHAN_PASSIVE_SCAN) ++#else ++ if (flags & IEEE80211_CHAN_NO_IR) ++#endif ++ chan_flags |= CHAN_NO_IR; ++ if (flags & IEEE80211_CHAN_RADAR) ++ chan_flags |= CHAN_RADAR; ++#endif ++ return chan_flags; ++} ++ ++static inline s8_l chan_to_fw_pwr(int power) ++{ ++ return power > 127 ? 127 : (s8_l)power; ++} ++ ++static inline void limit_chan_bw(u8_l *bw, u16_l primary, u16_l *center1) ++{ ++ int oft, new_oft = 10; ++ ++ if (*bw <= PHY_CHNL_BW_40) ++ return; ++ ++ oft = *center1 - primary; ++ *bw = PHY_CHNL_BW_40; ++ ++ if (oft < 0) ++ new_oft = new_oft * -1; ++ if (abs(oft) == 10 || abs(oft) == 50) ++ new_oft = new_oft * -1; ++ ++ *center1 = primary + new_oft; ++} ++ ++struct rwnx_cmd *rwnx_cmd_malloc(void) ++{ ++ struct rwnx_cmd *cmd = NULL; ++ unsigned long flags = 0; ++ ++ spin_lock_irqsave(&cmd_array_lock, flags); ++ ++ for (cmd_array_index = 0; cmd_array_index < RWNX_CMD_ARRAY_SIZE; ++ cmd_array_index++) { ++ if (cmd_array[cmd_array_index].used == 0) { ++ AICWFDBG(LOGTRACE, "%s get cmd_array[%d]:%p \r\n", ++ __func__, cmd_array_index, ++ &cmd_array[cmd_array_index]); ++ cmd = &cmd_array[cmd_array_index]; ++ cmd_array[cmd_array_index].used = 1; ++ break; ++ } ++ } ++ ++ if (cmd_array_index >= RWNX_CMD_HIGH_WATER_SIZE) { ++ AICWFDBG(LOGERROR, "%s cmd(%d) was pending...\r\n", __func__, ++ cmd_array_index); ++ mdelay(100); ++ } ++ ++ if (!cmd) { ++ AICWFDBG(LOGERROR, "%s array is empty...\r\n", __func__); ++ } ++ ++ spin_unlock_irqrestore(&cmd_array_lock, flags); ++ ++ return cmd; ++} ++ ++void rwnx_cmd_free(struct rwnx_cmd *cmd) ++{ ++ unsigned long flags = 0; ++ ++ spin_lock_irqsave(&cmd_array_lock, flags); ++ cmd->used = 0; ++ AICWFDBG(LOGTRACE, "%s cmd_array[%d]:%p \r\n", __func__, cmd->array_id, ++ cmd); ++ spin_unlock_irqrestore(&cmd_array_lock, flags); ++} ++ ++int rwnx_init_cmd_array(void) ++{ ++ AICWFDBG(LOGTRACE, "%s Enter \r\n", __func__); ++ spin_lock_init(&cmd_array_lock); ++ ++ for (cmd_array_index = 0; cmd_array_index < RWNX_CMD_ARRAY_SIZE; ++ cmd_array_index++) { ++ AICWFDBG(LOGTRACE, "%s cmd_queue[%d]:%p \r\n", __func__, ++ cmd_array_index, &cmd_array[cmd_array_index]); ++ cmd_array[cmd_array_index].used = 0; ++ cmd_array[cmd_array_index].array_id = cmd_array_index; ++ } ++ AICWFDBG(LOGTRACE, "%s Exit \r\n", __func__); ++ ++ return 0; ++} ++ ++void rwnx_free_cmd_array(void) ++{ ++ AICWFDBG(LOGTRACE, "%s Enter \r\n", __func__); ++ ++ for (cmd_array_index = 0; cmd_array_index < RWNX_CMD_ARRAY_SIZE; ++ cmd_array_index++) { ++ cmd_array[cmd_array_index].used = 0; ++ } ++ ++ AICWFDBG(LOGTRACE, "%s Exit \r\n", __func__); ++} ++ ++/** ++ ****************************************************************************** ++ * @brief Allocate memory for a message ++ * ++ * This primitive allocates memory for a message that has to be sent. The memory ++ * is allocated dynamically on the heap and the length of the variable parameter ++ * structure has to be provided in order to allocate the correct size. ++ * ++ * Several additional parameters are provided which will be preset in the message ++ * and which may be used internally to choose the kind of memory to allocate. ++ * ++ * The memory allocated will be automatically freed by the kernel, after the ++ * pointer has been sent to ke_msg_send(). If the message is not sent, it must ++ * be freed explicitly with ke_msg_free(). ++ * ++ * Allocation failure is considered critical and should not happen. ++ * ++ * @param[in] id Message identifier ++ * @param[in] dest_id Destination Task Identifier ++ * @param[in] src_id Source Task Identifier ++ * @param[in] param_len Size of the message parameters to be allocated ++ * ++ * @return Pointer to the parameter member of the ke_msg. If the parameter ++ * structure is empty, the pointer will point to the end of the message ++ * and should not be used (except to retrieve the message pointer or to ++ * send the message) ++ ****************************************************************************** ++ */ ++static inline void *rwnx_msg_zalloc(lmac_msg_id_t const id, ++ lmac_task_id_t const dest_id, ++ lmac_task_id_t const src_id, ++ uint16_t const param_len) ++{ ++ struct lmac_msg *msg; ++ gfp_t flags; ++ ++ // if (is_non_blocking_msg(id) && (in_softirq()||in_atomic())) ++ flags = GFP_ATOMIC; ++ // else ++ // flags = GFP_KERNEL; ++ ++ msg = (struct lmac_msg *)kzalloc(sizeof(struct lmac_msg) + param_len, ++ flags); ++ if (msg == NULL) { ++ AICWFDBG(LOGERROR, "%s: msg allocation failed\n", __func__); ++ return NULL; ++ } ++ msg->id = id; ++ msg->dest_id = dest_id; ++ msg->src_id = src_id; ++ msg->param_len = param_len; ++ //printk("rwnx_msg_zalloc size=%d id=%d\n",msg->param_len,msg->id); ++ ++ return msg->param; ++} ++ ++static void rwnx_msg_free(struct rwnx_hw *rwnx_hw, const void *msg_params) ++{ ++ struct lmac_msg *msg = ++ container_of((void *)msg_params, struct lmac_msg, param); ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Free the message */ ++ kfree(msg); ++} ++ ++//void rwnx_pm_relax(struct aic_sdio_dev *sdiodev); ++//void rwnx_pm_stay_awake(struct aic_sdio_dev *sdiodev); ++ ++static int rwnx_send_msg(struct rwnx_hw *rwnx_hw, const void *msg_params, ++ int reqcfm, lmac_msg_id_t reqid, void *cfm) ++{ ++ struct lmac_msg *msg; ++ struct rwnx_cmd *cmd; ++ bool nonblock; ++ int ret = 0; ++ ++ //RWNX_DBG(RWNX_FN_ENTRY_STR); ++ AICWFDBG(LOGTRACE, ++ "%s (%d)%s reqcfm:%d in_irq:%d in_softirq:%d in_atomic:%d\r\n", ++ __func__, reqid, RWNX_ID2STR(reqid), reqcfm, (int)in_irq(), ++ (int)in_softirq(), (int)in_atomic()); ++ ++#ifdef AICWF_USB_SUPPORT ++ if (rwnx_hw->usbdev->state == USB_DOWN_ST) { ++ rwnx_msg_free(rwnx_hw, msg_params); ++ usb_err("bus is down\n"); ++ return 0; ++ } ++#endif ++#ifdef AICWF_SDIO_SUPPORT ++ rwnx_wakeup_lock(rwnx_hw->ws_tx); ++ if (rwnx_hw->sdiodev->bus_if->state == BUS_DOWN_ST) { ++ rwnx_msg_free(rwnx_hw, msg_params); ++ sdio_err("bus is down\n"); ++ rwnx_wakeup_unlock(rwnx_hw->ws_tx); ++ return 0; ++ } ++#endif ++ ++ msg = container_of((void *)msg_params, struct lmac_msg, param); ++ ++#if 0 ++ if (!test_bit(RWNX_DEV_STARTED, &rwnx_hw->drv_flags) && ++ reqid != DBG_MEM_READ_CFM && reqid != DBG_MEM_WRITE_CFM && ++ reqid != DBG_MEM_BLOCK_WRITE_CFM && reqid != DBG_START_APP_CFM && ++ reqid != MM_SET_RF_CALIB_CFM && reqid != MM_SET_RF_CONFIG_CFM && ++ reqid != MM_RESET_CFM && reqid != MM_VERSION_CFM && ++ reqid != MM_START_CFM && reqid != MM_SET_IDLE_CFM && ++ reqid != ME_CONFIG_CFM && reqid != MM_SET_PS_MODE_CFM && ++ reqid != ME_CHAN_CONFIG_CFM) { ++ printk(KERN_CRIT "%s: bypassing (RWNX_DEV_RESTARTING set) 0x%02x\n", ++ __func__, reqid); ++ kfree(msg); ++ return -EBUSY; ++ } ++#endif ++#if 0 ++ else if (!rwnx_hw->ipc_env) { ++ printk(KERN_CRIT "%s: bypassing (restart must have failed)\n", __func__); ++ kfree(msg); ++ return -EBUSY; ++ } ++#endif ++ ++ //nonblock = is_non_blocking_msg(msg->id); ++ nonblock = 0; ++ cmd = rwnx_cmd_malloc(); //kzalloc(sizeof(struct rwnx_cmd), nonblock ? GFP_ATOMIC : GFP_KERNEL); ++ cmd->result = -EINTR; ++ cmd->id = msg->id; ++ cmd->reqid = reqid; ++ cmd->a2e_msg = msg; ++ cmd->e2a_msg = cfm; ++ if (nonblock) ++ cmd->flags = RWNX_CMD_FLAG_NONBLOCK; ++ if (reqcfm) ++ cmd->flags |= RWNX_CMD_FLAG_REQ_CFM; ++ ++#if 0 ++ if (cfm != NULL) { ++ do { ++ if(rwnx_hw->cmd_mgr->state == RWNX_CMD_MGR_STATE_CRASHED) ++ break; ++ spin_lock_bh(&rwnx_hw->cmd_mgr->lock); ++ empty = list_empty(&rwnx_hw->cmd_mgr->cmds); ++ spin_unlock_bh(&rwnx_hw->cmd_mgr->lock); ++ if(!empty) { ++ 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 ++ } ++#endif ++ if (reqcfm) { ++ cmd->flags &= ++ ~RWNX_CMD_FLAG_WAIT_ACK; // we don't need ack any more ++ ret = rwnx_hw->cmd_mgr->queue(rwnx_hw->cmd_mgr, cmd); ++ } else { ++#ifdef AICWF_SDIO_SUPPORT ++ aicwf_set_cmd_tx((void *)(rwnx_hw->sdiodev), cmd->a2e_msg, ++ sizeof(struct lmac_msg) + ++ cmd->a2e_msg->param_len); ++#else ++ aicwf_set_cmd_tx((void *)(rwnx_hw->usbdev), cmd->a2e_msg, ++ sizeof(struct lmac_msg) + ++ cmd->a2e_msg->param_len); ++#endif ++ } ++ ++ if (!reqcfm || ret) ++ rwnx_cmd_free(cmd); //kfree(cmd); ++ ++ rwnx_wakeup_unlock(rwnx_hw->ws_tx); ++ return 0; ++} ++ ++static int rwnx_send_msg1(struct rwnx_hw *rwnx_hw, const void *msg_params, ++ int reqcfm, lmac_msg_id_t reqid, void *cfm, ++ bool defer) ++{ ++ struct lmac_msg *msg; ++ struct rwnx_cmd *cmd; ++ bool nonblock; ++ int ret = 0; ++ ++ // RWNX_DBG(RWNX_FN_ENTRY_STR); ++ printk("%s (%d)%s reqcfm:%d in_irq:%d in_softirq:%d in_atomic:%d\r\n", ++ __func__, reqid, RWNX_ID2STR(reqid), reqcfm, (int)in_irq(), ++ (int)in_softirq(), (int)in_atomic()); ++ ++ rwnx_wakeup_lock(rwnx_hw->ws_tx); ++ msg = container_of((void *)msg_params, struct lmac_msg, param); ++ ++ //nonblock = is_non_blocking_msg(msg->id); ++ nonblock = 0; ++ cmd = rwnx_cmd_malloc(); //kzalloc(sizeof(struct rwnx_cmd), nonblock ? GFP_ATOMIC : GFP_KERNEL); ++ cmd->result = -EINTR; ++ cmd->id = msg->id; ++ cmd->reqid = reqid; ++ cmd->a2e_msg = msg; ++ cmd->e2a_msg = cfm; ++ if (nonblock) ++ cmd->flags = RWNX_CMD_FLAG_NONBLOCK; ++ if (reqcfm) ++ cmd->flags |= RWNX_CMD_FLAG_REQ_CFM; ++ ++ if (reqcfm) { ++ cmd->flags &= ++ ~RWNX_CMD_FLAG_WAIT_ACK; // we don't need ack any more ++ if (!defer) ++ ret = rwnx_hw->cmd_mgr->queue(rwnx_hw->cmd_mgr, cmd); ++ else ++ ret = cmd_mgr_queue_force_defer(rwnx_hw->cmd_mgr, cmd); ++ } ++ ++ if (!reqcfm || ret) ++ rwnx_cmd_free(cmd); //kfree(cmd); ++ ++ if (!ret) ++ ret = cmd->result; ++ ++ rwnx_wakeup_unlock(rwnx_hw->ws_tx); ++ //return ret; ++ return 0; ++} ++ ++/****************************************************************************** ++ * Control messages handling functions (FULLMAC) ++ *****************************************************************************/ ++int rwnx_send_reset(struct rwnx_hw *rwnx_hw) ++{ ++ void *void_param; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* RESET REQ has no parameter */ ++ void_param = rwnx_msg_zalloc(MM_RESET_REQ, TASK_MM, DRV_TASK_ID, 0); ++ if (!void_param) ++ return -ENOMEM; ++ ++ return rwnx_send_msg(rwnx_hw, void_param, 1, MM_RESET_CFM, NULL); ++} ++ ++int rwnx_send_start(struct rwnx_hw *rwnx_hw) ++{ ++ struct mm_start_req *start_req_param; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the START REQ message */ ++ start_req_param = rwnx_msg_zalloc(MM_START_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_start_req)); ++ if (!start_req_param) ++ return -ENOMEM; ++ ++ /* Set parameters for the START message */ ++ memcpy(&start_req_param->phy_cfg, &rwnx_hw->phy.cfg, ++ sizeof(rwnx_hw->phy.cfg)); ++ start_req_param->uapsd_timeout = ++ (u32_l)rwnx_hw->mod_params->uapsd_timeout; ++ start_req_param->lp_clk_accuracy = ++ (u16_l)rwnx_hw->mod_params->lp_clk_ppm; ++ ++ /* Send the START REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, start_req_param, 1, MM_START_CFM, NULL); ++} ++ ++int rwnx_send_version_req(struct rwnx_hw *rwnx_hw, struct mm_version_cfm *cfm) ++{ ++ void *void_param; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* VERSION REQ has no parameter */ ++ void_param = rwnx_msg_zalloc(MM_VERSION_REQ, TASK_MM, DRV_TASK_ID, 0); ++ if (!void_param) ++ return -ENOMEM; ++ ++ return rwnx_send_msg(rwnx_hw, void_param, 1, MM_VERSION_CFM, cfm); ++} ++ ++int rwnx_send_add_if(struct rwnx_hw *rwnx_hw, const unsigned char *mac, ++ enum nl80211_iftype iftype, bool p2p, ++ struct mm_add_if_cfm *cfm) ++{ ++ struct mm_add_if_req *add_if_req_param; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the ADD_IF_REQ message */ ++ add_if_req_param = rwnx_msg_zalloc(MM_ADD_IF_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_add_if_req)); ++ if (!add_if_req_param) ++ return -ENOMEM; ++ ++ /* Set parameters for the ADD_IF_REQ message */ ++ memcpy(&(add_if_req_param->addr.array[0]), mac, ETH_ALEN); ++ switch (iftype) { ++#ifdef CONFIG_RWNX_FULLMAC ++ //case NL80211_IFTYPE_P2P_DEVICE: ++ case NL80211_IFTYPE_P2P_CLIENT: ++ add_if_req_param->p2p = true; ++ // no break ++#endif /* CONFIG_RWNX_FULLMAC */ ++ case NL80211_IFTYPE_STATION: ++ add_if_req_param->type = MM_STA; ++ break; ++ ++ case NL80211_IFTYPE_ADHOC: ++ add_if_req_param->type = MM_IBSS; ++ break; ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ case NL80211_IFTYPE_P2P_GO: ++ add_if_req_param->p2p = true; ++ // no break ++#endif /* CONFIG_RWNX_FULLMAC */ ++ case NL80211_IFTYPE_AP: ++ add_if_req_param->type = MM_AP; ++ break; ++ case NL80211_IFTYPE_MESH_POINT: ++ add_if_req_param->type = MM_MESH_POINT; ++ break; ++ case NL80211_IFTYPE_AP_VLAN: ++ return -1; ++ case NL80211_IFTYPE_MONITOR: ++ add_if_req_param->type = MM_MONITOR; ++ break; ++ default: ++ add_if_req_param->type = MM_STA; ++ break; ++ } ++ ++ /* Send the ADD_IF_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, add_if_req_param, 1, MM_ADD_IF_CFM, cfm); ++} ++ ++int rwnx_send_remove_if(struct rwnx_hw *rwnx_hw, u8 vif_index, bool defer) ++{ ++ struct mm_remove_if_req *remove_if_req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MM_REMOVE_IF_REQ message */ ++ remove_if_req = rwnx_msg_zalloc(MM_REMOVE_IF_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_remove_if_req)); ++ if (!remove_if_req) ++ return -ENOMEM; ++ ++ /* Set parameters for the MM_REMOVE_IF_REQ message */ ++ remove_if_req->inst_nbr = vif_index; ++ ++ /* Send the MM_REMOVE_IF_REQ message to LMAC FW */ ++ return rwnx_send_msg1(rwnx_hw, remove_if_req, 1, MM_REMOVE_IF_CFM, NULL, ++ defer); ++} ++ ++int rwnx_send_set_channel(struct rwnx_hw *rwnx_hw, int phy_idx, ++ struct mm_set_channel_cfm *cfm) ++{ ++ struct mm_set_channel_req *req; ++ enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20_NOHT; ++ u16 center_freq = 2412, center_freq1 = 2412, center_freq2 = 2412; ++ s8 tx_power = 0; ++ u8 flags = 0; ++ enum nl80211_band band = NL80211_BAND_2GHZ; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ if (phy_idx >= rwnx_hw->phy.cnt) ++ return -ENOTSUPP; ++ ++ req = rwnx_msg_zalloc(MM_SET_CHANNEL_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_set_channel_req)); ++ if (!req) ++ return -ENOMEM; ++ ++ if (phy_idx == 0) { ++#ifdef CONFIG_RWNX_FULLMAC ++ /* On FULLMAC only setting channel of secondary chain */ ++ wiphy_err(rwnx_hw->wiphy, ++ "Trying to set channel of primary chain"); ++ return 0; ++#endif /* CONFIG_RWNX_FULLMAC */ ++ } else { ++ struct rwnx_sec_phy_chan *chan = &rwnx_hw->phy.sec_chan; ++ width = chnl2bw[chan->type]; ++ band = chan->band; ++ center_freq = chan->prim20_freq; ++ center_freq1 = chan->center_freq1; ++ center_freq2 = chan->center_freq2; ++ flags = 0; ++ } ++ ++ req->chan.band = band; ++ req->chan.type = bw2chnl[width]; ++ req->chan.prim20_freq = center_freq; ++ req->chan.center1_freq = center_freq1; ++ req->chan.center2_freq = center_freq2; ++ req->chan.tx_power = tx_power; ++ req->chan.flags = flags; ++ req->index = phy_idx; ++ ++ if (rwnx_hw->phy.limit_bw) ++ limit_chan_bw(&req->chan.type, req->chan.prim20_freq, ++ &req->chan.center1_freq); ++ ++ RWNX_DBG("mac80211: freq=%d(c1:%d - c2:%d)/width=%d - band=%d\n" ++ " hw(%d): prim20=%d(c1:%d - c2:%d)/ type=%d - band=%d\n", ++ center_freq, center_freq1, center_freq2, width, band, phy_idx, ++ req->chan.prim20_freq, req->chan.center1_freq, ++ req->chan.center2_freq, req->chan.type, req->chan.band); ++ ++ /* Send the MM_SET_CHANNEL_REQ REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, MM_SET_CHANNEL_CFM, cfm); ++} ++ ++int rwnx_send_key_add(struct rwnx_hw *rwnx_hw, u8 vif_idx, u8 sta_idx, ++ bool pairwise, u8 *key, u8 key_len, u8 key_idx, ++ u8 cipher_suite, struct mm_key_add_cfm *cfm) ++{ ++ struct mm_key_add_req *key_add_req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MM_KEY_ADD_REQ message */ ++ key_add_req = rwnx_msg_zalloc(MM_KEY_ADD_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_key_add_req)); ++ if (!key_add_req) ++ return -ENOMEM; ++ ++ /* Set parameters for the MM_KEY_ADD_REQ message */ ++ if (sta_idx != 0xFF) { ++ /* Pairwise key */ ++ key_add_req->sta_idx = sta_idx; ++ } else { ++ /* Default key */ ++ key_add_req->sta_idx = sta_idx; ++ key_add_req->key_idx = ++ (u8_l)key_idx; /* only useful for default keys */ ++ } ++ key_add_req->pairwise = pairwise; ++ key_add_req->inst_nbr = vif_idx; ++ key_add_req->key.length = key_len; ++ memcpy(&(key_add_req->key.array[0]), key, key_len); ++ ++ key_add_req->cipher_suite = cipher_suite; ++ ++ RWNX_DBG("%s: sta_idx:%d key_idx:%d inst_nbr:%d cipher:%d key_len:%d\n", ++ __func__, key_add_req->sta_idx, key_add_req->key_idx, ++ key_add_req->inst_nbr, key_add_req->cipher_suite, ++ key_add_req->key.length); ++#if defined(CONFIG_RWNX_DBG) || defined(CONFIG_DYNAMIC_DEBUG) ++ print_hex_dump_bytes("key: ", DUMP_PREFIX_OFFSET, ++ key_add_req->key.array, key_add_req->key.length); ++#endif ++ ++ /* Send the MM_KEY_ADD_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, key_add_req, 1, MM_KEY_ADD_CFM, cfm); ++} ++ ++int rwnx_send_key_del(struct rwnx_hw *rwnx_hw, uint8_t hw_key_idx) ++{ ++ struct mm_key_del_req *key_del_req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MM_KEY_DEL_REQ message */ ++ key_del_req = rwnx_msg_zalloc(MM_KEY_DEL_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_key_del_req)); ++ if (!key_del_req) ++ return -ENOMEM; ++ ++ /* Set parameters for the MM_KEY_DEL_REQ message */ ++ key_del_req->hw_key_idx = hw_key_idx; ++ ++ /* Send the MM_KEY_DEL_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, key_del_req, 1, MM_KEY_DEL_CFM, NULL); ++} ++ ++int rwnx_send_bcn(struct rwnx_hw *rwnx_hw, u8 *buf, u8 vif_idx, u16 bcn_len) ++{ ++ struct apm_set_bcn_ie_req *bcn_ie_req; ++ bcn_ie_req = ++ rwnx_msg_zalloc(APM_SET_BEACON_IE_REQ, TASK_APM, DRV_TASK_ID, ++ sizeof(struct apm_set_bcn_ie_req)); ++ if (!bcn_ie_req) ++ return -ENOMEM; ++ ++ bcn_ie_req->vif_idx = vif_idx; ++ bcn_ie_req->bcn_ie_len = bcn_len; ++ memcpy(bcn_ie_req->bcn_ie, (u8 *)buf, bcn_len); ++ kfree(buf); ++ ++ return rwnx_send_msg(rwnx_hw, bcn_ie_req, 1, APM_SET_BEACON_IE_CFM, ++ NULL); ++} ++ ++int rwnx_send_bcn_change(struct rwnx_hw *rwnx_hw, u8 vif_idx, u32 bcn_addr, ++ u16 bcn_len, u16 tim_oft, u16 tim_len, u16 *csa_oft) ++{ ++ struct mm_bcn_change_req *req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MM_BCN_CHANGE_REQ message */ ++ req = rwnx_msg_zalloc(MM_BCN_CHANGE_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_bcn_change_req)); ++ if (!req) ++ return -ENOMEM; ++ ++ /* Set parameters for the MM_BCN_CHANGE_REQ message */ ++ req->bcn_ptr = bcn_addr; ++ req->bcn_len = bcn_len; ++ req->tim_oft = tim_oft; ++ req->tim_len = tim_len; ++ req->inst_nbr = vif_idx; ++ ++ if (csa_oft) { ++ int i; ++ for (i = 0; i < BCN_MAX_CSA_CPT; i++) { ++ req->csa_oft[i] = csa_oft[i]; ++ } ++ } ++ ++ /* Send the MM_BCN_CHANGE_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, MM_BCN_CHANGE_CFM, NULL); ++} ++ ++int rwnx_send_roc(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif, ++ 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; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Create channel definition structure */ ++ cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT); ++ ++ /* Build the MM_REMAIN_ON_CHANNEL_REQ message */ ++ req = rwnx_msg_zalloc(MM_REMAIN_ON_CHANNEL_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_remain_on_channel_req)); ++ if (!req) ++ return -ENOMEM; ++ ++ /* Set parameters for the MM_REMAIN_ON_CHANNEL_REQ message */ ++ req->op_code = MM_ROC_OP_START; ++ req->vif_index = vif->vif_index; ++ req->duration_ms = duration; ++ req->band = chan->band; ++ req->type = bw2chnl[chandef.width]; ++ req->prim20_freq = chan->center_freq; ++ req->center1_freq = chandef.center_freq1; ++ req->center2_freq = chandef.center_freq2; ++ 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, ++ roc_cfm); ++} ++ ++int rwnx_send_cancel_roc(struct rwnx_hw *rwnx_hw) ++{ ++ struct mm_remain_on_channel_req *req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MM_REMAIN_ON_CHANNEL_REQ message */ ++ req = rwnx_msg_zalloc(MM_REMAIN_ON_CHANNEL_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_remain_on_channel_req)); ++ if (!req) ++ return -ENOMEM; ++ ++ /* Set parameters for the MM_REMAIN_ON_CHANNEL_REQ message */ ++ req->op_code = MM_ROC_OP_CANCEL; ++ ++ /* 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); ++} ++ ++int rwnx_send_set_power(struct rwnx_hw *rwnx_hw, u8 vif_idx, s8 pwr, ++ struct mm_set_power_cfm *cfm) ++{ ++ struct mm_set_power_req *req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MM_SET_POWER_REQ message */ ++ req = rwnx_msg_zalloc(MM_SET_POWER_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_set_power_req)); ++ if (!req) ++ return -ENOMEM; ++ ++ /* Set parameters for the MM_SET_POWER_REQ message */ ++ req->inst_nbr = vif_idx; ++ req->power = pwr; ++ ++ /* Send the MM_SET_POWER_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, MM_SET_POWER_CFM, cfm); ++} ++ ++int rwnx_send_set_edca(struct rwnx_hw *rwnx_hw, u8 hw_queue, u32 param, ++ bool uapsd, u8 inst_nbr) ++{ ++ struct mm_set_edca_req *set_edca_req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MM_SET_EDCA_REQ message */ ++ set_edca_req = rwnx_msg_zalloc(MM_SET_EDCA_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_set_edca_req)); ++ if (!set_edca_req) ++ return -ENOMEM; ++ ++ /* Set parameters for the MM_SET_EDCA_REQ message */ ++ set_edca_req->ac_param = param; ++ set_edca_req->uapsd = uapsd; ++ set_edca_req->hw_queue = hw_queue; ++ set_edca_req->inst_nbr = inst_nbr; ++ ++ /* Send the MM_SET_EDCA_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, set_edca_req, 1, MM_SET_EDCA_CFM, NULL); ++} ++ ++#ifdef CONFIG_RWNX_P2P_DEBUGFS ++int rwnx_send_p2p_oppps_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif, ++ u8 ctw, struct mm_set_p2p_oppps_cfm *cfm) ++{ ++ struct mm_set_p2p_oppps_req *p2p_oppps_req; ++ int error; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MM_SET_P2P_OPPPS_REQ message */ ++ p2p_oppps_req = ++ rwnx_msg_zalloc(MM_SET_P2P_OPPPS_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_set_p2p_oppps_req)); ++ ++ if (!p2p_oppps_req) { ++ return -ENOMEM; ++ } ++ ++ /* Fill the message parameters */ ++ p2p_oppps_req->vif_index = rwnx_vif->vif_index; ++ p2p_oppps_req->ctwindow = ctw; ++ ++ /* Send the MM_P2P_OPPPS_REQ message to LMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, p2p_oppps_req, 1, MM_SET_P2P_OPPPS_CFM, ++ cfm); ++ ++ return error; ++} ++ ++int rwnx_send_p2p_noa_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif, ++ int count, int interval, int duration, bool dyn_noa, ++ struct mm_set_p2p_noa_cfm *cfm) ++{ ++ struct mm_set_p2p_noa_req *p2p_noa_req; ++ int error; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Param check */ ++ if (count > 255) ++ count = 255; ++ ++ if (duration >= interval) { ++ dev_err(rwnx_hw->dev, ++ "Invalid p2p NOA config: interval=%d <= duration=%d\n", ++ interval, duration); ++ return -EINVAL; ++ } ++ ++ /* Build the MM_SET_P2P_NOA_REQ message */ ++ p2p_noa_req = rwnx_msg_zalloc(MM_SET_P2P_NOA_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_set_p2p_noa_req)); ++ ++ if (!p2p_noa_req) { ++ return -ENOMEM; ++ } ++ ++ /* Fill the message parameters */ ++ p2p_noa_req->vif_index = rwnx_vif->vif_index; ++ p2p_noa_req->noa_inst_nb = 0; ++ p2p_noa_req->count = count; ++ ++ if (count) { ++ p2p_noa_req->duration_us = duration * 1024; ++ p2p_noa_req->interval_us = interval * 1024; ++ p2p_noa_req->start_offset = (interval - duration - 10) * 1024; ++ p2p_noa_req->dyn_noa = dyn_noa; ++ } ++ ++ /* Send the MM_SET_2P_NOA_REQ message to LMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, p2p_noa_req, 1, MM_SET_P2P_NOA_CFM, cfm); ++ ++ return error; ++} ++#endif /* CONFIG_RWNX_P2P_DEBUGFS */ ++ ++#ifdef AICWF_ARP_OFFLOAD ++int rwnx_send_arpoffload_en_req(struct rwnx_hw *rwnx_hw, ++ struct rwnx_vif *rwnx_vif, u32_l ipaddr, ++ u8_l enable) ++{ ++ struct mm_set_arpoffload_en_req *arp_offload_req; ++ int error; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MM_SET_P2P_NOA_REQ message */ ++ arp_offload_req = ++ rwnx_msg_zalloc(MM_SET_ARPOFFLOAD_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_set_arpoffload_en_req)); ++ ++ if (!arp_offload_req) { ++ return -ENOMEM; ++ } ++ ++ /* Fill the message parameters */ ++ arp_offload_req->enable = enable; ++ arp_offload_req->vif_idx = rwnx_vif->vif_index; ++ arp_offload_req->ipaddr = ipaddr; ++ ++ /* Send the MM_ARPOFFLOAD_EN_REQ message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, arp_offload_req, 1, ++ MM_SET_ARPOFFLOAD_CFM, NULL); ++ ++ return error; ++} ++#endif ++ ++int rwnx_send_disable_agg_req(struct rwnx_hw *rwnx_hw, u8_l agg_disable, ++ u8_l agg_disable_rx, u8_l sta_idx) ++{ ++ struct mm_set_agg_disable_req *req; ++ int error; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MM_SET_AGG_DISABLE_REQ message */ ++ req = rwnx_msg_zalloc(MM_SET_AGG_DISABLE_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_set_agg_disable_req)); ++ ++ if (!req) { ++ return -ENOMEM; ++ } ++ ++ req->disable = agg_disable; ++ req->staidx = sta_idx; ++ req->disable_rx = agg_disable_rx; ++ ++ /* Send the MM_SET_AGG_DISABLE_REQ message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, req, 1, MM_SET_AGG_DISABLE_CFM, NULL); ++ ++ return (error); ++}; ++ ++int rwnx_send_coex_req(struct rwnx_hw *rwnx_hw, u8_l disable_coexnull, ++ u8_l enable_nullcts) ++{ ++ struct mm_set_coex_req *coex_req; ++ int error; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MM_SET_COEX_REQ message */ ++ coex_req = rwnx_msg_zalloc(MM_SET_COEX_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_set_coex_req)); ++ ++ if (!coex_req) { ++ return -ENOMEM; ++ } ++ ++ coex_req->bt_on = 1; ++ coex_req->disable_coexnull = disable_coexnull; ++ coex_req->enable_nullcts = enable_nullcts; ++ coex_req->enable_periodic_timer = 0; ++ coex_req->coex_timeslot_set = 0; ++ ++ /* Send the MM_SET_COEX_REQ message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, coex_req, 1, MM_SET_COEX_CFM, NULL); ++ ++ return error; ++}; ++ ++int rwnx_send_rf_config_req(struct rwnx_hw *rwnx_hw, u8_l ofst, u8_l sel, ++ u8_l *tbl, u16_l len) ++{ ++ struct mm_set_rf_config_req *rf_config_req; ++ int error; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MM_SET_RF_CONFIG_REQ message */ ++ rf_config_req = ++ rwnx_msg_zalloc(MM_SET_RF_CONFIG_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_set_rf_config_req)); ++ ++ if (!rf_config_req) { ++ return -ENOMEM; ++ } ++ ++ rf_config_req->table_sel = sel; ++ rf_config_req->table_ofst = ofst; ++ rf_config_req->table_num = 16; ++ rf_config_req->deft_page = 0; ++ ++ memcpy(rf_config_req->data, tbl, len); ++ ++ /* Send the MM_SET_RF_CONFIG_REQ message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, rf_config_req, 1, MM_SET_RF_CONFIG_CFM, ++ NULL); ++ ++ return (error); ++} ++ ++int rwnx_send_rf_calib_req(struct rwnx_hw *rwnx_hw, ++ struct mm_set_rf_calib_cfm *cfm) ++{ ++ struct mm_set_rf_calib_req *rf_calib_req; ++ xtal_cap_conf_t xtal_cap = { ++ 0, ++ }; ++ int error; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MM_SET_P2P_NOA_REQ message */ ++ rf_calib_req = ++ rwnx_msg_zalloc(MM_SET_RF_CALIB_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_set_rf_calib_req)); ++ ++ if (!rf_calib_req) { ++ return -ENOMEM; ++ } ++ ++ if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8801) { ++ rf_calib_req->cal_cfg_24g = 0xbf; ++ rf_calib_req->cal_cfg_5g = 0x3f; ++ } else if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ rf_calib_req->cal_cfg_24g = 0x0f8f; ++ rf_calib_req->cal_cfg_5g = 0; ++ } else if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ rf_calib_req->cal_cfg_24g = 0x0f8f; ++ rf_calib_req->cal_cfg_5g = 0x0f0f; ++ } ++ ++ rf_calib_req->param_alpha = 0x0c34c008; ++ rf_calib_req->bt_calib_en = 0; ++ rf_calib_req->bt_calib_param = 0x264203; ++ ++ get_userconfig_xtal_cap(&xtal_cap); ++ ++ if (xtal_cap.enable) { ++ printk("user xtal cap: %d, cap_fine: %d\n", xtal_cap.xtal_cap, ++ xtal_cap.xtal_cap_fine); ++ rf_calib_req->xtal_cap = xtal_cap.xtal_cap; ++ rf_calib_req->xtal_cap_fine = xtal_cap.xtal_cap_fine; ++ } else { ++ 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); ++ ++ return error; ++}; ++ ++int rwnx_send_get_macaddr_req(struct rwnx_hw *rwnx_hw, ++ struct mm_get_mac_addr_cfm *cfm) ++{ ++ struct mm_get_mac_addr_req *get_macaddr_req; ++ int error; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MM_GET_MAC_ADDR_REQ message */ ++ get_macaddr_req = ++ rwnx_msg_zalloc(MM_GET_MAC_ADDR_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_get_mac_addr_req)); ++ ++ if (!get_macaddr_req) { ++ return -ENOMEM; ++ } ++ ++ get_macaddr_req->get = 1; ++ ++ /* Send the MM_GET_MAC_ADDR_REQ message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, get_macaddr_req, 1, MM_GET_MAC_ADDR_CFM, ++ cfm); ++ ++ return error; ++}; ++ ++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_info_req *get_info_req; ++ int error; ++ ++ /* 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_info_req) { ++ return -ENOMEM; ++ } ++ ++ get_info_req->sta_idx = sta_idx; ++ ++ /* 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; ++} ++ ++#ifdef CONFIG_TEMP_COMP ++ ++int rwnx_send_get_temp_req(struct rwnx_hw *rwnx_hw, ++ struct mm_set_vendor_swconfig_cfm *cfm) ++{ ++ struct mm_set_vendor_swconfig_req *req; ++ int ret; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the TEMP_COMP_GET_REQ message */ ++ req = rwnx_msg_zalloc(MM_SET_VENDOR_SWCONFIG_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_set_vendor_swconfig_req)); ++ if (!req) { ++ AICWFDBG(LOGINFO, "%s msg_alloc fail\n", __func__); ++ return -ENOMEM; ++ } ++ req->swconfig_id = TEMP_COMP_GET_REQ; ++ ++ ret = rwnx_send_msg(rwnx_hw, req, 1, MM_SET_VENDOR_SWCONFIG_CFM, cfm); ++ if (!ret) ++ AICWFDBG(LOGINFO, "status=%d, temp=%d\n", ++ cfm->temp_comp_get_cfm.status, ++ cfm->temp_comp_get_cfm.degree); ++ else { ++ AICWFDBG(LOGINFO, "%s msg_fail\n", __func__); ++ return ret; ++ } ++ //rwnx_hw->started_jiffies = jiffies; ++ rwnx_hw->temp = cfm->temp_comp_get_cfm.degree; ++ ++ return ret; ++} ++ ++int rwnx_send_set_temp_comp_req(struct rwnx_hw *rwnx_hw, ++ struct mm_set_vendor_swconfig_cfm *cfm) ++{ ++ struct mm_set_vendor_swconfig_req *req; ++ int ret; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ /* Build the TEMP_COMP_SET_REQ message */ ++ req = rwnx_msg_zalloc(MM_SET_VENDOR_SWCONFIG_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_set_vendor_swconfig_req)); ++ if (!req) { ++ printk("%s msg_alloc fail\n", __func__); ++ return -ENOMEM; ++ } ++ req->swconfig_id = TEMP_COMP_SET_REQ; ++ req->temp_comp_set_req.enable = 1; ++ req->temp_comp_set_req.tmr_period_ms = 15 * 1000; ++ ++ ret = rwnx_send_msg(rwnx_hw, req, 1, MM_SET_VENDOR_SWCONFIG_CFM, cfm); ++ if (!ret) ++ printk("temp_comp status: %d\n", cfm->temp_comp_set_cfm.status); ++ else { ++ printk("%s msg_fail\n", __func__); ++ return ret; ++ } ++ return ret; ++} ++#endif ++ ++int rwnx_send_vendor_hwconfig_req(struct rwnx_hw *rwnx_hw, uint32_t hwconfig_id, ++ int32_t *param, int32_t *param_out) ++{ ++ struct mm_set_acs_txop_req *req0; ++ struct mm_set_channel_access_req *req1; ++ struct mm_set_mac_timescale_req *req2; ++ struct mm_set_cca_threshold_req *req3; ++ struct mm_set_bwmode_req *req4; ++ struct mm_set_ap_ps_level_req *req5 = NULL; ++ struct mm_set_customized_freq_req *req6; ++ ++ int error = 0; ++ int i; ++ ++ switch (hwconfig_id) { ++ case ACS_TXOP_REQ: ++ /* Build the ACS_TXOP_REQ message */ ++ req0 = rwnx_msg_zalloc(MM_SET_VENDOR_HWCONFIG_REQ, TASK_MM, ++ DRV_TASK_ID, ++ sizeof(struct mm_set_acs_txop_req)); ++ if (!req0) ++ return -ENOMEM; ++ req0->hwconfig_id = hwconfig_id; ++ req0->txop_be = param[0]; ++ req0->txop_bk = param[1]; ++ req0->txop_vi = param[2]; ++ req0->txop_vo = param[3]; ++ printk("set_acs_txop_req: be: %x,bk: %x,vi: %x,vo: %x\n", ++ req0->txop_be, req0->txop_bk, req0->txop_vi, ++ req0->txop_vo); ++ /* Send the MM_SET_VENDOR_HWCONFIG_CFM message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, req0, 1, ++ MM_SET_VENDOR_HWCONFIG_CFM, NULL); ++ break; ++ ++ case CHANNEL_ACCESS_REQ: ++ /* Build the CHANNEL_ACCESS_REQ message */ ++ req1 = rwnx_msg_zalloc( ++ MM_SET_VENDOR_HWCONFIG_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_set_channel_access_req)); ++ if (!req1) ++ return -ENOMEM; ++ req1->hwconfig_id = hwconfig_id; ++ req1->edca[0] = param[0]; ++ req1->edca[1] = param[1]; ++ req1->edca[2] = param[2]; ++ req1->edca[3] = param[3]; ++ req1->vif_idx = param[4]; ++ req1->retry_cnt = param[5]; ++ req1->rts_en = param[6]; ++ req1->long_nav_en = param[7]; ++ req1->cfe_en = param[8]; ++ req1->rc_retry_cnt[0] = param[9]; ++ req1->rc_retry_cnt[1] = param[10]; ++ req1->rc_retry_cnt[2] = param[11]; ++ req1->ccademod_th = param[12]; ++ req1->remove_1m2m = param[13]; ++ printk("set_channel_access_req:edca[]= %x %x %x %x\nvif_idx: %x, retry_cnt: %x, rts_en: %x, long_nav_en: %x, cfe_en: %x, rc_retry_cnt: %x:%x:%x, ccademod_th = %d remove_1m2m = %x\n", ++ req1->edca[0], req1->edca[1], req1->edca[2], ++ req1->edca[3], req1->vif_idx, req1->retry_cnt, ++ req1->rts_en, req1->long_nav_en, req1->cfe_en, ++ req1->rc_retry_cnt[0], req1->rc_retry_cnt[1], ++ req1->rc_retry_cnt[2], req1->ccademod_th, ++ req1->remove_1m2m); ++ /* Send the MM_SET_VENDOR_HWCONFIG_CFM message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, req1, 1, ++ MM_SET_VENDOR_HWCONFIG_CFM, NULL); ++ break; ++ ++ case MAC_TIMESCALE_REQ: ++ /* Build the MAC_TIMESCALE_REQ message */ ++ req2 = rwnx_msg_zalloc(MM_SET_VENDOR_HWCONFIG_REQ, TASK_MM, ++ DRV_TASK_ID, ++ sizeof(struct mm_set_mac_timescale_req)); ++ if (!req2) ++ return -ENOMEM; ++ req2->hwconfig_id = hwconfig_id; ++ req2->sifsA_time = param[0]; ++ req2->sifsB_time = param[1]; ++ req2->slot_time = param[2]; ++ req2->rx_startdelay_ofdm = param[3]; ++ req2->rx_startdelay_long = param[4]; ++ req2->rx_startdelay_short = param[5]; ++ printk("set_mac_timescale_req:sifsA_time: %x, sifsB_time: %x, slot_time: %x, rx_startdelay ofdm:%x long %x short %x\n", ++ req2->sifsA_time, req2->sifsB_time, req2->slot_time, ++ req2->rx_startdelay_ofdm, req2->rx_startdelay_long, ++ req2->rx_startdelay_short); ++ /* Send the MM_SET_VENDOR_HWCONFIG_CFM message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, req2, 1, ++ MM_SET_VENDOR_HWCONFIG_CFM, NULL); ++ break; ++ ++ case CCA_THRESHOLD_REQ: ++ /* Build the CCA_THRESHOLD_REQ message */ ++ req3 = rwnx_msg_zalloc(MM_SET_VENDOR_HWCONFIG_REQ, TASK_MM, ++ DRV_TASK_ID, ++ sizeof(struct mm_set_cca_threshold_req)); ++ if (!req3) ++ return -ENOMEM; ++ req3->hwconfig_id = hwconfig_id; ++ req3->auto_cca_en = param[0]; ++ req3->cca20p_rise_th = param[1]; ++ req3->cca20s_rise_th = param[2]; ++ req3->cca20p_fall_th = param[3]; ++ req3->cca20s_fall_th = param[4]; ++ printk("cca_threshold_req: auto_cca_en:%d\ncca20p_rise_th = %d\ncca20s_rise_th = %d\ncca20p_fall_th = %d\ncca20s_fall_th = %d\n", ++ req3->auto_cca_en, req3->cca20p_rise_th, ++ req3->cca20s_rise_th, req3->cca20p_fall_th, ++ req3->cca20s_fall_th); ++ /* Send the MM_SET_VENDOR_HWCONFIG_CFM message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, req3, 1, ++ MM_SET_VENDOR_HWCONFIG_CFM, NULL); ++ break; ++ case BWMODE_REQ: ++ /* Build the SET_BWMODE_REQ message */ ++ req4 = rwnx_msg_zalloc(MM_SET_VENDOR_HWCONFIG_REQ, TASK_MM, ++ DRV_TASK_ID, ++ sizeof(struct mm_set_bwmode_req)); ++ if (!req4) ++ return -ENOMEM; ++ req4->hwconfig_id = hwconfig_id; ++ req4->bwmode = param[0]; ++ printk("bwmode :%d\n", req4->bwmode); ++ /* Send the MM_SET_VENDOR_HWCONFIG_CFM message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, req4, 1, ++ MM_SET_VENDOR_HWCONFIG_CFM, NULL); ++ break; ++ case CHIP_TEMP_GET_REQ: ++ if ((rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DC) || ++ (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DW)) { ++ struct mm_get_chip_temp_req *req; ++ struct mm_set_vendor_hwconfig_cfm cfm = { ++ 0, ++ }; ++ /* Build the CHIP_TEMP_GET_REQ message */ ++ req = rwnx_msg_zalloc( ++ MM_SET_VENDOR_HWCONFIG_REQ, TASK_MM, ++ DRV_TASK_ID, ++ sizeof(struct mm_get_chip_temp_req)); ++ if (!req) ++ return -ENOMEM; ++ req->hwconfig_id = hwconfig_id; ++ /* Send the MM_SET_VENDOR_HWCONFIG_REQ message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, req, 1, ++ MM_SET_VENDOR_HWCONFIG_CFM, &cfm); ++ if (!error) { ++ if (param_out) { ++ param_out[0] = ++ (int32_t)cfm.chip_temp_cfm ++ .degree; ++ } ++ printk("get_chip_temp degree=%d\n", ++ cfm.chip_temp_cfm.degree); ++ } else { ++ printk("get_chip_temp err=%d\n", error); ++ } ++ } ++ break; ++ case AP_PS_LEVEL_SET_REQ: ++ /* ++ AP_PS_CLK_1 = 1, // 3:7 -> active 3, doze 7 ++ AP_PS_CLK_2, // 5:5 -> active 5, doze 5 ++ AP_PS_CLK_3, // 7:3 -> active 7, doze 3 ++ AP_PS_CLK_4, // 8:2 -> active 8, doze 2 ++ AP_PS_CLK_5, // 9:1 -> active 9, doze 1 ++ */ ++ /* Build the MM_SET_VENDOR_HWCONFIG_REQ message */ ++ req5 = rwnx_msg_zalloc(MM_SET_VENDOR_HWCONFIG_REQ, TASK_MM, ++ DRV_TASK_ID, ++ sizeof(struct mm_set_ap_ps_level_req)); ++ if (!req5) { ++ return -ENOMEM; ++ } ++ req5->hwconfig_id = hwconfig_id; ++ req5->ap_ps_level = param[0]; ++ ++ /* Send the MM_GET_MAC_ADDR_REQ message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, req5, 1, ++ MM_SET_VENDOR_HWCONFIG_CFM, NULL); ++ if (!error) ++ printk("set ap_ps_level=%d \n", param[0]); ++ break; ++ ++ case CUSTOMIZED_FREQ_REQ: ++ /* Build the CUSTOMIZED_FREQ_REQ message */ ++ req6 = rwnx_msg_zalloc( ++ MM_SET_VENDOR_HWCONFIG_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_set_customized_freq_req)); ++ if (!req6) ++ return -ENOMEM; ++ req5->hwconfig_id = hwconfig_id; ++ for (i = 0; i < 4; i++) { ++ req6->raw_freq[i] = param[i]; ++ req6->map_freq[i] = param[i + 4]; ++ } ++ printk("customized_freq_req: raw_freq[ %d %d %d %d ], map_freq[ %d %d %d %d]\n", ++ param[0], param[1], param[2], param[3], param[4], ++ param[5], param[6], param[7]); ++ /* Send the MM_SET_VENDOR_HWCONFIG_CFM message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, req5, 1, ++ MM_SET_VENDOR_HWCONFIG_CFM, NULL); ++ ++ break; ++ default: ++ return -ENOMEM; ++ } ++ return error; ++} ++ ++int rwnx_send_vendor_swconfig_req(struct rwnx_hw *rwnx_hw, uint32_t swconfig_id, ++ int32_t *param_in, int32_t *param_out) ++{ ++ struct mm_set_vendor_swconfig_req *req; ++ struct mm_set_vendor_swconfig_cfm cfm = { ++ 0, ++ }; ++ int error; ++ ++ req = rwnx_msg_zalloc(MM_SET_VENDOR_SWCONFIG_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_set_vendor_swconfig_req)); ++ if (!req) { ++ return -ENOMEM; ++ } ++ req->swconfig_id = swconfig_id; ++ ++ switch (swconfig_id) { ++ case BCN_CFG_REQ: ++ /* Build the BCN_CFG_REQ message */ ++ req->bcn_cfg_req.tim_bcmc_ignored_enable = (bool_l)param_in[0]; ++ printk("bcn_cfg_req: tim_bcmc_ignd=%d\n", ++ req->bcn_cfg_req.tim_bcmc_ignored_enable); ++ /* Send the MM_SET_VENDOR_SWCONFIG_REQ message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, req, 1, ++ MM_SET_VENDOR_SWCONFIG_CFM, &cfm); ++ if (!error) { ++ param_out[0] = ++ (int32_t)cfm.bcn_cfg_cfm.tim_bcmc_ignored_status; ++ printk("status=%d\n", ++ cfm.bcn_cfg_cfm.tim_bcmc_ignored_status); ++ } ++ break; ++ ++ case TEMP_COMP_SET_REQ: ++ /* Build the TEMP_COMP_SET_REQ message */ ++ req->temp_comp_set_req.enable = (u8_l)param_in[0]; ++ req->temp_comp_set_req.tmr_period_ms = (u32_l)param_in[1]; ++ printk("temp_comp_set_req: en=%d, tmr=%x\n", ++ req->temp_comp_set_req.enable, ++ req->temp_comp_set_req.tmr_period_ms); ++ /* Send the MM_SET_VENDOR_SWCONFIG_REQ message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, req, 1, ++ MM_SET_VENDOR_SWCONFIG_CFM, &cfm); ++ if (!error) { ++ param_out[0] = (int32_t)cfm.temp_comp_set_cfm.status; ++ printk("status=%d\n", cfm.temp_comp_set_cfm.status); ++ } ++ break; ++ ++ case TEMP_COMP_GET_REQ: ++ printk("temp_comp_get_req\n"); ++ /* Send the MM_SET_VENDOR_SWCONFIG_REQ message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, req, 1, ++ MM_SET_VENDOR_SWCONFIG_CFM, &cfm); ++ if (!error) { ++ param_out[0] = (int32_t)cfm.temp_comp_get_cfm.status; ++ param_out[1] = (int32_t)cfm.temp_comp_get_cfm.degree; ++ printk("status=%d, degree=%d\n", ++ cfm.temp_comp_get_cfm.status, ++ cfm.temp_comp_get_cfm.degree); ++ } ++ break; ++ ++ case EXT_FLAGS_SET_REQ: ++ /* Build the EXT_FLAGS_SET_REQ message */ ++ req->ext_flags_set_req.user_flags = (u32_l)param_in[0]; ++ printk("ext_flags_set_req: flags=%x\n", ++ req->ext_flags_set_req.user_flags); ++ /* Send the MM_SET_VENDOR_SWCONFIG_REQ message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, req, 1, ++ MM_SET_VENDOR_SWCONFIG_CFM, &cfm); ++ if (!error) { ++ param_out[0] = ++ (uint32_t)cfm.ext_flags_set_cfm.user_flags; ++ printk("cfm flags=%x\n", ++ cfm.ext_flags_set_cfm.user_flags); ++ } ++ break; ++ ++ case EXT_FLAGS_GET_REQ: ++ /* Build the EXT_FLAGS_GET_REQ message */ ++ printk("ext_flags_get_req\n"); ++ /* Send the MM_SET_VENDOR_SWCONFIG_REQ message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, req, 1, ++ MM_SET_VENDOR_SWCONFIG_CFM, &cfm); ++ if (!error) { ++ param_out[0] = ++ (uint32_t)cfm.ext_flags_get_cfm.user_flags; ++ printk("cfm flags=%x\n", ++ cfm.ext_flags_get_cfm.user_flags); ++ } ++ break; ++ ++ case EXT_FLAGS_MASK_SET_REQ: ++ /* Build the EXT_FLAGS_MASK_SET_REQ message */ ++ req->ext_flags_mask_set_req.user_flags_mask = ++ (u32_l)param_in[0]; ++ req->ext_flags_mask_set_req.user_flags_val = (u32_l)param_in[1]; ++ printk("ext_flags_mask_set_req: flags mask=0x%x, val=0x%x\n", ++ req->ext_flags_mask_set_req.user_flags_mask, ++ req->ext_flags_mask_set_req.user_flags_val); ++ /* Send the MM_SET_VENDOR_SWCONFIG_REQ message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, req, 1, ++ MM_SET_VENDOR_SWCONFIG_CFM, &cfm); ++ if (!error) { ++ param_out[0] = ++ (uint32_t)cfm.ext_flags_mask_set_cfm.user_flags; ++ printk("cfm flags=%x\n", ++ cfm.ext_flags_mask_set_cfm.user_flags); ++ } ++ break; ++ ++ default: ++ error = -ENOMEM; ++ break; ++ } ++ ++ return error; ++} ++ ++int rwnx_send_mask_set_ext_flags_req(struct rwnx_hw *rwnx_hw, ++ uint32_t flags_mask, uint32_t flags_val, ++ struct mm_set_vendor_swconfig_cfm *cfm) ++{ ++ struct mm_set_vendor_swconfig_req *req; ++ int ret; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ /* Build the REQ message */ ++ req = rwnx_msg_zalloc(MM_SET_VENDOR_SWCONFIG_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_set_vendor_swconfig_req)); ++ if (!req) { ++ AICWFDBG(LOGERROR, "%s msg_alloc fail\n", __func__); ++ return -ENOMEM; ++ } ++ req->swconfig_id = EXT_FLAGS_MASK_SET_REQ; ++ req->ext_flags_mask_set_req.user_flags_mask = (u32_l)flags_mask; ++ req->ext_flags_mask_set_req.user_flags_val = (u32_l)flags_val; ++ ++ ret = rwnx_send_msg(rwnx_hw, req, 1, MM_SET_VENDOR_SWCONFIG_CFM, cfm); ++ if (!ret) { ++ AICWFDBG(LOGINFO, "curr ext_flags=%x\n", ++ cfm->ext_flags_mask_set_cfm.user_flags); ++ } else { ++ AICWFDBG(LOGERROR, "%s send_msg_fail\n", __func__); ++ return ret; ++ } ++ return ret; ++} ++ ++#ifdef CONFIG_SDIO_BT ++int rwnx_sdio_bt_send_req(struct rwnx_hw *rwnx_hw, uint32_t len, ++ struct sk_buff *skb) ++{ ++ struct mm_bt_send_req *req; ++ struct mm_bt_send_cfm cfm; ++ int error; ++ ++ if (testmode) { ++ AICWFDBG(LOGERROR, "%s testmode can not send\n", __func__); ++ return 0; ++ } ++ cfm.status = 0; ++ req = rwnx_msg_zalloc(TDLS_SDIO_BT_SEND_REQ, TASK_TDLS, DRV_TASK_ID, ++ sizeof(struct mm_bt_send_req)); ++ ++ if (!req) { ++ return -ENOMEM; ++ } ++ ++ req->data_len = len; ++ memcpy(req->bt_data, skb->data, len); ++ ++ error = rwnx_send_msg(rwnx_hw, req, 1, TDLS_SDIO_BT_SEND_CFM, &cfm); ++ if (!cfm.status) { ++ printk("bt send no cfm"); ++ } ++ ++ return error; ++} ++#endif ++ ++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_lvl_req(struct rwnx_hw *rwnx_hw) ++{ ++ struct mm_set_txpwr_lvl_req *txpwr_lvl_req; ++ txpwr_lvl_conf_v2_t txpwr_lvl_v2_tmp; ++ txpwr_lvl_conf_v2_t *txpwr_lvl_v2; ++ int error; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MM_SET_TXPWR_LVL_REQ message */ ++ txpwr_lvl_req = ++ rwnx_msg_zalloc(MM_SET_TXPWR_IDX_LVL_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_set_txpwr_lvl_req)); ++ ++ if (!txpwr_lvl_req) { ++ return -ENOMEM; ++ } ++ ++ txpwr_lvl_v2 = &txpwr_lvl_v2_tmp; ++ ++ get_userconfig_txpwr_lvl_v2_in_fdrv(txpwr_lvl_v2); ++ ++ if (txpwr_lvl_v2->enable == 0) { ++ rwnx_msg_free(rwnx_hw, txpwr_lvl_req); ++ return 0; ++ } else { ++ AICWFDBG(LOGINFO, "%s:enable:%d\r\n", __func__, ++ txpwr_lvl_v2->enable); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_1m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_2m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_5m5_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_11m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_6m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_9m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_12m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_18m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_24m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_36m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_48m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[10]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_54m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[11]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs0_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs1_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs2_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs3_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs4_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs5_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs6_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs7_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs8_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs9_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs0_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs1_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs2_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs3_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs4_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs5_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs6_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs7_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs8_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs9_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs10_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[10]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs11_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[11]); ++ ++ if ((testmode == 0) && (chip_sub_id == 0)) { ++ txpwr_lvl_req->txpwr_lvl.enable = txpwr_lvl_v2->enable; ++ txpwr_lvl_req->txpwr_lvl.dsss = ++ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[3]; // 11M ++ txpwr_lvl_req->txpwr_lvl.ofdmlowrate_2g4 = ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[4]; // MCS4 ++ txpwr_lvl_req->txpwr_lvl.ofdm64qam_2g4 = ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[7]; // MCS7 ++ txpwr_lvl_req->txpwr_lvl.ofdm256qam_2g4 = ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[9]; // MCS9 ++ txpwr_lvl_req->txpwr_lvl.ofdm1024qam_2g4 = ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[11]; // MCS11 ++ txpwr_lvl_req->txpwr_lvl.ofdmlowrate_5g = 13; // unused ++ txpwr_lvl_req->txpwr_lvl.ofdm64qam_5g = 13; // unused ++ txpwr_lvl_req->txpwr_lvl.ofdm256qam_5g = 13; // unused ++ txpwr_lvl_req->txpwr_lvl.ofdm1024qam_5g = 13; // unused ++ } else { ++ txpwr_lvl_req->txpwr_lvl_v2 = *txpwr_lvl_v2; ++ } ++ ++ /* Send the MM_SET_TXPWR_LVL_REQ message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, txpwr_lvl_req, 1, ++ MM_SET_TXPWR_IDX_LVL_CFM, NULL); ++ ++ return (error); ++ } ++} ++ ++int rwnx_send_txpwr_lvl_v3_req(struct rwnx_hw *rwnx_hw) ++{ ++ struct mm_set_txpwr_lvl_req *txpwr_lvl_req; ++ txpwr_lvl_conf_v3_t txpwr_lvl_v3_tmp; ++ txpwr_lvl_conf_v3_t *txpwr_lvl_v3; ++ txpwr_loss_conf_t txpwr_loss_tmp; ++ txpwr_loss_conf_t *txpwr_loss; ++ int error; ++ int i; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MM_SET_TXPWR_LVL_REQ message */ ++ txpwr_lvl_req = ++ rwnx_msg_zalloc(MM_SET_TXPWR_IDX_LVL_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_set_txpwr_lvl_req)); ++ ++ if (!txpwr_lvl_req) { ++ return -ENOMEM; ++ } ++ ++ txpwr_lvl_v3 = &txpwr_lvl_v3_tmp; ++ txpwr_loss = &txpwr_loss_tmp; ++ txpwr_loss->loss_enable_2g4 = 0; ++ txpwr_loss->loss_enable_5g = 0; ++ ++ get_userconfig_txpwr_lvl_v3_in_fdrv(txpwr_lvl_v3); ++ get_userconfig_txpwr_loss(txpwr_loss); ++ ++ if (txpwr_loss->loss_enable_2g4 == 1) { ++ AICWFDBG(LOGINFO, "%s:loss_value_2g4: %d\r\n", __func__, ++ txpwr_loss->loss_value_2g4); ++ ++ for (i = 0; i <= 11; i++) ++ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[i] -= ++ txpwr_loss->loss_value_2g4; ++ for (i = 0; i <= 9; i++) ++ txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[i] -= ++ txpwr_loss->loss_value_2g4; ++ for (i = 0; i <= 11; i++) ++ txpwr_lvl_v3->pwrlvl_11ax_2g4[i] -= ++ txpwr_loss->loss_value_2g4; ++ } ++ ++ if (txpwr_loss->loss_enable_5g == 1) { ++ AICWFDBG(LOGINFO, "%s:loss_value_5g: %d\r\n", __func__, ++ txpwr_loss->loss_value_5g); ++ ++ for (i = 0; i <= 11; i++) ++ txpwr_lvl_v3->pwrlvl_11a_5g[i] -= ++ txpwr_loss->loss_value_5g; ++ for (i = 0; i <= 9; i++) ++ txpwr_lvl_v3->pwrlvl_11n_11ac_5g[i] -= ++ txpwr_loss->loss_value_5g; ++ for (i = 0; i <= 11; i++) ++ txpwr_lvl_v3->pwrlvl_11ax_5g[i] -= ++ txpwr_loss->loss_value_5g; ++ } ++ ++ if (txpwr_lvl_v3->enable == 0) { ++ rwnx_msg_free(rwnx_hw, txpwr_lvl_req); ++ return 0; ++ } else { ++ AICWFDBG(LOGINFO, "%s:enable:%d\r\n", __func__, ++ txpwr_lvl_v3->enable); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_1m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_2m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_5m5_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_11m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_6m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_9m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_12m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_18m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_24m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_36m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_48m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[10]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_54m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[11]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs0_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs1_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs2_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs3_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs4_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs5_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs6_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs7_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs8_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs9_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs0_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_2g4[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs1_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_2g4[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs2_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_2g4[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs3_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_2g4[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs4_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_2g4[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs5_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_2g4[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs6_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_2g4[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs7_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_2g4[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs8_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_2g4[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs9_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_2g4[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs10_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_2g4[10]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs11_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_2g4[11]); ++ ++ AICWFDBG(LOGINFO, "%s:lvl_11a_1m_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11a_5g[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_2m_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11a_5g[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_5m5_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11a_5g[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_11m_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11a_5g[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_6m_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11a_5g[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_9m_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11a_5g[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_12m_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11a_5g[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_18m_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11a_5g[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_24m_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11a_5g[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_36m_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11a_5g[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_48m_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11a_5g[10]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_54m_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11a_5g[11]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs0_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_5g[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs1_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_5g[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs2_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_5g[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs3_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_5g[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs4_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_5g[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs5_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_5g[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs6_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_5g[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs7_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_5g[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs8_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_5g[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs9_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_5g[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs0_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_5g[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs1_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_5g[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs2_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_5g[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs3_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_5g[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs4_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_5g[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs5_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_5g[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs6_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_5g[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs7_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_5g[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs8_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_5g[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs9_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_5g[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs10_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_5g[10]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs11_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_5g[11]); ++ ++ txpwr_lvl_req->txpwr_lvl_v3 = *txpwr_lvl_v3; ++ ++ /* Send the MM_SET_TXPWR_LVL_REQ message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, txpwr_lvl_req, 1, ++ MM_SET_TXPWR_IDX_LVL_CFM, NULL); ++ ++ return (error); ++ } ++} ++ ++int rwnx_send_txpwr_lvl_v4_req(struct rwnx_hw *rwnx_hw) ++{ ++ struct mm_set_txpwr_lvl_req *txpwr_lvl_req; ++ txpwr_lvl_conf_v4_t txpwr_lvl_v4_tmp; ++ txpwr_lvl_conf_v4_t *txpwr_lvl_v4; ++ txpwr_loss_conf_t txpwr_loss_tmp; ++ txpwr_loss_conf_t *txpwr_loss; ++ int error; ++ int i; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MM_SET_TXPWR_LVL_REQ message */ ++ txpwr_lvl_req = ++ rwnx_msg_zalloc(MM_SET_TXPWR_IDX_LVL_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_set_txpwr_lvl_req)); ++ ++ if (!txpwr_lvl_req) { ++ return -ENOMEM; ++ } ++ ++ txpwr_lvl_v4 = &txpwr_lvl_v4_tmp; ++ txpwr_loss = &txpwr_loss_tmp; ++ txpwr_loss->loss_enable_2g4 = 0; ++ txpwr_loss->loss_enable_5g = 0; ++ ++ get_userconfig_txpwr_lvl_v4_in_fdrv(txpwr_lvl_v4); ++ get_userconfig_txpwr_loss(txpwr_loss); ++ ++ if (txpwr_loss->loss_enable_2g4 == 1) { ++ AICWFDBG(LOGINFO, "%s:loss_value_2g4: %d\r\n", __func__, ++ txpwr_loss->loss_value_2g4); ++ ++ for (i = 0; i <= 11; i++) ++ txpwr_lvl_v4->pwrlvl_11b_11ag_2g4[i] -= ++ txpwr_loss->loss_value_2g4; ++ for (i = 0; i <= 9; i++) ++ txpwr_lvl_v4->pwrlvl_11n_11ac_2g4[i] -= ++ txpwr_loss->loss_value_2g4; ++ for (i = 0; i <= 11; i++) ++ txpwr_lvl_v4->pwrlvl_11ax_2g4[i] -= ++ txpwr_loss->loss_value_2g4; ++ } ++ ++ if (txpwr_loss->loss_enable_5g == 1) { ++ AICWFDBG(LOGINFO, "%s:loss_value_5g: %d\r\n", __func__, ++ txpwr_loss->loss_value_5g); ++ ++ for (i = 0; i <= 7; i++) ++ txpwr_lvl_v4->pwrlvl_11a_5g[i] -= ++ txpwr_loss->loss_value_5g; ++ for (i = 0; i <= 9; i++) ++ txpwr_lvl_v4->pwrlvl_11n_11ac_5g[i] -= ++ txpwr_loss->loss_value_5g; ++ for (i = 0; i <= 11; i++) ++ txpwr_lvl_v4->pwrlvl_11ax_5g[i] -= ++ txpwr_loss->loss_value_5g; ++ } ++ ++ if (txpwr_lvl_v4->enable == 0) { ++ rwnx_msg_free(rwnx_hw, txpwr_lvl_req); ++ return 0; ++ } else { ++ AICWFDBG(LOGINFO, "%s:enable:%d\r\n", __func__, ++ txpwr_lvl_v4->enable); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_1m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11b_11ag_2g4[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_2m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11b_11ag_2g4[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_5m5_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11b_11ag_2g4[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_11m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11b_11ag_2g4[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_6m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11b_11ag_2g4[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_9m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11b_11ag_2g4[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_12m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11b_11ag_2g4[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_18m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11b_11ag_2g4[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_24m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11b_11ag_2g4[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_36m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11b_11ag_2g4[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_48m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11b_11ag_2g4[10]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_54m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11b_11ag_2g4[11]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs0_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_2g4[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs1_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_2g4[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs2_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_2g4[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs3_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_2g4[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs4_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_2g4[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs5_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_2g4[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs6_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_2g4[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs7_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_2g4[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs8_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_2g4[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs9_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_2g4[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs0_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_2g4[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs1_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_2g4[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs2_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_2g4[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs3_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_2g4[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs4_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_2g4[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs5_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_2g4[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs6_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_2g4[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs7_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_2g4[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs8_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_2g4[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs9_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_2g4[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs10_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_2g4[10]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs11_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_2g4[11]); ++ ++ AICWFDBG(LOGINFO, "%s:lvl_11a_6m_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11a_5g[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_9m_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11a_5g[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_12m_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11a_5g[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_18m_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11a_5g[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_24m_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11a_5g[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_36m_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11a_5g[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_48m_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11a_5g[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_54m_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11a_5g[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs0_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_5g[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs1_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_5g[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs2_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_5g[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs3_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_5g[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs4_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_5g[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs5_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_5g[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs6_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_5g[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs7_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_5g[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs8_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_5g[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs9_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_5g[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs0_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_5g[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs1_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_5g[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs2_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_5g[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs3_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_5g[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs4_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_5g[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs5_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_5g[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs6_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_5g[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs7_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_5g[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs8_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_5g[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs9_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_5g[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs10_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_5g[10]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs11_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_5g[11]); ++ ++ txpwr_lvl_req->txpwr_lvl_v4 = *txpwr_lvl_v4; ++ ++ /* Send the MM_SET_TXPWR_LVL_REQ message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, txpwr_lvl_req, 1, ++ MM_SET_TXPWR_IDX_LVL_CFM, NULL); ++ ++ return (error); ++ } ++} ++ ++int rwnx_send_txpwr_lvl_adj_req(struct rwnx_hw *rwnx_hw) ++{ ++ struct mm_set_txpwr_lvl_adj_req *txpwr_lvl_adj_req; ++ txpwr_lvl_adj_conf_t txpwr_lvl_adj_tmp; ++ txpwr_lvl_adj_conf_t *txpwr_lvl_adj; ++ int error; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MM_SET_TXPWR_LVL_REQ message */ ++ txpwr_lvl_adj_req = ++ rwnx_msg_zalloc(MM_SET_TXPWR_LVL_ADJ_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_set_txpwr_lvl_adj_req)); ++ ++ if (!txpwr_lvl_adj_req) { ++ return -ENOMEM; ++ } ++ ++ txpwr_lvl_adj = &txpwr_lvl_adj_tmp; ++ ++ get_userconfig_txpwr_lvl_adj_in_fdrv(txpwr_lvl_adj); ++ ++ if (txpwr_lvl_adj->enable == 0) { ++ rwnx_msg_free(rwnx_hw, txpwr_lvl_adj_req); ++ return 0; ++ } else { ++ AICWFDBG(LOGINFO, "%s:enable:%d\r\n", __func__, ++ txpwr_lvl_adj->enable); ++ AICWFDBG(LOGINFO, "%s:lvl_adj_2g4_chan_1_4:%d\r\n", __func__, ++ txpwr_lvl_adj->pwrlvl_adj_tbl_2g4[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_adj_2g4_chan_5_9:%d\r\n", __func__, ++ txpwr_lvl_adj->pwrlvl_adj_tbl_2g4[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_adj_2g4_chan_10_13:%d\r\n", __func__, ++ txpwr_lvl_adj->pwrlvl_adj_tbl_2g4[2]); ++ ++ AICWFDBG(LOGINFO, "%s:lvl_adj_5g_chan_42:%d\r\n", __func__, ++ txpwr_lvl_adj->pwrlvl_adj_tbl_5g[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_adj_5g_chan_58:%d\r\n", __func__, ++ txpwr_lvl_adj->pwrlvl_adj_tbl_5g[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_adj_5g_chan_106:%d\r\n", __func__, ++ txpwr_lvl_adj->pwrlvl_adj_tbl_5g[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_adj_5g_chan_122:%d\r\n", __func__, ++ txpwr_lvl_adj->pwrlvl_adj_tbl_5g[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_adj_5g_chan_138:%d\r\n", __func__, ++ txpwr_lvl_adj->pwrlvl_adj_tbl_5g[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_adj_5g_chan_155:%d\r\n", __func__, ++ txpwr_lvl_adj->pwrlvl_adj_tbl_5g[5]); ++ ++ txpwr_lvl_adj_req->txpwr_lvl_adj = *txpwr_lvl_adj; ++ ++ /* Send the MM_SET_TXPWR_LVL_REQ message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, txpwr_lvl_adj_req, 1, ++ MM_SET_TXPWR_LVL_ADJ_CFM, NULL); ++ ++ return (error); ++ } ++} ++ ++int rwnx_send_txpwr_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_LVL_REQ message */ ++ txpwr_idx_req = ++ rwnx_msg_zalloc(MM_SET_TXPWR_IDX_LVL_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_LVL_REQ message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, txpwr_idx_req, 1, ++ MM_SET_TXPWR_IDX_LVL_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; ++ ++ if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8801) { ++ get_userconfig_txpwr_ofst(txpwr_ofst); ++ } else if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ get_userconfig_txpwr_ofst_in_fdrv(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; ++ } ++}; ++ ++int rwnx_send_txpwr_ofst2x_req(struct rwnx_hw *rwnx_hw) ++{ ++ struct mm_set_txpwr_ofst_req *txpwr_ofst_req; ++ txpwr_ofst2x_conf_t *txpwr_ofst2x; ++ int error = 0; ++ int type, ch_grp; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MM_SET_TXPWR_OFST_REQ message */ ++ txpwr_ofst_req = ++ rwnx_msg_zalloc(MM_SET_TXPWR_OFST_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_set_txpwr_ofst_req)); ++ ++ if (!txpwr_ofst_req) { ++ return -ENOMEM; ++ } ++ ++ txpwr_ofst2x = &txpwr_ofst_req->txpwr_ofst2x; ++ txpwr_ofst2x->enable = 0; ++ for (type = 0; type < 3; type++) { ++ for (ch_grp = 0; ch_grp < 6; ch_grp++) { ++ if (ch_grp < 3) { ++ txpwr_ofst2x->pwrofst2x_tbl_2g4[type][ch_grp] = ++ 0; ++ } ++ txpwr_ofst2x->pwrofst2x_tbl_5g[type][ch_grp] = 0; ++ } ++ } ++ if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ get_userconfig_txpwr_ofst2x_in_fdrv(txpwr_ofst2x); ++ } ++ if (txpwr_ofst2x->enable) { ++ AICWFDBG(LOGINFO, "%s:enable:%d\r\n", __func__, ++ txpwr_ofst2x->enable); ++ AICWFDBG( ++ LOGINFO, ++ "pwrofst2x 2.4g: [0]:11b, [1]:ofdm_highrate, [2]:ofdm_lowrate\n" ++ " chan=" ++ "\t1-4" ++ "\t5-9" ++ "\t10-13"); ++ for (type = 0; type < 3; type++) { ++ AICWFDBG(LOGINFO, "\n [%d] =", type); ++ for (ch_grp = 0; ch_grp < 3; ch_grp++) { ++ AICWFDBG( ++ LOGINFO, "\t%d", ++ txpwr_ofst2x->pwrofst2x_tbl_2g4[type] ++ [ch_grp]); ++ } ++ } ++ AICWFDBG( ++ LOGINFO, ++ "\npwrofst2x 5g: [0]:ofdm_lowrate, [1]:ofdm_highrate, [2]:ofdm_midrate\n" ++ " chan=" ++ "\t36-50" ++ "\t51-64" ++ "\t98-114" ++ "\t115-130" ++ "\t131-146" ++ "\t147-166"); ++ for (type = 0; type < 3; type++) { ++ AICWFDBG(LOGINFO, "\n [%d] =", type); ++ for (ch_grp = 0; ch_grp < 6; ch_grp++) { ++ AICWFDBG( ++ LOGINFO, "\t%d", ++ txpwr_ofst2x->pwrofst2x_tbl_5g[type] ++ [ch_grp]); ++ } ++ } ++ AICWFDBG(LOGINFO, "\n"); ++ ++ /* Send the MM_SET_TXPWR_OFST_REQ message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, txpwr_ofst_req, 1, ++ MM_SET_TXPWR_OFST_CFM, NULL); ++ } else { ++ AICWFDBG(LOGINFO, "%s:Do not use txpwr_ofst2x\r\n", __func__); ++ rwnx_msg_free(rwnx_hw, txpwr_ofst_req); ++ } ++ ++ return (error); ++} ++ ++int rwnx_send_txpwr_ofst2x_v2_req(struct rwnx_hw *rwnx_hw) ++{ ++ struct mm_set_txpwr_ofst_req *txpwr_ofst_req; ++ txpwr_ofst2x_conf_v2_t *txpwr_ofst2x_v2; ++ int error = 0; ++ int type, ch_grp; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MM_SET_TXPWR_OFST_REQ message */ ++ txpwr_ofst_req = ++ rwnx_msg_zalloc(MM_SET_TXPWR_OFST_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_set_txpwr_ofst_req)); ++ ++ if (!txpwr_ofst_req) { ++ return -ENOMEM; ++ } ++ ++ txpwr_ofst2x_v2 = &txpwr_ofst_req->txpwr_ofst2x_v2; ++ txpwr_ofst2x_v2->enable = 0; ++ ++ get_userconfig_txpwr_ofst2x_v2_in_fdrv(txpwr_ofst2x_v2); ++ ++ if (txpwr_ofst2x_v2->enable) { ++ AICWFDBG(LOGINFO, "%s:enable:%d\r\n", __func__, ++ txpwr_ofst2x_v2->enable); ++ AICWFDBG( ++ LOGINFO, ++ "pwrofst2x 2.4g(ant0/ant1): [0]:11b, [1]:ofdm_highrate\n" ++ " chan=" ++ "\t1-4" ++ "\t5-9" ++ "\t10-13"); ++ for (type = 0; type < 2; type++) { ++ AICWFDBG(LOGINFO, "\n [%d] =", type); ++ for (ch_grp = 0; ch_grp < 3; ch_grp++) { ++ AICWFDBG( ++ LOGINFO, "\t%d/%d", ++ txpwr_ofst2x_v2 ++ ->pwrofst2x_tbl_2g4_ant0[ch_grp] ++ [type], ++ txpwr_ofst2x_v2 ++ ->pwrofst2x_tbl_2g4_ant1[ch_grp] ++ [type]); ++ } ++ } ++ AICWFDBG(LOGINFO, ++ "\npwrofst2x 5g(ant0/ant1): [0]:ofdm_highrate\n" ++ " chan=" ++ "\t36-50" ++ "\t51-64" ++ "\t98-114" ++ "\t115-130" ++ "\t131-146" ++ "\t147-166"); ++ for (type = 0; type < 1; type++) { ++ AICWFDBG(LOGINFO, "\n [%d] =", type); ++ for (ch_grp = 0; ch_grp < 6; ch_grp++) { ++ AICWFDBG(LOGINFO, "\t%d/%d", ++ txpwr_ofst2x_v2 ++ ->pwrofst2x_tbl_5g_ant0[ch_grp] ++ [type], ++ txpwr_ofst2x_v2 ++ ->pwrofst2x_tbl_5g_ant1[ch_grp] ++ [type]); ++ } ++ } ++ AICWFDBG(LOGINFO, "\n"); ++ ++ /* Send the MM_SET_TXPWR_OFST_REQ message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, txpwr_ofst_req, 1, ++ MM_SET_TXPWR_OFST_CFM, NULL); ++ } else { ++ AICWFDBG(LOGINFO, "%s:Do not use txpwr_ofst2x_v2\r\n", ++ __func__); ++ rwnx_msg_free(rwnx_hw, txpwr_ofst_req); ++ } ++ ++ return (error); ++} ++ ++#ifdef CONFIG_APF ++int rwnx_send_set_apf_prog_req(struct rwnx_hw *rwnx_hw, u8_l *program, ++ u32_l program_len) ++{ ++ struct mm_set_apf_prog_req *req; ++ int error = 0; ++ int buffer_len, buffer_start = 0, buffer_end, page; ++ ++ /* current only 8800d80 support apf */ ++ if (rwnx_hw->sdiodev->chipid != PRODUCT_ID_AIC8800D80) { ++ return 0; ++ } ++ ++ if (!program) ++ return -ENOMEM; ++ ++ for (page = 0; buffer_start < program_len; page++) { ++ buffer_end = buffer_start + LMAC_MSG_MAX_LEN; ++ if (buffer_end > program_len) ++ buffer_end = program_len; ++ buffer_len = buffer_end - buffer_start; ++ ++ /* Build the MM_SET_TXOP_REQ message */ ++ req = rwnx_msg_zalloc(MM_SET_APF_PROG_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_set_apf_prog_req)); ++ if (!req) ++ return -ENOMEM; ++ ++ req->program_len = buffer_len; ++ req->offset = page; ++ memcpy(req->program, program + buffer_start, buffer_len); ++ buffer_start = buffer_end; ++ ++ /* Send the MM_SET_TXOP_REQ message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, req, 1, MM_SET_APF_PROG_CFM, ++ NULL); ++ if (error) ++ break; ++ } ++ return error; ++} ++ ++int rwnx_send_get_apf_prog_req(struct rwnx_hw *rwnx_hw, u8_l *program, ++ u32_l program_len) ++{ ++ struct mm_get_apf_prog_req *req; ++ int error = 0; ++ struct mm_get_apf_prog_cfm cfm; ++ int buffer_len, buffer_start = 0, buffer_end, page; ++ ++ /* current only 8800d80 support apf */ ++ if (rwnx_hw->sdiodev->chipid != PRODUCT_ID_AIC8800D80) { ++ return 0; ++ } ++ ++ if (!program) ++ return -ENOMEM; ++ ++ for (page = 0; buffer_start < program_len; page++) { ++ buffer_end = buffer_start + LMAC_MSG_MAX_LEN; ++ if (buffer_end > program_len) ++ buffer_end = program_len; ++ buffer_len = buffer_end - buffer_start; ++ ++ /* Build the MM_SET_TXOP_REQ message */ ++ req = rwnx_msg_zalloc(MM_GET_APF_PROG_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_get_apf_prog_req)); ++ if (!req) ++ return -ENOMEM; ++ ++ req->offset = page; ++ /* Send the MM_GET_APF_PROG_REQ message to UMAC FW */ ++ error = rwnx_send_msg(rwnx_hw, req, 1, MM_GET_APF_PROG_CFM, ++ &cfm); ++ if (error) ++ break; ++ ++ memcpy(program + buffer_start, cfm.program, buffer_len); ++ buffer_start = buffer_end; ++ } ++ ++ return error; ++} ++#endif ++ ++int rwnx_send_set_filter(struct rwnx_hw *rwnx_hw, uint32_t filter) ++{ ++ struct mm_set_filter_req *set_filter_req_param; ++ uint32_t rx_filter = 0; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MM_SET_FILTER_REQ message */ ++ set_filter_req_param = ++ rwnx_msg_zalloc(MM_SET_FILTER_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_set_filter_req)); ++ if (!set_filter_req_param) ++ return -ENOMEM; ++ ++ /* Set parameters for the MM_SET_FILTER_REQ message */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) ++ if (filter & FIF_PROMISC_IN_BSS) ++ rx_filter |= NXMAC_ACCEPT_UNICAST_BIT; ++#endif ++ if (filter & FIF_ALLMULTI) ++ rx_filter |= NXMAC_ACCEPT_MULTICAST_BIT; ++ ++ if (filter & (FIF_FCSFAIL | FIF_PLCPFAIL)) ++ rx_filter |= NXMAC_ACCEPT_ERROR_FRAMES_BIT; ++ ++ if (filter & FIF_BCN_PRBRESP_PROMISC) ++ rx_filter |= NXMAC_ACCEPT_OTHER_BSSID_BIT; ++ ++ if (filter & FIF_CONTROL) ++ rx_filter |= NXMAC_ACCEPT_OTHER_CNTRL_FRAMES_BIT | ++ NXMAC_ACCEPT_CF_END_BIT | NXMAC_ACCEPT_ACK_BIT | ++ NXMAC_ACCEPT_CTS_BIT | NXMAC_ACCEPT_RTS_BIT | ++ NXMAC_ACCEPT_BA_BIT | NXMAC_ACCEPT_BAR_BIT; ++ ++ if (filter & FIF_OTHER_BSS) ++ rx_filter |= NXMAC_ACCEPT_OTHER_BSSID_BIT; ++ ++ if (filter & FIF_PSPOLL) { ++ /* TODO: check if the MAC filters apply to our BSSID or is general */ ++ rx_filter |= NXMAC_ACCEPT_PS_POLL_BIT; ++ } ++ ++ if (filter & FIF_PROBE_REQ) { ++ rx_filter |= NXMAC_ACCEPT_PROBE_REQ_BIT; ++ rx_filter |= NXMAC_ACCEPT_ALL_BEACON_BIT; ++ } ++ ++ /* Add the filter flags that are set by default and cannot be changed here */ ++ rx_filter |= RWNX_MAC80211_NOT_CHANGEABLE; ++ ++ /* XXX */ ++ //if (ieee80211_hw_check(rwnx_hw->hw, AMPDU_AGGREGATION)) ++ rx_filter |= NXMAC_ACCEPT_BA_BIT; ++ ++ /* Now copy all the flags into the message parameter */ ++ set_filter_req_param->filter = rx_filter; ++ ++ RWNX_DBG("new total_flags = 0x%08x rx filter set to 0x%08x\r\n", filter, ++ rx_filter); ++ ++ /* Send the MM_SET_FILTER_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, set_filter_req_param, 1, ++ MM_SET_FILTER_CFM, NULL); ++} ++ ++/****************************************************************************** ++ * Control messages handling functions (FULLMAC only) ++ *****************************************************************************/ ++#ifdef CONFIG_RWNX_FULLMAC ++#ifdef CONFIG_HE_FOR_OLD_KERNEL ++extern struct ieee80211_sband_iftype_data rwnx_he_capa; ++#endif ++#ifdef CONFIG_VHT_FOR_OLD_KERNEL ++static struct ieee80211_sta_vht_cap *rwnx_vht_capa; ++#endif ++int rwnx_send_me_config_req(struct rwnx_hw *rwnx_hw) ++{ ++ struct me_config_req *req; ++ struct wiphy *wiphy = rwnx_hw->wiphy; ++ ++ struct ieee80211_sta_ht_cap *ht_cap; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) || \ ++ defined(CONFIG_VHT_FOR_OLD_KERNEL) ++ struct ieee80211_sta_vht_cap *vht_cap; ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) ++ struct ieee80211_sta_he_cap const *he_cap = NULL; ++#else ++#ifdef CONFIG_HE_FOR_OLD_KERNEL ++ struct ieee80211_sta_he_cap const *he_cap; ++#endif ++#endif ++ uint8_t *ht_mcs; ++ int i; ++ ++ if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ rwnx_hw->mod_params->use_80 = true; ++ } ++ ++ if (rwnx_hw->band_5g_support) { ++ ht_cap = &wiphy->bands[NL80211_BAND_5GHZ]->ht_cap; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) || \ ++ defined(CONFIG_VHT_FOR_OLD_KERNEL) ++ vht_cap = &wiphy->bands[NL80211_BAND_5GHZ]->vht_cap; ++#endif ++ } else { ++ ht_cap = &wiphy->bands[NL80211_BAND_2GHZ]->ht_cap; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) || \ ++ defined(CONFIG_VHT_FOR_OLD_KERNEL) ++ vht_cap = &wiphy->bands[NL80211_BAND_2GHZ]->vht_cap; ++#endif ++ } ++#ifdef CONFIG_VHT_FOR_OLD_KERNEL ++ rwnx_vht_capa = vht_cap; ++#endif ++ ++ ht_mcs = (uint8_t *)&ht_cap->mcs; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the ME_CONFIG_REQ message */ ++ req = rwnx_msg_zalloc(ME_CONFIG_REQ, TASK_ME, DRV_TASK_ID, ++ sizeof(struct me_config_req)); ++ if (!req) ++ return -ENOMEM; ++ ++ /* Set parameters for the ME_CONFIG_REQ message */ ++ req->ht_supp = ht_cap->ht_supported; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) || \ ++ defined(CONFIG_VHT_FOR_OLD_KERNEL) ++ req->vht_supp = vht_cap->vht_supported; ++#endif ++ req->ht_cap.ht_capa_info = ++ cpu_to_le16(ht_cap->cap | IEEE80211_HT_CAP_LDPC_CODING); ++ req->ht_cap.a_mpdu_param = ht_cap->ampdu_factor | ++ (ht_cap->ampdu_density ++ << IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); ++ for (i = 0; i < sizeof(ht_cap->mcs); i++) ++ req->ht_cap.mcs_rate[i] = ht_mcs[i]; ++ req->ht_cap.ht_extended_capa = 0; ++ req->ht_cap.tx_beamforming_capa = 0; ++ req->ht_cap.asel_capa = 0; ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) || \ ++ defined(CONFIG_VHT_FOR_OLD_KERNEL) ++ if (req->vht_supp) { ++ req->vht_cap.vht_capa_info = cpu_to_le32(vht_cap->cap); ++ req->vht_cap.rx_highest = ++ cpu_to_le16(vht_cap->vht_mcs.rx_highest); ++ req->vht_cap.rx_mcs_map = ++ cpu_to_le16(vht_cap->vht_mcs.rx_mcs_map); ++ req->vht_cap.tx_highest = ++ cpu_to_le16(vht_cap->vht_mcs.tx_highest); ++ req->vht_cap.tx_mcs_map = ++ cpu_to_le16(vht_cap->vht_mcs.tx_mcs_map); ++ } ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) || \ ++ defined(CONFIG_HE_FOR_OLD_KERNEL) ++#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; ++#endif ++ req->he_supp = he_cap->has_he; ++ for (i = 0; ++ i < ARRAY_SIZE(he_cap->he_cap_elem.mac_cap_info); ++ i++) { ++ req->he_cap.mac_cap_info[i] = ++ he_cap->he_cap_elem.mac_cap_info[i]; ++ } ++ for (i = 0; ++ i < ARRAY_SIZE(he_cap->he_cap_elem.phy_cap_info); ++ i++) { ++ req->he_cap.phy_cap_info[i] = ++ he_cap->he_cap_elem.phy_cap_info[i]; ++ } ++ req->he_cap.mcs_supp.rx_mcs_80 = ++ cpu_to_le16(he_cap->he_mcs_nss_supp.rx_mcs_80); ++ req->he_cap.mcs_supp.tx_mcs_80 = ++ cpu_to_le16(he_cap->he_mcs_nss_supp.tx_mcs_80); ++ req->he_cap.mcs_supp.rx_mcs_160 = ++ cpu_to_le16(he_cap->he_mcs_nss_supp.rx_mcs_160); ++ req->he_cap.mcs_supp.tx_mcs_160 = ++ cpu_to_le16(he_cap->he_mcs_nss_supp.tx_mcs_160); ++ req->he_cap.mcs_supp.rx_mcs_80p80 = cpu_to_le16( ++ he_cap->he_mcs_nss_supp.rx_mcs_80p80); ++ req->he_cap.mcs_supp.tx_mcs_80p80 = cpu_to_le16( ++ he_cap->he_mcs_nss_supp.tx_mcs_80p80); ++ for (i = 0; i < MAC_HE_PPE_THRES_MAX_LEN; i++) { ++ req->he_cap.ppe_thres[i] = he_cap->ppe_thres[i]; ++ } ++ req->he_ul_on = rwnx_hw->mod_params->he_ul_on; ++ } ++#else ++ req->he_supp = false; ++ req->he_ul_on = false; ++#endif ++ req->ps_on = rwnx_hw->mod_params->ps_on; ++ req->dpsm = rwnx_hw->mod_params->dpsm; ++ req->tx_lft = rwnx_hw->mod_params->tx_lft; ++ req->ant_div_on = rwnx_hw->mod_params->ant_div; ++ if (rwnx_hw->mod_params->use_80) ++ req->phy_bw_max = PHY_CHNL_BW_80; ++ else if (rwnx_hw->mod_params->use_2040) ++ req->phy_bw_max = PHY_CHNL_BW_40; ++ else ++ req->phy_bw_max = PHY_CHNL_BW_20; ++ ++ wiphy_info(wiphy, "HT supp %d, VHT supp %d, HE supp %d\n", ++ req->ht_supp, req->vht_supp, req->he_supp); ++ /* Send the ME_CONFIG_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, ME_CONFIG_CFM, NULL); ++ } ++ ++ int rwnx_send_me_chan_config_req(struct rwnx_hw * rwnx_hw, char *ccode) ++ { ++ struct me_chan_config_req *req; ++ struct wiphy *wiphy = rwnx_hw->wiphy; ++ int i; ++#ifdef CONFIG_POWER_LIMIT ++ int8_t max_pwr; ++ uint8_t r_idx; ++ txpwr_loss_conf_t txpwr_loss_tmp; ++ txpwr_loss_conf_t *txpwr_loss; ++#endif ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the ME_CHAN_CONFIG_REQ message */ ++ req = rwnx_msg_zalloc(ME_CHAN_CONFIG_REQ, TASK_ME, DRV_TASK_ID, ++ sizeof(struct me_chan_config_req)); ++ if (!req) ++ return -ENOMEM; ++ ++#ifdef CONFIG_POWER_LIMIT ++ txpwr_loss = &txpwr_loss_tmp; ++ get_userconfig_txpwr_loss(txpwr_loss); ++ ++ if (txpwr_loss->loss_enable_2g4 == 1) ++ AICWFDBG(LOGINFO, "%s:loss_value_2g4: %d\r\n", __func__, ++ txpwr_loss->loss_value_2g4); ++ if (txpwr_loss->loss_enable_5g == 1) ++ AICWFDBG(LOGINFO, "%s:loss_value_5g: %d\r\n", __func__, ++ txpwr_loss->loss_value_5g); ++ r_idx = get_ccode_region(ccode); ++#endif ++ ++ req->chan2G4_cnt = 0; ++ if (wiphy->bands[NL80211_BAND_2GHZ] != NULL) { ++ struct ieee80211_supported_band *b = ++ wiphy->bands[NL80211_BAND_2GHZ]; ++ for (i = 0; i < b->n_channels; i++) { ++ req->chan2G4[req->chan2G4_cnt].flags = 0; ++ if (b->channels[i].flags & ++ IEEE80211_CHAN_DISABLED) ++ req->chan2G4[req->chan2G4_cnt].flags |= ++ CHAN_DISABLED; ++ req->chan2G4[req->chan2G4_cnt].flags |= ++ get_chan_flags(b->channels[i].flags); ++ req->chan2G4[req->chan2G4_cnt].band = ++ NL80211_BAND_2GHZ; ++ req->chan2G4[req->chan2G4_cnt].freq = ++ b->channels[i].center_freq; ++ req->chan2G4[req->chan2G4_cnt].tx_power = ++ chan_to_fw_pwr( ++ b->channels[i].max_power); ++#ifdef CONFIG_POWER_LIMIT ++ { ++ max_pwr = get_powerlimit_by_freq( ++ PHY_BAND_2G4, ++ req->chan2G4[req->chan2G4_cnt] ++ .freq, ++ r_idx); ++ if (txpwr_loss->loss_enable_2g4 == 1) ++ max_pwr -= ++ txpwr_loss ++ ->loss_value_2g4; ++ if (req->chan2G4[req->chan2G4_cnt] ++ .tx_power > max_pwr) ++ req->chan2G4[req->chan2G4_cnt] ++ .tx_power = max_pwr; ++ } ++#endif ++ req->chan2G4_cnt++; ++ if (req->chan2G4_cnt == ++ MAC_DOMAINCHANNEL_24G_MAX) ++ break; ++ } ++ } ++ ++ req->chan5G_cnt = 0; ++ if (wiphy->bands[NL80211_BAND_5GHZ] != NULL) { ++ struct ieee80211_supported_band *b = ++ wiphy->bands[NL80211_BAND_5GHZ]; ++ for (i = 0; i < b->n_channels; i++) { ++ req->chan5G[req->chan5G_cnt].flags = 0; ++ if (b->channels[i].flags & ++ IEEE80211_CHAN_DISABLED) ++ req->chan5G[req->chan5G_cnt].flags |= ++ CHAN_DISABLED; ++ req->chan5G[req->chan5G_cnt].flags |= ++ get_chan_flags(b->channels[i].flags); ++ req->chan5G[req->chan5G_cnt].band = ++ NL80211_BAND_5GHZ; ++ req->chan5G[req->chan5G_cnt].freq = ++ b->channels[i].center_freq; ++ req->chan5G[req->chan5G_cnt].tx_power = ++ chan_to_fw_pwr( ++ b->channels[i].max_power); ++#ifdef CONFIG_POWER_LIMIT ++ { ++ max_pwr = get_powerlimit_by_freq( ++ PHY_BAND_5G, ++ req->chan5G[req->chan5G_cnt] ++ .freq, ++ r_idx); ++ if (txpwr_loss->loss_enable_5g == 1) ++ max_pwr -= ++ txpwr_loss ++ ->loss_value_5g; ++ if (req->chan5G[req->chan5G_cnt] ++ .tx_power > max_pwr) ++ req->chan5G[req->chan5G_cnt] ++ .tx_power = max_pwr; ++ } ++#endif ++ req->chan5G_cnt++; ++ if (req->chan5G_cnt == MAC_DOMAINCHANNEL_5G_MAX) ++ break; ++ } ++ } ++ ++ /* Send the ME_CHAN_CONFIG_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, ME_CHAN_CONFIG_CFM, NULL); ++ } ++ ++ int rwnx_send_me_set_control_port_req(struct rwnx_hw * rwnx_hw, ++ bool opened, u8 sta_idx) ++ { ++ struct me_set_control_port_req *req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the ME_SET_CONTROL_PORT_REQ message */ ++ req = rwnx_msg_zalloc(ME_SET_CONTROL_PORT_REQ, TASK_ME, ++ DRV_TASK_ID, ++ sizeof(struct me_set_control_port_req)); ++ if (!req) ++ return -ENOMEM; ++ ++ /* Set parameters for the ME_SET_CONTROL_PORT_REQ message */ ++ req->sta_idx = sta_idx; ++ req->control_port_open = opened; ++ ++ /* Send the ME_SET_CONTROL_PORT_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, ME_SET_CONTROL_PORT_CFM, ++ NULL); ++ } ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) && \ ++ LINUX_VERSION_CODE < KERNEL_VERSION(4, 20, 0)) ++ struct ieee80211_he_cap_elem_4_19 { ++ u8 mac_cap_info[6]; ++ u8 phy_cap_info[11]; ++ } __packed; ++#endif ++ ++ int rwnx_send_me_sta_add(struct rwnx_hw * rwnx_hw, ++ struct station_parameters * params, ++ const u8 *mac, u8 inst_nbr, ++ struct me_sta_add_cfm *cfm) ++ { ++ struct me_sta_add_req *req; ++ ++#if LINUX_VERSION_CODE >= HIGH_KERNEL_VERSION ++ struct link_station_parameters *link_sta_params = ++ ¶ms->link_sta_params; ++#else ++ struct station_parameters *link_sta_params = params; ++#endif ++ u8 *ht_mcs = (u8 *)&link_sta_params->ht_capa->mcs; ++ ++ int i; ++ struct rwnx_vif *rwnx_vif = rwnx_hw->vif_table[inst_nbr]; ++#if (defined CONFIG_HE_FOR_OLD_KERNEL) || (defined CONFIG_VHT_FOR_OLD_KERNEL) ++ struct aic_sta *sta = ++ &rwnx_hw->aic_table[rwnx_vif->ap.aic_index]; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ printk("assoc_req idx %d, he: %d, vht: %d\n ", ++ rwnx_vif->ap.aic_index, sta->he, sta->vht); ++ if (rwnx_vif->ap.aic_index < ++ NX_REMOTE_STA_MAX + NX_VIRT_DEV_MAX) ++ rwnx_vif->ap.aic_index++; ++ else ++ rwnx_vif->ap.aic_index = 0; ++#endif ++ ++ /* Build the MM_STA_ADD_REQ message */ ++ req = rwnx_msg_zalloc(ME_STA_ADD_REQ, TASK_ME, DRV_TASK_ID, ++ sizeof(struct me_sta_add_req)); ++ if (!req) { ++ return -ENOMEM; ++ } ++ ++ /* Set parameters for the MM_STA_ADD_REQ message */ ++ memcpy(&(req->mac_addr.array[0]), mac, ETH_ALEN); ++ ++ req->rate_set.length = link_sta_params->supported_rates_len; ++ for (i = 0; i < link_sta_params->supported_rates_len; i++) ++ req->rate_set.array[i] = ++ link_sta_params->supported_rates[i]; ++ ++ req->flags = 0; ++ if (link_sta_params->ht_capa) { ++ const struct ieee80211_ht_cap *ht_capa = ++ link_sta_params->ht_capa; ++ ++ req->flags |= STA_HT_CAPA; ++ req->ht_cap.ht_capa_info = ++ cpu_to_le16(ht_capa->cap_info); ++ req->ht_cap.a_mpdu_param = ht_capa->ampdu_params_info; ++ for (i = 0; i < sizeof(ht_capa->mcs); i++) ++ req->ht_cap.mcs_rate[i] = ht_mcs[i]; ++ req->ht_cap.ht_extended_capa = ++ cpu_to_le16(ht_capa->extended_ht_cap_info); ++ req->ht_cap.tx_beamforming_capa = ++ cpu_to_le32(ht_capa->tx_BF_cap_info); ++ req->ht_cap.asel_capa = ht_capa->antenna_selection_info; ++ } ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) ++ if (link_sta_params->vht_capa) { ++ const struct ieee80211_vht_cap *vht_capa = ++ link_sta_params->vht_capa; ++ ++ req->flags |= STA_VHT_CAPA; ++ req->vht_cap.vht_capa_info = ++ cpu_to_le32(vht_capa->vht_cap_info); ++ req->vht_cap.rx_highest = ++ cpu_to_le16(vht_capa->supp_mcs.rx_highest); ++ req->vht_cap.rx_mcs_map = ++ cpu_to_le16(vht_capa->supp_mcs.rx_mcs_map); ++ req->vht_cap.tx_highest = ++ cpu_to_le16(vht_capa->supp_mcs.tx_highest); ++ req->vht_cap.tx_mcs_map = ++ cpu_to_le16(vht_capa->supp_mcs.tx_mcs_map); ++ } ++#elif defined(CONFIG_VHT_FOR_OLD_KERNEL) ++ if (sta->vht) { ++ //const struct ieee80211_vht_cap *vht_capa = rwnx_vht_capa; ++ ++ req->flags |= STA_VHT_CAPA; ++ req->vht_cap.vht_capa_info = cpu_to_le32(rwnx_vht_capa->cap); ++ req->vht_cap.rx_highest = ++ sta->supp_mcs ++ .rx_highest; //cpu_to_le16(rwnx_vht_capa->vht_mcs.rx_highest); ++ req->vht_cap.rx_mcs_map = ++ sta->supp_mcs ++ .rx_mcs_map; //cpu_to_le16(rwnx_vht_capa->vht_mcs.rx_mcs_map); ++ req->vht_cap.tx_highest = ++ sta->supp_mcs ++ .tx_highest; //cpu_to_le16(rwnx_vht_capa->vht_mcs.tx_highest); ++ req->vht_cap.tx_mcs_map = ++ sta->supp_mcs ++ .tx_mcs_map; //cpu_to_le16(rwnx_vht_capa->vht_mcs.tx_mcs_map); ++ } ++#endif ++ ++ AICWFDBG(LOGDEBUG, ++ "rx map %x rx high %x tx map %x tx high %x \n", ++ req->vht_cap.rx_mcs_map, req->vht_cap.rx_highest, ++ req->vht_cap.tx_mcs_map, req->vht_cap.tx_highest); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) ++ if (link_sta_params->he_capa) { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 20, 0) ++ const struct ieee80211_he_cap_elem_4_19 *he_capa = ++ (const struct ieee80211_he_cap_elem_4_19 *) ++ link_sta_params->he_capa; ++#else ++ const struct ieee80211_he_cap_elem *he_capa = ++ link_sta_params->he_capa; ++#endif ++ struct ieee80211_he_mcs_nss_supp *mcs_nss_supp = ++ (struct ieee80211_he_mcs_nss_supp *)(he_capa + ++ 1); ++ ++ req->flags |= STA_HE_CAPA; ++ for (i = 0; i < ARRAY_SIZE(he_capa->mac_cap_info); ++ i++) { ++ req->he_cap.mac_cap_info[i] = ++ he_capa->mac_cap_info[i]; ++ } ++ for (i = 0; i < ARRAY_SIZE(he_capa->phy_cap_info); ++ i++) { ++ req->he_cap.phy_cap_info[i] = ++ he_capa->phy_cap_info[i]; ++ } ++ req->he_cap.mcs_supp.rx_mcs_80 = ++ mcs_nss_supp->rx_mcs_80; ++ req->he_cap.mcs_supp.tx_mcs_80 = ++ mcs_nss_supp->tx_mcs_80; ++ req->he_cap.mcs_supp.rx_mcs_160 = ++ mcs_nss_supp->rx_mcs_160; ++ req->he_cap.mcs_supp.tx_mcs_160 = ++ mcs_nss_supp->tx_mcs_160; ++ req->he_cap.mcs_supp.rx_mcs_80p80 = ++ mcs_nss_supp->rx_mcs_80p80; ++ req->he_cap.mcs_supp.tx_mcs_80p80 = ++ mcs_nss_supp->tx_mcs_80p80; ++ } ++#else ++#ifdef CONFIG_HE_FOR_OLD_KERNEL ++ if (sta->he) { ++ const struct ieee80211_he_cap_elem *he_capa = ++ &rwnx_he_capa.he_cap.he_cap_elem; ++ struct ieee80211_he_mcs_nss_supp *mcs_nss_supp = ++ (struct ieee80211_he_mcs_nss_supp *)(he_capa + 1); ++ req->flags |= STA_HE_CAPA; ++ for (i = 0; i < ARRAY_SIZE(he_capa->mac_cap_info); i++) { ++ req->he_cap.mac_cap_info[i] = ++ sta->he_cap_elem.mac_cap_info ++ [i]; //he_capa->mac_cap_info[i]; ++ } ++ for (i = 0; i < ARRAY_SIZE(he_capa->phy_cap_info); i++) { ++ req->he_cap.phy_cap_info[i] = ++ sta->he_cap_elem.phy_cap_info ++ [i]; //he_capa->phy_cap_info[i]; ++ } ++ req->he_cap.mcs_supp.rx_mcs_80 = ++ sta->he_mcs_nss_supp ++ .rx_mcs_80; //mcs_nss_supp->rx_mcs_80; ++ req->he_cap.mcs_supp.tx_mcs_80 = ++ sta->he_mcs_nss_supp ++ .tx_mcs_80; //mcs_nss_supp->tx_mcs_80; ++ req->he_cap.mcs_supp.rx_mcs_160 = mcs_nss_supp->rx_mcs_160; ++ req->he_cap.mcs_supp.tx_mcs_160 = mcs_nss_supp->tx_mcs_160; ++ req->he_cap.mcs_supp.rx_mcs_80p80 = mcs_nss_supp->rx_mcs_80p80; ++ req->he_cap.mcs_supp.tx_mcs_80p80 = mcs_nss_supp->tx_mcs_80p80; ++ } ++#endif ++#endif ++ ++ AICWFDBG(LOGDEBUG, ++ "rwnx sta add he mcs/nss rx mcs 80 0x%04x \n", ++ le16_to_cpu(req->he_cap.mcs_supp.rx_mcs_80)); ++ AICWFDBG(LOGDEBUG, ++ "rwnx sta add he mcs/nss tx mcs 80 0x%04x \n", ++ le16_to_cpu(req->he_cap.mcs_supp.tx_mcs_80)); ++ ++ if (params->sta_flags_set & BIT(NL80211_STA_FLAG_WME)) ++ req->flags |= STA_QOS_CAPA; ++ ++ if (params->sta_flags_set & BIT(NL80211_STA_FLAG_MFP)) ++ req->flags |= STA_MFP_CAPA; ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) ++ if (link_sta_params->opmode_notif_used) { ++ req->flags |= STA_OPMOD_NOTIF; ++ req->opmode = link_sta_params->opmode_notif_used; ++ } ++#endif ++ ++ req->aid = cpu_to_le16(params->aid); ++ req->uapsd_queues = params->uapsd_queues; ++ req->max_sp_len = params->max_sp * 2; ++ req->vif_idx = inst_nbr; ++ ++ if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) { ++ //struct rwnx_vif *rwnx_vif = rwnx_hw->vif_table[inst_nbr]; ++ req->tdls_sta = true; ++ if ((params->ext_capab[3] & ++ WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH) && ++ !rwnx_vif->tdls_chsw_prohibited) ++ req->tdls_chsw_allowed = true; ++ if (rwnx_vif->tdls_status == TDLS_SETUP_RSP_TX) ++ req->tdls_sta_initiator = true; ++ } ++ ++ /* Send the ME_STA_ADD_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, ME_STA_ADD_CFM, cfm); ++ } ++ ++ int rwnx_send_me_sta_del(struct rwnx_hw * rwnx_hw, u8 sta_idx, ++ bool tdls_sta) ++ { ++ struct me_sta_del_req *req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MM_STA_DEL_REQ message */ ++ req = rwnx_msg_zalloc(ME_STA_DEL_REQ, TASK_ME, DRV_TASK_ID, ++ sizeof(struct me_sta_del_req)); ++ if (!req) ++ return -ENOMEM; ++ ++ /* Set parameters for the MM_STA_DEL_REQ message */ ++ req->sta_idx = sta_idx; ++ req->tdls_sta = tdls_sta; ++ ++ /* Send the ME_STA_DEL_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, ME_STA_DEL_CFM, NULL); ++ } ++ ++ int rwnx_send_me_traffic_ind(struct rwnx_hw * rwnx_hw, u8 sta_idx, ++ bool uapsd, u8 tx_status) ++ { ++ struct me_traffic_ind_req *req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the ME_UTRAFFIC_IND_REQ message */ ++ req = rwnx_msg_zalloc(ME_TRAFFIC_IND_REQ, TASK_ME, DRV_TASK_ID, ++ sizeof(struct me_traffic_ind_req)); ++ if (!req) ++ return -ENOMEM; ++ ++ /* Set parameters for the ME_TRAFFIC_IND_REQ message */ ++ req->sta_idx = sta_idx; ++ req->tx_avail = tx_status; ++ req->uapsd = uapsd; ++ ++ /* Send the ME_TRAFFIC_IND_REQ to UMAC FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, ME_TRAFFIC_IND_CFM, NULL); ++ } ++ ++ int rwnx_send_me_rc_stats(struct rwnx_hw * rwnx_hw, u8 sta_idx, ++ struct me_rc_stats_cfm * cfm) ++ { ++ struct me_rc_stats_req *req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the ME_RC_STATS_REQ message */ ++ req = rwnx_msg_zalloc(ME_RC_STATS_REQ, TASK_ME, DRV_TASK_ID, ++ sizeof(struct me_rc_stats_req)); ++ if (!req) ++ return -ENOMEM; ++ ++ /* Set parameters for the ME_RC_STATS_REQ message */ ++ req->sta_idx = sta_idx; ++ ++ /* Send the ME_RC_STATS_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, ME_RC_STATS_CFM, cfm); ++ } ++ ++ int rwnx_send_me_rc_set_rate(struct rwnx_hw * rwnx_hw, u8 sta_idx, ++ u16 rate_cfg) ++ { ++ struct me_rc_set_rate_req *req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the ME_RC_SET_RATE_REQ message */ ++ req = rwnx_msg_zalloc(ME_RC_SET_RATE_REQ, TASK_ME, DRV_TASK_ID, ++ sizeof(struct me_rc_set_rate_req)); ++ if (!req) ++ return -ENOMEM; ++ ++ /* Set parameters for the ME_RC_SET_RATE_REQ message */ ++ req->sta_idx = sta_idx; ++ req->fixed_rate_cfg = rate_cfg; ++ ++ /* Send the ME_RC_SET_RATE_REQ message to FW */ ++ return rwnx_send_msg(rwnx_hw, req, 0, 0, NULL); ++ } ++ ++ int rwnx_send_me_set_ps_mode(struct rwnx_hw * rwnx_hw, u8 ps_mode) ++ { ++ struct me_set_ps_mode_req *req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the ME_SET_PS_MODE_REQ message */ ++ req = rwnx_msg_zalloc(ME_SET_PS_MODE_REQ, TASK_ME, DRV_TASK_ID, ++ sizeof(struct me_set_ps_mode_req)); ++ if (!req) ++ return -ENOMEM; ++ ++ /* Set parameters for the ME_SET_PS_MODE_REQ message */ ++ req->ps_state = ps_mode; ++ ++ /* Send the ME_SET_PS_MODE_REQ message to FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, ME_SET_PS_MODE_CFM, NULL); ++ } ++ ++ int rwnx_send_me_set_lp_level(struct rwnx_hw * rwnx_hw, u8 lp_level, ++ u8 disable_filter) ++ { ++ struct me_set_lp_level_req *req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ printk("%s %d %d \n", __func__, lp_level, disable_filter); ++ /* Build the ME_SET_LP_LEVEL_REQ message */ ++ req = rwnx_msg_zalloc(ME_SET_LP_LEVEL_REQ, TASK_ME, DRV_TASK_ID, ++ sizeof(struct me_set_lp_level_req)); ++ if (!req) ++ return -ENOMEM; ++ ++ /* Set parameters for the ME_SET_LP_LEVEL_REQ message */ ++ req->lp_level = lp_level; ++ req->disable_filter = disable_filter; ++ /* Send the ME_SET_LP_LEVEL_REQ message to FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, ME_SET_LP_LEVEL_CFM, ++ NULL); ++ } ++ ++ int rwnx_send_sm_connect_req(struct rwnx_hw * rwnx_hw, ++ struct rwnx_vif * rwnx_vif, ++ struct cfg80211_connect_params * sme, ++ struct sm_connect_cfm * cfm) ++ { ++ struct sm_connect_req *req; ++ int i; ++ u32_l flags = 0; ++ bool gval = false; ++ bool pval = false; ++ rwnx_vif->wep_enabled = false; ++ rwnx_vif->wep_auth_err = false; ++ rwnx_vif->last_auth_type = 0; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the SM_CONNECT_REQ message */ ++ req = rwnx_msg_zalloc(SM_CONNECT_REQ, TASK_SM, DRV_TASK_ID, ++ sizeof(struct sm_connect_req)); ++ if (!req) ++ return -ENOMEM; ++ ++ if ((sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP40) || ++ (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP104)) { ++ gval = true; ++ } ++ ++ if (sme->crypto.n_ciphers_pairwise && ++ ((sme->crypto.ciphers_pairwise[0] == ++ WLAN_CIPHER_SUITE_WEP40) || ++ (sme->crypto.ciphers_pairwise[0] == ++ WLAN_CIPHER_SUITE_WEP104))) { ++ pval = true; ++ } ++ ++ /* Set parameters for the SM_CONNECT_REQ message */ ++ if (sme->crypto.n_ciphers_pairwise && ++ ((sme->crypto.ciphers_pairwise[0] == ++ WLAN_CIPHER_SUITE_WEP40) || ++ (sme->crypto.ciphers_pairwise[0] == ++ WLAN_CIPHER_SUITE_TKIP) || ++ (sme->crypto.ciphers_pairwise[0] == ++ WLAN_CIPHER_SUITE_WEP104))) ++ flags |= DISABLE_HT; ++ ++ if (sme->crypto.control_port) ++ flags |= CONTROL_PORT_HOST; ++ ++ if (sme->crypto.control_port_no_encrypt) ++ flags |= CONTROL_PORT_NO_ENC; ++ ++ if (use_pairwise_key(&sme->crypto)) ++ flags |= WPA_WPA2_IN_USE; ++ ++ if (sme->mfp == NL80211_MFP_REQUIRED) ++ flags |= MFP_IN_USE; ++ ++ if (rwnx_vif->sta.ap) ++ flags |= REASSOCIATION; ++ ++ req->ctrl_port_ethertype = sme->crypto.control_port_ethertype; ++ ++ if (sme->bssid) ++ memcpy(&req->bssid, sme->bssid, ETH_ALEN); ++ else ++ req->bssid = mac_addr_bcst; ++ req->vif_idx = rwnx_vif->vif_index; ++ if (sme->channel) { ++ req->chan.band = sme->channel->band; ++ req->chan.freq = sme->channel->center_freq; ++ req->chan.flags = get_chan_flags(sme->channel->flags); ++ } else { ++ req->chan.freq = (u16_l)-1; ++ } ++ for (i = 0; i < sme->ssid_len; i++) ++ req->ssid.array[i] = sme->ssid[i]; ++ req->ssid.length = sme->ssid_len; ++ req->flags = flags; ++ if (WARN_ON(sme->ie_len > sizeof(req->ie_buf))) ++ goto invalid_param; ++ if (sme->ie_len) ++ memcpy(req->ie_buf, sme->ie, sme->ie_len); ++ req->ie_len = sme->ie_len; ++ req->listen_interval = rwnx_mod_params.listen_itv; ++ req->dont_wait_bcmc = !rwnx_mod_params.listen_bcmc; ++ ++ /* Set auth_type */ ++ if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) ++ req->auth_type = WLAN_AUTH_OPEN; ++ else if (sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) ++ req->auth_type = WLAN_AUTH_OPEN; ++ else if (sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY) ++ req->auth_type = WLAN_AUTH_SHARED_KEY; ++ else if (sme->auth_type == NL80211_AUTHTYPE_FT) { ++ req->auth_type = WLAN_AUTH_FT; ++ } else if (sme->auth_type == NL80211_AUTHTYPE_SAE) ++ req->auth_type = WLAN_AUTH_SAE; ++ else ++ goto invalid_param; ++ ++ /* Set UAPSD queues */ ++ req->uapsd_queues = rwnx_mod_params.uapsd_queues; ++ ++ rwnx_vif->wep_enabled = pval & gval; ++ ++ if (rwnx_vif->wep_enabled) { ++ rwnx_vif->last_auth_type = sme->auth_type; ++ } ++ ++ rwnx_vif->sta.ssid_len = (int)sme->ssid_len; ++ memset(rwnx_vif->sta.ssid, 0, rwnx_vif->sta.ssid_len + 1); ++ memcpy(rwnx_vif->sta.ssid, sme->ssid, rwnx_vif->sta.ssid_len); ++ if (sme->bssid) ++ memcpy(rwnx_vif->sta.bssid, sme->bssid, ETH_ALEN); ++ ++ printk("%s drv_vif_index:%d connect to %s(%d) channel:%d auth_type:%d\r\n", ++ __func__, rwnx_vif->drv_vif_index, rwnx_vif->sta.ssid, ++ rwnx_vif->sta.ssid_len, req->chan.freq, req->auth_type); ++ ++ /* Send the SM_CONNECT_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, SM_CONNECT_CFM, cfm); ++ ++ invalid_param: ++ rwnx_msg_free(rwnx_hw, req); ++ return -EINVAL; ++ } ++ ++ int rwnx_send_sm_disconnect_req(struct rwnx_hw * rwnx_hw, ++ struct rwnx_vif * rwnx_vif, u16 reason) ++ { ++ struct sm_disconnect_req *req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the SM_DISCONNECT_REQ message */ ++ req = rwnx_msg_zalloc(SM_DISCONNECT_REQ, TASK_SM, DRV_TASK_ID, ++ sizeof(struct sm_disconnect_req)); ++ if (!req) ++ return -ENOMEM; ++ ++ /* Set parameters for the SM_DISCONNECT_REQ message */ ++ req->reason_code = reason; ++ req->vif_idx = rwnx_vif->vif_index; ++ ++ /* Send the SM_DISCONNECT_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, SM_DISCONNECT_CFM, NULL); ++ } ++ ++ int rwnx_send_sm_external_auth_required_rsp(struct rwnx_hw * rwnx_hw, ++ struct rwnx_vif * rwnx_vif, ++ u16 status) ++ { ++ struct sm_external_auth_required_rsp *rsp; ++ ++ /* Build the SM_EXTERNAL_AUTH_CFM message */ ++ rsp = rwnx_msg_zalloc( ++ SM_EXTERNAL_AUTH_REQUIRED_RSP, TASK_SM, DRV_TASK_ID, ++ sizeof(struct sm_external_auth_required_rsp)); ++ if (!rsp) ++ return -ENOMEM; ++ ++ rsp->status = status; ++ rsp->vif_idx = rwnx_vif->vif_index; ++ ++ /* send the SM_EXTERNAL_AUTH_REQUIRED_RSP message UMAC FW */ ++ return rwnx_send_msg(rwnx_hw, rsp, 1, ++ SM_EXTERNAL_AUTH_REQUIRED_RSP_CFM, NULL); ++ } ++ ++ int rwnx_send_apm_start_req(struct rwnx_hw * rwnx_hw, ++ struct rwnx_vif * vif, ++ struct cfg80211_ap_settings * settings, ++ struct apm_start_cfm * cfm, ++ struct rwnx_ipc_elem_var * elem) ++ { ++ struct apm_start_req *req; ++ struct rwnx_bcn *bcn = &vif->ap.bcn; ++ u8 *buf; ++ u32 flags = 0; ++ const u8 *rate_ie; ++ u8 rate_len = 0; ++ int var_offset = ++ offsetof(struct ieee80211_mgmt, u.beacon.variable); ++ const u8 *var_pos; ++ int len, i; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the APM_START_REQ message */ ++ req = rwnx_msg_zalloc(APM_START_REQ, TASK_APM, DRV_TASK_ID, ++ sizeof(struct apm_start_req)); ++ if (!req) ++ return -ENOMEM; ++ ++ // Build the beacon ++ bcn->dtim = (u8)settings->dtim_period; ++ buf = rwnx_build_bcn(bcn, &settings->beacon); ++ if (!buf) { ++ rwnx_msg_free(rwnx_hw, req); ++ return -ENOMEM; ++ } ++ ++ // Retrieve the basic rate set from the beacon buffer ++ len = bcn->len - var_offset; ++ var_pos = buf + var_offset; ++ ++// Assume that rate higher that 54 Mbps are BSS membership ++#define IS_BASIC_RATE(r) ((r & 0x80) && ((r & ~0x80) <= (54 * 2))) ++ ++ rate_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, var_pos, len); ++ if (rate_ie) { ++ const u8 *rates = rate_ie + 2; ++ for (i = 0; ++ (i < rate_ie[1]) && (rate_len < MAC_RATESET_LEN); ++ i++) { ++ if (IS_BASIC_RATE(rates[i])) ++ req->basic_rates.array[rate_len++] = ++ rates[i]; ++ } ++ } ++ rate_ie = ++ cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, var_pos, len); ++ if (rate_ie) { ++ const u8 *rates = rate_ie + 2; ++ for (i = 0; ++ (i < rate_ie[1]) && (rate_len < MAC_RATESET_LEN); ++ i++) { ++ if (IS_BASIC_RATE(rates[i])) ++ req->basic_rates.array[rate_len++] = ++ rates[i]; ++ } ++ } ++ req->basic_rates.length = rate_len; ++#undef IS_BASIC_RATE ++ ++#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; ++ } ++#else ++ rwnx_send_bcn(rwnx_hw, buf, vif->vif_index, bcn->len); ++#endif ++ ++ /* Set parameters for the APM_START_REQ message */ ++ req->vif_idx = vif->vif_index; ++ req->bcn_addr = elem->dma_addr; ++ req->bcn_len = bcn->len; ++ req->tim_oft = bcn->head_len; ++ req->tim_len = bcn->tim_len; ++ req->chan.band = settings->chandef.chan->band; ++ req->chan.freq = settings->chandef.chan->center_freq; ++#ifdef CONFIG_RADAR_OR_IR_DETECT ++ req->chan.flags = get_chan_flags(settings->chandef.chan->flags); ++#else ++ req->chan.flags = 0; ++#endif ++ printk("chan.flags %u \n", req->chan.flags); ++ req->chan.tx_power = ++ chan_to_fw_pwr(settings->chandef.chan->max_power); ++ req->center_freq1 = settings->chandef.center_freq1; ++ req->center_freq2 = settings->chandef.center_freq2; ++ req->ch_width = bw2chnl[settings->chandef.width]; ++ req->bcn_int = settings->beacon_interval; ++ if (settings->crypto.control_port) ++ flags |= CONTROL_PORT_HOST; ++ ++ if (settings->crypto.control_port_no_encrypt) ++ flags |= CONTROL_PORT_NO_ENC; ++ ++ if (use_pairwise_key(&settings->crypto)) ++ flags |= WPA_WPA2_IN_USE; ++ ++ if (settings->crypto.control_port_ethertype) ++ req->ctrl_port_ethertype = ++ settings->crypto.control_port_ethertype; ++ else ++ req->ctrl_port_ethertype = ETH_P_PAE; ++ req->flags = flags; ++ ++ /* Send the APM_START_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, APM_START_CFM, cfm); ++ } ++ ++ int rwnx_send_apm_stop_req(struct rwnx_hw * rwnx_hw, ++ struct rwnx_vif * vif) ++ { ++ struct apm_stop_req *req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the APM_STOP_REQ message */ ++ req = rwnx_msg_zalloc(APM_STOP_REQ, TASK_APM, DRV_TASK_ID, ++ sizeof(struct apm_stop_req)); ++ if (!req) ++ return -ENOMEM; ++ ++ /* Set parameters for the APM_STOP_REQ message */ ++ req->vif_idx = vif->vif_index; ++ ++ /* Send the APM_STOP_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, APM_STOP_CFM, NULL); ++ } ++ ++ uint8_t scanning; // = 0; ++ ++#define P2P_WILDCARD_SSID "DIRECT-" ++#define P2P_WILDCARD_SSID_LEN (sizeof(P2P_WILDCARD_SSID) - 1) ++ ++#ifdef CONFIG_SET_VENDOR_EXTENSION_IE ++ u8_l vendor_extension_data[256]; ++ u8_l vendor_extension_len = 0; ++#if 0 ++u8_l vendor_extension_data[]={ ++ 0x10,0x49,0x00,0x17,0x00,0x01,0x37,0x10, ++ 0x06,0x00,0x10,0xc5,0xc9,0x91,0xeb,0x1f, ++ 0xce,0x4d,0x00,0xa1,0x2a,0xdf,0xa1,0xe9, ++ 0xc3,0x44,0xe6,0x10,0x49,0x00,0x21,0x00, ++ 0x01,0x37,0x20,0x01,0x00,0x01,0x05,0x20, ++ 0x02,0x00,0x04,0x43,0x56,0x54,0x45,0x20, ++ 0x05,0x00,0x0d,0x31,0x39,0x32,0x2e,0x31, ++ 0x36,0x38,0x2e,0x31,0x35,0x34,0x2e,0x31}; ++#endif ++ ++ void rwnx_insert_vendor_extension_data(struct scanu_vendor_ie_req * ++ ie_req) ++ { ++ u8_l temp_ie[256]; ++ u8_l vendor_extension_subelement[3] = { 0x00, 0x37, 0x2A }; ++ u8_l vendor_extension_id[2] = { 0x10, 0x49 }; ++ int index = 0; ++ int vendor_extension_subelement_len = 0; ++ ++ memset(temp_ie, 0, 256); ++ ++ //find vendor_extension_subelement ++ for (index = 0; index < ie_req->add_ie_len; index++) { ++ if (ie_req->ie[index] == vendor_extension_id[0]) { ++ index++; ++ if (index == ie_req->add_ie_len) { ++ return; ++ } ++ if (ie_req->ie[index] == ++ vendor_extension_id[1] && ++ ie_req->ie[index + 3] == ++ vendor_extension_subelement[0] && ++ ie_req->ie[index + 4] == ++ vendor_extension_subelement[1] && ++ ie_req->ie[index + 5] == ++ vendor_extension_subelement[2]) { ++ index = index + 2; ++ vendor_extension_subelement_len = ++ ie_req->ie[index]; ++ printk("%s find vendor_extension_subelement,index:%d len:%d\r\n", ++ __func__, index, ++ ie_req->ie[index]); ++ break; ++ } ++ } ++ } ++ index = index + vendor_extension_subelement_len; ++ ++ //insert vendor extension ++ memcpy(&temp_ie[0], ie_req->ie, index + 1); ++ memcpy(&temp_ie[index + 1], vendor_extension_data, ++ vendor_extension_len /*sizeof(vendor_extension_data)*/); //insert vendor extension data ++ memcpy(&temp_ie[index + 1 + ++ vendor_extension_len /*sizeof(vendor_extension_data)*/ ++ ], ++ &ie_req->ie[index + 1], ie_req->add_ie_len - index); ++ ++ memcpy(ie_req->ie, temp_ie, ++ ie_req->add_ie_len + ++ vendor_extension_len /*sizeof(vendor_extension_data)*/); ++ ie_req->add_ie_len = ++ ie_req->add_ie_len + ++ vendor_extension_len /*sizeof(vendor_extension_data)*/; ++ ie_req->ie[1] = ++ ie_req->ie[1] + ++ vendor_extension_len /*sizeof(vendor_extension_data)*/; ++ ++ //rwnx_data_dump((char*)__func__, (void*)ie_req->ie, ie_req->add_ie_len); ++ } ++#endif //CONFIG_SET_VENDOR_EXTENSION_IE ++ ++ int rwnx_send_scanu_req(struct rwnx_hw * rwnx_hw, ++ struct rwnx_vif * rwnx_vif, ++ struct cfg80211_scan_request * param) ++ { ++ struct scanu_start_req *req = NULL; ++ struct scanu_vendor_ie_req *ie_req = NULL; ++ struct mm_add_if_cfm add_if_cfm; ++ int i; ++ uint8_t chan_flags = 0; ++ int err; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the SCANU_START_REQ message */ ++ req = rwnx_msg_zalloc(SCANU_START_REQ, TASK_SCANU, DRV_TASK_ID, ++ sizeof(struct scanu_start_req)); ++ if (!req) ++ return -ENOMEM; ++ ++ scanning = 1; ++ /* Set parameters */ ++ req->vif_idx = rwnx_vif->vif_index; ++ req->chan_cnt = ++ (u8)min_t(int, SCAN_CHANNEL_MAX, param->n_channels); ++ req->ssid_cnt = (u8)min_t(int, SCAN_SSID_MAX, param->n_ssids); ++ req->bssid = mac_addr_bcst; ++ req->no_cck = param->no_cck; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0) ++ if (param->duration_mandatory) ++ //req->duration = ieee80211_tu_to_usec(param->duration); ++ req->duration = 0; ++#endif ++ ++#ifdef CONFIG_RADAR_OR_IR_DETECT ++ if (req->ssid_cnt == 0) ++ chan_flags |= CHAN_NO_IR; ++#endif ++ for (i = 0; i < req->ssid_cnt; i++) { ++ int j; ++ for (j = 0; j < param->ssids[i].ssid_len; j++) ++ req->ssid[i].array[j] = param->ssids[i].ssid[j]; ++ req->ssid[i].length = param->ssids[i].ssid_len; ++ ++ if (!memcmp(P2P_WILDCARD_SSID, param->ssids[i].ssid, ++ P2P_WILDCARD_SSID_LEN)) { ++ AICWFDBG(LOGINFO, "p2p scanu:%d,%d,%d\n", ++ rwnx_vif->vif_index, ++ rwnx_vif->is_p2p_vif, ++ rwnx_hw->is_p2p_alive); ++#ifdef CONFIG_USE_P2P0 ++ if (rwnx_vif->is_p2p_vif && ++ !rwnx_hw->is_p2p_alive) { ++#else ++ if (rwnx_vif == rwnx_hw->p2p_dev_vif && !rwnx_vif->up) { ++#endif ++ err = rwnx_send_add_if( ++ rwnx_hw, rwnx_vif->wdev.address, ++ RWNX_VIF_TYPE(rwnx_vif), false, ++ &add_if_cfm); ++ if (err) ++ goto error; ++ ++ if (add_if_cfm.status != 0) { ++ return -EIO; ++ } ++ ++ /* Save the index retrieved from LMAC */ ++ spin_lock_bh(&rwnx_hw->cb_lock); ++ rwnx_vif->vif_index = ++ add_if_cfm.inst_nbr; ++ rwnx_vif->up = true; ++ rwnx_hw->vif_started++; ++ rwnx_hw->vif_table[add_if_cfm.inst_nbr] = ++ rwnx_vif; ++ spin_unlock_bh(&rwnx_hw->cb_lock); ++ } ++ rwnx_hw->is_p2p_alive = 1; ++#ifndef CONFIG_USE_P2P0 ++ mod_timer(&rwnx_hw->p2p_alive_timer, ++ jiffies + msecs_to_jiffies(1000)); ++ atomic_set(&rwnx_hw->p2p_alive_timer_count, 0); ++#endif ++ AICWFDBG(LOGINFO, "p2p scan start\n"); ++ } ++ } ++ ++#if 1 ++ if (param->ie) { ++#if 0 ++ if (rwnx_ipc_elem_var_allocs(rwnx_hw, &rwnx_hw->scan_ie, ++ param->ie_len, DMA_TO_DEVICE, ++ NULL, param->ie, NULL)) ++ goto error; ++ ++ req->add_ie_len = param->ie_len; ++ req->add_ies = rwnx_hw->scan_ie.dma_addr; ++#else ++ ie_req = rwnx_msg_zalloc(SCANU_VENDOR_IE_REQ, TASK_SCANU, ++ DRV_TASK_ID, ++ sizeof(struct scanu_vendor_ie_req)); ++ if (!ie_req) ++ return -ENOMEM; ++ ++ ie_req->add_ie_len = param->ie_len; ++ ie_req->vif_idx = rwnx_vif->vif_index; ++ memcpy(ie_req->ie, param->ie, param->ie_len); ++#ifdef CONFIG_SET_VENDOR_EXTENSION_IE ++ rwnx_insert_vendor_extension_data(ie_req); ++#endif //CONFIG_SET_VENDOR_EXTENSION_IE ++ req->add_ie_len = 0; ++ req->add_ies = 0; ++ ++ err = rwnx_send_msg(rwnx_hw, ie_req, 1, SCANU_VENDOR_IE_CFM, ++ NULL); ++ if (err) ++ goto error; ++#endif ++ } else { ++ req->add_ie_len = 0; ++ req->add_ies = 0; ++ } ++#else ++ req->add_ie_len = 0; ++ req->add_ies = 0; ++#endif ++ ++ for (i = 0; i < req->chan_cnt; i++) { ++ struct ieee80211_channel *chan = param->channels[i]; ++ AICWFDBG(LOGDEBUG, "scan channel:%d(%d) \r\n", ++ ieee80211_frequency_to_channel( ++ chan->center_freq), ++ chan->center_freq); ++ req->chan[i].band = chan->band; ++ req->chan[i].freq = chan->center_freq; ++ req->chan[i].flags = ++ chan_flags | get_chan_flags(chan->flags); ++ req->chan[i].tx_power = ++ chan_to_fw_pwr(chan->max_reg_power); ++ } ++ ++ /* Send the SCANU_START_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, SCANU_START_CFM_ADDTIONAL, ++ NULL); ++ error: ++ if (req != NULL) ++ rwnx_msg_free(rwnx_hw, req); ++ if (ie_req != NULL) ++ rwnx_msg_free(rwnx_hw, ie_req); ++ return -ENOMEM; ++ } ++ ++ int rwnx_send_scanu_cancel_req(struct rwnx_hw * rwnx_hw, ++ struct scan_cancel_cfm * cfm) ++ { ++ struct scan_cancel_req *req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the SCAN_CANCEL_REQ message */ ++ req = rwnx_msg_zalloc(SCANU_CANCEL_REQ, TASK_SCANU, DRV_TASK_ID, ++ sizeof(struct scan_cancel_req)); ++ if (!req) ++ return -ENOMEM; ++ ++ /* Send the SCAN_CANCEL_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, SCANU_CANCEL_CFM, cfm); ++ } ++ ++ int rwnx_send_apm_start_cac_req(struct rwnx_hw * rwnx_hw, ++ struct rwnx_vif * vif, ++ struct cfg80211_chan_def * chandef, ++ struct apm_start_cac_cfm * cfm) ++ { ++ struct apm_start_cac_req *req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the APM_START_CAC_REQ message */ ++ req = rwnx_msg_zalloc(APM_START_CAC_REQ, TASK_APM, DRV_TASK_ID, ++ sizeof(struct apm_start_cac_req)); ++ if (!req) ++ return -ENOMEM; ++ ++ /* Set parameters for the APM_START_CAC_REQ message */ ++ req->vif_idx = vif->vif_index; ++ req->chan.band = chandef->chan->band; ++ req->chan.type = bw2chnl[chandef->width]; ++ req->chan.prim20_freq = chandef->chan->center_freq; ++ req->chan.center1_freq = chandef->center_freq1; ++ req->chan.center2_freq = chandef->center_freq2; ++ req->chan.tx_power = 20; ++ req->chan.flags = get_chan_flags(chandef->chan->flags); ++ ++ /* Send the APM_START_CAC_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, APM_START_CAC_CFM, cfm); ++ } ++ ++ int rwnx_send_apm_stop_cac_req(struct rwnx_hw * rwnx_hw, ++ struct rwnx_vif * vif) ++ { ++ struct apm_stop_cac_req *req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the APM_STOP_CAC_REQ message */ ++ req = rwnx_msg_zalloc(APM_STOP_CAC_REQ, TASK_APM, DRV_TASK_ID, ++ sizeof(struct apm_stop_cac_req)); ++ if (!req) ++ return -ENOMEM; ++ ++ /* Set parameters for the APM_STOP_CAC_REQ message */ ++ req->vif_idx = vif->vif_index; ++ ++ /* Send the APM_STOP_CAC_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, APM_STOP_CAC_CFM, NULL); ++ } ++ ++ int rwnx_send_mesh_start_req(struct rwnx_hw * rwnx_hw, ++ struct rwnx_vif * vif, ++ const struct mesh_config *conf, ++ const struct mesh_setup *setup, ++ struct mesh_start_cfm *cfm) ++ { ++ // Message to send ++ struct mesh_start_req *req; ++ // Supported basic rates ++ struct ieee80211_supported_band *band_2GHz = ++ rwnx_hw->wiphy->bands[NL80211_BAND_2GHZ]; ++ /* Counter */ ++ int i; ++ /* Return status */ ++ int status; ++ /* DMA Address to be unmapped after confirmation reception */ ++ u32 dma_addr = 0; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MESH_START_REQ message */ ++ req = rwnx_msg_zalloc(MESH_START_REQ, TASK_MESH, DRV_TASK_ID, ++ sizeof(struct mesh_start_req)); ++ if (!req) { ++ return -ENOMEM; ++ } ++ ++ req->vif_index = vif->vif_index; ++ req->bcn_int = setup->beacon_interval; ++ req->dtim_period = setup->dtim_period; ++ req->mesh_id_len = setup->mesh_id_len; ++ ++ for (i = 0; i < setup->mesh_id_len; i++) { ++ req->mesh_id[i] = *(setup->mesh_id + i); ++ } ++ ++ req->user_mpm = setup->user_mpm; ++ req->is_auth = setup->is_authenticated; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) ++ req->auth_id = setup->auth_id; ++#endif ++ req->ie_len = setup->ie_len; ++ ++ if (setup->ie_len) { ++ /* ++ * Need to provide a Virtual Address to the MAC so that it can download the ++ * additional information elements. ++ */ ++ req->ie_addr = ++ dma_map_single(rwnx_hw->dev, (void *)setup->ie, ++ setup->ie_len, DMA_FROM_DEVICE); ++ ++ /* Check DMA mapping result */ ++ if (dma_mapping_error(rwnx_hw->dev, req->ie_addr)) { ++ printk(KERN_CRIT ++ "%s - DMA Mapping error on additional IEs\n", ++ __func__); ++ ++ /* Consider there is no Additional IEs */ ++ req->ie_len = 0; ++ } else { ++ /* Store DMA Address so that we can unmap the memory section once MESH_START_CFM is received */ ++ dma_addr = req->ie_addr; ++ } ++ } ++ ++ /* Provide rate information */ ++ req->basic_rates.length = 0; ++ for (i = 0; i < band_2GHz->n_bitrates; i++) { ++ u16 rate = band_2GHz->bitrates[i].bitrate; ++ ++ /* Read value is in in units of 100 Kbps, provided value is in units ++ * of 1Mbps, and multiplied by 2 so that 5.5 becomes 11 */ ++ rate = (rate << 1) / 10; ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) // TODO: check basic rates ++ if (setup->basic_rates & CO_BIT(i)) { ++ rate |= 0x80; ++ } ++#endif ++ ++ req->basic_rates.array[i] = (u8)rate; ++ req->basic_rates.length++; ++ } ++ ++ /* Provide channel information */ ++ req->chan.band = setup->chandef.chan->band; ++ req->chan.freq = setup->chandef.chan->center_freq; ++ req->chan.flags = 0; ++ req->chan.tx_power = ++ chan_to_fw_pwr(setup->chandef.chan->max_power); ++ req->center_freq1 = setup->chandef.center_freq1; ++ req->center_freq2 = setup->chandef.center_freq2; ++ req->ch_width = bw2chnl[setup->chandef.width]; ++ ++ /* Send the MESH_START_REQ message to UMAC FW */ ++ status = rwnx_send_msg(rwnx_hw, req, 1, MESH_START_CFM, cfm); ++ ++ /* Unmap DMA area */ ++ if (setup->ie_len) { ++ dma_unmap_single(rwnx_hw->dev, dma_addr, setup->ie_len, ++ DMA_TO_DEVICE); ++ } ++ ++ /* Return the status */ ++ return status; ++ } ++ ++ int rwnx_send_mesh_stop_req(struct rwnx_hw * rwnx_hw, ++ struct rwnx_vif * vif, ++ struct mesh_stop_cfm * cfm) ++ { ++ // Message to send ++ struct mesh_stop_req *req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MESH_STOP_REQ message */ ++ req = rwnx_msg_zalloc(MESH_STOP_REQ, TASK_MESH, DRV_TASK_ID, ++ sizeof(struct mesh_stop_req)); ++ if (!req) { ++ return -ENOMEM; ++ } ++ ++ req->vif_idx = vif->vif_index; ++ ++ /* Send the MESH_STOP_REQ message to UMAC FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, MESH_STOP_CFM, cfm); ++ } ++ ++ int rwnx_send_mesh_update_req(struct rwnx_hw * rwnx_hw, ++ struct rwnx_vif * vif, u32 mask, ++ const struct mesh_config *p_mconf, ++ struct mesh_update_cfm *cfm) ++ { ++ // Message to send ++ struct mesh_update_req *req; ++ // Keep only bit for fields which can be updated ++ u32 supp_mask = (mask << 1) & ++ (CO_BIT(NL80211_MESHCONF_GATE_ANNOUNCEMENTS) | ++ CO_BIT(NL80211_MESHCONF_HWMP_ROOTMODE) | ++ CO_BIT(NL80211_MESHCONF_FORWARDING) | ++ CO_BIT(NL80211_MESHCONF_POWER_MODE)); ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ if (!supp_mask) { ++ return -ENOENT; ++ } ++ ++ /* Build the MESH_UPDATE_REQ message */ ++ req = rwnx_msg_zalloc(MESH_UPDATE_REQ, TASK_MESH, DRV_TASK_ID, ++ sizeof(struct mesh_update_req)); ++ ++ if (!req) { ++ return -ENOMEM; ++ } ++ ++ req->vif_idx = vif->vif_index; ++ ++ if (supp_mask & CO_BIT(NL80211_MESHCONF_GATE_ANNOUNCEMENTS)) { ++ req->flags |= CO_BIT(MESH_UPDATE_FLAGS_GATE_MODE_BIT); ++ req->gate_announ = ++ p_mconf->dot11MeshGateAnnouncementProtocol; ++ } ++ ++ if (supp_mask & CO_BIT(NL80211_MESHCONF_HWMP_ROOTMODE)) { ++ req->flags |= CO_BIT(MESH_UPDATE_FLAGS_ROOT_MODE_BIT); ++ req->root_mode = p_mconf->dot11MeshHWMPRootMode; ++ } ++ ++ if (supp_mask & CO_BIT(NL80211_MESHCONF_FORWARDING)) { ++ req->flags |= CO_BIT(MESH_UPDATE_FLAGS_MESH_FWD_BIT); ++ req->mesh_forward = p_mconf->dot11MeshForwarding; ++ } ++ ++ if (supp_mask & CO_BIT(NL80211_MESHCONF_POWER_MODE)) { ++ req->flags |= CO_BIT(MESH_UPDATE_FLAGS_LOCAL_PSM_BIT); ++ req->local_ps_mode = p_mconf->power_mode; ++ } ++ ++ /* Send the MESH_UPDATE_REQ message to UMAC FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, MESH_UPDATE_CFM, cfm); ++ } ++ ++ int rwnx_send_mesh_peer_info_req(struct rwnx_hw * rwnx_hw, ++ struct rwnx_vif * vif, u8 sta_idx, ++ struct mesh_peer_info_cfm * cfm) ++ { ++ // Message to send ++ struct mesh_peer_info_req *req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MESH_PEER_INFO_REQ message */ ++ req = rwnx_msg_zalloc(MESH_PEER_INFO_REQ, TASK_MESH, ++ DRV_TASK_ID, ++ sizeof(struct mesh_peer_info_req)); ++ if (!req) { ++ return -ENOMEM; ++ } ++ ++ req->sta_idx = sta_idx; ++ ++ /* Send the MESH_PEER_INFO_REQ message to UMAC FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, MESH_PEER_INFO_CFM, cfm); ++ } ++ ++ void rwnx_send_mesh_peer_update_ntf(struct rwnx_hw * rwnx_hw, ++ struct rwnx_vif * vif, u8 sta_idx, ++ u8 mlink_state) ++ { ++ // Message to send ++ struct mesh_peer_update_ntf *ntf; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MESH_PEER_UPDATE_NTF message */ ++ ntf = rwnx_msg_zalloc(MESH_PEER_UPDATE_NTF, TASK_MESH, ++ DRV_TASK_ID, ++ sizeof(struct mesh_peer_update_ntf)); ++ ++ if (ntf) { ++ ntf->vif_idx = vif->vif_index; ++ ntf->sta_idx = sta_idx; ++ ntf->state = mlink_state; ++ ++ /* Send the MESH_PEER_INFO_REQ message to UMAC FW */ ++ rwnx_send_msg(rwnx_hw, ntf, 0, 0, NULL); ++ } ++ } ++ ++ void rwnx_send_mesh_path_create_req( ++ struct rwnx_hw * rwnx_hw, struct rwnx_vif * vif, u8 * tgt_addr) ++ { ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Check if we are already waiting for a confirmation */ ++ if (!vif->ap.create_path) { ++ // Message to send ++ struct mesh_path_create_req *req; ++ ++ /* Build the MESH_PATH_CREATE_REQ message */ ++ req = rwnx_msg_zalloc( ++ MESH_PATH_CREATE_REQ, TASK_MESH, DRV_TASK_ID, ++ sizeof(struct mesh_path_create_req)); ++ ++ if (req) { ++ req->vif_idx = vif->vif_index; ++ memcpy(&req->tgt_mac_addr, tgt_addr, ETH_ALEN); ++ ++ vif->ap.create_path = true; ++ ++ /* Send the MESH_PATH_CREATE_REQ message to UMAC FW */ ++ rwnx_send_msg(rwnx_hw, req, 0, 0, NULL); ++ } ++ } ++ } ++ ++ int rwnx_send_mesh_path_update_req(struct rwnx_hw * rwnx_hw, ++ struct rwnx_vif * vif, ++ const u8 *tgt_addr, ++ const u8 *p_nhop_addr, ++ struct mesh_path_update_cfm *cfm) ++ { ++ // Message to send ++ struct mesh_path_update_req *req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MESH_PATH_UPDATE_REQ message */ ++ req = rwnx_msg_zalloc(MESH_PATH_UPDATE_REQ, TASK_MESH, ++ DRV_TASK_ID, ++ sizeof(struct mesh_path_update_req)); ++ if (!req) { ++ return -ENOMEM; ++ } ++ ++ req->delete = (p_nhop_addr == NULL); ++ req->vif_idx = vif->vif_index; ++ memcpy(&req->tgt_mac_addr, tgt_addr, ETH_ALEN); ++ ++ if (p_nhop_addr) { ++ memcpy(&req->nhop_mac_addr, p_nhop_addr, ETH_ALEN); ++ } ++ ++ /* Send the MESH_PATH_UPDATE_REQ message to UMAC FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, MESH_PATH_UPDATE_CFM, ++ cfm); ++ } ++ ++ void rwnx_send_mesh_proxy_add_req(struct rwnx_hw * rwnx_hw, ++ struct rwnx_vif * vif, u8 * ext_addr) ++ { ++ // Message to send ++ struct mesh_proxy_add_req *req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MESH_PROXY_ADD_REQ message */ ++ req = rwnx_msg_zalloc(MESH_PROXY_ADD_REQ, TASK_MESH, ++ DRV_TASK_ID, ++ sizeof(struct mesh_proxy_add_req)); ++ ++ if (req) { ++ req->vif_idx = vif->vif_index; ++ memcpy(&req->ext_sta_addr, ext_addr, ETH_ALEN); ++ ++ /* Send the MESH_PROXY_ADD_REQ message to UMAC FW */ ++ rwnx_send_msg(rwnx_hw, req, 0, 0, NULL); ++ } ++ } ++ ++ int rwnx_send_tdls_peer_traffic_ind_req(struct rwnx_hw * rwnx_hw, ++ struct rwnx_vif * rwnx_vif) ++ { ++ struct tdls_peer_traffic_ind_req *tdls_peer_traffic_ind_req; ++ ++ if (!rwnx_vif->sta.tdls_sta) ++ return -ENOLINK; ++ ++ /* Build the TDLS_PEER_TRAFFIC_IND_REQ message */ ++ tdls_peer_traffic_ind_req = rwnx_msg_zalloc( ++ TDLS_PEER_TRAFFIC_IND_REQ, TASK_TDLS, DRV_TASK_ID, ++ sizeof(struct tdls_peer_traffic_ind_req)); ++ ++ if (!tdls_peer_traffic_ind_req) ++ return -ENOMEM; ++ ++ /* Set parameters for the TDLS_PEER_TRAFFIC_IND_REQ message */ ++ tdls_peer_traffic_ind_req->vif_index = rwnx_vif->vif_index; ++ tdls_peer_traffic_ind_req->sta_idx = ++ rwnx_vif->sta.tdls_sta->sta_idx; ++ memcpy(&(tdls_peer_traffic_ind_req->peer_mac_addr.array[0]), ++ rwnx_vif->sta.tdls_sta->mac_addr, ETH_ALEN); ++ tdls_peer_traffic_ind_req->dialog_token = ++ 0; // check dialog token value ++ tdls_peer_traffic_ind_req->last_tid = ++ rwnx_vif->sta.tdls_sta->tdls.last_tid; ++ tdls_peer_traffic_ind_req->last_sn = ++ rwnx_vif->sta.tdls_sta->tdls.last_sn; ++ ++ /* Send the TDLS_PEER_TRAFFIC_IND_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, tdls_peer_traffic_ind_req, 0, 0, ++ NULL); ++ } ++ ++ int rwnx_send_config_monitor_req(struct rwnx_hw * rwnx_hw, ++ struct cfg80211_chan_def * chandef, ++ struct me_config_monitor_cfm * cfm) ++ { ++ struct me_config_monitor_req *req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the ME_CONFIG_MONITOR_REQ message */ ++ req = rwnx_msg_zalloc(ME_CONFIG_MONITOR_REQ, TASK_ME, ++ DRV_TASK_ID, ++ sizeof(struct me_config_monitor_req)); ++ if (!req) ++ return -ENOMEM; ++ ++ if (chandef) { ++ req->chan_set = true; ++ ++ req->chan.band = chandef->chan->band; ++ req->chan.type = bw2chnl[chandef->width]; ++ req->chan.prim20_freq = chandef->chan->center_freq; ++ req->chan.center1_freq = chandef->center_freq1; ++ req->chan.center2_freq = chandef->center_freq2; ++ req->chan.tx_power = ++ chan_to_fw_pwr(chandef->chan->max_power); ++ ++ if (rwnx_hw->phy.limit_bw) ++ limit_chan_bw(&req->chan.type, ++ req->chan.prim20_freq, ++ &req->chan.center1_freq); ++ } else { ++ req->chan_set = false; ++ } ++ ++ req->uf = rwnx_hw->mod_params->uf; ++ req->auto_reply = rwnx_hw->mod_params->auto_reply; ++ ++ /* Send the ME_CONFIG_MONITOR_REQ message to FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, ME_CONFIG_MONITOR_CFM, ++ cfm); ++ } ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++ int rwnx_send_tdls_chan_switch_req(struct rwnx_hw * rwnx_hw, ++ struct rwnx_vif * rwnx_vif, ++ struct rwnx_sta * rwnx_sta, ++ bool sta_initiator, u8 oper_class, ++ struct cfg80211_chan_def *chandef, ++ struct tdls_chan_switch_cfm *cfm) ++ { ++ struct tdls_chan_switch_req *tdls_chan_switch_req; ++ ++ /* Build the TDLS_CHAN_SWITCH_REQ message */ ++ tdls_chan_switch_req = ++ rwnx_msg_zalloc(TDLS_CHAN_SWITCH_REQ, TASK_TDLS, ++ DRV_TASK_ID, ++ sizeof(struct tdls_chan_switch_req)); ++ ++ if (!tdls_chan_switch_req) ++ return -ENOMEM; ++ ++ /* Set parameters for the TDLS_CHAN_SWITCH_REQ message */ ++ tdls_chan_switch_req->vif_index = rwnx_vif->vif_index; ++ tdls_chan_switch_req->sta_idx = rwnx_sta->sta_idx; ++ memcpy(&(tdls_chan_switch_req->peer_mac_addr.array[0]), ++ rwnx_sta_addr(rwnx_sta), ETH_ALEN); ++ tdls_chan_switch_req->initiator = sta_initiator; ++ tdls_chan_switch_req->band = chandef->chan->band; ++ tdls_chan_switch_req->type = bw2chnl[chandef->width]; ++ tdls_chan_switch_req->prim20_freq = chandef->chan->center_freq; ++ tdls_chan_switch_req->center1_freq = chandef->center_freq1; ++ tdls_chan_switch_req->center2_freq = chandef->center_freq2; ++ tdls_chan_switch_req->tx_power = ++ chan_to_fw_pwr(chandef->chan->max_power); ++ tdls_chan_switch_req->op_class = oper_class; ++ ++ /* Send the TDLS_CHAN_SWITCH_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, tdls_chan_switch_req, 1, ++ TDLS_CHAN_SWITCH_CFM, cfm); ++ } ++ ++ int rwnx_send_tdls_cancel_chan_switch_req( ++ struct rwnx_hw * rwnx_hw, struct rwnx_vif * rwnx_vif, ++ struct rwnx_sta * rwnx_sta, ++ struct tdls_cancel_chan_switch_cfm * cfm) ++ { ++ struct tdls_cancel_chan_switch_req *tdls_cancel_chan_switch_req; ++ ++ /* Build the TDLS_CHAN_SWITCH_REQ message */ ++ tdls_cancel_chan_switch_req = rwnx_msg_zalloc( ++ TDLS_CANCEL_CHAN_SWITCH_REQ, TASK_TDLS, DRV_TASK_ID, ++ sizeof(struct tdls_cancel_chan_switch_req)); ++ if (!tdls_cancel_chan_switch_req) ++ return -ENOMEM; ++ ++ /* Set parameters for the TDLS_CHAN_SWITCH_REQ message */ ++ tdls_cancel_chan_switch_req->vif_index = rwnx_vif->vif_index; ++ tdls_cancel_chan_switch_req->sta_idx = rwnx_sta->sta_idx; ++ memcpy(&(tdls_cancel_chan_switch_req->peer_mac_addr.array[0]), ++ rwnx_sta_addr(rwnx_sta), ETH_ALEN); ++ ++ /* Send the TDLS_CHAN_SWITCH_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, tdls_cancel_chan_switch_req, 1, ++ TDLS_CANCEL_CHAN_SWITCH_CFM, cfm); ++ } ++ ++#ifdef CONFIG_RWNX_BFMER ++#ifdef CONFIG_RWNX_FULLMAC ++ void rwnx_send_bfmer_enable(struct rwnx_hw * rwnx_hw, ++ struct rwnx_sta * rwnx_sta, ++ const struct ieee80211_vht_cap *vht_cap) ++#endif /* CONFIG_RWNX_FULLMAC*/ ++ { ++ struct mm_bfmer_enable_req *bfmer_en_req; ++#ifdef CONFIG_RWNX_FULLMAC ++ __le32 vht_capability; ++ u8 rx_nss = 0; ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ if (!vht_cap) { ++#endif /* CONFIG_RWNX_FULLMAC */ ++ goto end; ++ } ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ vht_capability = vht_cap->vht_cap_info; ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++ if (!(vht_capability & ++ IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)) { ++ goto end; ++ } ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ rx_nss = rwnx_bfmer_get_rx_nss(vht_cap); ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++ /* Allocate a structure that will contain the beamforming report */ ++ if (rwnx_bfmer_report_add(rwnx_hw, rwnx_sta, ++ RWNX_BFMER_REPORT_SPACE_SIZE)) { ++ goto end; ++ } ++ ++ /* Build the MM_BFMER_ENABLE_REQ message */ ++ bfmer_en_req = ++ rwnx_msg_zalloc(MM_BFMER_ENABLE_REQ, TASK_MM, ++ DRV_TASK_ID, ++ sizeof(struct mm_bfmer_enable_req)); ++ ++ /* Check message allocation */ ++ if (!bfmer_en_req) { ++ /* Free memory allocated for the report */ ++ rwnx_bfmer_report_del(rwnx_hw, rwnx_sta); ++ ++ /* Do not use beamforming */ ++ goto end; ++ } ++ ++ /* Provide DMA address to the MAC */ ++ bfmer_en_req->host_bfr_addr = rwnx_sta->bfm_report->dma_addr; ++ bfmer_en_req->host_bfr_size = RWNX_BFMER_REPORT_SPACE_SIZE; ++ bfmer_en_req->sta_idx = rwnx_sta->sta_idx; ++#ifdef CONFIG_RWNX_FULLMAC ++ bfmer_en_req->aid = rwnx_sta->aid; ++ bfmer_en_req->rx_nss = rx_nss; ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++ if (vht_capability & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) { ++ bfmer_en_req->vht_mu_bfmee = true; ++ } else { ++ bfmer_en_req->vht_mu_bfmee = false; ++ } ++ ++ /* Send the MM_BFMER_EN_REQ message to LMAC FW */ ++ rwnx_send_msg(rwnx_hw, bfmer_en_req, 0, 0, NULL); ++ ++ end: ++ return; ++ } ++ ++#ifdef CONFIG_RWNX_MUMIMO_TX ++ int rwnx_send_mu_group_update_req(struct rwnx_hw * rwnx_hw, ++ struct rwnx_sta * rwnx_sta) ++ { ++ struct mm_mu_group_update_req *req; ++ int group_id, i = 0; ++ u64 map; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MM_MU_GROUP_UPDATE_REQ message */ ++ req = rwnx_msg_zalloc(MM_MU_GROUP_UPDATE_REQ, TASK_MM, ++ DRV_TASK_ID, ++ sizeof(struct mm_mu_group_update_req) + ++ rwnx_sta->group_info.cnt * ++ sizeof(req->groups[0])); ++ ++ /* Check message allocation */ ++ if (!req) ++ return -ENOMEM; ++ ++ /* Go through the groups the STA belongs to */ ++ group_sta_for_each(rwnx_sta, group_id, map) ++ { ++ int user_pos = rwnx_mu_group_sta_get_pos( ++ rwnx_hw, rwnx_sta, group_id); ++ ++ if (WARN((i >= rwnx_sta->group_info.cnt), ++ "STA%d: Too much group (%d)\n", ++ rwnx_sta->sta_idx, i + 1)) ++ break; ++ ++ req->groups[i].group_id = group_id; ++ req->groups[i].user_pos = user_pos; ++ ++ i++; ++ } ++ ++ req->group_cnt = rwnx_sta->group_info.cnt; ++ req->sta_idx = rwnx_sta->sta_idx; ++ ++ /* Send the MM_MU_GROUP_UPDATE_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, MM_MU_GROUP_UPDATE_CFM, ++ NULL); ++ } ++#endif /* CONFIG_RWNX_MUMIMO_TX */ ++#endif /* CONFIG_RWNX_BFMER */ ++ ++ /********************************************************************** ++ * Debug Messages ++ *********************************************************************/ ++ int rwnx_send_dbg_trigger_req(struct rwnx_hw * rwnx_hw, char *msg) ++ { ++ struct mm_dbg_trigger_req *req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MM_DBG_TRIGGER_REQ message */ ++ req = rwnx_msg_zalloc(MM_DBG_TRIGGER_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_dbg_trigger_req)); ++ if (!req) ++ return -ENOMEM; ++ ++ /* Set parameters for the MM_DBG_TRIGGER_REQ message */ ++ strncpy(req->error, msg, sizeof(req->error)); ++ ++ /* Send the MM_DBG_TRIGGER_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, req, 0, -1, NULL); ++ } ++ ++ int rwnx_send_dbg_mem_read_req(struct rwnx_hw * rwnx_hw, u32 mem_addr, ++ struct dbg_mem_read_cfm * cfm) ++ { ++ struct dbg_mem_read_req *mem_read_req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the DBG_MEM_READ_REQ message */ ++ mem_read_req = ++ rwnx_msg_zalloc(DBG_MEM_READ_REQ, TASK_DBG, DRV_TASK_ID, ++ sizeof(struct dbg_mem_read_req)); ++ if (!mem_read_req) ++ return -ENOMEM; ++ ++ /* Set parameters for the DBG_MEM_READ_REQ message */ ++ mem_read_req->memaddr = mem_addr; ++ ++ /* Send the DBG_MEM_READ_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, mem_read_req, 1, DBG_MEM_READ_CFM, ++ cfm); ++ } ++ ++ int rwnx_send_dbg_mem_write_req(struct rwnx_hw * rwnx_hw, u32 mem_addr, ++ u32 mem_data) ++ { ++ struct dbg_mem_write_req *mem_write_req; ++ ++ //RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the DBG_MEM_WRITE_REQ message */ ++ mem_write_req = ++ rwnx_msg_zalloc(DBG_MEM_WRITE_REQ, TASK_DBG, ++ DRV_TASK_ID, ++ sizeof(struct dbg_mem_write_req)); ++ if (!mem_write_req) ++ return -ENOMEM; ++ ++ /* Set parameters for the DBG_MEM_WRITE_REQ message */ ++ mem_write_req->memaddr = mem_addr; ++ mem_write_req->memdata = mem_data; ++ ++ /* Send the DBG_MEM_WRITE_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, mem_write_req, 1, ++ DBG_MEM_WRITE_CFM, NULL); ++ } ++ ++ int rwnx_send_dbg_mem_mask_write_req(struct rwnx_hw * rwnx_hw, ++ u32 mem_addr, u32 mem_mask, ++ u32 mem_data) ++ { ++ struct dbg_mem_mask_write_req *mem_mask_write_req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the DBG_MEM_MASK_WRITE_REQ message */ ++ mem_mask_write_req = ++ rwnx_msg_zalloc(DBG_MEM_MASK_WRITE_REQ, TASK_DBG, ++ DRV_TASK_ID, ++ sizeof(struct dbg_mem_mask_write_req)); ++ if (!mem_mask_write_req) ++ return -ENOMEM; ++ ++ /* Set parameters for the DBG_MEM_MASK_WRITE_REQ message */ ++ mem_mask_write_req->memaddr = mem_addr; ++ mem_mask_write_req->memmask = mem_mask; ++ mem_mask_write_req->memdata = mem_data; ++ ++ /* Send the DBG_MEM_MASK_WRITE_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, mem_mask_write_req, 1, ++ DBG_MEM_MASK_WRITE_CFM, NULL); ++ } ++ ++#ifdef CONFIG_RFTEST ++ int rwnx_send_rftest_req(struct rwnx_hw * rwnx_hw, u32_l cmd, ++ u32_l argc, u8_l * argv, ++ struct dbg_rftest_cmd_cfm * cfm) ++ { ++ struct dbg_rftest_cmd_req *mem_rftest_cmd_req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the DBG_RFTEST_CMD_REQ message */ ++ mem_rftest_cmd_req = ++ rwnx_msg_zalloc(DBG_RFTEST_CMD_REQ, TASK_DBG, ++ DRV_TASK_ID, ++ sizeof(struct dbg_rftest_cmd_req)); ++ if (!mem_rftest_cmd_req) ++ return -ENOMEM; ++ ++ if (argc > 10) ++ return -ENOMEM; ++ ++ /* Set parameters for the DBG_MEM_MASK_WRITE_REQ message */ ++ mem_rftest_cmd_req->cmd = cmd; ++ mem_rftest_cmd_req->argc = argc; ++ if (argc != 0) ++ memcpy(mem_rftest_cmd_req->argv, argv, argc); ++ ++ /* Send the DBG_RFTEST_CMD_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, mem_rftest_cmd_req, 1, ++ DBG_RFTEST_CMD_CFM, cfm); ++ } ++#endif ++ ++#ifdef CONFIG_MCU_MESSAGE ++ int rwnx_send_dbg_custom_msg_req(struct rwnx_hw * rwnx_hw, u32 cmd, ++ void *buf, u32 len, u32 action, ++ struct dbg_custom_msg_cfm *cfm) ++ { ++ struct dbg_custom_msg_req *cust_msg_req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the DBG_CUSTOM_MSG_REQ message */ ++ cust_msg_req = rwnx_msg_zalloc( ++ DBG_CUSTOM_MSG_REQ, TASK_DBG, DRV_TASK_ID, ++ offsetof(struct dbg_custom_msg_req, buf) + len); ++ if (!cust_msg_req) ++ return -ENOMEM; ++ ++ /* Set parameters for the DBG_CUSTOM_MSG_REQ message */ ++ cust_msg_req->cmd = cmd; ++ cust_msg_req->len = len; ++ cust_msg_req->flags = action; ++ if (buf) { ++ memcpy(cust_msg_req->buf, buf, len); ++ } ++ ++ /* Send the DBG_CUSTOM_MSG_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, cust_msg_req, 1, ++ DBG_CUSTOM_MSG_CFM, cfm); ++ } ++#endif ++ ++ int rwnx_send_dbg_set_mod_filter_req(struct rwnx_hw * rwnx_hw, ++ u32 filter) ++ { ++ struct dbg_set_mod_filter_req *set_mod_filter_req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the DBG_SET_MOD_FILTER_REQ message */ ++ set_mod_filter_req = ++ rwnx_msg_zalloc(DBG_SET_MOD_FILTER_REQ, TASK_DBG, ++ DRV_TASK_ID, ++ sizeof(struct dbg_set_mod_filter_req)); ++ if (!set_mod_filter_req) ++ return -ENOMEM; ++ ++ /* Set parameters for the DBG_SET_MOD_FILTER_REQ message */ ++ set_mod_filter_req->mod_filter = filter; ++ ++ /* Send the DBG_SET_MOD_FILTER_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, set_mod_filter_req, 1, ++ DBG_SET_MOD_FILTER_CFM, NULL); ++ } ++ ++ int rwnx_send_dbg_set_sev_filter_req(struct rwnx_hw * rwnx_hw, ++ u32 filter) ++ { ++ struct dbg_set_sev_filter_req *set_sev_filter_req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the DBG_SET_SEV_FILTER_REQ message */ ++ set_sev_filter_req = ++ rwnx_msg_zalloc(DBG_SET_SEV_FILTER_REQ, TASK_DBG, ++ DRV_TASK_ID, ++ sizeof(struct dbg_set_sev_filter_req)); ++ if (!set_sev_filter_req) ++ return -ENOMEM; ++ ++ /* Set parameters for the DBG_SET_SEV_FILTER_REQ message */ ++ set_sev_filter_req->sev_filter = filter; ++ ++ /* Send the DBG_SET_SEV_FILTER_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, set_sev_filter_req, 1, ++ DBG_SET_SEV_FILTER_CFM, NULL); ++ } ++ ++ int rwnx_send_dbg_get_sys_stat_req(struct rwnx_hw * rwnx_hw, ++ struct dbg_get_sys_stat_cfm * cfm) ++ { ++ void *req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Allocate the message */ ++ req = rwnx_msg_zalloc(DBG_GET_SYS_STAT_REQ, TASK_DBG, ++ DRV_TASK_ID, 0); ++ if (!req) ++ return -ENOMEM; ++ ++ /* Send the DBG_MEM_READ_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, DBG_GET_SYS_STAT_CFM, ++ cfm); ++ } ++ ++ int rwnx_send_dbg_mem_block_write_req(struct rwnx_hw * rwnx_hw, ++ u32 mem_addr, u32 mem_size, ++ u32 * mem_data) ++ { ++ struct dbg_mem_block_write_req *mem_blk_write_req; ++ ++ //RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the DBG_MEM_BLOCK_WRITE_REQ message */ ++ mem_blk_write_req = ++ rwnx_msg_zalloc(DBG_MEM_BLOCK_WRITE_REQ, TASK_DBG, ++ DRV_TASK_ID, ++ sizeof(struct dbg_mem_block_write_req)); ++ if (!mem_blk_write_req) ++ return -ENOMEM; ++ ++ /* Set parameters for the DBG_MEM_BLOCK_WRITE_REQ message */ ++ mem_blk_write_req->memaddr = mem_addr; ++ mem_blk_write_req->memsize = mem_size; ++ memcpy(mem_blk_write_req->memdata, mem_data, mem_size); ++ ++ /* Send the DBG_MEM_BLOCK_WRITE_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, mem_blk_write_req, 1, ++ DBG_MEM_BLOCK_WRITE_CFM, NULL); ++ } ++ ++ int rwnx_send_dbg_mem_block_read_req( ++ struct rwnx_hw * rwnx_hw, u32 mem_addr, u32 mem_size, ++ struct dbg_mem_block_read_cfm * cfm) ++ { ++ struct dbg_mem_block_read_req *mem_blk_read_req; ++ ++ //RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the DBG_MEM_BLOCK_READ_REQ message */ ++ mem_blk_read_req = ++ rwnx_msg_zalloc(DBG_MEM_BLOCK_READ_REQ, TASK_DBG, ++ DRV_TASK_ID, ++ sizeof(struct dbg_mem_block_read_req)); ++ if (!mem_blk_read_req) ++ return -ENOMEM; ++ ++ /* Set parameters for the DBG_MEM_BLOCK_READ_REQ message */ ++ mem_blk_read_req->memaddr = mem_addr; ++ mem_blk_read_req->memsize = mem_size; ++ ++ /* Send the DBG_MEM_BLOCK_READ_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, mem_blk_read_req, 1, ++ DBG_MEM_BLOCK_READ_CFM, cfm); ++ } ++ ++ int rwnx_send_dbg_start_app_req(struct rwnx_hw * rwnx_hw, u32 boot_addr, ++ u32 boot_type) ++ { ++ struct dbg_start_app_req *start_app_req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* 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) ++ 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(rwnx_hw, start_app_req, 1, ++ DBG_START_APP_CFM, NULL); ++ } ++ ++ int rwnx_send_cfg_rssi_req(struct rwnx_hw * rwnx_hw, u8 vif_index, ++ int rssi_thold, u32 rssi_hyst) ++ { ++ struct mm_cfg_rssi_req *req; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ /* Build the MM_CFG_RSSI_REQ message */ ++ req = rwnx_msg_zalloc(MM_CFG_RSSI_REQ, TASK_MM, DRV_TASK_ID, ++ sizeof(struct mm_cfg_rssi_req)); ++ if (!req) ++ return -ENOMEM; ++ ++ if (rwnx_hw->vif_table[vif_index] == NULL) ++ return 0; ++ ++ /* Set parameters for the MM_CFG_RSSI_REQ message */ ++ req->vif_index = vif_index; ++ req->rssi_thold = (s8)rssi_thold; ++ req->rssi_hyst = (u8)rssi_hyst; ++ ++ /* Send the MM_CFG_RSSI_REQ message to LMAC FW */ ++ return rwnx_send_msg(rwnx_hw, req, 1, MM_CFG_RSSI_CFM, NULL); ++ } +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_tx.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_tx.h +new file mode 100755 +index 000000000..3ae8feec5 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_msg_tx.h +@@ -0,0 +1,230 @@ ++/** ++ **************************************************************************************** ++ * ++ * @file rwnx_msg_tx.h ++ * ++ * @brief TX function declarations ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ **************************************************************************************** ++ */ ++ ++#ifndef _RWNX_MSG_TX_H_ ++#define _RWNX_MSG_TX_H_ ++ ++#include "rwnx_defs.h" ++ ++int rwnx_send_reset(struct rwnx_hw *rwnx_hw); ++int rwnx_send_start(struct rwnx_hw *rwnx_hw); ++int rwnx_send_version_req(struct rwnx_hw *rwnx_hw, struct mm_version_cfm *cfm); ++int rwnx_send_add_if(struct rwnx_hw *rwnx_hw, const unsigned char *mac, ++ enum nl80211_iftype iftype, bool p2p, ++ struct mm_add_if_cfm *cfm); ++int rwnx_send_remove_if(struct rwnx_hw *rwnx_hw, u8 vif_index, bool defer); ++int rwnx_send_set_channel(struct rwnx_hw *rwnx_hw, int phy_idx, ++ struct mm_set_channel_cfm *cfm); ++int rwnx_send_key_add(struct rwnx_hw *rwnx_hw, u8 vif_idx, u8 sta_idx, ++ bool pairwise, u8 *key, u8 key_len, u8 key_idx, ++ u8 cipher_suite, struct mm_key_add_cfm *cfm); ++int rwnx_send_key_del(struct rwnx_hw *rwnx_hw, uint8_t hw_key_idx); ++int rwnx_send_bcn(struct rwnx_hw *rwnx_hw, u8 *buf, u8 vif_idx, u16 bcn_len); ++ ++int rwnx_send_bcn_change(struct rwnx_hw *rwnx_hw, u8 vif_idx, u32 bcn_addr, ++ u16 bcn_len, u16 tim_oft, u16 tim_len, u16 *csa_oft); ++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 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); ++int rwnx_send_set_edca(struct rwnx_hw *rwnx_hw, u8 hw_queue, u32 param, ++ bool uapsd, u8 inst_nbr); ++int rwnx_send_tdls_chan_switch_req(struct rwnx_hw *rwnx_hw, ++ struct rwnx_vif *rwnx_vif, ++ struct rwnx_sta *rwnx_sta, ++ bool sta_initiator, u8 oper_class, ++ struct cfg80211_chan_def *chandef, ++ struct tdls_chan_switch_cfm *cfm); ++int rwnx_send_tdls_cancel_chan_switch_req( ++ struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif, ++ struct rwnx_sta *rwnx_sta, struct tdls_cancel_chan_switch_cfm *cfm); ++ ++#ifdef CONFIG_RWNX_P2P_DEBUGFS ++int rwnx_send_p2p_oppps_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif, ++ u8 ctw, struct mm_set_p2p_oppps_cfm *cfm); ++int rwnx_send_p2p_noa_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif, ++ int count, int interval, int duration, bool dyn_noa, ++ struct mm_set_p2p_noa_cfm *cfm); ++#endif /* CONFIG_RWNX_P2P_DEBUGFS */ ++ ++#ifdef AICWF_ARP_OFFLOAD ++int rwnx_send_arpoffload_en_req(struct rwnx_hw *rwnx_hw, ++ struct rwnx_vif *rwnx_vif, u32_l ipaddr, ++ u8_l enable); ++#endif ++int rwnx_send_rf_config_req(struct rwnx_hw *rwnx_hw, u8_l ofst, u8_l sel, ++ u8_l *tbl, u16_l len); ++int rwnx_send_rf_calib_req(struct rwnx_hw *rwnx_hw, ++ struct mm_set_rf_calib_cfm *cfm); ++int rwnx_send_get_macaddr_req(struct rwnx_hw *rwnx_hw, ++ struct mm_get_mac_addr_cfm *cfm); ++ ++#ifdef CONFIG_RWNX_FULLMAC ++int rwnx_send_me_config_req(struct rwnx_hw *rwnx_hw); ++int rwnx_send_me_chan_config_req(struct rwnx_hw *rwnx_hw, char *ccode); ++int rwnx_send_me_set_control_port_req(struct rwnx_hw *rwnx_hw, bool opened, ++ u8 sta_idx); ++int rwnx_send_me_sta_add(struct rwnx_hw *rwnx_hw, ++ struct station_parameters *params, const u8 *mac, ++ u8 inst_nbr, struct me_sta_add_cfm *cfm); ++int rwnx_send_me_sta_del(struct rwnx_hw *rwnx_hw, u8 sta_idx, bool tdls_sta); ++int rwnx_send_me_traffic_ind(struct rwnx_hw *rwnx_hw, u8 sta_idx, bool uapsd, ++ u8 tx_status); ++int rwnx_send_me_rc_stats(struct rwnx_hw *rwnx_hw, u8 sta_idx, ++ struct me_rc_stats_cfm *cfm); ++int rwnx_send_me_rc_set_rate(struct rwnx_hw *rwnx_hw, u8 sta_idx, u16 rate_idx); ++int rwnx_send_me_set_ps_mode(struct rwnx_hw *rwnx_hw, u8 ps_mode); ++int rwnx_send_me_set_lp_level(struct rwnx_hw *rwnx_hw, u8 lp_level, ++ u8 disable_filter); ++int rwnx_send_sm_connect_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif, ++ struct cfg80211_connect_params *sme, ++ struct sm_connect_cfm *cfm); ++int rwnx_send_sm_disconnect_req(struct rwnx_hw *rwnx_hw, ++ struct rwnx_vif *rwnx_vif, u16 reason); ++int rwnx_send_sm_external_auth_required_rsp(struct rwnx_hw *rwnx_hw, ++ struct rwnx_vif *rwnx_vif, ++ u16 status); ++int rwnx_send_apm_start_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif, ++ struct cfg80211_ap_settings *settings, ++ struct apm_start_cfm *cfm, ++ struct rwnx_ipc_elem_var *elem); ++int rwnx_send_apm_stop_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif); ++int rwnx_send_scanu_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif, ++ struct cfg80211_scan_request *param); ++int rwnx_send_scanu_cancel_req(struct rwnx_hw *rwnx_hw, ++ struct scan_cancel_cfm *cfm); ++ ++int rwnx_send_apm_start_cac_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif, ++ struct cfg80211_chan_def *chandef, ++ struct apm_start_cac_cfm *cfm); ++int rwnx_send_apm_stop_cac_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif); ++int rwnx_send_tdls_peer_traffic_ind_req(struct rwnx_hw *rwnx_hw, ++ struct rwnx_vif *rwnx_vif); ++int rwnx_send_config_monitor_req(struct rwnx_hw *rwnx_hw, ++ struct cfg80211_chan_def *chandef, ++ struct me_config_monitor_cfm *cfm); ++int rwnx_send_mesh_start_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif, ++ const struct mesh_config *conf, ++ const struct mesh_setup *setup, ++ struct mesh_start_cfm *cfm); ++int rwnx_send_mesh_stop_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif, ++ struct mesh_stop_cfm *cfm); ++int rwnx_send_mesh_update_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif, ++ u32 mask, const struct mesh_config *p_mconf, ++ struct mesh_update_cfm *cfm); ++int rwnx_send_mesh_peer_info_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif, ++ u8 sta_idx, struct mesh_peer_info_cfm *cfm); ++void rwnx_send_mesh_peer_update_ntf(struct rwnx_hw *rwnx_hw, ++ struct rwnx_vif *vif, u8 sta_idx, ++ u8 mlink_state); ++void rwnx_send_mesh_path_create_req(struct rwnx_hw *rwnx_hw, ++ struct rwnx_vif *vif, u8 *tgt_addr); ++int rwnx_send_mesh_path_update_req(struct rwnx_hw *rwnx_hw, ++ struct rwnx_vif *vif, const u8 *tgt_addr, ++ const u8 *p_nhop_addr, ++ struct mesh_path_update_cfm *cfm); ++void rwnx_send_mesh_proxy_add_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif, ++ u8 *ext_addr); ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++#ifdef CONFIG_RWNX_BFMER ++#ifdef CONFIG_RWNX_FULLMAC ++void rwnx_send_bfmer_enable(struct rwnx_hw *rwnx_hw, struct rwnx_sta *rwnx_sta, ++ const struct ieee80211_vht_cap *vht_cap); ++#endif /* CONFIG_RWNX_FULLMAC */ ++#ifdef CONFIG_RWNX_MUMIMO_TX ++int rwnx_send_mu_group_update_req(struct rwnx_hw *rwnx_hw, ++ struct rwnx_sta *rwnx_sta); ++#endif /* CONFIG_RWNX_MUMIMO_TX */ ++#endif /* CONFIG_RWNX_BFMER */ ++ ++/* Debug messages */ ++int rwnx_send_dbg_trigger_req(struct rwnx_hw *rwnx_hw, char *msg); ++int rwnx_send_dbg_mem_read_req(struct rwnx_hw *rwnx_hw, u32 mem_addr, ++ struct dbg_mem_read_cfm *cfm); ++int rwnx_send_dbg_mem_write_req(struct rwnx_hw *rwnx_hw, u32 mem_addr, ++ u32 mem_data); ++int rwnx_send_dbg_mem_mask_write_req(struct rwnx_hw *rwnx_hw, u32 mem_addr, ++ u32 mem_mask, u32 mem_data); ++int rwnx_send_dbg_set_mod_filter_req(struct rwnx_hw *rwnx_hw, u32 filter); ++#ifdef CONFIG_RFTEST ++int rwnx_send_rftest_req(struct rwnx_hw *rwnx_hw, u32_l cmd, u32_l argc, ++ u8_l *argv, struct dbg_rftest_cmd_cfm *cfm); ++#endif ++#ifdef CONFIG_MCU_MESSAGE ++int rwnx_send_dbg_custom_msg_req(struct rwnx_hw *rwnx_hw, u32 cmd, void *buf, ++ u32 len, u32 action, ++ struct dbg_custom_msg_cfm *cfm); ++#endif ++int rwnx_send_dbg_set_sev_filter_req(struct rwnx_hw *rwnx_hw, u32 filter); ++int rwnx_send_dbg_get_sys_stat_req(struct rwnx_hw *rwnx_hw, ++ struct dbg_get_sys_stat_cfm *cfm); ++int rwnx_send_dbg_mem_block_write_req(struct rwnx_hw *rwnx_hw, u32 mem_addr, ++ u32 mem_size, u32 *mem_data); ++int rwnx_send_dbg_mem_block_read_req(struct rwnx_hw *rwnx_hw, u32 mem_addr, ++ u32 mem_size, ++ struct dbg_mem_block_read_cfm *cfm); ++int rwnx_send_dbg_start_app_req(struct rwnx_hw *rwnx_hw, u32 boot_addr, ++ 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_disable_agg_req(struct rwnx_hw *rwnx_hw, u8_l agg_disable, ++ u8_l agg_disable_rx, u8_l sta_idx); ++int rwnx_send_coex_req(struct rwnx_hw *rwnx_hw, u8_l disable_coexnull, ++ u8_l enable_nullcts); ++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_temp_req(struct rwnx_hw *rwnx_hw, ++ struct mm_set_vendor_swconfig_cfm *cfm); ++int rwnx_send_set_temp_comp_req(struct rwnx_hw *rwnx_hw, ++ struct mm_set_vendor_swconfig_cfm *cfm); ++int rwnx_send_vendor_hwconfig_req(struct rwnx_hw *rwnx_hw, uint32_t hwconfig_id, ++ int32_t *param, int32_t *param_out); ++int rwnx_send_vendor_swconfig_req(struct rwnx_hw *rwnx_hw, uint32_t swconfig_id, ++ int32_t *param_in, int32_t *param_out); ++int rwnx_send_mask_set_ext_flags_req(struct rwnx_hw *rwnx_hw, ++ uint32_t flags_mask, uint32_t flags_val, ++ struct mm_set_vendor_swconfig_cfm *cfm); ++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); ++int rwnx_send_txpwr_ofst2x_req(struct rwnx_hw *rwnx_hw); ++int rwnx_send_txpwr_ofst2x_v2_req(struct rwnx_hw *rwnx_hw); ++int rwnx_send_set_filter(struct rwnx_hw *rwnx_hw, uint32_t filter); ++int rwnx_send_txpwr_lvl_req(struct rwnx_hw *rwnx_hw); ++int rwnx_send_txpwr_lvl_v3_req(struct rwnx_hw *rwnx_hw); ++int rwnx_send_txpwr_lvl_v4_req(struct rwnx_hw *rwnx_hw); ++int rwnx_send_txpwr_lvl_adj_req(struct rwnx_hw *rwnx_hw); ++#ifdef CONFIG_APF ++int rwnx_send_set_apf_prog_req(struct rwnx_hw *rwnx_hw, u8_l *program, ++ u32_l program_len); ++int rwnx_send_get_apf_prog_req(struct rwnx_hw *rwnx_hw, u8_l *program, ++ u32_l program_len); ++#endif ++ ++#ifdef CONFIG_SDIO_BT ++int rwnx_sdio_bt_send_req(struct rwnx_hw *rwnx_hw, uint32_t len, ++ struct sk_buff *skb); ++#endif ++ ++#endif /* _RWNX_MSG_TX_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mu_group.c b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mu_group.c +new file mode 100755 +index 000000000..100237a44 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mu_group.c +@@ -0,0 +1,678 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_mu_group.c ++ * ++ * Copyright (C) RivieraWaves 2016-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++#include "rwnx_defs.h" ++#include "rwnx_msg_tx.h" ++#include "rwnx_events.h" ++ ++/** ++ * rwnx_mu_group_sta_init - Initialize group information for a STA ++ * ++ * @sta: Sta to initialize ++ */ ++void rwnx_mu_group_sta_init(struct rwnx_sta *sta, ++ const struct ieee80211_vht_cap *vht_cap) ++{ ++ sta->group_info.map = 0; ++ sta->group_info.cnt = 0; ++ sta->group_info.active.next = LIST_POISON1; ++ sta->group_info.update.next = LIST_POISON1; ++ sta->group_info.last_update = 0; ++ sta->group_info.traffic = 0; ++ sta->group_info.group = 0; ++ ++ if (!vht_cap || !(vht_cap->vht_cap_info & ++ IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)) { ++ sta->group_info.map = RWNX_SU_GROUP; ++ } ++} ++ ++/** ++ * rwnx_mu_group_sta_del - Remove a sta from all MU group ++ * ++ * @rwnx_hw: main driver data ++ * @sta: STA to remove ++ * ++ * Remove one sta from all the MU groups it belongs to. ++ */ ++void rwnx_mu_group_sta_del(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta) ++{ ++ struct rwnx_mu_info *mu = &rwnx_hw->mu; ++ int i, j, group_id; ++ bool lock_taken; ++ u64 map; ++ ++ lock_taken = (down_interruptible(&mu->lock) == 0); ++ ++ group_sta_for_each(sta, group_id, map) ++ { ++ struct rwnx_mu_group *group = ++ rwnx_mu_group_from_id(mu, group_id); ++ ++ for (i = 0; i < CONFIG_USER_MAX; i++) { ++ if (group->users[i] == sta) { ++ group->users[i] = NULL; ++ group->user_cnt--; ++ /* Don't keep group with only one user */ ++ if (group->user_cnt == 1) { ++ for (j = 0; j < CONFIG_USER_MAX; j++) { ++ if (group->users[j]) { ++ group->users[j] ++ ->group_info ++ .cnt--; ++ group->users[j] ++ ->group_info ++ .map &= ~BIT_ULL( ++ group->group_id); ++ if (group->users[j] ++ ->group_info ++ .group == ++ group_id) ++ group->users[j] ++ ->group_info ++ .group = ++ 0; ++ group->user_cnt--; ++ break; ++ } ++ } ++ mu->group_cnt--; ++ trace_mu_group_delete(group->group_id); ++ } else { ++ trace_mu_group_update(group); ++ } ++ break; ++ } ++ } ++ ++ WARN((i == CONFIG_USER_MAX), ++ "sta %d doesn't belongs to group %d", sta->sta_idx, ++ group_id); ++ } ++ ++ sta->group_info.map = 0; ++ sta->group_info.cnt = 0; ++ sta->group_info.traffic = 0; ++ ++ if (sta->group_info.active.next != LIST_POISON1) ++ list_del(&sta->group_info.active); ++ ++ if (sta->group_info.update.next != LIST_POISON1) ++ list_del(&sta->group_info.update); ++ ++ if (lock_taken) ++ up(&mu->lock); ++} ++ ++/** ++ * rwnx_mu_group_sta_get_map - Get the list of group a STA belongs to ++ * ++ * @sta: pointer to the sta ++ * ++ * @return the list of group a STA belongs to as a bitfield ++ */ ++u64 rwnx_mu_group_sta_get_map(struct rwnx_sta *sta) ++{ ++ if (sta) ++ return sta->group_info.map; ++ return 0; ++} ++ ++/** ++ * rwnx_mu_group_sta_get_pos - Get sta position in a group ++ * ++ * @rwnx_hw: main driver data ++ * @sta: pointer to the sta ++ * @group_id: Group id ++ * ++ * @return the positon of @sta in group @group_id or -1 if the sta ++ * doesn't belongs to the group (or group id is invalid) ++ */ ++int rwnx_mu_group_sta_get_pos(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta, ++ int group_id) ++{ ++ struct rwnx_mu_group *group; ++ int i; ++ ++ group = rwnx_mu_group_from_id(&rwnx_hw->mu, group_id); ++ if (!group) ++ return -1; ++ ++ for (i = 0; i < CONFIG_USER_MAX; i++) { ++ if (group->users[i] == sta) ++ return i; ++ } ++ ++ WARN(1, "sta %d doesn't belongs to group %d", sta->sta_idx, group_id); ++ return -1; ++} ++ ++/** ++ * rwnx_mu_group_move_head - Move (or add) one element at the top of a list ++ * ++ * @list: list pointer ++ * @elem: element to move (or add) at the top of @list ++ * ++ */ ++static inline void rwnx_mu_group_move_head(struct list_head *list, ++ struct list_head *elem) ++{ ++ if (elem->next != LIST_POISON1) { ++ __list_del_entry(elem); ++ } ++ list_add(elem, list); ++} ++ ++/** ++ * rwnx_mu_group_remove_users - Remove all the users of a group ++ * ++ * @mu: pointer on MU info ++ * @group: pointer on group to remove users from ++ * ++ * Loop over all users one one group and remove this group from their ++ * map (and count). ++ * Each users is also added to the update_sta list, so that group info ++ * will be resent to fw for this user. ++ */ ++static inline void rwnx_mu_group_remove_users(struct rwnx_mu_info *mu, ++ struct rwnx_mu_group *group) ++{ ++ struct rwnx_sta *sta; ++ int i, group_id = group->group_id; ++ ++ for (i = 0; i < CONFIG_USER_MAX; i++) { ++ if (group->users[i]) { ++ sta = group->users[i]; ++ group->users[i] = NULL; ++ sta->group_info.cnt--; ++ sta->group_info.map &= ~BIT_ULL(group_id); ++ rwnx_mu_group_move_head(&mu->update_sta, ++ &sta->group_info.update); ++ } ++ } ++ ++ if (group->user_cnt) ++ mu->group_cnt--; ++ group->user_cnt = 0; ++ trace_mu_group_delete(group_id); ++} ++ ++/** ++ * rwnx_mu_group_add_users - Add users to a group ++ * ++ * @mu: pointer on MU info ++ * @group: pointer on group to add users in ++ * @nb_user: number of users to ad ++ * @users: table of user to add ++ * ++ * Add @nb_users to @group (which may already have users) ++ * Each new users is added to the first free position. ++ * It is assume that @group has at least @nb_user free position. If it is not ++ * case it only add the number of users needed to complete the group. ++ * Each users (effectively added to @group) is also added to the update_sta ++ * list, so that group info will be resent to fw for this user. ++ */ ++static inline void rwnx_mu_group_add_users(struct rwnx_mu_info *mu, ++ struct rwnx_mu_group *group, ++ int nb_user, struct rwnx_sta **users) ++{ ++ int i, j, group_id = group->group_id; ++ ++ if (!group->user_cnt) ++ mu->group_cnt++; ++ ++ j = 0; ++ for (i = 0; i < nb_user; i++) { ++ for (; j < CONFIG_USER_MAX; j++) { ++ if (group->users[j] == NULL) { ++ group->users[j] = users[i]; ++ users[i]->group_info.cnt++; ++ users[i]->group_info.map |= BIT_ULL(group_id); ++ ++ rwnx_mu_group_move_head( ++ &(mu->update_sta), ++ &(users[i]->group_info.update)); ++ group->user_cnt++; ++ j++; ++ break; ++ } ++ ++ WARN(j == (CONFIG_USER_MAX - 1), ++ "Too many user for group %d (nb_user=%d)", ++ group_id, group->user_cnt + nb_user - i); ++ } ++ } ++ ++ trace_mu_group_update(group); ++} ++ ++/** ++ * rwnx_mu_group_create_one - create on group with a specific group of user ++ * ++ * @mu: pointer on MU info ++ * @nb_user: number of user to include in the group (<= CONFIG_USER_MAX) ++ * @users: table of users ++ * ++ * Try to create a new group with a specific group of users. ++ * 1- First it checks if a group containing all this users already exists. ++ * ++ * 2- Then it checks if it is possible to complete a group which already ++ * contains at least one user. ++ * ++ * 3- Finally it create a new group. To do so, it take take the last group of ++ * the active_groups list, remove all its current users and add the new ones ++ * ++ * In all cases, the group selected is moved at the top of the active_groups ++ * list ++ * ++ * @return 1 if a new group has been created and 0 otherwise ++ */ ++static int rwnx_mu_group_create_one(struct rwnx_mu_info *mu, int nb_user, ++ struct rwnx_sta **users, int *nb_group_left) ++{ ++ int i, group_id; ++ struct rwnx_mu_group *group; ++ u64 group_match; ++ u64 group_avail; ++ ++ group_match = users[0]->group_info.map; ++ group_avail = users[0]->group_info.map; ++ for (i = 1; i < nb_user; i++) { ++ group_match &= users[i]->group_info.map; ++ group_avail |= users[i]->group_info.map; ++ } ++ ++ if (group_match) { ++ /* a group (or more) with all the users already exist */ ++ group_id = RWNX_GET_FIRST_GROUP_ID(group_match); ++ group = rwnx_mu_group_from_id(mu, group_id); ++ rwnx_mu_group_move_head(&mu->active_groups, &group->list); ++ return 0; ++ } ++ ++#if CONFIG_USER_MAX > 2 ++ if (group_avail) { ++ /* check if we can complete a group */ ++ struct rwnx_sta *users2[CONFIG_USER_MAX]; ++ int nb_user2; ++ ++ group_for_each(group_id, group_avail) ++ { ++ group = rwnx_mu_group_from_id(mu, group_id); ++ if (group->user_cnt == CONFIG_USER_MAX) ++ continue; ++ ++ nb_user2 = 0; ++ for (i = 0; i < nb_user; i++) { ++ if (!(users[i]->group_info.map & ++ BIT_ULL(group_id))) { ++ users2[nb_user2] = users[i]; ++ nb_user2++; ++ } ++ } ++ ++ if ((group->user_cnt + nb_user2) <= CONFIG_USER_MAX) { ++ rwnx_mu_group_add_users(mu, group, nb_user2, ++ users2); ++ rwnx_mu_group_move_head(&mu->active_groups, ++ &group->list); ++ return 0; ++ } ++ } ++ } ++#endif /* CONFIG_USER_MAX > 2*/ ++ ++ /* create a new group */ ++ group = list_last_entry(&mu->active_groups, struct rwnx_mu_group, list); ++ rwnx_mu_group_remove_users(mu, group); ++ rwnx_mu_group_add_users(mu, group, nb_user, users); ++ rwnx_mu_group_move_head(&mu->active_groups, &group->list); ++ (*nb_group_left)--; ++ ++ return 1; ++} ++ ++/** ++ * rwnx_mu_group_create - Create new groups containing one specific sta ++ * ++ * @mu: pointer on MU info ++ * @sta: sta to add in each group ++ * @nb_group_left: maximum number to new group allowed. (updated on exit) ++ * ++ * This will try to create "all the possible" group with a specific sta being ++ * a member of all these group. ++ * The function simply loops over the @active_sta list (starting from @sta). ++ * When it has (CONFIG_USER_MAX - 1) users it try to create a new group with ++ * these users (plus @sta). ++ * Loops end when there is no more users, or no more new group is allowed ++ * ++ */ ++static void rwnx_mu_group_create(struct rwnx_mu_info *mu, struct rwnx_sta *sta, ++ int *nb_group_left) ++{ ++ struct rwnx_sta *user_sta = sta; ++ struct rwnx_sta *users[CONFIG_USER_MAX]; ++ int nb_user = 1; ++ ++ users[0] = sta; ++ while (*nb_group_left) { ++ list_for_each_entry_continue (user_sta, &mu->active_sta, ++ group_info.active) { ++ users[nb_user] = user_sta; ++ if (++nb_user == CONFIG_USER_MAX) { ++ break; ++ } ++ } ++ ++ if (nb_user > 1) { ++ if (rwnx_mu_group_create_one(mu, nb_user, users, ++ nb_group_left)) ++ (*nb_group_left)--; ++ ++ if (nb_user < CONFIG_USER_MAX) ++ break; ++ else ++ nb_user = 1; ++ } else ++ break; ++ } ++} ++ ++/** ++ * rwnx_mu_group_work - process function of the "group_work" ++ * ++ * The work is scheduled when several sta (MU beamformee capable) are active. ++ * When called, the @active_sta contains the list of the active sta (starting ++ * from the most recent one), and @active_groups is the list of all possible ++ * groups ordered so that the first one is the most recently used. ++ * ++ * This function will create new groups, starting from group containing the ++ * most "active" sta. ++ * For example if the list of sta is : ++ * sta8 -> sta3 -> sta4 -> sta7 -> sta1 ++ * and the number of user per group is 3, it will create grooups : ++ * - sta8 / sta3 / sta4 ++ * - sta8 / sta7 / sta1 ++ * - sta3 / sta4 / sta7 ++ * - sta3 / sta1 ++ * - sta4 / sta7 / sta1 ++ * - sta7 / sta1 ++ * ++ * To create new group, the least used group are first selected. ++ * It is only allowed to create NX_MU_GROUP_MAX per iteration. ++ * ++ * Once groups have been updated, mu group information is update to the fw. ++ * To do so it use the @update_sta list to know which sta has been affected. ++ * As it is necessary to wait for fw confirmation before using this new group ++ * MU is temporarily disabled during group update ++ * ++ * Work is then rescheduled. ++ * ++ * At the end of the function, both @active_sta and @update_sta list are empty. ++ * ++ * Note: ++ * - This is still a WIP, and will require more tuning ++ * - not all combinations are created, to avoid to much processing. ++ * - reschedule delay should be adaptative ++ */ ++void rwnx_mu_group_work(struct work_struct *ws) ++{ ++ struct delayed_work *dw = container_of(ws, struct delayed_work, work); ++ struct rwnx_mu_info *mu = ++ container_of(dw, struct rwnx_mu_info, group_work); ++ struct rwnx_hw *rwnx_hw = container_of(mu, struct rwnx_hw, mu); ++ struct rwnx_sta *sta, *next; ++ int nb_group_left = NX_MU_GROUP_MAX; ++ ++ if (WARN(!rwnx_hw->mod_params->mutx, ++ "In group formation work, but mutx disabled")) ++ return; ++ ++ if (down_interruptible(&mu->lock) != 0) ++ return; ++ ++ mu->update_count++; ++ if (!mu->update_count) ++ mu->update_count++; ++ ++ list_for_each_entry_safe (sta, next, &mu->active_sta, ++ group_info.active) { ++ if (nb_group_left) ++ rwnx_mu_group_create(mu, sta, &nb_group_left); ++ ++ sta->group_info.last_update = mu->update_count; ++ list_del(&sta->group_info.active); ++ } ++ ++ if (!list_empty(&mu->update_sta)) { ++ list_for_each_entry_safe (sta, next, &mu->update_sta, ++ group_info.update) { ++ rwnx_send_mu_group_update_req(rwnx_hw, sta); ++ list_del(&sta->group_info.update); ++ } ++ } ++ ++ mu->next_group_select = jiffies; ++ rwnx_mu_group_sta_select(rwnx_hw); ++ up(&mu->lock); ++ ++ return; ++} ++ ++/** ++ * rwnx_mu_group_init - Initialize MU groups ++ * ++ * @rwnx_hw: main driver data ++ * ++ * Initialize all MU group ++ */ ++void rwnx_mu_group_init(struct rwnx_hw *rwnx_hw) ++{ ++ struct rwnx_mu_info *mu = &rwnx_hw->mu; ++ int i; ++ ++ INIT_LIST_HEAD(&mu->active_groups); ++ INIT_LIST_HEAD(&mu->active_sta); ++ INIT_LIST_HEAD(&mu->update_sta); ++ ++ for (i = 0; i < NX_MU_GROUP_MAX; i++) { ++ int j; ++ mu->groups[i].user_cnt = 0; ++ mu->groups[i].group_id = i + 1; ++ for (j = 0; j < CONFIG_USER_MAX; j++) { ++ mu->groups[i].users[j] = NULL; ++ } ++ list_add(&mu->groups[i].list, &mu->active_groups); ++ } ++ ++ mu->update_count = 1; ++ mu->group_cnt = 0; ++ mu->next_group_select = jiffies; ++ INIT_DELAYED_WORK(&mu->group_work, rwnx_mu_group_work); ++ sema_init(&mu->lock, 1); ++} ++ ++/** ++ * rwnx_mu_set_active_sta - mark a STA as active ++ * ++ * @rwnx_hw: main driver data ++ * @sta: pointer to the sta ++ * @traffic: Number of buffers to add in the sta's traffic counter ++ * ++ * If @sta is MU beamformee capable (and MU-MIMO tx is enabled) move the ++ * sta at the top of the @active_sta list. ++ * It also schedule the group_work if not already scheduled and the list ++ * contains more than one sta. ++ * ++ * If a STA was already in the list during the last group update ++ * (i.e. sta->group_info.last_update == mu->update_count) it is not added ++ * back to the list until a sta that wasn't active during the last update is ++ * added. This is to avoid scheduling group update with a list of sta that ++ * were all already in the list during previous update. ++ * ++ * It is called with mu->lock taken. ++ */ ++void rwnx_mu_set_active_sta(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta, ++ int traffic) ++{ ++ struct rwnx_mu_info *mu = &rwnx_hw->mu; ++ ++ if (!sta || (sta->group_info.map & RWNX_SU_GROUP)) ++ return; ++ ++ sta->group_info.traffic += traffic; ++ ++ if ((sta->group_info.last_update != mu->update_count) || ++ !list_empty(&mu->active_sta)) { ++ rwnx_mu_group_move_head(&mu->active_sta, ++ &sta->group_info.active); ++ ++ if (!delayed_work_pending(&mu->group_work) && ++ !list_is_singular(&mu->active_sta)) { ++ schedule_delayed_work( ++ &mu->group_work, ++ msecs_to_jiffies(RWNX_MU_GROUP_INTERVAL)); ++ } ++ } ++} ++ ++/** ++ * rwnx_mu_set_active_group - mark a MU group as active ++ * ++ * @rwnx_hw: main driver data ++ * @group_id: Group id ++ * ++ * move a group at the top of the @active_groups list ++ */ ++void rwnx_mu_set_active_group(struct rwnx_hw *rwnx_hw, int group_id) ++{ ++ struct rwnx_mu_info *mu = &rwnx_hw->mu; ++ struct rwnx_mu_group *group = rwnx_mu_group_from_id(mu, group_id); ++ ++ rwnx_mu_group_move_head(&mu->active_groups, &group->list); ++} ++ ++/** ++ * rwnx_mu_group_sta_select - Select the best group for MU stas ++ * ++ * @rwnx_hw: main driver data ++ * ++ * For each MU capable client of AP interfaces this function tries to select ++ * the best group to use. ++ * ++ * In first pass, gather information from all stations to form statistics ++ * for each group for the previous @RWNX_MU_GROUP_SELECT_INTERVAL interval: ++ * - number of buffers transmitted ++ * - number of user ++ * ++ * Then groups with more than 2 active users, are assigned after being ordered ++ * by traffic : ++ * - group with highest traffic is selected: set this group for all its users ++ * - update nb_users for all others group (as one sta may be in several groups) ++ * - select the next group that have still mor than 2 users and assign it. ++ * - continue until all group are processed ++ * ++ */ ++void rwnx_mu_group_sta_select(struct rwnx_hw *rwnx_hw) ++{ ++ struct rwnx_mu_info *mu = &rwnx_hw->mu; ++ int nb_users[NX_MU_GROUP_MAX + 1]; ++ int traffic[NX_MU_GROUP_MAX + 1]; ++ int order[NX_MU_GROUP_MAX + 1]; ++ struct rwnx_sta *sta; ++ struct rwnx_vif *vif; ++ struct list_head *head; ++ u64 map; ++ int i, j, update, group_id, tmp, cnt = 0; ++ ++ if (!mu->group_cnt || time_before(jiffies, mu->next_group_select)) ++ return; ++ ++ list_for_each_entry (vif, &rwnx_hw->vifs, list) { ++ if (RWNX_VIF_TYPE(vif) != NL80211_IFTYPE_AP) ++ continue; ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ head = &vif->ap.sta_list; ++#else ++ head = &vif->stations; ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++ memset(nb_users, 0, sizeof(nb_users)); ++ memset(traffic, 0, sizeof(traffic)); ++ list_for_each_entry (sta, head, list) { ++ int sta_traffic = sta->group_info.traffic; ++ ++ /* reset statistics for next selection */ ++ sta->group_info.traffic = 0; ++ if (sta->group_info.group) ++ trace_mu_group_selection(sta, 0); ++ sta->group_info.group = 0; ++ ++ if (sta->group_info.cnt == 0 || ++ sta_traffic < RWNX_MU_GROUP_MIN_TRAFFIC) ++ continue; ++ ++ group_sta_for_each(sta, group_id, map) ++ { ++ nb_users[group_id]++; ++ traffic[group_id] += sta_traffic; ++ ++ /* list group with 2 users or more */ ++ if (nb_users[group_id] == 2) ++ order[cnt++] = group_id; ++ } ++ } ++ ++ /* reorder list of group with more that 2 users */ ++ update = 1; ++ while (update) { ++ update = 0; ++ for (i = 0; i < cnt - 1; i++) { ++ if (traffic[order[i]] < traffic[order[i + 1]]) { ++ tmp = order[i]; ++ order[i] = order[i + 1]; ++ order[i + 1] = tmp; ++ update = 1; ++ } ++ } ++ } ++ ++ /* now assign group in traffic order */ ++ for (i = 0; i < cnt; i++) { ++ struct rwnx_mu_group *group; ++ group_id = order[i]; ++ ++ if (nb_users[group_id] < 2) ++ continue; ++ ++ group = rwnx_mu_group_from_id(mu, group_id); ++ for (j = 0; j < CONFIG_USER_MAX; j++) { ++ if (group->users[j]) { ++ trace_mu_group_selection( ++ group->users[j], group_id); ++ group->users[j]->group_info.group = ++ group_id; ++ ++ group_sta_for_each(group->users[j], tmp, ++ map) ++ { ++ if (group_id != tmp) ++ nb_users[tmp]--; ++ } ++ } ++ } ++ } ++ } ++ ++ mu->next_group_select = ++ jiffies + msecs_to_jiffies(RWNX_MU_GROUP_SELECT_INTERVAL); ++ mu->next_group_select |= 1; ++} +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mu_group.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mu_group.h +new file mode 100755 +index 000000000..afb0f2b8c +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_mu_group.h +@@ -0,0 +1,178 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_mu_group.h ++ * ++ * Copyright (C) RivieraWaves 2016-2019 ++ * ++ ****************************************************************************** ++ */ ++#ifndef _RWNX_MU_GROUP_H_ ++#define _RWNX_MU_GROUP_H_ ++ ++#include ++#include ++ ++struct rwnx_hw; ++struct rwnx_sta; ++ ++#ifdef CONFIG_RWNX_MUMIMO_TX ++ ++/** ++ * struct rwnx_sta_group_info - Group Information for a STA ++ * ++ * @active: node for @mu->active_sta list ++ * @update: node for @mu->update_sta list ++ * @cnt: Number of groups the STA belongs to ++ * @map: Bitfield of groups the sta belongs to ++ * @traffic: Number of buffers sent since previous group selection ++ * @group: Id of the group selected by previous group selection ++ * (cf @rwnx_mu_group_sta_select) ++ */ ++struct rwnx_sta_group_info { ++ struct list_head active; ++ struct list_head update; ++ u16 last_update; ++ int cnt; ++ u64 map; ++ int traffic; ++ u8 group; ++}; ++ ++/** ++ * struct mu_group_info - Information about the users of a group ++ * ++ * @list: node for mu->active_groups ++ * @group_id: Group identifier ++ * @user_cnt: Number of the users in the group ++ * @users: Pointer to the sta, ordered by user position ++ */ ++struct rwnx_mu_group { ++ struct list_head list; ++ int group_id; ++ int user_cnt; ++ struct rwnx_sta *users[CONFIG_USER_MAX]; ++}; ++ ++/** ++ * struct rwnx_mu_info - Information about all MU group ++ * ++ * @active_groups: List of all possible groups. Ordered from the most recently ++ * used one to the least one (and possibly never used) ++ * @active_sta: List of MU beamformee sta that have been active (since previous ++ * group update). Ordered from the most recently active. ++ * @update_sta: List of sta whose group information has changed and need to be ++ * updated at fw level ++ * @groups: Table of all groups ++ * @group_work: Work item used to schedule group update ++ * @update_count: Counter used to identify the last group formation update. ++ * (cf rwnx_sta_group_info.last_update) ++ * @lock: Lock taken during group update. If tx happens lock is taken, then tx ++ * will not used MU. ++ * @next_group_assign: Next time the group selection should be run ++ * (ref @rwnx_mu_group_sta_select) ++ * @group_cnt: Number of group created ++ */ ++struct rwnx_mu_info { ++ struct list_head active_groups; ++ struct list_head active_sta; ++ struct list_head update_sta; ++ struct rwnx_mu_group groups[NX_MU_GROUP_MAX]; ++ struct delayed_work group_work; ++ u16 update_count; ++ struct semaphore lock; ++ unsigned long next_group_select; ++ u8 group_cnt; ++}; ++ ++#define RWNX_SU_GROUP BIT_ULL(0) ++#define RWNX_MU_GROUP_MASK 0x7ffffffffffffffeULL ++#define RWNX_MU_GROUP_INTERVAL 200 /* in ms */ ++#define RWNX_MU_GROUP_SELECT_INTERVAL 100 /* in ms */ ++// minimum traffic in a RWNX_MU_GROUP_SELECT_INTERVAL to consider the sta ++#define RWNX_MU_GROUP_MIN_TRAFFIC 50 /* in number of packet */ ++ ++#define RWNX_GET_FIRST_GROUP_ID(map) (fls64(map) - 1) ++ ++#define group_sta_for_each(sta, id, map) \ ++ do { \ ++ map = sta->group_info.map & RWNX_MU_GROUP_MASK; \ ++ for (id = (fls64(map) - 1); id > 0; \ ++ map &= ~(u64)BIT_ULL(id), id = (fls64(map) - 1)) \ ++ } while (0) ++ ++#define group_for_each(id, map) \ ++ for (id = (fls64(map) - 1); id > 0; \ ++ map &= ~(u64)BIT_ULL(id), id = (fls64(map) - 1)) ++ ++#define RWNX_MUMIMO_INFO_POS_ID(info) (((info) >> 6) & 0x3) ++#define RWNX_MUMIMO_INFO_GROUP_ID(info) ((info)&0x3f) ++ ++static inline struct rwnx_mu_group * ++rwnx_mu_group_from_id(struct rwnx_mu_info *mu, int id) ++{ ++ if (id > NX_MU_GROUP_MAX) ++ return NULL; ++ ++ return &mu->groups[id - 1]; ++} ++ ++void rwnx_mu_group_sta_init(struct rwnx_sta *sta, ++ const struct ieee80211_vht_cap *vht_cap); ++void rwnx_mu_group_sta_del(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta); ++u64 rwnx_mu_group_sta_get_map(struct rwnx_sta *sta); ++int rwnx_mu_group_sta_get_pos(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta, ++ int group_id); ++ ++void rwnx_mu_group_init(struct rwnx_hw *rwnx_hw); ++ ++void rwnx_mu_set_active_sta(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta, ++ int traffic); ++void rwnx_mu_set_active_group(struct rwnx_hw *rwnx_hw, int group_id); ++void rwnx_mu_group_sta_select(struct rwnx_hw *rwnx_hw); ++ ++#else /* ! CONFIG_RWNX_MUMIMO_TX */ ++ ++static inline void ++rwnx_mu_group_sta_init(struct rwnx_sta *sta, ++ const struct ieee80211_vht_cap *vht_cap) ++{ ++} ++ ++static inline void rwnx_mu_group_sta_del(struct rwnx_hw *rwnx_hw, ++ struct rwnx_sta *sta) ++{ ++} ++ ++static inline u64 rwnx_mu_group_sta_get_map(struct rwnx_sta *sta) ++{ ++ return 0; ++} ++ ++static inline int rwnx_mu_group_sta_get_pos(struct rwnx_hw *rwnx_hw, ++ struct rwnx_sta *sta, int group_id) ++{ ++ return 0; ++} ++ ++static inline void rwnx_mu_group_init(struct rwnx_hw *rwnx_hw) ++{ ++} ++ ++static inline void rwnx_mu_set_active_sta(struct rwnx_hw *rwnx_hw, ++ struct rwnx_sta *sta, int traffic) ++{ ++} ++ ++static inline void rwnx_mu_set_active_group(struct rwnx_hw *rwnx_hw, ++ int group_id) ++{ ++} ++ ++static inline void rwnx_mu_group_sta_select(struct rwnx_hw *rwnx_hw) ++{ ++} ++ ++#endif /* CONFIG_RWNX_MUMIMO_TX */ ++ ++#endif /* _RWNX_MU_GROUP_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_platform.c b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_platform.c +new file mode 100755 +index 000000000..fa3790763 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_platform.c +@@ -0,0 +1,4029 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_platform.c ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "rwnx_platform.h" ++#include "reg_access.h" ++#include "hal_desc.h" ++#include "rwnx_main.h" ++/* flare-edge (6.18 port, PORT-PLAN.md §4.1): rwnx_pci.{c,h} are dead code on ++ * this board (SDIO-only, no PCIe variant) and were dropped from the tree. ++ * rwnx_platform_{,un}register_drv() below are already only called under ++ * AICWF_PCIE_SUPPORT (rwnx_main.c); guard their pci-specific bodies to ++ * match instead of carrying the header forward. */ ++#ifdef AICWF_PCIE_SUPPORT ++#include "rwnx_pci.h" ++#endif ++#ifndef CONFIG_RWNX_FHOST ++#include "ipc_host.h" ++#endif /* !CONFIG_RWNX_FHOST */ ++#include "rwnx_msg_tx.h" ++ ++#ifdef AICWF_SDIO_SUPPORT ++#include "aicwf_sdio.h" ++#endif ++ ++#ifdef AICWF_USB_SUPPORT ++#include "aicwf_usb.h" ++#endif ++#include "md5.h" ++#include "aicwf_compat_8800dc.h" ++#include "aicwf_compat_8800d80.h" ++ ++#ifdef CONFIG_USE_FW_REQUEST ++#include ++#endif ++ ++#define FW_PATH_MAX_LEN 200 ++extern char aic_fw_path[FW_PATH_MAX_LEN]; ++ ++//Parser state ++#define INIT 0 ++#define CMD 1 ++#define PRINT 2 ++#define GET_VALUE 3 ++ ++struct rwnx_plat *g_rwnx_plat; ++ ++typedef struct { ++ txpwr_lvl_conf_t txpwr_lvl; ++ txpwr_lvl_conf_v2_t txpwr_lvl_v2; ++ txpwr_lvl_conf_v3_t txpwr_lvl_v3; ++ txpwr_lvl_conf_v4_t txpwr_lvl_v4; ++ txpwr_lvl_adj_conf_t txpwr_lvl_adj; ++ txpwr_loss_conf_t txpwr_loss; ++ txpwr_ofst_conf_t txpwr_ofst; ++ txpwr_ofst2x_conf_t txpwr_ofst2x; ++ txpwr_ofst2x_conf_v2_t txpwr_ofst2x_v2; ++ xtal_cap_conf_t xtal_cap; ++} userconfig_info_t; ++ ++userconfig_info_t userconfig_info = { ++ .txpwr_lvl = { ++ .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_lvl_v2 = { ++ .enable = 1, ++ .pwrlvl_11b_11ag_2g4 = ++ //1M, 2M, 5M5, 11M, 6M, 9M, 12M, 18M, 24M, 36M, 48M, 54M ++ { 20, 20, 20, 20, 20, 20, 20, 20, 18, 18, 16, 16}, ++ .pwrlvl_11n_11ac_2g4 = ++ //MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9 ++ { 20, 20, 20, 20, 18, 18, 16, 16, 16, 16}, ++ .pwrlvl_11ax_2g4 = ++ //MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9, MCS10,MCS11 ++ { 20, 20, 20, 20, 18, 18, 16, 16, 16, 16, 15, 15}, ++ }, ++ .txpwr_lvl_v3 = { ++ .enable = 1, ++ .pwrlvl_11b_11ag_2g4 = ++ //1M, 2M, 5M5, 11M, 6M, 9M, 12M, 18M, 24M, 36M, 48M, 54M ++ { 20, 20, 20, 20, 20, 20, 20, 20, 18, 18, 16, 16}, ++ .pwrlvl_11n_11ac_2g4 = ++ //MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9 ++ { 20, 20, 20, 20, 18, 18, 16, 16, 16, 16}, ++ .pwrlvl_11ax_2g4 = ++ //MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9, MCS10,MCS11 ++ { 20, 20, 20, 20, 18, 18, 16, 16, 16, 16, 15, 15}, ++ .pwrlvl_11a_5g = ++ //NA, NA, NA, NA, 6M, 9M, 12M, 18M, 24M, 36M, 48M, 54M ++ { 0x80, 0x80, 0x80, 0x80, 20, 20, 20, 20, 18, 18, 16, 16}, ++ .pwrlvl_11n_11ac_5g = ++ //MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9 ++ { 20, 20, 20, 20, 18, 18, 16, 16, 16, 15}, ++ .pwrlvl_11ax_5g = ++ //MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9, MCS10,MCS11 ++ { 20, 20, 20, 20, 18, 18, 16, 16, 16, 15, 14, 14}, ++ }, ++ .txpwr_lvl_v4 = { ++ .enable = 1, ++ .pwrlvl_11b_11ag_2g4 = ++ //1M, 2M, 5M5, 11M, 6M, 9M, 12M, 18M, 24M, 36M, 48M, 54M ++ { 20, 20, 20, 20, 20, 20, 20, 20, 18, 18, 16, 16}, ++ .pwrlvl_11n_11ac_2g4 = ++ //MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9 ++ { 20, 20, 20, 20, 18, 18, 16, 16, 16, 16}, ++ .pwrlvl_11ax_2g4 = ++ //MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9, MCS10,MCS11 ++ { 20, 20, 20, 20, 18, 18, 16, 16, 16, 16, 15, 15}, ++ .pwrlvl_11a_5g = ++ //6M, 9M, 12M, 18M, 24M, 36M, 48M, 54M ++ { 20, 20, 20, 20, 18, 18, 16, 16}, ++ .pwrlvl_11n_11ac_5g = ++ //MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9 ++ { 20, 20, 20, 20, 18, 18, 16, 16, 16, 15}, ++ .pwrlvl_11ax_5g = ++ //MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9, MCS10,MCS11 ++ { 20, 20, 20, 20, 18, 18, 16, 16, 16, 15, 14, 14}, ++ }, ++ .txpwr_loss = { ++ .loss_enable_2g4 = 0, ++ .loss_value_2g4 = 0, ++ .loss_enable_5g = 0, ++ .loss_value_5g = 0, ++ }, ++ .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, ++ }, ++ .txpwr_ofst2x = { ++ .enable = 0, ++ .pwrofst2x_tbl_2g4 = ++ { // ch1-4, ch5-9, ch10-13 ++ { 0, 0, 0 }, // 11b ++ { 0, 0, 0 }, // ofdm_highrate ++ { 0, 0, 0 }, // ofdm_lowrate ++ }, ++ .pwrofst2x_tbl_5g = ++ { // ch42, ch58, ch106,ch122,ch138,ch155 ++ { 0, 0, 0, 0, 0, 0 }, // ofdm_lowrate ++ { 0, 0, 0, 0, 0, 0 }, // ofdm_highrate ++ { 0, 0, 0, 0, 0, 0 }, // ofdm_midrate ++ }, ++ }, ++ .txpwr_ofst2x_v2 = { ++ .enable = 0, ++ .pwrofst_flags = 0, ++ .pwrofst2x_tbl_2g4_ant0 = ++ { // 11b, ofdm_highrate, ofdm_lowrate ++ { 0, 0, 0 }, // ch1-4 ++ { 0, 0, 0 }, // ch5-9 ++ { 0, 0, 0 }, // ch10-13 ++ }, ++ .pwrofst2x_tbl_2g4_ant1 = ++ { // 11b, ofdm_highrate, ofdm_lowrate ++ { 0, 0, 0 }, // ch1-4 ++ { 0, 0, 0 }, // ch5-9 ++ { 0, 0, 0 }, // ch10-13 ++ }, ++ .pwrofst2x_tbl_5g_ant0 = ++ { // ofdm_highrate, ofdm_lowrate, ofdm_midrate ++ { 0, 0, 0 }, // ch42 ++ { 0, 0, 0 }, // ch58 ++ { 0, 0, 0 }, // ch106 ++ { 0, 0, 0 }, // ch122 ++ { 0, 0, 0 }, // ch138 ++ { 0, 0, 0 }, // ch155 ++ }, ++ .pwrofst2x_tbl_5g_ant1 = ++ { // ofdm_highrate, ofdm_lowrate, ofdm_midrate ++ { 0, 0, 0 }, // ch42 ++ { 0, 0, 0 }, // ch58 ++ { 0, 0, 0 }, // ch106 ++ { 0, 0, 0 }, // ch122 ++ { 0, 0, 0 }, // ch138 ++ { 0, 0, 0 }, // ch155 ++ }, ++ .pwrofst2x_tbl_6g_ant0 = { 0, }, // ofdm_highrate: 6e_ch7 ~ 6e_ch229 ++ .pwrofst2x_tbl_6g_ant1 = { 0, }, // ofdm_highrate: 6e_ch7 ~ 6e_ch229 ++ }, ++ .xtal_cap = { ++ .enable = 0, ++ .xtal_cap = 24, ++ .xtal_cap_fine = 31, ++ }, ++}; ++ ++typedef struct { ++ char ccode[3]; ++ Regions_code region; ++} reg_table; ++ ++/* If the region conflicts with the kernel, the actual authentication standard prevails */ ++reg_table reg_tables[] = { ++ { .ccode = "CN", .region = REGIONS_SRRC }, ++ { .ccode = "US", .region = REGIONS_FCC }, ++ { .ccode = "DE", .region = REGIONS_ETSI }, ++ { .ccode = "00", .region = REGIONS_DEFAULT }, ++ { .ccode = "WW", .region = REGIONS_DEFAULT }, ++ { .ccode = "XX", .region = REGIONS_DEFAULT }, ++ { .ccode = "JP", .region = REGIONS_JP }, ++ { .ccode = "AD", .region = REGIONS_ETSI }, ++ { .ccode = "AE", .region = REGIONS_ETSI }, ++ { .ccode = "AF", .region = REGIONS_ETSI }, ++ { .ccode = "AI", .region = REGIONS_ETSI }, ++ { .ccode = "AL", .region = REGIONS_ETSI }, ++ { .ccode = "AM", .region = REGIONS_ETSI }, ++ { .ccode = "AN", .region = REGIONS_ETSI }, ++ { .ccode = "AR", .region = REGIONS_FCC }, ++ { .ccode = "AS", .region = REGIONS_FCC }, ++ { .ccode = "AT", .region = REGIONS_ETSI }, ++ { .ccode = "AU", .region = REGIONS_ETSI }, ++ { .ccode = "AW", .region = REGIONS_ETSI }, ++ { .ccode = "AZ", .region = REGIONS_ETSI }, ++ { .ccode = "BA", .region = REGIONS_ETSI }, ++ { .ccode = "BB", .region = REGIONS_FCC }, ++ { .ccode = "BD", .region = REGIONS_JP }, ++ { .ccode = "BE", .region = REGIONS_ETSI }, ++ { .ccode = "BF", .region = REGIONS_FCC }, ++ { .ccode = "BG", .region = REGIONS_ETSI }, ++ { .ccode = "BH", .region = REGIONS_ETSI }, ++ { .ccode = "BL", .region = REGIONS_ETSI }, ++ { .ccode = "BM", .region = REGIONS_FCC }, ++ { .ccode = "BN", .region = REGIONS_JP }, ++ { .ccode = "BO", .region = REGIONS_JP }, ++ { .ccode = "BR", .region = REGIONS_FCC }, ++ { .ccode = "BS", .region = REGIONS_FCC }, ++ { .ccode = "BT", .region = REGIONS_ETSI }, ++ { .ccode = "BW", .region = REGIONS_ETSI }, ++ { .ccode = "BY", .region = REGIONS_ETSI }, ++ { .ccode = "BZ", .region = REGIONS_JP }, ++ { .ccode = "CA", .region = REGIONS_FCC }, ++ { .ccode = "CF", .region = REGIONS_FCC }, ++ { .ccode = "CH", .region = REGIONS_ETSI }, ++ { .ccode = "CI", .region = REGIONS_FCC }, ++ { .ccode = "CL", .region = REGIONS_ETSI }, ++ { .ccode = "CO", .region = REGIONS_FCC }, ++ { .ccode = "CR", .region = REGIONS_FCC }, ++ { .ccode = "CX", .region = REGIONS_FCC }, ++ { .ccode = "CY", .region = REGIONS_ETSI }, ++ { .ccode = "CZ", .region = REGIONS_ETSI }, ++ { .ccode = "DK", .region = REGIONS_ETSI }, ++ { .ccode = "DM", .region = REGIONS_FCC }, ++ { .ccode = "DO", .region = REGIONS_FCC }, ++ { .ccode = "DZ", .region = REGIONS_JP }, ++ { .ccode = "EC", .region = REGIONS_FCC }, ++ { .ccode = "EE", .region = REGIONS_ETSI }, ++ { .ccode = "EG", .region = REGIONS_ETSI }, ++ { .ccode = "ES", .region = REGIONS_ETSI }, ++ { .ccode = "ET", .region = REGIONS_ETSI }, ++ { .ccode = "FI", .region = REGIONS_ETSI }, ++ { .ccode = "FM", .region = REGIONS_FCC }, ++ { .ccode = "FR", .region = REGIONS_ETSI }, ++ { .ccode = "GB", .region = REGIONS_ETSI }, ++ { .ccode = "GD", .region = REGIONS_FCC }, ++ { .ccode = "GE", .region = REGIONS_ETSI }, ++ { .ccode = "GF", .region = REGIONS_ETSI }, ++ { .ccode = "GH", .region = REGIONS_FCC }, ++ { .ccode = "GI", .region = REGIONS_ETSI }, ++ { .ccode = "GL", .region = REGIONS_ETSI }, ++ { .ccode = "GP", .region = REGIONS_ETSI }, ++ { .ccode = "GR", .region = REGIONS_ETSI }, ++ { .ccode = "GT", .region = REGIONS_FCC }, ++ { .ccode = "GU", .region = REGIONS_FCC }, ++ { .ccode = "GY", .region = REGIONS_DEFAULT }, ++ { .ccode = "HK", .region = REGIONS_ETSI }, ++ { .ccode = "HN", .region = REGIONS_FCC }, ++ { .ccode = "HR", .region = REGIONS_ETSI }, ++ { .ccode = "HT", .region = REGIONS_FCC }, ++ { .ccode = "HU", .region = REGIONS_ETSI }, ++ { .ccode = "ID", .region = REGIONS_ETSI }, ++ { .ccode = "IE", .region = REGIONS_ETSI }, ++ { .ccode = "IL", .region = REGIONS_ETSI }, ++ { .ccode = "IN", .region = REGIONS_ETSI }, ++ { .ccode = "IQ", .region = REGIONS_ETSI }, ++ { .ccode = "IR", .region = REGIONS_JP }, ++ { .ccode = "IS", .region = REGIONS_ETSI }, ++ { .ccode = "IT", .region = REGIONS_ETSI }, ++ { .ccode = "JM", .region = REGIONS_FCC }, ++ { .ccode = "JO", .region = REGIONS_ETSI }, ++ { .ccode = "KE", .region = REGIONS_ETSI }, ++ { .ccode = "KG", .region = REGIONS_ETSI }, ++ { .ccode = "KH", .region = REGIONS_ETSI }, ++ { .ccode = "KN", .region = REGIONS_ETSI }, ++ { .ccode = "KP", .region = REGIONS_JP }, ++ { .ccode = "KR", .region = REGIONS_ETSI }, ++ { .ccode = "KW", .region = REGIONS_ETSI }, ++ { .ccode = "KY", .region = REGIONS_FCC }, ++ { .ccode = "KZ", .region = REGIONS_DEFAULT }, ++ { .ccode = "LB", .region = REGIONS_ETSI }, ++ { .ccode = "LC", .region = REGIONS_ETSI }, ++ { .ccode = "LI", .region = REGIONS_ETSI }, ++ { .ccode = "LK", .region = REGIONS_FCC }, ++ { .ccode = "LS", .region = REGIONS_ETSI }, ++ { .ccode = "LT", .region = REGIONS_ETSI }, ++ { .ccode = "LU", .region = REGIONS_ETSI }, ++ { .ccode = "LV", .region = REGIONS_ETSI }, ++ { .ccode = "LY", .region = REGIONS_ETSI }, ++ { .ccode = "MA", .region = REGIONS_ETSI }, ++ { .ccode = "MC", .region = REGIONS_ETSI }, ++ { .ccode = "MD", .region = REGIONS_ETSI }, ++ { .ccode = "ME", .region = REGIONS_ETSI }, ++ { .ccode = "MF", .region = REGIONS_ETSI }, ++ { .ccode = "MH", .region = REGIONS_FCC }, ++ { .ccode = "MK", .region = REGIONS_ETSI }, ++ { .ccode = "MN", .region = REGIONS_ETSI }, ++ { .ccode = "MO", .region = REGIONS_ETSI }, ++ { .ccode = "MP", .region = REGIONS_FCC }, ++ { .ccode = "MQ", .region = REGIONS_ETSI }, ++ { .ccode = "MR", .region = REGIONS_ETSI }, ++ { .ccode = "MT", .region = REGIONS_ETSI }, ++ { .ccode = "MU", .region = REGIONS_FCC }, ++ { .ccode = "MV", .region = REGIONS_ETSI }, ++ { .ccode = "MW", .region = REGIONS_ETSI }, ++ { .ccode = "MX", .region = REGIONS_FCC }, ++ { .ccode = "MY", .region = REGIONS_FCC }, ++ { .ccode = "NA", .region = REGIONS_ETSI }, ++ { .ccode = "NG", .region = REGIONS_ETSI }, ++ { .ccode = "NI", .region = REGIONS_FCC }, ++ { .ccode = "NL", .region = REGIONS_ETSI }, ++ { .ccode = "NO", .region = REGIONS_ETSI }, ++ { .ccode = "NP", .region = REGIONS_JP }, ++ { .ccode = "NZ", .region = REGIONS_ETSI }, ++ { .ccode = "OM", .region = REGIONS_ETSI }, ++ { .ccode = "PA", .region = REGIONS_FCC }, ++ { .ccode = "PE", .region = REGIONS_FCC }, ++ { .ccode = "PF", .region = REGIONS_ETSI }, ++ { .ccode = "PG", .region = REGIONS_FCC }, ++ { .ccode = "PH", .region = REGIONS_FCC }, ++ { .ccode = "PK", .region = REGIONS_ETSI }, ++ { .ccode = "PL", .region = REGIONS_ETSI }, ++ { .ccode = "PM", .region = REGIONS_ETSI }, ++ { .ccode = "PR", .region = REGIONS_FCC }, ++ { .ccode = "PT", .region = REGIONS_ETSI }, ++ { .ccode = "PW", .region = REGIONS_FCC }, ++ { .ccode = "PY", .region = REGIONS_FCC }, ++ { .ccode = "QA", .region = REGIONS_ETSI }, ++ { .ccode = "RE", .region = REGIONS_ETSI }, ++ { .ccode = "RO", .region = REGIONS_ETSI }, ++ { .ccode = "RS", .region = REGIONS_ETSI }, ++ { .ccode = "RU", .region = REGIONS_ETSI }, ++ { .ccode = "RW", .region = REGIONS_FCC }, ++ { .ccode = "SA", .region = REGIONS_ETSI }, ++ { .ccode = "SE", .region = REGIONS_ETSI }, ++ { .ccode = "SG", .region = REGIONS_ETSI }, ++ { .ccode = "SI", .region = REGIONS_ETSI }, ++ { .ccode = "SK", .region = REGIONS_ETSI }, ++ { .ccode = "SM", .region = REGIONS_ETSI }, ++ { .ccode = "SN", .region = REGIONS_FCC }, ++ { .ccode = "SR", .region = REGIONS_ETSI }, ++ { .ccode = "SV", .region = REGIONS_FCC }, ++ { .ccode = "SY", .region = REGIONS_DEFAULT }, ++ { .ccode = "TC", .region = REGIONS_FCC }, ++ { .ccode = "TD", .region = REGIONS_ETSI }, ++ { .ccode = "TG", .region = REGIONS_ETSI }, ++ { .ccode = "TH", .region = REGIONS_FCC }, ++ { .ccode = "TJ", .region = REGIONS_ETSI }, ++ { .ccode = "TM", .region = REGIONS_ETSI }, ++ { .ccode = "TN", .region = REGIONS_ETSI }, ++ { .ccode = "TR", .region = REGIONS_ETSI }, ++ { .ccode = "TT", .region = REGIONS_FCC }, ++ { .ccode = "TW", .region = REGIONS_FCC }, ++ { .ccode = "UA", .region = REGIONS_ETSI }, ++ { .ccode = "UG", .region = REGIONS_FCC }, ++ { .ccode = "UY", .region = REGIONS_FCC }, ++ { .ccode = "UZ", .region = REGIONS_ETSI }, ++ { .ccode = "VC", .region = REGIONS_ETSI }, ++ { .ccode = "VE", .region = REGIONS_FCC }, ++ { .ccode = "VI", .region = REGIONS_FCC }, ++ { .ccode = "VN", .region = REGIONS_JP }, ++ { .ccode = "VU", .region = REGIONS_FCC }, ++ { .ccode = "WF", .region = REGIONS_ETSI }, ++ { .ccode = "YE", .region = REGIONS_DEFAULT }, ++ { .ccode = "YT", .region = REGIONS_ETSI }, ++ { .ccode = "ZA", .region = REGIONS_ETSI }, ++ { .ccode = "ZM", .region = REGIONS_ETSI }, ++ { .ccode = "ZW", .region = REGIONS_ETSI }, ++}; ++ ++uint8_t get_ccode_region(char *ccode) ++{ ++ int i, cnt; ++ AICWFDBG(LOGDEBUG, "%s ccode:%s\r\n", __func__, ccode); ++ ++ cnt = sizeof(reg_tables) / sizeof(reg_tables[0]); ++ ++ for (i = 0; i < cnt; i++) { ++ if (reg_tables[i].ccode[0] == ccode[0] && ++ reg_tables[i].ccode[1] == ccode[1]) { ++ AICWFDBG(LOGDEBUG, "region: %d\r\n", ++ reg_tables[i].region); ++ return reg_tables[i].region; ++ } ++ } ++ AICWFDBG(LOGDEBUG, "use default region\r\n"); ++ return REGIONS_DEFAULT; ++} ++ ++u8 get_region_index(char *name) ++{ ++ if (strncmp(name, "SRRC", 4) == 0) ++ return REGIONS_SRRC; ++ else if (strncmp(name, "FCC", 3) == 0) ++ return REGIONS_FCC; ++ else if (strncmp(name, "ETSI", 4) == 0) ++ return REGIONS_ETSI; ++ else if (strncmp(name, "JP", 2) == 0) ++ return REGIONS_JP; ++ else if (strncmp(name, "UNSET", 5) == 0) ++ return REGIONS_DEFAULT; ++ ++ return REGIONS_DEFAULT; ++} ++ ++#ifdef CONFIG_POWER_LIMIT ++#define POWER_LIMIT_INVALID_VAL POWER_LEVEL_INVALID_VAL ++ ++#define POWER_LIMIT_CC_MATCHED_BIT (0x1U << 0) ++ ++#define MAX_2_4G_BW_NUM 2 ++#define MAX_5G_BW_NUM 3 ++#define MAX_REGION_NUM 5 ++ ++typedef struct { ++ u8_l ch_cnt_2g4[MAX_2_4G_BW_NUM]; ++ u8_l ch_cnt_5g[MAX_5G_BW_NUM]; ++ u8_l ch_num_2g4[MAX_2_4G_BW_NUM][MAC_DOMAINCHANNEL_24G_MAX]; ++ u8_l ch_num_5g[MAX_5G_BW_NUM][MAC_DOMAINCHANNEL_5G_MAX]; ++ s8_l max_pwr_2g4[MAX_2_4G_BW_NUM][MAC_DOMAINCHANNEL_24G_MAX]; ++ s8_l max_pwr_5g[MAX_5G_BW_NUM][MAC_DOMAINCHANNEL_5G_MAX]; ++} txpwr_lmt_info_t; ++ ++typedef struct { ++ u32_l flags; ++ txpwr_lmt_info_t txpwr_lmt[MAX_REGION_NUM]; ++} powerlimit_info_t; ++ ++powerlimit_info_t powerlimit_info = { ++ 0, ++}; ++#endif ++ ++#ifdef CONFIG_RWNX_TL4 ++/** ++ * rwnx_plat_tl4_fw_upload() - Load the requested 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 hex file, into the specified address ++ */ ++static int rwnx_plat_tl4_fw_upload(struct rwnx_plat *rwnx_plat, u8 *fw_addr, ++ char *filename) ++{ ++ struct device *dev = rwnx_platform_get_dev(rwnx_plat); ++ const struct firmware *fw; ++ int err = 0; ++ u32 *dst; ++ u8 const *file_data; ++ char typ0, typ1; ++ u32 addr0, addr1; ++ u32 dat0, dat1; ++ int remain; ++ ++ err = request_firmware(&fw, filename, dev); ++ if (err) { ++ return err; ++ } ++ file_data = fw->data; ++ remain = fw->size; ++ ++ /* Copy the file on the Embedded side */ ++ dev_dbg(dev, "\n### Now copy %s firmware, @ = %p\n", filename, fw_addr); ++ ++ /* Walk through all the lines of the configuration file */ ++ while (remain >= 16) { ++ u32 data, offset; ++ ++ if (sscanf(file_data, "%c:%08X %04X", &typ0, &addr0, &dat0) != ++ 3) ++ break; ++ if ((addr0 & 0x01) != 0) { ++ addr0 = addr0 - 1; ++ dat0 = 0; ++ } else { ++ file_data += 16; ++ remain -= 16; ++ } ++ if ((remain < 16) || ++ (sscanf(file_data, "%c:%08X %04X", &typ1, &addr1, &dat1) != ++ 3) || ++ (typ1 != typ0) || (addr1 != (addr0 + 1))) { ++ typ1 = typ0; ++ addr1 = addr0 + 1; ++ dat1 = 0; ++ } else { ++ file_data += 16; ++ remain -= 16; ++ } ++ ++ if (typ0 == 'C') { ++ offset = 0x00200000; ++ if ((addr1 % 4) == 3) ++ offset += 2 * (addr1 - 3); ++ else ++ offset += 2 * (addr1 + 1); ++ ++ data = dat1 | (dat0 << 16); ++ } else { ++ offset = 2 * (addr1 - 1); ++ data = dat0 | (dat1 << 16); ++ } ++ dst = (u32 *)(fw_addr + offset); ++ *dst = data; ++ } ++ ++ release_firmware(fw); ++ ++ return err; ++} ++#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"); ++#endif ++ ++#if 0 ++/** ++ * rwnx_plat_bin_fw_upload() - Load the requested binary 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 binary file, into the specified address ++ */ ++static int rwnx_plat_bin_fw_upload(struct rwnx_plat *rwnx_plat, u8 *fw_addr, ++ char *filename) ++{ ++ const struct firmware *fw; ++ struct device *dev = rwnx_platform_get_dev(rwnx_plat); ++ int err = 0; ++ unsigned int i, size; ++ u32 *src, *dst; ++ ++ 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 = (u32 *)fw->data; ++ dst = (u32 *)fw_addr; ++ size = (unsigned int)fw->size; ++ ++ /* check potential platform bug on multiple stores vs memcpy */ ++ for (i = 0; i < size; i += 4) { ++ *dst++ = *src++; ++ } ++ ++ release_firmware(fw); ++ ++ return err; ++} ++#endif ++ ++#define MD5(x) \ ++ x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], \ ++ x[11], x[12], x[13], x[14], x[15] ++#define MD5PINRT \ ++ "file md5:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\r\n" ++ ++static int rwnx_load_firmware(u32 **fw_buf, const char *name, ++ struct device *device) ++{ ++#ifdef CONFIG_USE_FW_REQUEST ++ const struct firmware *fw = NULL; ++ u32 *dst = NULL; ++ void *buffer = NULL; ++ MD5_CTX md5; ++ unsigned char decrypt[16]; ++ int size = 0; ++ int ret = 0; ++ ++ printk("%s: request firmware = %s \n", __func__, name); ++ ++ ret = request_firmware(&fw, name, NULL); ++ ++ if (ret < 0) { ++ printk("Load %s fail\n", name); ++ release_firmware(fw); ++ return -1; ++ } ++ ++ size = fw->size; ++ dst = (u32 *)fw->data; ++ ++ if (size <= 0) { ++ printk("wrong size of firmware file\n"); ++ release_firmware(fw); ++ return -1; ++ } ++ ++ buffer = vmalloc(size); ++ memset(buffer, 0, size); ++ memcpy(buffer, dst, size); ++ ++ *fw_buf = buffer; ++ ++ MD5Init(&md5); ++ MD5Update(&md5, (unsigned char *)buffer, size); ++ MD5Final(&md5, decrypt); ++ printk(MD5PINRT, MD5(decrypt)); ++ ++ release_firmware(fw); ++ ++ return size; ++#else ++ 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; ++ MD5_CTX md5; ++ unsigned char decrypt[16]; ++ ++ /* get the firmware path */ ++ path = __getname(); ++ if (!path) { ++ *fw_buf = NULL; ++ return -1; ++ } ++ ++ len = snprintf(path, FW_PATH_MAX_LEN, "%s/%s", aic_fw_path, name); ++ ++ //len = snprintf(path, FW_PATH_MAX_LEN, "%s", name); ++ if (len >= FW_PATH_MAX_LEN) { ++ AICWFDBG(LOGERROR, "%s: %s file's path too long\n", __func__, ++ name); ++ *fw_buf = NULL; ++ __putname(path); ++ return -1; ++ } ++ ++ AICWFDBG(LOGINFO, "%s :firmware path = %s \n", __func__, path); ++ ++ /* open the firmware file */ ++ fp = filp_open(path, O_RDONLY, 0); ++ if (IS_ERR_OR_NULL(fp)) { ++ AICWFDBG(LOGERROR, "%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) { ++ AICWFDBG(LOGERROR, "%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) { ++ AICWFDBG(LOGERROR, "%s: %s file rdlen invalid %d\n", __func__, ++ name, (int)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; ++ } ++ ++#if 0 ++ /*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]; ++ } ++#endif ++ ++ __putname(path); ++ filp_close(fp, NULL); ++ fp = NULL; ++ //kfree(buffer); ++ //buffer = NULL; ++ *fw_buf = (u32 *)buffer; ++ ++ MD5Init(&md5); ++ MD5Update(&md5, (unsigned char *)buffer, size); ++ MD5Final(&md5, decrypt); ++ ++ AICWFDBG(LOGINFO, MD5PINRT, MD5(decrypt)); ++ ++ return size; ++#endif ++} ++ ++/* buffer is allocated by kzalloc */ ++int rwnx_request_firmware_common(struct rwnx_hw *rwnx_hw, u32 **buffer, ++ const char *filename) ++{ ++ int size; ++ ++ AICWFDBG(LOGINFO, "### Load file %s\n", filename); ++ ++ size = rwnx_load_firmware(buffer, filename, NULL); ++ ++ return size; ++} ++ ++static void rwnx_restore_firmware(u32 **fw_buf) ++{ ++#ifdef CONFIG_USE_FW_REQUEST ++ vfree(*fw_buf); ++#else ++ kfree(*fw_buf); ++#endif ++ *fw_buf = NULL; ++} ++ ++void rwnx_release_firmware_common(u32 **buffer) ++{ ++ rwnx_restore_firmware(buffer); ++} ++ ++/** ++ * rwnx_plat_bin_fw_upload_2() - Load the requested binary FW into embedded side. ++ * ++ * @rwnx_hw: Main driver data ++ * @fw_addr: Address where the fw must be loaded ++ * @filename: Name of the fw. ++ * ++ * Load a fw, stored as a binary file, into the specified address ++ */ ++int rwnx_plat_bin_fw_upload_2(struct rwnx_hw *rwnx_hw, u32 fw_addr, ++ char *filename) ++{ ++ int err = 0; ++ unsigned int i = 0, size; ++ // u32 *src; ++ u32 *dst = NULL; ++ ++ /* Copy the file on the Embedded side */ ++ AICWFDBG(LOGINFO, "### Upload %s firmware, @ = %x\n", filename, ++ fw_addr); ++ ++ size = rwnx_request_firmware_common(rwnx_hw, &dst, filename); ++ if (!dst) { ++ AICWFDBG(LOGERROR, "No such file or directory\n"); ++ return -1; ++ } ++ if (size <= 0) { ++ AICWFDBG(LOGERROR, "wrong size of firmware file\n"); ++ dst = NULL; ++ err = -1; ++ } ++ ++ AICWFDBG(LOGINFO, "size=%d, dst[0]=%x\n", size, dst[0]); ++ if (size > 512) { ++ for (; i < (size - 512); i += 512) { ++ //printk("wr blk 0: %p -> %x\r\n", dst + i / 4, fw_addr + i); ++ err = rwnx_send_dbg_mem_block_write_req( ++ rwnx_hw, fw_addr + i, 512, dst + i / 4); ++ if (err) { ++ AICWFDBG(LOGERROR, ++ "bin upload fail: %x, err:%d\r\n", ++ fw_addr + i, err); ++ break; ++ } ++ } ++ } ++ if (!err && (i < size)) { ++ //printk("wr blk 1: %p -> %x\r\n", dst + i / 4, fw_addr + i); ++ err = rwnx_send_dbg_mem_block_write_req(rwnx_hw, fw_addr + i, ++ size - i, dst + i / 4); ++ if (err) { ++ AICWFDBG(LOGERROR, "bin upload fail: %x, err:%d\r\n", ++ fw_addr + i, err); ++ } ++ } ++ ++ if (dst) { ++ rwnx_release_firmware_common(&dst); ++ } ++ ++ return err; ++} ++ ++typedef struct { ++ txpwr_idx_conf_t txpwr_idx; ++ txpwr_ofst_conf_t txpwr_ofst; ++ xtal_cap_conf_t xtal_cap; ++} nvram_info_t; ++ ++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, ++ }, ++ .xtal_cap = { ++ .enable = 0, ++ .xtal_cap = 24, ++ .xtal_cap_fine = 31, ++ }, ++}; ++ ++void get_userconfig_txpwr_ofst_in_fdrv(txpwr_ofst_conf_t *txpwr_ofst) ++{ ++ txpwr_ofst->enable = userconfig_info.txpwr_ofst.enable; ++ txpwr_ofst->chan_1_4 = userconfig_info.txpwr_ofst.chan_1_4; ++ txpwr_ofst->chan_5_9 = userconfig_info.txpwr_ofst.chan_5_9; ++ txpwr_ofst->chan_10_13 = userconfig_info.txpwr_ofst.chan_10_13; ++ txpwr_ofst->chan_36_64 = userconfig_info.txpwr_ofst.chan_36_64; ++ txpwr_ofst->chan_100_120 = userconfig_info.txpwr_ofst.chan_100_120; ++ txpwr_ofst->chan_122_140 = userconfig_info.txpwr_ofst.chan_122_140; ++ txpwr_ofst->chan_142_165 = userconfig_info.txpwr_ofst.chan_142_165; ++ ++ AICWFDBG(LOGINFO, "%s:enable :%d\r\n", __func__, ++ txpwr_ofst->enable); ++ AICWFDBG(LOGINFO, "%s:chan_1_4 :%d\r\n", __func__, ++ txpwr_ofst->chan_1_4); ++ AICWFDBG(LOGINFO, "%s:chan_5_9 :%d\r\n", __func__, ++ txpwr_ofst->chan_5_9); ++ AICWFDBG(LOGINFO, "%s:chan_10_13 :%d\r\n", __func__, ++ txpwr_ofst->chan_10_13); ++ AICWFDBG(LOGINFO, "%s:chan_36_64 :%d\r\n", __func__, ++ txpwr_ofst->chan_36_64); ++ AICWFDBG(LOGINFO, "%s:chan_100_120:%d\r\n", __func__, ++ txpwr_ofst->chan_100_120); ++ AICWFDBG(LOGINFO, "%s:chan_122_140:%d\r\n", __func__, ++ txpwr_ofst->chan_122_140); ++ AICWFDBG(LOGINFO, "%s:chan_142_165:%d\r\n", __func__, ++ txpwr_ofst->chan_142_165); ++} ++ ++void get_userconfig_txpwr_ofst2x_in_fdrv(txpwr_ofst2x_conf_t *txpwr_ofst2x) ++{ ++ int type, ch_grp; ++ *txpwr_ofst2x = userconfig_info.txpwr_ofst2x; ++ AICWFDBG(LOGINFO, "%s:enable :%d\r\n", __func__, ++ txpwr_ofst2x->enable); ++ AICWFDBG( ++ LOGINFO, ++ "pwrofst2x 2.4g: [0]:11b, [1]:ofdm_highrate, [2]:ofdm_lowrate\n" ++ " chan=" ++ "\t1-4" ++ "\t5-9" ++ "\t10-13"); ++ for (type = 0; type < 3; type++) { ++ AICWFDBG(LOGINFO, "\n [%d] =", type); ++ for (ch_grp = 0; ch_grp < 3; ch_grp++) { ++ AICWFDBG(LOGINFO, "\t%d", ++ txpwr_ofst2x->pwrofst2x_tbl_2g4[type][ch_grp]); ++ } ++ } ++ AICWFDBG( ++ LOGINFO, ++ "\npwrofst2x 5g: [0]:ofdm_lowrate, [1]:ofdm_highrate, [2]:ofdm_midrate\n" ++ " chan=" ++ "\t36-50" ++ "\t51-64" ++ "\t98-114" ++ "\t115-130" ++ "\t131-146" ++ "\t147-166"); ++ for (type = 0; type < 3; type++) { ++ AICWFDBG(LOGINFO, "\n [%d] =", type); ++ for (ch_grp = 0; ch_grp < 6; ch_grp++) { ++ AICWFDBG(LOGINFO, "\t%d", ++ txpwr_ofst2x->pwrofst2x_tbl_5g[type][ch_grp]); ++ } ++ } ++ AICWFDBG(LOGINFO, "\n"); ++} ++ ++void get_userconfig_txpwr_ofst2x_v2_in_fdrv( ++ txpwr_ofst2x_conf_v2_t *txpwr_ofst2x_v2) ++{ ++ int type, ch_grp; ++ *txpwr_ofst2x_v2 = userconfig_info.txpwr_ofst2x_v2; ++ AICWFDBG(LOGINFO, "%s:enable :%d\r\n", __func__, ++ txpwr_ofst2x_v2->enable); ++ AICWFDBG(LOGINFO, ++ "pwrofst2x 2.4g(ant0/ant1): [0]:11b, [1]:ofdm_highrate\n" ++ " chan=" ++ "\t1-4" ++ "\t5-9" ++ "\t10-13"); ++ for (type = 0; type < 2; type++) { ++ AICWFDBG(LOGINFO, "\n [%d] =", type); ++ for (ch_grp = 0; ch_grp < 3; ch_grp++) { ++ AICWFDBG(LOGINFO, "\t%d/%d", ++ txpwr_ofst2x_v2 ++ ->pwrofst2x_tbl_2g4_ant0[ch_grp][type], ++ txpwr_ofst2x_v2->pwrofst2x_tbl_2g4_ant1[ch_grp] ++ [type]); ++ } ++ } ++ AICWFDBG(LOGINFO, "\npwrofst2x 5g: [0]:ofdm_highrate\n" ++ " chan=" ++ "\t36-50" ++ "\t51-64" ++ "\t98-114" ++ "\t115-130" ++ "\t131-146" ++ "\t147-166"); ++ for (type = 0; type < 1; type++) { ++ AICWFDBG(LOGINFO, "\n [%d] =", type); ++ for (ch_grp = 0; ch_grp < 6; ch_grp++) { ++ AICWFDBG(LOGINFO, "\t%d/%d", ++ txpwr_ofst2x_v2 ++ ->pwrofst2x_tbl_5g_ant0[ch_grp][type], ++ txpwr_ofst2x_v2 ++ ->pwrofst2x_tbl_5g_ant1[ch_grp][type]); ++ } ++ } ++ AICWFDBG(LOGINFO, "\n"); ++} ++ ++void get_userconfig_txpwr_idx(txpwr_idx_conf_t *txpwr_idx) ++{ ++ memcpy(txpwr_idx, &(nvram_info.txpwr_idx), sizeof(txpwr_idx_conf_t)); ++} ++ ++void get_userconfig_txpwr_ofst(txpwr_ofst_conf_t *txpwr_ofst) ++{ ++ memcpy(txpwr_ofst, &(nvram_info.txpwr_ofst), sizeof(txpwr_ofst_conf_t)); ++} ++ ++void get_userconfig_xtal_cap(xtal_cap_conf_t *xtal_cap) ++{ ++ if (nvram_info.xtal_cap.enable) { ++ *xtal_cap = nvram_info.xtal_cap; ++ } ++ ++ if (userconfig_info.xtal_cap.enable) { ++ *xtal_cap = userconfig_info.xtal_cap; ++ } ++ ++ AICWFDBG(LOGINFO, "%s:enable :%d\r\n", __func__, ++ xtal_cap->enable); ++ AICWFDBG(LOGINFO, "%s:xtal_cap :%d\r\n", __func__, ++ xtal_cap->xtal_cap); ++ AICWFDBG(LOGINFO, "%s:xtal_cap_fine:%d\r\n", __func__, ++ xtal_cap->xtal_cap_fine); ++} ++ ++s8_l get_txpwr_max(s8_l power) ++{ ++ int i = 0; ++ ++ if (g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800D80 || ++ g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ for (i = 0; i <= 11; i++) { ++ if (power < ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[i]) ++ power = userconfig_info.txpwr_lvl_v3 ++ .pwrlvl_11b_11ag_2g4[i]; ++ } ++ for (i = 0; i <= 9; i++) { ++ if (power < ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[i]) ++ power = userconfig_info.txpwr_lvl_v3 ++ .pwrlvl_11n_11ac_2g4[i]; ++ } ++ for (i = 0; i <= 11; i++) { ++ if (power < ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[i]) ++ power = userconfig_info.txpwr_lvl_v3 ++ .pwrlvl_11ax_2g4[i]; ++ } ++ for (i = 4; i <= 11; i++) { ++ if (power < ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[i]) ++ power = userconfig_info.txpwr_lvl_v3 ++ .pwrlvl_11a_5g[i]; ++ } ++ for (i = 0; i <= 9; i++) { ++ if (power < ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[i]) ++ power = userconfig_info.txpwr_lvl_v3 ++ .pwrlvl_11n_11ac_5g[i]; ++ } ++ for (i = 0; i <= 11; i++) { ++ if (power < ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[i]) ++ power = userconfig_info.txpwr_lvl_v3 ++ .pwrlvl_11ax_5g[i]; ++ } ++ ++ if ((userconfig_info.txpwr_loss.loss_enable_2g4 == 1) || ++ (userconfig_info.txpwr_loss.loss_enable_5g == 1)) { ++ if (userconfig_info.txpwr_loss.loss_value_2g4 < ++ userconfig_info.txpwr_loss.loss_value_5g) ++ power += ++ userconfig_info.txpwr_loss.loss_value_5g; ++ else ++ power += userconfig_info.txpwr_loss ++ .loss_value_2g4; ++ } ++ ++ } else if (g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ for (i = 0; i <= 11; i++) { ++ if (power < ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[i]) ++ power = userconfig_info.txpwr_lvl_v2 ++ .pwrlvl_11b_11ag_2g4[i]; ++ } ++ for (i = 0; i <= 9; i++) { ++ if (power < ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11n_11ac_2g4[i]) ++ power = userconfig_info.txpwr_lvl_v2 ++ .pwrlvl_11n_11ac_2g4[i]; ++ } ++ for (i = 0; i <= 11; i++) { ++ if (power < ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[i]) ++ power = userconfig_info.txpwr_lvl_v2 ++ .pwrlvl_11ax_2g4[i]; ++ } ++ } ++ ++ printk("%s:txpwr_max:%d \r\n", __func__, power); ++ return power; ++} ++ ++void set_txpwr_loss_ofst(s8_l value) ++{ ++ int i = 0; ++ if (g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800D80) { ++ for (i = 0; i <= 11; i++) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[i] += ++ value; ++ } ++ for (i = 0; i <= 9; i++) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[i] += ++ value; ++ } ++ for (i = 0; i <= 11; i++) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[i] += ++ value; ++ } ++ for (i = 4; i <= 11; i++) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[i] += value; ++ } ++ for (i = 0; i <= 9; i++) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[i] += ++ value; ++ } ++ for (i = 0; i <= 11; i++) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[i] += value; ++ } ++ } else if (g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ for (i = 0; i <= 11; i++) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11b_11ag_2g4[i] += ++ value; ++ } ++ for (i = 0; i <= 9; i++) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11n_11ac_2g4[i] += ++ value; ++ } ++ for (i = 0; i <= 11; i++) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_2g4[i] += ++ value; ++ } ++ for (i = 0; i <= 7; i++) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11a_5g[i] += value; ++ } ++ for (i = 0; i <= 9; i++) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11n_11ac_5g[i] += ++ value; ++ } ++ for (i = 0; i <= 11; i++) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_5g[i] += value; ++ } ++ } else if (g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ for (i = 0; i <= 11; i++) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[i] += ++ value; ++ } ++ for (i = 0; i <= 9; i++) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11n_11ac_2g4[i] += ++ value; ++ } ++ for (i = 0; i <= 11; i++) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[i] += ++ value; ++ } ++ } ++ printk("%s:value:%d\r\n", __func__, value); ++} ++ ++#define MATCH_NODE(type, node, cfg_key) \ ++ { \ ++ cfg_key, offsetof(type, node) \ ++ } ++ ++struct parse_match_t { ++ char keyname[64]; ++ int offset; ++}; ++ ++static const char *parse_key_prefix[] = { ++ [0x01] = "module0_", ++ [0x21] = "module1_", ++}; ++ ++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"), ++ ++ 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"), ++ ++ MATCH_NODE(nvram_info_t, xtal_cap.enable, "xtal_enable"), ++ MATCH_NODE(nvram_info_t, xtal_cap.xtal_cap, "xtal_cap"), ++ MATCH_NODE(nvram_info_t, xtal_cap.xtal_cap_fine, "xtal_cap_fine"), ++}; ++ ++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; ++} ++ ++int rwnx_atoi2(char *value, int c_len) ++{ ++ int len = 0; ++ int i = 0; ++ int result = 0; ++ int flag = 1; ++ ++ if (value[0] == '-') { ++ flag = -1; ++ value++; ++ } ++ len = c_len; ++ ++ for (i = 0; i < len; i++) { ++ result = result * 10; ++ if (value[i] >= 48 && value[i] <= 57) { ++ result += value[i] - 48; ++ } else { ++ result = 0; ++ break; ++ } ++ } ++ ++ return result * flag; ++} ++ ++int rwnx_atoi(char *value) ++{ ++ int len = 0; ++ int i = 0; ++ int result = 0; ++ int flag = 1; ++ ++ if (value[0] == '-') { ++ flag = -1; ++ value++; ++ } ++ len = strlen(value); ++ ++ for (i = 0; i < len; i++) { ++ result = result * 10; ++ if (value[i] >= 48 && value[i] <= 57) { ++ result += value[i] - 48; ++ } else { ++ result = 0; ++ break; ++ } ++ } ++ ++ return result * flag; ++} ++ ++void rwnx_plat_nvram_set_value(char *command, char *value) ++{ ++ //TODO send command ++ AICWFDBG(LOGINFO, "%s:command=%s value=%s\n", __func__, command, value); ++ if (!strcmp(command, "enable")) { ++ userconfig_info.txpwr_lvl.enable = rwnx_atoi(value); ++ userconfig_info.txpwr_lvl_v2.enable = rwnx_atoi(value); ++ } else if (!strcmp(command, "dsss")) { ++ userconfig_info.txpwr_lvl.dsss = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofdmlowrate_2g4")) { ++ userconfig_info.txpwr_lvl.ofdmlowrate_2g4 = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofdm64qam_2g4")) { ++ userconfig_info.txpwr_lvl.ofdm64qam_2g4 = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofdm256qam_2g4")) { ++ userconfig_info.txpwr_lvl.ofdm256qam_2g4 = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofdm1024qam_2g4")) { ++ userconfig_info.txpwr_lvl.ofdm1024qam_2g4 = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofdmlowrate_5g")) { ++ userconfig_info.txpwr_lvl.ofdmlowrate_5g = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofdm64qam_5g")) { ++ userconfig_info.txpwr_lvl.ofdm64qam_5g = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofdm256qam_5g")) { ++ userconfig_info.txpwr_lvl.ofdm256qam_5g = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofdm1024qam_5g")) { ++ userconfig_info.txpwr_lvl.ofdm1024qam_5g = rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_1m_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_2m_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_5m5_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[2] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_11m_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[3] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_6m_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[4] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_9m_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[5] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_12m_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[6] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_18m_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[7] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_24m_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[8] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_36m_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[9] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_48m_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[10] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_54m_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[11] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs0_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11n_11ac_2g4[0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs1_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11n_11ac_2g4[1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs2_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11n_11ac_2g4[2] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs3_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11n_11ac_2g4[3] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs4_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11n_11ac_2g4[4] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs5_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11n_11ac_2g4[5] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs6_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11n_11ac_2g4[6] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs7_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11n_11ac_2g4[7] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs8_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11n_11ac_2g4[8] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs9_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11n_11ac_2g4[9] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs0_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs1_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs2_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[2] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs3_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[3] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs4_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[4] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs5_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[5] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs6_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[6] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs7_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[7] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs8_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[8] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs9_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[9] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs10_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[10] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs11_2g4")) { ++ userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[11] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_enable")) { ++ userconfig_info.txpwr_ofst.enable = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_chan_1_4")) { ++ userconfig_info.txpwr_ofst.chan_1_4 = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_chan_5_9")) { ++ userconfig_info.txpwr_ofst.chan_5_9 = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_chan_10_13")) { ++ userconfig_info.txpwr_ofst.chan_10_13 = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_chan_36_64")) { ++ userconfig_info.txpwr_ofst.chan_36_64 = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_chan_100_120")) { ++ userconfig_info.txpwr_ofst.chan_100_120 = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_chan_122_140")) { ++ userconfig_info.txpwr_ofst.chan_122_140 = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_chan_142_165")) { ++ userconfig_info.txpwr_ofst.chan_142_165 = rwnx_atoi(value); ++ } else if (!strcmp(command, "xtal_enable")) { ++ userconfig_info.xtal_cap.enable = rwnx_atoi(value); ++ } else if (!strcmp(command, "xtal_cap")) { ++ userconfig_info.xtal_cap.xtal_cap = rwnx_atoi(value); ++ } else if (!strcmp(command, "xtal_cap_fine")) { ++ userconfig_info.xtal_cap.xtal_cap_fine = rwnx_atoi(value); ++ } else { ++ AICWFDBG(LOGERROR, "invalid cmd: %s\n", command); ++ } ++} ++ ++void rwnx_plat_nvram_set_value_v3(char *command, char *value) ++{ ++ //TODO send command ++ AICWFDBG(LOGINFO, "%s:command=%s value=%s\n", __func__, command, value); ++ if (!strcmp(command, "enable")) { ++ userconfig_info.txpwr_lvl.enable = rwnx_atoi(value); ++ userconfig_info.txpwr_lvl_v3.enable = rwnx_atoi(value); ++ } else if (!strcmp(command, "dsss")) { ++ userconfig_info.txpwr_lvl.dsss = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofdmlowrate_2g4")) { ++ userconfig_info.txpwr_lvl.ofdmlowrate_2g4 = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofdm64qam_2g4")) { ++ userconfig_info.txpwr_lvl.ofdm64qam_2g4 = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofdm256qam_2g4")) { ++ userconfig_info.txpwr_lvl.ofdm256qam_2g4 = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofdm1024qam_2g4")) { ++ userconfig_info.txpwr_lvl.ofdm1024qam_2g4 = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofdmlowrate_5g")) { ++ userconfig_info.txpwr_lvl.ofdmlowrate_5g = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofdm64qam_5g")) { ++ userconfig_info.txpwr_lvl.ofdm64qam_5g = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofdm256qam_5g")) { ++ userconfig_info.txpwr_lvl.ofdm256qam_5g = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofdm1024qam_5g")) { ++ userconfig_info.txpwr_lvl.ofdm1024qam_5g = rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_1m_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_2m_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_5m5_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[2] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_11m_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[3] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_6m_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[4] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_9m_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[5] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_12m_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[6] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_18m_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[7] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_24m_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[8] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_36m_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[9] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_48m_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[10] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_54m_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[11] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs0_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs1_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs2_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[2] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs3_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[3] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs4_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[4] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs5_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[5] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs6_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[6] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs7_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[7] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs8_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[8] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs9_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[9] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs0_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs1_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs2_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[2] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs3_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[3] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs4_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[4] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs5_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[5] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs6_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[6] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs7_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[7] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs8_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[8] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs9_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[9] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs10_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[10] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs11_2g4")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[11] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11a_1m_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11a_2m_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11a_5m5_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[2] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11a_11m_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[3] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11a_6m_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[4] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11a_9m_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[5] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11a_12m_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[6] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11a_18m_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[7] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11a_24m_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[8] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11a_36m_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[9] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11a_48m_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[10] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11a_54m_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[11] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs0_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs1_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs2_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[2] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs3_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[3] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs4_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[4] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs5_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[5] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs6_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[6] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs7_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[7] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs8_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[8] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs9_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[9] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs0_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs1_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs2_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[2] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs3_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[3] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs4_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[4] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs5_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[5] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs6_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[6] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs7_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[7] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs8_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[8] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs9_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[9] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs10_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[10] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs11_5g")) { ++ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[11] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_adj_enable")) { ++ userconfig_info.txpwr_lvl_adj.enable = rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_adj_2g4_chan_1_4")) { ++ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_2g4[0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_adj_2g4_chan_5_9")) { ++ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_2g4[1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_adj_2g4_chan_10_13")) { ++ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_2g4[2] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_adj_5g_chan_42")) { ++ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_adj_5g_chan_58")) { ++ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_adj_5g_chan_106")) { ++ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[2] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_adj_5g_chan_122")) { ++ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[3] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_adj_5g_chan_138")) { ++ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[4] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_adj_5g_chan_155")) { ++ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[5] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "loss_enable_2g4")) { ++ userconfig_info.txpwr_loss.loss_enable_2g4 = rwnx_atoi(value); ++ } else if (!strcmp(command, "loss_value_2g4")) { ++ userconfig_info.txpwr_loss.loss_value_2g4 = rwnx_atoi(value); ++ } else if (!strcmp(command, "loss_enable_5g")) { ++ userconfig_info.txpwr_loss.loss_enable_5g = rwnx_atoi(value); ++ } else if (!strcmp(command, "loss_value_5g")) { ++ userconfig_info.txpwr_loss.loss_value_5g = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_enable")) { ++ userconfig_info.txpwr_ofst.enable = rwnx_atoi(value); ++ userconfig_info.txpwr_ofst2x.enable = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_chan_1_4")) { ++ userconfig_info.txpwr_ofst.chan_1_4 = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_chan_5_9")) { ++ userconfig_info.txpwr_ofst.chan_5_9 = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_chan_10_13")) { ++ userconfig_info.txpwr_ofst.chan_10_13 = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_chan_36_64")) { ++ userconfig_info.txpwr_ofst.chan_36_64 = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_chan_100_120")) { ++ userconfig_info.txpwr_ofst.chan_100_120 = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_chan_122_140")) { ++ userconfig_info.txpwr_ofst.chan_122_140 = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_chan_142_165")) { ++ userconfig_info.txpwr_ofst.chan_142_165 = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_2g4_11b_chan_1_4")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[0][0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_2g4_11b_chan_5_9")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[0][1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_2g4_11b_chan_10_13")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[0][2] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_2g4_ofdm_highrate_chan_1_4")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[1][0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_2g4_ofdm_highrate_chan_5_9")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[1][1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_2g4_ofdm_highrate_chan_10_13")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[1][2] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_2g4_ofdm_lowrate_chan_1_4")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[2][0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_2g4_ofdm_lowrate_chan_5_9")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[2][1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_2g4_ofdm_lowrate_chan_10_13")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[2][2] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ofdm_lowrate_chan_42")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[0][0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ofdm_lowrate_chan_58")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[0][1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ofdm_lowrate_chan_106")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[0][2] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ofdm_lowrate_chan_122")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[0][3] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ofdm_lowrate_chan_138")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[0][4] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ofdm_lowrate_chan_155")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[0][5] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_42")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[1][0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_58")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[1][1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_106")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[1][2] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_122")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[1][3] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_138")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[1][4] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_155")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[1][5] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ofdm_midrate_chan_42")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[2][0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ofdm_midrate_chan_58")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[2][1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ofdm_midrate_chan_106")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[2][2] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ofdm_midrate_chan_122")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[2][3] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ofdm_midrate_chan_138")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[2][4] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ofdm_midrate_chan_155")) { ++ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[2][5] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "xtal_enable")) { ++ userconfig_info.xtal_cap.enable = rwnx_atoi(value); ++ } else if (!strcmp(command, "xtal_cap")) { ++ userconfig_info.xtal_cap.xtal_cap = rwnx_atoi(value); ++ } else if (!strcmp(command, "xtal_cap_fine")) { ++ userconfig_info.xtal_cap.xtal_cap_fine = rwnx_atoi(value); ++ } else { ++ AICWFDBG(LOGERROR, "invalid cmd: %s\n", command); ++ } ++} ++ ++void rwnx_plat_userconfig_parsing2(char *buffer, int size) ++{ ++ int i = 0; ++ int parse_state = 0; ++ char command[30]; ++ char value[100]; ++ int char_counter = 0; ++ ++ memset(command, 0, 30); ++ memset(value, 0, 100); ++ ++ for (i = 0; i < size; i++) { ++ //Send command or print nvram log when char is \r or \n ++ if (buffer[i] == 0x0a || buffer[i] == 0x0d) { ++ if (command[0] != 0 && value[0] != 0) { ++ if (parse_state == PRINT) { ++ AICWFDBG(LOGINFO, "%s:%s\r\n", __func__, ++ value); ++ } else if (parse_state == GET_VALUE) { ++ rwnx_plat_nvram_set_value(command, ++ value); ++ } ++ } ++ //Reset command value and char_counter ++ memset(command, 0, 30); ++ memset(value, 0, 100); ++ char_counter = 0; ++ parse_state = INIT; ++ continue; ++ } ++ ++ //Switch parser state ++ if (parse_state == INIT) { ++ if (buffer[i] == '#') { ++ parse_state = PRINT; ++ continue; ++ } else if (buffer[i] == 0x0a || buffer[i] == 0x0d) { ++ parse_state = INIT; ++ continue; ++ } else { ++ parse_state = CMD; ++ } ++ } ++ ++ //Fill data to command and value ++ if (parse_state == PRINT) { ++ command[0] = 0x01; ++ value[char_counter] = buffer[i]; ++ char_counter++; ++ } else if (parse_state == CMD) { ++ if (command[0] != 0 && buffer[i] == '=') { ++ parse_state = GET_VALUE; ++ char_counter = 0; ++ continue; ++ } ++ command[char_counter] = buffer[i]; ++ char_counter++; ++ } else if (parse_state == GET_VALUE) { ++ value[char_counter] = buffer[i]; ++ char_counter++; ++ } ++ } ++} ++ ++void rwnx_plat_userconfig_parsing3(char *buffer, int size) ++{ ++ int i = 0; ++ int parse_state = 0; ++ char command[64]; ++ char value[100]; ++ int char_counter = 0; ++ ++ memset(command, 0, 64); ++ memset(value, 0, 100); ++ ++ for (i = 0; i < size; i++) { ++ //Send command or print nvram log when char is \r or \n ++ if (buffer[i] == 0x0a || buffer[i] == 0x0d) { ++ if (command[0] != 0 && value[0] != 0) { ++ if (parse_state == PRINT) { ++ AICWFDBG(LOGINFO, "%s:%s\r\n", __func__, ++ value); ++ } else if (parse_state == GET_VALUE) { ++ rwnx_plat_nvram_set_value_v3(command, ++ value); ++ } ++ } ++ //Reset command value and char_counter ++ memset(command, 0, 64); ++ memset(value, 0, 100); ++ char_counter = 0; ++ parse_state = INIT; ++ continue; ++ } ++ ++ //Switch parser state ++ if (parse_state == INIT) { ++ if (buffer[i] == '#') { ++ parse_state = PRINT; ++ continue; ++ } else if (buffer[i] == 0x0a || buffer[i] == 0x0d) { ++ parse_state = INIT; ++ continue; ++ } else { ++ parse_state = CMD; ++ } ++ } ++ ++ //Fill data to command and value ++ if (parse_state == PRINT) { ++ command[0] = 0x01; ++ value[char_counter] = buffer[i]; ++ char_counter++; ++ } else if (parse_state == CMD) { ++ if (command[0] != 0 && buffer[i] == '=') { ++ parse_state = GET_VALUE; ++ char_counter = 0; ++ continue; ++ } ++ command[char_counter] = buffer[i]; ++ char_counter++; ++ } else if (parse_state == GET_VALUE) { ++ if (buffer[i] != 0x2D && ++ (buffer[i] < 0x30 || buffer[i] > 0x39)) { ++ continue; ++ } ++ value[char_counter] = buffer[i]; ++ char_counter++; ++ } ++ } ++} ++ ++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; ++ } ++ ++ printk("%s rwnx_hw->vendor_info:0x%02X \r\n", __func__, ++ rwnx_hw->vendor_info); ++ if (rwnx_hw->vendor_info == 0x00 || ++ (rwnx_hw->vendor_info > ++ (sizeof(parse_key_prefix) / sizeof(parse_key_prefix[0]) - 1))) { ++ printk("Unsuppor vendor info config\n"); ++ printk("Using module0 config\n"); ++ rwnx_hw->vendor_info = 0x01; ++ //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 long *)((unsigned long)&nvram_info + ++ parse_match_tab[i].offset) = ++ val; ++ printk("%s, %s = %ld\n", __func__, ++ parse_match_tab[i].keyname, val); ++ break; ++ } ++ } ++ } ++ vfree(data); ++} ++ ++void rwnx_plat_nvram_set_value_8800d80x2(char *command, char *value) ++{ ++ //TODO send command ++ AICWFDBG(LOGINFO, "%s:command=%s value=%s\n", __func__, command, value); ++ if (!strcmp(command, "enable")) { ++ userconfig_info.txpwr_lvl_v4.enable = rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_1m_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11b_11ag_2g4[0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_2m_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11b_11ag_2g4[1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_5m5_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11b_11ag_2g4[2] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_11m_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11b_11ag_2g4[3] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_6m_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11b_11ag_2g4[4] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_9m_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11b_11ag_2g4[5] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_12m_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11b_11ag_2g4[6] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_18m_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11b_11ag_2g4[7] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_24m_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11b_11ag_2g4[8] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_36m_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11b_11ag_2g4[9] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_48m_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11b_11ag_2g4[10] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11b_11ag_54m_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11b_11ag_2g4[11] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs0_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11n_11ac_2g4[0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs1_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11n_11ac_2g4[1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs2_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11n_11ac_2g4[2] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs3_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11n_11ac_2g4[3] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs4_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11n_11ac_2g4[4] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs5_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11n_11ac_2g4[5] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs6_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11n_11ac_2g4[6] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs7_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11n_11ac_2g4[7] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs8_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11n_11ac_2g4[8] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs9_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11n_11ac_2g4[9] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs0_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_2g4[0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs1_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_2g4[1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs2_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_2g4[2] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs3_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_2g4[3] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs4_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_2g4[4] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs5_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_2g4[5] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs6_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_2g4[6] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs7_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_2g4[7] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs8_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_2g4[8] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs9_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_2g4[9] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs10_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_2g4[10] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs11_2g4")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_2g4[11] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11a_6m_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11a_5g[0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11a_9m_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11a_5g[1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11a_12m_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11a_5g[2] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11a_18m_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11a_5g[3] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11a_24m_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11a_5g[4] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11a_36m_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11a_5g[5] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11a_48m_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11a_5g[6] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11a_54m_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11a_5g[7] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs0_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11n_11ac_5g[0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs1_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11n_11ac_5g[1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs2_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11n_11ac_5g[2] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs3_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11n_11ac_5g[3] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs4_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11n_11ac_5g[4] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs5_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11n_11ac_5g[5] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs6_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11n_11ac_5g[6] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs7_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11n_11ac_5g[7] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs8_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11n_11ac_5g[8] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11n_11ac_mcs9_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11n_11ac_5g[9] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs0_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_5g[0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs1_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_5g[1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs2_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_5g[2] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs3_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_5g[3] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs4_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_5g[4] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs5_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_5g[5] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs6_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_5g[6] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs7_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_5g[7] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs8_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_5g[8] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs9_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_5g[9] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs10_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_5g[10] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_11ax_mcs11_5g")) { ++ userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_5g[11] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_adj_enable")) { ++ userconfig_info.txpwr_lvl_adj.enable = rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_adj_2g4_chan_1_4")) { ++ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_2g4[0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_adj_2g4_chan_5_9")) { ++ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_2g4[1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_adj_2g4_chan_10_13")) { ++ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_2g4[2] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_adj_5g_chan_42")) { ++ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_adj_5g_chan_58")) { ++ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_adj_5g_chan_106")) { ++ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[2] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_adj_5g_chan_122")) { ++ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[3] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_adj_5g_chan_138")) { ++ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[4] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "lvl_adj_5g_chan_155")) { ++ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[5] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "loss_enable_2g4")) { ++ userconfig_info.txpwr_loss.loss_enable_2g4 = rwnx_atoi(value); ++ } else if (!strcmp(command, "loss_value_2g4")) { ++ userconfig_info.txpwr_loss.loss_value_2g4 = rwnx_atoi(value); ++ } else if (!strcmp(command, "loss_enable_5g")) { ++ userconfig_info.txpwr_loss.loss_enable_5g = rwnx_atoi(value); ++ } else if (!strcmp(command, "loss_value_5g")) { ++ userconfig_info.txpwr_loss.loss_value_5g = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_enable")) { ++ userconfig_info.txpwr_ofst2x_v2.enable = rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_2g4_ant0_11b_chan_1_4")) { ++ userconfig_info.txpwr_ofst2x_v2.pwrofst2x_tbl_2g4_ant0[0][0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_2g4_ant0_11b_chan_5_9")) { ++ userconfig_info.txpwr_ofst2x_v2.pwrofst2x_tbl_2g4_ant0[1][0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_2g4_ant0_11b_chan_10_13")) { ++ userconfig_info.txpwr_ofst2x_v2.pwrofst2x_tbl_2g4_ant0[2][0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_2g4_ant0_ofdm_highrate_chan_1_4")) { ++ userconfig_info.txpwr_ofst2x_v2.pwrofst2x_tbl_2g4_ant0[0][1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_2g4_ant0_ofdm_highrate_chan_5_9")) { ++ userconfig_info.txpwr_ofst2x_v2.pwrofst2x_tbl_2g4_ant0[1][1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_2g4_ant0_ofdm_highrate_chan_10_13")) { ++ userconfig_info.txpwr_ofst2x_v2.pwrofst2x_tbl_2g4_ant0[2][1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_2g4_ant1_11b_chan_1_4")) { ++ userconfig_info.txpwr_ofst2x_v2.pwrofst2x_tbl_2g4_ant1[0][0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_2g4_ant1_11b_chan_5_9")) { ++ userconfig_info.txpwr_ofst2x_v2.pwrofst2x_tbl_2g4_ant1[1][0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_2g4_ant1_11b_chan_10_13")) { ++ userconfig_info.txpwr_ofst2x_v2.pwrofst2x_tbl_2g4_ant1[2][0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_2g4_ant1_ofdm_highrate_chan_1_4")) { ++ userconfig_info.txpwr_ofst2x_v2.pwrofst2x_tbl_2g4_ant1[0][1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_2g4_ant1_ofdm_highrate_chan_5_9")) { ++ userconfig_info.txpwr_ofst2x_v2.pwrofst2x_tbl_2g4_ant1[1][1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_2g4_ant1_ofdm_highrate_chan_10_13")) { ++ userconfig_info.txpwr_ofst2x_v2.pwrofst2x_tbl_2g4_ant1[2][1] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ant0_ofdm_highrate_chan_42")) { ++ userconfig_info.txpwr_ofst2x_v2.pwrofst2x_tbl_5g_ant0[0][0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ant0_ofdm_highrate_chan_58")) { ++ userconfig_info.txpwr_ofst2x_v2.pwrofst2x_tbl_5g_ant0[1][0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ant0_ofdm_highrate_chan_106")) { ++ userconfig_info.txpwr_ofst2x_v2.pwrofst2x_tbl_5g_ant0[2][0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ant0_ofdm_highrate_chan_122")) { ++ userconfig_info.txpwr_ofst2x_v2.pwrofst2x_tbl_5g_ant0[3][0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ant0_ofdm_highrate_chan_138")) { ++ userconfig_info.txpwr_ofst2x_v2.pwrofst2x_tbl_5g_ant0[4][0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ant0_ofdm_highrate_chan_155")) { ++ userconfig_info.txpwr_ofst2x_v2.pwrofst2x_tbl_5g_ant0[5][0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ant1_ofdm_highrate_chan_42")) { ++ userconfig_info.txpwr_ofst2x_v2.pwrofst2x_tbl_5g_ant1[0][0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ant1_ofdm_highrate_chan_58")) { ++ userconfig_info.txpwr_ofst2x_v2.pwrofst2x_tbl_5g_ant1[1][0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ant1_ofdm_highrate_chan_106")) { ++ userconfig_info.txpwr_ofst2x_v2.pwrofst2x_tbl_5g_ant1[2][0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ant1_ofdm_highrate_chan_122")) { ++ userconfig_info.txpwr_ofst2x_v2.pwrofst2x_tbl_5g_ant1[3][0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ant1_ofdm_highrate_chan_138")) { ++ userconfig_info.txpwr_ofst2x_v2.pwrofst2x_tbl_5g_ant1[4][0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "ofst_5g_ant1_ofdm_highrate_chan_155")) { ++ userconfig_info.txpwr_ofst2x_v2.pwrofst2x_tbl_5g_ant1[5][0] = ++ rwnx_atoi(value); ++ } else if (!strcmp(command, "xtal_enable")) { ++ userconfig_info.xtal_cap.enable = rwnx_atoi(value); ++ } else if (!strcmp(command, "xtal_cap")) { ++ userconfig_info.xtal_cap.xtal_cap = rwnx_atoi(value); ++ } else if (!strcmp(command, "xtal_cap_fine")) { ++ userconfig_info.xtal_cap.xtal_cap_fine = rwnx_atoi(value); ++ } else { ++ AICWFDBG(LOGERROR, "invalid cmd: %s\n", command); ++ } ++} ++ ++void rwnx_plat_userconfig_parsing_8800d80x2(char *buffer, int size) ++{ ++ int i = 0; ++ int parse_state = 0; ++ char command[100]; ++ char value[100]; ++ int char_counter = 0; ++ ++ memset(command, 0, 64); ++ memset(value, 0, 100); ++ ++ for (i = 0; i < size; i++) { ++ //Send command or print nvram log when char is \r or \n ++ if (buffer[i] == 0x0a || buffer[i] == 0x0d) { ++ if (command[0] != 0 && value[0] != 0) { ++ if (parse_state == PRINT) { ++ AICWFDBG(LOGINFO, "%s:%s\r\n", __func__, ++ value); ++ } else if (parse_state == GET_VALUE) { ++ rwnx_plat_nvram_set_value_8800d80x2( ++ command, value); ++ } ++ } ++ //Reset command value and char_counter ++ memset(command, 0, 64); ++ memset(value, 0, 100); ++ char_counter = 0; ++ parse_state = INIT; ++ continue; ++ } ++ ++ //Switch parser state ++ if (parse_state == INIT) { ++ if (buffer[i] == '#') { ++ parse_state = PRINT; ++ continue; ++ } else if (buffer[i] == 0x0a || buffer[i] == 0x0d) { ++ parse_state = INIT; ++ continue; ++ } else { ++ parse_state = CMD; ++ } ++ } ++ ++ //Fill data to command and value ++ if (parse_state == PRINT) { ++ command[0] = 0x01; ++ value[char_counter] = buffer[i]; ++ char_counter++; ++ } else if (parse_state == CMD) { ++ if (command[0] != 0 && buffer[i] == '=') { ++ parse_state = GET_VALUE; ++ char_counter = 0; ++ continue; ++ } ++ command[char_counter] = buffer[i]; ++ char_counter++; ++ } else if (parse_state == GET_VALUE) { ++ if (buffer[i] != 0x2D && ++ (buffer[i] < 0x30 || buffer[i] > 0x39)) { ++ continue; ++ } ++ value[char_counter] = buffer[i]; ++ char_counter++; ++ } ++ } ++} ++ ++static int aic_load_firmware(u32 **fw_buf, char *fw_path, const char *name, ++ struct device *device) ++{ ++#ifdef CONFIG_USE_FW_REQUEST ++ const struct firmware *fw = NULL; ++ u32 *dst = NULL; ++ void *buffer = NULL; ++ MD5_CTX md5; ++ unsigned char decrypt[16]; ++ int size = 0; ++ int ret = 0; ++ ++ AICWFDBG(LOGINFO, "%s: request firmware = %s \n", __func__, name); ++ ++ ret = request_firmware(&fw, name, NULL); ++ ++ if (ret < 0) { ++ AICWFDBG(LOGERROR, "Load %s fail\n", name); ++ release_firmware(fw); ++ return -1; ++ } ++ ++ size = fw->size; ++ dst = (u32 *)fw->data; ++ ++ if (size <= 0) { ++ AICWFDBG(LOGERROR, "wrong size of firmware file\n"); ++ release_firmware(fw); ++ return -1; ++ } ++ ++ buffer = vmalloc(size); ++ memset(buffer, 0, size); ++ memcpy(buffer, dst, size); ++ ++ *fw_buf = buffer; ++ ++ MD5Init(&md5); ++ MD5Update(&md5, (unsigned char *)buffer, size); ++ MD5Final(&md5, decrypt); ++ AICWFDBG(LOGINFO, MD5PINRT, MD5(decrypt)); ++ ++ release_firmware(fw); ++ ++ return size; ++#else ++ 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 = sprintf(path, "%s/%s", fw_path, name); ++ ++ AICWFDBG(LOGINFO, "%s :firmware path = %s \n", __func__, path); ++ ++ /* open the firmware file */ ++ fp = filp_open(path, O_RDONLY, 0); ++ if (IS_ERR(fp) || (!fp)) { ++ printk("%s: %s file failed to open\n", __func__, name); ++ if (IS_ERR(fp)) { ++ printk("is_Err\n"); ++ } ++ if ((!fp)) { ++ printk("null\n"); ++ } ++ *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 = vmalloc(size); ++ memset(buffer, 0, size); ++ 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 %d %d\n", __func__, name, ++ (int)rdlen, size); ++ *fw_buf = NULL; ++ __putname(path); ++ filp_close(fp, NULL); ++ fp = NULL; ++ vfree(buffer); ++ buffer = NULL; ++ return -1; ++ } ++ if (rdlen > 0) { ++ fp->f_pos += rdlen; ++ //printk("f_pos=%d\n", (int)fp->f_pos); ++ } ++ ++#if 0 ++ /*start to transform the data format*/ ++ src = (u32*)buffer; ++ //printk("malloc dst\n"); ++ dst = (u32*)vmalloc(size); ++ memset(dst, 0, size); ++ ++ if(!dst){ ++ *fw_buf=NULL; ++ __putname(path); ++ filp_close(fp,NULL); ++ fp=NULL; ++ vfree(buffer); ++ buffer=NULL; ++ return -1; ++ } ++ ++ for(i=0;i<(size/4);i++){ ++ dst[i] = src[i]; ++ } ++#endif ++ ++ __putname(path); ++ filp_close(fp, NULL); ++ fp = NULL; ++ //vfree(buffer); ++ //buffer=NULL; ++ *fw_buf = (u32 *)buffer; ++ ++ return size; ++#endif ++} ++ ++#define FW_USERCONFIG_NAME "aic_userconfig.txt" ++ ++int rwnx_plat_userconfig_upload_android(struct rwnx_hw *rwnx_hw, char *fw_path, ++ char *filename) ++{ ++ int size; ++ u32 *dst = NULL; ++ ++ printk("userconfig file path:%s \r\n", filename); ++ ++ /* load aic firmware */ ++ size = aic_load_firmware(&dst, fw_path, filename, NULL); ++ if (size <= 0) { ++ printk("wrong size of firmware file\n"); ++ vfree(dst); ++ dst = NULL; ++ return 0; ++ } ++ ++ /* Copy the file on the Embedded side */ ++ printk("### Upload %s userconfig, size=%d\n", filename, size); ++ ++ rwnx_plat_userconfig_parsing(rwnx_hw, (char *)dst, size); ++ ++ if (dst) { ++ vfree(dst); ++ dst = NULL; ++ } ++ ++ printk("userconfig download complete\n\n"); ++ ++ return 0; ++} ++ ++/** ++ * rwnx_plat_fmac_load() - Load FW code ++ * ++ * @rwnx_hw: Main driver data ++ */ ++#if 0 ++static int rwnx_plat_fmac_load(struct rwnx_hw *rwnx_hw, char *fw_path) ++{ ++ int ret = 0; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ret = rwnx_plat_userconfig_upload_android(rwnx_hw, fw_path, FW_USERCONFIG_NAME); ++ return ret; ++} ++#endif ++ ++/** ++ * rwnx_platform_reset() - Reset the platform ++ * ++ * @rwnx_plat: platform data ++ */ ++static int rwnx_platform_reset(struct rwnx_plat *rwnx_plat) ++{ ++ u32 regval; ++ ++#if defined(AICWF_USB_SUPPORT) || defined(AICWF_SDIO_SUPPORT) ++ return 0; ++#endif ++ ++ /* the doc states that SOFT implies FPGA_B_RESET ++ * adding FPGA_B_RESET is clearer */ ++ RWNX_REG_WRITE(SOFT_RESET | FPGA_B_RESET, rwnx_plat, RWNX_ADDR_SYSTEM, ++ SYSCTRL_MISC_CNTL_ADDR); ++ msleep(100); ++ ++ regval = RWNX_REG_READ(rwnx_plat, RWNX_ADDR_SYSTEM, ++ SYSCTRL_MISC_CNTL_ADDR); ++ ++ if (regval & SOFT_RESET) { ++ dev_err(rwnx_platform_get_dev(rwnx_plat), "reset: failed\n"); ++ return -EIO; ++ } ++ ++ RWNX_REG_WRITE(regval & ~FPGA_B_RESET, rwnx_plat, RWNX_ADDR_SYSTEM, ++ SYSCTRL_MISC_CNTL_ADDR); ++ msleep(100); ++ return 0; ++} ++ ++/** ++ * rwmx_platform_save_config() - Save hardware config before reload ++ * ++ * @rwnx_plat: Pointer to platform data ++ * ++ * Return configuration registers values. ++ */ ++static void *rwnx_term_save_config(struct rwnx_plat *rwnx_plat) ++{ ++ const u32 *reg_list; ++ u32 *reg_value, *res; ++ int i, size = 0; ++ ++ if (rwnx_plat->get_config_reg) { ++ size = rwnx_plat->get_config_reg(rwnx_plat, ®_list); ++ } ++ ++ if (size <= 0) ++ return NULL; ++ ++ res = kmalloc(sizeof(u32) * size, GFP_KERNEL); ++ if (!res) ++ return NULL; ++ ++ reg_value = res; ++ for (i = 0; i < size; i++) { ++ *reg_value++ = ++ RWNX_REG_READ(rwnx_plat, RWNX_ADDR_SYSTEM, *reg_list++); ++ } ++ ++ return res; ++} ++ ++#if 0 ++/** ++ * rwmx_platform_restore_config() - Restore hardware config after reload ++ * ++ * @rwnx_plat: Pointer to platform data ++ * @reg_value: Pointer of value to restore ++ * (obtained with rwmx_platform_save_config()) ++ * ++ * Restore configuration registers value. ++ */ ++static void rwnx_term_restore_config(struct rwnx_plat *rwnx_plat, ++ u32 *reg_value) ++{ ++ const u32 *reg_list; ++ int i, size = 0; ++ ++ if (!reg_value || !rwnx_plat->get_config_reg) ++ return; ++ ++ size = rwnx_plat->get_config_reg(rwnx_plat, ®_list); ++ ++ for (i = 0; i < size; i++) { ++ RWNX_REG_WRITE(*reg_value++, rwnx_plat, RWNX_ADDR_SYSTEM, ++ *reg_list++); ++ } ++} ++#endif ++ ++#ifndef CONFIG_RWNX_FHOST ++#if 0 ++static int rwnx_check_fw_compatibility(struct rwnx_hw *rwnx_hw) ++{ ++ struct ipc_shared_env_tag *shared = rwnx_hw->ipc_env->shared; ++#ifdef CONFIG_RWNX_FULLMAC ++ struct wiphy *wiphy = rwnx_hw->wiphy; ++#endif //CONFIG_RWNX_FULLMAC ++#ifdef CONFIG_RWNX_OLD_IPC ++ int ipc_shared_version = 10; ++#else //CONFIG_RWNX_OLD_IPC ++ int ipc_shared_version = 11; ++#endif //CONFIG_RWNX_OLD_IPC ++ int res = 0; ++ ++ if (shared->comp_info.ipc_shared_version != ipc_shared_version) { ++ wiphy_err(wiphy, "Different versions of IPC shared version between driver and FW (%d != %d)\n ", ++ ipc_shared_version, shared->comp_info.ipc_shared_version); ++ res = -1; ++ } ++ ++ if (shared->comp_info.radarbuf_cnt != IPC_RADARBUF_CNT) { ++ wiphy_err(wiphy, "Different number of host buffers available for Radar events handling "\ ++ "between driver and FW (%d != %d)\n", IPC_RADARBUF_CNT, ++ shared->comp_info.radarbuf_cnt); ++ res = -1; ++ } ++ ++ if (shared->comp_info.unsuprxvecbuf_cnt != IPC_UNSUPRXVECBUF_CNT) { ++ wiphy_err(wiphy, "Different number of host buffers available for unsupported Rx vectors "\ ++ "handling between driver and FW (%d != %d)\n", IPC_UNSUPRXVECBUF_CNT, ++ shared->comp_info.unsuprxvecbuf_cnt); ++ res = -1; ++ } ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ if (shared->comp_info.rxdesc_cnt != IPC_RXDESC_CNT) { ++ wiphy_err(wiphy, "Different number of shared descriptors available for Data RX handling "\ ++ "between driver and FW (%d != %d)\n", IPC_RXDESC_CNT, ++ shared->comp_info.rxdesc_cnt); ++ res = -1; ++ } ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++ if (shared->comp_info.rxbuf_cnt != IPC_RXBUF_CNT) { ++ wiphy_err(wiphy, "Different number of host buffers available for Data Rx handling "\ ++ "between driver and FW (%d != %d)\n", IPC_RXBUF_CNT, ++ shared->comp_info.rxbuf_cnt); ++ res = -1; ++ } ++ ++ if (shared->comp_info.msge2a_buf_cnt != IPC_MSGE2A_BUF_CNT) { ++ wiphy_err(wiphy, "Different number of host buffers available for Emb->App MSGs "\ ++ "sending between driver and FW (%d != %d)\n", IPC_MSGE2A_BUF_CNT, ++ shared->comp_info.msge2a_buf_cnt); ++ res = -1; ++ } ++ ++ if (shared->comp_info.dbgbuf_cnt != IPC_DBGBUF_CNT) { ++ wiphy_err(wiphy, "Different number of host buffers available for debug messages "\ ++ "sending between driver and FW (%d != %d)\n", IPC_DBGBUF_CNT, ++ shared->comp_info.dbgbuf_cnt); ++ res = -1; ++ } ++ ++ if (shared->comp_info.bk_txq != NX_TXDESC_CNT0) { ++ wiphy_err(wiphy, "Driver and FW have different sizes of BK TX queue (%d != %d)\n", ++ NX_TXDESC_CNT0, shared->comp_info.bk_txq); ++ res = -1; ++ } ++ ++ if (shared->comp_info.be_txq != NX_TXDESC_CNT1) { ++ wiphy_err(wiphy, "Driver and FW have different sizes of BE TX queue (%d != %d)\n", ++ NX_TXDESC_CNT1, shared->comp_info.be_txq); ++ res = -1; ++ } ++ ++ if (shared->comp_info.vi_txq != NX_TXDESC_CNT2) { ++ wiphy_err(wiphy, "Driver and FW have different sizes of VI TX queue (%d != %d)\n", ++ NX_TXDESC_CNT2, shared->comp_info.vi_txq); ++ res = -1; ++ } ++ ++ if (shared->comp_info.vo_txq != NX_TXDESC_CNT3) { ++ wiphy_err(wiphy, "Driver and FW have different sizes of VO TX queue (%d != %d)\n", ++ NX_TXDESC_CNT3, shared->comp_info.vo_txq); ++ res = -1; ++ } ++ ++#if NX_TXQ_CNT == 5 ++ if (shared->comp_info.bcn_txq != NX_TXDESC_CNT4) { ++ wiphy_err(wiphy, "Driver and FW have different sizes of BCN TX queue (%d != %d)\n", ++ NX_TXDESC_CNT4, shared->comp_info.bcn_txq); ++ res = -1; ++ } ++#else ++ if (shared->comp_info.bcn_txq > 0) { ++ wiphy_err(wiphy, "BCMC enabled in firmware but disabled in driver\n"); ++ res = -1; ++ } ++#endif /* NX_TXQ_CNT == 5 */ ++ ++ if (shared->comp_info.ipc_shared_size != sizeof(ipc_shared_env)) { ++ wiphy_err(wiphy, "Different sizes of IPC shared between driver and FW (%zd != %d)\n", ++ sizeof(ipc_shared_env), shared->comp_info.ipc_shared_size); ++ res = -1; ++ } ++ ++ if (shared->comp_info.msg_api != MSG_API_VER) { ++ wiphy_warn(wiphy, "WARNING: Different supported message API versions between "\ ++ "driver and FW (%d != %d)\n", MSG_API_VER, shared->comp_info.msg_api); ++ } ++ ++ return res; ++} ++#endif ++#endif /* !CONFIG_RWNX_FHOST */ ++ ++void get_userconfig_txpwr_lvl_in_fdrv(txpwr_lvl_conf_t *txpwr_lvl) ++{ ++ txpwr_lvl->enable = userconfig_info.txpwr_lvl.enable; ++ txpwr_lvl->dsss = userconfig_info.txpwr_lvl.dsss; ++ txpwr_lvl->ofdmlowrate_2g4 = userconfig_info.txpwr_lvl.ofdmlowrate_2g4; ++ txpwr_lvl->ofdm64qam_2g4 = userconfig_info.txpwr_lvl.ofdm64qam_2g4; ++ txpwr_lvl->ofdm256qam_2g4 = userconfig_info.txpwr_lvl.ofdm256qam_2g4; ++ txpwr_lvl->ofdm1024qam_2g4 = userconfig_info.txpwr_lvl.ofdm1024qam_2g4; ++ txpwr_lvl->ofdmlowrate_5g = userconfig_info.txpwr_lvl.ofdmlowrate_5g; ++ txpwr_lvl->ofdm64qam_5g = userconfig_info.txpwr_lvl.ofdm64qam_5g; ++ txpwr_lvl->ofdm256qam_5g = userconfig_info.txpwr_lvl.ofdm256qam_5g; ++ txpwr_lvl->ofdm1024qam_5g = userconfig_info.txpwr_lvl.ofdm1024qam_5g; ++ ++ AICWFDBG(LOGINFO, "%s:enable:%d\r\n", __func__, txpwr_lvl->enable); ++ AICWFDBG(LOGINFO, "%s:dsss:%d\r\n", __func__, txpwr_lvl->dsss); ++ AICWFDBG(LOGINFO, "%s:ofdmlowrate_2g4:%d\r\n", __func__, ++ txpwr_lvl->ofdmlowrate_2g4); ++ AICWFDBG(LOGINFO, "%s:ofdm64qam_2g4:%d\r\n", __func__, ++ txpwr_lvl->ofdm64qam_2g4); ++ AICWFDBG(LOGINFO, "%s:ofdm256qam_2g4:%d\r\n", __func__, ++ txpwr_lvl->ofdm256qam_2g4); ++ AICWFDBG(LOGINFO, "%s:ofdm1024qam_2g4:%d\r\n", __func__, ++ txpwr_lvl->ofdm1024qam_2g4); ++ AICWFDBG(LOGINFO, "%s:ofdmlowrate_5g:%d\r\n", __func__, ++ txpwr_lvl->ofdmlowrate_5g); ++ AICWFDBG(LOGINFO, "%s:ofdm64qam_5g:%d\r\n", __func__, ++ txpwr_lvl->ofdm64qam_5g); ++ AICWFDBG(LOGINFO, "%s:ofdm256qam_5g:%d\r\n", __func__, ++ txpwr_lvl->ofdm256qam_5g); ++ AICWFDBG(LOGINFO, "%s:ofdm1024qam_5g:%d\r\n", __func__, ++ txpwr_lvl->ofdm1024qam_5g); ++} ++ ++void get_userconfig_txpwr_lvl_v2_in_fdrv(txpwr_lvl_conf_v2_t *txpwr_lvl_v2) ++{ ++ *txpwr_lvl_v2 = userconfig_info.txpwr_lvl_v2; ++ ++ AICWFDBG(LOGINFO, "%s:enable:%d\r\n", __func__, txpwr_lvl_v2->enable); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_1m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_2m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_5m5_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_11m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_6m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_9m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_12m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_18m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_24m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_36m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_48m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[10]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_54m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[11]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs0_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs1_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs2_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs3_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs4_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs5_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs6_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs7_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs8_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs9_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs0_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs1_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs2_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs3_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs4_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs5_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs6_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs7_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs8_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs9_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs10_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[10]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs11_2g4:%d\r\n", __func__, ++ txpwr_lvl_v2->pwrlvl_11ax_2g4[11]); ++} ++ ++void get_userconfig_txpwr_lvl_v3_in_fdrv(txpwr_lvl_conf_v3_t *txpwr_lvl_v3) ++{ ++ *txpwr_lvl_v3 = userconfig_info.txpwr_lvl_v3; ++ ++ AICWFDBG(LOGINFO, "%s:enable:%d\r\n", __func__, txpwr_lvl_v3->enable); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_1m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_2m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_5m5_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_11m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_6m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_9m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_12m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_18m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_24m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_36m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_48m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[10]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_54m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[11]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs0_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs1_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs2_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs3_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs4_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs5_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs6_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs7_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs8_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs9_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs0_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_2g4[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs1_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_2g4[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs2_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_2g4[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs3_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_2g4[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs4_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_2g4[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs5_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_2g4[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs6_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_2g4[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs7_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_2g4[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs8_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_2g4[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs9_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_2g4[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs10_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_2g4[10]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs11_2g4:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_2g4[11]); ++ ++ AICWFDBG(LOGINFO, "%s:lvl_11a_1m_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11a_5g[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_2m_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11a_5g[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_5m5_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11a_5g[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_11m_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11a_5g[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_6m_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11a_5g[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_9m_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11a_5g[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_12m_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11a_5g[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_18m_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11a_5g[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_24m_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11a_5g[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_36m_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11a_5g[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_48m_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11a_5g[10]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_54m_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11a_5g[11]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs0_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_5g[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs1_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_5g[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs2_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_5g[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs3_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_5g[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs4_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_5g[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs5_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_5g[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs6_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_5g[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs7_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_5g[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs8_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_5g[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs9_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11n_11ac_5g[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs0_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_5g[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs1_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_5g[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs2_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_5g[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs3_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_5g[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs4_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_5g[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs5_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_5g[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs6_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_5g[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs7_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_5g[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs8_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_5g[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs9_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_5g[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs10_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_5g[10]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs11_5g:%d\r\n", __func__, ++ txpwr_lvl_v3->pwrlvl_11ax_5g[11]); ++} ++ ++void get_userconfig_txpwr_lvl_v4_in_fdrv(txpwr_lvl_conf_v4_t *txpwr_lvl_v4) ++{ ++ *txpwr_lvl_v4 = userconfig_info.txpwr_lvl_v4; ++ ++ AICWFDBG(LOGINFO, "%s:enable:%d\r\n", __func__, txpwr_lvl_v4->enable); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_1m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11b_11ag_2g4[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_2m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11b_11ag_2g4[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_5m5_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11b_11ag_2g4[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_11m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11b_11ag_2g4[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_6m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11b_11ag_2g4[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_9m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11b_11ag_2g4[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_12m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11b_11ag_2g4[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_18m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11b_11ag_2g4[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_24m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11b_11ag_2g4[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_36m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11b_11ag_2g4[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_48m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11b_11ag_2g4[10]); ++ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_54m_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11b_11ag_2g4[11]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs0_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_2g4[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs1_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_2g4[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs2_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_2g4[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs3_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_2g4[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs4_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_2g4[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs5_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_2g4[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs6_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_2g4[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs7_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_2g4[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs8_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_2g4[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs9_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_2g4[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs0_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_2g4[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs1_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_2g4[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs2_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_2g4[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs3_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_2g4[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs4_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_2g4[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs5_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_2g4[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs6_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_2g4[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs7_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_2g4[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs8_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_2g4[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs9_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_2g4[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs10_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_2g4[10]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs11_2g4:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_2g4[11]); ++ ++ AICWFDBG(LOGINFO, "%s:lvl_11a_6m_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11a_5g[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_9m_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11a_5g[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_12m_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11a_5g[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_18m_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11a_5g[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_24m_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11a_5g[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_36m_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11a_5g[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_48m_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11a_5g[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11a_54m_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11a_5g[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs0_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_5g[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs1_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_5g[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs2_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_5g[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs3_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_5g[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs4_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_5g[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs5_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_5g[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs6_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_5g[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs7_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_5g[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs8_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_5g[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs9_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11n_11ac_5g[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs0_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_5g[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs1_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_5g[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs2_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_5g[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs3_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_5g[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs4_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_5g[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs5_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_5g[5]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs6_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_5g[6]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs7_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_5g[7]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs8_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_5g[8]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs9_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_5g[9]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs10_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_5g[10]); ++ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs11_5g:%d\r\n", __func__, ++ txpwr_lvl_v4->pwrlvl_11ax_5g[11]); ++} ++ ++void get_userconfig_txpwr_lvl_adj_in_fdrv(txpwr_lvl_adj_conf_t *txpwr_lvl_adj) ++{ ++ *txpwr_lvl_adj = userconfig_info.txpwr_lvl_adj; ++ ++ AICWFDBG(LOGINFO, "%s:enable:%d\r\n", __func__, txpwr_lvl_adj->enable); ++ AICWFDBG(LOGINFO, "%s:lvl_adj_2g4_chan_1_4:%d\r\n", __func__, ++ txpwr_lvl_adj->pwrlvl_adj_tbl_2g4[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_adj_2g4_chan_5_9:%d\r\n", __func__, ++ txpwr_lvl_adj->pwrlvl_adj_tbl_2g4[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_adj_2g4_chan_10_13:%d\r\n", __func__, ++ txpwr_lvl_adj->pwrlvl_adj_tbl_2g4[2]); ++ ++ AICWFDBG(LOGINFO, "%s:lvl_adj_5g_chan_42:%d\r\n", __func__, ++ txpwr_lvl_adj->pwrlvl_adj_tbl_5g[0]); ++ AICWFDBG(LOGINFO, "%s:lvl_adj_5g_chan_58:%d\r\n", __func__, ++ txpwr_lvl_adj->pwrlvl_adj_tbl_5g[1]); ++ AICWFDBG(LOGINFO, "%s:lvl_adj_5g_chan_106:%d\r\n", __func__, ++ txpwr_lvl_adj->pwrlvl_adj_tbl_5g[2]); ++ AICWFDBG(LOGINFO, "%s:lvl_adj_5g_chan_122:%d\r\n", __func__, ++ txpwr_lvl_adj->pwrlvl_adj_tbl_5g[3]); ++ AICWFDBG(LOGINFO, "%s:lvl_adj_5g_chan_138:%d\r\n", __func__, ++ txpwr_lvl_adj->pwrlvl_adj_tbl_5g[4]); ++ AICWFDBG(LOGINFO, "%s:lvl_adj_5g_chan_155:%d\r\n", __func__, ++ txpwr_lvl_adj->pwrlvl_adj_tbl_5g[5]); ++} ++ ++#ifdef CONFIG_POWER_LIMIT ++#define GetLineFromBuffer(buffer) strsep(&buffer, "\n") ++ ++int isAllSpaceOrTab(uint8_t *data, uint8_t size) ++{ ++ uint8_t cnt = 0, NumOfSpaceAndTab = 0; ++ while (size > cnt) { ++ if (data[cnt] == ' ' || data[cnt] == '\t' || data[cnt] == '\0') ++ ++NumOfSpaceAndTab; ++ ++cnt; ++ } ++ return size == NumOfSpaceAndTab; ++} ++ ++int IsCommentString(char *szStr) ++{ ++ if (*szStr == '#' && *(szStr + 1) == ' ') ++ return 1; ++ else ++ return 0; ++} ++ ++int ParseQualifiedString(char *In, u32 *Start, char *Out, char LeftQualifier, ++ char RightQualifier) ++{ ++ u32 i = 0, j = 0; ++ char c = In[(*Start)++]; ++ if (c != LeftQualifier) ++ return 0; ++ i = (*Start); ++ c = In[(*Start)++]; ++ while (c != RightQualifier && c != '\0') ++ c = In[(*Start)++]; ++ if (c == '\0') ++ return 0; ++ j = (*Start) - 2; ++ strncpy((char *)Out, (const char *)(In + i), j - i + 1); ++ return 1; ++} ++ ++int GetU1ByteIntegerFromStringInDecimal(char *Str, u8 *pInt) ++{ ++ u16 i = 0; ++ *pInt = 0; ++ while (Str[i] != '\0') { ++ if (Str[i] >= '0' && Str[i] <= '9') { ++ *pInt *= 10; ++ *pInt += (Str[i] - '0'); ++ } else ++ return 0; ++ ++i; ++ } ++ return 1; ++} ++int GetS1ByteIntegerFromStringInDecimal(char *str, s8 *val) ++{ ++ u8 negative = 0; ++ u16 i = 0; ++ *val = 0; ++ while (str[i] != '\0') { ++ if (i == 0 && (str[i] == '+' || str[i] == '-')) { ++ if (str[i] == '-') ++ negative = 1; ++ } else if (str[i] >= '0' && str[i] <= '9') { ++ *val *= 10; ++ *val += (str[i] - '0'); ++ } else ++ return 0; ++ ++i; ++ } ++ if (negative) ++ *val = -*val; ++ return 1; ++} ++ ++int8_t rwnx_plat_powerlimit_save(u8_l band, char *channel, u8_l bw, char *limit, ++ char *name) ++{ ++ u8 channel_num, powerLimit_val, reg_idx; ++ ++ if (GetU1ByteIntegerFromStringInDecimal((char *)channel, ++ &channel_num) == 0 || ++ GetS1ByteIntegerFromStringInDecimal((char *)limit, ++ &powerLimit_val) == 0) { ++ AICWFDBG(LOGERROR, ++ "Illegal index of power limit table [ch %s][val %s]\n", ++ channel, limit); ++ return -1; ++ } ++ ++ reg_idx = get_region_index(name); ++ ++ if (band == PHY_BAND_2G4) { ++ uint8_t cur_idx = ++ powerlimit_info.txpwr_lmt[reg_idx].ch_cnt_2g4[bw]; ++ AICWFDBG( ++ LOGINFO, ++ "reg_idx=%d, band=%d, bw=%d, cur_idx=%d, ch=%s, pwr=%s\n", ++ reg_idx, band, bw, cur_idx, channel, limit); ++ if (cur_idx < MAC_DOMAINCHANNEL_24G_MAX) { ++ powerlimit_info.txpwr_lmt[reg_idx] ++ .ch_num_2g4[bw][cur_idx] = channel_num; ++ powerlimit_info.txpwr_lmt[reg_idx] ++ .max_pwr_2g4[bw][cur_idx] = powerLimit_val; ++ powerlimit_info.txpwr_lmt[reg_idx].ch_cnt_2g4[bw]++; ++ } else { ++ AICWFDBG(LOGERROR, "band %d chan_cnt reached %d\n", ++ band, MAC_DOMAINCHANNEL_24G_MAX); ++ AICWFDBG(LOGERROR, "channel=%s(%d) powerLimit=%s(%d)\n", ++ channel, channel_num, limit, powerLimit_val); ++ } ++ } else if (band == PHY_BAND_5G) { ++ uint8_t cur_idx = ++ powerlimit_info.txpwr_lmt[reg_idx].ch_cnt_5g[bw]; ++ AICWFDBG( ++ LOGINFO, ++ "reg_idx=%d, band=%d, bw=%d, cur_idx=%d, ch=%s, pwr=%s\n", ++ reg_idx, band, bw, cur_idx, channel, limit); ++ if (cur_idx < MAC_DOMAINCHANNEL_5G_MAX) { ++ powerlimit_info.txpwr_lmt[reg_idx] ++ .ch_num_5g[bw][cur_idx] = channel_num; ++ powerlimit_info.txpwr_lmt[reg_idx] ++ .max_pwr_5g[bw][cur_idx] = powerLimit_val; ++ powerlimit_info.txpwr_lmt[reg_idx].ch_cnt_5g[bw]++; ++ } else { ++ AICWFDBG(LOGERROR, "band %d chan_cnt reached %d\n", ++ band, MAC_DOMAINCHANNEL_5G_MAX); ++ AICWFDBG(LOGERROR, "channel=%s(%d) powerLimit=%s(%d)\n", ++ channel, channel_num, limit, powerLimit_val); ++ } ++ } ++ ++ return 0; ++} ++ ++void rwnx_plat_powerlimit_parsing(char *buffer, int size, char *cc) ++{ ++#define LD_STAGE_EXC_MAPPING 0 ++#define LD_STAGE_TAB_DEFINE 1 ++#define LD_STAGE_TAB_START 2 ++#define LD_STAGE_COLUMN_DEFINE 3 ++#define LD_STAGE_CH_ROW 4 ++ ++ uint8_t loadingStage = LD_STAGE_EXC_MAPPING; ++ uint32_t i = 0, forCnt = 0; ++ uint32_t i_cc; ++ char *szLine, *ptmp; ++ char band[10], colNumBuf[10], bandwidth[10]; ++ uint8_t colNum = 0, band_cc = 0, bw_cc = 0; ++ char **reg_name = NULL; ++ // clear powerlimit info at first ++ memset((void *)&powerlimit_info, 0, sizeof(powerlimit_info_t)); ++ ptmp = buffer; ++ for (szLine = GetLineFromBuffer(ptmp); szLine != NULL; ++ szLine = GetLineFromBuffer(ptmp)) { ++ if (isAllSpaceOrTab(szLine, sizeof(*szLine))) ++ continue; ++ if (IsCommentString(szLine)) ++ continue; ++ ++ if (loadingStage == LD_STAGE_EXC_MAPPING) { ++ if (szLine[0] == '#' || szLine[1] == '#') { ++ loadingStage = LD_STAGE_TAB_DEFINE; ++ } else { ++ continue; ++ } ++ } ++ ++ if (loadingStage == LD_STAGE_TAB_DEFINE) { ++ /* read "## 2.4G" */ ++ if (szLine[0] != '#' || szLine[1] != '#') ++ continue; ++ ++ /* skip the space */ ++ i = 2; ++ while (szLine[i] == ' ' || szLine[i] == '\t') ++ ++i; ++ ++ szLine[--i] = ++ ' '; /* return the space in front of the regulation info */ ++ ++ /* Parse the label of the table */ ++ memset((void *)band, 0, 10); ++ memset((void *)bandwidth, 0, 10); ++ memset((void *)colNumBuf, 0, 10); ++ ++ if (!ParseQualifiedString(szLine, &i, band, ' ', ',')) { ++ AICWFDBG(LOGERROR, "Fail to parse band!\n"); ++ goto exit; ++ } ++ if (strncmp(band, "2.4G", 4) == 0) { ++ band_cc = PHY_BAND_2G4; ++ } else if (strncmp(band, "5G", 2) == 0) { ++ band_cc = PHY_BAND_5G; ++ } ++ ++ if (!ParseQualifiedString(szLine, &i, bandwidth, ' ', ++ ',')) { ++ AICWFDBG(LOGERROR, ++ "Fail to parse bandwidth!\n"); ++ goto exit; ++ } ++ if (strncmp(bandwidth, "20M", 3) == 0) ++ bw_cc = PHY_CHNL_BW_20; ++ else if (strncmp(bandwidth, "40M", 3) == 0) ++ bw_cc = PHY_CHNL_BW_40; ++ else if (strncmp(bandwidth, "80M", 3) == 0) ++ bw_cc = PHY_CHNL_BW_80; ++ ++ if (!ParseQualifiedString(szLine, &i, colNumBuf, '#', ++ '#')) { ++ AICWFDBG(LOGERROR, ++ "Fail to parse column number!\n"); ++ goto exit; ++ } ++ if (!GetU1ByteIntegerFromStringInDecimal(colNumBuf, ++ &colNum)) { ++ AICWFDBG( ++ LOGERROR, ++ "Column number \"%s\" is not unsigned decimal\n", ++ colNumBuf); ++ goto exit; ++ } ++ if (colNum == 0) { ++ AICWFDBG(LOGERROR, "Column number is 0\n"); ++ goto exit; ++ } ++ ++ AICWFDBG(LOGINFO, "band=%s, bandwidth=%s, colnum=%d\n", ++ band, bandwidth, colNum); ++ loadingStage = LD_STAGE_TAB_START; ++ } else if (loadingStage == LD_STAGE_TAB_START) { ++ /* read "## START" */ ++ if (szLine[0] != '#' || szLine[1] != '#') ++ continue; ++ ++ /* skip the space */ ++ i = 2; ++ while (szLine[i] == ' ' || szLine[i] == '\t') ++ ++i; ++ ++ if (strncmp((u8 *)(szLine + i), "START", 5)) { ++ AICWFDBG(LOGERROR, ++ "Missing \"## START\" label\n"); ++ goto exit; ++ } ++ ++ loadingStage = LD_STAGE_COLUMN_DEFINE; ++ } else if (loadingStage == LD_STAGE_COLUMN_DEFINE) { ++ /* read "## FCC ETSI" */ ++ if (szLine[0] != '#' || szLine[1] != '#') ++ continue; ++ ++ /* skip the space */ ++ i = 2; ++ while (szLine[i] == ' ' || szLine[i] == '\t') ++ ++i; ++ ++ reg_name = (char **)kmalloc(sizeof(char *) * colNum, ++ GFP_KERNEL); ++ if (!reg_name) { ++ AICWFDBG(LOGERROR, "reg_name alloc fail\n"); ++ goto exit; ++ } ++ ++ for (forCnt = 0; forCnt < colNum; ++forCnt) { ++ /* skip the space */ ++ while (szLine[i] == ' ' || szLine[i] == '\t') ++ i++; ++ i_cc = i; ++ ++ while (szLine[i] != ' ' && szLine[i] != '\t' && ++ szLine[i] != '\0') ++ i++; ++ ++ reg_name[forCnt] = (char *)kmalloc(i - i_cc + 1, ++ GFP_KERNEL); ++ if (!reg_name[forCnt]) { ++ AICWFDBG( ++ LOGERROR, ++ "reg_name element alloc fail\n"); ++ goto exit; ++ } ++ ++ strncpy(reg_name[forCnt], szLine + i_cc, ++ i - i_cc); ++ reg_name[forCnt][i - i_cc] = '\0'; ++ AICWFDBG(LOGINFO, "reg_name: %s\n", ++ reg_name[forCnt]); ++ } ++ ++ loadingStage = LD_STAGE_CH_ROW; ++ } else if (loadingStage == LD_STAGE_CH_ROW) { ++ char channel[10] = { 0 }, powerLimit[10] = { 0 }; ++ u8 cnt = 0; ++ ++ /* the table ends */ ++ if (szLine[0] == '#' && szLine[1] == '#') { ++ i = 2; ++ while (szLine[i] == ' ' || szLine[i] == '\t') ++ ++i; ++ ++ if (strncmp((u8 *)(szLine + i), "END", 3) == ++ 0) { ++ loadingStage = LD_STAGE_TAB_DEFINE; ++ if (reg_name) { ++ for (forCnt = 0; ++ forCnt < colNum; ++ ++forCnt) { ++ if (reg_name[forCnt]) { ++ kfree(reg_name[forCnt]); ++ reg_name[forCnt] = ++ NULL; ++ } ++ } ++ kfree(reg_name); ++ reg_name = NULL; ++ } ++ colNum = 0; ++ continue; ++ } else { ++ AICWFDBG( ++ LOGERROR, ++ "Missing \"## END\" label\n"); ++ goto exit; ++ } ++ } ++ ++ if ((szLine[0] != 'c' && szLine[0] != 'C') || ++ (szLine[1] != 'h' && szLine[1] != 'H')) { ++ AICWFDBG( ++ LOGERROR, ++ "Wrong channel prefix: '%c','%c'(%d,%d)\n", ++ szLine[0], szLine[1], szLine[0], ++ szLine[1]); ++ continue; ++ } ++ i = 2; /* move to the location behind 'h' */ ++ ++ /* load the channel number */ ++ cnt = 0; ++ while (szLine[i] >= '0' && szLine[i] <= '9') { ++ channel[cnt] = szLine[i]; ++ ++cnt; ++ ++i; ++ } ++ ++ for (forCnt = 0; forCnt < colNum; ++forCnt) { ++ /* skip the space between channel number and the power limit value */ ++ while (szLine[i] == ' ' || szLine[i] == '\t') ++ ++i; ++ ++ /* load the power limit value */ ++ memset((void *)powerLimit, 0, 10); ++ ++ if (szLine[i] == 'N' && szLine[i + 1] == 'A') { ++ /* ++ * means channel not available ++ */ ++ sprintf(powerLimit, "%d", ++ POWER_LIMIT_INVALID_VAL); ++ i += 2; ++ } else if ((szLine[i] >= '0' && ++ szLine[i] <= '9') || ++ szLine[i] == '+' || ++ szLine[i] == '-') { ++ /* case of dBm value */ ++ cnt = 0; ++ while ((szLine[i] >= '0' && ++ szLine[i] <= '9') || ++ szLine[i] == '+' || ++ szLine[i] == '-') { ++ powerLimit[cnt] = szLine[i]; ++ ++cnt; ++ ++i; ++ } ++ } else { ++ AICWFDBG( ++ LOGERROR, ++ "Wrong limit expression \"%c%c\"(%d, %d)\n", ++ szLine[i], szLine[i + 1], ++ szLine[i], szLine[i + 1]); ++ goto exit; ++ } ++ ++ if (rwnx_plat_powerlimit_save( ++ band_cc, channel, bw_cc, powerLimit, ++ reg_name[forCnt]) < 0) ++ goto exit; ++ } ++ } ++ } ++ ++ powerlimit_info.flags |= POWER_LIMIT_CC_MATCHED_BIT; ++exit: ++ if (reg_name) { ++ for (forCnt = 0; forCnt < colNum; ++forCnt) { ++ if (reg_name[forCnt]) { ++ kfree(reg_name[forCnt]); ++ reg_name[forCnt] = NULL; ++ } ++ } ++ kfree(reg_name); ++ reg_name = NULL; ++ } ++ ++ return; ++} ++ ++/// 5G lower bound freq ++#define PHY_FREQ_5G 5000 ++ ++uint16_t phy_channel_to_freq(uint8_t band, int channel) ++{ ++ if ((band == PHY_BAND_2G4) && (channel >= 1) && (channel <= 14)) { ++ if (channel == 14) ++ return 2484; ++ else ++ return 2407 + channel * 5; ++ } else if ((band == PHY_BAND_5G) && (channel >= 1) && ++ (channel <= 165)) { ++ return PHY_FREQ_5G + channel * 5; ++ } ++ return 0; ++} ++ ++int8_t get_powerlimit_by_freq(uint8_t band, uint16_t freq, uint8_t r_idx) ++{ ++ int8_t ret = POWER_LIMIT_INVALID_VAL; ++ uint8_t idx; ++ if (!(powerlimit_info.flags & POWER_LIMIT_CC_MATCHED_BIT)) { ++ AICWFDBG(LOGERROR, "powerlimit flag not set\n"); ++ return ret; ++ } ++ ++ if (band == PHY_BAND_2G4) { ++ uint8_t idx_cnt = ++ powerlimit_info.txpwr_lmt[r_idx].ch_cnt_2g4[0]; ++ for (idx = 0; idx < idx_cnt; idx++) { ++ int ch_num = powerlimit_info.txpwr_lmt[r_idx] ++ .ch_num_2g4[0][idx]; ++ uint16_t freq_tmp = ++ phy_channel_to_freq(PHY_BAND_2G4, ch_num); ++ if (freq == freq_tmp) { ++ ret = powerlimit_info.txpwr_lmt[r_idx] ++ .max_pwr_2g4[0][idx]; ++ AICWFDBG(LOGINFO, ++ "[%d]: ch=%d(freq=%d), pwr=%d\n", idx, ++ ch_num, freq, ret); ++ break; ++ } ++ } ++ if (idx == idx_cnt) ++ AICWFDBG(LOGERROR, ++ "powerlimit search failed: band=%d freq=%d\n", ++ band, freq); ++ } else if (band == PHY_BAND_5G) { ++ uint8_t idx_cnt = powerlimit_info.txpwr_lmt[r_idx].ch_cnt_5g[0]; ++ for (idx = 0; idx < idx_cnt; idx++) { ++ int ch_num = powerlimit_info.txpwr_lmt[r_idx] ++ .ch_num_5g[0][idx]; ++ uint16_t freq_tmp = ++ phy_channel_to_freq(PHY_BAND_5G, ch_num); ++ if (freq == freq_tmp) { ++ ret = powerlimit_info.txpwr_lmt[r_idx] ++ .max_pwr_5g[0][idx]; ++ AICWFDBG(LOGINFO, ++ "[%d]: ch=%d(freq=%d), pwr=%d\n", idx, ++ ch_num, freq, ret); ++ break; ++ } ++ } ++ if (idx == idx_cnt) ++ AICWFDBG(LOGERROR, ++ "powerlimit search failed: band=%d freq=%d\n", ++ band, freq); ++ } ++ return ret; ++} ++ ++int8_t get_powerlimit_by_chnum(uint8_t chnum, uint8_t r_idx, uint8_t bw) ++{ ++ int8_t ret = POWER_LIMIT_INVALID_VAL; ++ uint8_t idx; ++ if (!(powerlimit_info.flags & POWER_LIMIT_CC_MATCHED_BIT)) { ++ AICWFDBG(LOGERROR, "powerlimit flag not set\n"); ++ return ret; ++ } ++ ++ if (chnum <= 14) { ++ uint8_t idx_cnt = ++ powerlimit_info.txpwr_lmt[r_idx].ch_cnt_2g4[bw]; ++ for (idx = 0; idx < idx_cnt; idx++) { ++ uint8_t ch_num = powerlimit_info.txpwr_lmt[r_idx] ++ .ch_num_2g4[bw][idx]; ++ if (chnum == ch_num) { ++ ret = powerlimit_info.txpwr_lmt[r_idx] ++ .max_pwr_2g4[bw][idx]; ++ AICWFDBG(LOGINFO, "[%d]: ch=%d, pwr=%d\n", idx, ++ ch_num, ret); ++ break; ++ } ++ } ++ if (idx == idx_cnt) ++ AICWFDBG( ++ LOGERROR, ++ "%s powerlimit search failed: chnum=%d, please confirm the center frequency\n", ++ __func__, chnum); ++ } else if (chnum <= 165) { ++ uint8_t idx_cnt = ++ powerlimit_info.txpwr_lmt[r_idx].ch_cnt_5g[bw]; ++ for (idx = 0; idx < idx_cnt; idx++) { ++ uint8_t ch_num = powerlimit_info.txpwr_lmt[r_idx] ++ .ch_num_5g[bw][idx]; ++ if (chnum == ch_num) { ++ ret = powerlimit_info.txpwr_lmt[r_idx] ++ .max_pwr_5g[bw][idx]; ++ AICWFDBG(LOGINFO, "[%d]: ch=%d, pwr=%d\n", idx, ++ ch_num, ret); ++ break; ++ } ++ } ++ if (idx == idx_cnt) ++ AICWFDBG( ++ LOGERROR, ++ "%s powerlimit search failed: chnum=%d, please confirm the center frequency\n", ++ __func__, chnum); ++ } ++ ++ return ret; ++} ++#endif ++ ++/** ++ * rwnx_plat_userconfig_load ---Load aic_userconfig.txt ++ *@filename name of config ++*/ ++static int rwnx_plat_userconfig_load(struct rwnx_hw *rwnx_hw) ++{ ++ if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8801) { ++ rwnx_plat_userconfig_upload_android(rwnx_hw, aic_fw_path, ++ FW_USERCONFIG_NAME); ++ } else if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DC) { ++ rwnx_plat_userconfig_load_8800dc(rwnx_hw); ++ } else if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800DW) { ++ rwnx_plat_userconfig_load_8800dw(rwnx_hw); ++ } else if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80) { ++ rwnx_plat_userconfig_load_8800d80(rwnx_hw); ++#ifdef CONFIG_POWER_LIMIT ++ rwnx_plat_powerlimit_load_8800d80(rwnx_hw); ++#endif ++ } else if (rwnx_hw->sdiodev->chipid == PRODUCT_ID_AIC8800D80X2) { ++ rwnx_plat_userconfig_load_8800d80x2(rwnx_hw); ++#ifdef CONFIG_POWER_LIMIT ++ rwnx_plat_powerlimit_load_8800d80x2(rwnx_hw); ++#endif ++ } ++ return 0; ++} ++ ++void get_userconfig_txpwr_loss(txpwr_loss_conf_t *txpwr_loss) ++{ ++ txpwr_loss->loss_enable_2g4 = ++ userconfig_info.txpwr_loss.loss_enable_2g4; ++ txpwr_loss->loss_value_2g4 = userconfig_info.txpwr_loss.loss_value_2g4; ++ txpwr_loss->loss_enable_5g = userconfig_info.txpwr_loss.loss_enable_5g; ++ txpwr_loss->loss_value_5g = userconfig_info.txpwr_loss.loss_value_5g; ++ ++ AICWFDBG( ++ LOGDEBUG, ++ "%s:loss_enable_2g4: %d, val_2g4: %d, loss_enable_5g: %d, val_5g: %d\r\n", ++ __func__, txpwr_loss->loss_enable_2g4, ++ txpwr_loss->loss_value_2g4, txpwr_loss->loss_enable_5g, ++ txpwr_loss->loss_value_5g); ++} ++ ++/** ++ * rwnx_platform_on() - Start the platform ++ * ++ * @rwnx_hw: Main driver data ++ * @config: Config to restore (NULL if nothing to restore) ++ * ++ * It starts the platform : ++ * - load fw and ucodes ++ * - initialize IPC ++ * - boot the fw ++ * - enable link communication/IRQ ++ * ++ * Called by 802.11 part ++ */ ++int rwnx_platform_on(struct rwnx_hw *rwnx_hw, void *config) ++{ ++ int ret; ++ struct rwnx_plat *rwnx_plat = rwnx_hw->plat; ++ (void)ret; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ if (rwnx_plat->enabled) ++ return 0; ++ ++#ifndef CONFIG_ROM_PATCH_EN ++#ifdef CONFIG_DOWNLOAD_FW ++ ret = rwnx_plat_fmac_load(rwnx_hw, (char *)config); ++ if (ret) ++ return ret; ++#endif /* !CONFIG_ROM_PATCH_EN */ ++#endif ++ ++#if 0 ++ ret = rwnx_plat_patch_load(rwnx_hw); ++ if (ret) { ++ return ret; ++ } ++#endif ++ ++ rwnx_plat_userconfig_load(rwnx_hw); ++ ++ //rwnx_plat->enabled = true; ++ ++ return 0; ++} ++ ++/** ++ * rwnx_platform_off() - Stop the platform ++ * ++ * @rwnx_hw: Main driver data ++ * @config: Updated with pointer to config, to be able to restore it with ++ * rwnx_platform_on(). It's up to the caller to free the config. Set to NULL ++ * if configuration is not needed. ++ * ++ * Called by 802.11 part ++ */ ++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 ++ ++ if (!rwnx_hw->plat->enabled) { ++ if (config) ++ *config = NULL; ++ return; ++ } ++ ++ if (config) ++ *config = rwnx_term_save_config(rwnx_hw->plat); ++ ++ rwnx_hw->plat->disable(rwnx_hw); ++ ++ tasklet_kill(&rwnx_hw->task); ++ rwnx_platform_reset(rwnx_hw->plat); ++ ++ rwnx_hw->plat->enabled = false; ++} ++ ++/** ++ * rwnx_platform_init() - Initialize the platform ++ * ++ * @rwnx_plat: platform data (already updated by platform driver) ++ * @platform_data: Pointer to store the main driver data pointer (aka rwnx_hw) ++ * That will be set as driver data for the platform driver ++ * Return: 0 on success, < 0 otherwise ++ * ++ * Called by the platform driver after it has been probed ++ */ ++int rwnx_platform_init(struct rwnx_plat *rwnx_plat, void **platform_data) ++{ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ rwnx_plat->enabled = false; ++ g_rwnx_plat = rwnx_plat; ++ ++#if defined CONFIG_RWNX_FULLMAC ++ return rwnx_cfg80211_init(rwnx_plat, platform_data); ++#elif defined CONFIG_RWNX_FHOST ++ return rwnx_fhost_init(rwnx_plat, platform_data); ++#endif ++} ++ ++/** ++ * rwnx_platform_deinit() - Deinitialize the platform ++ * ++ * @rwnx_hw: main driver data ++ * ++ * Called by the platform driver after it is removed ++ */ ++void rwnx_platform_deinit(struct rwnx_hw *rwnx_hw) ++{ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++#if defined CONFIG_RWNX_FULLMAC ++ rwnx_cfg80211_deinit(rwnx_hw); ++#elif defined CONFIG_RWNX_FHOST ++ rwnx_fhost_deinit(rwnx_hw); ++#endif ++} ++ ++/** ++ * rwnx_platform_register_drv() - Register all possible platform drivers ++ */ ++int rwnx_platform_register_drv(void) ++{ ++#ifdef AICWF_PCIE_SUPPORT ++ return rwnx_pci_register_drv(); ++#else ++ return 0; ++#endif ++} ++ ++/** ++ * rwnx_platform_unregister_drv() - Unegister all platform drivers ++ */ ++void rwnx_platform_unregister_drv(void) ++{ ++#ifdef AICWF_PCIE_SUPPORT ++ rwnx_pci_unregister_drv(); ++#endif ++} ++ ++struct device *rwnx_platform_get_dev(struct rwnx_plat *rwnx_plat) ++{ ++#ifdef AICWF_SDIO_SUPPORT ++ return rwnx_plat->sdiodev->dev; ++#endif ++#ifdef AICWF_USB_SUPPORT ++ return rwnx_plat->usbdev->dev; ++#endif ++ return &(rwnx_plat->pci_dev->dev); ++} ++ ++#ifndef CONFIG_RWNX_SDM ++MODULE_FIRMWARE(RWNX_AGC_FW_NAME); ++MODULE_FIRMWARE(RWNX_FCU_FW_NAME); ++MODULE_FIRMWARE(RWNX_LDPC_RAM_NAME); ++#endif ++MODULE_FIRMWARE(RWNX_MAC_FW_NAME); ++#ifndef CONFIG_RWNX_TL4 ++MODULE_FIRMWARE(RWNX_MAC_FW_NAME2); ++#endif +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_platform.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_platform.h +new file mode 100755 +index 000000000..f9412fcbc +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_platform.h +@@ -0,0 +1,160 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_platorm.h ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++#ifndef _RWNX_PLATFORM_H_ ++#define _RWNX_PLATFORM_H_ ++ ++#include ++#include "lmac_msg.h" ++ ++#define RWNX_CONFIG_FW_NAME "rwnx_settings.ini" ++#define RWNX_PHY_CONFIG_TRD_NAME "rwnx_trident.ini" ++#define RWNX_PHY_CONFIG_KARST_NAME "rwnx_karst.ini" ++#define RWNX_AGC_FW_NAME "agcram.bin" ++#define RWNX_LDPC_RAM_NAME "ldpcram.bin" ++#ifdef CONFIG_RWNX_FULLMAC ++#define RWNX_MAC_FW_BASE_NAME "fmacfw" ++#elif defined CONFIG_RWNX_FHOST ++#define RWNX_MAC_FW_BASE_NAME "fhostfw" ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++#ifdef CONFIG_RWNX_TL4 ++#define RWNX_MAC_FW_NAME RWNX_MAC_FW_BASE_NAME ".hex" ++#else ++#define RWNX_MAC_FW_NAME RWNX_MAC_FW_BASE_NAME ".ihex" ++#define RWNX_MAC_FW_NAME2 RWNX_MAC_FW_BASE_NAME ".bin" ++#endif ++ ++#define RWNX_FCU_FW_NAME "fcuram.bin" ++#if (defined(CONFIG_DPD) && !defined(CONFIG_FORCE_DPD_CALIB)) ++#define FW_DPDRESULT_NAME_8800DC "aic_dpdresult_lite_8800dc.bin" ++#endif ++ ++/** ++ * Type of memory to access (cf rwnx_plat.get_address) ++ * ++ * @RWNX_ADDR_CPU To access memory of the embedded CPU ++ * @RWNX_ADDR_SYSTEM To access memory/registers of one subsystem of the ++ * embedded system ++ * ++ */ ++enum rwnx_platform_addr { ++ RWNX_ADDR_CPU, ++ RWNX_ADDR_SYSTEM, ++ RWNX_ADDR_MAX, ++}; ++ ++#define POWER_LEVEL_INVALID_VAL (127) ++ ++typedef enum { ++ REGIONS_SRRC, ++ REGIONS_FCC, ++ REGIONS_ETSI, ++ REGIONS_JP, ++ REGIONS_DEFAULT, ++} Regions_code; ++ ++struct rwnx_hw; ++ ++/** ++ * struct rwnx_plat - Operation pointers for RWNX PCI platform ++ * ++ * @pci_dev: pointer to pci dev ++ * @enabled: Set if embedded platform has been enabled (i.e. fw loaded and ++ * ipc started) ++ * @enable: Configure communication with the fw (i.e. configure the transfers ++ * enable and register interrupt) ++ * @disable: Stop communication with the fw ++ * @deinit: Free all ressources allocated for the embedded platform ++ * @get_address: Return the virtual address to access the requested address on ++ * the platform. ++ * @ack_irq: Acknowledge the irq at link level. ++ * @get_config_reg: Return the list (size + pointer) of registers to restore in ++ * order to reload the platform while keeping the current configuration. ++ * ++ * @priv Private data for the link driver ++ */ ++struct rwnx_plat { ++ struct pci_dev *pci_dev; ++ ++#ifdef AICWF_SDIO_SUPPORT ++ struct aic_sdio_dev *sdiodev; ++#endif ++ ++#ifdef AICWF_USB_SUPPORT ++ struct aic_usb_dev *usbdev; ++#endif ++ bool enabled; ++ ++ int (*enable)(struct rwnx_hw *rwnx_hw); ++ int (*disable)(struct rwnx_hw *rwnx_hw); ++ void (*deinit)(struct rwnx_plat *rwnx_plat); ++ u8 *(*get_address)(struct rwnx_plat *rwnx_plat, int addr_name, ++ unsigned int offset); ++ void (*ack_irq)(struct rwnx_plat *rwnx_plat); ++ int (*get_config_reg)(struct rwnx_plat *rwnx_plat, const u32 **list); ++ ++ u8 priv[0] __aligned(sizeof(void *)); ++}; ++ ++#define RWNX_ADDR(plat, base, offset) plat->get_address(plat, base, offset) ++ ++#define RWNX_REG_READ(plat, base, offset) \ ++ readl(plat->get_address(plat, base, offset)) ++ ++#define RWNX_REG_WRITE(val, plat, base, offset) \ ++ writel(val, plat->get_address(plat, base, offset)) ++ ++extern struct rwnx_plat *g_rwnx_plat; ++ ++int rwnx_platform_init(struct rwnx_plat *rwnx_plat, void **platform_data); ++void rwnx_platform_deinit(struct rwnx_hw *rwnx_hw); ++ ++int rwnx_platform_on(struct rwnx_hw *rwnx_hw, void *config); ++void rwnx_platform_off(struct rwnx_hw *rwnx_hw, void **config); ++ ++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); ++void get_userconfig_xtal_cap(xtal_cap_conf_t *xtal_cap); ++s8_l get_txpwr_max(s8_l power); ++void set_txpwr_loss_ofst(s8_l value); ++ ++void get_userconfig_txpwr_lvl_in_fdrv(txpwr_lvl_conf_t *txpwr_lvl); ++void get_userconfig_txpwr_lvl_v2_in_fdrv(txpwr_lvl_conf_v2_t *txpwr_lvl_v2); ++void get_userconfig_txpwr_lvl_v3_in_fdrv(txpwr_lvl_conf_v3_t *txpwr_lvl_v3); ++void get_userconfig_txpwr_lvl_v4_in_fdrv(txpwr_lvl_conf_v4_t *txpwr_lvl_v4); ++void get_userconfig_txpwr_lvl_adj_in_fdrv(txpwr_lvl_adj_conf_t *txpwr_lvl_adj); ++uint8_t get_ccode_region(char *ccode); ++u8 get_region_index(char *name); ++ ++#ifdef CONFIG_POWER_LIMIT ++int8_t rwnx_plat_powerlimit_save(u8_l band, char *channel, u8_l bw, char *limit, ++ char *name); ++void rwnx_plat_powerlimit_parsing(char *buffer, int size, char *cc); ++int8_t get_powerlimit_by_freq(uint8_t band, uint16_t freq, uint8_t r_idx); ++int8_t get_powerlimit_by_chnum(uint8_t chnum, uint8_t r_idx, uint8_t bw); ++#endif ++ ++void get_userconfig_txpwr_ofst_in_fdrv(txpwr_ofst_conf_t *txpwr_ofst); ++void get_userconfig_txpwr_ofst2x_in_fdrv(txpwr_ofst2x_conf_t *txpwr_ofst2x); ++void get_userconfig_txpwr_ofst2x_v2_in_fdrv( ++ txpwr_ofst2x_conf_v2_t *txpwr_ofst2x_v2); ++void get_userconfig_txpwr_loss(txpwr_loss_conf_t *txpwr_loss); ++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) ++{ ++ return rwnx_plat->pci_dev->irq; ++} ++ ++#endif /* _RWNX_PLATFORM_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_prof.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_prof.h +new file mode 100755 +index 000000000..3ff82e43b +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_prof.h +@@ -0,0 +1,148 @@ ++/** ++ **************************************************************************************** ++ * ++ * @file rwnx_prof.h ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ **************************************************************************************** ++ */ ++ ++#ifndef _RWNX_PROF_H_ ++#define _RWNX_PROF_H_ ++ ++#include "reg_access.h" ++#include "rwnx_platform.h" ++ ++static inline void rwnx_prof_set(struct rwnx_hw *rwnx_hw, int val) ++{ ++ struct rwnx_plat *rwnx_plat = rwnx_hw->plat; ++ RWNX_REG_WRITE(val, rwnx_plat, RWNX_ADDR_SYSTEM, ++ NXMAC_SW_SET_PROFILING_ADDR); ++} ++ ++static inline void rwnx_prof_clear(struct rwnx_hw *rwnx_hw, int val) ++{ ++ struct rwnx_plat *rwnx_plat = rwnx_hw->plat; ++ RWNX_REG_WRITE(val, rwnx_plat, RWNX_ADDR_SYSTEM, ++ NXMAC_SW_CLEAR_PROFILING_ADDR); ++} ++ ++#if 0 ++/* Defines for SW Profiling registers values */ ++enum { ++ TX_IPC_IRQ, ++ TX_IPC_EVT, ++ TX_PREP_EVT, ++ TX_DMA_IRQ, ++ TX_MAC_IRQ, ++ TX_PAYL_HDL, ++ TX_CFM_EVT, ++ TX_IPC_CFM, ++ RX_MAC_IRQ, // 8 ++ RX_TRIGGER_EVT, ++ RX_DMA_IRQ, ++ RX_DMA_EVT, ++ RX_IPC_IND, ++ RX_MPDU_XFER, ++ DBG_PROF_MAX ++}; ++#endif ++ ++enum { ++ SW_PROF_HOSTBUF_IDX = 12, ++ /****** IPC IRQs related signals ******/ ++ /* E2A direction */ ++ SW_PROF_IRQ_E2A_RXDESC = ++ 16, // to make sure we let 16 bits available for LMAC FW ++ SW_PROF_IRQ_E2A_TXCFM, ++ SW_PROF_IRQ_E2A_DBG, ++ SW_PROF_IRQ_E2A_MSG, ++ SW_PROF_IPC_MSGPUSH, ++ SW_PROF_MSGALLOC, ++ SW_PROF_MSGIND, ++ SW_PROF_DBGIND, ++ ++ /* A2E direction */ ++ SW_PROF_IRQ_A2E_TXCFM_BACK, ++ ++ /****** Driver functions related signals ******/ ++ SW_PROF_WAIT_QUEUE_STOP, ++ SW_PROF_WAIT_QUEUE_WAKEUP, ++ SW_PROF_RWNXDATAIND, ++ SW_PROF_RWNX_IPC_IRQ_HDLR, ++ SW_PROF_RWNX_IPC_THR_IRQ_HDLR, ++ SW_PROF_IEEE80211RX, ++ SW_PROF_RWNX_PATTERN, ++ SW_PROF_MAX ++}; ++ ++// [LT]For debug purpose only ++#if (0) ++#define SW_PROF_CHAN_CTXT_CFM_HDL_BIT (21) ++#define SW_PROF_CHAN_CTXT_CFM_BIT (22) ++#define SW_PROF_CHAN_CTXT_CFM_SWDONE_BIT (23) ++#define SW_PROF_CHAN_CTXT_PUSH_BIT (24) ++#define SW_PROF_CHAN_CTXT_QUEUE_BIT (25) ++#define SW_PROF_CHAN_CTXT_TX_BIT (26) ++#define SW_PROF_CHAN_CTXT_TX_PAUSE_BIT (27) ++#define SW_PROF_CHAN_CTXT_PSWTCH_BIT (28) ++#define SW_PROF_CHAN_CTXT_SWTCH_BIT (29) ++ ++// TO DO: update this ++ ++#define REG_SW_SET_PROFILING_CHAN(env, bit) \ ++ rwnx_prof_set((struct rwnx_hw *)env, BIT(bit)) ++ ++#define REG_SW_CLEAR_PROFILING_CHAN(env, bit) \ ++ rwnx_prof_clear((struct rwnx_hw *)env, BIT(bit)) ++ ++#else ++#define SW_PROF_CHAN_CTXT_CFM_HDL_BIT (0) ++#define SW_PROF_CHAN_CTXT_CFM_BIT (0) ++#define SW_PROF_CHAN_CTXT_CFM_SWDONE_BIT (0) ++#define SW_PROF_CHAN_CTXT_PUSH_BIT (0) ++#define SW_PROF_CHAN_CTXT_QUEUE_BIT (0) ++#define SW_PROF_CHAN_CTXT_TX_BIT (0) ++#define SW_PROF_CHAN_CTXT_TX_PAUSE_BIT (0) ++#define SW_PROF_CHAN_CTXT_PSWTCH_BIT (0) ++#define SW_PROF_CHAN_CTXT_SWTCH_BIT (0) ++ ++#define REG_SW_SET_PROFILING_CHAN(env, bit) \ ++ do { \ ++ } while (0) ++#define REG_SW_CLEAR_PROFILING_CHAN(env, bit) \ ++ do { \ ++ } while (0) ++#endif ++ ++#ifdef CONFIG_RWNX_SW_PROFILING ++/* Macros for SW PRofiling registers access */ ++#define REG_SW_SET_PROFILING(env, bit) \ ++ rwnx_prof_set((struct rwnx_hw *)env, BIT(bit)) ++ ++#define REG_SW_SET_HOSTBUF_IDX_PROFILING(env, val) \ ++ rwnx_prof_set((struct rwnx_hw *)env, val << (SW_PROF_HOSTBUF_IDX)) ++ ++#define REG_SW_CLEAR_PROFILING(env, bit) \ ++ rwnx_prof_clear((struct rwnx_hw *)env, BIT(bit)) ++ ++#define REG_SW_CLEAR_HOSTBUF_IDX_PROFILING(env) \ ++ rwnx_prof_clear((struct rwnx_hw *)env, 0x0F << (SW_PROF_HOSTBUF_IDX)) ++ ++#else ++#define REG_SW_SET_PROFILING(env, value) \ ++ do { \ ++ } while (0) ++#define REG_SW_CLEAR_PROFILING(env, value) \ ++ do { \ ++ } while (0) ++#define REG_SW_SET_HOSTBUF_IDX_PROFILING(env, val) \ ++ do { \ ++ } while (0) ++#define REG_SW_CLEAR_HOSTBUF_IDX_PROFILING(env) \ ++ do { \ ++ } while (0) ++#endif ++ ++#endif /* _RWNX_PROF_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_radar.c b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_radar.c +new file mode 100755 +index 000000000..d0b982f27 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_radar.c +@@ -0,0 +1,1644 @@ ++/** ++****************************************************************************** ++ * ++ * @file rwnx_radar.c ++ * ++ * @brief Functions to handle radar detection ++ * Radar detection is copied (and adapted) from ath driver source code. ++ * ++ * Copyright (c) 2012 Neratec Solutions AG ++ * Copyright (C) RivieraWaves 2015-2019 ++ * ++ ****************************************************************************** ++ */ ++#include ++#include ++#include ++#include ++ ++#include "rwnx_radar.h" ++#include "rwnx_defs.h" ++#include "rwnx_msg_tx.h" ++#include "rwnx_events.h" ++#include "rwnx_compat.h" ++ ++/* ++ * tolerated deviation of radar time stamp in usecs on both sides ++ * TODO: this might need to be HW-dependent ++ */ ++#define PRI_TOLERANCE 16 ++ ++/** ++ * struct radar_types - contains array of patterns defined for one DFS domain ++ * @domain: DFS regulatory domain ++ * @num_radar_types: number of radar types to follow ++ * @radar_types: radar types array ++ */ ++struct radar_types { ++ enum nl80211_dfs_regions region; ++ u32 num_radar_types; ++ const struct radar_detector_specs *spec_riu; ++ const struct radar_detector_specs *spec_fcu; ++}; ++ ++/** ++ * Type of radar waveform: ++ * RADAR_WAVEFORM_SHORT : waveform defined by ++ * - pulse width ++ * - pulse interval in a burst (pri) ++ * - number of pulses in a burst (ppb) ++ * ++ * RADAR_WAVEFORM_WEATHER : ++ * same than SHORT except that ppb is dependent of pri ++ * ++ * RADAR_WAVEFORM_INTERLEAVED : ++ * same than SHORT except there are several value of pri (interleaved) ++ * ++ * RADAR_WAVEFORM_LONG : ++ * ++ */ ++enum radar_waveform_type { ++ RADAR_WAVEFORM_SHORT, ++ RADAR_WAVEFORM_WEATHER, ++ RADAR_WAVEFORM_INTERLEAVED, ++ RADAR_WAVEFORM_LONG ++}; ++ ++/** ++ * struct radar_detector_specs - detector specs for a radar pattern type ++ * @type_id: pattern type, as defined by regulatory ++ * @width_min: minimum radar pulse width in [us] ++ * @width_max: maximum radar pulse width in [us] ++ * @pri_min: minimum pulse repetition interval in [us] (including tolerance) ++ * @pri_max: minimum pri in [us] (including tolerance) ++ * @num_pri: maximum number of different pri for this type ++ * @ppb: pulses per bursts for this type ++ * @ppb_thresh: number of pulses required to trigger detection ++ * @max_pri_tolerance: pulse time stamp tolerance on both sides [us] ++ * @type: Type of radar waveform ++ */ ++struct radar_detector_specs { ++ u8 type_id; ++ u8 width_min; ++ u8 width_max; ++ u16 pri_min; ++ u16 pri_max; ++ u8 num_pri; ++ u8 ppb; ++ u8 ppb_thresh; ++ u8 max_pri_tolerance; ++ enum radar_waveform_type type; ++}; ++ ++/* percentage on ppb threshold to trigger detection */ ++#define MIN_PPB_THRESH 50 ++#define PPB_THRESH(PPB) ((PPB * MIN_PPB_THRESH + 50) / 100) ++#define PRF2PRI(PRF) ((1000000 + PRF / 2) / PRF) ++ ++/* width tolerance */ ++#define WIDTH_TOLERANCE 2 ++#define WIDTH_LOWER(X) (X) ++#define WIDTH_UPPER(X) (X) ++ ++#define ETSI_PATTERN_SHORT(ID, WMIN, WMAX, PMIN, PMAX, PPB) \ ++ { \ ++ ID, WIDTH_LOWER(WMIN), WIDTH_UPPER(WMAX), \ ++ (PRF2PRI(PMAX) - PRI_TOLERANCE), \ ++ (PRF2PRI(PMIN) + PRI_TOLERANCE), 1, PPB, \ ++ PPB_THRESH(PPB), PRI_TOLERANCE, RADAR_WAVEFORM_SHORT \ ++ } ++ ++#define ETSI_PATTERN_INTERLEAVED(ID, WMIN, WMAX, PMIN, PMAX, PRFMIN, PRFMAX, \ ++ PPB) \ ++ { \ ++ ID, WIDTH_LOWER(WMIN), WIDTH_UPPER(WMAX), \ ++ (PRF2PRI(PMAX) * PRFMIN - PRI_TOLERANCE), \ ++ (PRF2PRI(PMIN) * PRFMAX + PRI_TOLERANCE), PRFMAX, \ ++ PPB *PRFMAX, PPB_THRESH(PPB), PRI_TOLERANCE, \ ++ RADAR_WAVEFORM_INTERLEAVED \ ++ } ++ ++/* radar types as defined by ETSI EN-301-893 v1.7.1 */ ++static const struct radar_detector_specs etsi_radar_ref_types_v17_riu[] = { ++ ETSI_PATTERN_SHORT(0, 0, 8, 700, 700, 18), ++ ETSI_PATTERN_SHORT(1, 0, 10, 200, 1000, 10), ++ ETSI_PATTERN_SHORT(2, 0, 22, 200, 1600, 15), ++ ETSI_PATTERN_SHORT(3, 0, 22, 2300, 4000, 25), ++ ETSI_PATTERN_SHORT(4, 20, 38, 2000, 4000, 20), ++ ETSI_PATTERN_INTERLEAVED(5, 0, 8, 300, 400, 2, 3, 10), ++ ETSI_PATTERN_INTERLEAVED(6, 0, 8, 400, 1200, 2, 3, 15), ++}; ++ ++static const struct radar_detector_specs etsi_radar_ref_types_v17_fcu[] = { ++ ETSI_PATTERN_SHORT(0, 0, 8, 700, 700, 18), ++ ETSI_PATTERN_SHORT(1, 0, 8, 200, 1000, 10), ++ ETSI_PATTERN_SHORT(2, 0, 16, 200, 1600, 15), ++ ETSI_PATTERN_SHORT(3, 0, 16, 2300, 4000, 25), ++ ETSI_PATTERN_SHORT(4, 20, 34, 2000, 4000, 20), ++ ETSI_PATTERN_INTERLEAVED(5, 0, 8, 300, 400, 2, 3, 10), ++ ETSI_PATTERN_INTERLEAVED(6, 0, 8, 400, 1200, 2, 3, 15), ++}; ++ ++static const struct radar_types etsi_radar_types_v17 = { ++ .region = NL80211_DFS_ETSI, ++ .num_radar_types = ARRAY_SIZE(etsi_radar_ref_types_v17_riu), ++ .spec_riu = etsi_radar_ref_types_v17_riu, ++ .spec_fcu = etsi_radar_ref_types_v17_fcu, ++}; ++ ++#define FCC_PATTERN(ID, WMIN, WMAX, PMIN, PMAX, PRF, PPB, TYPE) \ ++ { \ ++ ID, WIDTH_LOWER(WMIN), WIDTH_UPPER(WMAX), \ ++ PMIN - PRI_TOLERANCE, PMAX *PRF + PRI_TOLERANCE, PRF, \ ++ PPB *PRF, PPB_THRESH(PPB), PRI_TOLERANCE, TYPE \ ++ } ++ ++static const struct radar_detector_specs fcc_radar_ref_types_riu[] = { ++ FCC_PATTERN(0, 0, 8, 1428, 1428, 1, 18, RADAR_WAVEFORM_SHORT), ++ FCC_PATTERN(1, 0, 8, 518, 3066, 1, 102, RADAR_WAVEFORM_WEATHER), ++ FCC_PATTERN(2, 0, 8, 150, 230, 1, 23, RADAR_WAVEFORM_SHORT), ++ FCC_PATTERN(3, 6, 20, 200, 500, 1, 16, RADAR_WAVEFORM_SHORT), ++ FCC_PATTERN(4, 10, 28, 200, 500, 1, 12, RADAR_WAVEFORM_SHORT), ++ FCC_PATTERN(5, 50, 110, 1000, 2000, 1, 8, RADAR_WAVEFORM_LONG), ++ FCC_PATTERN(6, 0, 8, 333, 333, 1, 9, RADAR_WAVEFORM_SHORT), ++}; ++ ++static const struct radar_detector_specs fcc_radar_ref_types_fcu[] = { ++ FCC_PATTERN(0, 0, 8, 1428, 1428, 1, 18, RADAR_WAVEFORM_SHORT), ++ FCC_PATTERN(1, 0, 8, 518, 3066, 1, 102, RADAR_WAVEFORM_WEATHER), ++ FCC_PATTERN(2, 0, 8, 150, 230, 1, 23, RADAR_WAVEFORM_SHORT), ++ FCC_PATTERN(3, 6, 12, 200, 500, 1, 16, RADAR_WAVEFORM_SHORT), ++ FCC_PATTERN(4, 10, 22, 200, 500, 1, 12, RADAR_WAVEFORM_SHORT), ++ FCC_PATTERN(5, 50, 104, 1000, 2000, 1, 8, RADAR_WAVEFORM_LONG), ++ FCC_PATTERN(6, 0, 8, 333, 333, 1, 9, RADAR_WAVEFORM_SHORT), ++}; ++ ++static const struct radar_types fcc_radar_types = { ++ .region = NL80211_DFS_FCC, ++ .num_radar_types = ARRAY_SIZE(fcc_radar_ref_types_riu), ++ .spec_riu = fcc_radar_ref_types_riu, ++ .spec_fcu = fcc_radar_ref_types_fcu, ++}; ++ ++#define JP_PATTERN FCC_PATTERN ++static const struct radar_detector_specs jp_radar_ref_types_riu[] = { ++ JP_PATTERN(0, 0, 8, 1428, 1428, 1, 18, RADAR_WAVEFORM_SHORT), ++ JP_PATTERN(1, 2, 8, 3846, 3846, 1, 18, RADAR_WAVEFORM_SHORT), ++ JP_PATTERN(2, 0, 8, 1388, 1388, 1, 18, RADAR_WAVEFORM_SHORT), ++ JP_PATTERN(3, 0, 8, 4000, 4000, 1, 18, RADAR_WAVEFORM_SHORT), ++ JP_PATTERN(4, 0, 8, 150, 230, 1, 23, RADAR_WAVEFORM_SHORT), ++ JP_PATTERN(5, 6, 20, 200, 500, 1, 16, RADAR_WAVEFORM_SHORT), ++ JP_PATTERN(6, 10, 28, 200, 500, 1, 12, RADAR_WAVEFORM_SHORT), ++ JP_PATTERN(7, 50, 110, 1000, 2000, 1, 8, RADAR_WAVEFORM_LONG), ++ JP_PATTERN(8, 0, 8, 333, 333, 1, 9, RADAR_WAVEFORM_SHORT), ++}; ++ ++static const struct radar_detector_specs jp_radar_ref_types_fcu[] = { ++ JP_PATTERN(0, 0, 8, 1428, 1428, 1, 18, RADAR_WAVEFORM_SHORT), ++ JP_PATTERN(1, 2, 6, 3846, 3846, 1, 18, RADAR_WAVEFORM_SHORT), ++ JP_PATTERN(2, 0, 8, 1388, 1388, 1, 18, RADAR_WAVEFORM_SHORT), ++ JP_PATTERN(3, 2, 2, 4000, 4000, 1, 18, RADAR_WAVEFORM_SHORT), ++ JP_PATTERN(4, 0, 8, 150, 230, 1, 23, RADAR_WAVEFORM_SHORT), ++ JP_PATTERN(5, 6, 12, 200, 500, 1, 16, RADAR_WAVEFORM_SHORT), ++ JP_PATTERN(6, 10, 22, 200, 500, 1, 12, RADAR_WAVEFORM_SHORT), ++ JP_PATTERN(7, 50, 104, 1000, 2000, 1, 8, RADAR_WAVEFORM_LONG), ++ JP_PATTERN(8, 0, 8, 333, 333, 1, 9, RADAR_WAVEFORM_SHORT), ++}; ++ ++static const struct radar_types jp_radar_types = { ++ .region = NL80211_DFS_JP, ++ .num_radar_types = ARRAY_SIZE(jp_radar_ref_types_riu), ++ .spec_riu = jp_radar_ref_types_riu, ++ .spec_fcu = jp_radar_ref_types_fcu, ++}; ++ ++static const struct radar_types *dfs_domains[] = { ++ &etsi_radar_types_v17, ++ &fcc_radar_types, ++ &jp_radar_types, ++}; ++ ++/** ++ * struct pri_sequence - sequence of pulses matching one PRI ++ * @head: list_head ++ * @pri: pulse repetition interval (PRI) in usecs ++ * @dur: duration of sequence in usecs ++ * @count: number of pulses in this sequence ++ * @count_falses: number of not matching pulses in this sequence ++ * @first_ts: time stamp of first pulse in usecs ++ * @last_ts: time stamp of last pulse in usecs ++ * @deadline_ts: deadline when this sequence becomes invalid (first_ts + dur) ++ * @ppb_thresh: Number of pulses to validate detection ++ * (need for weather radar whose value depends of pri) ++ */ ++struct pri_sequence { ++ struct list_head head; ++ u32 pri; ++ u32 dur; ++ u32 count; ++ u32 count_falses; ++ u64 first_ts; ++ u64 last_ts; ++ u64 deadline_ts; ++ u8 ppb_thresh; ++}; ++ ++/** ++ * struct pulse_elem - elements in pulse queue ++ * @ts: time stamp in usecs ++ */ ++struct pulse_elem { ++ struct list_head head; ++ u64 ts; ++}; ++ ++/** ++ * struct pri_detector - PRI detector element for a dedicated radar type ++ * @head: ++ * @rs: detector specs for this detector element ++ * @last_ts: last pulse time stamp considered for this element in usecs ++ * @sequences: list_head holding potential pulse sequences ++ * @pulses: list connecting pulse_elem objects ++ * @count: number of pulses in queue ++ * @max_count: maximum number of pulses to be queued ++ * @window_size: window size back from newest pulse time stamp in usecs ++ * @freq: ++ */ ++struct pri_detector { ++ struct list_head head; ++ const struct radar_detector_specs *rs; ++ u64 last_ts; ++ struct list_head sequences; ++ struct list_head pulses; ++ u32 count; ++ u32 max_count; ++ u32 window_size; ++ struct pri_detector_ops *ops; ++ u16 freq; ++}; ++ ++/** ++ * struct pri_detector_ops - PRI detector ops (dependent of waveform type) ++ * @init : Initialize pri_detector structure ++ * @add_pulse : Add a pulse to the pri-detector ++ * @reset_on_pri_overflow : Should the pri_detector be resetted when pri overflow ++ */ ++struct pri_detector_ops { ++ void (*init)(struct pri_detector *pde); ++ struct pri_sequence *(*add_pulse)(struct pri_detector *pde, u16 len, ++ u64 ts, u16 pri); ++ int reset_on_pri_overflow; ++}; ++ ++/****************************************************************************** ++ * PRI (pulse repetition interval) sequence detection ++ *****************************************************************************/ ++/** ++ * Singleton Pulse and Sequence Pools ++ * ++ * Instances of pri_sequence and pulse_elem are kept in singleton pools to ++ * reduce the number of dynamic allocations. They are shared between all ++ * instances and grow up to the peak number of simultaneously used objects. ++ * ++ * Memory is freed after all references to the pools are released. ++ */ ++static u32 singleton_pool_references; ++static LIST_HEAD(pulse_pool); ++static LIST_HEAD(pseq_pool); ++static DEFINE_SPINLOCK(pool_lock); ++ ++static void pool_register_ref(void) ++{ ++ spin_lock_bh(&pool_lock); ++ singleton_pool_references++; ++ spin_unlock_bh(&pool_lock); ++} ++ ++static void pool_deregister_ref(void) ++{ ++ spin_lock_bh(&pool_lock); ++ singleton_pool_references--; ++ if (singleton_pool_references == 0) { ++ /* free singleton pools with no references left */ ++ struct pri_sequence *ps, *ps0; ++ struct pulse_elem *p, *p0; ++ ++ list_for_each_entry_safe (p, p0, &pulse_pool, head) { ++ list_del(&p->head); ++ kfree(p); ++ } ++ list_for_each_entry_safe (ps, ps0, &pseq_pool, head) { ++ list_del(&ps->head); ++ kfree(ps); ++ } ++ } ++ spin_unlock_bh(&pool_lock); ++} ++ ++static void pool_put_pulse_elem(struct pulse_elem *pe) ++{ ++ spin_lock_bh(&pool_lock); ++ list_add(&pe->head, &pulse_pool); ++ spin_unlock_bh(&pool_lock); ++} ++ ++static void pool_put_pseq_elem(struct pri_sequence *pse) ++{ ++ spin_lock_bh(&pool_lock); ++ list_add(&pse->head, &pseq_pool); ++ spin_unlock_bh(&pool_lock); ++} ++ ++static struct pri_sequence *pool_get_pseq_elem(void) ++{ ++ struct pri_sequence *pse = NULL; ++ spin_lock_bh(&pool_lock); ++ if (!list_empty(&pseq_pool)) { ++ pse = list_first_entry(&pseq_pool, struct pri_sequence, head); ++ list_del(&pse->head); ++ } ++ spin_unlock_bh(&pool_lock); ++ ++ if (pse == NULL) { ++ pse = kmalloc(sizeof(*pse), GFP_ATOMIC); ++ } ++ ++ return pse; ++} ++ ++static struct pulse_elem *pool_get_pulse_elem(void) ++{ ++ struct pulse_elem *pe = NULL; ++ spin_lock_bh(&pool_lock); ++ if (!list_empty(&pulse_pool)) { ++ pe = list_first_entry(&pulse_pool, struct pulse_elem, head); ++ list_del(&pe->head); ++ } ++ spin_unlock_bh(&pool_lock); ++ return pe; ++} ++ ++static struct pulse_elem *pulse_queue_get_tail(struct pri_detector *pde) ++{ ++ struct list_head *l = &pde->pulses; ++ if (list_empty(l)) ++ return NULL; ++ return list_entry(l->prev, struct pulse_elem, head); ++} ++ ++static bool pulse_queue_dequeue(struct pri_detector *pde) ++{ ++ struct pulse_elem *p = pulse_queue_get_tail(pde); ++ if (p != NULL) { ++ list_del_init(&p->head); ++ pde->count--; ++ /* give it back to pool */ ++ pool_put_pulse_elem(p); ++ } ++ return (pde->count > 0); ++} ++ ++/** ++ * pulse_queue_check_window - remove pulses older than window ++ * @pde: pointer on pri_detector ++ * ++ * dequeue pulse that are too old. ++ */ ++static void pulse_queue_check_window(struct pri_detector *pde) ++{ ++ u64 min_valid_ts; ++ struct pulse_elem *p; ++ ++ /* there is no delta time with less than 2 pulses */ ++ if (pde->count < 2) ++ return; ++ ++ if (pde->last_ts <= pde->window_size) ++ return; ++ ++ min_valid_ts = pde->last_ts - pde->window_size; ++ while ((p = pulse_queue_get_tail(pde)) != NULL) { ++ if (p->ts >= min_valid_ts) ++ return; ++ pulse_queue_dequeue(pde); ++ } ++} ++ ++/** ++ * pulse_queue_enqueue - Queue one pulse ++ * @pde: pointer on pri_detector ++ * ++ * Add one pulse to the list. If the maximum number of pulses ++ * if reached, remove oldest one. ++ */ ++static bool pulse_queue_enqueue(struct pri_detector *pde, u64 ts) ++{ ++ struct pulse_elem *p = pool_get_pulse_elem(); ++ if (p == NULL) { ++ p = kmalloc(sizeof(*p), GFP_ATOMIC); ++ if (p == NULL) { ++ return false; ++ } ++ } ++ INIT_LIST_HEAD(&p->head); ++ p->ts = ts; ++ list_add(&p->head, &pde->pulses); ++ pde->count++; ++ pde->last_ts = ts; ++ pulse_queue_check_window(pde); ++ if (pde->count >= pde->max_count) ++ pulse_queue_dequeue(pde); ++ ++ return true; ++} ++ ++/*************************************************************************** ++ * Short waveform ++ **************************************************************************/ ++/** ++ * pde_get_multiple() - get number of multiples considering a given tolerance ++ * @return factor if abs(val - factor*fraction) <= tolerance, 0 otherwise ++ */ ++static u32 pde_get_multiple(u32 val, u32 fraction, u32 tolerance) ++{ ++ u32 remainder; ++ u32 factor; ++ u32 delta; ++ ++ if (fraction == 0) ++ return 0; ++ ++ delta = (val < fraction) ? (fraction - val) : (val - fraction); ++ ++ if (delta <= tolerance) ++ /* val and fraction are within tolerance */ ++ return 1; ++ ++ factor = val / fraction; ++ remainder = val % fraction; ++ if (remainder > tolerance) { ++ /* no exact match */ ++ if ((fraction - remainder) <= tolerance) ++ /* remainder is within tolerance */ ++ factor++; ++ else ++ factor = 0; ++ } ++ return factor; ++} ++ ++/** ++ * pde_short_create_sequences - create_sequences function for ++ * SHORT/WEATHER/INTERLEAVED radar waveform ++ * @pde: pointer on pri_detector ++ * @ts: timestamp of the pulse ++ * @min_count: Minimum number of pulse to be present in the sequence. ++ * (With this pulse there is already a sequence with @min_count ++ * pulse, so if we can't create a sequence with more pulse don't ++ * create it) ++ * @return: false if an error occured (memory allocation) true otherwise ++ * ++ * For each pulses queued check if we can create a sequence with ++ * pri = (ts - pulse_queued.ts) which contains more than @min_count pulses. ++ * ++ */ ++static bool pde_short_create_sequences(struct pri_detector *pde, u64 ts, ++ u32 min_count) ++{ ++ struct pulse_elem *p; ++ u16 pulse_idx = 0; ++ ++ list_for_each_entry (p, &pde->pulses, head) { ++ struct pri_sequence ps, *new_ps; ++ struct pulse_elem *p2; ++ u32 tmp_false_count; ++ u64 min_valid_ts; ++ u32 delta_ts = ts - p->ts; ++ pulse_idx++; ++ ++ if (delta_ts < pde->rs->pri_min) ++ /* ignore too small pri */ ++ continue; ++ ++ if (delta_ts > pde->rs->pri_max) ++ /* stop on too large pri (sorted list) */ ++ break; ++ ++ /* build a new sequence with new potential pri */ ++ ps.count = 2; ++ ps.count_falses = pulse_idx - 1; ++ ps.first_ts = p->ts; ++ ps.last_ts = ts; ++ ps.pri = ts - p->ts; ++ ps.dur = ps.pri * (pde->rs->ppb - 1) + ++ 2 * pde->rs->max_pri_tolerance; ++ ++ p2 = p; ++ tmp_false_count = 0; ++ if (ps.dur > ts) ++ min_valid_ts = 0; ++ else ++ min_valid_ts = ts - ps.dur; ++ /* check which past pulses are candidates for new sequence */ ++ list_for_each_entry_continue (p2, &pde->pulses, head) { ++ u32 factor; ++ if (p2->ts < min_valid_ts) ++ /* stop on crossing window border */ ++ break; ++ /* check if pulse match (multi)PRI */ ++ factor = pde_get_multiple(ps.last_ts - p2->ts, ps.pri, ++ pde->rs->max_pri_tolerance); ++ if (factor > 0) { ++ ps.count++; ++ ps.first_ts = p2->ts; ++ /* ++ * on match, add the intermediate falses ++ * and reset counter ++ */ ++ ps.count_falses += tmp_false_count; ++ tmp_false_count = 0; ++ } else { ++ /* this is a potential false one */ ++ tmp_false_count++; ++ } ++ } ++ if (ps.count <= min_count) { ++ /* did not reach minimum count, drop sequence */ ++ continue; ++ } ++ /* this is a valid one, add it */ ++ ps.deadline_ts = ps.first_ts + ps.dur; ++ if (pde->rs->type == RADAR_WAVEFORM_WEATHER) { ++ ps.ppb_thresh = 19000000 / (360 * ps.pri); ++ ps.ppb_thresh = PPB_THRESH(ps.ppb_thresh); ++ } else { ++ ps.ppb_thresh = pde->rs->ppb_thresh; ++ } ++ ++ new_ps = pool_get_pseq_elem(); ++ if (new_ps == NULL) { ++ return false; ++ } ++ memcpy(new_ps, &ps, sizeof(ps)); ++ INIT_LIST_HEAD(&new_ps->head); ++ list_add(&new_ps->head, &pde->sequences); ++ } ++ return true; ++} ++ ++/** ++ * pde_short_add_to_existing_seqs - add_to_existing_seqs function for ++ * SHORT/WEATHER/INTERLEAVED radar waveform ++ * @pde: pointer on pri_detector ++ * @ts: timestamp of the pulse ++ * ++ * Check all sequemces created for this pde. ++ * - If the sequence is too old delete it. ++ * - Else if the delta with the previous pulse match the pri of the sequence ++ * add the pulse to this sequence. If the pulse cannot be added it is added ++ * to the false pulses for this sequence ++ * ++ * @return the length of the longest sequence in which the pulse has been added ++ */ ++static u32 pde_short_add_to_existing_seqs(struct pri_detector *pde, u64 ts) ++{ ++ u32 max_count = 0; ++ struct pri_sequence *ps, *ps2; ++ list_for_each_entry_safe (ps, ps2, &pde->sequences, head) { ++ u32 delta_ts; ++ u32 factor; ++ ++ /* first ensure that sequence is within window */ ++ if (ts > ps->deadline_ts) { ++ list_del_init(&ps->head); ++ pool_put_pseq_elem(ps); ++ continue; ++ } ++ ++ delta_ts = ts - ps->last_ts; ++ factor = pde_get_multiple(delta_ts, ps->pri, ++ pde->rs->max_pri_tolerance); ++ ++ if (factor > 0) { ++ ps->last_ts = ts; ++ ps->count++; ++ ++ if (max_count < ps->count) ++ max_count = ps->count; ++ } else { ++ ps->count_falses++; ++ } ++ } ++ return max_count; ++} ++ ++/** ++ * pde_short_check_detection - check_detection function for ++ * SHORT/WEATHER/INTERLEAVED radar waveform ++ * @pde: pointer on pri_detector ++ * ++ * Check all sequemces created for this pde. ++ * - If a sequence contains more pulses than the threshold and more matching ++ * that false pulses. ++ * ++ * @return The first complete sequence, and NULL if no sequence is complete. ++ */ ++static struct pri_sequence *pde_short_check_detection(struct pri_detector *pde) ++{ ++ struct pri_sequence *ps; ++ ++ if (list_empty(&pde->sequences)) ++ return NULL; ++ ++ list_for_each_entry (ps, &pde->sequences, head) { ++ /* ++ * we assume to have enough matching confidence if we ++ * 1) have enough pulses ++ * 2) have more matching than false pulses ++ */ ++ if ((ps->count >= ps->ppb_thresh) && ++ (ps->count * pde->rs->num_pri > ps->count_falses)) { ++ return ps; ++ } ++ } ++ return NULL; ++} ++ ++/** ++ * pde_short_init - init function for ++ * SHORT/WEATHER/INTERLEAVED radar waveform ++ * @pde: pointer on pri_detector ++ * ++ * Initialize pri_detector window size to the maximun size of one burst ++ * for the radar specification associated. ++ */ ++static void pde_short_init(struct pri_detector *pde) ++{ ++ pde->window_size = pde->rs->pri_max * pde->rs->ppb * pde->rs->num_pri; ++ pde->max_count = pde->rs->ppb * 2; ++} ++ ++static void pri_detector_reset(struct pri_detector *pde, u64 ts); ++/** ++ * pde_short_add_pulse - Add pulse to a pri_detector for ++ * SHORT/WEATHER/INTERLEAVED radar waveform ++ * ++ * @pde : pointer on pri_detector ++ * @len : width of the pulse ++ * @ts : timestamp of the pulse received ++ * @pri : Delta in us with the previous pulse. ++ * (0 means that delta in bigger than 65535 us) ++ * ++ * Process on pulse within this pri_detector ++ * - First try to add it to existing sequence ++ * - Then try to create a new and longest sequence ++ * - Check if this pulse complete a sequence ++ * - If not save this pulse in the list ++ */ ++static struct pri_sequence *pde_short_add_pulse(struct pri_detector *pde, ++ u16 len, u64 ts, u16 pri) ++{ ++ u32 max_updated_seq; ++ struct pri_sequence *ps; ++ const struct radar_detector_specs *rs = pde->rs; ++ ++ if (pde->count == 0) { ++ /* This is the first pulse after reset, no need to check sequences */ ++ pulse_queue_enqueue(pde, ts); ++ return NULL; ++ } ++ ++ if ((ts - pde->last_ts) < rs->max_pri_tolerance) { ++ /* if delta to last pulse is too short, don't use this pulse */ ++ return NULL; ++ } ++ ++ max_updated_seq = pde_short_add_to_existing_seqs(pde, ts); ++ ++ if (!pde_short_create_sequences(pde, ts, max_updated_seq)) { ++ pri_detector_reset(pde, ts); ++ return NULL; ++ } ++ ++ ps = pde_short_check_detection(pde); ++ ++ if (ps == NULL) ++ pulse_queue_enqueue(pde, ts); ++ ++ return ps; ++} ++ ++/** ++ * pri detector ops to detect short radar waveform ++ * A Short waveform is defined by : ++ * The width of pulses. ++ * The interval between two pulses inside a burst (called pri) ++ * (some waveform may have or 2/3 interleaved pri) ++ * The number of pulses per burst (ppb) ++ */ ++static struct pri_detector_ops pri_detector_short = { ++ .init = pde_short_init, ++ .add_pulse = pde_short_add_pulse, ++ .reset_on_pri_overflow = 1, ++}; ++ ++/*************************************************************************** ++ * Long waveform ++ **************************************************************************/ ++#define LONG_RADAR_DURATION 12000000 ++#define LONG_RADAR_BURST_MIN_DURATION (12000000 / 20) ++#define LONG_RADAR_MAX_BURST 20 ++ ++/** ++ * pde_long_init - init function for LONG radar waveform ++ * @pde: pointer on pri_detector ++ * ++ * Initialize pri_detector window size to the long waveform radar ++ * waveform (ie. 12s) and max_count ++ */ ++static void pde_long_init(struct pri_detector *pde) ++{ ++ pde->window_size = LONG_RADAR_DURATION; ++ pde->max_count = LONG_RADAR_MAX_BURST; /* only count burst not pulses */ ++} ++ ++/** ++ * pde_long_add_pulse - Add pulse to a pri_detector for ++ * LONG radar waveform ++ * ++ * @pde : pointer on pri_detector ++ * @len : width of the pulse ++ * @ts : timestamp of the pulse received ++ * @pri : Delta in us with the previous pulse. ++ * ++ * ++ * For long pulse we only handle one sequence. Since each burst ++ * have a different set of parameters (number of pulse, pri) than ++ * the previous one we only use pulse width to add the pulse in the ++ * sequence. ++ * We only queue one pulse per burst and valid the radar when enough burst ++ * has been detected. ++ */ ++static struct pri_sequence *pde_long_add_pulse(struct pri_detector *pde, ++ u16 len, u64 ts, u16 pri) ++{ ++ struct pri_sequence *ps; ++ const struct radar_detector_specs *rs = pde->rs; ++ ++ if (list_empty(&pde->sequences)) { ++ /* First pulse, create a new sequence */ ++ ps = pool_get_pseq_elem(); ++ if (ps == NULL) { ++ return NULL; ++ } ++ ++ /*For long waveform, "count" represents the number of burst detected */ ++ ps->count = 1; ++ /*"count_false" represents the number of pulse in the current burst */ ++ ps->count_falses = 1; ++ ps->first_ts = ts; ++ ps->last_ts = ts; ++ ps->deadline_ts = ts + pde->window_size; ++ ps->pri = 0; ++ INIT_LIST_HEAD(&ps->head); ++ list_add(&ps->head, &pde->sequences); ++ pulse_queue_enqueue(pde, ts); ++ } else { ++ u32 delta_ts; ++ ++ ps = (struct pri_sequence *)pde->sequences.next; ++ ++ delta_ts = ts - ps->last_ts; ++ ps->last_ts = ts; ++ ++ if (delta_ts < rs->pri_max) { ++ /* ignore pulse too close from previous one */ ++ } else if ((delta_ts >= rs->pri_min) && ++ (delta_ts <= rs->pri_max)) { ++ /* this is a new pulse in the current burst, ignore it ++ (i.e don't queue it) */ ++ ps->count_falses++; ++ } else if ((ps->count > 2) && ++ (ps->dur + delta_ts) < ++ LONG_RADAR_BURST_MIN_DURATION) { ++ /* not enough time between burst, ignore pulse */ ++ } else { ++ /* a new burst */ ++ ps->count++; ++ ps->count_falses = 1; ++ ++ /* reset the start of the sequence if deadline reached */ ++ if (ts > ps->deadline_ts) { ++ struct pulse_elem *p; ++ u64 min_valid_ts; ++ ++ min_valid_ts = ts - pde->window_size; ++ while ((p = pulse_queue_get_tail(pde)) != ++ NULL) { ++ if (p->ts >= min_valid_ts) { ++ ps->first_ts = p->ts; ++ ps->deadline_ts = ++ p->ts + ++ pde->window_size; ++ break; ++ } ++ pulse_queue_dequeue(pde); ++ ps->count--; ++ } ++ } ++ ++ /* valid radar if enough burst detected and delta with first burst ++ is at least duration/2 */ ++ if (ps->count > pde->rs->ppb_thresh && ++ (ts - ps->first_ts) > (pde->window_size / 2)) { ++ return ps; ++ } else { ++ pulse_queue_enqueue(pde, ts); ++ ps->dur = delta_ts; ++ } ++ } ++ } ++ ++ return NULL; ++} ++ ++/** ++ * pri detector ops to detect long radar waveform ++ */ ++static struct pri_detector_ops pri_detector_long = { ++ .init = pde_long_init, ++ .add_pulse = pde_long_add_pulse, ++ .reset_on_pri_overflow = 0, ++}; ++ ++/*************************************************************************** ++ * PRI detector init/reset/exit/get ++ **************************************************************************/ ++/** ++ * pri_detector_init- Create a new pri_detector ++ * ++ * @dpd: dfs_pattern_detector instance pointer ++ * @radar_type: index of radar pattern ++ * @freq: Frequency of the pri detector ++ */ ++struct pri_detector *pri_detector_init(struct dfs_pattern_detector *dpd, ++ u16 radar_type, u16 freq) ++{ ++ struct pri_detector *pde; ++ ++ pde = kzalloc(sizeof(*pde), GFP_ATOMIC); ++ if (pde == NULL) ++ return NULL; ++ ++ INIT_LIST_HEAD(&pde->sequences); ++ INIT_LIST_HEAD(&pde->pulses); ++ INIT_LIST_HEAD(&pde->head); ++ list_add(&pde->head, &dpd->detectors[radar_type]); ++ ++ pde->rs = &dpd->radar_spec[radar_type]; ++ pde->freq = freq; ++ ++ if (pde->rs->type == RADAR_WAVEFORM_LONG) { ++ /* for LONG WAVEFORM */ ++ pde->ops = &pri_detector_long; ++ } else { ++ /* for SHORT, WEATHER and INTERLEAVED */ ++ pde->ops = &pri_detector_short; ++ } ++ ++ /* Init dependent of specs */ ++ pde->ops->init(pde); ++ ++ pool_register_ref(); ++ return pde; ++} ++ ++/** ++ * pri_detector_reset - Reset pri_detector ++ * ++ * @pde: pointer on pri_detector ++ * @ts: New ts reference for the pri_detector ++ * ++ * free pulse queue and sequences list and give objects back to pools ++ */ ++static void pri_detector_reset(struct pri_detector *pde, u64 ts) ++{ ++ struct pri_sequence *ps, *ps0; ++ struct pulse_elem *p, *p0; ++ list_for_each_entry_safe (ps, ps0, &pde->sequences, head) { ++ list_del_init(&ps->head); ++ pool_put_pseq_elem(ps); ++ } ++ list_for_each_entry_safe (p, p0, &pde->pulses, head) { ++ list_del_init(&p->head); ++ pool_put_pulse_elem(p); ++ } ++ pde->count = 0; ++ pde->last_ts = ts; ++} ++ ++/** ++ * pri_detector_exit - Delete pri_detector ++ * ++ * @pde: pointer on pri_detector ++ */ ++static void pri_detector_exit(struct pri_detector *pde) ++{ ++ pri_detector_reset(pde, 0); ++ pool_deregister_ref(); ++ list_del(&pde->head); ++ kfree(pde); ++} ++ ++/** ++ * pri_detector_get() - get pri detector for a given frequency and type ++ * @dpd: dfs_pattern_detector instance pointer ++ * @freq: frequency in MHz ++ * @radar_type: index of radar pattern ++ * @return pointer to pri detector on success, NULL otherwise ++ * ++ * Return existing pri detector for the given frequency or return a ++ * newly create one. ++ * Pri detector are "merged" by frequency so that if a pri detector for a freq ++ * of +/- 2Mhz already exists don't create a new one. ++ * ++ * Maybe will need to adapt frequency merge for pattern with chirp. ++ */ ++static struct pri_detector *pri_detector_get(struct dfs_pattern_detector *dpd, ++ u16 freq, u16 radar_type) ++{ ++ struct pri_detector *pde, *cur = NULL; ++ list_for_each_entry (pde, &dpd->detectors[radar_type], head) { ++ if (pde->freq == freq) { ++ if (pde->count) ++ return pde; ++ else ++ cur = pde; ++ } else if (pde->freq - 2 == freq && pde->count) { ++ return pde; ++ } else if (pde->freq + 2 == freq && pde->count) { ++ return pde; ++ } ++ } ++ ++ if (cur) ++ return cur; ++ else ++ return pri_detector_init(dpd, radar_type, freq); ++} ++ ++/****************************************************************************** ++ * DFS Pattern Detector ++ *****************************************************************************/ ++/** ++ * dfs_pattern_detector_reset() - reset all channel detectors ++ * ++ * @dpd: dfs_pattern_detector ++ */ ++static void dfs_pattern_detector_reset(struct dfs_pattern_detector *dpd) ++{ ++ struct pri_detector *pde; ++ int i; ++ ++ for (i = 0; i < dpd->num_radar_types; i++) { ++ if (!list_empty(&dpd->detectors[i])) ++ list_for_each_entry (pde, &dpd->detectors[i], head) ++ pri_detector_reset(pde, dpd->last_pulse_ts); ++ } ++ ++ dpd->last_pulse_ts = 0; ++ dpd->prev_jiffies = jiffies; ++} ++ ++/** ++ * dfs_pattern_detector_reset() - delete all channel detectors ++ * ++ * @dpd: dfs_pattern_detector ++ */ ++static void dfs_pattern_detector_exit(struct dfs_pattern_detector *dpd) ++{ ++ struct pri_detector *pde, *pde0; ++ int i; ++ ++ for (i = 0; i < dpd->num_radar_types; i++) { ++ if (!list_empty(&dpd->detectors[i])) ++ list_for_each_entry_safe (pde, pde0, &dpd->detectors[i], ++ head) ++ pri_detector_exit(pde); ++ } ++ ++ kfree(dpd); ++} ++ ++/** ++ * dfs_pattern_detector_pri_overflow - reset all channel detectors on pri ++ * overflow ++ * @dpd: dfs_pattern_detector ++ */ ++static void dfs_pattern_detector_pri_overflow(struct dfs_pattern_detector *dpd) ++{ ++ struct pri_detector *pde; ++ int i; ++ ++ for (i = 0; i < dpd->num_radar_types; i++) { ++ if (!list_empty(&dpd->detectors[i])) ++ list_for_each_entry (pde, &dpd->detectors[i], head) ++ if (pde->ops->reset_on_pri_overflow) ++ pri_detector_reset(pde, ++ dpd->last_pulse_ts); ++ } ++} ++ ++/** ++ * dfs_pattern_detector_add_pulse - Process one pulse ++ * ++ * @dpd: dfs_pattern_detector ++ * @chain: Chain that correspond to this pattern_detector (only for debug) ++ * @freq: frequency of the pulse ++ * @pri: Delta with previous pulse. (0 if delta is too big for u16) ++ * @len: width of the pulse ++ * @now: jiffies value when pulse was received ++ * ++ * Get (or create) the channel_detector for this frequency. Then add the pulse ++ * in each pri_detector created in this channel_detector. ++ * ++ * ++ * @return True is the pulse complete a radar pattern, false otherwise ++ */ ++static bool dfs_pattern_detector_add_pulse(struct dfs_pattern_detector *dpd, ++ enum rwnx_radar_chain chain, ++ u16 freq, u16 pri, u16 len, u32 now) ++{ ++ u32 i; ++ ++ /* ++ * pulses received for a non-supported or un-initialized ++ * domain are treated as detected radars for fail-safety ++ */ ++ if (dpd->region == NL80211_DFS_UNSET) ++ return true; ++ ++ /* Compute pulse time stamp */ ++ if (pri == 0) { ++ u32 delta_jiffie; ++ if (unlikely(now < dpd->prev_jiffies)) { ++ delta_jiffie = 0xffffffff - dpd->prev_jiffies + now; ++ } else { ++ delta_jiffie = now - dpd->prev_jiffies; ++ } ++ dpd->last_pulse_ts += jiffies_to_usecs(delta_jiffie); ++ dpd->prev_jiffies = now; ++ dfs_pattern_detector_pri_overflow(dpd); ++ } else { ++ dpd->last_pulse_ts += pri; ++ } ++ ++ for (i = 0; i < dpd->num_radar_types; i++) { ++ struct pri_sequence *ps; ++ struct pri_detector *pde; ++ const struct radar_detector_specs *rs = &dpd->radar_spec[i]; ++ ++ /* no need to look up for pde if len is not within range */ ++ if ((rs->width_min > len) || (rs->width_max < len)) { ++ continue; ++ } ++ ++ pde = pri_detector_get(dpd, freq, i); ++ 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; ++ } ++ } ++ ++ return false; ++} ++ ++/** ++ * get_dfs_domain_radar_types() - get radar types for a given DFS domain ++ * @param domain DFS domain ++ * @return radar_types ptr on success, NULL if DFS domain is not supported ++ */ ++static const struct radar_types * ++get_dfs_domain_radar_types(enum nl80211_dfs_regions region) ++{ ++ u32 i; ++ for (i = 0; i < ARRAY_SIZE(dfs_domains); i++) { ++ if (dfs_domains[i]->region == region) ++ return dfs_domains[i]; ++ } ++ return NULL; ++} ++ ++/** ++ * get_dfs_max_radar_types() - get maximum radar types for all supported domain ++ * @return the maximum number of radar pattern supported by on region ++ */ ++static u16 get_dfs_max_radar_types(void) ++{ ++ u32 i; ++ u16 max = 0; ++ for (i = 0; i < ARRAY_SIZE(dfs_domains); i++) { ++ if (dfs_domains[i]->num_radar_types > max) ++ max = dfs_domains[i]->num_radar_types; ++ } ++ return max; ++} ++ ++/** ++ * dfs_pattern_detector_set_domain - set DFS domain ++ * ++ * @dpd: dfs_pattern_detector ++ * @region: DFS region ++ * ++ * set DFS domain, resets detector lines upon domain changes ++ */ ++static bool dfs_pattern_detector_set_domain(struct dfs_pattern_detector *dpd, ++ enum nl80211_dfs_regions region, ++ u8 chain) ++{ ++ const struct radar_types *rt; ++ struct pri_detector *pde, *pde0; ++ int i; ++ ++ if (dpd->region == region) ++ return true; ++ ++ dpd->region = NL80211_DFS_UNSET; ++ ++ rt = get_dfs_domain_radar_types(region); ++ if (rt == NULL) ++ return false; ++ ++ /* delete all pri detectors for previous DFS domain */ ++ for (i = 0; i < dpd->num_radar_types; i++) { ++ if (!list_empty(&dpd->detectors[i])) ++ list_for_each_entry_safe (pde, pde0, &dpd->detectors[i], ++ head) ++ pri_detector_exit(pde); ++ } ++ ++ if (chain == RWNX_RADAR_RIU) ++ dpd->radar_spec = rt->spec_riu; ++ else ++ dpd->radar_spec = rt->spec_fcu; ++ dpd->num_radar_types = rt->num_radar_types; ++ ++ dpd->region = region; ++ ++ AICWFDBG(LOGINFO, "set_region %d \n", region); ++ return true; ++} ++ ++/** ++ * dfs_pattern_detector_init - Initialize dfs_pattern_detector ++ * ++ * @region: DFS region ++ * @return: pointer on dfs_pattern_detector ++ * ++ */ ++static struct dfs_pattern_detector * ++dfs_pattern_detector_init(enum nl80211_dfs_regions region, u8 chain) ++{ ++ struct dfs_pattern_detector *dpd; ++ u16 i, max_radar_type = get_dfs_max_radar_types(); ++ ++ dpd = kmalloc(sizeof(*dpd) + max_radar_type * sizeof(dpd->detectors[0]), ++ GFP_KERNEL); ++ if (dpd == NULL) ++ return NULL; ++ ++ dpd->region = NL80211_DFS_UNSET; ++ dpd->enabled = RWNX_RADAR_DETECT_DISABLE; ++ dpd->last_pulse_ts = 0; ++ dpd->prev_jiffies = jiffies; ++ dpd->num_radar_types = 0; ++ for (i = 0; i < max_radar_type; i++) ++ INIT_LIST_HEAD(&dpd->detectors[i]); ++ ++ if (dfs_pattern_detector_set_domain(dpd, region, chain)) ++ return dpd; ++ ++ kfree(dpd); ++ return NULL; ++} ++ ++/****************************************************************************** ++ * driver interface ++ *****************************************************************************/ ++static u16 rwnx_radar_get_center_freq(struct rwnx_hw *rwnx_hw, u8 chain) ++{ ++ if (chain == RWNX_RADAR_FCU) ++ return rwnx_hw->phy.sec_chan.center_freq1; ++ ++ if (chain == RWNX_RADAR_RIU) { ++#ifdef CONFIG_RWNX_FULLMAC ++ if (!rwnx_chanctx_valid(rwnx_hw, rwnx_hw->cur_chanctx)) { ++ WARN(1, "Radar pulse without channel information"); ++ } else ++ return rwnx_hw->chanctx_table[rwnx_hw->cur_chanctx] ++ .chan_def.center_freq1; ++#endif /* CONFIG_RWNX_FULLMAC */ ++ } ++ ++ return 0; ++} ++ ++static void rwnx_radar_detected(struct rwnx_hw *rwnx_hw) ++{ ++#ifdef CONFIG_RWNX_FULLMAC ++ struct cfg80211_chan_def chan_def; ++ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++ ++ if (!rwnx_chanctx_valid(rwnx_hw, rwnx_hw->cur_chanctx)) { ++ WARN(1, "Radar detected without channel information"); ++ return; ++ } ++ ++ /* ++ recopy chan_def in local variable because rwnx_radar_cancel_cac may ++ clean the variable (if in CAC and it's the only vif using this context) ++ and CAC should be aborted before reporting the radar. ++ */ ++ chan_def = rwnx_hw->chanctx_table[rwnx_hw->cur_chanctx].chan_def; ++ ++ rwnx_radar_cancel_cac(&rwnx_hw->radar); ++ cfg80211_radar_event(rwnx_hw->wiphy, &chan_def, GFP_KERNEL); ++ ++#endif /* CONFIG_RWNX_FULLMAC */ ++} ++ ++static void rwnx_radar_process_pulse(struct work_struct *ws) ++{ ++ struct rwnx_radar *radar = ++ container_of(ws, struct rwnx_radar, detection_work); ++ struct rwnx_hw *rwnx_hw = container_of(radar, struct rwnx_hw, radar); ++ int chain; ++ u32 pulses[RWNX_RADAR_LAST][RWNX_RADAR_PULSE_MAX]; ++ u16 pulses_count[RWNX_RADAR_LAST]; ++ u32 now = ++ jiffies; /* would be better to store jiffies value in IT handler */ ++ ++ /* recopy pulses locally to avoid too long spin_lock */ ++ spin_lock_bh(&radar->lock); ++ for (chain = RWNX_RADAR_RIU; chain < RWNX_RADAR_LAST; chain++) { ++ int start, count; ++ ++ count = radar->pulses[chain].count; ++ start = radar->pulses[chain].index - count; ++ if (start < 0) ++ start += RWNX_RADAR_PULSE_MAX; ++ ++ pulses_count[chain] = count; ++ if (count == 0) ++ continue; ++ ++ if ((start + count) > RWNX_RADAR_PULSE_MAX) { ++ u16 count1 = (RWNX_RADAR_PULSE_MAX - start); ++ memcpy(&(pulses[chain][0]), ++ &(radar->pulses[chain].buffer[start]), ++ count1 * sizeof(struct radar_pulse)); ++ memcpy(&(pulses[chain][count1]), ++ &(radar->pulses[chain].buffer[0]), ++ (count - count1) * sizeof(struct radar_pulse)); ++ } else { ++ memcpy(&(pulses[chain][0]), ++ &(radar->pulses[chain].buffer[start]), ++ count * sizeof(struct radar_pulse)); ++ } ++ radar->pulses[chain].count = 0; ++ } ++ spin_unlock_bh(&radar->lock); ++ ++ /* now process pulses */ ++ for (chain = RWNX_RADAR_RIU; chain < RWNX_RADAR_LAST; chain++) { ++ int i; ++ u16 freq; ++ ++ if (pulses_count[chain] == 0) ++ continue; ++ ++ freq = rwnx_radar_get_center_freq(rwnx_hw, chain); ++ ++ 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)) { ++ u16 idx = radar->detected[chain].index; ++ ++ if (chain == RWNX_RADAR_RIU) { ++ /* operating chain, inform upper layer to change channel */ ++ if (radar->dpd[chain]->enabled == ++ RWNX_RADAR_DETECT_REPORT) { ++ rwnx_radar_detected(rwnx_hw); ++ /* no need to report new radar until upper layer set a ++ new channel. This prevent warning if a new radar is ++ detected while mac80211 is changing channel */ ++ rwnx_radar_detection_enable( ++ radar, ++ RWNX_RADAR_DETECT_DISABLE, ++ chain); ++ /* purge any event received since the beginning of the ++ function (we are sure not to interfer with tasklet ++ as we disable detection just before) */ ++ radar->pulses[chain].count = 0; ++ } ++ } else { ++ /* secondary radar detection chain, simply report info in ++ debugfs for now */ ++ } ++ ++ radar->detected[chain].freq[idx] = ++ (s16)freq + (2 * p->freq); ++ radar->detected[chain].time[idx] = ++ ktime_get_real_seconds(); ++ radar->detected[chain].index = ++ ((idx + 1) % NX_NB_RADAR_DETECTED); ++ radar->detected[chain].count++; ++ /* no need to process next pulses for this chain */ ++ break; ++ } ++ } ++ } ++} ++ ++#ifdef CONFIG_RWNX_FULLMAC ++static void rwnx_radar_cac_work(struct work_struct *ws) ++{ ++ struct delayed_work *dw = container_of(ws, struct delayed_work, work); ++ struct rwnx_radar *radar = ++ container_of(dw, struct rwnx_radar, cac_work); ++ struct rwnx_hw *rwnx_hw = container_of(radar, struct rwnx_hw, radar); ++ struct rwnx_chanctx *ctxt; ++ ++ if (radar->cac_vif == NULL) { ++ WARN(1, "CAC finished but no vif set"); ++ return; ++ } ++ ++ ctxt = &rwnx_hw->chanctx_table[radar->cac_vif->ch_index]; ++ /* flare-edge (6.18 port): cfg80211_cac_event() gained a trailing ++ * unsigned int link_id (0 for non-MLO, per its doc comment). */ ++ cfg80211_cac_event(radar->cac_vif->ndev, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) ++ &ctxt->chan_def, ++#endif ++ NL80211_RADAR_CAC_FINISHED, GFP_KERNEL, 0); ++ rwnx_send_apm_stop_cac_req(rwnx_hw, radar->cac_vif); ++ rwnx_chanctx_unlink(radar->cac_vif); ++ ++ radar->cac_vif = NULL; ++} ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++bool rwnx_radar_detection_init(struct rwnx_radar *radar) ++{ ++ spin_lock_init(&radar->lock); ++ ++ radar->dpd[RWNX_RADAR_RIU] = ++ dfs_pattern_detector_init(NL80211_DFS_UNSET, RWNX_RADAR_RIU); ++ if (radar->dpd[RWNX_RADAR_RIU] == NULL) ++ return false; ++ ++ radar->dpd[RWNX_RADAR_FCU] = ++ dfs_pattern_detector_init(NL80211_DFS_UNSET, RWNX_RADAR_FCU); ++ if (radar->dpd[RWNX_RADAR_FCU] == NULL) { ++ rwnx_radar_detection_deinit(radar); ++ return false; ++ } ++ ++ INIT_WORK(&radar->detection_work, rwnx_radar_process_pulse); ++#ifdef CONFIG_RWNX_FULLMAC ++ INIT_DELAYED_WORK(&radar->cac_work, rwnx_radar_cac_work); ++ radar->cac_vif = NULL; ++#endif /* CONFIG_RWNX_FULLMAC */ ++ return true; ++} ++ ++void rwnx_radar_detection_deinit(struct rwnx_radar *radar) ++{ ++ if (radar->dpd[RWNX_RADAR_RIU]) { ++ dfs_pattern_detector_exit(radar->dpd[RWNX_RADAR_RIU]); ++ radar->dpd[RWNX_RADAR_RIU] = NULL; ++ } ++ if (radar->dpd[RWNX_RADAR_FCU]) { ++ dfs_pattern_detector_exit(radar->dpd[RWNX_RADAR_FCU]); ++ radar->dpd[RWNX_RADAR_FCU] = NULL; ++ } ++} ++ ++bool rwnx_radar_set_domain(struct rwnx_radar *radar, ++ enum nl80211_dfs_regions region) ++{ ++ 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], ++ region, RWNX_RADAR_FCU)); ++} ++ ++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); ++ } ++} ++ ++bool rwnx_radar_detection_is_enable(struct rwnx_radar *radar, u8 chain) ++{ ++ return radar->dpd[chain]->enabled != RWNX_RADAR_DETECT_DISABLE; ++} ++ ++#ifdef CONFIG_RWNX_FULLMAC ++void rwnx_radar_start_cac(struct rwnx_radar *radar, u32 cac_time_ms, ++ struct rwnx_vif *vif) ++{ ++ WARN(radar->cac_vif != NULL, "CAC already in progress"); ++ radar->cac_vif = vif; ++ schedule_delayed_work(&radar->cac_work, msecs_to_jiffies(cac_time_ms)); ++} ++ ++void rwnx_radar_cancel_cac(struct rwnx_radar *radar) ++{ ++ struct rwnx_hw *rwnx_hw = container_of(radar, struct rwnx_hw, radar); ++ ++ if (radar->cac_vif == NULL) { ++ return; ++ } ++ ++ if (cancel_delayed_work(&radar->cac_work)) { ++ struct rwnx_chanctx *ctxt; ++ ctxt = &rwnx_hw->chanctx_table[radar->cac_vif->ch_index]; ++ rwnx_send_apm_stop_cac_req(rwnx_hw, radar->cac_vif); ++ cfg80211_cac_event(radar->cac_vif->ndev, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) ++ &ctxt->chan_def, ++#endif ++ NL80211_RADAR_CAC_ABORTED, GFP_KERNEL, 0); ++ rwnx_chanctx_unlink(radar->cac_vif); ++ } ++ ++ radar->cac_vif = NULL; ++} ++ ++void rwnx_radar_detection_enable_on_cur_channel(struct rwnx_hw *rwnx_hw) ++{ ++ struct rwnx_chanctx *ctxt; ++ ++ /* If no information on current channel do nothing */ ++ if (!rwnx_chanctx_valid(rwnx_hw, rwnx_hw->cur_chanctx)) ++ return; ++ ++ ctxt = &rwnx_hw->chanctx_table[rwnx_hw->cur_chanctx]; ++ if (ctxt->chan_def.chan->flags & IEEE80211_CHAN_RADAR) { ++ rwnx_radar_detection_enable(&rwnx_hw->radar, ++ RWNX_RADAR_DETECT_REPORT, ++ RWNX_RADAR_RIU); ++ } else { ++ rwnx_radar_detection_enable(&rwnx_hw->radar, ++ RWNX_RADAR_DETECT_DISABLE, ++ RWNX_RADAR_RIU); ++ } ++} ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++/***************************************************************************** ++ * Debug functions ++ *****************************************************************************/ ++static int rwnx_radar_dump_pri_detector(char *buf, size_t len, ++ struct pri_detector *pde) ++{ ++ char freq_info[] = "Freq = %3.dMhz\n"; ++ char seq_info[] = " pri | count | false \n"; ++ struct pri_sequence *seq; ++ int res, write = 0; ++ ++ if (list_empty(&pde->sequences)) { ++ return 0; ++ } ++ ++ if (buf == NULL) { ++ int nb_seq = 1; ++ list_for_each_entry (seq, &pde->sequences, head) { ++ nb_seq++; ++ } ++ ++ return (sizeof(freq_info) + nb_seq * sizeof(seq_info)); ++ } ++ ++ res = scnprintf(buf, len, freq_info, pde->freq); ++ write += res; ++ len -= res; ++ ++ res = scnprintf(&buf[write], len, "%s", seq_info); ++ write += res; ++ len -= res; ++ ++ list_for_each_entry (seq, &pde->sequences, head) { ++ res = scnprintf(&buf[write], len, ++ " %6.d | %2.d | %.2d \n", seq->pri, ++ seq->count, seq->count_falses); ++ write += res; ++ len -= res; ++ } ++ ++ return write; ++} ++ ++int rwnx_radar_dump_pattern_detector(char *buf, size_t len, ++ struct rwnx_radar *radar, u8 chain) ++{ ++ struct dfs_pattern_detector *dpd = radar->dpd[chain]; ++ char info[] = "Type = %3.d\n"; ++ struct pri_detector *pde; ++ int i, res, write = 0; ++ ++ /* if buf is NULL return size needed for dump */ ++ if (buf == NULL) { ++ int size_needed = 0; ++ ++ for (i = 0; i < dpd->num_radar_types; i++) { ++ list_for_each_entry (pde, &dpd->detectors[i], head) { ++ size_needed += rwnx_radar_dump_pri_detector( ++ NULL, 0, pde); ++ } ++ size_needed += sizeof(info); ++ ++ return size_needed; ++ } ++ } ++ ++ /* */ ++ for (i = 0; i < dpd->num_radar_types; i++) { ++ res = scnprintf(&buf[write], len, info, i); ++ ++ write += res; ++ len -= res; ++ list_for_each_entry (pde, &dpd->detectors[i], head) { ++ res = rwnx_radar_dump_pri_detector(&buf[write], len, ++ pde); ++ write += res; ++ len -= res; ++ } ++ } ++ ++ return write; ++} ++ ++int rwnx_radar_dump_radar_detected(char *buf, size_t len, ++ struct rwnx_radar *radar, u8 chain) ++{ ++ struct rwnx_radar_detected *detect = &(radar->detected[chain]); ++ char info[] = "2001/02/02 - 02:20 5126MHz\n"; ++ int idx, i, res, write = 0; ++ int count = detect->count; ++ ++ if (count > NX_NB_RADAR_DETECTED) ++ count = NX_NB_RADAR_DETECTED; ++ ++ if (buf == NULL) { ++ return (count * sizeof(info)) + 1; ++ } ++ ++ idx = (detect->index - detect->count) % NX_NB_RADAR_DETECTED; ++ ++ for (i = 0; i < count; i++) { ++ struct tm tm; ++ time64_to_tm(detect->time[idx], 0, &tm); ++ ++ res = scnprintf(&buf[write], len, ++ "%.4d/%.2d/%.2d - %.2d:%.2d %4.4dMHz\n", ++ (int)tm.tm_year + 1900, tm.tm_mon + 1, ++ tm.tm_mday, tm.tm_hour, tm.tm_min, ++ detect->freq[idx]); ++ write += res; ++ len -= res; ++ ++ idx = (idx + 1) % NX_NB_RADAR_DETECTED; ++ } ++ ++ return write; ++} +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_radar.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_radar.h +new file mode 100755 +index 000000000..13632af52 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_radar.h +@@ -0,0 +1,170 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_radar.h ++ * ++ * @brief Functions to handle radar detection ++ * ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ ****************************************************************************** ++ */ ++#ifndef _RWNX_RADAR_H_ ++#define _RWNX_RADAR_H_ ++ ++#include ++ ++struct rwnx_vif; ++struct rwnx_hw; ++ ++enum rwnx_radar_chain { RWNX_RADAR_RIU = 0, RWNX_RADAR_FCU, RWNX_RADAR_LAST }; ++ ++enum rwnx_radar_detector { ++ RWNX_RADAR_DETECT_DISABLE = 0, /* Ignore radar pulses */ ++ RWNX_RADAR_DETECT_ENABLE = 1, /* Process pattern detection but do not ++ report radar to upper layer (for test) */ ++ RWNX_RADAR_DETECT_REPORT = 2 /* Process pattern detection and report ++ radar to upper layer. */ ++}; ++ ++#ifdef CONFIG_RWNX_RADAR ++#include ++#include ++ ++#define RWNX_RADAR_PULSE_MAX 32 ++ ++/** ++ * struct rwnx_radar_pulses - List of pulses reported by HW ++ * @index: write index ++ * @count: number of valid pulses ++ * @buffer: buffer of pulses ++ */ ++struct rwnx_radar_pulses { ++ /* Last radar pulses received */ ++ int index; ++ int count; ++ u32 buffer[RWNX_RADAR_PULSE_MAX]; ++}; ++ ++/** ++ * struct dfs_pattern_detector - DFS pattern detector ++ * @region: active DFS region, NL80211_DFS_UNSET until set ++ * @num_radar_types: number of different radar types ++ * @last_pulse_ts: time stamp of last valid pulse in usecs ++ * @prev_jiffies: ++ * @radar_detector_specs: array of radar detection specs ++ * @channel_detectors: list connecting channel_detector elements ++ */ ++struct dfs_pattern_detector { ++ u8 enabled; ++ enum nl80211_dfs_regions region; ++ u8 num_radar_types; ++ u64 last_pulse_ts; ++ u32 prev_jiffies; ++ const struct radar_detector_specs *radar_spec; ++ struct list_head detectors[]; ++}; ++ ++#define NX_NB_RADAR_DETECTED 4 ++ ++/** ++ * struct rwnx_radar_detected - List of radar detected ++ */ ++struct rwnx_radar_detected { ++ u16 index; ++ u16 count; ++ s64 time[NX_NB_RADAR_DETECTED]; ++ s16 freq[NX_NB_RADAR_DETECTED]; ++}; ++ ++struct rwnx_radar { ++ struct rwnx_radar_pulses pulses[RWNX_RADAR_LAST]; ++ struct dfs_pattern_detector *dpd[RWNX_RADAR_LAST]; ++ struct rwnx_radar_detected detected[RWNX_RADAR_LAST]; ++ struct work_struct detection_work; /* Work used to process radar pulses */ ++ spinlock_t lock; /* lock for pulses processing */ ++ ++ /* In softmac cac is handled by mac80211 */ ++#ifdef CONFIG_RWNX_FULLMAC ++ struct delayed_work cac_work; /* Work used to handle CAC */ ++ struct rwnx_vif *cac_vif; /* vif on which we started CAC */ ++#endif ++}; ++ ++bool rwnx_radar_detection_init(struct rwnx_radar *radar); ++void rwnx_radar_detection_deinit(struct rwnx_radar *radar); ++bool rwnx_radar_set_domain(struct rwnx_radar *radar, ++ enum nl80211_dfs_regions region); ++void rwnx_radar_detection_enable(struct rwnx_radar *radar, u8 enable, u8 chain); ++bool rwnx_radar_detection_is_enable(struct rwnx_radar *radar, u8 chain); ++void rwnx_radar_start_cac(struct rwnx_radar *radar, u32 cac_time_ms, ++ struct rwnx_vif *vif); ++void rwnx_radar_cancel_cac(struct rwnx_radar *radar); ++void rwnx_radar_detection_enable_on_cur_channel(struct rwnx_hw *rwnx_hw); ++int rwnx_radar_dump_pattern_detector(char *buf, size_t len, ++ struct rwnx_radar *radar, u8 chain); ++int rwnx_radar_dump_radar_detected(char *buf, size_t len, ++ struct rwnx_radar *radar, u8 chain); ++ ++#else ++ ++struct rwnx_radar {}; ++ ++static inline bool rwnx_radar_detection_init(struct rwnx_radar *radar) ++{ ++ return true; ++} ++ ++static inline void rwnx_radar_detection_deinit(struct rwnx_radar *radar) ++{ ++} ++ ++static inline bool rwnx_radar_set_domain(struct rwnx_radar *radar, ++ enum nl80211_dfs_regions region) ++{ ++ return true; ++} ++ ++static inline void rwnx_radar_detection_enable(struct rwnx_radar *radar, ++ u8 enable, u8 chain) ++{ ++} ++ ++static inline bool rwnx_radar_detection_is_enable(struct rwnx_radar *radar, ++ u8 chain) ++{ ++ return false; ++} ++ ++static inline void rwnx_radar_start_cac(struct rwnx_radar *radar, ++ u32 cac_time_ms, struct rwnx_vif *vif) ++{ ++} ++ ++static inline void rwnx_radar_cancel_cac(struct rwnx_radar *radar) ++{ ++} ++ ++static inline void ++rwnx_radar_detection_enable_on_cur_channel(struct rwnx_hw *rwnx_hw) ++{ ++} ++ ++static inline int rwnx_radar_dump_pattern_detector(char *buf, size_t len, ++ struct rwnx_radar *radar, ++ u8 chain) ++{ ++ return 0; ++} ++ ++static inline int rwnx_radar_dump_radar_detected(char *buf, size_t len, ++ struct rwnx_radar *radar, ++ u8 chain) ++{ ++ return 0; ++} ++ ++#endif /* CONFIG_RWNX_RADAR */ ++ ++#endif // _RWNX_RADAR_H_ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_rx.c b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_rx.c +new file mode 100755 +index 000000000..21782fdac +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_rx.c +@@ -0,0 +1,2806 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_rx.c ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ ****************************************************************************** ++ */ ++#include ++#include ++#include ++#include ++ ++#include "rwnx_defs.h" ++#include "rwnx_rx.h" ++#include "rwnx_tx.h" ++#include "rwnx_prof.h" ++#include "ipc_host.h" ++#include "rwnx_events.h" ++#include "rwnx_compat.h" ++#include "aicwf_txrxif.h" ++#ifdef AICWF_ARP_OFFLOAD ++#include ++#include ++#include "rwnx_msg_tx.h" ++#endif ++ ++#ifndef IEEE80211_MAX_CHAINS ++#define IEEE80211_MAX_CHAINS 4 ++#endif ++ ++u8 dhcped; // = 0; ++ ++u16 tx_legrates_lut_rate[] = { 10, 20, 55, 110, 60, 90, ++ 120, 180, 240, 360, 480, 540 }; ++ ++struct rwnx_legrate legrates_lut[] = { ++ [0] = { .idx = 0, .rate = 10 }, [1] = { .idx = 1, .rate = 20 }, ++ [2] = { .idx = 2, .rate = 55 }, [3] = { .idx = 3, .rate = 110 }, ++ [4] = { .idx = -1, .rate = 0 }, [5] = { .idx = -1, .rate = 0 }, ++ [6] = { .idx = -1, .rate = 0 }, [7] = { .idx = -1, .rate = 0 }, ++ [8] = { .idx = 10, .rate = 480 }, [9] = { .idx = 8, .rate = 240 }, ++ [10] = { .idx = 6, .rate = 120 }, [11] = { .idx = 4, .rate = 60 }, ++ [12] = { .idx = 11, .rate = 540 }, [13] = { .idx = 9, .rate = 360 }, ++ [14] = { .idx = 7, .rate = 180 }, [15] = { .idx = 5, .rate = 90 }, ++}; ++ ++struct vendor_radiotap_hdr { ++ u8 oui[3]; ++ u8 subns; ++ u16 len; ++ u8 data[]; ++}; ++ ++/** ++ * rwnx_rx_get_vif - Return pointer to the destination vif ++ * ++ * @rwnx_hw: main driver data ++ * @vif_idx: vif index present in rx descriptor ++ * ++ * Select the vif that should receive this frame. Returns NULL if the destination ++ * vif is not active or vif is not specified in the descriptor. ++ */ ++static inline struct rwnx_vif *rwnx_rx_get_vif(struct rwnx_hw *rwnx_hw, ++ int vif_idx) ++{ ++ struct rwnx_vif *rwnx_vif = NULL; ++ ++ if (vif_idx < NX_VIRT_DEV_MAX) { ++ rwnx_vif = rwnx_hw->vif_table[vif_idx]; ++ ++ if (!rwnx_vif) { ++ AICWFDBG(LOGERROR, "%s rwnx_hw->vif_table[%d] NULL\r\n", ++ __func__, vif_idx); ++ return NULL; ++ } else if (!rwnx_vif->up) { ++ AICWFDBG(LOGERROR, ++ "%s rwnx_hw->vif_table[%d] is down\r\n", ++ __func__, vif_idx); ++ return NULL; ++ } ++ } ++ ++ return rwnx_vif; ++} ++ ++/** ++ * rwnx_rx_vector_convert - Convert a legacy RX vector into a new RX vector format ++ * ++ * @rwnx_hw: main driver data. ++ * @rx_vect1: Rx vector 1 descriptor of the received frame. ++ * @rx_vect2: Rx vector 2 descriptor of the received frame. ++ */ ++static void rwnx_rx_vector_convert(struct rwnx_hw *rwnx_hw, ++ struct rx_vector_1 *rx_vect1, ++ struct rx_vector_2 *rx_vect2) ++{ ++ struct rx_vector_1_old rx_vect1_leg; ++ struct rx_vector_2_old rx_vect2_leg; ++ u32_l phy_vers = rwnx_hw->version_cfm.version_phy_2; ++ ++ // Check if we need to do the conversion. Only if old modem is used ++ if (__MDM_MAJOR_VERSION(phy_vers) > 0) { ++ rx_vect1->rssi1 = rx_vect1->rssi_leg; ++ return; ++ } ++ ++ // Copy the received vector locally ++ memcpy(&rx_vect1_leg, rx_vect1, sizeof(struct rx_vector_1_old)); ++ ++ // Reset it ++ memset(rx_vect1, 0, sizeof(struct rx_vector_1)); ++ ++ // Perform the conversion ++ rx_vect1->format_mod = rx_vect1_leg.format_mod; ++ rx_vect1->ch_bw = rx_vect1_leg.ch_bw; ++ rx_vect1->antenna_set = rx_vect1_leg.antenna_set; ++ rx_vect1->leg_length = rx_vect1_leg.leg_length; ++ rx_vect1->leg_rate = rx_vect1_leg.leg_rate; ++ rx_vect1->rssi1 = rx_vect1_leg.rssi1; ++ ++ switch (rx_vect1->format_mod) { ++ case FORMATMOD_NON_HT: ++ case FORMATMOD_NON_HT_DUP_OFDM: ++ rx_vect1->leg.lsig_valid = rx_vect1_leg.lsig_valid; ++ rx_vect1->leg.chn_bw_in_non_ht = rx_vect1_leg.num_extn_ss; ++ rx_vect1->leg.dyn_bw_in_non_ht = rx_vect1_leg.dyn_bw; ++ break; ++ case FORMATMOD_HT_MF: ++ case FORMATMOD_HT_GF: ++ rx_vect1->ht.aggregation = rx_vect1_leg.aggregation; ++ rx_vect1->ht.fec = rx_vect1_leg.fec_coding; ++ rx_vect1->ht.lsig_valid = rx_vect1_leg.lsig_valid; ++ rx_vect1->ht.length = rx_vect1_leg.ht_length; ++ rx_vect1->ht.mcs = rx_vect1_leg.mcs; ++ rx_vect1->ht.num_extn_ss = rx_vect1_leg.num_extn_ss; ++ rx_vect1->ht.short_gi = rx_vect1_leg.short_gi; ++ rx_vect1->ht.smoothing = rx_vect1_leg.smoothing; ++ rx_vect1->ht.sounding = rx_vect1_leg.sounding; ++ rx_vect1->ht.stbc = rx_vect1_leg.stbc; ++ break; ++ case FORMATMOD_VHT: ++ rx_vect1->vht.beamformed = !rx_vect1_leg.smoothing; ++ rx_vect1->vht.fec = rx_vect1_leg.fec_coding; ++ rx_vect1->vht.length = ++ rx_vect1_leg.ht_length | rx_vect1_leg._ht_length << 8; ++ rx_vect1->vht.mcs = rx_vect1_leg.mcs & 0x0F; ++ rx_vect1->vht.nss = rx_vect1_leg.stbc ? rx_vect1_leg.n_sts / 2 : ++ rx_vect1_leg.n_sts; ++ rx_vect1->vht.doze_not_allowed = rx_vect1_leg.doze_not_allowed; ++ rx_vect1->vht.short_gi = rx_vect1_leg.short_gi; ++ rx_vect1->vht.sounding = rx_vect1_leg.sounding; ++ rx_vect1->vht.stbc = rx_vect1_leg.stbc; ++ rx_vect1->vht.group_id = rx_vect1_leg.group_id; ++ rx_vect1->vht.partial_aid = rx_vect1_leg.partial_aid; ++ rx_vect1->vht.first_user = rx_vect1_leg.first_user; ++ break; ++ } ++ ++ if (!rx_vect2) ++ return; ++ ++ // Copy the received vector 2 locally ++ memcpy(&rx_vect2_leg, rx_vect2, sizeof(struct rx_vector_2_old)); ++ ++ // Reset it ++ memset(rx_vect2, 0, sizeof(struct rx_vector_2)); ++ ++ rx_vect2->rcpi1 = rx_vect2_leg.rcpi; ++ rx_vect2->rcpi2 = rx_vect2_leg.rcpi; ++ rx_vect2->rcpi3 = rx_vect2_leg.rcpi; ++ rx_vect2->rcpi4 = rx_vect2_leg.rcpi; ++ ++ rx_vect2->evm1 = rx_vect2_leg.evm1; ++ rx_vect2->evm2 = rx_vect2_leg.evm2; ++ rx_vect2->evm3 = rx_vect2_leg.evm3; ++ rx_vect2->evm4 = rx_vect2_leg.evm4; ++} ++ ++/** ++ * rwnx_rx_statistic - save some statistics about received frames ++ * ++ * @rwnx_hw: main driver data. ++ * @hw_rxhdr: Rx Hardware descriptor of the received frame. ++ * @sta: STA that sent the frame. ++ */ ++static void rwnx_rx_statistic(struct rwnx_hw *rwnx_hw, ++ struct hw_rxhdr *hw_rxhdr, struct rwnx_sta *sta) ++{ ++#if 1 //def CONFIG_RWNX_DEBUGFS ++ struct rwnx_stats *stats = &rwnx_hw->stats; ++ struct rwnx_rx_rate_stats *rate_stats = &sta->stats.rx_rate; ++ struct rx_vector_1 *rxvect = &hw_rxhdr->hwvect.rx_vect1; ++ int mpdu, ampdu, mpdu_prev, rate_idx; ++ ++ /* save complete hwvect */ ++ sta->stats.last_rx = hw_rxhdr->hwvect; ++ ++ /* update ampdu rx stats */ ++ mpdu = hw_rxhdr->hwvect.mpdu_cnt; ++ ampdu = hw_rxhdr->hwvect.ampdu_cnt; ++ mpdu_prev = stats->ampdus_rx_map[ampdu]; ++ ++ if (mpdu_prev < mpdu) { ++ stats->ampdus_rx_miss += mpdu - mpdu_prev - 1; ++ } else { ++ stats->ampdus_rx[mpdu_prev]++; ++ } ++ stats->ampdus_rx_map[ampdu] = mpdu; ++ ++ /* update rx rate statistic */ ++ if (!rate_stats->size) ++ return; ++ ++ if (rxvect->format_mod > FORMATMOD_NON_HT_DUP_OFDM) { ++ int mcs; ++ int bw = rxvect->ch_bw; ++ int sgi; ++ int nss; ++ switch (rxvect->format_mod) { ++ case FORMATMOD_HT_MF: ++ case FORMATMOD_HT_GF: ++ mcs = rxvect->ht.mcs % 8; ++ nss = rxvect->ht.mcs / 8; ++ sgi = rxvect->ht.short_gi; ++ rate_idx = N_CCK + N_OFDM + nss * 32 + mcs * 4 + ++ bw * 2 + sgi; ++ break; ++ case FORMATMOD_VHT: ++ mcs = rxvect->vht.mcs; ++ nss = rxvect->vht.nss; ++ sgi = rxvect->vht.short_gi; ++ rate_idx = N_CCK + N_OFDM + N_HT + nss * 80 + mcs * 8 + ++ bw * 2 + sgi; ++ break; ++ case FORMATMOD_HE_SU: ++ mcs = rxvect->he.mcs; ++ nss = rxvect->he.nss; ++ sgi = rxvect->he.gi_type; ++ rate_idx = N_CCK + N_OFDM + N_HT + N_VHT + nss * 144 + ++ mcs * 12 + bw * 3 + sgi; ++ break; ++ default: ++ mcs = rxvect->he.mcs; ++ nss = rxvect->he.nss; ++ sgi = rxvect->he.gi_type; ++ rate_idx = N_CCK + N_OFDM + N_HT + N_VHT + N_HE_SU + ++ nss * 216 + mcs * 18 + ++ rxvect->he.ru_size * 3 + sgi; ++ break; ++ } ++ } else { ++ int idx = legrates_lut[rxvect->leg_rate].idx; ++ if (idx < 4) { ++ rate_idx = idx * 2 + rxvect->pre_type; ++ } else { ++ rate_idx = N_CCK + idx - 4; ++ } ++ } ++ if (rate_idx < rate_stats->size) { ++ if (!rate_stats->table[rate_idx]) ++ rate_stats->rate_cnt++; ++ rate_stats->table[rate_idx]++; ++ rate_stats->cpt++; ++ } else { ++ wiphy_err(rwnx_hw->wiphy, ++ "RX: Invalid index conversion => %d/%d\n", rate_idx, ++ rate_stats->size); ++ } ++#endif ++} ++ ++/** ++ * rwnx_rx_data_skb - Process one data frame ++ * ++ * @rwnx_hw: main driver data ++ * @rwnx_vif: vif that received the buffer ++ * @skb: skb received ++ * @rxhdr: HW rx descriptor ++ * @return: true if buffer has been forwarded to upper layer ++ * ++ * If buffer is amsdu , it is first split into a list of skb. ++ * Then each skb may be: ++ * - forwarded to upper layer ++ * - resent on wireless interface ++ * ++ * When vif is a STA interface, every skb is only forwarded to upper layer. ++ * When vif is an AP interface, multicast skb are forwarded and resent, whereas ++ * skb for other BSS's STA are only resent. ++ */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) ++#define RAISE_RX_SOFTIRQ() cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ) ++#endif /* LINUX_VERSION_CODE */ ++ ++void rwnx_rx_data_skb_resend(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif, ++ struct sk_buff *skb, struct hw_rxhdr *rxhdr) ++{ ++ struct sk_buff *rx_skb = skb; ++ const struct ethhdr *eth; ++ struct sk_buff *skb_copy; ++ ++ rx_skb->dev = rwnx_vif->ndev; ++ skb_reset_mac_header(rx_skb); ++ eth = eth_hdr(rx_skb); ++ ++ //printk("resend\n"); ++ /* resend pkt on wireless interface */ ++ /* always need to copy buffer when forward=0 to get enough headrom for tsdesc */ ++ skb_copy = skb_copy_expand(rx_skb, ++ sizeof(struct rwnx_txhdr) + ++ RWNX_SWTXHDR_ALIGN_SZ + 3 + 24 + 8, ++ 0, GFP_ATOMIC); ++ ++ if (skb_copy) { ++ int res; ++ skb_copy->protocol = htons(ETH_P_802_3); ++ skb_reset_network_header(skb_copy); ++ skb_reset_mac_header(skb_copy); ++ ++ rwnx_vif->is_resending = true; ++ res = dev_queue_xmit(skb_copy); ++ rwnx_vif->is_resending = false; ++ /* note: buffer is always consummed by dev_queue_xmit */ ++ if (res == NET_XMIT_DROP) { ++ rwnx_vif->net_stats.rx_dropped++; ++ rwnx_vif->net_stats.tx_dropped++; ++ } else if (res != NET_XMIT_SUCCESS) { ++ netdev_err( ++ rwnx_vif->ndev, ++ "Failed to re-send buffer to driver (res=%d)", ++ res); ++ rwnx_vif->net_stats.tx_errors++; ++ } ++ } else { ++ netdev_err(rwnx_vif->ndev, "Failed to copy skb"); ++ } ++} ++ ++static void rwnx_rx_data_skb_forward(struct rwnx_hw *rwnx_hw, ++ struct rwnx_vif *rwnx_vif, ++ struct sk_buff *skb, ++ struct hw_rxhdr *rxhdr) ++{ ++ struct sk_buff *rx_skb; ++ ++ rx_skb = skb; ++ rx_skb->dev = rwnx_vif->ndev; ++ skb_reset_mac_header(rx_skb); ++ ++#ifdef CONFIG_BR_SUPPORT ++ void *br_port = NULL; ++ ++ if (1) { //(check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE) == _TRUE) { ++ /* Insert NAT2.5 RX here! */ ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) ++ br_port = rwnx_vif->ndev->br_port; ++#else ++ rcu_read_lock(); ++ br_port = rcu_dereference(rwnx_vif->ndev->rx_handler_data); ++ rcu_read_unlock(); ++#endif ++ ++ if (br_port) { ++ int nat25_handle_frame(struct rwnx_vif * vif, ++ struct sk_buff * skb); ++ ++ if (nat25_handle_frame(rwnx_vif, rx_skb) == -1) { ++ /* priv->ext_stats.rx_data_drops++; */ ++ /* DEBUG_ERR("RX DROP: nat25_handle_frame fail!\n"); */ ++ /* return FAIL; */ ++ } ++ } ++ } ++#endif /* CONFIG_BR_SUPPORT */ ++ ++ /* 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); ++ ++#ifdef CONFIG_FILTER_TCP_ACK ++ filter_rx_tcp_ack(rwnx_hw, rx_skb->data, cpu_to_le16(rx_skb->len)); ++#endif ++ ++#ifdef CONFIG_RX_NETIF_RECV_SKB //modify by aic ++ local_bh_disable(); ++ netif_receive_skb(rx_skb); ++ local_bh_enable(); ++#else ++ if (in_interrupt()) { ++ netif_rx(rx_skb); ++ } else { ++/* ++ * If the receive is not processed inside an ISR, the softirqd must be woken explicitly to service the NET_RX_SOFTIRQ. ++ * * In 2.6 kernels, this is handledby netif_rx(), but in earlier kernels, we need to do it manually. ++ */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) ++ netif_rx(rx_skb); ++#else ++ ulong flags; ++ netif_rx(rx_skb); ++ local_irq_save(flags); ++ RAISE_RX_SOFTIRQ(); ++ local_irq_restore(flags); ++#endif ++ } ++#endif ++ REG_SW_CLEAR_PROFILING(rwnx_hw, SW_PROF_IEEE80211RX); ++ ++ rwnx_hw->stats.last_rx = jiffies; ++} ++ ++static bool rwnx_rx_data_skb(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif, ++ struct sk_buff *skb, struct hw_rxhdr *rxhdr) ++{ ++ struct sk_buff_head list; ++ struct sk_buff *rx_skb; ++ bool amsdu = rxhdr->flags_is_amsdu; ++ u8 flags_dst_idx = rxhdr->flags_dst_idx; ++ bool resend = false, forward = true; ++ ++ skb->dev = rwnx_vif->ndev; ++ ++ __skb_queue_head_init(&list); ++ ++ if (amsdu) { ++#if 1 ++ rwnx_rxdata_process_amsdu( ++ rwnx_hw, skb, rxhdr->flags_vif_idx, ++ &list); //rxhdr not used below since skb free! ++#else ++ int count; ++ ieee80211_amsdu_to_8023s(skb, &list, rwnx_vif->ndev->dev_addr, ++ RWNX_VIF_TYPE(rwnx_vif), 0, NULL, ++ NULL); ++ ++ count = skb_queue_len(&list); ++ if (count > ARRAY_SIZE(rwnx_hw->stats.amsdus_rx)) ++ count = ARRAY_SIZE(rwnx_hw->stats.amsdus_rx); ++ rwnx_hw->stats.amsdus_rx[count - 1]++; ++#endif ++ } else { ++ rwnx_hw->stats.amsdus_rx[0]++; ++ __skb_queue_head(&list, skb); ++ } ++ ++ if (((RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_AP) || ++ (RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_AP_VLAN) || ++ (RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_P2P_GO)) && ++ !(rwnx_vif->ap.flags & RWNX_AP_ISOLATE)) { ++ const struct ethhdr *eth; ++ rx_skb = skb_peek(&list); ++ skb_reset_mac_header(rx_skb); ++ eth = eth_hdr(rx_skb); ++ ++ if (unlikely(is_multicast_ether_addr(eth->h_dest))) { ++ /* broadcast pkt need to be forwared to upper layer and resent ++ on wireless interface */ ++ resend = true; ++ } else { ++ /* unicast pkt for STA inside the BSS, no need to forward to upper ++ layer simply resend on wireless interface */ ++ if (flags_dst_idx != RWNX_INVALID_STA) { ++ struct rwnx_sta *sta = ++ &rwnx_hw->sta_table[flags_dst_idx]; ++ if (sta->valid && ++ (sta->vlan_idx == rwnx_vif->vif_index)) { ++ forward = false; ++ resend = true; ++ } ++ } ++ } ++ } else if (RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_MESH_POINT) { ++ const struct ethhdr *eth; ++ rx_skb = skb_peek(&list); ++ skb_reset_mac_header(rx_skb); ++ eth = eth_hdr(rx_skb); ++ ++ if (!is_multicast_ether_addr(eth->h_dest)) { ++ /* unicast pkt for STA inside the BSS, no need to forward to upper ++ layer simply resend on wireless interface */ ++ if (flags_dst_idx != RWNX_INVALID_STA) { ++ forward = false; ++ resend = true; ++ } ++ } ++ } ++ ++ while (!skb_queue_empty(&list)) { ++ rx_skb = __skb_dequeue(&list); ++ ++ /* resend pkt on wireless interface */ ++ if (resend) { ++ struct sk_buff *skb_copy; ++ /* always need to copy buffer when forward=0 to get enough headrom for tsdesc */ ++ skb_copy = skb_copy_expand( ++ rx_skb, ++ sizeof(struct rwnx_txhdr) + ++ RWNX_SWTXHDR_ALIGN_SZ + 3 + 24 + 8, ++ 0, GFP_ATOMIC); ++ ++ if (skb_copy) { ++ int res; ++ skb_copy->protocol = htons(ETH_P_802_3); ++ skb_reset_network_header(skb_copy); ++ skb_reset_mac_header(skb_copy); ++ ++ rwnx_vif->is_resending = true; ++ res = dev_queue_xmit(skb_copy); ++ rwnx_vif->is_resending = false; ++ /* note: buffer is always consummed by dev_queue_xmit */ ++ if (res == NET_XMIT_DROP) { ++ rwnx_vif->net_stats.rx_dropped++; ++ rwnx_vif->net_stats.tx_dropped++; ++ } else if (res != NET_XMIT_SUCCESS) { ++ netdev_err( ++ rwnx_vif->ndev, ++ "Failed to re-send buffer to driver (res=%d)", ++ res); ++ rwnx_vif->net_stats.tx_errors++; ++ } ++ } else { ++ netdev_err(rwnx_vif->ndev, ++ "Failed to copy skb"); ++ } ++ } ++ ++ /* forward pkt to upper layer */ ++ if (forward) { ++#ifdef CONFIG_BR_SUPPORT ++ void *br_port = NULL; ++ ++ if (1) { //(check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE) == _TRUE) { ++ /* Insert NAT2.5 RX here! */ ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) ++ br_port = rwnx_vif->ndev->br_port; ++#else ++ rcu_read_lock(); ++ br_port = rcu_dereference( ++ rwnx_vif->ndev->rx_handler_data); ++ rcu_read_unlock(); ++#endif ++ ++ if (br_port) { ++ int nat25_handle_frame( ++ struct rwnx_vif * vif, ++ struct sk_buff * skb); ++ ++ if (nat25_handle_frame(rwnx_vif, ++ rx_skb) == -1) { ++ /* priv->ext_stats.rx_data_drops++; */ ++ /* DEBUG_ERR("RX DROP: nat25_handle_frame fail!\n"); */ ++ /* return FAIL; */ ++ } ++ } ++ } ++#endif /* CONFIG_BR_SUPPORT */ ++ ++ /* 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); ++ ++#ifdef CONFIG_FILTER_TCP_ACK ++ filter_rx_tcp_ack(rwnx_hw, rx_skb->data, ++ cpu_to_le16(rx_skb->len)); ++#endif ++ ++#ifdef CONFIG_RX_NETIF_RECV_SKB //modify by aic ++ local_bh_disable(); ++ netif_receive_skb(rx_skb); ++ local_bh_enable(); ++#else ++ if (in_interrupt()) { ++ netif_rx(rx_skb); ++ } else { ++/* ++ * If the receive is not processed inside an ISR, the softirqd must be woken explicitly to service the NET_RX_SOFTIRQ. ++ * * In 2.6 kernels, this is handledby netif_rx(), but in earlier kernels, we need to do it manually. ++ */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) ++ netif_rx(rx_skb); ++#else ++ ulong flags; ++ netif_rx(rx_skb); ++ local_irq_save(flags); ++ RAISE_RX_SOFTIRQ(); ++ local_irq_restore(flags); ++#endif ++ } ++#endif ++ REG_SW_CLEAR_PROFILING(rwnx_hw, SW_PROF_IEEE80211RX); ++ ++ rwnx_hw->stats.last_rx = jiffies; ++ } ++ } ++ ++ return forward; ++} ++ ++#ifdef CONFIG_HE_FOR_OLD_KERNEL ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)) ++const u8 *cfg80211_find_ie_match(u8 eid, const u8 *ies, int len, ++ const u8 *match, int match_len, ++ int match_offset) ++{ ++ const struct element *elem; ++ ++ /* match_offset can't be smaller than 2, unless match_len is ++ * zero, in which case match_offset must be zero as well. ++ */ ++ if (WARN_ON((match_len && match_offset < 2) || ++ (!match_len && match_offset))) ++ return NULL; ++ ++ for_each_element_id (elem, eid, ies, len) { ++ if (elem->datalen >= match_offset - 2 + match_len && ++ !memcmp(elem->data + match_offset - 2, match, match_len)) ++ return (void *)elem; ++ } ++ ++ return NULL; ++} ++#endif ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)) ++static inline const u8 *cfg80211_find_ext_ie(u8 ext_eid, const u8 *ies, int len) ++{ ++ return cfg80211_find_ie_match(WLAN_EID_EXTENSION, ies, len, &ext_eid, 1, ++ 2); ++} ++#endif ++#endif ++ ++/** ++ * rwnx_rx_mgmt - Process one 802.11 management frame ++ * ++ * @rwnx_hw: main driver data ++ * @rwnx_vif: vif to upload the buffer to ++ * @skb: skb received ++ * @rxhdr: HW rx descriptor ++ * ++ * Forward the management frame to a given interface. ++ */ ++static void rwnx_rx_mgmt(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif, ++ struct sk_buff *skb, struct hw_rxhdr *hw_rxhdr) ++{ ++ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; ++ struct rx_vector_1 *rxvect = &hw_rxhdr->hwvect.rx_vect1; ++ ++ //printk("rwnx_rx_mgmt\n"); ++ ++#if (defined CONFIG_HE_FOR_OLD_KERNEL) || (defined CONFIG_VHT_FOR_OLD_KERNEL) ++ struct aic_sta *sta = &rwnx_hw->aic_table[rwnx_vif->ap.aic_index]; ++ const u8 *ie; ++ u32 len; ++ ++ if (skb->data[0] != 0x80) ++ AICWFDBG(LOGDEBUG, "rxmgmt:%x,%x\n", skb->data[0], ++ skb->data[1]); ++ ++ if (ieee80211_is_assoc_req(mgmt->frame_control) && ++ rwnx_vif->wdev.iftype == NL80211_IFTYPE_AP) { ++ printk("ASSOC_REQ: sta_idx %d MAC %pM\n", ++ rwnx_vif->ap.aic_index, mgmt->sa); ++ sta->sta_idx = rwnx_vif->ap.aic_index; ++ len = skb->len - (mgmt->u.assoc_req.variable - skb->data); ++ ++#ifdef CONFIG_HE_FOR_OLD_KERNEL ++ struct ieee80211_he_cap_elem *he; ++ struct ieee80211_he_mcs_nss_supp *he_mcs; ++ ie = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY, ++ mgmt->u.assoc_req.variable, len); ++ if (ie && ie[1] >= sizeof(*he) + 1) { ++ printk("assoc_req: find he\n"); ++ he = (struct ieee80211_he_cap_elem *)(ie + 3); ++ he_mcs = (struct ieee80211_he_mcs_nss_supp ++ *)((u8 *)he + sizeof(*he)); ++ memcpy(&sta->he_cap_elem, ie + 3, ++ sizeof(struct ieee80211_he_cap_elem)); ++ ++ sta->he_mcs_nss_supp.rx_mcs_80 = he_mcs->rx_mcs_80; ++ sta->he_mcs_nss_supp.tx_mcs_80 = he_mcs->tx_mcs_80; ++ sta->he = true; ++ } else { ++ printk("assoc_req: no find he\n"); ++ sta->he = false; ++ } ++#endif ++ ++#ifdef CONFIG_VHT_FOR_OLD_KERNEL ++ struct ieee80211_vht_cap *vht; ++ ie = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, ++ mgmt->u.assoc_req.variable, len); ++ if (ie && ie[1] >= sizeof(*vht)) { ++ printk("assoc_req: find vht\n"); ++ memcpy(&sta->vht_cap_info, ie + 2, 4); ++ memcpy(&sta->supp_mcs, ie + 2 + 4, ++ sizeof(struct ieee80211_vht_mcs_info)); ++ sta->vht = true; ++ } else { ++ printk("assoc_req: no find vht\n"); ++ sta->vht = false; ++ } ++#endif ++ } ++#endif ++ ++ /*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) { ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)) ++#ifdef CONFIG_GKI ++ rwnx_cfg80211_notify_new_peer_candidate( ++ rwnx_vif->ndev, mgmt->sa, ++ mgmt->u.beacon.variable, ++ skb->len - offsetof(struct ieee80211_mgmt, ++ u.beacon.variable), ++ GFP_ATOMIC); ++#else ++ cfg80211_notify_new_peer_candidate( ++ rwnx_vif->ndev, mgmt->sa, ++ mgmt->u.beacon.variable, ++ skb->len - offsetof(struct ieee80211_mgmt, ++ u.beacon.variable), ++ GFP_ATOMIC); ++#endif ++#else ++ ++#ifdef CONFIG_GKI ++ /* TODO: the value of parameter sig_dbm need to be confirmed */ ++ rwnx_cfg80211_notify_new_peer_candidate( ++ rwnx_vif->ndev, mgmt->sa, ++ mgmt->u.beacon.variable, ++ skb->len - offsetof(struct ieee80211_mgmt, ++ u.beacon.variable), ++ rxvect->rssi1, GFP_ATOMIC); ++#else ++ /* TODO: the value of parameter sig_dbm need to be confirmed */ ++ cfg80211_notify_new_peer_candidate( ++ rwnx_vif->ndev, mgmt->sa, ++ mgmt->u.beacon.variable, ++ skb->len - offsetof(struct ieee80211_mgmt, ++ u.beacon.variable), ++ rxvect->rssi1, GFP_ATOMIC); ++#endif ++ ++#endif ++ } else { ++#ifdef CONFIG_GKI ++ rwnx_cfg80211_report_obss_beacon( ++ rwnx_hw->wiphy, skb->data, skb->len, ++ hw_rxhdr->phy_info.phy_prim20_freq, ++ rxvect->rssi1); ++#else ++ cfg80211_report_obss_beacon( ++ rwnx_hw->wiphy, skb->data, skb->len, ++ hw_rxhdr->phy_info.phy_prim20_freq, ++ rxvect->rssi1); ++#endif ++ } ++ } else if ((ieee80211_is_deauth(mgmt->frame_control) || ++ ieee80211_is_disassoc(mgmt->frame_control)) && ++ (mgmt->u.deauth.reason_code == ++ WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA || ++ mgmt->u.deauth.reason_code == ++ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA)) { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) // TODO: process unprot mgmt ++ cfg80211_rx_unprot_mlme_mgmt(rwnx_vif->ndev, skb->data, ++ skb->len); ++#endif ++ } else if ((RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_STATION) && ++ (ieee80211_is_action(mgmt->frame_control) && ++ (mgmt->u.action.category == 6))) { ++ struct cfg80211_ft_event_params ft_event; ++ ft_event.target_ap = (uint8_t *)&mgmt->u.action + ETH_ALEN + 2; ++ ft_event.ies = (uint8_t *)&mgmt->u.action + ETH_ALEN * 2 + 2; ++ ft_event.ies_len = skb->len - (ft_event.ies - (uint8_t *)mgmt); ++ ft_event.ric_ies = NULL; ++ ft_event.ric_ies_len = 0; ++ cfg80211_ft_event(rwnx_vif->ndev, &ft_event); ++ } else { ++ cfg80211_rx_mgmt(&rwnx_vif->wdev, ++ hw_rxhdr->phy_info.phy_prim20_freq, ++ rxvect->rssi1, skb->data, skb->len, 0); ++ } ++} ++ ++/** ++ * rwnx_rx_mgmt_any - Process one 802.11 management frame ++ * ++ * @rwnx_hw: main driver data ++ * @skb: skb received ++ * @rxhdr: HW rx descriptor ++ * ++ * Process the management frame and free the corresponding skb. ++ * If vif is not specified in the rx descriptor, the the frame is uploaded ++ * on all active vifs. ++ */ ++static void rwnx_rx_mgmt_any(struct rwnx_hw *rwnx_hw, struct sk_buff *skb, ++ struct hw_rxhdr *hw_rxhdr) ++{ ++ 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) ++ continue; ++ rwnx_rx_mgmt(rwnx_hw, rwnx_vif, skb, hw_rxhdr); ++ } ++ } else { ++ rwnx_vif = rwnx_rx_get_vif(rwnx_hw, vif_idx); ++ if (rwnx_vif) ++ rwnx_rx_mgmt(rwnx_hw, rwnx_vif, skb, hw_rxhdr); ++ } ++ ++ dev_kfree_skb(skb); ++} ++ ++/** ++ * rwnx_rx_rtap_hdrlen - Return radiotap header length ++ * ++ * @rxvect: Rx vector used to fill the radiotap header ++ * @has_vend_rtap: boolean indicating if vendor specific data is present ++ * ++ * Compute the length of the radiotap header based on @rxvect and vendor ++ * specific data (if any). ++ */ ++static u8 rwnx_rx_rtap_hdrlen(struct rx_vector_1 *rxvect, bool has_vend_rtap) ++{ ++ u8 rtap_len; ++ ++ /* Compute radiotap header length */ ++ rtap_len = sizeof(struct ieee80211_radiotap_header) + 8; ++ ++ // Check for multiple antennas ++ if (hweight32(rxvect->antenna_set) > 1) ++ // antenna and antenna signal fields ++ rtap_len += 4 * hweight8(rxvect->antenna_set); ++ ++ // TSFT ++ if (!has_vend_rtap) { ++ rtap_len = ALIGN(rtap_len, 8); ++ rtap_len += 8; ++ } ++ ++ // IEEE80211_HW_SIGNAL_DBM ++ rtap_len++; ++ ++ // Check if single antenna ++ if (hweight32(rxvect->antenna_set) == 1) ++ rtap_len++; //Single antenna ++ ++ // padding for RX FLAGS ++ rtap_len = ALIGN(rtap_len, 2); ++ ++ // Check for HT frames ++ if ((rxvect->format_mod == FORMATMOD_HT_MF) || ++ (rxvect->format_mod == FORMATMOD_HT_GF)) ++ rtap_len += 3; ++ ++ // Check for AMPDU ++ if (!(has_vend_rtap) && ++ ((rxvect->format_mod >= FORMATMOD_VHT) || ++ ((rxvect->format_mod > FORMATMOD_NON_HT_DUP_OFDM) && ++ (rxvect->ht.aggregation)))) { ++ rtap_len = ALIGN(rtap_len, 4); ++ rtap_len += 8; ++ } ++ ++ // Check for VHT frames ++ if (rxvect->format_mod == FORMATMOD_VHT) { ++ rtap_len = ALIGN(rtap_len, 2); ++ rtap_len += 12; ++ } ++ ++ // Check for HE frames ++ if (rxvect->format_mod == FORMATMOD_HE_SU) { ++ rtap_len = ALIGN(rtap_len, 2); ++ rtap_len += sizeof(struct ieee80211_radiotap_he); ++ } ++ ++ // Check for multiple antennas ++ if (hweight32(rxvect->antenna_set) > 1) { ++ // antenna and antenna signal fields ++ rtap_len += 2 * hweight8(rxvect->antenna_set); ++ } ++ ++ // Check for vendor specific data ++ if (has_vend_rtap) { ++ /* vendor presence bitmap */ ++ rtap_len += 4; ++ /* alignment for fixed 6-byte vendor data header */ ++ rtap_len = ALIGN(rtap_len, 2); ++ } ++ ++ return rtap_len; ++} ++ ++/** ++ * rwnx_rx_add_rtap_hdr - Add radiotap header to sk_buff ++ * ++ * @rwnx_hw: main driver data ++ * @skb: skb received (will include the radiotap header) ++ * @rxvect: Rx vector ++ * @phy_info: Information regarding the phy ++ * @hwvect: HW Info (NULL if vendor specific data is available) ++ * @rtap_len: Length of the radiotap header ++ * @vend_rtap_len: radiotap vendor length (0 if not present) ++ * @vend_it_present: radiotap vendor present ++ * ++ * Builds a radiotap header and add it to @skb. ++ */ ++static void rwnx_rx_add_rtap_hdr(struct rwnx_hw *rwnx_hw, struct sk_buff *skb, ++ struct rx_vector_1 *rxvect, ++ struct phy_channel_info_desc *phy_info, ++ struct hw_vect *hwvect, int rtap_len, ++ u8 vend_rtap_len, u32 vend_it_present) ++{ ++ struct ieee80211_radiotap_header *rtap; ++ u8 *pos, rate_idx; ++ __le32 *it_present; ++ u32 it_present_val = 0; ++ bool fec_coding = false; ++ bool short_gi = false; ++ bool stbc = false; ++ bool aggregation = false; ++ ++ rtap = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len); ++ memset((u8 *)rtap, 0, rtap_len); ++ ++ rtap->it_version = 0; ++ rtap->it_pad = 0; ++ rtap->it_len = cpu_to_le16(rtap_len + vend_rtap_len); ++ ++ it_present = &rtap->it_present; ++ ++ // Check for multiple antennas ++ if (hweight32(rxvect->antenna_set) > 1) { ++ int chain; ++ unsigned long chains = rxvect->antenna_set; ++ ++ for_each_set_bit (chain, &chains, IEEE80211_MAX_CHAINS) { ++ it_present_val |= ++ BIT(IEEE80211_RADIOTAP_EXT) | ++ BIT(IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE); ++ put_unaligned_le32(it_present_val, it_present); ++ it_present++; ++ it_present_val = BIT(IEEE80211_RADIOTAP_ANTENNA) | ++ BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL); ++ } ++ } ++ ++ // Check if vendor specific data is present ++ if (vend_rtap_len) { ++ it_present_val |= BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE) | ++ BIT(IEEE80211_RADIOTAP_EXT); ++ put_unaligned_le32(it_present_val, it_present); ++ it_present++; ++ it_present_val = vend_it_present; ++ } ++ ++ put_unaligned_le32(it_present_val, it_present); ++ pos = (void *)(it_present + 1); ++ ++ // IEEE80211_RADIOTAP_TSFT ++ if (hwvect) { ++ rtap->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); ++ // padding ++ while ((pos - (u8 *)rtap) & 7) ++ *pos++ = 0; ++ put_unaligned_le64((((u64)le32_to_cpu(hwvect->tsf_hi) << 32) + ++ (u64)le32_to_cpu(hwvect->tsf_lo)), ++ pos); ++ pos += 8; ++ } ++ ++ // IEEE80211_RADIOTAP_FLAGS ++ rtap->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_FLAGS); ++ if (hwvect && (!hwvect->frm_successful_rx)) ++ *pos |= IEEE80211_RADIOTAP_F_BADFCS; ++ if (!rxvect->pre_type && ++ (rxvect->format_mod <= FORMATMOD_NON_HT_DUP_OFDM)) ++ *pos |= IEEE80211_RADIOTAP_F_SHORTPRE; ++ pos++; ++ ++ // IEEE80211_RADIOTAP_RATE ++ // check for HT, VHT or HE frames ++ if (rxvect->format_mod >= FORMATMOD_HE_SU) { ++ rate_idx = rxvect->he.mcs; ++ fec_coding = rxvect->he.fec; ++ stbc = rxvect->he.stbc; ++ aggregation = true; ++ *pos = 0; ++ } else if (rxvect->format_mod == FORMATMOD_VHT) { ++ rate_idx = rxvect->vht.mcs; ++ fec_coding = rxvect->vht.fec; ++ short_gi = rxvect->vht.short_gi; ++ stbc = rxvect->vht.stbc; ++ aggregation = true; ++ *pos = 0; ++ } else if (rxvect->format_mod > FORMATMOD_NON_HT_DUP_OFDM) { ++ rate_idx = rxvect->ht.mcs; ++ fec_coding = rxvect->ht.fec; ++ short_gi = rxvect->ht.short_gi; ++ stbc = rxvect->ht.stbc; ++ aggregation = rxvect->ht.aggregation; ++ *pos = 0; ++ } else { ++ struct ieee80211_supported_band *band = ++ rwnx_hw->wiphy->bands[phy_info->phy_band]; ++ rtap->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE); ++ BUG_ON((rate_idx = legrates_lut[rxvect->leg_rate].idx) == -1); ++ if (phy_info->phy_band == NL80211_BAND_5GHZ) ++ rate_idx -= ++ 4; /* rwnx_ratetable_5ghz[0].hw_value == 4 */ ++ *pos = DIV_ROUND_UP(band->bitrates[rate_idx].bitrate, 5); ++ } ++ pos++; ++ ++ // IEEE80211_RADIOTAP_CHANNEL ++ rtap->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_CHANNEL); ++ put_unaligned_le16(phy_info->phy_prim20_freq, pos); ++ pos += 2; ++ ++ if (phy_info->phy_band == NL80211_BAND_5GHZ) ++ put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ, ++ pos); ++ else if (rxvect->format_mod > FORMATMOD_NON_HT_DUP_OFDM) ++ put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ, ++ pos); ++ else ++ put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ, ++ pos); ++ pos += 2; ++ ++ if (hweight32(rxvect->antenna_set) == 1) { ++ // IEEE80211_RADIOTAP_DBM_ANTSIGNAL ++ rtap->it_present |= ++ cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL); ++ *pos++ = rxvect->rssi1; ++ ++ // IEEE80211_RADIOTAP_ANTENNA ++ rtap->it_present |= ++ cpu_to_le32(1 << IEEE80211_RADIOTAP_ANTENNA); ++ *pos++ = rxvect->antenna_set; ++ } ++ ++ // IEEE80211_RADIOTAP_LOCK_QUALITY is missing ++ // IEEE80211_RADIOTAP_DB_ANTNOISE is missing ++ ++ // IEEE80211_RADIOTAP_RX_FLAGS ++ rtap->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RX_FLAGS); ++ // 2 byte alignment ++ if ((pos - (u8 *)rtap) & 1) ++ *pos++ = 0; ++ put_unaligned_le16(0, pos); ++ //Right now, we only support fcs error (no RX_FLAG_FAILED_PLCP_CRC) ++ pos += 2; ++ ++ // Check if HT ++ if ((rxvect->format_mod == FORMATMOD_HT_MF) || ++ (rxvect->format_mod == FORMATMOD_HT_GF)) { ++ rtap->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_MCS); ++ *pos++ = IEEE80211_RADIOTAP_MCS_HAVE_MCS | ++ IEEE80211_RADIOTAP_MCS_HAVE_GI | ++ IEEE80211_RADIOTAP_MCS_HAVE_BW; ++ *pos = 0; ++ if (short_gi) ++ *pos |= IEEE80211_RADIOTAP_MCS_SGI; ++ if (rxvect->ch_bw == PHY_CHNL_BW_40) ++ *pos |= IEEE80211_RADIOTAP_MCS_BW_40; ++ if (rxvect->format_mod == FORMATMOD_HT_GF) ++ *pos |= IEEE80211_RADIOTAP_MCS_FMT_GF; ++ if (fec_coding) ++ *pos |= IEEE80211_RADIOTAP_MCS_FEC_LDPC; ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) ++ *pos++ |= stbc << 5; ++#else ++ *pos++ |= stbc << IEEE80211_RADIOTAP_MCS_STBC_SHIFT; ++#endif ++ *pos++ = rate_idx; ++ } ++ ++ // check for HT or VHT frames ++ if (aggregation && hwvect) { ++ // 4 byte alignment ++ while ((pos - (u8 *)rtap) & 3) ++ pos++; ++ rtap->it_present |= ++ cpu_to_le32(1 << IEEE80211_RADIOTAP_AMPDU_STATUS); ++ put_unaligned_le32(hwvect->ampdu_cnt, pos); ++ pos += 4; ++ put_unaligned_le32(0, pos); ++ pos += 4; ++ } ++ ++ // Check for VHT frames ++ if (rxvect->format_mod == FORMATMOD_VHT) { ++ u16 vht_details = IEEE80211_RADIOTAP_VHT_KNOWN_GI | ++ IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH; ++ u8 vht_nss = rxvect->vht.nss + 1; ++ ++ rtap->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_VHT); ++ ++ if ((rxvect->ch_bw == PHY_CHNL_BW_160) && ++ phy_info->phy_center2_freq) ++ vht_details &= ~IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH; ++ put_unaligned_le16(vht_details, pos); ++ pos += 2; ++ ++ // flags ++ if (short_gi) ++ *pos |= IEEE80211_RADIOTAP_VHT_FLAG_SGI; ++ if (stbc) ++ *pos |= IEEE80211_RADIOTAP_VHT_FLAG_STBC; ++ pos++; ++ ++ // bandwidth ++ if (rxvect->ch_bw == PHY_CHNL_BW_40) ++ *pos++ = 1; ++ if (rxvect->ch_bw == PHY_CHNL_BW_80) ++ *pos++ = 4; ++ else if ((rxvect->ch_bw == PHY_CHNL_BW_160) && ++ phy_info->phy_center2_freq) ++ *pos++ = 0; //80P80 ++ else if (rxvect->ch_bw == PHY_CHNL_BW_160) ++ *pos++ = 11; ++ else // 20 MHz ++ *pos++ = 0; ++ ++ // MCS/NSS ++ *pos = (rate_idx << 4) | vht_nss; ++ pos += 4; ++ if (fec_coding) ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0) ++ *pos |= 0x01; ++#else ++ *pos |= IEEE80211_RADIOTAP_CODING_LDPC_USER0; ++#endif ++ pos++; ++ // group ID ++ pos++; ++ // partial_aid ++ pos += 2; ++ } ++ ++ // Check for HE frames ++ if (rxvect->format_mod == FORMATMOD_HE_SU) { ++ struct ieee80211_radiotap_he he; ++#define HE_PREP(f, val) cpu_to_le16(FIELD_PREP(IEEE80211_RADIOTAP_HE_##f, val)) ++#define D1_KNOWN(f) cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_##f##_KNOWN) ++#define D2_KNOWN(f) cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_##f##_KNOWN) ++ ++ he.data1 = D1_KNOWN(DATA_MCS) | D1_KNOWN(BSS_COLOR) | ++ D1_KNOWN(BEAM_CHANGE) | D1_KNOWN(UL_DL) | ++ D1_KNOWN(CODING) | D1_KNOWN(STBC) | ++ D1_KNOWN(BW_RU_ALLOC) | D1_KNOWN(DOPPLER) | ++ D1_KNOWN(DATA_DCM); ++ he.data2 = D2_KNOWN(GI) | D2_KNOWN(TXBF); ++ ++ if (stbc) { ++ he.data6 |= HE_PREP(DATA6_NSTS, 2); ++ he.data3 |= HE_PREP(DATA3_STBC, 1); ++ } else { ++ he.data6 |= HE_PREP(DATA6_NSTS, rxvect->he.nss); ++ } ++ ++ he.data3 |= HE_PREP(DATA3_BSS_COLOR, rxvect->he.bss_color); ++ he.data3 |= HE_PREP(DATA3_BEAM_CHANGE, rxvect->he.beam_change); ++ he.data3 |= HE_PREP(DATA3_UL_DL, rxvect->he.uplink_flag); ++ he.data3 |= HE_PREP(DATA3_BSS_COLOR, rxvect->he.bss_color); ++ he.data3 |= HE_PREP(DATA3_DATA_MCS, rxvect->he.mcs); ++ he.data3 |= HE_PREP(DATA3_DATA_DCM, rxvect->he.dcm); ++ he.data3 |= HE_PREP(DATA3_CODING, rxvect->he.fec); ++ ++ he.data5 |= HE_PREP(DATA5_GI, rxvect->he.gi_type); ++ he.data5 |= HE_PREP(DATA5_TXBF, rxvect->he.beamformed); ++ he.data5 |= HE_PREP(DATA5_LTF_SIZE, rxvect->he.he_ltf_type + 1); ++ ++ switch (rxvect->ch_bw) { ++ case PHY_CHNL_BW_20: ++ he.data5 |= HE_PREP( ++ DATA5_DATA_BW_RU_ALLOC, ++ IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_20MHZ); ++ break; ++ case PHY_CHNL_BW_40: ++ he.data5 |= HE_PREP( ++ DATA5_DATA_BW_RU_ALLOC, ++ IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_40MHZ); ++ break; ++ case PHY_CHNL_BW_80: ++ he.data5 |= HE_PREP( ++ DATA5_DATA_BW_RU_ALLOC, ++ IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_80MHZ); ++ break; ++ case PHY_CHNL_BW_160: ++ he.data5 |= HE_PREP( ++ DATA5_DATA_BW_RU_ALLOC, ++ IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_160MHZ); ++ break; ++ default: ++ WARN_ONCE(1, "Invalid SU BW %d\n", rxvect->ch_bw); ++ } ++ ++ he.data6 |= HE_PREP(DATA6_DOPPLER, rxvect->he.doppler); ++ ++ /* ensure 2 byte alignment */ ++ while ((pos - (u8 *)rtap) & 1) ++ pos++; ++ rtap->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_HE); ++ memcpy(pos, &he, sizeof(he)); ++ pos += sizeof(he); ++ } ++ ++ // Rx Chains ++ if (hweight32(rxvect->antenna_set) > 1) { ++ int chain; ++ unsigned long chains = rxvect->antenna_set; ++ u8 rssis[4] = { rxvect->rssi1, rxvect->rssi1, rxvect->rssi1, ++ rxvect->rssi1 }; ++ ++ for_each_set_bit (chain, &chains, IEEE80211_MAX_CHAINS) { ++ *pos++ = rssis[chain]; ++ *pos++ = chain; ++ } ++ } ++} ++ ++/** ++ * rwnx_rx_monitor - Build radiotap header for skb an send it to netdev ++ * ++ * @rwnx_hw: main driver data ++ * @rwnx_vif: vif that received the buffer ++ * @skb: sk_buff received ++ * @hw_rxhdr_ptr: Pointer to HW RX header ++ * @rtap_len: Radiotap Header length ++ * ++ * Add radiotap header to the receved skb and send it to netdev ++ */ ++static int rwnx_rx_monitor(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif, ++ struct sk_buff *skb, struct hw_rxhdr *hw_rxhdr_ptr, ++ u8 rtap_len) ++{ ++ skb->dev = rwnx_vif->ndev; ++ ++ if (rwnx_vif->wdev.iftype != NL80211_IFTYPE_MONITOR) { ++ netdev_err(rwnx_vif->ndev, "not a monitor vif\n"); ++ return -1; ++ } ++ ++ /* Add RadioTap Header */ ++ rwnx_rx_add_rtap_hdr(rwnx_hw, skb, &hw_rxhdr_ptr->hwvect.rx_vect1, ++ &hw_rxhdr_ptr->phy_info, &hw_rxhdr_ptr->hwvect, ++ rtap_len, 0, 0); ++ ++ skb_reset_mac_header(skb); ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ skb->pkt_type = PACKET_OTHERHOST; ++ skb->protocol = htons(ETH_P_802_2); ++ ++#ifdef CONFIG_FILTER_TCP_ACK ++ filter_rx_tcp_ack(rwnx_hw, skb->data, cpu_to_le16(skb->len)); ++#endif ++ ++ local_bh_disable(); ++ netif_receive_skb(skb); ++ local_bh_enable(); ++ ++ return 0; ++} ++ ++#ifdef AICWF_ARP_OFFLOAD ++void arpoffload_proc(struct sk_buff *skb, struct rwnx_vif *rwnx_vif) ++{ ++ struct iphdr *iphead = (struct iphdr *)(skb->data); ++ struct udphdr *udph; ++ struct DHCPInfo *dhcph; ++ ++ if (skb->protocol == htons(ETH_P_IP)) { // IP ++ if (iphead->protocol == IPPROTO_UDP) { // UDP ++ udph = (struct udphdr *)((u8 *)iphead + ++ (iphead->ihl << 2)); ++ if ((udph->source == __constant_htons(SERVER_PORT)) && ++ (udph->dest == ++ __constant_htons(CLIENT_PORT))) { // DHCP offset/ack ++ dhcph = (struct DHCPInfo ++ *)((u8 *)udph + ++ sizeof(struct udphdr)); ++ if (dhcph->cookie == htonl(DHCP_MAGIC) && ++ dhcph->op == 2 && ++ !memcmp(dhcph->chaddr, ++ rwnx_vif->ndev->dev_addr, ++ 6)) { // match magic word ++ u32 length = ntohs(udph->len) - ++ sizeof(struct udphdr) - ++ offsetof(struct DHCPInfo, ++ options); ++ u16 offset = 0; ++ u8 *option = dhcph->options; ++ while (option[offset] != ++ DHCP_OPTION_END && ++ offset < length) { ++ if (option[offset] == ++ DHCP_OPTION_MESSAGE_TYPE) { ++ if (option[offset + 2] == ++ DHCP_ACK) { ++ dhcped = 1; ++ AICWFDBG( ++ LOGINFO, ++ "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); ++ } ++ } ++ offset += ++ 2 + option[offset + 1]; ++ } ++ } ++ } ++ } ++ } ++} ++#endif ++ ++#ifdef AICWF_RX_REORDER ++void reord_rxframe_free(spinlock_t *lock, struct list_head *q, ++ struct list_head *list) ++{ ++ spin_lock_bh(lock); ++ list_add(list, q); ++ spin_unlock_bh(lock); ++} ++ ++struct recv_msdu *reord_rxframe_alloc(spinlock_t *lock, struct list_head *q) ++{ ++ struct recv_msdu *rxframe; ++ ++ spin_lock_bh(lock); ++ if (list_empty(q)) { ++ spin_unlock_bh(lock); ++ return NULL; ++ } ++ rxframe = list_entry(q->next, struct recv_msdu, rxframe_list); ++ list_del_init(q->next); ++ spin_unlock_bh(lock); ++ return rxframe; ++} ++ ++struct reord_ctrl_info *reord_init_sta(struct aicwf_rx_priv *rx_priv, ++ const u8 *mac_addr) ++{ ++ u8 i = 0; ++ struct reord_ctrl *preorder_ctrl = NULL; ++ struct reord_ctrl_info *reord_info; ++#ifdef AICWF_SDIO_SUPPORT ++ struct aicwf_bus *bus_if = rx_priv->sdiodev->bus_if; ++#else ++ struct aicwf_bus *bus_if = rx_priv->usbdev->bus_if; ++#endif ++ ++ if (bus_if->state == BUS_DOWN_ST || rx_priv == NULL) { ++ AICWFDBG(LOGERROR, "bad stat!\n"); ++ return NULL; ++ } ++ ++ AICWFDBG(LOGINFO, "reord_init_sta:%pM\n", mac_addr); ++ reord_info = kmalloc(sizeof(struct reord_ctrl_info), GFP_ATOMIC); ++ if (!reord_info) ++ return NULL; ++ ++ memcpy(reord_info->mac_addr, mac_addr, ETH_ALEN); ++ for (i = 0; i < 8; i++) { ++ preorder_ctrl = &reord_info->preorder_ctrl[i]; ++ preorder_ctrl->enable = true; ++ preorder_ctrl->ind_sn = 0xffff; ++ preorder_ctrl->wsize_b = AICWF_REORDER_WINSIZE; ++ preorder_ctrl->rx_priv = rx_priv; ++ INIT_LIST_HEAD(&preorder_ctrl->reord_list); ++ spin_lock_init(&preorder_ctrl->reord_list_lock); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) ++ init_timer(&preorder_ctrl->reord_timer); ++ preorder_ctrl->reord_timer.data = (ulong)preorder_ctrl; ++ preorder_ctrl->reord_timer.function = reord_timeout_handler; ++#else ++ timer_setup(&preorder_ctrl->reord_timer, reord_timeout_handler, ++ 0); ++#endif ++ INIT_WORK(&preorder_ctrl->reord_timer_work, ++ reord_timeout_worker); ++ } ++ ++ return reord_info; ++} ++ ++int reord_flush_tid(struct aicwf_rx_priv *rx_priv, struct sk_buff *skb, u8 tid) ++{ ++ struct reord_ctrl_info *reord_info; ++ struct reord_ctrl *preorder_ctrl; ++ struct rwnx_vif *rwnx_vif = (struct rwnx_vif *)rx_priv->rwnx_vif; ++ struct ethhdr *eh = (struct ethhdr *)(skb->data); ++ u8 *mac; ++ unsigned long flags; ++ u8 found = 0; ++ struct list_head *phead, *plist; ++ struct recv_msdu *prframe; ++ int ret; ++ ++ if ((rwnx_vif->wdev.iftype == NL80211_IFTYPE_STATION) || ++ (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)) ++ mac = eh->h_dest; ++ else if ((rwnx_vif->wdev.iftype == NL80211_IFTYPE_AP) || ++ (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)) ++ mac = eh->h_source; ++ else { ++ AICWFDBG(LOGERROR, "error mode:%d!\n", rwnx_vif->wdev.iftype); ++ dev_kfree_skb(skb); ++ return -1; ++ } ++ ++ spin_lock_bh(&rx_priv->stas_reord_lock); ++ list_for_each_entry (reord_info, &rx_priv->stas_reord_list, list) { ++ if (!memcmp(mac, reord_info->mac_addr, ETH_ALEN)) { ++ found = 1; ++ preorder_ctrl = &reord_info->preorder_ctrl[tid]; ++ break; ++ } ++ } ++ if (!found) { ++ spin_unlock_bh(&rx_priv->stas_reord_lock); ++ return 0; ++ } ++ spin_unlock_bh(&rx_priv->stas_reord_lock); ++ ++ if (preorder_ctrl->enable == false) ++ return 0; ++ spin_lock_irqsave(&preorder_ctrl->reord_list_lock, flags); ++ phead = &preorder_ctrl->reord_list; ++ while (1) { ++ if (list_empty(phead)) { ++ break; ++ } ++ plist = phead->next; ++ prframe = ++ list_entry(plist, struct recv_msdu, reord_pending_list); ++ reord_single_frame_ind(rx_priv, prframe); ++ list_del_init(&(prframe->reord_pending_list)); ++ } ++ ++ AICWFDBG(LOGINFO, "flush:tid=%d", tid); ++ preorder_ctrl->enable = false; ++ spin_unlock_irqrestore(&preorder_ctrl->reord_list_lock, flags); ++ if (timer_pending(&preorder_ctrl->reord_timer)) ++ ret = timer_delete_sync(&preorder_ctrl->reord_timer); ++ cancel_work_sync(&preorder_ctrl->reord_timer_work); ++ ++ return 0; ++} ++ ++void reord_deinit_sta(struct aicwf_rx_priv *rx_priv, ++ struct reord_ctrl_info *reord_info) ++{ ++ u8 i = 0; ++ unsigned long flags; ++ struct reord_ctrl *preorder_ctrl = NULL; ++ int ret; ++ ++ if (rx_priv == NULL) { ++ txrx_err("bad rx_priv!\n"); ++ return; ++ } ++ ++ for (i = 0; i < 8; i++) { ++ struct recv_msdu *req, *next; ++ preorder_ctrl = &reord_info->preorder_ctrl[i]; ++ if (preorder_ctrl->enable) { ++ preorder_ctrl->enable = false; ++ if (timer_pending(&preorder_ctrl->reord_timer)) { ++ ret = timer_delete_sync( ++ &preorder_ctrl->reord_timer); ++ } ++ cancel_work_sync(&preorder_ctrl->reord_timer_work); ++ } ++ spin_lock_irqsave(&preorder_ctrl->reord_list_lock, flags); ++ list_for_each_entry_safe (req, next, &preorder_ctrl->reord_list, ++ reord_pending_list) { ++ list_del_init(&req->reord_pending_list); ++ if (req->pkt != NULL) ++ dev_kfree_skb(req->pkt); ++ req->pkt = NULL; ++ reord_rxframe_free(&rx_priv->freeq_lock, ++ &rx_priv->rxframes_freequeue, ++ &req->rxframe_list); ++ } ++ spin_unlock_irqrestore(&preorder_ctrl->reord_list_lock, flags); ++ } ++ spin_lock_bh(&rx_priv->stas_reord_lock); ++ list_del(&reord_info->list); ++ spin_unlock_bh(&rx_priv->stas_reord_lock); ++ kfree(reord_info); ++} ++ ++int reord_single_frame_ind(struct aicwf_rx_priv *rx_priv, ++ struct recv_msdu *prframe) ++{ ++ struct list_head *rxframes_freequeue = NULL; ++ struct sk_buff *skb = NULL; ++ struct rwnx_vif *rwnx_vif = (struct rwnx_vif *)rx_priv->rwnx_vif; ++ struct sk_buff_head list; ++ struct sk_buff *rx_skb; ++ ++ rxframes_freequeue = &rx_priv->rxframes_freequeue; ++ skb = prframe->pkt; ++ ++#ifdef CONFIG_BR_SUPPORT ++ void *br_port = NULL; ++ ++ if (1) { //(check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE) == _TRUE) { ++ /* Insert NAT2.5 RX here! */ ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) ++ br_port = rwnx_vif->ndev->br_port; ++#else ++ rcu_read_lock(); ++ br_port = rcu_dereference(rwnx_vif->ndev->rx_handler_data); ++ rcu_read_unlock(); ++#endif ++ ++ if (br_port) { ++ int nat25_handle_frame(struct rwnx_vif * vif, ++ struct sk_buff * skb); ++ ++ if (nat25_handle_frame(rwnx_vif, skb) == -1) { ++ /* priv->ext_stats.rx_data_drops++; */ ++ /* DEBUG_ERR("RX DROP: nat25_handle_frame fail!\n"); */ ++ /* return FAIL; */ ++ } ++ } ++ } ++#endif /* CONFIG_BR_SUPPORT */ ++ ++ if (skb == NULL) { ++ txrx_err("skb is NULL\n"); ++ return -1; ++ } ++ ++ if (!prframe->forward) { ++ //printk("single: %d not forward: drop\n", prframe->seq_num); ++ 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; ++ __skb_queue_head_init(&list); ++ //printk("sg:%d\n", prframe->is_amsdu); ++ if (prframe->is_amsdu) { ++ rwnx_rxdata_process_amsdu( ++ rwnx_vif->rwnx_hw, skb, rwnx_vif->vif_index, ++ &list); //rxhdr not used below since skb free! ++ } else { ++ __skb_queue_head(&list, skb); ++ } ++ ++ while (!skb_queue_empty(&list)) { ++ rx_skb = __skb_dequeue(&list); ++ ++ rwnx_vif->net_stats.rx_packets++; ++ rwnx_vif->net_stats.rx_bytes += rx_skb->len; ++ //printk("netif sn=%d, len=%d\n", precv_frame->attrib.seq_num, skb->len); ++ ++ rx_skb->dev = rwnx_vif->ndev; ++ 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)); ++ ++#ifdef CONFIG_FILTER_TCP_ACK ++ filter_rx_tcp_ack(rwnx_vif->rwnx_hw, rx_skb->data, ++ cpu_to_le16(rx_skb->len)); ++#endif ++ ++#ifdef CONFIG_RX_NETIF_RECV_SKB //AIDEN test ++ local_bh_disable(); ++ netif_receive_skb(rx_skb); ++ local_bh_enable(); ++#else ++ if (in_interrupt()) { ++ netif_rx(rx_skb); ++ } else { ++ /* ++ * If the receive is not processed inside an ISR, the softirqd must be woken explicitly to service the NET_RX_SOFTIRQ. ++ * * In 2.6 kernels, this is handledby netif_rx(), but in earlier kernels, we need to do it manually. ++ */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) ++ netif_rx(rx_skb); ++#else ++ ulong flags; ++ netif_rx(rx_skb); ++ local_irq_save(flags); ++ RAISE_RX_SOFTIRQ(); ++ local_irq_restore(flags); ++#endif ++ } ++#endif /* CONFIG_RX_NETIF_RECV_SKB */ ++ } ++ ++ prframe->pkt = NULL; ++ reord_rxframe_free(&rx_priv->freeq_lock, rxframes_freequeue, ++ &prframe->rxframe_list); ++ ++ return 0; ++} ++ ++bool reord_rxframes_process(struct aicwf_rx_priv *rx_priv, ++ struct reord_ctrl *preorder_ctrl, int bforced) ++{ ++ struct list_head *phead, *plist; ++ struct recv_msdu *prframe; ++ bool bPktInBuf = false; ++ ++ if (bforced == true) { ++ phead = &preorder_ctrl->reord_list; ++ if (list_empty(phead)) { ++ return false; ++ } ++ ++ plist = phead->next; ++ prframe = ++ list_entry(plist, struct recv_msdu, reord_pending_list); ++ preorder_ctrl->ind_sn = prframe->seq_num; ++ } ++ ++ phead = &preorder_ctrl->reord_list; ++ if (list_empty(phead)) { ++ return bPktInBuf; ++ } ++ ++ list_for_each_entry (prframe, phead, reord_pending_list) { ++ if (!SN_LESS(preorder_ctrl->ind_sn, prframe->seq_num)) { ++ if (SN_EQUAL(preorder_ctrl->ind_sn, prframe->seq_num)) { ++ preorder_ctrl->ind_sn = ++ (preorder_ctrl->ind_sn + 1) & 0xFFF; ++ } ++ } else { ++ bPktInBuf = true; ++ break; ++ } ++ } ++ ++ return bPktInBuf; ++} ++ ++void reord_rxframes_ind(struct aicwf_rx_priv *rx_priv, ++ struct reord_ctrl *preorder_ctrl) ++{ ++ struct list_head *phead, *plist; ++ struct recv_msdu *prframe; ++ ++ phead = &preorder_ctrl->reord_list; ++ while (1) { ++ //spin_lock_bh(&preorder_ctrl->reord_list_lock); ++ if (list_empty(phead)) { ++ // spin_unlock_bh(&preorder_ctrl->reord_list_lock); ++ break; ++ } ++ ++ plist = phead->next; ++ prframe = ++ list_entry(plist, struct recv_msdu, reord_pending_list); ++ ++ if (!SN_LESS(preorder_ctrl->ind_sn, prframe->seq_num)) { ++ list_del_init(&(prframe->reord_pending_list)); ++ // spin_unlock_bh(&preorder_ctrl->reord_list_lock); ++ reord_single_frame_ind(rx_priv, prframe); ++ } else { ++ // spin_unlock_bh(&preorder_ctrl->reord_list_lock); ++ break; ++ } ++ } ++} ++ ++int reorder_timeout = REORDER_UPDATE_TIME; ++module_param(reorder_timeout, int, 0660); ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) ++void reord_timeout_handler(ulong data) ++#else ++void reord_timeout_handler(struct timer_list *t) ++#endif ++{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) ++ struct reord_ctrl *preorder_ctrl = (struct reord_ctrl *)data; ++#else ++ struct reord_ctrl *preorder_ctrl = ++ timer_container_of(preorder_ctrl, t, reord_timer); ++#endif ++ ++#if 0 //AIDEN ++ struct aicwf_rx_priv *rx_priv = preorder_ctrl->rx_priv; ++ ++ if (reord_rxframes_process(rx_priv, preorder_ctrl, true) == true) { ++ mod_timer(&preorder_ctrl->reord_timer, jiffies + msecs_to_jiffies(REORDER_UPDATE_TIME)); ++ } ++#endif ++ ++ if (!work_pending(&preorder_ctrl->reord_timer_work)) ++ schedule_work(&preorder_ctrl->reord_timer_work); ++} ++ ++void reord_timeout_worker(struct work_struct *work) ++{ ++ struct reord_ctrl *preorder_ctrl = ++ container_of(work, struct reord_ctrl, reord_timer_work); ++ struct aicwf_rx_priv *rx_priv = preorder_ctrl->rx_priv; ++ ++ spin_lock_bh(&preorder_ctrl->reord_list_lock); ++#if 1 //AIDEN ++ if (reord_rxframes_process(rx_priv, preorder_ctrl, true) == true) { ++ mod_timer( ++ &preorder_ctrl->reord_timer, ++ jiffies + ++ msecs_to_jiffies( ++ reorder_timeout /*REORDER_UPDATE_TIME*/)); ++ } ++#endif ++ ++ reord_rxframes_ind(rx_priv, preorder_ctrl); ++ spin_unlock_bh(&preorder_ctrl->reord_list_lock); ++ ++ return; ++} ++ ++int reord_process_unit(struct aicwf_rx_priv *rx_priv, struct sk_buff *skb, ++ u16 seq_num, u8 tid, u8 forward, u8 is_amsdu) ++{ ++ int ret = 0; ++ u8 *mac; ++ struct recv_msdu *pframe; ++ struct reord_ctrl *preorder_ctrl; ++ struct reord_ctrl_info *reord_info; ++ struct rwnx_vif *rwnx_vif = (struct rwnx_vif *)rx_priv->rwnx_vif; ++ struct ethhdr *eh = (struct ethhdr *)(skb->data); ++ u8 *da = eh->h_dest; ++ u8 is_mcast = ((*da) & 0x01) ? 1 : 0; ++ ++ if (rwnx_vif == NULL || skb->len <= 14) { ++ dev_kfree_skb(skb); ++ return -1; ++ } ++ ++ pframe = reord_rxframe_alloc(&rx_priv->freeq_lock, ++ &rx_priv->rxframes_freequeue); ++ if (!pframe) { ++ dev_kfree_skb(skb); ++ return -1; ++ } ++ ++ INIT_LIST_HEAD(&pframe->reord_pending_list); ++ pframe->seq_num = seq_num; ++ pframe->tid = tid; ++ pframe->rx_data = skb->data; ++ //pframe->len = skb->len; ++ pframe->pkt = skb; ++ pframe->forward = forward; ++ preorder_ctrl = pframe->preorder_ctrl; ++ pframe->is_amsdu = is_amsdu; ++ ++ if ((ntohs(eh->h_proto) == ETH_P_PAE) || is_mcast) ++ return reord_single_frame_ind(rx_priv, pframe); ++ ++ if ((rwnx_vif->wdev.iftype == NL80211_IFTYPE_STATION) || ++ (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)) ++ mac = eh->h_dest; ++ else if ((rwnx_vif->wdev.iftype == NL80211_IFTYPE_AP) || ++ (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)) ++ mac = eh->h_source; ++ else { ++ dev_kfree_skb(skb); ++ return -1; ++ } ++ ++ spin_lock_bh(&rx_priv->stas_reord_lock); ++ list_for_each_entry (reord_info, &rx_priv->stas_reord_list, list) { ++ if (!memcmp(mac, reord_info->mac_addr, ETH_ALEN)) { ++ preorder_ctrl = &reord_info->preorder_ctrl[pframe->tid]; ++ break; ++ } ++ } ++ ++ if (&reord_info->list == &rx_priv->stas_reord_list) { ++ reord_info = reord_init_sta(rx_priv, mac); ++ if (!reord_info) { ++ spin_unlock_bh(&rx_priv->stas_reord_lock); ++ dev_kfree_skb(skb); ++ return -1; ++ } ++ list_add_tail(&reord_info->list, &rx_priv->stas_reord_list); ++ preorder_ctrl = &reord_info->preorder_ctrl[pframe->tid]; ++ } else { ++ if (preorder_ctrl->enable == false) { ++ preorder_ctrl->enable = true; ++ preorder_ctrl->ind_sn = 0xffff; ++ preorder_ctrl->wsize_b = AICWF_REORDER_WINSIZE; ++ preorder_ctrl->rx_priv = rx_priv; ++ } ++ } ++ spin_unlock_bh(&rx_priv->stas_reord_lock); ++ ++ if (preorder_ctrl->enable == false) { ++ spin_lock_bh(&preorder_ctrl->reord_list_lock); ++ preorder_ctrl->ind_sn = pframe->seq_num; ++ reord_single_frame_ind(rx_priv, pframe); ++ preorder_ctrl->ind_sn = (preorder_ctrl->ind_sn + 1) % 4096; ++ spin_unlock_bh(&rx_priv->stas_reord_lock); ++ return 0; ++ } ++ ++ spin_lock_bh(&preorder_ctrl->reord_list_lock); ++ if (reord_need_check(preorder_ctrl, pframe->seq_num)) { ++#if 1 ++ if (pframe->rx_data[42] == 0x80) { //this is rtp package ++ if (pframe->seq_num == preorder_ctrl->ind_sn) { ++ printk("%s pframe->seq_num1:%d \r\n", __func__, ++ pframe->seq_num); ++ reord_single_frame_ind( ++ rx_priv, pframe); //not need to reorder ++ } else { ++ printk("%s free pframe->seq_num:%d \r\n", ++ __func__, pframe->seq_num); ++ if (pframe->pkt) { ++ dev_kfree_skb(pframe->pkt); ++ pframe->pkt = NULL; ++ } ++ reord_rxframe_free(&rx_priv->freeq_lock, ++ &rx_priv->rxframes_freequeue, ++ &pframe->rxframe_list); ++ } ++ } else { ++ //printk("%s pframe->seq_num2:%d \r\n", __func__, pframe->seq_num); ++ reord_single_frame_ind(rx_priv, ++ pframe); //not need to reorder ++ } ++#else ++ reord_single_frame_ind(rx_priv, pframe); //not need to reor ++#endif ++ spin_unlock_bh(&preorder_ctrl->reord_list_lock); ++ return 0; ++ } ++ ++ if (reord_rxframe_enqueue(preorder_ctrl, pframe)) { ++ spin_unlock_bh(&preorder_ctrl->reord_list_lock); ++ goto fail; ++ } ++ ++ if (reord_rxframes_process(rx_priv, preorder_ctrl, false) == true) { ++ if (!timer_pending(&preorder_ctrl->reord_timer)) { ++ ret = mod_timer( ++ &preorder_ctrl->reord_timer, ++ jiffies + ++ msecs_to_jiffies( ++ reorder_timeout /*REORDER_UPDATE_TIME*/)); ++ } ++ } else { ++ if (timer_pending(&preorder_ctrl->reord_timer)) { ++ ret = timer_delete(&preorder_ctrl->reord_timer); ++ } ++ } ++ ++ reord_rxframes_ind(rx_priv, preorder_ctrl); ++ spin_unlock_bh(&preorder_ctrl->reord_list_lock); ++ ++ return 0; ++ ++fail: ++ if (pframe->pkt) { ++ dev_kfree_skb(pframe->pkt); ++ pframe->pkt = NULL; ++ } ++ reord_rxframe_free(&rx_priv->freeq_lock, &rx_priv->rxframes_freequeue, ++ &pframe->rxframe_list); ++ return ret; ++} ++ ++int reord_need_check(struct reord_ctrl *preorder_ctrl, u16 seq_num) ++{ ++ u8 wsize = preorder_ctrl->wsize_b; ++ u16 wend = (preorder_ctrl->ind_sn + wsize - 1) & 0xFFF; ++ ++ if (preorder_ctrl->ind_sn == 0xFFFF) { ++ preorder_ctrl->ind_sn = seq_num; ++ } ++ ++ if (SN_LESS(seq_num, preorder_ctrl->ind_sn)) { ++ return -1; ++ } ++ ++ if (SN_EQUAL(seq_num, preorder_ctrl->ind_sn)) { ++ preorder_ctrl->ind_sn = (preorder_ctrl->ind_sn + 1) & 0xFFF; ++ } else if (SN_LESS(wend, seq_num)) { ++ if (seq_num >= (wsize - 1)) ++ preorder_ctrl->ind_sn = seq_num - (wsize - 1); ++ else ++ preorder_ctrl->ind_sn = ++ 0xFFF - (wsize - (seq_num + 1)) + 1; ++ } ++ ++ return 0; ++} ++ ++int reord_rxframe_enqueue(struct reord_ctrl *preorder_ctrl, ++ struct recv_msdu *prframe) ++{ ++ struct list_head *preord_list = &preorder_ctrl->reord_list; ++ struct list_head *phead, *plist; ++ struct recv_msdu *pnextrframe; ++ ++ phead = preord_list; ++ plist = phead->next; ++ ++ while (phead != plist) { ++ pnextrframe = ++ list_entry(plist, struct recv_msdu, reord_pending_list); ++ if (SN_LESS(pnextrframe->seq_num, prframe->seq_num)) { ++ plist = plist->next; ++ continue; ++ } else if (SN_EQUAL(pnextrframe->seq_num, prframe->seq_num)) { ++ return -1; ++ } else { ++ break; ++ } ++ } ++ list_add_tail(&(prframe->reord_pending_list), plist); ++ ++ return 0; ++} ++#endif /* AICWF_RX_REORDER */ ++ ++void remove_sec_hdr_mgmt_frame(struct hw_rxhdr *hw_rxhdr, struct sk_buff *skb) ++{ ++ u8 hdr_len = 24; ++ u8 mgmt_header[24] = { 0 }; ++ ++ if (!hw_rxhdr->hwvect.ga_frame) { ++ if (((skb->data[0] & 0x0C) == 0) && ++ (skb->data[1] & 0x40) == 0x40) { //protect management frame ++ printk("frame type %x\n", skb->data[0]); ++ if (hw_rxhdr->hwvect.decr_status == ++ RWNX_RX_HD_DECR_CCMP128) { ++ memcpy(mgmt_header, skb->data, hdr_len); ++ skb_pull(skb, 8); ++ memcpy(skb->data, mgmt_header, hdr_len); ++ hw_rxhdr->hwvect.len -= 8; ++ } else { ++ printk("unsupport decr_status:%d\n", ++ hw_rxhdr->hwvect.decr_status); ++ } ++ } ++ } ++} ++ ++#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 = timer_container_of(defrag_ctrl, t, defrag_timer); ++#endif ++ ++ printk("%s:%p\r\n", __func__, defrag_ctrl); ++ spin_lock_bh(&defrag_ctrl->rwnx_hw->defrag_lock); ++ list_del_init(&defrag_ctrl->list); ++ dev_kfree_skb(defrag_ctrl->skb); ++ kfree(defrag_ctrl); ++ spin_unlock_bh(&defrag_ctrl->rwnx_hw->defrag_lock); ++} ++ ++void rwnx_rxdata_process_amsdu(struct rwnx_hw *rwnx_hw, struct sk_buff *skb, ++ u8 vif_idx, struct sk_buff_head *list) ++{ ++ u16 len_alligned = 0; ++ u16 sublen = 0; ++ struct sk_buff *sub_skb = NULL; ++ struct rwnx_vif *rwnx_vif; ++ ++ //if (is_amsdu) ++ { ++ //skb_pull(skb, pull_len-8); ++ /* |amsdu sub1 | amsdu sub2 | ... */ ++ len_alligned = 0; ++ sublen = 0; ++ sub_skb = NULL; ++ 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_ATOMIC); ++ if (!sub_skb) { ++ printk("sub_skb alloc fail:%d\n", sublen); ++ break; ++ } ++ 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, vif_idx); ++ if (!rwnx_vif) { ++ printk("Frame received but no active vif (%d)", ++ vif_idx); ++ //dev_kfree_skb(sub_skb); ++ break; ++ } ++ ++ __skb_queue_tail(list, sub_skb); ++ ++ //printk("a:%p\n", sub_skb); ++ //if (!rwnx_rx_data_skb(rwnx_hw, rwnx_vif, sub_skb, hw_rxhdr)) ++ // dev_kfree_skb(sub_skb); ++#endif ++ skb_pull(skb, len_alligned); ++ } ++ //printk("af:%p\n", skb); ++ ++ dev_kfree_skb(skb); ++ //return 0; ++ } ++} ++ ++u8 rwnx_rxdataind_aicwf(struct rwnx_hw *rwnx_hw, void *hostid, void *rx_priv) ++{ ++ struct hw_rxhdr *hw_rxhdr; ++ struct rxdesc_tag *rxdesc = NULL; ++ struct rwnx_vif *rwnx_vif; ++ struct sk_buff *skb = hostid; ++ int msdu_offset = sizeof(struct hw_rxhdr) + 2; ++ u16_l status = 0; ++ struct aicwf_rx_priv *rx_priv_tmp; ++ u8 hdr_len = 24; ++ u8 ra[MAC_ADDR_LEN] = { 0 }; ++ u8 ta[MAC_ADDR_LEN] = { 0 }; ++ 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; ++ struct sk_buff *skb_tmp = NULL; ++ int ret; ++ u8 sta_idx = 0; ++ u16_l frame_ctrl; ++ u8 is_amsdu = 0; ++ bool resend = false, forward = true; ++ const struct ethhdr *eth; ++ ++ hw_rxhdr = (struct hw_rxhdr *)skb->data; ++ ++#ifdef AICWF_RX_REORDER ++ if (hw_rxhdr->is_monitor_vif) { ++ status = RX_STAT_MONITOR; ++ //printk("monitor rx\n"); ++ } ++#endif ++ ++ if (hw_rxhdr->flags_upload) ++ status |= RX_STAT_FORWARD; ++ ++ /* Check if we need to delete the buffer */ ++ if (status & RX_STAT_DELETE) { ++ /* Remove the SK buffer from the rxbuf_elems table */ ++#if 0 ++ rwnx_ipc_rxbuf_elem_pull(rwnx_hw, skb); ++#endif ++ /* 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 = NULL; ++ struct hw_rxhdr hw_rxhdr_copy; ++ u8 rtap_len; ++ u16 frm_len = 0; ++ ++ //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; ++ } ++ ++ 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); ++ ++ 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); ++ skb->data += (msdu_offset + 2); //sdio/usb word allign ++ ++ //Save frame length ++ frm_len = le32_to_cpu(hw_rxhdr->hwvect.len); ++ ++ // Reserve space for frame ++ skb->len = frm_len; ++ ++ //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 ++ skb_monitor = ++ skb_copy_expand(skb, rtap_len, 0, GFP_ATOMIC); ++ skb_monitor->data += ++ (msdu_offset + 2); //sdio/usb word allign ++ ++ //Save frame length ++ frm_len = le32_to_cpu(hw_rxhdr->hwvect.len); ++#endif ++ } ++ ++ 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) { ++ 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) { ++ if (rxdesc) ++ 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); ++ ++ if (rxdesc) ++ hdr->h_proto = htons(rxdesc->frame_len - ++ sizeof(struct ethhdr)); ++ } ++ ++ goto end; ++ } ++ ++ /* Check if it must be discarded after informing upper layer */ ++ if (status & RX_STAT_SPURIOUS) { ++ struct ieee80211_hdr *hdr; ++ ++ hdr = (struct ieee80211_hdr *)(skb->data + msdu_offset); ++ rwnx_vif = rwnx_rx_get_vif(rwnx_hw, hw_rxhdr->flags_vif_idx); ++ if (rwnx_vif) { ++#ifdef CONFIG_GKI ++ rwnx_cfg80211_rx_spurious_frame(rwnx_vif->ndev, ++ hdr->addr2, GFP_ATOMIC); ++#else ++ /* flare-edge (6.18 port): link_id param added for MLO; ++ * -1 = "not applicable" (this driver has no MLO). */ ++ cfg80211_rx_spurious_frame(rwnx_vif->ndev, hdr->addr2, ++ -1, GFP_ATOMIC); ++#endif ++ } ++ goto end; ++ } ++ ++ /* Check if we need to forward the buffer */ ++ if (status & RX_STAT_FORWARD) { ++ rwnx_rx_vector_convert(rwnx_hw, &hw_rxhdr->hwvect.rx_vect1, ++ &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); ++ } else if ((skb->data[1] & 0x3) == 0x2) { //from ds ++ memcpy(ta, &skb->data[16], MAC_ADDR_LEN); ++ memcpy(ra, &skb->data[4], MAC_ADDR_LEN); ++ } ++ ++ pull_len += (hdr_len + 8); ++ ++ switch (hw_rxhdr->hwvect.decr_status) { ++ case RWNX_RX_HD_DECR_CCMP128: ++ pull_len += 8; //ccmp_header ++ //skb_pull(&skb->data[skb->len-8], 8); //ccmp_mic_len ++ memcpy(ether_type, &skb->data[hdr_len + 6 + 8], ++ 2); ++ break; ++ case RWNX_RX_HD_DECR_TKIP: ++ pull_len += 8; //tkip_header ++ memcpy(ether_type, &skb->data[hdr_len + 6 + 8], ++ 2); ++ break; ++ case RWNX_RX_HD_DECR_WEP: ++ pull_len += 4; //wep_header ++ memcpy(ether_type, &skb->data[hdr_len + 6 + 4], ++ 2); ++ break; ++ case RWNX_RX_HD_DECR_WAPI: ++ pull_len += 18; //wapi_header ++ memcpy(ether_type, &skb->data[hdr_len + 6 + 18], ++ 2); ++ break; ++ ++ default: ++ memcpy(ether_type, &skb->data[hdr_len + 6], 2); ++ break; ++ } ++ if (is_amsdu) ++ hw_rxhdr->flags_is_amsdu = 1; ++ else ++ hw_rxhdr->flags_is_amsdu = 0; ++ ++ if (is_amsdu) { ++#if 1 ++ skb_pull(skb, pull_len - 8); ++#else ++ 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; ++#endif ++ } ++ ++ 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,%d,sn=%d,%d\r\n", ++ (frame_ctrl & MAC_FCTRL_MOREFRAG), ++ frag_num, skb->len, seq_num, pull_len); ++ 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; ++ } ++ } ++ } ++ ++ //printk("rx frag: sn=%d, fn=%d, skb->len=%d\r\n", seq_num, frag_num, skb->len); ++ 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); ++ spin_unlock_bh( ++ &rwnx_hw->defrag_lock); ++ 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); ++ spin_unlock_bh( ++ &rwnx_hw->defrag_lock); ++ return 0; ++ } else { ++ defrag_info = kzalloc( ++ sizeof(struct defrag_ctrl_info), ++ GFP_KERNEL); ++ if (defrag_info == NULL) { ++ printk("no defrag_ctrl_info\r\n"); ++ dev_kfree_skb(skb); ++ spin_unlock_bh( ++ &rwnx_hw->defrag_lock); ++ return 0; ++ } ++ defrag_info->skb = ++ __dev_alloc_skb( ++ 2000, ++ GFP_KERNEL); ++ if (defrag_info->skb == NULL) { ++ printk("no fragment skb\r\n"); ++ dev_kfree_skb(skb); ++ kfree(defrag_info); ++ spin_unlock_bh( ++ &rwnx_hw->defrag_lock); ++ 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; ++ defrag_info->rwnx_hw = rwnx_hw; ++ //printk("first:%p,%p,%p,%p,%p, %d,%d\r\n", defrag_info, defrag_info->skb, defrag_info->skb->head, defrag_info->skb->tail, defrag_info->skb->end, defrag_info->frm_len, skb->len); ++ 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; ++ } ++ } ++ ++ if (!defrag_info) ++ spin_unlock_bh( ++ &rwnx_hw->defrag_lock); ++ else { ++ if (defrag_info ++ ->next_fn != ++ frag_num) { ++ printk("discard:%d:%d\n", ++ defrag_info ++ ->next_fn, ++ frag_num); ++ dev_kfree_skb( ++ skb); ++ spin_unlock_bh( ++ &rwnx_hw->defrag_lock); ++ 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); ++ ++ 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); ++ spin_unlock_bh( ++ &rwnx_hw->defrag_lock); ++ return 0; ++ } ++ dev_kfree_skb(skb); ++ ++ skb_tmp = ++ defrag_info->skb; ++ list_del_init( ++ &defrag_info ++ ->list); ++ if (timer_pending( ++ &defrag_info ++ ->defrag_timer)) { ++ ret = timer_delete( ++ &defrag_info ++ ->defrag_timer); ++ } ++ kfree(defrag_info); ++ spin_unlock_bh( ++ &rwnx_hw->defrag_lock); ++ ++ if (!rwnx_rx_data_skb( ++ rwnx_hw, ++ rwnx_vif, ++ skb_tmp, ++ hw_rxhdr)) ++ dev_kfree_skb( ++ skb_tmp); ++ ++ return 0; ++ } ++ } ++ } ++ } ++ ++ if (!is_frag && !is_amsdu) { ++ 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) { ++ remove_sec_hdr_mgmt_frame(hw_rxhdr, skb); ++ 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 end; ++ } ++ ++ 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 end; ++ } ++ } ++ ++ if (hw_rxhdr->flags_is_4addr && ++ !rwnx_vif->use_4addr) { ++#ifdef CONFIG_GKI ++ rwnx_cfg80211_rx_unexpected_4addr_frame( ++ rwnx_vif->ndev, sta->mac_addr, ++ GFP_ATOMIC); ++#else ++ /* flare-edge (6.18 port): link_id param ++ * added for MLO; -1 = n/a (no MLO). */ ++ cfg80211_rx_unexpected_4addr_frame( ++ rwnx_vif->ndev, sta->mac_addr, ++ -1, GFP_ATOMIC); ++#endif ++ } ++ } ++ ++ skb->priority = 256 + tid; //hw_rxhdr->flags_user_prio; ++ ++#ifdef AICWF_RX_REORDER ++ rx_priv_tmp = rx_priv; ++ rx_priv_tmp->rwnx_vif = (void *)rwnx_vif; ++ ++ 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, 1, ++ hw_rxhdr->flags_is_amsdu); ++ 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) && ++ !hw_rxhdr->flags_is_amsdu) ++ dev_kfree_skb(skb); ++ } else { ++ if (!rwnx_rx_data_skb(rwnx_hw, rwnx_vif, ++ skb, hw_rxhdr) && ++ !hw_rxhdr->flags_is_amsdu) ++ dev_kfree_skb(skb); ++ } ++ } else if ((rwnx_vif->wdev.iftype == ++ NL80211_IFTYPE_AP) || ++ (rwnx_vif->wdev.iftype == ++ NL80211_IFTYPE_P2P_GO)) { ++#if 1 ++ skb_reset_mac_header(skb); ++ eth = eth_hdr(skb); ++ //printk("da:%pM, %x,%x, len=%d\n", eth->h_dest, skb->data[12], skb->data[13], skb->len); ++ ++ if (unlikely(is_multicast_ether_addr( ++ eth->h_dest))) { ++ /* broadcast pkt need to be forwared to upper layer and resent ++ on wireless interface */ ++ resend = true; ++ } else { ++ /* unicast pkt for STA inside the BSS, no need to forward to upper ++ layer simply resend on wireless interface */ ++ if (hw_rxhdr->flags_dst_idx != ++ RWNX_INVALID_STA) { ++ struct rwnx_sta *sta = ++ &rwnx_hw->sta_table ++ [hw_rxhdr->flags_dst_idx]; ++ if (sta->valid && ++ (sta->vlan_idx == ++ rwnx_vif->vif_index)) { ++ resend = true; ++ forward = false; ++ } ++ } ++ } ++ ++ if (resend) ++ rwnx_rx_data_skb_resend(rwnx_hw, ++ rwnx_vif, skb, ++ hw_rxhdr); ++ ++ if (forward) { ++ if (is_qos && ++ hw_rxhdr->flags_need_reord) ++ reord_process_unit( ++ (struct aicwf_rx_priv *) ++ rx_priv, ++ skb, seq_num, tid, 1, ++ hw_rxhdr->flags_is_amsdu); ++ 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, ++ hw_rxhdr->flags_is_amsdu); ++ 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 ++ if (!rwnx_rx_data_skb(rwnx_hw, rwnx_vif, skb, ++ hw_rxhdr)) ++ dev_kfree_skb(skb); ++#endif ++ } ++#else ++ if (!rwnx_rx_data_skb(rwnx_hw, rwnx_vif, skb, hw_rxhdr)) ++ dev_kfree_skb(skb); ++#endif ++ } ++ } ++ ++end: ++ return 0; ++} +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_rx.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_rx.h +new file mode 100755 +index 000000000..2bafe2071 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_rx.h +@@ -0,0 +1,399 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_rx.h ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ ****************************************************************************** ++ */ ++#ifndef _RWNX_RX_H_ ++#define _RWNX_RX_H_ ++ ++#include "aicwf_txrxif.h" ++ ++#define SERVER_PORT 67 ++#define CLIENT_PORT 68 ++#define DHCP_MAGIC 0x63825363 ++#define DHCP_ACK 5 ++#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */ ++#define DHCP_OPTION_END 255 ++ ++enum rx_status_bits { ++ /// The buffer can be forwarded to the networking stack ++ RX_STAT_FORWARD = 1 << 0, ++ /// A new buffer has to be allocated ++ RX_STAT_ALLOC = 1 << 1, ++ /// The buffer has to be deleted ++ RX_STAT_DELETE = 1 << 2, ++ /// The length of the buffer has to be updated ++ RX_STAT_LEN_UPDATE = 1 << 3, ++ /// The length in the Ethernet header has to be updated ++ RX_STAT_ETH_LEN_UPDATE = 1 << 4, ++ /// Simple copy ++ RX_STAT_COPY = 1 << 5, ++ /// Spurious frame (inform upper layer and discard) ++ RX_STAT_SPURIOUS = 1 << 6, ++ /// packet for monitor interface ++ RX_STAT_MONITOR = 1 << 7, ++}; ++ ++/* ++ * Decryption status subfields. ++ * { ++ */ ++#define RWNX_RX_HD_DECR_UNENC 0 // ENCRYPTION TYPE NONE ++#define RWNX_RX_HD_DECR_WEP 1 // ENCRYPTION TYPE WEP ++#define RWNX_RX_HD_DECR_TKIP 2 // ENCRYPTION TYPE TKIP ++#define RWNX_RX_HD_DECR_CCMP128 3 // ENCRYPTION TYPE CCMP128 ++#define RWNX_RX_HD_DECR_CCMP256 4 // ENCRYPTION TYPE CCMP256 ++#define RWNX_RX_HD_DECR_GCMP128 5 // ENCRYPTION TYPE GCMP128 ++#define RWNX_RX_HD_DECR_GCMP256 6 // ENCRYPTION TYPE GCMP256 ++#define RWNX_RX_HD_DECR_WAPI 7 // ENCRYPTION TYPE WAPI ++// @} ++ ++//#ifdef CONFIG_RWNX_MON_DATA ++#if 0 ++#define RX_MACHDR_BACKUP_LEN 64 ++#endif ++ ++struct rx_vector_1_old { ++ /** Receive Vector 1a */ ++ u32 leg_length : 12; ++ u32 leg_rate : 4; ++ u32 ht_length : 16; ++ ++ /** Receive Vector 1b */ ++ u32 _ht_length : 4; // FIXME ++ u32 short_gi : 1; ++ u32 stbc : 2; ++ u32 smoothing : 1; ++ u32 mcs : 7; ++ u32 pre_type : 1; ++ u32 format_mod : 3; ++ u32 ch_bw : 2; ++ u32 n_sts : 3; ++ u32 lsig_valid : 1; ++ u32 sounding : 1; ++ u32 num_extn_ss : 2; ++ u32 aggregation : 1; ++ u32 fec_coding : 1; ++ u32 dyn_bw : 1; ++ u32 doze_not_allowed : 1; ++ ++ /** Receive Vector 1c */ ++ u32 antenna_set : 8; ++ u32 partial_aid : 9; ++ u32 group_id : 6; ++ u32 first_user : 1; ++ s32 rssi1 : 8; ++ ++ /** Receive Vector 1d */ ++ s32 rssi2 : 8; ++ s32 rssi3 : 8; ++ s32 rssi4 : 8; ++ u32 reserved_1d : 8; ++}; ++ ++struct rx_leg_vect { ++ u8 dyn_bw_in_non_ht : 1; ++ u8 chn_bw_in_non_ht : 2; ++ u8 rsvd_nht : 4; ++ u8 lsig_valid : 1; ++} __packed; ++ ++struct rx_ht_vect { ++ u16 sounding : 1; ++ u16 smoothing : 1; ++ u16 short_gi : 1; ++ u16 aggregation : 1; ++ u16 stbc : 1; ++ u16 num_extn_ss : 2; ++ u16 lsig_valid : 1; ++ u16 mcs : 7; ++ u16 fec : 1; ++ u16 length : 16; ++} __packed; ++ ++struct rx_vht_vect { ++ u8 sounding : 1; ++ u8 beamformed : 1; ++ u8 short_gi : 1; ++ u8 rsvd_vht1 : 1; ++ u8 stbc : 1; ++ u8 doze_not_allowed : 1; ++ u8 first_user : 1; ++ u8 rsvd_vht2 : 1; ++ u16 partial_aid : 9; ++ u16 group_id : 6; ++ u16 rsvd_vht3 : 1; ++ u32 mcs : 4; ++ u32 nss : 3; ++ u32 fec : 1; ++ u32 length : 20; ++ u32 rsvd_vht4 : 4; ++} __packed; ++ ++struct rx_he_vect { ++ u8 sounding : 1; ++ u8 beamformed : 1; ++ u8 gi_type : 2; ++ u8 stbc : 1; ++ u8 rsvd_he1 : 3; ++ ++ u8 uplink_flag : 1; ++ u8 beam_change : 1; ++ u8 dcm : 1; ++ u8 he_ltf_type : 2; ++ u8 doppler : 1; ++ u8 rsvd_he2 : 2; ++ ++ u8 bss_color : 6; ++ u8 rsvd_he3 : 2; ++ ++ u8 txop_duration : 7; ++ u8 rsvd_he4 : 1; ++ ++ u8 pe_duration : 4; ++ u8 spatial_reuse : 4; ++ ++ u8 sig_b_comp_mode : 1; ++ u8 dcm_sig_b : 1; ++ u8 mcs_sig_b : 3; ++ u8 ru_size : 3; ++ ++ u32 mcs : 4; ++ u32 nss : 3; ++ u32 fec : 1; ++ u32 length : 20; ++ u32 rsvd_he6 : 4; ++} __packed; ++ ++struct rx_vector_1 { ++ u8 format_mod : 4; ++ u8 ch_bw : 3; ++ u8 pre_type : 1; ++ u8 antenna_set : 8; ++ s32 rssi_leg : 8; ++ u32 leg_length : 12; ++ u32 leg_rate : 4; ++ s32 rssi1 : 8; ++ ++ union { ++ struct rx_leg_vect leg; ++ struct rx_ht_vect ht; ++ struct rx_vht_vect vht; ++ struct rx_he_vect he; ++ }; ++} __packed; ++ ++struct rx_vector_2_old { ++ /** Receive Vector 2a */ ++ u32 rcpi : 8; ++ u32 evm1 : 8; ++ u32 evm2 : 8; ++ u32 evm3 : 8; ++ ++ /** Receive Vector 2b */ ++ u32 evm4 : 8; ++ u32 reserved2b_1 : 8; ++ u32 reserved2b_2 : 8; ++ u32 reserved2b_3 : 8; ++}; ++ ++struct rx_vector_2 { ++ /** Receive Vector 2a */ ++ u32 rcpi1 : 8; ++ u32 rcpi2 : 8; ++ u32 rcpi3 : 8; ++ u32 rcpi4 : 8; ++ ++ /** Receive Vector 2b */ ++ u32 evm1 : 8; ++ u32 evm2 : 8; ++ u32 evm3 : 8; ++ u32 evm4 : 8; ++}; ++ ++struct phy_channel_info_desc { ++ /** PHY channel information 1 */ ++ u32 phy_band : 8; ++ u32 phy_channel_type : 8; ++ u32 phy_prim20_freq : 16; ++ /** PHY channel information 2 */ ++ u32 phy_center1_freq : 16; ++ u32 phy_center2_freq : 16; ++}; ++ ++struct hw_vect { ++ /** Total length for the MPDU transfer */ ++ u32 len : 16; ++ ++ u32 reserved : 8; //data type is included ++ /** AMPDU Status Information */ ++ u32 mpdu_cnt : 6; ++ u32 ampdu_cnt : 2; ++ ++ /** TSF Low */ ++ __le32 tsf_lo; ++ /** TSF High */ ++ __le32 tsf_hi; ++ ++ /** Receive Vector 1 */ ++ struct rx_vector_1 rx_vect1; ++ /** Receive Vector 2 */ ++ struct rx_vector_2 rx_vect2; ++ ++ /** Status **/ ++ u32 rx_vect2_valid : 1; ++ u32 resp_frame : 1; ++ /** Decryption Status */ ++ u32 decr_status : 3; ++ u32 rx_fifo_oflow : 1; ++ ++ /** Frame Unsuccessful */ ++ u32 undef_err : 1; ++ u32 phy_err : 1; ++ u32 fcs_err : 1; ++ u32 addr_mismatch : 1; ++ u32 ga_frame : 1; ++ u32 current_ac : 2; ++ ++ u32 frm_successful_rx : 1; ++ /** Descriptor Done */ ++ u32 desc_done_rx : 1; ++ /** Key Storage RAM Index */ ++ u32 key_sram_index : 10; ++ /** Key Storage RAM Index Valid */ ++ u32 key_sram_v : 1; ++ u32 type : 2; ++ u32 subtype : 4; ++}; ++ ++//#ifdef CONFIG_RWNX_MON_DATA ++#if 0 ++/// MAC header backup descriptor ++struct mon_machdrdesc { ++ /// Length of the buffer ++ u32 buf_len; ++ /// Buffer containing mac header, LLC and SNAP ++ u8 buffer[RX_MACHDR_BACKUP_LEN]; ++}; ++#endif ++ ++struct hw_rxhdr { ++ /** RX vector */ ++ struct hw_vect hwvect; ++ ++ /** PHY channel information */ ++ struct phy_channel_info_desc phy_info; ++ ++ /** RX flags */ ++ u32 flags_is_amsdu : 1; ++ u32 flags_is_80211_mpdu : 1; ++ u32 flags_is_4addr : 1; ++ u32 flags_new_peer : 1; ++#if defined(AICWF_SDIO_SUPPORT) || defined(AICWF_USB_SUPPORT) ++ u32 flags_user_prio : 1; // aic: fw not fill any more ++ u32 flags_need_reord : 1; ++ u32 flags_upload : 1; ++#else ++ u32 flags_user_prio : 3; ++#endif ++#ifndef AICWF_RX_REORDER ++ u32 flags_rsvd0 : 1; ++#else ++ u32 is_monitor_vif : 1; ++#endif ++ u32 flags_vif_idx : 8; // 0xFF if invalid VIF index ++ u32 flags_sta_idx : 8; // 0xFF if invalid STA index ++ u32 flags_dst_idx : 8; // 0xFF if unknown destination STA ++//#ifdef CONFIG_RWNX_MON_DATA ++#if 0 ++ /// MAC header backup descriptor (used only for MSDU when there is a monitor and a data interface) ++ struct mon_machdrdesc mac_hdr_backup; ++#endif ++ /** Pattern indicating if the buffer is available for the driver */ ++ u32 pattern; ++}; ++ ++struct rwnx_legrate { ++ int idx; ++ int rate; ++}; ++ ++extern struct rwnx_legrate legrates_lut[]; ++extern u16 tx_legrates_lut_rate[]; ++ ++struct DHCPInfo { ++ u8 op; ++ u8 htype; ++ u8 hlen; ++ u8 hops; ++ u32 xid; ++ u16 secs; ++ u16 flags; ++ u32 ciaddr; ++ u32 yiaddr; ++ u32 siaddr; ++ u32 giaddr; ++ u8 chaddr[16]; ++ u8 sname[64]; ++ u8 file[128]; ++ u32 cookie; ++ u8 options[308]; /* 312 - cookie */ ++}; ++ ++u8 rwnx_rxdataind_aicwf(struct rwnx_hw *rwnx_hw, void *hostid, void *rx_priv); ++int aicwf_process_rxframes(struct aicwf_rx_priv *rx_priv); ++ ++#ifdef AICWF_ARP_OFFLOAD ++void arpoffload_proc(struct sk_buff *skb, struct rwnx_vif *rwnx_vif); ++#endif ++#ifdef AICWF_RX_REORDER ++struct recv_msdu *reord_rxframe_alloc(spinlock_t *lock, struct list_head *q); ++void reord_rxframe_free(spinlock_t *lock, struct list_head *q, ++ struct list_head *list); ++struct reord_ctrl_info *reord_init_sta(struct aicwf_rx_priv *rx_priv, ++ const u8 *mac_addr); ++void reord_deinit_sta(struct aicwf_rx_priv *rx_priv, ++ struct reord_ctrl_info *reord_info); ++int reord_need_check(struct reord_ctrl *preorder_ctrl, u16 seq_num); ++int reord_rxframe_enqueue(struct reord_ctrl *preorder_ctrl, ++ struct recv_msdu *prframe); ++void reord_timeout_worker(struct work_struct *work); ++int reord_single_frame_ind(struct aicwf_rx_priv *rx_priv, ++ struct recv_msdu *prframe); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) ++void reord_timeout_handler(ulong data); ++#else ++void reord_timeout_handler(struct timer_list *t); ++#endif ++ ++#endif ++void rwnx_rxdata_process_amsdu(struct rwnx_hw *rwnx_hw, struct sk_buff *skb, ++ u8 vif_idx, struct sk_buff_head *list); ++ ++#ifdef CONFIG_HE_FOR_OLD_KERNEL ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 197) ++struct element { ++ u8 id; ++ u8 datalen; ++ u8 data[]; ++}; ++/* element iteration helpers */ ++#define for_each_element(_elem, _data, _datalen) \ ++ for (_elem = (const struct element *)(_data); \ ++ (const u8 *)(_data) + (_datalen) - (const u8 *)_elem >= \ ++ (int)sizeof(*_elem) && \ ++ (const u8 *)(_data) + (_datalen) - (const u8 *)_elem >= \ ++ (int)sizeof(*_elem) + _elem->datalen; \ ++ _elem = (const struct element *)(_elem->data + _elem->datalen)) ++ ++#define for_each_element_id(element, _id, data, datalen) \ ++ for_each_element (element, data, datalen) \ ++ if (element->id == (_id)) ++#endif ++#endif ++ ++#endif /* _RWNX_RX_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_strs.c b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_strs.c +new file mode 100755 +index 000000000..818995b1f +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_strs.c +@@ -0,0 +1,265 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_strs.c ++ * ++ * @brief Miscellaneous debug strings ++ * ++ * Copyright (C) RivieraWaves 2014-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++#include "lmac_msg.h" ++static const char *const rwnx_mmid2str[MSG_I(MM_MAX)] = { ++ [MSG_I(MM_RESET_REQ)] = "MM_RESET_REQ", ++ [MSG_I(MM_RESET_CFM)] = "MM_RESET_CFM", ++ [MSG_I(MM_START_REQ)] = "MM_START_REQ", ++ [MSG_I(MM_START_CFM)] = "MM_START_CFM", ++ [MSG_I(MM_VERSION_REQ)] = "MM_VERSION_REQ", ++ [MSG_I(MM_VERSION_CFM)] = "MM_VERSION_CFM", ++ [MSG_I(MM_ADD_IF_REQ)] = "MM_ADD_IF_REQ", ++ [MSG_I(MM_ADD_IF_CFM)] = "MM_ADD_IF_CFM", ++ [MSG_I(MM_REMOVE_IF_REQ)] = "MM_REMOVE_IF_REQ", ++ [MSG_I(MM_REMOVE_IF_CFM)] = "MM_REMOVE_IF_CFM", ++ [MSG_I(MM_STA_ADD_REQ)] = "MM_STA_ADD_REQ", ++ [MSG_I(MM_STA_ADD_CFM)] = "MM_STA_ADD_CFM", ++ [MSG_I(MM_STA_DEL_REQ)] = "MM_STA_DEL_REQ", ++ [MSG_I(MM_STA_DEL_CFM)] = "MM_STA_DEL_CFM", ++ [MSG_I(MM_SET_FILTER_REQ)] = "MM_SET_FILTER_REQ", ++ [MSG_I(MM_SET_FILTER_CFM)] = "MM_SET_FILTER_CFM", ++ [MSG_I(MM_SET_CHANNEL_REQ)] = "MM_SET_CHANNEL_REQ", ++ [MSG_I(MM_SET_CHANNEL_CFM)] = "MM_SET_CHANNEL_CFM", ++ [MSG_I(MM_SET_DTIM_REQ)] = "MM_SET_DTIM_REQ", ++ [MSG_I(MM_SET_DTIM_CFM)] = "MM_SET_DTIM_CFM", ++ [MSG_I(MM_SET_BEACON_INT_REQ)] = "MM_SET_BEACON_INT_REQ", ++ [MSG_I(MM_SET_BEACON_INT_CFM)] = "MM_SET_BEACON_INT_CFM", ++ [MSG_I(MM_SET_BASIC_RATES_REQ)] = "MM_SET_BASIC_RATES_REQ", ++ [MSG_I(MM_SET_BASIC_RATES_CFM)] = "MM_SET_BASIC_RATES_CFM", ++ [MSG_I(MM_SET_BSSID_REQ)] = "MM_SET_BSSID_REQ", ++ [MSG_I(MM_SET_BSSID_CFM)] = "MM_SET_BSSID_CFM", ++ [MSG_I(MM_SET_EDCA_REQ)] = "MM_SET_EDCA_REQ", ++ [MSG_I(MM_SET_EDCA_CFM)] = "MM_SET_EDCA_CFM", ++ [MSG_I(MM_SET_MODE_REQ)] = "MM_SET_MODE_REQ", ++ [MSG_I(MM_SET_MODE_CFM)] = "MM_SET_MODE_CFM", ++ [MSG_I(MM_SET_VIF_STATE_REQ)] = "MM_SET_VIF_STATE_REQ", ++ [MSG_I(MM_SET_VIF_STATE_CFM)] = "MM_SET_VIF_STATE_CFM", ++ [MSG_I(MM_SET_SLOTTIME_REQ)] = "MM_SET_SLOTTIME_REQ", ++ [MSG_I(MM_SET_SLOTTIME_CFM)] = "MM_SET_SLOTTIME_CFM", ++ [MSG_I(MM_SET_IDLE_REQ)] = "MM_SET_IDLE_REQ", ++ [MSG_I(MM_SET_IDLE_CFM)] = "MM_SET_IDLE_CFM", ++ [MSG_I(MM_KEY_ADD_REQ)] = "MM_KEY_ADD_REQ", ++ [MSG_I(MM_KEY_ADD_CFM)] = "MM_KEY_ADD_CFM", ++ [MSG_I(MM_KEY_DEL_REQ)] = "MM_KEY_DEL_REQ", ++ [MSG_I(MM_KEY_DEL_CFM)] = "MM_KEY_DEL_CFM", ++ [MSG_I(MM_BA_ADD_REQ)] = "MM_BA_ADD_REQ", ++ [MSG_I(MM_BA_ADD_CFM)] = "MM_BA_ADD_CFM", ++ [MSG_I(MM_BA_DEL_REQ)] = "MM_BA_DEL_REQ", ++ [MSG_I(MM_BA_DEL_CFM)] = "MM_BA_DEL_CFM", ++ [MSG_I(MM_PRIMARY_TBTT_IND)] = "MM_PRIMARY_TBTT_IND", ++ [MSG_I(MM_SECONDARY_TBTT_IND)] = "MM_SECONDARY_TBTT_IND", ++ [MSG_I(MM_SET_POWER_REQ)] = "MM_SET_POWER_REQ", ++ [MSG_I(MM_SET_POWER_CFM)] = "MM_SET_POWER_CFM", ++ [MSG_I(MM_DBG_TRIGGER_REQ)] = "MM_DBG_TRIGGER_REQ", ++ [MSG_I(MM_SET_PS_MODE_REQ)] = "MM_SET_PS_MODE_REQ", ++ [MSG_I(MM_SET_PS_MODE_CFM)] = "MM_SET_PS_MODE_CFM", ++ [MSG_I(MM_CHAN_CTXT_ADD_REQ)] = "MM_CHAN_CTXT_ADD_REQ", ++ [MSG_I(MM_CHAN_CTXT_ADD_CFM)] = "MM_CHAN_CTXT_ADD_CFM", ++ [MSG_I(MM_CHAN_CTXT_DEL_REQ)] = "MM_CHAN_CTXT_DEL_REQ", ++ [MSG_I(MM_CHAN_CTXT_DEL_CFM)] = "MM_CHAN_CTXT_DEL_CFM", ++ [MSG_I(MM_CHAN_CTXT_LINK_REQ)] = "MM_CHAN_CTXT_LINK_REQ", ++ [MSG_I(MM_CHAN_CTXT_LINK_CFM)] = "MM_CHAN_CTXT_LINK_CFM", ++ [MSG_I(MM_CHAN_CTXT_UNLINK_REQ)] = "MM_CHAN_CTXT_UNLINK_REQ", ++ [MSG_I(MM_CHAN_CTXT_UNLINK_CFM)] = "MM_CHAN_CTXT_UNLINK_CFM", ++ [MSG_I(MM_CHAN_CTXT_UPDATE_REQ)] = "MM_CHAN_CTXT_UPDATE_REQ", ++ [MSG_I(MM_CHAN_CTXT_UPDATE_CFM)] = "MM_CHAN_CTXT_UPDATE_CFM", ++ [MSG_I(MM_CHAN_CTXT_SCHED_REQ)] = "MM_CHAN_CTXT_SCHED_REQ", ++ [MSG_I(MM_CHAN_CTXT_SCHED_CFM)] = "MM_CHAN_CTXT_SCHED_CFM", ++ [MSG_I(MM_BCN_CHANGE_REQ)] = "MM_BCN_CHANGE_REQ", ++ [MSG_I(MM_BCN_CHANGE_CFM)] = "MM_BCN_CHANGE_CFM", ++ [MSG_I(MM_TIM_UPDATE_REQ)] = "MM_TIM_UPDATE_REQ", ++ [MSG_I(MM_TIM_UPDATE_CFM)] = "MM_TIM_UPDATE_CFM", ++ [MSG_I(MM_CONNECTION_LOSS_IND)] = "MM_CONNECTION_LOSS_IND", ++ [MSG_I(MM_CHANNEL_SWITCH_IND)] = "MM_CHANNEL_SWITCH_IND", ++ [MSG_I(MM_CHANNEL_PRE_SWITCH_IND)] = "MM_CHANNEL_PRE_SWITCH_IND", ++ [MSG_I(MM_REMAIN_ON_CHANNEL_REQ)] = "MM_REMAIN_ON_CHANNEL_REQ", ++ [MSG_I(MM_REMAIN_ON_CHANNEL_CFM)] = "MM_REMAIN_ON_CHANNEL_CFM", ++ [MSG_I(MM_REMAIN_ON_CHANNEL_EXP_IND)] = "MM_REMAIN_ON_CHANNEL_EXP_IND", ++ [MSG_I(MM_PS_CHANGE_IND)] = "MM_PS_CHANGE_IND", ++ [MSG_I(MM_TRAFFIC_REQ_IND)] = "MM_TRAFFIC_REQ_IND", ++ [MSG_I(MM_SET_PS_OPTIONS_REQ)] = "MM_SET_PS_OPTIONS_REQ", ++ [MSG_I(MM_SET_PS_OPTIONS_CFM)] = "MM_SET_PS_OPTIONS_CFM", ++ [MSG_I(MM_P2P_VIF_PS_CHANGE_IND)] = "MM_P2P_VIF_PS_CHANGE_IND", ++ [MSG_I(MM_CSA_COUNTER_IND)] = "MM_CSA_COUNTER_IND", ++ [MSG_I(MM_CHANNEL_SURVEY_IND)] = "MM_CHANNEL_SURVEY_IND", ++ [MSG_I(MM_SET_P2P_NOA_REQ)] = "MM_SET_P2P_NOA_REQ", ++ [MSG_I(MM_SET_P2P_OPPPS_REQ)] = "MM_SET_P2P_OPPPS_REQ", ++ [MSG_I(MM_SET_P2P_NOA_CFM)] = "MM_SET_P2P_NOA_CFM", ++ [MSG_I(MM_SET_P2P_OPPPS_CFM)] = "MM_SET_P2P_OPPPS_CFM", ++ [MSG_I(MM_CFG_RSSI_REQ)] = "MM_CFG_RSSI_REQ", ++ [MSG_I(MM_RSSI_STATUS_IND)] = "MM_RSSI_STATUS_IND", ++ [MSG_I(MM_CSA_FINISH_IND)] = "MM_CSA_FINISH_IND", ++ [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_LVL_REQ)] = "MM_SET_TXPWR_IDX_LVL_REQ", ++ [MSG_I(MM_SET_TXPWR_IDX_LVL_CFM)] = "MM_SET_TXPWR_IDX_LVL_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_VENDOR_HWCONFIG_REQ)] = "MM_SET_VENDOR_HWCONFIG_REQ", ++ [MSG_I(MM_SET_VENDOR_HWCONFIG_CFM)] = "MM_SET_VENDOR_HWCONFIG_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", ++ [MSG_I(MM_SET_RESUME_RESTORE_REQ)] = "MM_SET_RESUME_RESTORE_REQ", ++ [MSG_I(MM_SET_RESUME_RESTORE_CFM)] = "MM_SET_RESUME_RESTORE_CFM", ++ [MSG_I(MM_GET_WIFI_DISABLE_REQ)] = "MM_GET_WIFI_DISABLE_REQ", ++ [MSG_I(MM_GET_WIFI_DISABLE_CFM)] = "MM_GET_WIFI_DISABLE_CFM", ++ [MSG_I(MM_CFG_RSSI_CFM)] = "MM_CFG_RSSI_CFM", ++}; ++ ++static const char *const rwnx_dbgid2str[MSG_I(DBG_MAX)] = { ++ [MSG_I(DBG_MEM_READ_REQ)] = "DBG_MEM_READ_REQ", ++ [MSG_I(DBG_MEM_READ_CFM)] = "DBG_MEM_READ_CFM", ++ [MSG_I(DBG_MEM_WRITE_REQ)] = "DBG_MEM_WRITE_REQ", ++ [MSG_I(DBG_MEM_WRITE_CFM)] = "DBG_MEM_WRITE_CFM", ++ [MSG_I(DBG_SET_MOD_FILTER_REQ)] = "DBG_SET_MOD_FILTER_REQ", ++ [MSG_I(DBG_SET_MOD_FILTER_CFM)] = "DBG_SET_MOD_FILTER_CFM", ++ [MSG_I(DBG_SET_SEV_FILTER_REQ)] = "DBG_SET_SEV_FILTER_REQ", ++ [MSG_I(DBG_SET_SEV_FILTER_CFM)] = "DBG_SET_SEV_FILTER_CFM", ++ [MSG_I(DBG_ERROR_IND)] = "DBG_ERROR_IND", ++ [MSG_I(DBG_GET_SYS_STAT_REQ)] = "DBG_GET_SYS_STAT_REQ", ++ [MSG_I(DBG_GET_SYS_STAT_CFM)] = "DBG_GET_SYS_STAT_CFM", ++}; ++ ++static const char *const rwnx_scanid2str[MSG_I(SCAN_MAX)] = { ++ [MSG_I(SCAN_START_REQ)] = "SCAN_START_REQ", ++ [MSG_I(SCAN_START_CFM)] = "SCAN_START_CFM", ++ [MSG_I(SCAN_DONE_IND)] = "SCAN_DONE_IND", ++}; ++ ++static const char *const rwnx_tdlsid2str[MSG_I(TDLS_MAX)] = { ++ [MSG_I(TDLS_CHAN_SWITCH_CFM)] = "TDLS_CHAN_SWITCH_CFM", ++ [MSG_I(TDLS_CHAN_SWITCH_REQ)] = "TDLS_CHAN_SWITCH_REQ", ++ [MSG_I(TDLS_CHAN_SWITCH_IND)] = "TDLS_CHAN_SWITCH_IND", ++ [MSG_I(TDLS_CHAN_SWITCH_BASE_IND)] = "TDLS_CHAN_SWITCH_BASE_IND", ++ [MSG_I(TDLS_CANCEL_CHAN_SWITCH_REQ)] = "TDLS_CANCEL_CHAN_SWITCH_REQ", ++ [MSG_I(TDLS_CANCEL_CHAN_SWITCH_CFM)] = "TDLS_CANCEL_CHAN_SWITCH_CFM", ++ [MSG_I(TDLS_PEER_PS_IND)] = "TDLS_PEER_PS_IND", ++ [MSG_I(TDLS_PEER_TRAFFIC_IND_REQ)] = "TDLS_PEER_TRAFFIC_IND_REQ", ++ [MSG_I(TDLS_PEER_TRAFFIC_IND_CFM)] = "TDLS_PEER_TRAFFIC_IND_CFM", ++}; ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ ++static const char *const rwnx_scanuid2str[MSG_I(SCANU_MAX)] = { ++ [MSG_I(SCANU_START_REQ)] = "SCANU_START_REQ", ++ [MSG_I(SCANU_START_CFM)] = "SCANU_START_CFM", ++ [MSG_I(SCANU_JOIN_REQ)] = "SCANU_JOIN_REQ", ++ [MSG_I(SCANU_JOIN_CFM)] = "SCANU_JOIN_CFM", ++ [MSG_I(SCANU_RESULT_IND)] = "SCANU_RESULT_IND", ++ [MSG_I(SCANU_FAST_REQ)] = "SCANU_FAST_REQ", ++ [MSG_I(SCANU_FAST_CFM)] = "SCANU_FAST_CFM", ++ [MSG_I(SCANU_VENDOR_IE_REQ)] = "SCANU_VENDOR_IE_REQ", ++ [MSG_I(SCANU_VENDOR_IE_CFM)] = "SCANU_VENDOR_IE_CFM", ++ [MSG_I(SCANU_START_CFM_ADDTIONAL)] = "SCANU_START_CFM_ADDTIONAL", ++ [MSG_I(SCANU_CANCEL_REQ)] = "SCANU_CANCEL_REQ", ++ [MSG_I(SCANU_CANCEL_CFM)] = "SCANU_CANCEL_CFM", ++}; ++ ++static const char *const rwnx_meid2str[MSG_I(ME_MAX)] = { ++ [MSG_I(ME_CONFIG_REQ)] = "ME_CONFIG_REQ", ++ [MSG_I(ME_CONFIG_CFM)] = "ME_CONFIG_CFM", ++ [MSG_I(ME_CHAN_CONFIG_REQ)] = "ME_CHAN_CONFIG_REQ", ++ [MSG_I(ME_CHAN_CONFIG_CFM)] = "ME_CHAN_CONFIG_CFM", ++ [MSG_I(ME_SET_CONTROL_PORT_REQ)] = "ME_SET_CONTROL_PORT_REQ", ++ [MSG_I(ME_SET_CONTROL_PORT_CFM)] = "ME_SET_CONTROL_PORT_CFM", ++ [MSG_I(ME_TKIP_MIC_FAILURE_IND)] = "ME_TKIP_MIC_FAILURE_IND", ++ [MSG_I(ME_STA_ADD_REQ)] = "ME_STA_ADD_REQ", ++ [MSG_I(ME_STA_ADD_CFM)] = "ME_STA_ADD_CFM", ++ [MSG_I(ME_STA_DEL_REQ)] = "ME_STA_DEL_REQ", ++ [MSG_I(ME_STA_DEL_CFM)] = "ME_STA_DEL_CFM", ++ [MSG_I(ME_TX_CREDITS_UPDATE_IND)] = "ME_TX_CREDITS_UPDATE_IND", ++ [MSG_I(ME_RC_STATS_REQ)] = "ME_RC_STATS_REQ", ++ [MSG_I(ME_RC_STATS_CFM)] = "ME_RC_STATS_CFM", ++ [MSG_I(ME_RC_SET_RATE_REQ)] = "ME_RC_SET_RATE_REQ", ++ [MSG_I(ME_TRAFFIC_IND_REQ)] = "ME_TRAFFIC_IND_REQ", ++ [MSG_I(ME_TRAFFIC_IND_CFM)] = "ME_TRAFFIC_IND_CFM", ++ [MSG_I(ME_SET_PS_MODE_REQ)] = "ME_SET_PS_MODE_REQ", ++ [MSG_I(ME_SET_PS_MODE_CFM)] = "ME_SET_PS_MODE_CFM", ++}; ++ ++static const char *const rwnx_smid2str[MSG_I(SM_MAX)] = { ++ [MSG_I(SM_CONNECT_REQ)] = "SM_CONNECT_REQ", ++ [MSG_I(SM_CONNECT_CFM)] = "SM_CONNECT_CFM", ++ [MSG_I(SM_CONNECT_IND)] = "SM_CONNECT_IND", ++ [MSG_I(SM_DISCONNECT_REQ)] = "SM_DISCONNECT_REQ", ++ [MSG_I(SM_DISCONNECT_CFM)] = "SM_DISCONNECT_CFM", ++ [MSG_I(SM_DISCONNECT_IND)] = "SM_DISCONNECT_IND", ++ [MSG_I(SM_EXTERNAL_AUTH_REQUIRED_IND)] = ++ "SM_EXTERNAL_AUTH_REQUIRED_IND", ++ [MSG_I(SM_EXTERNAL_AUTH_REQUIRED_RSP)] = ++ "SM_EXTERNAL_AUTH_REQUIRED_RSP", ++ [MSG_I(SM_EXTERNAL_AUTH_REQUIRED_RSP_CFM)] = ++ "SM_EXTERNAL_AUTH_REQUIRED_RSP_CFM", ++}; ++ ++static const char *const rwnx_apmid2str[MSG_I(APM_MAX)] = { ++ [MSG_I(APM_START_REQ)] = "APM_START_REQ", ++ [MSG_I(APM_START_CFM)] = "APM_START_CFM", ++ [MSG_I(APM_STOP_REQ)] = "APM_STOP_REQ", ++ [MSG_I(APM_STOP_CFM)] = "APM_STOP_CFM", ++ [MSG_I(APM_START_CAC_REQ)] = "APM_START_CAC_REQ", ++ [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)] = { ++ [MSG_I(MESH_START_REQ)] = "MESH_START_REQ", ++ [MSG_I(MESH_START_CFM)] = "MESH_START_CFM", ++ [MSG_I(MESH_STOP_REQ)] = "MESH_STOP_REQ", ++ [MSG_I(MESH_STOP_CFM)] = "MESH_STOP_CFM", ++ [MSG_I(MESH_UPDATE_REQ)] = "MESH_UPDATE_REQ", ++ [MSG_I(MESH_UPDATE_CFM)] = "MESH_UPDATE_CFM", ++ [MSG_I(MESH_PATH_CREATE_REQ)] = "MESH_PATH_CREATE_REQ", ++ [MSG_I(MESH_PATH_CREATE_CFM)] = "MESH_PATH_CREATE_CFM", ++ [MSG_I(MESH_PATH_UPDATE_REQ)] = "MESH_PATH_UPDATE_REQ", ++ [MSG_I(MESH_PATH_UPDATE_CFM)] = "MESH_PATH_UPDATE_CFM", ++ [MSG_I(MESH_PROXY_ADD_REQ)] = "MESH_PROXY_ADD_REQ", ++ [MSG_I(MESH_PEER_UPDATE_IND)] = "MESH_PEER_UPDATE_IND", ++ [MSG_I(MESH_PATH_UPDATE_IND)] = "MESH_PATH_UPDATE_IND", ++ [MSG_I(MESH_PROXY_UPDATE_IND)] = "MESH_PROXY_UPDATE_IND", ++}; ++ ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++const char *const *rwnx_id2str[TASK_LAST_EMB + 1] = { ++ [TASK_MM] = rwnx_mmid2str, [TASK_DBG] = rwnx_dbgid2str, ++ [TASK_SCAN] = rwnx_scanid2str, [TASK_TDLS] = rwnx_tdlsid2str, ++#ifdef CONFIG_RWNX_FULLMAC ++ [TASK_SCANU] = rwnx_scanuid2str, [TASK_ME] = rwnx_meid2str, ++ [TASK_SM] = rwnx_smid2str, [TASK_APM] = rwnx_apmid2str, ++ [TASK_MESH] = rwnx_meshid2str, ++#endif ++}; +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_strs.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_strs.h +new file mode 100755 +index 000000000..6aec43dbc +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_strs.h +@@ -0,0 +1,33 @@ ++/** ++ **************************************************************************************** ++ * ++ * @file rwnx_strs.h ++ * ++ * @brief Miscellaneous debug strings ++ * ++ * Copyright (C) RivieraWaves 2014-2019 ++ * ++ **************************************************************************************** ++ */ ++ ++#ifndef _RWNX_STRS_H_ ++#define _RWNX_STRS_H_ ++ ++#ifdef CONFIG_RWNX_FHOST ++ ++#define RWNX_ID2STR(tag) "Cmd" ++ ++#else ++#include "lmac_msg.h" ++ ++#define RWNX_ID2STR(tag) \ ++ (((MSG_T(tag) < ARRAY_SIZE(rwnx_id2str)) && \ ++ (rwnx_id2str[MSG_T(tag)]) && \ ++ ((rwnx_id2str[MSG_T(tag)])[MSG_I(tag)])) ? \ ++ (rwnx_id2str[MSG_T(tag)])[MSG_I(tag)] : \ ++ "unknown") ++ ++extern const char *const *rwnx_id2str[TASK_LAST_EMB + 1]; ++#endif /* CONFIG_RWNX_FHOST */ ++ ++#endif /* _RWNX_STRS_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_tdls.c b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_tdls.c +new file mode 100755 +index 000000000..905213e9a +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_tdls.c +@@ -0,0 +1,810 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_tx.c ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++/** ++ * INCLUDE FILES ++ ****************************************************************************** ++ */ ++ ++#include "rwnx_tdls.h" ++#include "rwnx_compat.h" ++ ++/** ++ * FUNCTION DEFINITIONS ++ ****************************************************************************** ++ */ ++ ++static u16 rwnx_get_tdls_sta_capab(struct rwnx_vif *rwnx_vif, u16 status_code) ++{ ++ u16 capab = 0; ++ ++ /* The capability will be 0 when sending a failure code */ ++ if (status_code != 0) ++ return capab; ++ ++ if (rwnx_vif->sta.ap->band != NL80211_BAND_2GHZ) ++ return capab; ++ ++ capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; ++ capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; ++ ++ return capab; ++} ++ ++static int rwnx_tdls_prepare_encap_data(struct rwnx_hw *rwnx_hw, ++ struct rwnx_vif *rwnx_vif, ++ const u8 *peer, u8 action_code, ++ u8 dialog_token, u16 status_code, ++ struct sk_buff *skb) ++{ ++ struct ieee80211_tdls_data *tf; ++ tf = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_data) - ++ sizeof(tf->u)); ++ ++ // set eth header ++ memcpy(tf->da, peer, ETH_ALEN); ++ memcpy(tf->sa, rwnx_hw->wiphy->perm_addr, ETH_ALEN); ++ tf->ether_type = cpu_to_be16(ETH_P_TDLS); ++ ++ // set common TDLS info ++ tf->payload_type = WLAN_TDLS_SNAP_RFTYPE; ++ tf->category = WLAN_CATEGORY_TDLS; ++ tf->action_code = action_code; ++ ++ // set action specific TDLS info ++ switch (action_code) { ++ case WLAN_TDLS_SETUP_REQUEST: ++ skb_put(skb, sizeof(tf->u.setup_req)); ++ tf->u.setup_req.dialog_token = dialog_token; ++ tf->u.setup_req.capability = cpu_to_le16( ++ rwnx_get_tdls_sta_capab(rwnx_vif, status_code)); ++ break; ++ ++ case WLAN_TDLS_SETUP_RESPONSE: ++ skb_put(skb, sizeof(tf->u.setup_resp)); ++ tf->u.setup_resp.status_code = cpu_to_le16(status_code); ++ tf->u.setup_resp.dialog_token = dialog_token; ++ tf->u.setup_resp.capability = cpu_to_le16( ++ rwnx_get_tdls_sta_capab(rwnx_vif, status_code)); ++ break; ++ ++ case WLAN_TDLS_SETUP_CONFIRM: ++ skb_put(skb, sizeof(tf->u.setup_cfm)); ++ tf->u.setup_cfm.status_code = cpu_to_le16(status_code); ++ tf->u.setup_cfm.dialog_token = dialog_token; ++ break; ++ ++ case WLAN_TDLS_TEARDOWN: ++ skb_put(skb, sizeof(tf->u.teardown)); ++ tf->u.teardown.reason_code = cpu_to_le16(status_code); ++ break; ++ ++ case WLAN_TDLS_DISCOVERY_REQUEST: ++ skb_put(skb, sizeof(tf->u.discover_req)); ++ tf->u.discover_req.dialog_token = dialog_token; ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int rwnx_prep_tdls_direct(struct rwnx_hw *rwnx_hw, ++ struct rwnx_vif *rwnx_vif, const u8 *peer, ++ u8 action_code, u8 dialog_token, ++ u16 status_code, struct sk_buff *skb) ++{ ++ struct ieee80211_mgmt *mgmt; ++ ++ mgmt = (void *)skb_put(skb, 24); ++ memset(mgmt, 0, 24); ++ memcpy(mgmt->da, peer, ETH_ALEN); ++ memcpy(mgmt->sa, rwnx_hw->wiphy->perm_addr, ETH_ALEN); ++ memcpy(mgmt->bssid, rwnx_vif->sta.ap->mac_addr, ETH_ALEN); ++ ++ mgmt->frame_control = ++ cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION); ++ ++ switch (action_code) { ++ case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: ++ skb_put(skb, 1 + sizeof(mgmt->u.action.u.tdls_discover_resp)); ++ mgmt->u.action.category = WLAN_CATEGORY_PUBLIC; ++ mgmt->u.action.u.tdls_discover_resp.action_code = ++ WLAN_PUB_ACTION_TDLS_DISCOVER_RES; ++ mgmt->u.action.u.tdls_discover_resp.dialog_token = dialog_token; ++ mgmt->u.action.u.tdls_discover_resp.capability = cpu_to_le16( ++ rwnx_get_tdls_sta_capab(rwnx_vif, status_code)); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int rwnx_add_srates_ie(struct rwnx_hw *rwnx_hw, struct sk_buff *skb) ++{ ++ u8 i, rates, *pos; ++ int rate; ++ struct ieee80211_supported_band *rwnx_band_2GHz = ++ rwnx_hw->wiphy->bands[NL80211_BAND_2GHZ]; ++ ++ rates = 8; ++ ++ if (skb_tailroom(skb) < rates + 2) ++ return -ENOMEM; ++ ++ pos = skb_put(skb, rates + 2); ++ *pos++ = WLAN_EID_SUPP_RATES; ++ *pos++ = rates; ++ for (i = 0; i < rates; i++) { ++ rate = rwnx_band_2GHz->bitrates[i].bitrate; ++ rate = DIV_ROUND_UP(rate, 5); ++ *pos++ = (u8)rate; ++ } ++ ++ return 0; ++} ++ ++static int rwnx_add_ext_srates_ie(struct rwnx_hw *rwnx_hw, struct sk_buff *skb) ++{ ++ u8 i, exrates, *pos; ++ int rate; ++ struct ieee80211_supported_band *rwnx_band_2GHz = ++ rwnx_hw->wiphy->bands[NL80211_BAND_2GHZ]; ++ ++ exrates = rwnx_band_2GHz->n_bitrates - 8; ++ ++ if (skb_tailroom(skb) < exrates + 2) ++ return -ENOMEM; ++ ++ pos = skb_put(skb, exrates + 2); ++ *pos++ = WLAN_EID_EXT_SUPP_RATES; ++ *pos++ = exrates; ++ for (i = 8; i < (8 + exrates); i++) { ++ rate = rwnx_band_2GHz->bitrates[i].bitrate; ++ rate = DIV_ROUND_UP(rate, 5); ++ *pos++ = (u8)rate; ++ } ++ ++ return 0; ++} ++ ++static void rwnx_tdls_add_supp_channels(struct rwnx_hw *rwnx_hw, ++ struct sk_buff *skb) ++{ ++ /* ++ * Add possible channels for TDLS. These are channels that are allowed ++ * to be active. ++ */ ++ u8 subband_cnt = 0; ++ u8 *pos_subband; ++ u8 *pos = skb_put(skb, 2); ++ 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]; ++ ++ *pos++ = WLAN_EID_SUPPORTED_CHANNELS; ++ ++ /* ++ * 5GHz and 2GHz channels numbers can overlap. Ignore this for now, as ++ * this doesn't happen in real world scenarios. ++ */ ++ ++ /* 2GHz, with 5MHz spacing */ ++ pos_subband = skb_put(skb, 2); ++ if (rwnx_band_2GHz->n_channels > 0) { ++ *pos_subband++ = ieee80211_frequency_to_channel( ++ rwnx_band_2GHz->channels[0].center_freq); ++ *pos_subband++ = rwnx_band_2GHz->n_channels; ++ subband_cnt++; ++ } ++ ++ /* 5GHz, with 20MHz spacing */ ++ pos_subband = skb_put(skb, 2); ++ if (rwnx_hw->band_5g_support) { ++ if (rwnx_band_5GHz->n_channels > 0) { ++ *pos_subband++ = ieee80211_frequency_to_channel( ++ rwnx_band_5GHz->channels[0].center_freq); ++ *pos_subband++ = rwnx_band_5GHz->n_channels; ++ subband_cnt++; ++ } ++ } ++ /* length */ ++ *pos = 2 * subband_cnt; ++} ++ ++static void rwnx_tdls_add_ext_capab(struct rwnx_hw *rwnx_hw, ++ struct sk_buff *skb) ++{ ++ u8 *pos = (void *)skb_put(skb, 7); ++ bool chan_switch = ++ rwnx_hw->wiphy->features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH; ++ ++ *pos++ = WLAN_EID_EXT_CAPABILITY; ++ *pos++ = 5; /* len */ ++ *pos++ = 0x0; ++ *pos++ = 0x0; ++ *pos++ = 0x0; ++ *pos++ = WLAN_EXT_CAPA4_TDLS_BUFFER_STA | ++ (chan_switch ? WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH : 0); ++ *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED; ++} ++ ++static void rwnx_add_wmm_info_ie(struct sk_buff *skb, u8 qosinfo) ++{ ++ u8 *pos = (void *)skb_put(skb, 9); ++ ++ *pos++ = WLAN_EID_VENDOR_SPECIFIC; ++ *pos++ = 7; /* len */ ++ *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ ++ *pos++ = 0x50; ++ *pos++ = 0xf2; ++ *pos++ = 2; /* WME */ ++ *pos++ = 0; /* WME info */ ++ *pos++ = 1; /* WME ver */ ++ *pos++ = qosinfo; /* U-APSD no in use */ ++} ++ ++/* translate numbering in the WMM parameter IE to the mac80211 notation */ ++static u8 rwnx_ac_from_wmm(int ac) ++{ ++ switch (ac) { ++ default: ++ WARN_ON_ONCE(1); ++ case 0: ++ return AC_BE; ++ case 1: ++ return AC_BK; ++ case 2: ++ return AC_VI; ++ case 3: ++ return AC_VO; ++ } ++} ++ ++static void rwnx_add_wmm_param_ie(struct sk_buff *skb, u8 acm_bits, ++ u32 *ac_params) ++{ ++ struct ieee80211_wmm_param_ie *wmm; ++ int i, j; ++ u8 cw_min, cw_max; ++ bool acm; ++ ++ wmm = (void *)skb_put(skb, sizeof(struct ieee80211_wmm_param_ie)); ++ memset(wmm, 0, sizeof(*wmm)); ++ ++ wmm->element_id = WLAN_EID_VENDOR_SPECIFIC; ++ wmm->len = sizeof(*wmm) - 2; ++ ++ wmm->oui[0] = 0x00; /* Microsoft OUI 00:50:F2 */ ++ wmm->oui[1] = 0x50; ++ wmm->oui[2] = 0xf2; ++ wmm->oui_type = 2; /* WME */ ++ wmm->oui_subtype = 1; /* WME param */ ++ wmm->version = 1; /* WME ver */ ++ wmm->qos_info = 0; /* U-APSD not in use */ ++ ++ /* ++ * Use the EDCA parameters defined for the BSS, or default if the AP ++ * doesn't support it, as mandated by 802.11-2012 section 10.22.4 ++ */ ++ for (i = 0; i < AC_MAX; i++) { ++ j = rwnx_ac_from_wmm(i); ++ cw_min = (ac_params[j] & 0xF0) >> 4; ++ cw_max = (ac_params[j] & 0xF00) >> 8; ++ acm = (acm_bits & (1 << j)) != 0; ++ ++ wmm->ac[i].aci_aifsn = ++ (i << 5) | (acm << 4) | (ac_params[j] & 0xF); ++ wmm->ac[i].cw = (cw_max << 4) | cw_min; ++ wmm->ac[i].txop_limit = (ac_params[j] & 0x0FFFF000) >> 12; ++ } ++} ++ ++static void rwnx_tdls_add_oper_classes(struct rwnx_vif *rwnx_vif, ++ struct sk_buff *skb) ++{ ++ u8 *pos; ++ u8 op_class; ++ struct cfg80211_chan_def chan_def; ++ struct ieee80211_channel chan; ++ ++ chan.band = rwnx_vif->sta.ap->band; ++ chan.center_freq = rwnx_vif->sta.ap->center_freq; ++ chan_def.chan = &chan; ++ chan_def.width = rwnx_vif->sta.ap->width; ++ chan_def.center_freq1 = rwnx_vif->sta.ap->center_freq1; ++ chan_def.center_freq2 = rwnx_vif->sta.ap->center_freq2; ++#ifdef CONFIG_GKI ++ if (!rwnx_ieee80211_chandef_to_operating_class(&chan_def, &op_class)) ++#else ++ if (!ieee80211_chandef_to_operating_class(&chan_def, &op_class)) ++#endif ++ return; ++ ++ pos = skb_put(skb, 4); ++ *pos++ = WLAN_EID_SUPPORTED_REGULATORY_CLASSES; ++ *pos++ = 2; /* len */ ++ ++ // current op class ++ *pos++ = op_class; ++ *pos++ = op_class; /* give current operating class as alternate too */ ++ ++ // need to add 5GHz classes? ++} ++ ++static void rwnx_ie_build_ht_cap(struct sk_buff *skb, ++ struct ieee80211_sta_ht_cap *ht_cap, u16 cap) ++{ ++ u8 *pos; ++ __le16 tmp; ++ ++ pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); ++ *pos++ = WLAN_EID_HT_CAPABILITY; ++ *pos++ = sizeof(struct ieee80211_ht_cap); ++ memset(pos, 0, sizeof(struct ieee80211_ht_cap)); ++ ++ /* capability flags */ ++ tmp = cpu_to_le16(cap); ++ memcpy(pos, &tmp, sizeof(u16)); ++ pos += sizeof(u16); ++ ++ /* AMPDU parameters */ ++ *pos++ = ht_cap->ampdu_factor | ++ (ht_cap->ampdu_density ++ << IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); ++ ++ /* MCS set */ ++ memcpy(pos, &ht_cap->mcs, sizeof(ht_cap->mcs)); ++ pos += sizeof(ht_cap->mcs); ++ ++ /* extended capabilities */ ++ pos += sizeof(__le16); ++ ++ /* BF capabilities */ ++ pos += sizeof(__le32); ++ ++ /* antenna selection */ ++ pos += sizeof(u8); ++} ++ ++static void rwnx_ie_build_vht_cap(struct sk_buff *skb, ++ struct ieee80211_sta_vht_cap *vht_cap, ++ u32 cap) ++{ ++ u8 *pos; ++ __le32 tmp; ++ ++ pos = skb_put(skb, 14); ++ ++ *pos++ = WLAN_EID_VHT_CAPABILITY; ++ *pos++ = sizeof(struct ieee80211_vht_cap); ++ memset(pos, 0, sizeof(struct ieee80211_vht_cap)); ++ ++ /* capability flags */ ++ tmp = cpu_to_le32(cap); ++ memcpy(pos, &tmp, sizeof(u32)); ++ pos += sizeof(u32); ++ ++ /* VHT MCS set */ ++ memcpy(pos, &vht_cap->vht_mcs, sizeof(vht_cap->vht_mcs)); ++ pos += sizeof(vht_cap->vht_mcs); ++} ++ ++static void rwnx_tdls_add_bss_coex_ie(struct sk_buff *skb) ++{ ++ u8 *pos = (void *)skb_put(skb, 3); ++ ++ *pos++ = WLAN_EID_BSS_COEX_2040; ++ *pos++ = 1; /* len */ ++ ++ *pos++ = WLAN_BSS_COEX_INFORMATION_REQUEST; ++} ++ ++static void rwnx_tdls_add_link_ie(struct rwnx_hw *rwnx_hw, ++ struct rwnx_vif *rwnx_vif, ++ struct sk_buff *skb, const u8 *peer, ++ bool initiator) ++{ ++ struct ieee80211_tdls_lnkie *lnkid; ++ const u8 *init_addr, *rsp_addr; ++ ++ if (initiator) { ++ init_addr = rwnx_hw->wiphy->perm_addr; ++ rsp_addr = peer; ++ } else { ++ init_addr = peer; ++ rsp_addr = rwnx_hw->wiphy->perm_addr; ++ } ++ ++ lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie)); ++ ++ lnkid->ie_type = WLAN_EID_LINK_ID; ++ lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2; ++ ++ memcpy(lnkid->bssid, rwnx_vif->sta.ap->mac_addr, ETH_ALEN); ++ memcpy(lnkid->init_sta, init_addr, ETH_ALEN); ++ memcpy(lnkid->resp_sta, rsp_addr, ETH_ALEN); ++} ++ ++static void rwnx_tdls_add_aid_ie(struct rwnx_vif *rwnx_vif, struct sk_buff *skb) ++{ ++ u8 *pos = (void *)skb_put(skb, 4); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) ++ *pos++ = WLAN_EID_AID; ++#else ++ *pos++ = 197; ++#endif ++ *pos++ = 2; /* len */ ++ *pos++ = rwnx_vif->sta.ap->aid; ++} ++ ++static u8 *rwnx_ie_build_ht_oper(struct rwnx_hw *rwnx_hw, ++ struct rwnx_vif *rwnx_vif, u8 *pos, ++ struct ieee80211_sta_ht_cap *ht_cap, ++ u16 prot_mode) ++{ ++ struct ieee80211_ht_operation *ht_oper; ++ /* Build HT Information */ ++ *pos++ = WLAN_EID_HT_OPERATION; ++ *pos++ = sizeof(struct ieee80211_ht_operation); ++ ht_oper = (struct ieee80211_ht_operation *)pos; ++ ht_oper->primary_chan = ++ ieee80211_frequency_to_channel(rwnx_vif->sta.ap->center_freq); ++ switch (rwnx_vif->sta.ap->width) { ++ case NL80211_CHAN_WIDTH_160: ++ case NL80211_CHAN_WIDTH_80P80: ++ case NL80211_CHAN_WIDTH_80: ++ case NL80211_CHAN_WIDTH_40: ++ if (rwnx_vif->sta.ap->center_freq1 > ++ rwnx_vif->sta.ap->center_freq) ++ ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; ++ else ++ ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW; ++ break; ++ default: ++ ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE; ++ break; ++ } ++ if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 && ++ rwnx_vif->sta.ap->width != NL80211_CHAN_WIDTH_20_NOHT && ++ rwnx_vif->sta.ap->width != NL80211_CHAN_WIDTH_20) ++ ht_oper->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; ++ ++ ht_oper->operation_mode = cpu_to_le16(prot_mode); ++ ht_oper->stbc_param = 0x0000; ++ ++ /* It seems that Basic MCS set and Supported MCS set ++ are identical for the first 10 bytes */ ++ memset(&ht_oper->basic_set, 0, 16); ++ memcpy(&ht_oper->basic_set, &ht_cap->mcs, 10); ++ ++ return pos + sizeof(struct ieee80211_ht_operation); ++} ++ ++static u8 *rwnx_ie_build_vht_oper(struct rwnx_hw *rwnx_hw, ++ struct rwnx_vif *rwnx_vif, u8 *pos, ++ struct ieee80211_sta_ht_cap *ht_cap, ++ u16 prot_mode) ++{ ++ struct ieee80211_vht_operation *vht_oper; ++ /* Build HT Information */ ++ *pos++ = WLAN_EID_VHT_OPERATION; ++ *pos++ = sizeof(struct ieee80211_vht_operation); ++ vht_oper = (struct ieee80211_vht_operation *)pos; ++ ++ switch (rwnx_vif->sta.ap->width) { ++ case NL80211_CHAN_WIDTH_80: ++ vht_oper->chan_width = ++ IEEE80211_VHT_CHANWIDTH_80MHZ; // Channel Width ++ CCFS0(vht_oper) = ieee80211_frequency_to_channel( ++ rwnx_vif->sta.ap ++ ->center_freq); // Channel Center Frequency Segment 0 ++ CCFS1(vht_oper) = ++ 0; // Channel Center Frequency Segment 1 (N.A.) ++ break; ++ case NL80211_CHAN_WIDTH_160: ++ vht_oper->chan_width = ++ IEEE80211_VHT_CHANWIDTH_160MHZ; // Channel Width ++ CCFS0(vht_oper) = ieee80211_frequency_to_channel( ++ rwnx_vif->sta.ap ++ ->center_freq); // Channel Center Frequency Segment 0 ++ CCFS1(vht_oper) = ++ 0; // Channel Center Frequency Segment 1 (N.A.) ++ break; ++ case NL80211_CHAN_WIDTH_80P80: ++ vht_oper->chan_width = ++ IEEE80211_VHT_CHANWIDTH_80P80MHZ; // Channel Width ++ CCFS0(vht_oper) = ieee80211_frequency_to_channel( ++ rwnx_vif->sta.ap ++ ->center_freq1); // Channel Center Frequency Segment 0 ++ CCFS1(vht_oper) = ieee80211_frequency_to_channel( ++ rwnx_vif->sta.ap ++ ->center_freq2); // Channel Center Frequency Segment 1 ++ break; ++ default: ++ vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_USE_HT; ++ CCFS0(vht_oper) = 0; ++ CCFS1(vht_oper) = 0; ++ break; ++ } ++ ++ vht_oper->basic_mcs_set = cpu_to_le16(rwnx_hw->mod_params->mcs_map); ++ ++ return pos + sizeof(struct ieee80211_vht_operation); ++} ++ ++static void rwnx_tdls_add_setup_start_ies(struct rwnx_hw *rwnx_hw, ++ struct rwnx_vif *rwnx_vif, ++ struct sk_buff *skb, const u8 *peer, ++ u8 action_code, bool initiator, ++ const u8 *extra_ies, ++ size_t extra_ies_len) ++{ ++ enum nl80211_band band = rwnx_vif->sta.ap->band; ++ struct ieee80211_supported_band *sband; ++ struct ieee80211_sta_ht_cap ht_cap; ++ struct ieee80211_sta_vht_cap vht_cap; ++ size_t offset = 0, noffset; ++ u8 *pos; ++ ++ rcu_read_lock(); ++ ++ rwnx_add_srates_ie(rwnx_hw, skb); ++ rwnx_add_ext_srates_ie(rwnx_hw, skb); ++ rwnx_tdls_add_supp_channels(rwnx_hw, skb); ++ rwnx_tdls_add_ext_capab(rwnx_hw, skb); ++ ++ /* add the QoS element if we support it */ ++ if (/*local->hw.queues >= IEEE80211_NUM_ACS &&*/ ++ action_code != WLAN_PUB_ACTION_TDLS_DISCOVER_RES) ++ rwnx_add_wmm_info_ie(skb, 0); /* no U-APSD */ ++ ++ rwnx_tdls_add_oper_classes(rwnx_vif, skb); ++ ++ /* ++ * with TDLS we can switch channels, and HT-caps are not necessarily ++ * the same on all bands. The specification limits the setup to a ++ * single HT-cap, so use the current band for now. ++ */ ++ sband = rwnx_hw->wiphy->bands[band]; ++ memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap)); ++ if (((action_code == WLAN_TDLS_SETUP_REQUEST) || ++ (action_code == WLAN_TDLS_SETUP_RESPONSE) || ++ (action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES)) && ++ ht_cap.ht_supported /* (!sta || sta->sta.ht_cap.ht_supported)*/) { ++ rwnx_ie_build_ht_cap(skb, &ht_cap, ht_cap.cap); ++ } ++ ++ if (ht_cap.ht_supported && ++ (ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) ++ rwnx_tdls_add_bss_coex_ie(skb); ++ ++ rwnx_tdls_add_link_ie(rwnx_hw, rwnx_vif, skb, peer, initiator); ++ ++ memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap)); ++ if (vht_cap.vht_supported) { ++ rwnx_tdls_add_aid_ie(rwnx_vif, skb); ++ rwnx_ie_build_vht_cap(skb, &vht_cap, vht_cap.cap); ++ // Operating mode Notification (optional) ++ } ++ ++ /* add any remaining IEs */ ++ if (extra_ies_len) { ++ noffset = extra_ies_len; ++ pos = skb_put(skb, noffset - offset); ++ memcpy(pos, extra_ies + offset, noffset - offset); ++ } ++ ++ rcu_read_unlock(); ++} ++ ++static void rwnx_tdls_add_setup_cfm_ies(struct rwnx_hw *rwnx_hw, ++ struct rwnx_vif *rwnx_vif, ++ struct sk_buff *skb, const u8 *peer, ++ bool initiator, const u8 *extra_ies, ++ size_t extra_ies_len) ++{ ++ struct ieee80211_supported_band *sband; ++ enum nl80211_band band = rwnx_vif->sta.ap->band; ++ struct ieee80211_sta_ht_cap ht_cap; ++ struct ieee80211_sta_vht_cap vht_cap; ++ ++ size_t offset = 0, noffset; ++ struct rwnx_sta *sta, *ap_sta; ++ u8 *pos; ++ ++ rcu_read_lock(); ++ ++ sta = rwnx_get_sta(rwnx_hw, peer); ++ ap_sta = rwnx_vif->sta.ap; ++ if (WARN_ON_ONCE(!sta || !ap_sta)) { ++ rcu_read_unlock(); ++ return; ++ } ++ ++ /* add the QoS param IE if both the peer and we support it */ ++ if (sta->qos) ++ rwnx_add_wmm_param_ie(skb, ap_sta->acm, ap_sta->ac_param); ++ ++ /* if HT support is only added in TDLS, we need an HT-operation IE */ ++ sband = rwnx_hw->wiphy->bands[band]; ++ memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap)); ++ if (ht_cap.ht_supported && !ap_sta->ht && sta->ht) { ++ pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation)); ++ /* send an empty HT operation IE */ ++ rwnx_ie_build_ht_oper(rwnx_hw, rwnx_vif, pos, &ht_cap, 0); ++ } ++ ++ rwnx_tdls_add_link_ie(rwnx_hw, rwnx_vif, skb, peer, initiator); ++ ++ memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap)); ++ if (vht_cap.vht_supported && !ap_sta->vht && sta->vht) { ++ pos = skb_put(skb, 2 + sizeof(struct ieee80211_vht_operation)); ++ rwnx_ie_build_vht_oper(rwnx_hw, rwnx_vif, pos, &ht_cap, 0); ++ // Operating mode Notification (optional) ++ } ++ ++ /* add any remaining IEs */ ++ if (extra_ies_len) { ++ noffset = extra_ies_len; ++ pos = skb_put(skb, noffset - offset); ++ memcpy(pos, extra_ies + offset, noffset - offset); ++ } ++ ++ rcu_read_unlock(); ++} ++ ++static void rwnx_tdls_add_ies(struct rwnx_hw *rwnx_hw, ++ struct rwnx_vif *rwnx_vif, struct sk_buff *skb, ++ const u8 *peer, u8 action_code, u16 status_code, ++ bool initiator, const u8 *extra_ies, ++ size_t extra_ies_len, u8 oper_class, ++ struct cfg80211_chan_def *chandef) ++{ ++ switch (action_code) { ++ case WLAN_TDLS_SETUP_REQUEST: ++ case WLAN_TDLS_SETUP_RESPONSE: ++ case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: ++ if (status_code == 0) ++ rwnx_tdls_add_setup_start_ies(rwnx_hw, rwnx_vif, skb, ++ peer, action_code, ++ initiator, extra_ies, ++ extra_ies_len); ++ break; ++ case WLAN_TDLS_SETUP_CONFIRM: ++ if (status_code == 0) ++ rwnx_tdls_add_setup_cfm_ies(rwnx_hw, rwnx_vif, skb, ++ peer, initiator, extra_ies, ++ extra_ies_len); ++ break; ++ ++ case WLAN_TDLS_TEARDOWN: ++ case WLAN_TDLS_DISCOVERY_REQUEST: ++ if (extra_ies_len) ++ memcpy(skb_put(skb, extra_ies_len), extra_ies, ++ extra_ies_len); ++ if (status_code == 0 || action_code == WLAN_TDLS_TEARDOWN) ++ rwnx_tdls_add_link_ie(rwnx_hw, rwnx_vif, skb, peer, ++ initiator); ++ break; ++ } ++} ++ ++int rwnx_tdls_send_mgmt_packet_data(struct rwnx_hw *rwnx_hw, ++ struct rwnx_vif *rwnx_vif, const u8 *peer, ++ u8 action_code, u8 dialog_token, ++ u16 status_code, u32 peer_capability, ++ bool initiator, const u8 *extra_ies, ++ size_t extra_ies_len, u8 oper_class, ++ struct cfg80211_chan_def *chandef) ++{ ++ struct sk_buff *skb; ++ int ret = 0; ++ 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]; ++ int channels = rwnx_band_2GHz->n_channels; ++ ++ if (rwnx_hw->band_5g_support) ++ channels += rwnx_band_5GHz->n_channels; ++ ++ skb = netdev_alloc_skb( ++ rwnx_vif->ndev, ++ sizeof(struct ieee80211_tdls_data) + // ethhdr + TDLS info ++ 10 + /* supported rates */ ++ 6 + /* extended supported rates */ ++ (2 + channels) + /* supported channels */ ++ sizeof(struct ieee_types_extcap) + ++ sizeof(struct ieee80211_wmm_param_ie) + ++ 4 + /* oper classes */ ++ 28 + //sizeof(struct ieee80211_ht_cap) + ++ sizeof(struct ieee_types_bss_co_2040) + ++ sizeof(struct ieee80211_tdls_lnkie) + ++ (2 + sizeof(struct ieee80211_vht_cap)) + 4 + /*AID*/ ++ (2 + sizeof(struct ieee80211_ht_operation)) + ++ extra_ies_len); ++ ++ if (!skb) ++ return 0; ++ ++ switch (action_code) { ++ case WLAN_TDLS_SETUP_REQUEST: ++ case WLAN_TDLS_SETUP_RESPONSE: ++ case WLAN_TDLS_SETUP_CONFIRM: ++ case WLAN_TDLS_TEARDOWN: ++ case WLAN_TDLS_DISCOVERY_REQUEST: ++ ret = rwnx_tdls_prepare_encap_data(rwnx_hw, rwnx_vif, peer, ++ action_code, dialog_token, ++ status_code, skb); ++ break; ++ ++ case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: ++ ret = rwnx_prep_tdls_direct(rwnx_hw, rwnx_vif, peer, ++ action_code, dialog_token, ++ status_code, skb); ++ break; ++ ++ default: ++ ret = -ENOTSUPP; ++ break; ++ } ++ ++ if (ret < 0) ++ goto fail; ++ ++ rwnx_tdls_add_ies(rwnx_hw, rwnx_vif, skb, peer, action_code, ++ status_code, initiator, extra_ies, extra_ies_len, ++ oper_class, chandef); ++ ++ if (action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) { ++ u64 cookie; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) ++ struct cfg80211_mgmt_tx_params params; ++ ++ params.len = skb->len; ++ params.buf = skb->data; ++ ret = rwnx_start_mgmt_xmit(rwnx_vif, NULL, ¶ms, false, ++ &cookie); ++#else ++ ret = rwnx_start_mgmt_xmit(rwnx_vif, NULL, NULL, false, 0, ++ skb->data, skb->len, false, false, ++ &cookie); ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ ++ ++ return ret; ++ } ++ ++ switch (action_code) { ++ case WLAN_TDLS_SETUP_REQUEST: ++ case WLAN_TDLS_SETUP_RESPONSE: ++ case WLAN_TDLS_SETUP_CONFIRM: ++ skb->priority = 2; ++ break; ++ default: ++ skb->priority = 5; ++ break; ++ } ++ ++ ret = rwnx_select_txq(rwnx_vif, skb); ++ ret = rwnx_start_xmit(skb, rwnx_vif->ndev); ++ ++ return ret; ++ ++fail: ++ dev_kfree_skb(skb); ++ return ret; ++} +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_tdls.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_tdls.h +new file mode 100755 +index 000000000..d41f0a99c +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_tdls.h +@@ -0,0 +1,56 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_tdls.h ++ * ++ * @brief TDLS function declarations ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++#ifndef RWNX_TDLS_H_ ++#define RWNX_TDLS_H_ ++ ++#include "rwnx_defs.h" ++ ++struct ieee_types_header { ++ u8 element_id; ++ u8 len; ++} __packed; ++ ++struct ieee_types_bss_co_2040 { ++ struct ieee_types_header ieee_hdr; ++ u8 bss_2040co; ++} __packed; ++ ++struct ieee_types_extcap { ++ struct ieee_types_header ieee_hdr; ++ u8 ext_capab[8]; ++} __packed; ++ ++struct ieee_types_vht_cap { ++ struct ieee_types_header ieee_hdr; ++ struct ieee80211_vht_cap vhtcap; ++} __packed; ++ ++struct ieee_types_vht_oper { ++ struct ieee_types_header ieee_hdr; ++ struct ieee80211_vht_operation vhtoper; ++} __packed; ++ ++struct ieee_types_aid { ++ struct ieee_types_header ieee_hdr; ++ u16 aid; ++} __packed; ++ ++int rwnx_tdls_send_mgmt_packet_data(struct rwnx_hw *rwnx_hw, ++ struct rwnx_vif *rwnx_vif, const u8 *peer, ++ u8 action_code, u8 dialog_token, ++ u16 status_code, u32 peer_capability, ++ bool initiator, const u8 *extra_ies, ++ size_t extra_ies_len, u8 oper_class, ++ struct cfg80211_chan_def *chandef); ++ ++#endif /* RWNX_TDLS_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_testmode.c b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_testmode.c +new file mode 100755 +index 000000000..4e8526f58 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_testmode.c +@@ -0,0 +1,220 @@ ++/** ++ **************************************************************************************** ++ * ++ * @file rwnx_testmode.c ++ * ++ * @brief Test mode function definitions ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ **************************************************************************************** ++ */ ++ ++#include ++#include ++ ++#include "rwnx_testmode.h" ++#include "rwnx_msg_tx.h" ++#include "rwnx_dini.h" ++#include "reg_access.h" ++ ++/* ++ * This function handles the user application commands for register access. ++ * ++ * It retrieves command ID carried with RWNX_TM_ATTR_COMMAND and calls to the ++ * handlers respectively. ++ * ++ * If it's an unknown commdn ID, -ENOSYS is returned; or -ENOMSG if the ++ * mandatory fields(RWNX_TM_ATTR_REG_OFFSET,RWNX_TM_ATTR_REG_VALUE32) ++ * are missing; Otherwise 0 is replied indicating the success of the command execution. ++ * ++ * If RWNX_TM_ATTR_COMMAND is RWNX_TM_CMD_APP2DEV_REG_READ, the register read ++ * value is returned with RWNX_TM_ATTR_REG_VALUE32. ++ * ++ * @hw: ieee80211_hw object that represents the device ++ * @tb: general message fields from the user space ++ */ ++int rwnx_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) ++{ ++ struct rwnx_hw *rwnx_hw = hw->priv; ++ u32 mem_addr, val32; ++ struct sk_buff *skb; ++ int status = 0; ++ ++ /* First check if register address is there */ ++ if (!tb[RWNX_TM_ATTR_REG_OFFSET]) { ++ printk("Error finding register offset\n"); ++ return -ENOMSG; ++ } ++ ++ mem_addr = nla_get_u32(tb[RWNX_TM_ATTR_REG_OFFSET]); ++ ++ switch (nla_get_u32(tb[RWNX_TM_ATTR_COMMAND])) { ++ case RWNX_TM_CMD_APP2DEV_REG_READ: { ++ struct dbg_mem_read_cfm mem_read_cfm; ++ ++ /*** Send the command to the LMAC ***/ ++ status = rwnx_send_dbg_mem_read_req(rwnx_hw, mem_addr, ++ &mem_read_cfm); ++ if (status) ++ return status; ++ ++ /* Allocate the answer message */ ++ skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); ++ if (!skb) { ++ printk("Error allocating memory\n"); ++ return -ENOMEM; ++ } ++ ++ val32 = mem_read_cfm.memdata; ++ if (nla_put_u32(skb, RWNX_TM_ATTR_REG_VALUE32, val32)) ++ goto nla_put_failure; ++ ++ /* Send the answer to upper layer */ ++ status = cfg80211_testmode_reply(skb); ++ if (status < 0) ++ printk("Error sending msg : %d\n", status); ++ } break; ++ ++ case RWNX_TM_CMD_APP2DEV_REG_WRITE: { ++ if (!tb[RWNX_TM_ATTR_REG_VALUE32]) { ++ printk("Error finding value to write\n"); ++ return -ENOMSG; ++ } else { ++ val32 = nla_get_u32(tb[RWNX_TM_ATTR_REG_VALUE32]); ++ /* Send the command to the LMAC */ ++ status = rwnx_send_dbg_mem_write_req(rwnx_hw, mem_addr, ++ val32); ++ if (status) ++ return status; ++ } ++ } break; ++ ++ default: ++ printk("Unknown testmode register command ID\n"); ++ return -ENOSYS; ++ } ++ ++ return status; ++ ++nla_put_failure: ++ kfree_skb(skb); ++ return -EMSGSIZE; ++} ++ ++/* ++ * This function handles the user application commands for Debug filter settings. ++ * ++ * @hw: ieee80211_hw object that represents the device ++ * @tb: general message fields from the user space ++ */ ++int rwnx_testmode_dbg_filter(struct ieee80211_hw *hw, struct nlattr **tb) ++{ ++ struct rwnx_hw *rwnx_hw = hw->priv; ++ u32 filter; ++ int status = 0; ++ ++ /* First check if the filter is there */ ++ if (!tb[RWNX_TM_ATTR_REG_FILTER]) { ++ printk("Error finding filter value\n"); ++ return -ENOMSG; ++ } ++ ++ filter = nla_get_u32(tb[RWNX_TM_ATTR_REG_FILTER]); ++ RWNX_DBG("testmode debug filter, setting: 0x%x\n", filter); ++ ++ switch (nla_get_u32(tb[RWNX_TM_ATTR_COMMAND])) { ++ case RWNX_TM_CMD_APP2DEV_SET_DBGMODFILTER: { ++ /* Send the command to the LMAC */ ++ status = rwnx_send_dbg_set_mod_filter_req(rwnx_hw, filter); ++ if (status) ++ return status; ++ } break; ++ case RWNX_TM_CMD_APP2DEV_SET_DBGSEVFILTER: { ++ /* Send the command to the LMAC */ ++ status = rwnx_send_dbg_set_sev_filter_req(rwnx_hw, filter); ++ if (status) ++ return status; ++ } break; ++ ++ default: ++ printk("Unknown testmode register command ID\n"); ++ return -ENOSYS; ++ } ++ ++ return status; ++} ++ ++/* ++ * This function handles the user application commands for register access without using ++ * the normal LMAC messaging way. ++ * This time register access will be done through direct PCI BAR windows. This can be used ++ * to access registers even when the :AMC FW is stuck. ++ * ++ * @hw: ieee80211_hw object that represents the device ++ * @tb: general message fields from the user space ++ */ ++int rwnx_testmode_reg_dbg(struct ieee80211_hw *hw, struct nlattr **tb) ++{ ++ struct rwnx_hw *rwnx_hw = hw->priv; ++ struct rwnx_plat *rwnx_plat = rwnx_hw->plat; ++ u32 mem_addr; ++ struct sk_buff *skb; ++ int status = 0; ++ volatile unsigned int reg_value = 0; ++ unsigned int offset; ++ ++ /* First check if register address is there */ ++ if (!tb[RWNX_TM_ATTR_REG_OFFSET]) { ++ printk("Error finding register offset\n"); ++ return -ENOMSG; ++ } ++ ++ mem_addr = nla_get_u32(tb[RWNX_TM_ATTR_REG_OFFSET]); ++ offset = mem_addr & 0x00FFFFFF; ++ ++ switch (nla_get_u32(tb[RWNX_TM_ATTR_COMMAND])) { ++ case RWNX_TM_CMD_APP2DEV_REG_READ_DBG: { ++ /*** Send the command to the LMAC ***/ ++ reg_value = RWNX_REG_READ(rwnx_plat, RWNX_ADDR_SYSTEM, offset); ++ ++ /* Allocate the answer message */ ++ skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); ++ if (!skb) { ++ printk("Error allocating memory\n"); ++ return -ENOMEM; ++ } ++ ++ if (nla_put_u32(skb, RWNX_TM_ATTR_REG_VALUE32, reg_value)) ++ goto nla_put_failure; ++ ++ /* Send the answer to upper layer */ ++ status = cfg80211_testmode_reply(skb); ++ if (status < 0) ++ printk("Error sending msg : %d\n", status); ++ } break; ++ ++ case RWNX_TM_CMD_APP2DEV_REG_WRITE_DBG: { ++ if (!tb[RWNX_TM_ATTR_REG_VALUE32]) { ++ printk("Error finding value to write\n"); ++ return -ENOMSG; ++ } else { ++ reg_value = nla_get_u32(tb[RWNX_TM_ATTR_REG_VALUE32]); ++ ++ /* Send the command to the LMAC */ ++ RWNX_REG_WRITE(reg_value, rwnx_plat, RWNX_ADDR_SYSTEM, ++ offset); ++ } ++ } break; ++ ++ default: ++ printk("Unknown testmode register command ID\n"); ++ return -ENOSYS; ++ } ++ ++ return status; ++ ++nla_put_failure: ++ kfree_skb(skb); ++ return -EMSGSIZE; ++} +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_testmode.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_testmode.h +new file mode 100755 +index 000000000..9d1bca47e +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_testmode.h +@@ -0,0 +1,64 @@ ++/** ++ **************************************************************************************** ++ * ++ * @file rwnx_testmode.h ++ * ++ * @brief Test mode function declarations ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ **************************************************************************************** ++ */ ++ ++#ifndef RWNX_TESTMODE_H_ ++#define RWNX_TESTMODE_H_ ++ ++#include ++#include ++ ++/* Commands from user space to kernel space(RWNX_TM_CMD_APP2DEV_XX) and ++ * from and kernel space to user space(RWNX_TM_CMD_DEV2APP_XX). ++ * The command ID is carried with RWNX_TM_ATTR_COMMAND. ++ */ ++enum rwnx_tm_cmd_t { ++ /* commands from user application to access register */ ++ RWNX_TM_CMD_APP2DEV_REG_READ = 1, ++ RWNX_TM_CMD_APP2DEV_REG_WRITE, ++ ++ /* commands from user application to select the Debug levels */ ++ RWNX_TM_CMD_APP2DEV_SET_DBGMODFILTER, ++ RWNX_TM_CMD_APP2DEV_SET_DBGSEVFILTER, ++ ++ /* commands to access registers without sending messages to LMAC layer, ++ * this must be used when LMAC FW is stuck. */ ++ RWNX_TM_CMD_APP2DEV_REG_READ_DBG, ++ RWNX_TM_CMD_APP2DEV_REG_WRITE_DBG, ++ ++ RWNX_TM_CMD_MAX, ++}; ++ ++enum rwnx_tm_attr_t { ++ RWNX_TM_ATTR_NOT_APPLICABLE = 0, ++ ++ RWNX_TM_ATTR_COMMAND, ++ ++ /* When RWNX_TM_ATTR_COMMAND is RWNX_TM_CMD_APP2DEV_REG_XXX, ++ * The mandatory fields are: ++ * RWNX_TM_ATTR_REG_OFFSET for the offset of the target register; ++ * RWNX_TM_ATTR_REG_VALUE32 for value */ ++ RWNX_TM_ATTR_REG_OFFSET, ++ RWNX_TM_ATTR_REG_VALUE32, ++ ++ /* When RWNX_TM_ATTR_COMMAND is RWNX_TM_CMD_APP2DEV_SET_DBGXXXFILTER, ++ * The mandatory field is RWNX_TM_ATTR_REG_FILTER. */ ++ RWNX_TM_ATTR_REG_FILTER, ++ ++ RWNX_TM_ATTR_MAX, ++}; ++ ++/***********************************************************************/ ++int rwnx_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb); ++int rwnx_testmode_dbg_filter(struct ieee80211_hw *hw, struct nlattr **tb); ++int rwnx_testmode_reg_dbg(struct ieee80211_hw *hw, struct nlattr **tb); ++ ++#endif /* RWNX_TESTMODE_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_tx.c b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_tx.c +new file mode 100755 +index 000000000..c10acd535 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_tx.c +@@ -0,0 +1,2521 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_tx.c ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ ****************************************************************************** ++ */ ++#include ++#include ++#include ++ ++#include "rwnx_defs.h" ++#include "rwnx_tx.h" ++#include "rwnx_msg_tx.h" ++#include "rwnx_mesh.h" ++#include "rwnx_events.h" ++#include "rwnx_compat.h" ++#include "aicwf_txrxif.h" ++#ifdef CONFIG_RWNX_MON_XMIT ++#include ++#endif ++ ++/****************************************************************************** ++ * Power Save functions ++ *****************************************************************************/ ++/** ++ * rwnx_set_traffic_status - Inform FW if traffic is available for STA in PS ++ * ++ * @rwnx_hw: Driver main data ++ * @sta: Sta in PS mode ++ * @available: whether traffic is buffered for the STA ++ * @ps_id: type of PS data requested (@LEGACY_PS_ID or @UAPSD_ID) ++ */ ++void rwnx_set_traffic_status(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta, ++ bool available, u8 ps_id) ++{ ++ if (sta->tdls.active) { ++ rwnx_send_tdls_peer_traffic_ind_req( ++ rwnx_hw, rwnx_hw->vif_table[sta->vif_idx]); ++ } 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 ++ } ++} ++ ++/** ++ * rwnx_ps_bh_enable - Enable/disable PS mode for one STA ++ * ++ * @rwnx_hw: Driver main data ++ * @sta: Sta which enters/leaves PS mode ++ * @enable: PS mode status ++ * ++ * This function will enable/disable PS mode for one STA. ++ * When enabling PS mode: ++ * - Stop all STA's txq for RWNX_TXQ_STOP_STA_PS reason ++ * - Count how many buffers are already ready for this STA ++ * - For BC/MC sta, update all queued SKB to use hw_queue BCMC ++ * - Update TIM if some packet are ready ++ * ++ * When disabling PS mode: ++ * - Start all STA's txq for RWNX_TXQ_STOP_STA_PS reason ++ * - For BC/MC sta, update all queued SKB to use hw_queue AC_BE ++ * - Update TIM if some packet are ready (otherwise fw will not update TIM ++ * in beacon for this STA) ++ * ++ * All counter/skb updates are protected from TX path by taking tx_lock ++ * ++ * NOTE: _bh_ in function name indicates that this function is called ++ * from a bottom_half tasklet. ++ */ ++void rwnx_ps_bh_enable(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta, ++ bool enable) ++{ ++ 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; ++ sta->ps.sp_cnt[UAPSD_ID] = 0; ++ rwnx_txq_sta_stop(sta, RWNX_TXQ_STOP_STA_PS, rwnx_hw); ++ ++ if (is_multicast_sta(sta->sta_idx)) { ++ txq = rwnx_txq_sta_get(sta, 0, rwnx_hw); ++ sta->ps.pkt_ready[LEGACY_PS_ID] = ++ skb_queue_len(&txq->sk_list); ++ sta->ps.pkt_ready[UAPSD_ID] = 0; ++ //txq->hwq = &rwnx_hw->hwq[RWNX_HWQ_BCMC]; ++ } else { ++ int i; ++ sta->ps.pkt_ready[LEGACY_PS_ID] = 0; ++ sta->ps.pkt_ready[UAPSD_ID] = 0; ++ foreach_sta_txq(sta, txq, i, rwnx_hw) ++ { ++ sta->ps.pkt_ready[txq->ps_id] += ++ skb_queue_len(&txq->sk_list); ++ } ++ } ++ ++ spin_unlock_bh(&rwnx_hw->tx_lock); ++ ++ //if (sta->ps.pkt_ready[LEGACY_PS_ID]) ++ //srwnx_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); ++ } else { ++#ifdef CREATE_TRACE_POINTS ++ trace_ps_disable(sta->sta_idx); ++#endif ++ spin_lock_bh(&rwnx_hw->tx_lock); ++ sta->ps.active = false; ++ ++ if (is_multicast_sta(sta->sta_idx)) { ++ txq = rwnx_txq_sta_get(sta, 0, rwnx_hw); ++ txq->hwq = &rwnx_hw->hwq[RWNX_HWQ_BE]; ++ txq->push_limit = 0; ++ } else { ++ int i; ++ foreach_sta_txq(sta, txq, i, rwnx_hw) ++ { ++ txq->push_limit = 0; ++ } ++ } ++ ++ 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]) ++ 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); ++ ++ tasklet_schedule(&rwnx_hw->task); ++ } ++} ++ ++/** ++ * rwnx_ps_bh_traffic_req - Handle traffic request for STA in PS mode ++ * ++ * @rwnx_hw: Driver main data ++ * @sta: Sta which enters/leaves PS mode ++ * @pkt_req: number of pkt to push ++ * @ps_id: type of PS data requested (@LEGACY_PS_ID or @UAPSD_ID) ++ * ++ * This function will make sure that @pkt_req are pushed to fw ++ * whereas the STA is in PS mode. ++ * If request is 0, send all traffic ++ * If request is greater than available pkt, reduce request ++ * Note: request will also be reduce if txq credits are not available ++ * ++ * All counter updates are protected from TX path by taking tx_lock ++ * ++ * NOTE: _bh_ in function name indicates that this function is called ++ * from the bottom_half tasklet. ++ */ ++void rwnx_ps_bh_traffic_req(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta, ++ u16 pkt_req, u8 ps_id) ++{ ++ int pkt_ready_all; ++ struct rwnx_txq *txq; ++ int schedule = 0; ++ ++ //if (WARN(!sta->ps.active, "sta %pM is not in Power Save mode", ++ // sta->mac_addr)) ++ // return; ++ if (!sta->ps.active) { ++ AICWFDBG(LOGTRACE, "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 ++ happens for p2p-go interface if NOA starts during a service period */ ++ if ((pkt_req == PS_SP_INTERRUPTED) && (ps_id == UAPSD_ID)) { ++ int tid; ++ sta->ps.sp_cnt[ps_id] = 0; ++ foreach_sta_txq(sta, txq, tid, rwnx_hw) ++ { ++ txq->push_limit = 0; ++ } ++ goto done; ++ } ++ ++ pkt_ready_all = (sta->ps.pkt_ready[ps_id] - sta->ps.sp_cnt[ps_id]); ++ ++ /* Don't start SP until previous one is finished or we don't have ++ packet ready (which must not happen for U-APSD) */ ++ if (sta->ps.sp_cnt[ps_id] || pkt_ready_all <= 0) { ++ goto done; ++ } ++ ++ /* Adapt request to what is available. */ ++ if (pkt_req == 0 || pkt_req > pkt_ready_all) { ++ pkt_req = pkt_ready_all; ++ } ++ ++ /* Reset the SP counter */ ++ sta->ps.sp_cnt[ps_id] = 0; ++ schedule = 1; ++ ++ /* "dispatch" the request between txq */ ++ if (is_multicast_sta(sta->sta_idx)) { ++ txq = rwnx_txq_sta_get(sta, 0, rwnx_hw); ++ //if (txq->credits <= 0) ++ // goto done; ++ if (pkt_req > txq->credits) ++ pkt_req = txq->credits; ++ txq->push_limit = pkt_req; ++ sta->ps.sp_cnt[ps_id] = pkt_req; ++ rwnx_txq_add_to_hw_list(txq); ++ } else { ++ int i, tid; ++ ++ //foreach_sta_txq_prio(sta, txq, tid, i, rwnx_hw) { ++ for (i = 0; i < NX_NB_TID_PER_STA; i++) { ++ u16 txq_len; ++ tid = nx_tid_prio[i]; ++ txq = rwnx_txq_sta_get(sta, tid, rwnx_hw); ++ txq_len = skb_queue_len(&txq->sk_list); ++ ++ if (txq->ps_id != ps_id) ++ continue; ++ ++ if (txq_len > txq->credits) ++ txq_len = txq->credits; ++ ++ if (txq_len == 0) ++ continue; ++ ++ if (txq_len < pkt_req) { ++ /* Not enough pkt queued in this txq, add this ++ txq to hwq list and process next txq */ ++ pkt_req -= txq_len; ++ txq->push_limit = txq_len; ++ sta->ps.sp_cnt[ps_id] += txq_len; ++ rwnx_txq_add_to_hw_list(txq); ++ } else { ++ /* Enough pkt in this txq to comlete the request ++ add this txq to hwq list and stop processing txq */ ++ txq->push_limit = pkt_req; ++ sta->ps.sp_cnt[ps_id] += pkt_req; ++ rwnx_txq_add_to_hw_list(txq); ++ break; ++ } ++ } ++ } ++ ++done: ++ spin_unlock_bh(&rwnx_hw->tx_lock); ++ if (schedule) ++ tasklet_schedule(&rwnx_hw->task); ++} ++ ++/****************************************************************************** ++ * TX functions ++ *****************************************************************************/ ++#define PRIO_STA_NULL 0xAA ++ ++static const int rwnx_down_hwq2tid[3] = { ++ [RWNX_HWQ_BK] = 2, ++ [RWNX_HWQ_BE] = 3, ++ [RWNX_HWQ_VI] = 5, ++}; ++ ++static void rwnx_downgrade_ac(struct rwnx_sta *sta, struct sk_buff *skb) ++{ ++ int8_t ac = rwnx_tid2hwq[skb->priority]; ++ ++ if (WARN((ac > RWNX_HWQ_VO), ++ "Unexepcted ac %d for skb before downgrade", ac)) ++ ac = RWNX_HWQ_VO; ++ ++ while (sta->acm & BIT(ac)) { ++ if (ac == RWNX_HWQ_BK) { ++ skb->priority = 1; ++ return; ++ } ++ ac--; ++ skb->priority = rwnx_down_hwq2tid[ac]; ++ } ++} ++ ++u16 rwnx_select_txq(struct rwnx_vif *rwnx_vif, struct sk_buff *skb) ++{ ++ struct rwnx_hw *rwnx_hw = rwnx_vif->rwnx_hw; ++ struct wireless_dev *wdev = &rwnx_vif->wdev; ++ struct rwnx_sta *sta = NULL; ++ struct rwnx_txq *txq; ++ u16 netdev_queue; ++ bool tdls_mgmgt_frame = false; ++ int nx_bcmc_txq_ndev_idx = NX_BCMC_TXQ_NDEV_IDX; ++ ++ if ((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8801) || ++ ((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DW) && ++ chip_id < 3)) { ++ nx_bcmc_txq_ndev_idx = NX_BCMC_TXQ_NDEV_IDX_FOR_OLD_IC; ++ } ++ ++ switch (wdev->iftype) { ++ case NL80211_IFTYPE_STATION: ++ case NL80211_IFTYPE_P2P_CLIENT: { ++ struct ethhdr *eth; ++ eth = (struct ethhdr *)skb->data; ++ if (eth->h_proto == cpu_to_be16(ETH_P_TDLS)) { ++ tdls_mgmgt_frame = true; ++ } ++ if ((rwnx_vif->tdls_status == TDLS_LINK_ACTIVE) && ++ (rwnx_vif->sta.tdls_sta != NULL) && ++ (memcmp(eth->h_dest, rwnx_vif->sta.tdls_sta->mac_addr, ++ ETH_ALEN) == 0)) ++ sta = rwnx_vif->sta.tdls_sta; ++ else ++ sta = rwnx_vif->sta.ap; ++ break; ++ } ++ case NL80211_IFTYPE_AP_VLAN: ++ if (rwnx_vif->ap_vlan.sta_4a) { ++ sta = rwnx_vif->ap_vlan.sta_4a; ++ break; ++ } ++ ++ /* AP_VLAN interface is not used for a 4A STA, ++ fallback searching sta amongs all AP's clients */ ++ rwnx_vif = rwnx_vif->ap_vlan.master; ++ case NL80211_IFTYPE_AP: ++ case NL80211_IFTYPE_P2P_GO: { ++ struct rwnx_sta *cur; ++ struct ethhdr *eth = (struct ethhdr *)skb->data; ++ ++ if (is_multicast_ether_addr(eth->h_dest)) { ++ sta = &rwnx_hw->sta_table[rwnx_vif->ap.bcmc_index]; ++ } else { ++ spin_lock_bh(&rwnx_vif->rwnx_hw->cb_lock); ++ list_for_each_entry (cur, &rwnx_vif->ap.sta_list, ++ list) { ++ if (!memcmp(cur->mac_addr, eth->h_dest, ++ ETH_ALEN)) { ++ sta = cur; ++ break; ++ } ++ } ++ spin_unlock_bh(&rwnx_vif->rwnx_hw->cb_lock); ++ } ++ ++ break; ++ } ++ case NL80211_IFTYPE_MESH_POINT: { ++ struct ethhdr *eth = (struct ethhdr *)skb->data; ++ ++ if (!rwnx_vif->is_resending) { ++ /* ++ * If ethernet source address is not the address of a mesh wireless interface, we are proxy for ++ * this address and have to inform the HW ++ */ ++ if (memcmp(ð->h_source[0], ++ &rwnx_vif->ndev->perm_addr[0], ETH_ALEN)) { ++ /* Check if LMAC is already informed */ ++ if (!rwnx_get_mesh_proxy_info( ++ rwnx_vif, (u8 *)ð->h_source, ++ true)) { ++ rwnx_send_mesh_proxy_add_req( ++ rwnx_hw, rwnx_vif, ++ (u8 *)ð->h_source); ++ } ++ } ++ } ++ ++ if (is_multicast_ether_addr(eth->h_dest)) { ++ sta = &rwnx_hw->sta_table[rwnx_vif->ap.bcmc_index]; ++ } else { ++ /* Path to be used */ ++ struct rwnx_mesh_path *p_mesh_path = NULL; ++ struct rwnx_mesh_path *p_cur_path; ++ /* Check if destination is proxied by a peer Mesh STA */ ++ struct rwnx_mesh_proxy *p_mesh_proxy = ++ rwnx_get_mesh_proxy_info( ++ rwnx_vif, (u8 *)ð->h_dest, false); ++ /* Mesh Target address */ ++ struct mac_addr *p_tgt_mac_addr; ++ ++ if (p_mesh_proxy) { ++ p_tgt_mac_addr = &p_mesh_proxy->proxy_addr; ++ } else { ++ p_tgt_mac_addr = ++ (struct mac_addr *)ð->h_dest; ++ } ++ ++ /* Look for path with provided target address */ ++ list_for_each_entry (p_cur_path, ++ &rwnx_vif->ap.mpath_list, list) { ++ if (!memcmp(&p_cur_path->tgt_mac_addr, ++ p_tgt_mac_addr, ETH_ALEN)) { ++ p_mesh_path = p_cur_path; ++ break; ++ } ++ } ++ ++ if (p_mesh_path) { ++ sta = p_mesh_path->p_nhop_sta; ++ } else { ++ rwnx_send_mesh_path_create_req( ++ rwnx_hw, rwnx_vif, ++ (u8 *)p_tgt_mac_addr); ++ } ++ } ++ ++ break; ++ } ++ default: ++ break; ++ } ++ ++ if (sta && sta->qos) { ++ if (tdls_mgmgt_frame) { ++ skb_set_queue_mapping(skb, ++ NX_STA_NDEV_IDX(skb->priority, ++ sta->sta_idx)); ++ } else { ++/* use the data classifier to determine what 802.1d tag the ++ * data frame has */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) ++ skb->priority = cfg80211_classify8021d(skb) & ++ IEEE80211_QOS_CTL_TAG1D_MASK; ++#else ++ skb->priority = cfg80211_classify8021d(skb, NULL) & ++ IEEE80211_QOS_CTL_TAG1D_MASK; ++#endif ++ } ++ if (sta->acm) ++ rwnx_downgrade_ac(sta, skb); ++ ++ txq = rwnx_txq_sta_get(sta, skb->priority, rwnx_hw); ++ netdev_queue = txq->ndev_idx; ++ } else if (sta) { ++ skb->priority = 0xFF; ++ txq = rwnx_txq_sta_get(sta, 0, rwnx_hw); ++ netdev_queue = txq->ndev_idx; ++ } else { ++ /* This packet will be dropped in xmit function, still need to select ++ an active queue for xmit to be called. As it most likely to happen ++ for AP interface, select BCMC queue ++ (TODO: select another queue if BCMC queue is stopped) */ ++ skb->priority = PRIO_STA_NULL; ++ netdev_queue = nx_bcmc_txq_ndev_idx; ++ } ++ ++#ifndef CONFIG_ONE_TXQ ++ BUG_ON(netdev_queue >= NX_NB_NDEV_TXQ); ++#endif ++ ++ return netdev_queue; ++} ++ ++/** ++ * rwnx_set_more_data_flag - Update MORE_DATA flag in tx sw desc ++ * ++ * @rwnx_hw: Driver main data ++ * @sw_txhdr: Header for pkt to be pushed ++ * ++ * If STA is in PS mode ++ * - Set EOSP in case the packet is the last of the UAPSD service period ++ * - Set MORE_DATA flag if more pkt are ready for this sta ++ * - Update TIM if this is the last pkt buffered for this sta ++ * ++ * note: tx_lock already taken. ++ */ ++static inline void rwnx_set_more_data_flag(struct rwnx_hw *rwnx_hw, ++ struct rwnx_sw_txhdr *sw_txhdr) ++{ ++ struct rwnx_sta *sta = sw_txhdr->rwnx_sta; ++ struct rwnx_vif *vif = sw_txhdr->rwnx_vif; ++ struct rwnx_txq *txq = sw_txhdr->txq; ++ ++ 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; ++ } ++ ++ if (sta->ps.pkt_ready[txq->ps_id]) { ++ sw_txhdr->desc.host.flags |= TXU_CNTRL_MORE_DATA; ++ } else { ++ rwnx_set_traffic_status(rwnx_hw, sta, false, ++ txq->ps_id); ++ } ++ } ++} ++ ++/** ++ * rwnx_get_tx_priv - Get STA and tid for one skb ++ * ++ * @rwnx_vif: vif ptr ++ * @skb: skb ++ * @tid: pointer updated with the tid to use for this skb ++ * ++ * @return: pointer on the destination STA (may be NULL) ++ * ++ * skb has already been parsed in rwnx_select_queue function ++ * simply re-read information form skb. ++ */ ++static struct rwnx_sta *rwnx_get_tx_priv(struct rwnx_vif *rwnx_vif, ++ struct sk_buff *skb, u8 *tid) ++{ ++ static struct rwnx_hw *rwnx_hw; ++ struct rwnx_sta *sta; ++ int sta_idx; ++ int nx_remote_sta_max = NX_REMOTE_STA_MAX; ++ int nx_bcmc_txq_ndev_idx = NX_BCMC_TXQ_NDEV_IDX; ++ ++ if ((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8801) || ++ ((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DW) && ++ chip_id < 3)) { ++ nx_remote_sta_max = NX_REMOTE_STA_MAX_FOR_OLD_IC; ++ nx_bcmc_txq_ndev_idx = NX_BCMC_TXQ_NDEV_IDX_FOR_OLD_IC; ++ } ++ ++ rwnx_hw = rwnx_vif->rwnx_hw; ++ *tid = skb->priority; ++ if (unlikely(skb->priority == PRIO_STA_NULL)) { ++ return NULL; ++ } else { ++ int ndev_idx = skb_get_queue_mapping(skb); ++ ++ if (ndev_idx == nx_bcmc_txq_ndev_idx) ++ sta_idx = nx_remote_sta_max + master_vif_idx(rwnx_vif); ++ else ++ sta_idx = ndev_idx / NX_NB_TID_PER_STA; ++ ++ sta = &rwnx_hw->sta_table[sta_idx]; ++ } ++ ++ return sta; ++} ++ ++/** ++ * rwnx_prep_tx - Prepare buffer for DMA transmission ++ * ++ * @rwnx_hw: Driver main data ++ * @txhdr: Tx descriptor ++ * ++ * Maps hw_txhdr and buffer data for transmission via DMA. ++ * - Data buffer with be downloaded by embebded side. ++ * - hw_txhdr will be uploaded by embedded side when buffer has been ++ * transmitted over the air. ++ */ ++static int rwnx_prep_tx(struct rwnx_hw *rwnx_hw, struct rwnx_txhdr *txhdr) ++{ ++#if 0 ++ struct rwnx_sw_txhdr *sw_txhdr = txhdr->sw_hdr; ++ struct rwnx_hw_txhdr *hw_txhdr = &txhdr->hw_hdr; ++ dma_addr_t dma_addr; ++ ++ /* MAP (and sync) memory for DMA */ ++ dma_addr = dma_map_single(rwnx_hw->dev, hw_txhdr, ++ sw_txhdr->map_len, DMA_BIDIRECTIONAL); ++ if (WARN_ON(dma_mapping_error(rwnx_hw->dev, dma_addr))) ++ return -1; ++ ++ sw_txhdr->dma_addr = dma_addr; ++#endif ++ return 0; ++} ++ ++/** ++ * rwnx_tx_push - Push one packet to fw ++ * ++ * @rwnx_hw: Driver main data ++ * @txhdr: tx desc of the buffer to push ++ * @flags: push flags (see @rwnx_push_flags) ++ * ++ * Push one packet to fw. Sw desc of the packet has already been updated. ++ * Only MORE_DATA flag will be set if needed. ++ */ ++void rwnx_tx_push(struct rwnx_hw *rwnx_hw, struct rwnx_txhdr *txhdr, int flags) ++{ ++ struct rwnx_sw_txhdr *sw_txhdr = txhdr->sw_hdr; ++ struct sk_buff *skb = sw_txhdr->skb; ++ struct rwnx_txq *txq = sw_txhdr->txq; ++ u16 hw_queue = txq->hwq->id; ++ int user = 0; ++ ++ lockdep_assert_held(&rwnx_hw->tx_lock); ++ ++ //printk("rwnx_tx_push\n"); ++ /* RETRY flag is not always set so retest here */ ++ if (txq->nb_retry) { ++ flags |= RWNX_PUSH_RETRY; ++ txq->nb_retry--; ++ if (txq->nb_retry == 0) { ++ WARN(skb != txq->last_retry_skb, ++ "last retry buffer is not the expected one"); ++ txq->last_retry_skb = NULL; ++ } ++ } else if (!(flags & RWNX_PUSH_RETRY)) { ++ txq->pkt_sent++; ++ } ++ ++#ifdef CONFIG_RWNX_AMSDUS_TX ++ if (txq->amsdu == sw_txhdr) { ++ WARN((flags & RWNX_PUSH_RETRY), "End A-MSDU on a retry"); ++ rwnx_hw->stats.amsdus[sw_txhdr->amsdu.nb - 1].done++; ++ txq->amsdu = NULL; ++ } else if (!(flags & RWNX_PUSH_RETRY) && ++ !(sw_txhdr->desc.host.flags & TXU_CNTRL_AMSDU)) { ++ rwnx_hw->stats.amsdus[0].done++; ++ } ++#endif /* CONFIG_RWNX_AMSDUS_TX */ ++ ++ /* Wait here to update hw_queue, as for multicast STA hwq may change ++ 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.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; ++ user = RWNX_TXQ_POS_ID(txq); ++#endif /* CONFIG_RWNX_MUMIMO_TX */ ++ ++ if (sw_txhdr->rwnx_sta) { ++ /* 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 ++ txq->pkt_pushed[user]++; ++//printk("txq->credits=%d\n",txq->credits); ++#if 0 ++ if (txq->credits <= 0) ++ rwnx_txq_stop(txq, RWNX_TXQ_STOP_FULL); ++#endif ++ ++ if (txq->push_limit) ++ txq->push_limit--; ++#if 0 ++ 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) || ++ (*(skb->data + sw_txhdr->headroom) == 0x30))) || ++ (sw_txhdr->desc.host.ethertype == 0x8e88) || ++ (sw_txhdr->desc.host.ethertype == 0xb488)) { ++ sw_txhdr->need_cfm = 1; ++ sw_txhdr->desc.host.hostid = ++ ((1 << 31) | rwnx_hw->sdio_env.txdesc_free_idx[0]); ++ aicwf_sdio_host_txdesc_push(&(rwnx_hw->sdio_env), 0, (long)skb); ++ if ((sw_txhdr->desc.host.flags & TXU_CNTRL_MGMT)) ++ AICWFDBG(LOGINFO, ++ "need cfm mgmt:%x,user_idx=%d, skb=%p\n", ++ *(skb->data + sw_txhdr->headroom), ++ rwnx_hw->sdio_env.txdesc_free_idx[0], skb); ++ else ++ AICWFDBG(LOGINFO, ++ "need cfm ethertype:%8x,user_idx=%d, skb=%p\n", ++ sw_txhdr->desc.host.ethertype, ++ rwnx_hw->sdio_env.txdesc_free_idx[0], skb); ++ } else { ++ sw_txhdr->need_cfm = 0; ++ sw_txhdr->desc.host.hostid = 0; ++ if (sw_txhdr->raw_frame) { ++ sw_txhdr->desc.host.flags |= TXU_CNTRL_MGMT; ++ AICWFDBG( ++ LOGDEBUG, ++ "%s TXU_CNTRL_MGMT sw_txhdr->desc.host.flags:%x\r\n", ++ __func__, sw_txhdr->desc.host.flags); ++ } ++ if (sw_txhdr->fixed_rate) { ++ sw_txhdr->desc.host.hostid = ++ (0x01UL << 30) | sw_txhdr->rate_config; ++ AICWFDBG(LOGDEBUG, "%s TXU_CNTRL_MGMT hostid:%x\r\n", ++ __func__, sw_txhdr->desc.host.hostid); ++ } else { ++ sw_txhdr->desc.host.hostid = 0; ++ } ++ ++ sw_txhdr->rwnx_vif->net_stats.tx_packets++; ++ sw_txhdr->rwnx_vif->net_stats.tx_bytes += sw_txhdr->frame_len; ++ rwnx_hw->stats.last_tx = jiffies; ++ } ++ 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) || ++ (*(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; ++ sw_txhdr->desc.host.hostid = ++ ((1 << 31) | rwnx_hw->usb_env.txdesc_free_idx[0]); ++ aicwf_usb_host_txdesc_push(&(rwnx_hw->usb_env), 0, (long)(skb)); ++ } else { ++ sw_txhdr->need_cfm = 0; ++ sw_txhdr->desc.host.hostid = 0; ++ ++ sw_txhdr->rwnx_vif->net_stats.tx_packets++; ++ sw_txhdr->rwnx_vif->net_stats.tx_bytes += sw_txhdr->frame_len; ++ rwnx_hw->stats.last_tx = jiffies; ++ } ++ aicwf_frame_tx((void *)(rwnx_hw->usbdev), skb); ++#endif ++#endif ++#if 0 ++ txq->hwq->credits[user]--; ++#endif ++ rwnx_hw->stats.cfm_balance[hw_queue]++; ++} ++ ++/** ++ * rwnx_tx_retry - Push an AMPDU pkt that need to be retried ++ * ++ * @rwnx_hw: Driver main data ++ * @skb: pkt to re-push ++ * @txhdr: tx desc of the pkt to re-push ++ * @sw_retry: Indicates if fw decide to retry this buffer ++ * (i.e. it has never been transmitted over the air) ++ * ++ * Called when a packet needs to be repushed to the firmware. ++ * First update sw descriptor and then queue it in the retry list. ++ */ ++static void rwnx_tx_retry(struct rwnx_hw *rwnx_hw, struct sk_buff *skb, ++ struct rwnx_txhdr *txhdr, bool sw_retry) ++{ ++ struct rwnx_sw_txhdr *sw_txhdr = txhdr->sw_hdr; ++ struct tx_cfm_tag *cfm = &txhdr->hw_hdr.cfm; ++ struct rwnx_txq *txq = sw_txhdr->txq; ++ int peek_off = offsetof(struct rwnx_hw_txhdr, cfm); ++ int peek_len = sizeof(((struct rwnx_hw_txhdr *)0)->cfm); ++ ++ 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 ++ if (sw_txhdr->desc.host.flags & TXU_CNTRL_AMSDU) ++ rwnx_hw->stats.amsdus[sw_txhdr->amsdu.nb - 1].failed++; ++#endif ++ } ++ ++ /* MORE_DATA will be re-set if needed when pkt will be repushed */ ++ sw_txhdr->desc.host.flags &= ~TXU_CNTRL_MORE_DATA; ++ ++ cfm->status.value = 0; ++ dma_sync_single_for_device(rwnx_hw->dev, sw_txhdr->dma_addr + peek_off, ++ peek_len, DMA_BIDIRECTIONAL); ++ ++ txq->credits++; ++ if (txq->credits > 0) ++ rwnx_txq_start(txq, RWNX_TXQ_STOP_FULL); ++ ++ /* Queue the buffer */ ++ rwnx_txq_queue_skb(skb, txq, rwnx_hw, true); ++} ++ ++#ifdef CONFIG_RWNX_AMSDUS_TX ++/* return size of subframe (including header) */ ++static inline int rwnx_amsdu_subframe_length(struct ethhdr *eth, int eth_len) ++{ ++ /* ethernet header is replaced with amdsu header that have the same size ++ Only need to check if LLC/SNAP header will be added */ ++ int len = eth_len; ++ ++ if (ntohs(eth->h_proto) >= ETH_P_802_3_MIN) { ++ len += sizeof(rfc1042_header) + 2; ++ } ++ ++ return len; ++} ++ ++static inline bool rwnx_amsdu_is_aggregable(struct sk_buff *skb) ++{ ++ /* need to add some check on buffer to see if it can be aggregated ? */ ++ return true; ++} ++ ++/** ++ * rwnx_amsdu_del_subframe_header - remove AMSDU header ++ * ++ * amsdu_txhdr: amsdu tx descriptor ++ * ++ * Move back the ethernet header at the "beginning" of the data buffer. ++ * (which has been moved in @rwnx_amsdu_add_subframe_header) ++ */ ++static void rwnx_amsdu_del_subframe_header(struct rwnx_amsdu_txhdr *amsdu_txhdr) ++{ ++ struct sk_buff *skb = amsdu_txhdr->skb; ++ struct ethhdr *eth; ++ u8 *pos; ++ ++ pos = skb->data; ++ pos += sizeof(struct rwnx_amsdu_txhdr); ++ eth = (struct ethhdr *)pos; ++ pos += amsdu_txhdr->pad + sizeof(struct ethhdr); ++ ++ if (ntohs(eth->h_proto) >= ETH_P_802_3_MIN) { ++ pos += sizeof(rfc1042_header) + 2; ++ } ++ ++ memmove(pos, eth, sizeof(*eth)); ++ skb_pull(skb, (pos - skb->data)); ++} ++ ++/** ++ * rwnx_amsdu_add_subframe_header - Add AMSDU header and link subframe ++ * ++ * @rwnx_hw Driver main data ++ * @skb Buffer to aggregate ++ * @sw_txhdr Tx descriptor for the first A-MSDU subframe ++ * ++ * return 0 on sucess, -1 otherwise ++ * ++ * This functions Add A-MSDU header and LLC/SNAP header in the buffer ++ * and update sw_txhdr of the first subframe to link this buffer. ++ * If an error happens, the buffer will be queued as a normal buffer. ++ * ++ * ++ * Before After ++ * +-------------+ +-------------+ ++ * | HEADROOM | | HEADROOM | ++ * | | +-------------+ <- data ++ * | | | amsdu_txhdr | ++ * | | | * pad size | ++ * | | +-------------+ ++ * | | | ETH hdr | keep original eth hdr ++ * | | | | to restore it once transmitted ++ * | | +-------------+ <- packet_addr[x] ++ * | | | Pad | ++ * | | +-------------+ ++ * data -> +-------------+ | AMSDU HDR | ++ * | ETH hdr | +-------------+ ++ * | | | LLC/SNAP | ++ * +-------------+ +-------------+ ++ * | DATA | | DATA | ++ * | | | | ++ * +-------------+ +-------------+ ++ * ++ * Called with tx_lock hold ++ */ ++static int rwnx_amsdu_add_subframe_header(struct rwnx_hw *rwnx_hw, ++ struct sk_buff *skb, ++ struct rwnx_sw_txhdr *sw_txhdr) ++{ ++ struct rwnx_amsdu *amsdu = &sw_txhdr->amsdu; ++ struct rwnx_amsdu_txhdr *amsdu_txhdr; ++ struct ethhdr *amsdu_hdr, *eth = (struct ethhdr *)skb->data; ++ int headroom_need, map_len, msdu_len; ++ dma_addr_t dma_addr; ++ u8 *pos, *map_start; ++ ++ msdu_len = skb->len - sizeof(*eth); ++ headroom_need = sizeof(*amsdu_txhdr) + amsdu->pad + sizeof(*amsdu_hdr); ++ if (ntohs(eth->h_proto) >= ETH_P_802_3_MIN) { ++ headroom_need += sizeof(rfc1042_header) + 2; ++ msdu_len += sizeof(rfc1042_header) + 2; ++ } ++ ++ /* we should have enough headroom (checked in xmit) */ ++ if (WARN_ON(skb_headroom(skb) < headroom_need)) { ++ return -1; ++ } ++ ++ /* allocate headroom */ ++ pos = skb_push(skb, headroom_need); ++ amsdu_txhdr = (struct rwnx_amsdu_txhdr *)pos; ++ pos += sizeof(*amsdu_txhdr); ++ ++ /* move eth header */ ++ memmove(pos, eth, sizeof(*eth)); ++ eth = (struct ethhdr *)pos; ++ pos += sizeof(*eth); ++ ++ /* Add padding from previous subframe */ ++ map_start = pos; ++ memset(pos, 0, amsdu->pad); ++ pos += amsdu->pad; ++ ++ /* Add AMSDU hdr */ ++ amsdu_hdr = (struct ethhdr *)pos; ++ memcpy(amsdu_hdr->h_dest, eth->h_dest, ETH_ALEN); ++ memcpy(amsdu_hdr->h_source, eth->h_source, ETH_ALEN); ++ amsdu_hdr->h_proto = htons(msdu_len); ++ pos += sizeof(*amsdu_hdr); ++ ++ if (ntohs(eth->h_proto) >= ETH_P_802_3_MIN) { ++ memcpy(pos, rfc1042_header, sizeof(rfc1042_header)); ++ pos += sizeof(rfc1042_header); ++ } ++ ++ /* MAP (and sync) memory for DMA */ ++ map_len = msdu_len + amsdu->pad + sizeof(*amsdu_hdr); ++ dma_addr = dma_map_single(rwnx_hw->dev, map_start, map_len, ++ DMA_BIDIRECTIONAL); ++ if (WARN_ON(dma_mapping_error(rwnx_hw->dev, dma_addr))) { ++ pos -= sizeof(*eth); ++ memmove(pos, eth, sizeof(*eth)); ++ skb_pull(skb, headroom_need); ++ return -1; ++ } ++ ++ /* update amdsu_txhdr */ ++ amsdu_txhdr->map_len = map_len; ++ amsdu_txhdr->dma_addr = dma_addr; ++ amsdu_txhdr->skb = skb; ++ amsdu_txhdr->pad = amsdu->pad; ++ amsdu_txhdr->msdu_len = msdu_len; ++ ++ /* update rwnx_sw_txhdr (of the first subframe) */ ++ BUG_ON(amsdu->nb != sw_txhdr->desc.host.packet_cnt); ++ sw_txhdr->desc.host.packet_addr[amsdu->nb] = dma_addr; ++ sw_txhdr->desc.host.packet_len[amsdu->nb] = map_len; ++ sw_txhdr->desc.host.packet_cnt++; ++ amsdu->nb++; ++ ++ amsdu->pad = AMSDU_PADDING(map_len - amsdu->pad); ++ list_add_tail(&amsdu_txhdr->list, &amsdu->hdrs); ++ amsdu->len += map_len; ++ ++ trace_amsdu_subframe(sw_txhdr); ++ return 0; ++} ++ ++/** ++ * rwnx_amsdu_add_subframe - Add this buffer as an A-MSDU subframe if possible ++ * ++ * @rwnx_hw Driver main data ++ * @skb Buffer to aggregate if possible ++ * @sta Destination STA ++ * @txq sta's txq used for this buffer ++ * ++ * Tyr to aggregate the buffer in an A-MSDU. If it succeed then the ++ * buffer is added as a new A-MSDU subframe with AMSDU and LLC/SNAP ++ * headers added (so FW won't have to modify this subframe). ++ * ++ * To be added as subframe : ++ * - sta must allow amsdu ++ * - buffer must be aggregable (to be defined) ++ * - at least one other aggregable buffer is pending in the queue ++ * or an a-msdu (with enough free space) is currently in progress ++ * ++ * returns true if buffer has been added as A-MDSP subframe, false otherwise ++ * ++ */ ++static bool rwnx_amsdu_add_subframe(struct rwnx_hw *rwnx_hw, ++ struct sk_buff *skb, struct rwnx_sta *sta, ++ struct rwnx_txq *txq) ++{ ++ bool res = false; ++ struct ethhdr *eth; ++ ++ /* immediately return if amsdu are not allowed for this sta */ ++ if (!txq->amsdu_len || rwnx_hw->mod_params->amsdu_maxnb < 2 || ++ !rwnx_amsdu_is_aggregable(skb)) ++ return false; ++ ++ spin_lock_bh(&rwnx_hw->tx_lock); ++ if (txq->amsdu) { ++ /* aggreagation already in progress, add this buffer if enough space ++ available, otherwise end the current amsdu */ ++ struct rwnx_sw_txhdr *sw_txhdr = txq->amsdu; ++ eth = (struct ethhdr *)(skb->data); ++ ++ if (((sw_txhdr->amsdu.len + sw_txhdr->amsdu.pad + ++ rwnx_amsdu_subframe_length(eth, skb->len)) > ++ txq->amsdu_len) || ++ rwnx_amsdu_add_subframe_header(rwnx_hw, skb, sw_txhdr)) { ++ txq->amsdu = NULL; ++ goto end; ++ } ++ ++ if (sw_txhdr->amsdu.nb >= rwnx_hw->mod_params->amsdu_maxnb) { ++ rwnx_hw->stats.amsdus[sw_txhdr->amsdu.nb - 1].done++; ++ /* max number of subframes reached */ ++ txq->amsdu = NULL; ++ } ++ } else { ++ /* Check if a new amsdu can be started with the previous buffer ++ (if any) and this one */ ++ struct sk_buff *skb_prev = skb_peek_tail(&txq->sk_list); ++ struct rwnx_txhdr *txhdr; ++ struct rwnx_sw_txhdr *sw_txhdr; ++ int len1, len2; ++ ++ if (!skb_prev || !rwnx_amsdu_is_aggregable(skb_prev)) ++ goto end; ++ ++ txhdr = (struct rwnx_txhdr *)skb_prev->data; ++ sw_txhdr = txhdr->sw_hdr; ++ if ((sw_txhdr->amsdu.len) || ++ (sw_txhdr->desc.host.flags & TXU_CNTRL_RETRY)) ++ /* previous buffer is already a complete amsdu or a retry */ ++ goto end; ++ ++ eth = (struct ethhdr *)(skb_prev->data + sw_txhdr->headroom); ++ len1 = rwnx_amsdu_subframe_length( ++ eth, (sw_txhdr->frame_len + sizeof(struct ethhdr))); ++ ++ eth = (struct ethhdr *)(skb->data); ++ len2 = rwnx_amsdu_subframe_length(eth, skb->len); ++ ++ if (len1 + AMSDU_PADDING(len1) + len2 > txq->amsdu_len) ++ /* not enough space to aggregate those two buffers */ ++ goto end; ++ ++ /* Add subframe header. ++ Note: Fw will take care of adding AMDSU header for the first ++ subframe while generating 802.11 MAC header */ ++ INIT_LIST_HEAD(&sw_txhdr->amsdu.hdrs); ++ sw_txhdr->amsdu.len = len1; ++ sw_txhdr->amsdu.nb = 1; ++ sw_txhdr->amsdu.pad = AMSDU_PADDING(len1); ++ if (rwnx_amsdu_add_subframe_header(rwnx_hw, skb, sw_txhdr)) ++ goto end; ++ ++ sw_txhdr->desc.host.flags |= TXU_CNTRL_AMSDU; ++ ++ if (sw_txhdr->amsdu.nb < rwnx_hw->mod_params->amsdu_maxnb) ++ txq->amsdu = sw_txhdr; ++ else ++ rwnx_hw->stats.amsdus[sw_txhdr->amsdu.nb - 1].done++; ++ } ++ ++ res = true; ++ ++end: ++ spin_unlock_bh(&rwnx_hw->tx_lock); ++ return res; ++} ++#endif /* CONFIG_RWNX_AMSDUS_TX */ ++ ++#ifdef CONFIG_BR_SUPPORT ++int aic_br_client_tx(struct rwnx_vif *vif, struct sk_buff **pskb) ++{ ++ struct sk_buff *skb = *pskb; ++ ++ /* if(check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE) == _TRUE) */ ++ { ++ void dhcp_flag_bcast(struct rwnx_vif * vif, ++ struct sk_buff * skb); ++ int res, is_vlan_tag = 0, i, do_nat25 = 1; ++ unsigned short vlan_hdr = 0; ++ void *br_port = NULL; ++ ++ /* mac_clone_handle_frame(priv, skb); */ ++ ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) ++ br_port = vif->ndev->br_port; ++#else /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) */ ++ rcu_read_lock(); ++ br_port = rcu_dereference(vif->ndev->rx_handler_data); ++ rcu_read_unlock(); ++#endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) */ ++#ifdef BR_SUPPORT_DEBUG ++ printk("SA=%pM, br_mac=%pM, type=0x%x, da[0]=%x, scdb=%pM, vif_type=%d\n", ++ skb->data + MACADDRLEN, vif->br_mac, ++ *((unsigned short *)(skb->data + MACADDRLEN * 2)), ++ skb->data[0], vif->scdb_mac, RWNX_VIF_TYPE(vif)); ++#endif ++ spin_lock_bh(&vif->br_ext_lock); ++ if (!(skb->data[0] & 1) && br_port && ++ memcmp(skb->data + MACADDRLEN, vif->br_mac, MACADDRLEN) && ++ *((unsigned short *)(skb->data + MACADDRLEN * 2)) != ++ __constant_htons(ETH_P_8021Q) && ++ *((unsigned short *)(skb->data + MACADDRLEN * 2)) == ++ __constant_htons(ETH_P_IP) && ++ !memcmp(vif->scdb_mac, skb->data + MACADDRLEN, ++ MACADDRLEN) && ++ vif->scdb_entry) { ++ memcpy(skb->data + MACADDRLEN, vif->ndev->dev_addr, ++ MACADDRLEN); ++ vif->scdb_entry->ageing_timer = jiffies; ++ spin_unlock_bh(&vif->br_ext_lock); ++ } else ++ /* if (!priv->pmib->ethBrExtInfo.nat25_disable) */ ++ { ++ /* if (priv->dev->br_port && ++ * !memcmp(skb->data+MACADDRLEN, priv->br_mac, MACADDRLEN)) { */ ++#if 1 ++ if (*((unsigned short *)(skb->data + MACADDRLEN * 2)) == ++ __constant_htons(ETH_P_8021Q)) { ++ is_vlan_tag = 1; ++ vlan_hdr = *((unsigned short *)(skb->data + ++ MACADDRLEN * 2 + ++ 2)); ++ for (i = 0; i < 6; i++) ++ *((unsigned short *)(skb->data + ++ MACADDRLEN * 2 + ++ 2 - i * 2)) = ++ *((unsigned short *)(skb->data + ++ MACADDRLEN * ++ 2 - ++ 2 - ++ i * 2)); ++ skb_pull(skb, 4); ++ } ++ /* if SA == br_mac && skb== IP => copy SIP to br_ip ?? why */ ++ if (!memcmp(skb->data + MACADDRLEN, vif->br_mac, ++ MACADDRLEN) && ++ (*((unsigned short *)(skb->data + MACADDRLEN * 2)) == ++ __constant_htons(ETH_P_IP))) ++ memcpy(vif->br_ip, ++ skb->data + WLAN_ETHHDR_LEN + 12, 4); ++ ++ if (*((unsigned short *)(skb->data + MACADDRLEN * 2)) == ++ __constant_htons(ETH_P_IP)) { ++ if (memcmp(vif->scdb_mac, ++ skb->data + MACADDRLEN, ++ MACADDRLEN)) { ++#if 1 ++ void *scdb_findEntry( ++ struct rwnx_vif * vif, ++ unsigned char *macAddr, ++ unsigned char *ipAddr); ++ ++ vif->scdb_entry = (struct nat25_network_db_entry ++ *) ++ scdb_findEntry( ++ vif, ++ skb->data + MACADDRLEN, ++ skb->data + ++ WLAN_ETHHDR_LEN + ++ 12); ++ if (vif->scdb_entry != NULL) { ++ memcpy(vif->scdb_mac, ++ skb->data + MACADDRLEN, ++ MACADDRLEN); ++ memcpy(vif->scdb_ip, ++ skb->data + ++ WLAN_ETHHDR_LEN + ++ 12, ++ 4); ++ vif->scdb_entry->ageing_timer = ++ jiffies; ++ do_nat25 = 0; ++ } ++#endif ++ } else { ++ if (vif->scdb_entry) { ++ vif->scdb_entry->ageing_timer = ++ jiffies; ++ do_nat25 = 0; ++ } else { ++ memset(vif->scdb_mac, 0, ++ MACADDRLEN); ++ memset(vif->scdb_ip, 0, 4); ++ } ++ } ++ } ++ spin_unlock_bh(&vif->br_ext_lock); ++#endif /* 1 */ ++ if (do_nat25) { ++#if 1 ++ int nat25_db_handle(struct rwnx_vif * vif, ++ struct sk_buff * skb, ++ int method); ++ if (nat25_db_handle(vif, skb, NAT25_CHECK) == ++ 0) { ++ struct sk_buff *newskb; ++ ++ if (is_vlan_tag) { ++ skb_push(skb, 4); ++ for (i = 0; i < 6; i++) ++ *((unsigned short ++ *)(skb->data + ++ i * 2)) = ++ *((unsigned short ++ *)(skb->data + ++ 4 + ++ i * 2)); ++ *((unsigned short ++ *)(skb->data + ++ MACADDRLEN * 2)) = ++ __constant_htons( ++ ETH_P_8021Q); ++ *((unsigned short *)(skb->data + ++ MACADDRLEN * ++ 2 + ++ 2)) = ++ vlan_hdr; ++ } ++ ++ newskb = skb_copy(skb, ++ in_interrupt() ? ++ GFP_ATOMIC : ++ GFP_KERNEL); ++ if (newskb == NULL) { ++ /* priv->ext_stats.tx_drops++; */ ++ printk("TX DROP: skb_copy fail!\n"); ++ /* goto stop_proc; */ ++ return -1; ++ } ++ dev_kfree_skb_any(skb); ++ ++ *pskb = skb = newskb; ++ if (is_vlan_tag) { ++ vlan_hdr = *( ++ (unsigned short ++ *)(skb->data + ++ MACADDRLEN * ++ 2 + ++ 2)); ++ for (i = 0; i < 6; i++) ++ *((unsigned short ++ *)(skb->data + ++ MACADDRLEN * ++ 2 + ++ 2 - ++ i * 2)) = ++ *((unsigned short ++ *)(skb->data + ++ MACADDRLEN * ++ 2 - ++ 2 - ++ i * 2)); ++ skb_pull(skb, 4); ++ } ++ } ++ ++ if (skb_is_nonlinear(skb)) ++ printk("%s(): skb_is_nonlinear!!\n", ++ __FUNCTION__); ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)) ++ res = skb_linearize(skb, GFP_ATOMIC); ++#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)) */ ++ res = skb_linearize(skb); ++#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)) */ ++ if (res < 0) { ++ printk("TX DROP: skb_linearize fail!\n"); ++ /* goto free_and_stop; */ ++ return -1; ++ } ++ ++ res = nat25_db_handle(vif, skb, NAT25_INSERT); ++ if (res < 0) { ++ if (res == -2) { ++ /* priv->ext_stats.tx_drops++; */ ++ printk("TX DROP: nat25_db_handle fail!\n"); ++ /* goto free_and_stop; */ ++ return -1; ++ } ++ /* we just print warning message and let it go */ ++ /* DEBUG_WARN("%s()-%d: nat25_db_handle INSERT Warning!\n", __FUNCTION__, __LINE__); */ ++ /* return -1; */ /* return -1 will cause system crash on 2011/08/30! */ ++ return 0; ++ } ++#endif ++ } ++ ++ memcpy(skb->data + MACADDRLEN, vif->ndev->dev_addr, ++ MACADDRLEN); ++ ++ dhcp_flag_bcast(vif, skb); ++ ++ if (is_vlan_tag) { ++ skb_push(skb, 4); ++ for (i = 0; i < 6; i++) ++ *((unsigned short *)(skb->data + ++ i * 2)) = ++ *((unsigned short *)(skb->data + ++ 4 + ++ i * 2)); ++ *((unsigned short *)(skb->data + ++ MACADDRLEN * 2)) = ++ __constant_htons(ETH_P_8021Q); ++ *((unsigned short *)(skb->data + ++ MACADDRLEN * 2 + 2)) = ++ vlan_hdr; ++ } ++ } ++#if 0 ++ else { ++ if (*((unsigned short *)(skb->data + MACADDRLEN * 2)) == __constant_htons(ETH_P_8021Q)) ++ is_vlan_tag = 1; ++ ++ if (is_vlan_tag) { ++ if (ICMPV6_MCAST_MAC(skb->data) && ICMPV6_PROTO1A_VALN(skb->data)) ++ memcpy(skb->data + MACADDRLEN, GET_MY_HWADDR(padapter), MACADDRLEN); ++ } else { ++ if (ICMPV6_MCAST_MAC(skb->data) && ICMPV6_PROTO1A(skb->data)) ++ memcpy(skb->data + MACADDRLEN, GET_MY_HWADDR(padapter), MACADDRLEN); ++ } ++ } ++#endif /* 0 */ ++ ++ /* check if SA is equal to our MAC */ ++ if (memcmp(skb->data + MACADDRLEN, vif->ndev->dev_addr, ++ MACADDRLEN)) { ++ /* priv->ext_stats.tx_drops++; */ ++ printk("TX DROP: untransformed frame SA:%02X%02X%02X%02X%02X%02X!\n", ++ skb->data[6], skb->data[7], skb->data[8], ++ skb->data[9], skb->data[10], skb->data[11]); ++ /* goto free_and_stop; */ ++ return -1; ++ } ++ } ++ printk("%s:exit\n", __func__); ++ return 0; ++} ++#endif /* CONFIG_BR_SUPPORT */ ++ ++#ifdef CONFIG_FILTER_TCP_ACK ++/* return: ++ * 0, msg buf freed by the real driver ++ * others, skb need free by the caller,remember not use msg->skb! ++ */ ++ ++int intf_tx(struct rwnx_hw *priv, struct msg_buf *msg) ++{ ++ struct rwnx_vif *rwnx_vif = msg->rwnx_vif; ++ struct rwnx_hw *rwnx_hw = rwnx_vif->rwnx_hw; ++ struct rwnx_txhdr *txhdr; ++ struct rwnx_sw_txhdr *sw_txhdr; ++ struct txdesc_api *desc; ++ struct rwnx_sta *sta; ++ struct rwnx_txq *txq; ++ int headroom; ++ //int max_headroom; ++ int hdr_pads; ++ ++ u16 frame_len; ++ u16 frame_oft; ++ u8 tid; ++ struct sk_buff *skb = msg->skb; ++ struct ethhdr eth_t; ++ ++ move_tcpack_msg(rwnx_hw, msg); ++ kfree(msg); ++ ++ memcpy(ð_t, skb->data, sizeof(struct ethhdr)); ++ ++ /* Get the STA id and TID information */ ++ sta = rwnx_get_tx_priv(rwnx_vif, skb, &tid); ++ if (!sta) ++ goto free; ++ ++ txq = rwnx_txq_sta_get(sta, tid, rwnx_hw); ++ if (txq->idx == TXQ_INACTIVE) ++ goto free; ++ ++#ifdef CONFIG_RWNX_AMSDUS_TX ++ if (rwnx_amsdu_add_subframe(rwnx_hw, skb, sta, txq)) ++ return NETDEV_TX_OK; ++#endif ++ ++#ifdef CONFIG_BR_SUPPORT ++ if (1) { //(check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE) == _TRUE) { ++ void *br_port = NULL; ++ ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) ++ br_port = rwnx_vif->ndev->br_port; ++#else ++ rcu_read_lock(); ++ br_port = rcu_dereference(rwnx_vif->ndev->rx_handler_data); ++ rcu_read_unlock(); ++#endif ++ ++ if (br_port) { ++ s32 res = aic_br_client_tx(rwnx_vif, &skb); ++ if (res == -1) { ++ goto free; ++ } ++ } ++ } ++#endif /* CONFIG_BR_SUPPORT */ ++ ++ /* Retrieve the pointer to the Ethernet data */ ++ // eth = (struct ethhdr *)skb->data; ++ ++ skb_pull(skb, 14); ++ //hdr_pads = RWNX_SWTXHDR_ALIGN_PADS((long)eth); ++ hdr_pads = RWNX_SWTXHDR_ALIGN_PADS((long)skb->data); ++ headroom = sizeof(struct rwnx_txhdr) + hdr_pads; ++ ++ skb_push(skb, headroom); ++ ++ txhdr = (struct rwnx_txhdr *)skb->data; ++ sw_txhdr = kmem_cache_alloc(rwnx_hw->sw_txhdr_cache, GFP_ATOMIC); ++ if (unlikely(sw_txhdr == NULL)) ++ goto free; ++ txhdr->sw_hdr = sw_txhdr; ++ desc = &sw_txhdr->desc; ++ ++ frame_len = (u16)skb->len - headroom; // - sizeof(*eth); ++ ++ sw_txhdr->txq = txq; ++ sw_txhdr->frame_len = frame_len; ++ sw_txhdr->rwnx_sta = sta; ++ sw_txhdr->rwnx_vif = rwnx_vif; ++ sw_txhdr->skb = skb; ++ sw_txhdr->headroom = headroom; ++ sw_txhdr->map_len = skb->len - offsetof(struct rwnx_txhdr, hw_hdr); ++ ++#ifdef CONFIG_RWNX_AMSDUS_TX ++ sw_txhdr->amsdu.len = 0; ++ sw_txhdr->amsdu.nb = 0; ++#endif ++ sw_txhdr->raw_frame = 0; ++ sw_txhdr->fixed_rate = 0; ++ ++ // Fill-in the descriptor ++ memcpy(&desc->host.eth_dest_addr, eth_t.h_dest, ETH_ALEN); ++ memcpy(&desc->host.eth_src_addr, eth_t.h_source, ETH_ALEN); ++ desc->host.ethertype = eth_t.h_proto; ++ desc->host.staid = sta->sta_idx; ++ desc->host.tid = tid; ++ if (unlikely(rwnx_vif->wdev.iftype == NL80211_IFTYPE_AP_VLAN)) ++ desc->host.vif_idx = rwnx_vif->ap_vlan.master->vif_index; ++ else ++ desc->host.vif_idx = rwnx_vif->vif_index; ++ ++ if (rwnx_vif->use_4addr && (sta->sta_idx < NX_REMOTE_STA_MAX)) ++ desc->host.flags = TXU_CNTRL_USE_4ADDR; ++ else ++ desc->host.flags = 0; ++ ++ if ((rwnx_vif->tdls_status == TDLS_LINK_ACTIVE) && ++ rwnx_vif->sta.tdls_sta && ++ (memcmp(desc->host.eth_dest_addr.array, ++ rwnx_vif->sta.tdls_sta->mac_addr, ETH_ALEN) == 0)) { ++ desc->host.flags |= TXU_CNTRL_TDLS; ++ rwnx_vif->sta.tdls_sta->tdls.last_tid = desc->host.tid; ++ //rwnx_vif->sta.tdls_sta->tdls.last_sn = desc->host.sn; ++ } ++ ++ if (rwnx_vif->wdev.iftype == NL80211_IFTYPE_MESH_POINT) { ++ if (rwnx_vif->is_resending) { ++ desc->host.flags |= TXU_CNTRL_MESH_FWD; ++ } ++ } ++ ++#ifdef CONFIG_RWNX_SPLIT_TX_BUF ++ desc->host.packet_len[0] = frame_len; ++#else ++ desc->host.packet_len = frame_len; ++#endif ++ ++ txhdr->hw_hdr.cfm.status.value = 0; ++ ++ if (unlikely(rwnx_prep_tx(rwnx_hw, txhdr))) { ++ kmem_cache_free(rwnx_hw->sw_txhdr_cache, sw_txhdr); ++ skb_pull(skb, headroom); ++ dev_kfree_skb_any(skb); ++ return NETDEV_TX_BUSY; ++ } ++ ++ /* Fill-in TX descriptor */ ++ frame_oft = sizeof(struct rwnx_txhdr) - ++ offsetof(struct rwnx_txhdr, hw_hdr) + ++ hdr_pads; // + sizeof(*eth); ++#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.hostid = sw_txhdr->dma_addr; ++ ++ spin_lock_bh(&rwnx_hw->tx_lock); ++ if (rwnx_txq_queue_skb(skb, txq, rwnx_hw, false)) ++ rwnx_hwq_process(rwnx_hw, txq->hwq); ++ spin_unlock_bh(&rwnx_hw->tx_lock); ++ ++ return 0; //NETDEV_TX_OK ++ ++free: ++ dev_kfree_skb_any(skb); ++ ++ return 0; //NETDEV_TX_OK ++} ++#endif ++ ++/** ++ * netdev_tx_t (*ndo_start_xmit)(struct sk_buff *skb, ++ * struct net_device *dev); ++ * Called when a packet needs to be transmitted. ++ * Must return NETDEV_TX_OK , NETDEV_TX_BUSY. ++ * (can also return NETDEV_TX_LOCKED if NETIF_F_LLTX) ++ * ++ * - Initialize the desciptor for this pkt (stored in skb before data) ++ * - Push the pkt in the corresponding Txq ++ * - If possible (i.e. credit available and not in PS) the pkt is pushed ++ * to fw ++ */ ++netdev_tx_t rwnx_start_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct rwnx_vif *rwnx_vif = netdev_priv(dev); ++ struct rwnx_hw *rwnx_hw = rwnx_vif->rwnx_hw; ++ struct rwnx_txhdr *txhdr; ++ struct rwnx_sw_txhdr *sw_txhdr; ++ struct txdesc_api *desc; ++ struct rwnx_sta *sta; ++ struct rwnx_txq *txq; ++ int headroom; ++ int max_headroom; ++ int hdr_pads; ++ ++ u16 frame_len; ++ u16 frame_oft; ++ u8 tid; ++ ++ struct ethhdr eth_t; ++#ifdef CONFIG_FILTER_TCP_ACK ++ struct msg_buf *msgbuf = NULL; ++#endif ++ ++#ifdef CONFIG_ONE_TXQ ++ skb->queue_mapping = rwnx_select_txq(rwnx_vif, skb); ++#endif ++ ++ sk_pacing_shift_update(skb->sk, rwnx_hw->tcp_pacing_shift); ++ max_headroom = sizeof(struct rwnx_txhdr); ++ ++ /* check whether the current skb can be used */ ++ if (skb_shared(skb) || (skb_headroom(skb) < max_headroom) || ++ (skb_cloned(skb) && (dev->priv_flags & IFF_BRIDGE_PORT))) { ++ struct sk_buff *newskb = ++ skb_copy_expand(skb, max_headroom, 0, GFP_ATOMIC); ++ if (unlikely(newskb == NULL)) ++ goto free; ++ ++ dev_kfree_skb_any(skb); ++ ++ skb = newskb; ++ } ++ ++ if (skb->priority < 3) ++ skb->priority = 0; ++ ++#ifdef CONFIG_FILTER_TCP_ACK ++ if (cpu_to_le16(skb->len) <= MAX_TCP_ACK) { ++ msgbuf = intf_tcp_alloc_msg(msgbuf); ++ msgbuf->rwnx_vif = rwnx_vif; ++ msgbuf->skb = skb; ++ if (filter_send_tcp_ack(rwnx_hw, msgbuf, skb->data, ++ cpu_to_le16(skb->len))) { ++ return NETDEV_TX_OK; ++ } else { ++ move_tcpack_msg(rwnx_hw, msgbuf); ++ kfree(msgbuf); ++ } ++ } ++#endif ++ ++ memcpy(ð_t, skb->data, sizeof(struct ethhdr)); ++ ++ /* Get the STA id and TID information */ ++ sta = rwnx_get_tx_priv(rwnx_vif, skb, &tid); ++ if (!sta) ++ goto free; ++ ++ txq = rwnx_txq_sta_get(sta, tid, rwnx_hw); ++ if (txq->idx == TXQ_INACTIVE) ++ goto free; ++ ++#ifdef CONFIG_RWNX_AMSDUS_TX ++ if (rwnx_amsdu_add_subframe(rwnx_hw, skb, sta, txq)) ++ return NETDEV_TX_OK; ++#endif ++ ++#ifdef CONFIG_BR_SUPPORT ++ if (1) { //(check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE) == _TRUE) { ++ void *br_port = NULL; ++ ++#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) ++ br_port = rwnx_vif->ndev->br_port; ++#else ++ rcu_read_lock(); ++ br_port = rcu_dereference(rwnx_vif->ndev->rx_handler_data); ++ rcu_read_unlock(); ++#endif ++ ++ if (br_port) { ++ s32 res = aic_br_client_tx(rwnx_vif, &skb); ++ if (res == -1) { ++ goto free; ++ } ++ } ++ } ++#endif /* CONFIG_BR_SUPPORT */ ++ ++ /* Retrieve the pointer to the Ethernet data */ ++ // eth = (struct ethhdr *)skb->data; ++ ++ skb_pull(skb, 14); ++ //hdr_pads = RWNX_SWTXHDR_ALIGN_PADS((long)eth); ++ hdr_pads = RWNX_SWTXHDR_ALIGN_PADS((long)skb->data); ++ headroom = sizeof(struct rwnx_txhdr) + hdr_pads; ++ ++ skb_push(skb, headroom); ++ ++ txhdr = (struct rwnx_txhdr *)skb->data; ++ sw_txhdr = kmem_cache_alloc(rwnx_hw->sw_txhdr_cache, GFP_ATOMIC); ++ if (unlikely(sw_txhdr == NULL)) ++ goto free; ++ txhdr->sw_hdr = sw_txhdr; ++ desc = &sw_txhdr->desc; ++ ++ frame_len = (u16)skb->len - headroom; // - sizeof(*eth); ++ ++ sw_txhdr->txq = txq; ++ sw_txhdr->frame_len = frame_len; ++ sw_txhdr->rwnx_sta = sta; ++ sw_txhdr->rwnx_vif = rwnx_vif; ++ sw_txhdr->skb = skb; ++ sw_txhdr->headroom = headroom; ++ sw_txhdr->map_len = skb->len - offsetof(struct rwnx_txhdr, hw_hdr); ++ ++#ifdef CONFIG_RWNX_AMSDUS_TX ++ sw_txhdr->amsdu.len = 0; ++ sw_txhdr->amsdu.nb = 0; ++#endif ++ sw_txhdr->raw_frame = 0; ++ sw_txhdr->fixed_rate = 0; ++ ++ // Fill-in the descriptor ++ memcpy(&desc->host.eth_dest_addr, eth_t.h_dest, ETH_ALEN); ++ memcpy(&desc->host.eth_src_addr, eth_t.h_source, ETH_ALEN); ++ desc->host.ethertype = eth_t.h_proto; ++ desc->host.staid = sta->sta_idx; ++ desc->host.tid = tid; ++ if (unlikely(rwnx_vif->wdev.iftype == NL80211_IFTYPE_AP_VLAN)) ++ desc->host.vif_idx = rwnx_vif->ap_vlan.master->vif_index; ++ else ++ desc->host.vif_idx = rwnx_vif->vif_index; ++ ++ if (rwnx_vif->use_4addr && (sta->sta_idx < NX_REMOTE_STA_MAX)) ++ desc->host.flags = TXU_CNTRL_USE_4ADDR; ++ else ++ desc->host.flags = 0; ++ ++ if ((rwnx_vif->tdls_status == TDLS_LINK_ACTIVE) && ++ rwnx_vif->sta.tdls_sta && ++ (memcmp(desc->host.eth_dest_addr.array, ++ rwnx_vif->sta.tdls_sta->mac_addr, ETH_ALEN) == 0)) { ++ desc->host.flags |= TXU_CNTRL_TDLS; ++ rwnx_vif->sta.tdls_sta->tdls.last_tid = desc->host.tid; ++ //rwnx_vif->sta.tdls_sta->tdls.last_sn = desc->host.sn; ++ } ++ ++ if (rwnx_vif->wdev.iftype == NL80211_IFTYPE_MESH_POINT) { ++ if (rwnx_vif->is_resending) { ++ desc->host.flags |= TXU_CNTRL_MESH_FWD; ++ } ++ } ++ ++#ifdef CONFIG_RWNX_SPLIT_TX_BUF ++ desc->host.packet_len[0] = frame_len; ++#else ++ desc->host.packet_len = frame_len; ++#endif ++ ++ txhdr->hw_hdr.cfm.status.value = 0; ++ ++ if (unlikely(rwnx_prep_tx(rwnx_hw, txhdr))) { ++ kmem_cache_free(rwnx_hw->sw_txhdr_cache, sw_txhdr); ++ skb_pull(skb, headroom); ++ dev_kfree_skb_any(skb); ++ return NETDEV_TX_BUSY; ++ } ++ ++ /* Fill-in TX descriptor */ ++ frame_oft = sizeof(struct rwnx_txhdr) - ++ offsetof(struct rwnx_txhdr, hw_hdr) + ++ hdr_pads; // + sizeof(*eth); ++#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.hostid = sw_txhdr->dma_addr; ++ ++ spin_lock_bh(&rwnx_hw->tx_lock); ++ if (rwnx_txq_queue_skb(skb, txq, rwnx_hw, false)) ++ rwnx_hwq_process(rwnx_hw, txq->hwq); ++ spin_unlock_bh(&rwnx_hw->tx_lock); ++ ++ return NETDEV_TX_OK; ++ ++free: ++ dev_kfree_skb_any(skb); ++ ++ return NETDEV_TX_OK; ++} ++ ++#ifdef CONFIG_RWNX_MON_XMIT ++/** ++ * netdev_tx_t (*ndo_start_xmit)(struct sk_buff *skb, ++ * struct net_device *dev); ++ * Called when a packet needs to be transmitted. ++ * Must return NETDEV_TX_OK , NETDEV_TX_BUSY. ++ * (can also return NETDEV_TX_LOCKED if NETIF_F_LLTX) ++ * ++ * - Initialize the desciptor for this pkt (stored in skb before data) ++ * - Push the pkt in the corresponding Txq ++ * - If possible (i.e. credit available and not in PS) the pkt is pushed ++ * to fw ++ */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0)) ++#define IEEE80211_RADIOTAP_MCS_HAVE_STBC 0x20 ++#define IEEE80211_RADIOTAP_MCS_STBC_MASK 0x60 ++#define IEEE80211_RADIOTAP_MCS_STBC_SHIFT 5 ++#endif ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)) ++#define IEEE80211_RADIOTAP_CODING_LDPC_USER0 0x01 ++#endif ++ ++char bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; ++netdev_tx_t rwnx_start_monitor_if_xmit(struct sk_buff *skb, ++ struct net_device *dev) ++{ ++ int rtap_len, ret, idx; ++ struct ieee80211_radiotap_header *rtap_hdr; // net/ieee80211_radiotap.h ++ struct ieee80211_radiotap_iterator iterator; // net/cfg80211.h ++ u8_l *rtap_buf = (u8_l *)skb->data; ++ u8_l rate; ++ ++ struct rwnx_vif *vif = netdev_priv(dev); ++ struct rwnx_hw *rwnx_hw = vif->rwnx_hw; ++ struct rwnx_txhdr *txhdr; ++ struct rwnx_sw_txhdr *sw_txhdr; ++ struct txdesc_api *desc; ++ struct rwnx_sta *sta; ++ struct rwnx_txq *txq; ++ u16_l frame_len, headroom, frame_oft; ++ u8_l tid, rate_fmt = FORMATMOD_NON_HT, rate_idx = 0, ++ txsig_bw = PHY_CHNL_BW_20; ++ u8_l *pframe, *data; ++ bool robust; ++ struct sk_buff *skb_mgmt; ++ bool offchan = false; ++ int nx_off_chan_txq_idx = NX_OFF_CHAN_TXQ_IDX; ++ ++ rtap_hdr = (struct ieee80211_radiotap_header *)(rtap_buf); ++ rtap_len = ieee80211_get_radiotap_len(rtap_buf); //max_length ++ frame_len = skb->len; ++ ++ AICWFDBG(LOGINFO, ++ "rwnx_start_monitor_if_xmit, skb_len=%d, rtap_len=%d\n", ++ skb->len, rtap_len); ++ //rwnx_data_dump((char*)__func__, skb->data, skb->len); ++ if ((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8801) || ++ ((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DW) && ++ chip_id < 3)) { ++ nx_off_chan_txq_idx = NX_OFF_CHAN_TXQ_IDX_FOR_OLD_IC; ++ } ++ ++ if (unlikely(rtap_hdr->it_version)) { ++ AICWFDBG(LOGERROR, "%s itv \r\n", __func__); ++ goto free_tag; ++ } ++ ++ if (unlikely(skb->len < rtap_len)) { ++ AICWFDBG(LOGERROR, "%s skb->len < rtap_len \r\n", __func__); ++ goto free_tag; ++ } ++ ++ if (unlikely(rtap_len < sizeof(struct ieee80211_radiotap_header))) { ++ AICWFDBG( ++ LOGERROR, ++ "%s rtap_len < sizeof(struct ieee80211_radiotap_header) \r\n", ++ __func__); ++ goto free_tag; ++ } ++ ++ frame_len -= rtap_len; ++ pframe = rtap_buf + rtap_len; ++ ++ // Parse radiotap for injection items and overwrite attribs as needed ++ ret = ieee80211_radiotap_iterator_init(&iterator, rtap_hdr, rtap_len, ++ NULL); ++ while (!ret) { ++ ret = ieee80211_radiotap_iterator_next(&iterator); ++ if (ret) { ++ continue; ++ } ++ AICWFDBG( ++ LOGDEBUG, ++ "%s iterator.this_arg_index:%d iterator.this_arg:%x\r\n", ++ __func__, iterator.this_arg_index, *iterator.this_arg); ++ switch (iterator.this_arg_index) { ++ case IEEE80211_RADIOTAP_RATE: ++ // This is basic 802.11b/g rate; use MCS/VHT for higher rates ++ rate = *iterator.this_arg; ++ AICWFDBG(LOGDEBUG, "rate=0x%x\n", rate); ++ for (idx = 0; idx < HW_RATE_MAX; idx++) { ++ if ((rate * 5) == tx_legrates_lut_rate[idx]) { ++ AICWFDBG(LOGDEBUG, ++ "%s datarate:%d \r\n", ++ __func__, ++ tx_legrates_lut_rate[idx]); ++ break; ++ } ++ } ++ ++ if (idx < HW_RATE_MAX) { ++ rate_idx = idx; ++ AICWFDBG(LOGDEBUG, "rate_idx = %d \r\n", ++ rate_idx); ++ } else { ++ AICWFDBG(LOGERROR, ++ "invalid radiotap rate: %d\n", rate); ++ } ++ break; ++ ++ case IEEE80211_RADIOTAP_TX_FLAGS: { ++ u16_l txflags = get_unaligned_le16(iterator.this_arg); ++ AICWFDBG(LOGDEBUG, "txflags=0x%x\n", txflags); ++ if ((txflags & IEEE80211_RADIOTAP_F_TX_NOACK) == 0) { ++ AICWFDBG(LOGDEBUG, " TX_NOACK\n"); ++ } ++ if (txflags & 0x0010) { // Use preconfigured seq num ++ // NOTE: this is currently ignored due to qos_en=_FALSE and HW seq num override ++ AICWFDBG(LOGDEBUG, " GetSequence\n"); ++ } ++ } break; ++ ++ case IEEE80211_RADIOTAP_MCS: { ++ u8_l mcs_have = iterator.this_arg[0]; ++ AICWFDBG(LOGDEBUG, "mcs_have=0x%x\n", mcs_have); ++ rate_fmt = FORMATMOD_HT_MF; ++ if (mcs_have & IEEE80211_RADIOTAP_MCS_HAVE_BW) { ++ u8_l bw = (iterator.this_arg[1] & ++ IEEE80211_RADIOTAP_MCS_BW_MASK); ++ u8_l ch_offset = 0; ++ if (bw == IEEE80211_RADIOTAP_MCS_BW_40) { ++ txsig_bw = PHY_CHNL_BW_40; ++ } else if (bw == ++ IEEE80211_RADIOTAP_MCS_BW_20L) { ++ bw = IEEE80211_RADIOTAP_MCS_BW_20; ++ ch_offset = 1; // CHNL_OFFSET_LOWER; ++ } else if (bw == ++ IEEE80211_RADIOTAP_MCS_BW_20U) { ++ bw = IEEE80211_RADIOTAP_MCS_BW_20; ++ ch_offset = 2; // CHNL_OFFSET_UPPER; ++ } ++ AICWFDBG(LOGDEBUG, " bw=%d, ch_offset=%d\n", ++ bw, ch_offset); ++ } ++ if (mcs_have & IEEE80211_RADIOTAP_MCS_HAVE_MCS) { ++ u8_l fixed_rate = iterator.this_arg[2] & 0x7f; ++ if (fixed_rate > 31) { ++ fixed_rate = 0; ++ } ++ rate_idx = fixed_rate; ++ AICWFDBG(LOGDEBUG, " fixed_rate=0x%x\n", ++ fixed_rate); ++ } ++ if ((mcs_have & IEEE80211_RADIOTAP_MCS_HAVE_GI) && ++ (iterator.this_arg[1] & ++ IEEE80211_RADIOTAP_MCS_SGI)) { ++ AICWFDBG(LOGDEBUG, " sgi\n"); ++ } ++ if ((mcs_have & IEEE80211_RADIOTAP_MCS_HAVE_FEC) && ++ (iterator.this_arg[1] & ++ IEEE80211_RADIOTAP_MCS_FEC_LDPC)) { ++ AICWFDBG(LOGDEBUG, " ldpc\n"); ++ } ++ if (mcs_have & IEEE80211_RADIOTAP_MCS_HAVE_STBC) { ++ u8 stbc = (iterator.this_arg[1] & ++ IEEE80211_RADIOTAP_MCS_STBC_MASK) >> ++ IEEE80211_RADIOTAP_MCS_STBC_SHIFT; ++ AICWFDBG(LOGDEBUG, " stbc=0x%x\n", stbc); ++ } ++ } break; ++ ++ case IEEE80211_RADIOTAP_VHT: { ++ unsigned int mcs, nss; ++ u8 known = iterator.this_arg[0]; ++ u8 flags = iterator.this_arg[2]; ++ rate_fmt = FORMATMOD_VHT; ++ AICWFDBG(LOGDEBUG, "known=0x%x, flags=0x%x\n", known, ++ flags); ++ // NOTE: this code currently only supports 1SS for radiotap defined rates ++ if ((known & IEEE80211_RADIOTAP_VHT_KNOWN_STBC) && ++ (flags & IEEE80211_RADIOTAP_VHT_FLAG_STBC)) { ++ AICWFDBG(LOGDEBUG, " stbc\n"); ++ } ++ if ((known & IEEE80211_RADIOTAP_VHT_KNOWN_GI) && ++ (flags & IEEE80211_RADIOTAP_VHT_FLAG_SGI)) { ++ AICWFDBG(LOGDEBUG, " sgi\n"); ++ } ++ if (known & IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH) { ++ u8_l bw = iterator.this_arg[3] & 0x1F; ++ AICWFDBG(LOGDEBUG, " bw=0x%x\n", bw); ++ // NOTE: there are various L and U, but we just use straight 20/40/80 ++ // since it's not clear how to set CHNL_OFFSET_LOWER/_UPPER with different ++ // sideband sizes/configurations. TODO. ++ // Also, any 160 is treated as 80 due to lack of WIDTH_160. ++ txsig_bw = PHY_CHNL_BW_40; ++ if (bw == 0) { ++ txsig_bw = PHY_CHNL_BW_20; ++ AICWFDBG(LOGDEBUG, " 20M\n"); ++ } else if (bw >= 1 && bw <= 3) { ++ AICWFDBG(LOGDEBUG, " 40M\n"); ++ } else if (bw >= 4 && bw <= 10) { ++ AICWFDBG(LOGDEBUG, " 80M\n"); ++ } else if (bw >= 11 && bw <= 25) { ++ AICWFDBG(LOGDEBUG, " 160M\n"); ++ } ++ } ++ // User 0 ++ nss = iterator.this_arg[4] & ++ 0x0F; // Number of spatial streams ++ AICWFDBG(LOGDEBUG, " nss=0x%x\n", nss); ++ if (nss > 0) { ++ if (nss > 4) ++ nss = 4; ++ mcs = (iterator.this_arg[4] >> 4) & ++ 0x0F; // MCS rate index ++ if (mcs > 8) ++ mcs = 9; ++ rate_idx = mcs; ++ AICWFDBG(LOGDEBUG, " mcs=0x%x\n", mcs); ++ if (iterator.this_arg[8] & ++ IEEE80211_RADIOTAP_CODING_LDPC_USER0) { ++ AICWFDBG(LOGDEBUG, " ldpc\n"); ++ } ++ } ++ } break; ++ ++ case IEEE80211_RADIOTAP_HE: { ++ u16 data1 = ((u16)iterator.this_arg[1] << 8) | ++ iterator.this_arg[0]; ++ u16 data2 = ((u16)iterator.this_arg[3] << 8) | ++ iterator.this_arg[2]; ++ u16 data3 = ((u16)iterator.this_arg[5] << 8) | ++ iterator.this_arg[4]; ++ u16 data5 = ((u16)iterator.this_arg[9] << 8) | ++ iterator.this_arg[8]; ++ u8 fmt_he = ++ data1 & IEEE80211_RADIOTAP_HE_DATA1_FORMAT_MASK; ++ if (fmt_he == IEEE80211_RADIOTAP_HE_DATA1_FORMAT_MU) { ++ rate_fmt = FORMATMOD_HE_MU; ++ } else if (fmt_he == ++ IEEE80211_RADIOTAP_HE_DATA1_FORMAT_EXT_SU) { ++ rate_fmt = FORMATMOD_HE_ER; ++ } else { ++ rate_fmt = FORMATMOD_HE_SU; ++ } ++ if (data1 & ++ IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN) { ++ u8 mcs = ++ (data3 & ++ IEEE80211_RADIOTAP_HE_DATA3_DATA_MCS) >> ++ 8; ++ if (mcs > 11) ++ mcs = 11; ++ rate_idx = mcs; ++ } ++ if (data1 & ++ IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN) { ++ u8 bw = data5 & ++ IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC; ++ txsig_bw = ++ (bw == ++ IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_20MHZ) ? ++ PHY_CHNL_BW_20 : ++ PHY_CHNL_BW_40; ++ } ++ if (data2 & IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN) { ++ u8 gi = (data5 & ++ IEEE80211_RADIOTAP_HE_DATA5_GI) >> ++ 4; ++ AICWFDBG(LOGDEBUG, " gi: %d\n", gi); ++ } ++ } break; ++ ++ default: ++ AICWFDBG(LOGERROR, "unparsed arg: 0x%x\n", ++ iterator.this_arg_index); ++ break; ++ } ++ } ++ ++#if 0 ++ // dump buffer ++ tmp_len = 128; ++ if (skb->len < 128) { ++ tmp_len = skb->len; ++ } ++ for (idx = 0; idx < tmp_len; idx+=16) { ++ printk("[%04X] %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", idx, ++ rtap_buf[idx+0],rtap_buf[idx+1],rtap_buf[idx+2],rtap_buf[idx+3], ++ rtap_buf[idx+4],rtap_buf[idx+5],rtap_buf[idx+6],rtap_buf[idx+7], ++ rtap_buf[idx+8],rtap_buf[idx+9],rtap_buf[idx+10],rtap_buf[idx+11], ++ rtap_buf[idx+12],rtap_buf[idx+13],rtap_buf[idx+14],rtap_buf[idx+15]); ++ } ++#endif ++ //rwnx_data_dump((char*)__func__, pframe, frame_len); ++ ++ /* Get the STA id and TID information */ ++ sta = rwnx_get_tx_priv(vif, skb, &tid); ++ //if (!sta) { ++ // printk("sta=null, tid=0x%x\n", tid); ++ //} ++ /* Set TID and Queues indexes */ ++ if (sta) { ++ txq = rwnx_txq_sta_get(sta, 8, rwnx_hw); ++ } else { ++ if (offchan) ++ txq = &rwnx_hw->txq[nx_off_chan_txq_idx]; ++ else ++ txq = rwnx_txq_vif_get(vif, NX_UNK_TXQ_TYPE); ++ } ++ if (txq->idx == TXQ_INACTIVE) { ++ AICWFDBG(LOGERROR, "TXQ_INACTIVE\n"); ++ goto free_tag; ++ } ++ // prepare to xmit ++ headroom = sizeof(struct rwnx_txhdr); ++ skb_mgmt = dev_alloc_skb(headroom + frame_len); ++ if (!skb_mgmt) { ++ AICWFDBG(LOGERROR, "skb_mgmt alloc fail\n"); ++ goto free_tag; ++ } ++ skb_reserve(skb_mgmt, headroom); ++ data = skb_put(skb_mgmt, frame_len); ++ /* Copy the provided data */ ++ memcpy(data, pframe, frame_len); ++ robust = ieee80211_is_robust_mgmt_frame( ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)) ++ (void *)skb_mgmt ++#else ++ skb_mgmt ++#endif ++ ); ++ skb_push(skb_mgmt, headroom); ++ /* Fill the TX Header */ ++ txhdr = (struct rwnx_txhdr *)skb_mgmt->data; ++ txhdr->hw_hdr.cfm.status.value = 0; ++ /* Fill the SW TX Header */ ++ sw_txhdr = kmem_cache_alloc(rwnx_hw->sw_txhdr_cache, GFP_ATOMIC); ++ if (unlikely(sw_txhdr == NULL)) { ++ dev_kfree_skb(skb_mgmt); ++ AICWFDBG(LOGERROR, "sw_txhdr alloc fail\n"); ++ goto free_tag; ++ } ++ txhdr->sw_hdr = sw_txhdr; ++ sw_txhdr->txq = txq; ++ sw_txhdr->frame_len = frame_len; ++ sw_txhdr->rwnx_sta = sta; ++ sw_txhdr->rwnx_vif = vif; ++ sw_txhdr->skb = skb_mgmt; ++ sw_txhdr->headroom = headroom; ++ sw_txhdr->map_len = skb_mgmt->len - offsetof(struct rwnx_txhdr, hw_hdr); ++ sw_txhdr->raw_frame = 1; ++ sw_txhdr->fixed_rate = 1; ++ sw_txhdr->rate_config = ++ ((rate_fmt << FORMAT_MOD_TX_RCX_OFT) & FORMAT_MOD_TX_RCX_MASK) | ++ ((txsig_bw << BW_TX_RCX_OFT) & BW_TX_RCX_MASK) | ++ ((rate_idx << MCS_INDEX_TX_RCX_OFT) & ++ MCS_INDEX_TX_RCX_MASK); // from radiotap ++ /* Fill the Descriptor to be provided to the MAC SW */ ++ desc = &sw_txhdr->desc; ++ desc->host.staid = (sta) ? sta->sta_idx : 0xFF; ++ desc->host.vif_idx = vif->vif_index; ++ desc->host.tid = 0xFF; ++ desc->host.flags = TXU_CNTRL_MGMT; ++ if (robust) { ++ desc->host.flags |= TXU_CNTRL_MGMT_ROBUST; ++ } ++ 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_len[0] = frame_len; ++ desc->host.packet_cnt = 1; ++#else ++ desc->host.packet_addr = sw_txhdr->dma_addr + frame_oft; ++ desc->host.packet_len = frame_len; ++#endif ++#else ++ desc->host.packet_len = frame_len; ++#endif ++ ++ desc->host.hostid = sw_txhdr->dma_addr; ++ ++ memcpy(desc->host.eth_dest_addr.array, bcast, ETH_ALEN); ++ ++ spin_lock_bh(&rwnx_hw->tx_lock); ++ AICWFDBG(LOGTRACE, "%s send data\r\n", __func__); ++ if (rwnx_txq_queue_skb(skb_mgmt, txq, rwnx_hw, false)) ++ rwnx_hwq_process(rwnx_hw, txq->hwq); ++ spin_unlock_bh(&rwnx_hw->tx_lock); ++ ++free_tag: ++ dev_kfree_skb_any(skb); ++ return NETDEV_TX_OK; ++} ++#endif ++ ++/** ++ * rwnx_start_mgmt_xmit - Transmit a management frame ++ * ++ * @vif: Vif that send the frame ++ * @sta: Destination of the frame. May be NULL if the destiantion is unknown ++ * to the AP. ++ * @params: Mgmt frame parameters ++ * @offchan: Indicate whether the frame must be send via the offchan TXQ. ++ * (is is redundant with params->offchan ?) ++ * @cookie: updated with a unique value to identify the frame with upper layer ++ * ++ */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) ++int rwnx_start_mgmt_xmit(struct rwnx_vif *vif, struct rwnx_sta *sta, ++ struct cfg80211_mgmt_tx_params *params, bool offchan, ++ u64 *cookie) ++#else ++int rwnx_start_mgmt_xmit(struct rwnx_vif *vif, struct rwnx_sta *sta, ++ struct ieee80211_channel *channel, bool offchan, ++ unsigned int wait, const u8 *buf, size_t len, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) ++ bool no_cck, ++#endif ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) ++ bool dont_wait_for_ack, ++#endif ++ u64 *cookie) ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ ++{ ++ struct rwnx_hw *rwnx_hw = vif->rwnx_hw; ++ struct rwnx_txhdr *txhdr; ++ struct rwnx_sw_txhdr *sw_txhdr; ++ struct txdesc_api *desc; ++ struct sk_buff *skb; ++ u16 frame_len, headroom, frame_oft; ++ u8 *data; ++ int nx_off_chan_txq_idx = NX_OFF_CHAN_TXQ_IDX; ++ struct rwnx_txq *txq; ++ bool robust; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) ++ const u8 *buf = params->buf; ++ size_t len = params->len; ++ bool no_cck = params->no_cck; ++#endif ++ ++ AICWFDBG(LOGDEBUG, "mgmt xmit %x %x ", buf[0], buf[1]); ++ ++ if ((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8801) || ++ ((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DW) && ++ chip_id < 3)) { ++ nx_off_chan_txq_idx = NX_OFF_CHAN_TXQ_IDX_FOR_OLD_IC; ++ } ++ ++ headroom = sizeof(struct rwnx_txhdr); ++ frame_len = len; ++ ++ //---------------------------------------------------------------------- ++ ++ /* Set TID and Queues indexes */ ++ if (sta) { ++ txq = rwnx_txq_sta_get(sta, 8, rwnx_hw); ++ } else { ++ if (offchan) ++ txq = &rwnx_hw->txq[nx_off_chan_txq_idx]; ++ else ++ txq = rwnx_txq_vif_get(vif, NX_UNK_TXQ_TYPE); ++ } ++ ++ /* Ensure that TXQ is active */ ++ if (txq->idx == TXQ_INACTIVE) { ++ netdev_dbg(vif->ndev, "TXQ inactive\n"); ++ return -EBUSY; ++ } ++ ++ /* ++ * Create a SK Buff object that will contain the provided data ++ */ ++ skb = dev_alloc_skb(headroom + frame_len); ++ ++ if (!skb) { ++ return -ENOMEM; ++ } ++ ++ *cookie = (unsigned long)skb; ++ ++ /* ++ * Move skb->data pointer in order to reserve room for rwnx_txhdr ++ * headroom value will be equal to sizeof(struct rwnx_txhdr) ++ */ ++ skb_reserve(skb, headroom); ++ ++ /* ++ * Extend the buffer data area in order to contain the provided packet ++ * len value (for skb) will be equal to param->len ++ */ ++ data = skb_put(skb, frame_len); ++ /* Copy the provided data */ ++ memcpy(data, buf, frame_len); ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) ++ robust = ieee80211_is_robust_mgmt_frame(skb); ++#else ++ if (skb->len < 25) { ++ robust = false; ++ } ++ robust = ieee80211_is_robust_mgmt_frame((void *)skb->data); ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) ++ /* Update CSA counter if present */ ++ if (unlikely(params->n_csa_offsets) && ++ vif->wdev.iftype == NL80211_IFTYPE_AP && vif->ap.csa) { ++ int i; ++ ++ data = skb->data; ++ for (i = 0; i < params->n_csa_offsets; i++) { ++ data[params->csa_offsets[i]] = vif->ap.csa->count; ++ } ++ } ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ ++ ++ /* ++ * Go back to the beginning of the allocated data area ++ * skb->data pointer will move backward ++ */ ++ skb_push(skb, headroom); ++ ++ //---------------------------------------------------------------------- ++ ++ /* Fill the TX Header */ ++ txhdr = (struct rwnx_txhdr *)skb->data; ++ ++ txhdr->hw_hdr.cfm.status.value = 0; ++ ++ //---------------------------------------------------------------------- ++ ++ /* Fill the SW TX Header */ ++ sw_txhdr = kmem_cache_alloc(rwnx_hw->sw_txhdr_cache, GFP_ATOMIC); ++ if (unlikely(sw_txhdr == NULL)) { ++ dev_kfree_skb(skb); ++ return -ENOMEM; ++ } ++ txhdr->sw_hdr = sw_txhdr; ++ ++ sw_txhdr->txq = txq; ++ sw_txhdr->frame_len = frame_len; ++ sw_txhdr->rwnx_sta = sta; ++ sw_txhdr->rwnx_vif = vif; ++ sw_txhdr->skb = skb; ++ sw_txhdr->headroom = headroom; ++ sw_txhdr->map_len = skb->len - offsetof(struct rwnx_txhdr, hw_hdr); ++#ifdef CONFIG_RWNX_AMSDUS_TX ++ sw_txhdr->amsdu.len = 0; ++ sw_txhdr->amsdu.nb = 0; ++#endif ++ sw_txhdr->raw_frame = 0; ++ sw_txhdr->fixed_rate = 0; ++ ++ //---------------------------------------------------------------------- ++ ++ /* Fill the Descriptor to be provided to the MAC SW */ ++ desc = &sw_txhdr->desc; ++ ++ desc->host.ethertype = 0; ++ desc->host.staid = (sta) ? sta->sta_idx : 0xFF; ++ desc->host.vif_idx = vif->vif_index; ++ desc->host.tid = 0xFF; ++ desc->host.flags = TXU_CNTRL_MGMT; ++ if (robust) ++ desc->host.flags |= TXU_CNTRL_MGMT_ROBUST; ++ ++#ifdef CONFIG_RWNX_SPLIT_TX_BUF ++ desc->host.packet_len[0] = frame_len; ++#else ++ desc->host.packet_len = frame_len; ++#endif ++ ++ if (no_cck) { ++ desc->host.flags |= TXU_CNTRL_MGMT_NO_CCK; ++ } ++ ++ /* Get DMA Address */ ++ if (unlikely(rwnx_prep_tx(rwnx_hw, txhdr))) { ++ kmem_cache_free(rwnx_hw->sw_txhdr_cache, sw_txhdr); ++ dev_kfree_skb(skb); ++ return -EBUSY; ++ } ++ ++ 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.hostid = sw_txhdr->dma_addr; ++ ++ //---------------------------------------------------------------------- ++ ++ spin_lock_bh(&rwnx_hw->tx_lock); ++ if (rwnx_txq_queue_skb(skb, txq, rwnx_hw, false)) ++ rwnx_hwq_process(rwnx_hw, txq->hwq); ++ spin_unlock_bh(&rwnx_hw->tx_lock); ++ ++ return 0; ++} ++ ++/** ++ * rwnx_txdatacfm - FW callback for TX confirmation ++ * ++ * called with tx_lock hold ++ */ ++int rwnx_txdatacfm(void *pthis, void *host_id) ++{ ++ struct rwnx_hw *rwnx_hw = (struct rwnx_hw *)pthis; ++ struct sk_buff *skb = host_id; ++ struct rwnx_txhdr *txhdr; ++ union rwnx_hw_txstatus rwnx_txst; ++ 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); ++ ++ txhdr = (struct rwnx_txhdr *)skb->data; ++ sw_txhdr = txhdr->sw_hdr; ++ ++ /* Read status in the TX control header */ ++ rwnx_txst = txhdr->hw_hdr.cfm.status; ++ ++ /* Check status in the header. If status is null, it means that the buffer ++ * was not transmitted and we have to return immediately */ ++ if (rwnx_txst.value == 0) { ++ return -1; ++ } ++ ++#ifdef AICWF_USB_SUPPORT ++ if (rwnx_hw->usbdev->state == USB_DOWN_ST) { ++ headroom = sw_txhdr->headroom; ++ kmem_cache_free(rwnx_hw->sw_txhdr_cache, sw_txhdr); ++ skb_pull(skb, headroom); ++ consume_skb(skb); ++ return 0; ++ } ++#endif ++#ifdef AICWF_SDIO_SUPPORT ++ if (rwnx_hw->sdiodev->bus_if->state == BUS_DOWN_ST) { ++ headroom = sw_txhdr->headroom; ++ kmem_cache_free(rwnx_hw->sw_txhdr_cache, sw_txhdr); ++ skb_pull(skb, headroom); ++ consume_skb(skb); ++ return 0; ++ } ++#endif ++ ++ txq = sw_txhdr->txq; ++ /* don't use txq->hwq as it may have changed between push and confirm */ ++ hwq = &rwnx_hw->hwq[sw_txhdr->hw_queue]; ++ rwnx_txq_confirm_any(rwnx_hw, txq, hwq, sw_txhdr); ++ ++ /* Update txq and HW queue credits */ ++ if (sw_txhdr->desc.host.flags & TXU_CNTRL_MGMT) { ++ 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, ++ (skb->data + sw_txhdr->headroom), ++ sw_txhdr->frame_len, ++ rwnx_txst.acknowledged, GFP_ATOMIC); ++ } else if ((txq->idx != TXQ_INACTIVE) && ++ (rwnx_txst.retry_required || rwnx_txst.sw_retry_required)) { ++ bool sw_retry = (rwnx_txst.sw_retry_required) ? true : false; ++ ++ /* Reset the status */ ++ txhdr->hw_hdr.cfm.status.value = 0; ++ ++ /* The confirmed packet was part of an AMPDU and not acked ++ * correctly, so reinject it in the TX path to be retried */ ++ 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) { ++#if 0 ++ if (txhdr->hw_hdr.cfm.credits) { ++ txq->credits += txhdr->hw_hdr.cfm.credits; ++ if (txq->credits <= 0) ++ rwnx_txq_stop(txq, RWNX_TXQ_STOP_FULL); ++ else if (txq->credits > 0) ++ rwnx_txq_start(txq, RWNX_TXQ_STOP_FULL); ++ } ++#endif ++ ++ /* continue service period */ ++ if (unlikely(txq->push_limit && !rwnx_txq_is_full(txq))) { ++ rwnx_txq_add_to_hw_list(txq); ++ } ++ } ++ ++ if (txhdr->hw_hdr.cfm.ampdu_size && ++ txhdr->hw_hdr.cfm.ampdu_size < IEEE80211_MAX_AMPDU_BUF) ++ rwnx_hw->stats.ampdus_tx[txhdr->hw_hdr.cfm.ampdu_size - 1]++; ++ ++#ifdef CONFIG_RWNX_AMSDUS_TX ++ txq->amsdu_len = txhdr->hw_hdr.cfm.amsdu_size; ++#endif ++ ++ /* Update statistics */ ++ sw_txhdr->rwnx_vif->net_stats.tx_packets++; ++ sw_txhdr->rwnx_vif->net_stats.tx_bytes += sw_txhdr->frame_len; ++ ++ /* Release SKBs */ ++#ifdef CONFIG_RWNX_AMSDUS_TX ++ if (sw_txhdr->desc.host.flags & TXU_CNTRL_AMSDU) { ++ struct rwnx_amsdu_txhdr *amsdu_txhdr; ++ list_for_each_entry (amsdu_txhdr, &sw_txhdr->amsdu.hdrs, list) { ++ rwnx_amsdu_del_subframe_header(amsdu_txhdr); ++ consume_skb(amsdu_txhdr->skb); ++ } ++ } ++#endif /* CONFIG_RWNX_AMSDUS_TX */ ++ ++ headroom = sw_txhdr->headroom; ++ kmem_cache_free(rwnx_hw->sw_txhdr_cache, sw_txhdr); ++ skb_pull(skb, headroom); ++ consume_skb(skb); ++ ++ return 0; ++} ++ ++/** ++ * rwnx_txq_credit_update - Update credit for one txq ++ * ++ * @rwnx_hw: Driver main data ++ * @sta_idx: STA idx ++ * @tid: TID ++ * @update: offset to apply in txq credits ++ * ++ * Called when fw send ME_TX_CREDITS_UPDATE_IND message. ++ * Apply @update to txq credits, and stop/start the txq if needed ++ */ ++void rwnx_txq_credit_update(struct rwnx_hw *rwnx_hw, int sta_idx, u8 tid, ++ s8 update) ++{ ++ struct rwnx_sta *sta = &rwnx_hw->sta_table[sta_idx]; ++ struct rwnx_txq *txq; ++ ++ txq = rwnx_txq_sta_get(sta, tid, rwnx_hw); ++ ++ spin_lock_bh(&rwnx_hw->tx_lock); ++ ++ 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 ++ rwnx_txq_start(txq, RWNX_TXQ_STOP_FULL); ++ } ++ ++ spin_unlock_bh(&rwnx_hw->tx_lock); ++} +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_tx.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_tx.h +new file mode 100755 +index 000000000..f77f1f9f1 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_tx.h +@@ -0,0 +1,195 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_tx.h ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ ****************************************************************************** ++ */ ++#ifndef _RWNX_TX_H_ ++#define _RWNX_TX_H_ ++ ++#include ++#include ++#include ++#include "lmac_types.h" ++#include "ipc_shared.h" ++#include "rwnx_txq.h" ++#include "hal_desc.h" ++ ++#define RWNX_HWQ_BK 0 ++#define RWNX_HWQ_BE 1 ++#define RWNX_HWQ_VI 2 ++#define RWNX_HWQ_VO 3 ++#define RWNX_HWQ_BCMC 4 ++#define RWNX_HWQ_NB NX_TXQ_CNT ++#define RWNX_HWQ_ALL_ACS (RWNX_HWQ_BK | RWNX_HWQ_BE | RWNX_HWQ_VI | RWNX_HWQ_VO) ++#define RWNX_HWQ_ALL_ACS_BIT \ ++ (BIT(RWNX_HWQ_BK) | BIT(RWNX_HWQ_BE) | BIT(RWNX_HWQ_VI) | \ ++ BIT(RWNX_HWQ_VO)) ++ ++#define RWNX_TX_LIFETIME_MS 1000 ++#define RWNX_TX_MAX_RATES NX_TX_MAX_RATES ++ ++#define RWNX_SWTXHDR_ALIGN_SZ 4 ++#define RWNX_SWTXHDR_ALIGN_MSK (RWNX_SWTXHDR_ALIGN_SZ - 1) ++#define RWNX_SWTXHDR_ALIGN_PADS(x) \ ++ ((RWNX_SWTXHDR_ALIGN_SZ - ((x)&RWNX_SWTXHDR_ALIGN_MSK)) & \ ++ RWNX_SWTXHDR_ALIGN_MSK) ++#if RWNX_SWTXHDR_ALIGN_SZ & RWNX_SWTXHDR_ALIGN_MSK ++#error bad RWNX_SWTXHDR_ALIGN_SZ ++#endif ++ ++#define AMSDU_PADDING(x) ((4 - ((x)&0x3)) & 0x3) ++ ++#define TXU_CNTRL_RETRY BIT(0) ++#define TXU_CNTRL_MORE_DATA BIT(2) ++#define TXU_CNTRL_MGMT BIT(3) ++#define TXU_CNTRL_MGMT_NO_CCK BIT(4) ++#define TXU_CNTRL_AMSDU BIT(6) ++#define TXU_CNTRL_MGMT_ROBUST BIT(7) ++#define TXU_CNTRL_USE_4ADDR BIT(8) ++#define TXU_CNTRL_EOSP BIT(9) ++#define TXU_CNTRL_MESH_FWD BIT(10) ++#define TXU_CNTRL_TDLS BIT(11) ++ ++extern const int rwnx_tid2hwq[IEEE80211_NUM_TIDS]; ++ ++/** ++ * struct rwnx_amsdu_txhdr - Structure added in skb headroom (instead of ++ * rwnx_txhdr) for amsdu subframe buffer (except for the first subframe ++ * that has a normal rwnx_txhdr) ++ * ++ * @list List of other amsdu subframe (rwnx_sw_txhdr.amsdu.hdrs) ++ * @map_len Length to be downloaded for this subframe ++ * @dma_addr Buffer address form embedded point of view ++ * @skb skb ++ * @pad padding added before this subframe ++ * (only use when amsdu must be dismantled) ++ * @msdu_len Size, in bytes, of the MSDU (without padding nor amsdu header) ++ */ ++struct rwnx_amsdu_txhdr { ++ struct list_head list; ++ size_t map_len; ++ dma_addr_t dma_addr; ++ struct sk_buff *skb; ++ u16 pad; ++ u16 msdu_len; ++}; ++ ++/** ++ * struct rwnx_amsdu - Structure to manage creation of an A-MSDU, updated ++ * only In the first subframe of an A-MSDU ++ * ++ * @hdrs List of subframe of rwnx_amsdu_txhdr ++ * @len Current size for this A-MDSU (doesn't take padding into account) ++ * 0 means that no amsdu is in progress ++ * @nb Number of subframe in the amsdu ++ * @pad Padding to add before adding a new subframe ++ */ ++struct rwnx_amsdu { ++ struct list_head hdrs; ++ u16 len; ++ u8 nb; ++ u8 pad; ++}; ++ ++/** ++ * struct rwnx_sw_txhdr - Software part of tx header ++ * ++ * @rwnx_sta sta to which this buffer is addressed ++ * @rwnx_vif vif that send the buffer ++ * @txq pointer to TXQ used to send the buffer ++ * @hw_queue Index of the HWQ used to push the buffer. ++ * May be different than txq->hwq->id on confirmation. ++ * @frame_len Size of the frame (doesn't not include mac header) ++ * (Only used to update stat, can't we use skb->len instead ?) ++ * @headroom Headroom added in skb to add rwnx_txhdr ++ * (Only used to remove it before freeing skb, is it needed ?) ++ * @amsdu Description of amsdu whose first subframe is this buffer ++ * (amsdu.nb = 0 means this buffer is not part of amsdu) ++ * @skb skb received from transmission ++ * @map_len Length mapped for DMA (only rwnx_hw_txhdr and data are mapped) ++ * @dma_addr DMA address after mapping ++ * @desc Buffer description that will be copied in shared mem for FW ++ */ ++struct rwnx_sw_txhdr { ++ struct rwnx_sta *rwnx_sta; ++ struct rwnx_vif *rwnx_vif; ++ struct rwnx_txq *txq; ++ u8 hw_queue; ++ u16 frame_len; ++ u16 headroom; ++#ifdef CONFIG_RWNX_AMSDUS_TX ++ struct rwnx_amsdu amsdu; ++#endif ++ u32 need_cfm; ++ struct sk_buff *skb; ++ ++ size_t map_len; ++ dma_addr_t dma_addr; ++ struct txdesc_api desc; ++ ++ u8 raw_frame; ++ u8 fixed_rate; ++ u16 rate_config; ++}; ++ ++/** ++ * struct rwnx_txhdr - Stucture to control transimission of packet ++ * (Added in skb headroom) ++ * ++ * @sw_hdr: Information from driver ++ * @cache_guard: ++ * @hw_hdr: Information for/from hardware ++ */ ++struct rwnx_txhdr { ++ struct rwnx_sw_txhdr *sw_hdr; ++ char cache_guard[L1_CACHE_BYTES]; ++ struct rwnx_hw_txhdr hw_hdr; ++}; ++ ++u16 rwnx_select_txq(struct rwnx_vif *rwnx_vif, struct sk_buff *skb); ++netdev_tx_t rwnx_start_xmit(struct sk_buff *skb, struct net_device *dev); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) ++int rwnx_start_mgmt_xmit(struct rwnx_vif *vif, struct rwnx_sta *sta, ++ struct cfg80211_mgmt_tx_params *params, bool offchan, ++ u64 *cookie); ++#else ++int rwnx_start_mgmt_xmit(struct rwnx_vif *vif, struct rwnx_sta *sta, ++ struct ieee80211_channel *channel, bool offchan, ++ unsigned int wait, const u8 *buf, size_t len, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) ++ bool no_cck, ++#endif ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) ++ bool dont_wait_for_ack, ++#endif ++ u64 *cookie); ++#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ ++ ++#ifdef CONFIG_RWNX_MON_XMIT ++int rwnx_start_monitor_if_xmit(struct sk_buff *skb, struct net_device *dev); ++#endif ++int rwnx_txdatacfm(void *pthis, void *host_id); ++ ++struct rwnx_hw; ++struct rwnx_sta; ++void rwnx_set_traffic_status(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta, ++ bool available, u8 ps_id); ++void rwnx_ps_bh_enable(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta, ++ bool enable); ++void rwnx_ps_bh_traffic_req(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta, ++ u16 pkt_req, u8 ps_id); ++ ++void rwnx_switch_vif_sta_txq(struct rwnx_sta *sta, struct rwnx_vif *old_vif, ++ struct rwnx_vif *new_vif); ++ ++int rwnx_dbgfs_print_sta(char *buf, size_t size, struct rwnx_sta *sta, ++ struct rwnx_hw *rwnx_hw); ++void rwnx_txq_credit_update(struct rwnx_hw *rwnx_hw, int sta_idx, u8 tid, ++ s8 update); ++void rwnx_tx_push(struct rwnx_hw *rwnx_hw, struct rwnx_txhdr *txhdr, int flags); ++ ++#endif /* _RWNX_TX_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_txq.c b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_txq.c +new file mode 100755 +index 000000000..9ec9e9cef +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_txq.c +@@ -0,0 +1,1381 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_txq.c ++ * ++ * Copyright (C) RivieraWaves 2016-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++#include "rwnx_defs.h" ++#include "rwnx_tx.h" ++#include "ipc_host.h" ++#include "rwnx_events.h" ++ ++/****************************************************************************** ++ * Utils functions ++ *****************************************************************************/ ++#ifdef CONFIG_RWNX_FULLMAC ++const int nx_tid_prio[NX_NB_TID_PER_STA] = { 7, 6, 5, 4, 3, 0, 2, 1 }; ++ ++#ifdef CONFIG_TX_NETIF_FLOWCTRL ++extern int tx_fc_low_water; ++extern int tx_fc_high_water; ++#endif ++ ++static inline int rwnx_txq_sta_idx(struct rwnx_sta *sta, u8 tid) ++{ ++ if (is_multicast_sta(sta->sta_idx)) { ++ if ((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8801) || ++ ((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DW) && ++ chip_id < 3)) { ++ return NX_FIRST_VIF_TXQ_IDX_FOR_OLD_IC + sta->vif_idx; ++ } else { ++ return NX_FIRST_VIF_TXQ_IDX + sta->vif_idx; ++ } ++ } else { ++ return (sta->sta_idx * NX_NB_TXQ_PER_STA) + tid; ++ } ++} ++ ++static inline int rwnx_txq_vif_idx(struct rwnx_vif *vif, u8 type) ++{ ++ if ((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8801) || ++ ((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DW) && ++ chip_id < 3)) { ++ return NX_FIRST_VIF_TXQ_IDX_FOR_OLD_IC + master_vif_idx(vif) + ++ (type * NX_VIRT_DEV_MAX); ++ } else { ++ return NX_FIRST_VIF_TXQ_IDX + master_vif_idx(vif) + ++ (type * NX_VIRT_DEV_MAX); ++ } ++} ++ ++struct rwnx_txq *rwnx_txq_sta_get(struct rwnx_sta *sta, u8 tid, ++ struct rwnx_hw *rwnx_hw) ++{ ++ if (tid >= NX_NB_TXQ_PER_STA) ++ tid = 0; ++ ++ return &rwnx_hw->txq[rwnx_txq_sta_idx(sta, tid)]; ++} ++ ++struct rwnx_txq *rwnx_txq_vif_get(struct rwnx_vif *vif, u8 type) ++{ ++ if (type > NX_UNK_TXQ_TYPE) ++ type = NX_BCMC_TXQ_TYPE; ++ ++ return &vif->rwnx_hw->txq[rwnx_txq_vif_idx(vif, type)]; ++} ++ ++static inline struct rwnx_sta *rwnx_txq_2_sta(struct rwnx_txq *txq) ++{ ++ return txq->sta; ++} ++ ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++/****************************************************************************** ++ * Init/Deinit functions ++ *****************************************************************************/ ++/** ++ * rwnx_txq_init - Initialize a TX queue ++ * ++ * @txq: TX queue to be initialized ++ * @idx: TX queue index ++ * @status: TX queue initial status ++ * @hwq: Associated HW queue ++ * @ndev: Net device this queue belongs to ++ * (may be null for non netdev txq) ++ * ++ * Each queue is initialized with the credit of @NX_TXQ_INITIAL_CREDITS. ++ */ ++static void rwnx_txq_init(struct rwnx_txq *txq, int idx, u8 status, ++ struct rwnx_hwq *hwq, int tid, ++#ifdef CONFIG_RWNX_FULLMAC ++ struct rwnx_sta *sta, struct net_device *ndev ++#endif ++) ++{ ++ int i; ++ int nx_first_unk_txq_idx = NX_FIRST_UNK_TXQ_IDX; ++ int nx_bcmc_txq_ndev_idx = NX_BCMC_TXQ_NDEV_IDX; ++ int nx_first_vif_txq_idx = NX_FIRST_VIF_TXQ_IDX; ++ ++ if ((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8801) || ++ ((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DW) && ++ chip_id < 3)) { ++ nx_first_unk_txq_idx = NX_FIRST_UNK_TXQ_IDX_FOR_OLD_IC; ++ nx_bcmc_txq_ndev_idx = NX_BCMC_TXQ_NDEV_IDX_FOR_OLD_IC; ++ nx_first_vif_txq_idx = NX_FIRST_VIF_TXQ_IDX_FOR_OLD_IC; ++ } ++ ++ txq->idx = idx; ++ txq->status = status; ++ txq->credits = NX_TXQ_INITIAL_CREDITS; ++ txq->pkt_sent = 0; ++ skb_queue_head_init(&txq->sk_list); ++ txq->last_retry_skb = NULL; ++ txq->nb_retry = 0; ++ txq->hwq = hwq; ++ txq->sta = sta; ++ for (i = 0; i < CONFIG_USER_MAX; i++) ++ txq->pkt_pushed[i] = 0; ++ txq->push_limit = 0; ++ txq->tid = tid; ++#ifdef CONFIG_MAC80211_TXQ ++ txq->nb_ready_mac80211 = 0; ++#endif ++#ifdef CONFIG_RWNX_FULLMAC ++ txq->ps_id = LEGACY_PS_ID; ++ if (idx < nx_first_vif_txq_idx) { ++ int sta_idx = sta->sta_idx; ++ int tid = idx - (sta_idx * NX_NB_TXQ_PER_STA); ++ if (tid < NX_NB_TID_PER_STA) ++ txq->ndev_idx = NX_STA_NDEV_IDX(tid, sta_idx); ++ else ++ txq->ndev_idx = NDEV_NO_TXQ; ++ } else if (idx < nx_first_unk_txq_idx) { ++ txq->ndev_idx = nx_bcmc_txq_ndev_idx; ++ } else { ++ txq->ndev_idx = NDEV_NO_TXQ; ++ } ++ txq->ndev = ndev; ++#ifdef CONFIG_RWNX_AMSDUS_TX ++ txq->amsdu = NULL; ++ txq->amsdu_len = 0; ++#endif /* CONFIG_RWNX_AMSDUS_TX */ ++#endif /* CONFIG_RWNX_FULLMAC */ ++} ++ ++/** ++ * rwnx_txq_flush - Flush all buffers queued for a TXQ ++ * ++ * @rwnx_hw: main driver data ++ * @txq: txq to flush ++ */ ++void rwnx_txq_flush(struct rwnx_hw *rwnx_hw, struct rwnx_txq *txq) ++{ ++ struct sk_buff *skb; ++ ++ while ((skb = skb_dequeue(&txq->sk_list)) != NULL) { ++ struct rwnx_sw_txhdr *sw_txhdr = ++ ((struct rwnx_txhdr *)skb->data)->sw_hdr; ++ ++#ifdef CONFIG_RWNX_AMSDUS_TX ++ 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); ++ 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); ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ dev_kfree_skb_any(skb); ++#endif /* CONFIG_RWNX_FULLMAC */ ++ } ++} ++ ++/** ++ * rwnx_txq_deinit - De-initialize a TX queue ++ * ++ * @rwnx_hw: Driver main data ++ * @txq: TX queue to be de-initialized ++ * Any buffer stuck in a queue will be freed. ++ */ ++static void rwnx_txq_deinit(struct rwnx_hw *rwnx_hw, struct rwnx_txq *txq) ++{ ++ if (txq->idx == TXQ_INACTIVE) ++ return; ++ ++ spin_lock_bh(&rwnx_hw->tx_lock); ++ rwnx_txq_del_from_hw_list(txq); ++ txq->idx = TXQ_INACTIVE; ++ spin_unlock_bh(&rwnx_hw->tx_lock); ++ ++ rwnx_txq_flush(rwnx_hw, txq); ++} ++ ++/** ++ * rwnx_txq_vif_init - Initialize all TXQ linked to a vif ++ * ++ * @rwnx_hw: main driver data ++ * @rwnx_vif: Pointer on VIF ++ * @status: Intial txq status ++ * ++ * Softmac : 1 VIF TXQ per HWQ ++ * ++ * Fullmac : 1 VIF TXQ for BC/MC ++ * 1 VIF TXQ for MGMT to unknown STA ++ */ ++void rwnx_txq_vif_init(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif, ++ u8 status) ++{ ++ struct rwnx_txq *txq; ++ int idx; ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ txq = rwnx_txq_vif_get(rwnx_vif, NX_BCMC_TXQ_TYPE); ++ idx = rwnx_txq_vif_idx(rwnx_vif, NX_BCMC_TXQ_TYPE); ++ rwnx_txq_init(txq, idx, status, &rwnx_hw->hwq[RWNX_HWQ_BE], 0, ++ &rwnx_hw->sta_table[rwnx_vif->ap.bcmc_index], ++ rwnx_vif->ndev); ++ ++ txq = rwnx_txq_vif_get(rwnx_vif, NX_UNK_TXQ_TYPE); ++ idx = rwnx_txq_vif_idx(rwnx_vif, NX_UNK_TXQ_TYPE); ++ rwnx_txq_init(txq, idx, status, &rwnx_hw->hwq[RWNX_HWQ_VO], TID_MGT, ++ NULL, rwnx_vif->ndev); ++ ++#endif /* CONFIG_RWNX_FULLMAC */ ++} ++ ++/** ++ * rwnx_txq_vif_deinit - Deinitialize all TXQ linked to a vif ++ * ++ * @rwnx_hw: main driver data ++ * @rwnx_vif: Pointer on VIF ++ */ ++void rwnx_txq_vif_deinit(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif) ++{ ++ struct rwnx_txq *txq; ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ txq = rwnx_txq_vif_get(rwnx_vif, NX_BCMC_TXQ_TYPE); ++ rwnx_txq_deinit(rwnx_hw, txq); ++ ++ txq = rwnx_txq_vif_get(rwnx_vif, NX_UNK_TXQ_TYPE); ++ rwnx_txq_deinit(rwnx_hw, txq); ++ ++#endif /* CONFIG_RWNX_FULLMAC */ ++} ++ ++/** ++ * rwnx_txq_sta_init - Initialize TX queues for a STA ++ * ++ * @rwnx_hw: Main driver data ++ * @rwnx_sta: STA for which tx queues need to be initialized ++ * @status: Intial txq status ++ * ++ * This function initialize all the TXQ associated to a STA. ++ * Softmac : 1 TXQ per TID ++ * ++ * Fullmac : 1 TXQ per TID (limited to 8) ++ * 1 TXQ for MGMT ++ */ ++void rwnx_txq_sta_init(struct rwnx_hw *rwnx_hw, struct rwnx_sta *rwnx_sta, ++ u8 status) ++{ ++ struct rwnx_txq *txq; ++ int tid, idx; ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ struct rwnx_vif *rwnx_vif = rwnx_hw->vif_table[rwnx_sta->vif_idx]; ++ idx = rwnx_txq_sta_idx(rwnx_sta, 0); ++ ++ foreach_sta_txq(rwnx_sta, txq, tid, rwnx_hw) ++ { ++ rwnx_txq_init(txq, idx, status, ++ &rwnx_hw->hwq[rwnx_tid2hwq[tid]], tid, rwnx_sta, ++ rwnx_vif->ndev); ++ txq->ps_id = rwnx_sta->uapsd_tids & (1 << tid) ? UAPSD_ID : ++ LEGACY_PS_ID; ++ idx++; ++ } ++ ++#endif /* CONFIG_RWNX_FULLMAC*/ ++} ++ ++/** ++ * rwnx_txq_sta_deinit - Deinitialize TX queues for a STA ++ * ++ * @rwnx_hw: Main driver data ++ * @rwnx_sta: STA for which tx queues need to be deinitialized ++ */ ++void rwnx_txq_sta_deinit(struct rwnx_hw *rwnx_hw, struct rwnx_sta *rwnx_sta) ++{ ++ struct rwnx_txq *txq; ++ int tid; ++ ++ foreach_sta_txq(rwnx_sta, txq, tid, rwnx_hw) ++ { ++ rwnx_txq_deinit(rwnx_hw, txq); ++ } ++} ++ ++#ifdef CONFIG_RWNX_FULLMAC ++/** ++ * rwnx_txq_unk_vif_init - Initialize TXQ for unknown STA linked to a vif ++ * ++ * @rwnx_vif: Pointer on VIF ++ */ ++void rwnx_txq_unk_vif_init(struct rwnx_vif *rwnx_vif) ++{ ++ struct rwnx_hw *rwnx_hw = rwnx_vif->rwnx_hw; ++ struct rwnx_txq *txq; ++ int idx; ++ ++ txq = rwnx_txq_vif_get(rwnx_vif, NX_UNK_TXQ_TYPE); ++ idx = rwnx_txq_vif_idx(rwnx_vif, NX_UNK_TXQ_TYPE); ++ rwnx_txq_init(txq, idx, 0, &rwnx_hw->hwq[RWNX_HWQ_VO], TID_MGT, NULL, ++ rwnx_vif->ndev); ++} ++ ++/** ++ * rwnx_txq_tdls_vif_deinit - Deinitialize TXQ for unknown STA linked to a vif ++ * ++ * @rwnx_vif: Pointer on VIF ++ */ ++void rwnx_txq_unk_vif_deinit(struct rwnx_vif *rwnx_vif) ++{ ++ struct rwnx_txq *txq; ++ ++ txq = rwnx_txq_vif_get(rwnx_vif, NX_UNK_TXQ_TYPE); ++ rwnx_txq_deinit(rwnx_vif->rwnx_hw, txq); ++} ++ ++/** ++ * rwnx_init_unk_txq - Initialize TX queue for the transmission on a offchannel ++ * ++ * @vif: Interface for which the queue has to be initialized ++ * ++ * NOTE: Offchannel txq is only active for the duration of the ROC ++ */ ++void rwnx_txq_offchan_init(struct rwnx_vif *rwnx_vif) ++{ ++ struct rwnx_hw *rwnx_hw = rwnx_vif->rwnx_hw; ++ struct rwnx_txq *txq; ++ int nx_off_chan_txq_idx = NX_OFF_CHAN_TXQ_IDX; ++ ++ if ((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8801) || ++ ((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DW) && ++ chip_id < 3)) { ++ nx_off_chan_txq_idx = NX_OFF_CHAN_TXQ_IDX_FOR_OLD_IC; ++ } ++ ++ txq = &rwnx_hw->txq[nx_off_chan_txq_idx]; ++ rwnx_txq_init(txq, nx_off_chan_txq_idx, RWNX_TXQ_STOP_CHAN, ++ &rwnx_hw->hwq[RWNX_HWQ_VO], TID_MGT, NULL, ++ rwnx_vif->ndev); ++} ++ ++/** ++ * rwnx_deinit_offchan_txq - Deinitialize TX queue for offchannel ++ * ++ * @vif: Interface that manages the STA ++ * ++ * This function deintialize txq for one STA. ++ * Any buffer stuck in a queue will be freed. ++ */ ++void rwnx_txq_offchan_deinit(struct rwnx_vif *rwnx_vif) ++{ ++ struct rwnx_txq *txq; ++ ++ int nx_off_chan_txq_idx = NX_OFF_CHAN_TXQ_IDX; ++ ++ if ((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8801) || ++ ((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DW) && ++ chip_id < 3)) { ++ nx_off_chan_txq_idx = NX_OFF_CHAN_TXQ_IDX_FOR_OLD_IC; ++ } ++ ++ txq = &rwnx_vif->rwnx_hw->txq[nx_off_chan_txq_idx]; ++ rwnx_txq_deinit(rwnx_vif->rwnx_hw, txq); ++} ++ ++/** ++ * rwnx_txq_tdls_vif_init - Initialize TXQ vif for TDLS ++ * ++ * @rwnx_vif: Pointer on VIF ++ */ ++void rwnx_txq_tdls_vif_init(struct rwnx_vif *rwnx_vif) ++{ ++ struct rwnx_hw *rwnx_hw = rwnx_vif->rwnx_hw; ++ ++ if (!(rwnx_hw->wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) ++ return; ++ ++ rwnx_txq_unk_vif_init(rwnx_vif); ++} ++ ++/** ++ * rwnx_txq_tdls_vif_deinit - Deinitialize TXQ vif for TDLS ++ * ++ * @rwnx_vif: Pointer on VIF ++ */ ++void rwnx_txq_tdls_vif_deinit(struct rwnx_vif *rwnx_vif) ++{ ++ struct rwnx_hw *rwnx_hw = rwnx_vif->rwnx_hw; ++ ++ if (!(rwnx_hw->wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) ++ return; ++ ++ rwnx_txq_unk_vif_deinit(rwnx_vif); ++} ++#endif ++ ++/****************************************************************************** ++ * Start/Stop functions ++ *****************************************************************************/ ++/** ++ * rwnx_txq_add_to_hw_list - Add TX queue to a HW queue schedule list. ++ * ++ * @txq: TX queue to add ++ * ++ * Add the TX queue if not already present in the HW queue list. ++ * To be called with tx_lock hold ++ */ ++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; ++ } ++} ++ ++/** ++ * rwnx_txq_del_from_hw_list - Delete TX queue from a HW queue schedule list. ++ * ++ * @txq: TX queue to delete ++ * ++ * Remove the TX queue from the HW queue list if present. ++ * To be called with tx_lock hold ++ */ ++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); ++ } ++} ++ ++/** ++ * rwnx_txq_skb_ready - Check if skb are available for the txq ++ * ++ * @txq: Pointer on txq ++ * @return True if there are buffer ready to be pushed on this txq, ++ * false otherwise ++ */ ++static inline bool rwnx_txq_skb_ready(struct rwnx_txq *txq) ++{ ++#ifdef CONFIG_MAC80211_TXQ ++ if (txq->nb_ready_mac80211 != NOT_MAC80211_TXQ) ++ return ((txq->nb_ready_mac80211 > 0) || ++ !skb_queue_empty(&txq->sk_list)); ++ else ++#endif ++ return !skb_queue_empty(&txq->sk_list); ++} ++ ++/** ++ * rwnx_txq_start - Try to Start one TX queue ++ * ++ * @txq: TX queue to start ++ * @reason: reason why the TX queue is started (among RWNX_TXQ_STOP_xxx) ++ * ++ * Re-start the TX queue for one reason. ++ * If after this the txq is no longer stopped and some buffers are ready, ++ * the TX queue is also added to HW queue list. ++ * To be called with tx_lock hold ++ */ ++void rwnx_txq_start(struct rwnx_txq *txq, u16 reason) ++{ ++ 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); ++ } ++} ++ ++/** ++ * rwnx_txq_stop - Stop one TX queue ++ * ++ * @txq: TX queue to stop ++ * @reason: reason why the TX queue is stopped (among RWNX_TXQ_STOP_xxx) ++ * ++ * Stop the TX queue. It will remove the TX queue from HW queue list ++ * To be called with tx_lock hold ++ */ ++void rwnx_txq_stop(struct rwnx_txq *txq, u16 reason) ++{ ++ 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); ++ } ++} ++ ++/** ++ * rwnx_txq_sta_start - Start all the TX queue linked to a STA ++ * ++ * @sta: STA whose TX queues must be re-started ++ * @reason: Reason why the TX queue are restarted (among RWNX_TXQ_STOP_xxx) ++ * @rwnx_hw: Driver main data ++ * ++ * This function will re-start all the TX queues of the STA for the reason ++ * specified. It can be : ++ * - RWNX_TXQ_STOP_STA_PS: the STA is no longer in power save mode ++ * - RWNX_TXQ_STOP_VIF_PS: the VIF is in power save mode (p2p absence) ++ * - RWNX_TXQ_STOP_CHAN: the STA's VIF is now on the current active channel ++ * ++ * Any TX queue with buffer ready and not Stopped for other reasons, will be ++ * added to the HW queue list ++ * To be called with tx_lock hold ++ */ ++void rwnx_txq_sta_start(struct rwnx_sta *rwnx_sta, u16 reason ++#ifdef CONFIG_RWNX_FULLMAC ++ , ++ struct rwnx_hw *rwnx_hw ++#endif ++) ++{ ++ 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); ++ } ++} ++ ++/** ++ * rwnx_stop_sta_txq - Stop all the TX queue linked to a STA ++ * ++ * @sta: STA whose TX queues must be stopped ++ * @reason: Reason why the TX queue are stopped (among RWNX_TX_STOP_xxx) ++ * @rwnx_hw: Driver main data ++ * ++ * This function will stop all the TX queues of the STA for the reason ++ * specified. It can be : ++ * - RWNX_TXQ_STOP_STA_PS: the STA is in power save mode ++ * - RWNX_TXQ_STOP_VIF_PS: the VIF is in power save mode (p2p absence) ++ * - RWNX_TXQ_STOP_CHAN: the STA's VIF is not on the current active channel ++ * ++ * Any TX queue present in a HW queue list will be removed from this list. ++ * To be called with tx_lock hold ++ */ ++void rwnx_txq_sta_stop(struct rwnx_sta *rwnx_sta, u16 reason ++#ifdef CONFIG_RWNX_FULLMAC ++ , ++ struct rwnx_hw *rwnx_hw ++#endif ++) ++{ ++ struct rwnx_txq *txq; ++ int tid; ++ ++ 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); ++ } ++} ++ ++#ifdef CONFIG_RWNX_FULLMAC ++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) ++ rwnx_txq_sta_start(rwnx_vif->sta.tdls_sta, reason, rwnx_hw); ++ ++ spin_unlock_bh(&rwnx_hw->tx_lock); ++} ++#endif ++ ++#ifdef CONFIG_RWNX_FULLMAC ++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); ++ ++ if (rwnx_vif->sta.tdls_sta) ++ rwnx_txq_sta_stop(rwnx_vif->sta.tdls_sta, reason, rwnx_hw); ++ ++ spin_unlock_bh(&rwnx_hw->tx_lock); ++} ++#endif ++ ++#ifdef CONFIG_RWNX_FULLMAC ++static inline void ++rwnx_txq_vif_for_each_sta(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif, ++ void (*f)(struct rwnx_sta *, u16, struct rwnx_hw *), ++ u16 reason) ++{ ++ switch (RWNX_VIF_TYPE(rwnx_vif)) { ++ case NL80211_IFTYPE_STATION: ++ case NL80211_IFTYPE_P2P_CLIENT: { ++ if (rwnx_vif->tdls_status == TDLS_LINK_ACTIVE) ++ f(rwnx_vif->sta.tdls_sta, reason, rwnx_hw); ++ if (!WARN_ON(rwnx_vif->sta.ap == NULL)) ++ f(rwnx_vif->sta.ap, reason, rwnx_hw); ++ break; ++ } ++ case NL80211_IFTYPE_AP_VLAN: ++ rwnx_vif = rwnx_vif->ap_vlan.master; ++ case NL80211_IFTYPE_AP: ++ case NL80211_IFTYPE_MESH_POINT: ++ case NL80211_IFTYPE_P2P_GO: { ++ struct rwnx_sta *sta; ++ list_for_each_entry (sta, &rwnx_vif->ap.sta_list, list) { ++ f(sta, reason, rwnx_hw); ++ } ++ break; ++ } ++ default: ++ BUG(); ++ break; ++ } ++} ++#endif ++ ++/** ++ * rwnx_txq_vif_start - START TX queues of all STA associated to the vif ++ * and vif's TXQ ++ * ++ * @vif: Interface to start ++ * @reason: Start reason (RWNX_TXQ_STOP_CHAN or RWNX_TXQ_STOP_VIF_PS) ++ * @rwnx_hw: Driver main data ++ * ++ * Iterate over all the STA associated to the vif and re-start them for the ++ * reason @reason ++ * Take tx_lock ++ */ ++void rwnx_txq_vif_start(struct rwnx_vif *rwnx_vif, u16 reason, ++ 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 ++ //Reject if monitor interface ++ if (rwnx_vif->wdev.iftype == NL80211_IFTYPE_MONITOR) ++ goto end; ++ ++ if (rwnx_vif->roc_tdls && rwnx_vif->sta.tdls_sta && ++ rwnx_vif->sta.tdls_sta->tdls.chsw_en) { ++ rwnx_txq_sta_start(rwnx_vif->sta.tdls_sta, reason, rwnx_hw); ++ } ++ if (!rwnx_vif->roc_tdls) { ++ rwnx_txq_vif_for_each_sta(rwnx_hw, rwnx_vif, rwnx_txq_sta_start, ++ reason); ++ } ++ ++ txq = rwnx_txq_vif_get(rwnx_vif, NX_BCMC_TXQ_TYPE); ++ rwnx_txq_start(txq, reason); ++ txq = rwnx_txq_vif_get(rwnx_vif, NX_UNK_TXQ_TYPE); ++ rwnx_txq_start(txq, reason); ++ ++end: ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++ spin_unlock_bh(&rwnx_hw->tx_lock); ++} ++ ++/** ++ * rwnx_txq_vif_stop - STOP TX queues of all STA associated to the vif ++ * ++ * @vif: Interface to stop ++ * @arg: Stop reason (RWNX_TXQ_STOP_CHAN or RWNX_TXQ_STOP_VIF_PS) ++ * @rwnx_hw: Driver main data ++ * ++ * Iterate over all the STA associated to the vif and stop them for the ++ * reason RWNX_TXQ_STOP_CHAN or RWNX_TXQ_STOP_VIF_PS ++ * Take tx_lock ++ */ ++void rwnx_txq_vif_stop(struct rwnx_vif *rwnx_vif, u16 reason, ++ struct rwnx_hw *rwnx_hw) ++{ ++ struct rwnx_txq *txq; ++#ifdef CREATE_TRACE_POINTS ++ trace_txq_vif_stop(rwnx_vif->vif_index); ++#endif ++ spin_lock_bh(&rwnx_hw->tx_lock); ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ //Reject if monitor interface ++ if (rwnx_vif->wdev.iftype == NL80211_IFTYPE_MONITOR) ++ goto end; ++ ++ rwnx_txq_vif_for_each_sta(rwnx_hw, rwnx_vif, rwnx_txq_sta_stop, reason); ++ ++ txq = rwnx_txq_vif_get(rwnx_vif, NX_BCMC_TXQ_TYPE); ++ rwnx_txq_stop(txq, reason); ++ txq = rwnx_txq_vif_get(rwnx_vif, NX_UNK_TXQ_TYPE); ++ rwnx_txq_stop(txq, reason); ++ ++end: ++#endif /* CONFIG_RWNX_FULLMAC*/ ++ ++ spin_unlock_bh(&rwnx_hw->tx_lock); ++} ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ ++/** ++ * rwnx_start_offchan_txq - START TX queue for offchannel frame ++ * ++ * @rwnx_hw: Driver main data ++ */ ++void rwnx_txq_offchan_start(struct rwnx_hw *rwnx_hw) ++{ ++ struct rwnx_txq *txq; ++ int nx_off_chan_txq_idx = NX_OFF_CHAN_TXQ_IDX; ++ ++ if ((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8801) || ++ ((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DC || ++ g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DW) && ++ chip_id < 3)) { ++ nx_off_chan_txq_idx = NX_OFF_CHAN_TXQ_IDX_FOR_OLD_IC; ++ } ++ ++ txq = &rwnx_hw->txq[nx_off_chan_txq_idx]; ++ spin_lock_bh(&rwnx_hw->tx_lock); ++ rwnx_txq_start(txq, RWNX_TXQ_STOP_CHAN); ++ spin_unlock_bh(&rwnx_hw->tx_lock); ++} ++ ++/** ++ * rwnx_switch_vif_sta_txq - Associate TXQ linked to a STA to a new vif ++ * ++ * @sta: STA whose txq must be switched ++ * @old_vif: Vif currently associated to the STA (may no longer be active) ++ * @new_vif: vif which should be associated to the STA for now on ++ * ++ * This function will switch the vif (i.e. the netdev) associated to all STA's ++ * TXQ. This is used when AP_VLAN interface are created. ++ * If one STA is associated to an AP_vlan vif, it will be moved from the master ++ * AP vif to the AP_vlan vif. ++ * If an AP_vlan vif is removed, then STA will be moved back to mastert AP vif. ++ * ++ */ ++void rwnx_txq_sta_switch_vif(struct rwnx_sta *sta, struct rwnx_vif *old_vif, ++ struct rwnx_vif *new_vif) ++{ ++ struct rwnx_hw *rwnx_hw = new_vif->rwnx_hw; ++ struct rwnx_txq *txq; ++ int i; ++ ++ /* start TXQ on the new interface, and update ndev field in txq */ ++ if (!netif_carrier_ok(new_vif->ndev)) ++ netif_carrier_on(new_vif->ndev); ++ txq = rwnx_txq_sta_get(sta, 0, rwnx_hw); ++ for (i = 0; i < NX_NB_TID_PER_STA; i++, txq++) { ++ txq->ndev = new_vif->ndev; ++ netif_wake_subqueue(txq->ndev, txq->ndev_idx); ++ } ++} ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++/****************************************************************************** ++ * TXQ queue/schedule functions ++ *****************************************************************************/ ++/** ++ * rwnx_txq_queue_skb - Queue a buffer in a TX queue ++ * ++ * @skb: Buffer to queue ++ * @txq: TX Queue in which the buffer must be added ++ * @rwnx_hw: Driver main data ++ * @retry: Should it be queued in the retry list ++ * ++ * @return: Retrun 1 if txq has been added to hwq list, 0 otherwise ++ * ++ * Add a buffer in the buffer list of the TX queue ++ * and add this TX queue in the HW queue list if the txq is not stopped. ++ * If this is a retry packet it is added after the last retry packet or at the ++ * beginning if there is no retry packet queued. ++ * ++ * If the STA is in PS mode and this is the first packet queued for this txq ++ * update TIM. ++ * ++ * To be called with tx_lock hold ++ */ ++int rwnx_txq_queue_skb(struct sk_buff *skb, struct rwnx_txq *txq, ++ struct rwnx_hw *rwnx_hw, bool retry) ++{ ++#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); ++ } ++ } ++#endif ++ ++ if (!retry) { ++ /* add buffer in the sk_list */ ++ skb_queue_tail(&txq->sk_list, skb); ++ } else { ++ if (txq->last_retry_skb) ++#ifdef CONFIG_GKI ++ rwnx_skb_append(txq->last_retry_skb, skb, ++ &txq->sk_list); ++#else ++ skb_append(txq->last_retry_skb, skb, &txq->sk_list); ++#endif ++ else ++ skb_queue_head(&txq->sk_list, skb); ++ ++ 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 ++#ifndef CONFIG_ONE_TXQ ++ ++#ifdef CONFIG_TX_NETIF_FLOWCTRL ++ if ((txq->ndev_idx != NDEV_NO_TXQ) && ++ ((skb_queue_len(&txq->sk_list) > RWNX_NDEV_FLOW_CTRL_STOP) && ++ !rwnx_hw->sdiodev->flowctrl)) { ++// (atomic_read(&rwnx_hw->sdiodev->tx_priv->tx_pktcnt) >= tx_fc_high_water))) { ++#else ++ /* If too many buffer are queued for this TXQ stop netdev queue */ ++ if ((txq->ndev_idx != NDEV_NO_TXQ) && ++ (skb_queue_len(&txq->sk_list) > RWNX_NDEV_FLOW_CTRL_STOP)) { ++#endif ++ ++ txq->status |= RWNX_TXQ_NDEV_FLOW_CTRL; ++ netif_stop_subqueue(txq->ndev, txq->ndev_idx); ++#ifdef CREATE_TRACE_POINT ++ trace_txq_flowctrl_stop(txq); ++#endif ++ } ++#endif /* CONFIG_ONE_TXQ */ ++#else /* ! CONFIG_RWNX_FULLMAC */ ++ ++ if (!retry && ++txq->hwq->len == txq->hwq->len_stop) { ++ trace_hwq_flowctrl_stop(txq->hwq->id); ++ ieee80211_stop_queue(rwnx_hw->hw, txq->hwq->id); ++ rwnx_hw->stats.queues_stops++; ++ } ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++ /* add it in the hwq list if not stopped and not yet present */ ++ if (!rwnx_txq_is_stopped(txq)) { ++ rwnx_txq_add_to_hw_list(txq); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/** ++ * rwnx_txq_confirm_any - Process buffer confirmed by fw ++ * ++ * @rwnx_hw: Driver main data ++ * @txq: TX Queue ++ * @hwq: HW Queue ++ * @sw_txhdr: software descriptor of the confirmed packet ++ * ++ * Process a buffer returned by the fw. It doesn't check buffer status ++ * and only does systematic counter update: ++ * - hw credit ++ * - buffer pushed to fw ++ * ++ * To be called with tx_lock hold ++ */ ++void rwnx_txq_confirm_any(struct rwnx_hw *rwnx_hw, struct rwnx_txq *txq, ++ struct rwnx_hwq *hwq, struct rwnx_sw_txhdr *sw_txhdr) ++{ ++ int user = 0; ++ ++#ifdef CONFIG_RWNX_MUMIMO_TX ++ int group_id; ++ ++ user = RWNX_MUMIMO_INFO_POS_ID(sw_txhdr->desc.host.mumimo_info); ++ group_id = RWNX_MUMIMO_INFO_GROUP_ID(sw_txhdr->desc.host.mumimo_info); ++ ++ if ((txq->idx != TXQ_INACTIVE) && (txq->pkt_pushed[user] == 1) && ++ (txq->status & RWNX_TXQ_STOP_MU_POS)) ++ rwnx_txq_start(txq, RWNX_TXQ_STOP_MU_POS); ++ ++#endif /* CONFIG_RWNX_MUMIMO_TX */ ++ ++ if (txq->pkt_pushed[user]) ++ txq->pkt_pushed[user]--; ++ ++ hwq->need_processing = true; ++ rwnx_hw->stats.cfm_balance[hwq->id]--; ++} ++ ++/****************************************************************************** ++ * HWQ processing ++ *****************************************************************************/ ++static inline bool rwnx_txq_take_mu_lock(struct rwnx_hw *rwnx_hw) ++{ ++ bool res = false; ++#ifdef CONFIG_RWNX_MUMIMO_TX ++ if (rwnx_hw->mod_params->mutx) ++ res = (down_trylock(&rwnx_hw->mu.lock) == 0); ++#endif /* CONFIG_RWNX_MUMIMO_TX */ ++ return res; ++} ++ ++static inline void rwnx_txq_release_mu_lock(struct rwnx_hw *rwnx_hw) ++{ ++#ifdef CONFIG_RWNX_MUMIMO_TX ++ up(&rwnx_hw->mu.lock); ++#endif /* CONFIG_RWNX_MUMIMO_TX */ ++} ++ ++static inline void rwnx_txq_set_mu_info(struct rwnx_hw *rwnx_hw, ++ struct rwnx_txq *txq, int group_id, ++ int pos) ++{ ++#ifdef CONFIG_RWNX_MUMIMO_TX ++ trace_txq_select_mu_group(txq, group_id, pos); ++ if (group_id) { ++ txq->mumimo_info = group_id | (pos << 6); ++ rwnx_mu_set_active_group(rwnx_hw, group_id); ++ } else ++ txq->mumimo_info = 0; ++#endif /* CONFIG_RWNX_MUMIMO_TX */ ++} ++ ++static inline s8 rwnx_txq_get_credits(struct rwnx_txq *txq) ++{ ++ s8 cred = txq->credits; ++ /* if destination is in PS mode, push_limit indicates the maximum ++ number of packet that can be pushed on this txq. */ ++ if (txq->push_limit && (cred > txq->push_limit)) { ++ cred = txq->push_limit; ++ } ++ return cred; ++} ++ ++/** ++ * skb_queue_extract - Extract buffer from skb list ++ * ++ * @list: List of skb to extract from ++ * @head: List of skb to append to ++ * @nb_elt: Number of skb to extract ++ * ++ * extract the first @nb_elt of @list and append them to @head ++ * It is assume that: ++ * - @list contains more that @nb_elt ++ * - There is no need to take @list nor @head lock to modify them ++ */ ++static inline void skb_queue_extract(struct sk_buff_head *list, ++ struct sk_buff_head *head, int nb_elt) ++{ ++ int i; ++ struct sk_buff *first, *last, *ptr; ++ ++ first = ptr = list->next; ++ for (i = 0; i < nb_elt; i++) { ++ ptr = ptr->next; ++ } ++ last = ptr->prev; ++ ++ /* unlink nb_elt in list */ ++ list->qlen -= nb_elt; ++ list->next = ptr; ++ ptr->prev = (struct sk_buff *)list; ++ ++ /* append nb_elt at end of head */ ++ head->qlen += nb_elt; ++ last->next = (struct sk_buff *)head; ++ head->prev->next = first; ++ first->prev = head->prev; ++ head->prev = last; ++} ++ ++#ifdef CONFIG_MAC80211_TXQ ++/** ++ * rwnx_txq_mac80211_dequeue - Dequeue buffer from mac80211 txq and ++ * add them to push list ++ * ++ * @rwnx_hw: Main driver data ++ * @sk_list: List of buffer to push (initialized without lock) ++ * @txq: TXQ to dequeue buffers from ++ * @max: Max number of buffer to dequeue ++ * ++ * Dequeue buffer from mac80211 txq, prepare them for transmission and chain them ++ * to the list of buffer to push. ++ * ++ * @return true if no more buffer are queued in mac80211 txq and false otherwise. ++ */ ++static bool rwnx_txq_mac80211_dequeue(struct rwnx_hw *rwnx_hw, ++ struct sk_buff_head *sk_list, ++ struct rwnx_txq *txq, int max) ++{ ++ struct ieee80211_txq *mac_txq; ++ struct sk_buff *skb; ++ unsigned long mac_txq_len; ++ ++ if (txq->nb_ready_mac80211 == NOT_MAC80211_TXQ) ++ return true; ++ ++ mac_txq = container_of((void *)txq, struct ieee80211_txq, drv_priv); ++ ++ for (; max > 0; max--) { ++ skb = rwnx_tx_dequeue_prep(rwnx_hw, mac_txq); ++ if (skb == NULL) ++ return true; ++ ++ __skb_queue_tail(sk_list, skb); ++ } ++ ++ /* re-read mac80211 txq current length. ++ It is mainly for debug purpose to trace dropped packet. There is no ++ problems to have nb_ready_mac80211 != actual mac80211 txq length */ ++ ieee80211_txq_get_depth(mac_txq, &mac_txq_len, NULL); ++ if (txq->nb_ready_mac80211 > mac_txq_len) ++ trace_txq_drop(txq, txq->nb_ready_mac80211 - mac_txq_len); ++ txq->nb_ready_mac80211 = mac_txq_len; ++ ++ return (txq->nb_ready_mac80211 == 0); ++} ++#endif ++ ++/** ++ * rwnx_txq_get_skb_to_push - Get list of buffer to push for one txq ++ * ++ * @rwnx_hw: main driver data ++ * @hwq: HWQ on wich buffers will be pushed ++ * @txq: TXQ to get buffers from ++ * @user: user postion to use ++ * @sk_list_push: list to update ++ * ++ * ++ * This function will returned a list of buffer to push for one txq. ++ * It will take into account the number of credit of the HWQ for this user ++ * position and TXQ (and push_limit). ++ * This allow to get a list that can be pushed without having to test for ++ * hwq/txq status after each push ++ * ++ * If a MU group has been selected for this txq, it will also update the ++ * counter for the group ++ * ++ * @return true if txq no longer have buffer ready after the ones returned. ++ * false otherwise ++ */ ++static bool rwnx_txq_get_skb_to_push(struct rwnx_hw *rwnx_hw, ++ struct rwnx_hwq *hwq, struct rwnx_txq *txq, ++ int user, ++ struct sk_buff_head *sk_list_push) ++{ ++ int nb_ready = skb_queue_len(&txq->sk_list); ++ int credits = rwnx_txq_get_credits(txq); ++ bool res = false; ++ ++ __skb_queue_head_init(sk_list_push); ++ ++ if (credits >= nb_ready) { ++ skb_queue_splice_init(&txq->sk_list, sk_list_push); ++#ifdef CONFIG_MAC80211_TXQ ++ res = rwnx_txq_mac80211_dequeue(rwnx_hw, sk_list_push, txq, ++ credits - nb_ready); ++ credits = skb_queue_len(sk_list_push); ++#else ++ res = true; ++ credits = nb_ready; ++#endif ++ } else { ++ skb_queue_extract(&txq->sk_list, sk_list_push, credits); ++ ++ /* When processing PS service period (i.e. push_limit != 0), no longer ++ process this txq if the buffers extracted will complete the SP for ++ this txq */ ++ if (txq->push_limit && (credits == txq->push_limit)) ++ res = true; ++ } ++ ++ rwnx_mu_set_active_sta(rwnx_hw, rwnx_txq_2_sta(txq), credits); ++ ++ return res; ++} ++ ++/** ++ * rwnx_txq_select_user - Select User queue for a txq ++ * ++ * @rwnx_hw: main driver data ++ * @mu_lock: true is MU lock is taken ++ * @txq: TXQ to select MU group for ++ * @hwq: HWQ for the TXQ ++ * @user: Updated with user position selected ++ * ++ * @return false if it is no possible to process this txq. ++ * true otherwise ++ * ++ * This function selects the MU group to use for a TXQ. ++ * The selection is done as follow: ++ * ++ * - return immediately for STA that don't belongs to any group and select ++ * group 0 / user 0 ++ * ++ * - If MU tx is disabled (by user mutx_on, or because mu group are being ++ * updated !mu_lock), select group 0 / user 0 ++ * ++ * - Use the best group selected by @rwnx_mu_group_sta_select. ++ * ++ * Each time a group is selected (except for the first case where sta ++ * doesn't belongs to a MU group), the function checks that no buffer is ++ * pending for this txq on another user position. If this is the case stop ++ * the txq (RWNX_TXQ_STOP_MU_POS) and return false. ++ * ++ */ ++static bool rwnx_txq_select_user(struct rwnx_hw *rwnx_hw, bool mu_lock, ++ struct rwnx_txq *txq, struct rwnx_hwq *hwq, ++ int *user) ++{ ++ int pos = 0; ++#ifdef CONFIG_RWNX_MUMIMO_TX ++ int id, group_id = 0; ++ struct rwnx_sta *sta = rwnx_txq_2_sta(txq); ++ ++ /* for sta that belong to no group return immediately */ ++ if (!sta || !sta->group_info.cnt) ++ goto end; ++ ++ /* If MU is disabled, need to check user */ ++ if (!rwnx_hw->mod_params->mutx_on || !mu_lock) ++ goto check_user; ++ ++ /* Use the "best" group selected */ ++ group_id = sta->group_info.group; ++ ++ if (group_id > 0) ++ pos = rwnx_mu_group_sta_get_pos(rwnx_hw, sta, group_id); ++ ++check_user: ++ /* check that we can push on this user position */ ++#if CONFIG_USER_MAX == 2 ++ id = (pos + 1) & 0x1; ++ if (txq->pkt_pushed[id]) { ++ rwnx_txq_stop(txq, RWNX_TXQ_STOP_MU_POS); ++ return false; ++ } ++ ++#else ++ for (id = 0; id < CONFIG_USER_MAX; id++) { ++ if (id != pos && txq->pkt_pushed[id]) { ++ rwnx_txq_stop(txq, RWNX_TXQ_STOP_MU_POS); ++ return false; ++ } ++ } ++#endif ++ ++end: ++ rwnx_txq_set_mu_info(rwnx_hw, txq, group_id, pos); ++#endif /* CONFIG_RWNX_MUMIMO_TX */ ++ ++ *user = pos; ++ return true; ++} ++ ++/** ++ * rwnx_hwq_process - Process one HW queue list ++ * ++ * @rwnx_hw: Driver main data ++ * @hw_queue: HW queue index to process ++ * ++ * The function will iterate over all the TX queues linked in this HW queue ++ * list. For each TX queue, push as many buffers as possible in the HW queue. ++ * (NB: TX queue have at least 1 buffer, otherwise it wouldn't be in the list) ++ * - If TX queue no longer have buffer, remove it from the list and check next ++ * TX queue ++ * - If TX queue no longer have credits or has a push_limit (PS mode) and it ++ * is reached , remove it from the list and check next TX queue ++ * - If HW queue is full, update list head to start with the next TX queue on ++ * next call if current TX queue already pushed "too many" pkt in a row, and ++ * return ++ * ++ * To be called when HW queue list is modified: ++ * - when a buffer is pushed on a TX queue ++ * - when new credits are received ++ * - when a STA returns from Power Save mode or receives traffic request. ++ * - when Channel context change ++ * ++ * To be called with tx_lock hold ++ */ ++#define ALL_HWQ_MASK ((1 << CONFIG_USER_MAX) - 1) ++ ++void rwnx_hwq_process(struct rwnx_hw *rwnx_hw, struct rwnx_hwq *hwq) ++{ ++ 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); ++ if (!mu_enable) ++ credit_map = ALL_HWQ_MASK - 1; ++ ++ list_for_each_entry_safe (txq, next, &hwq->list, sched_list) { ++ struct rwnx_txhdr *txhdr = NULL; ++ 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__); ++ rwnx_txq_del_from_hw_list(txq); ++ rwnx_txq_flush(rwnx_hw, txq); ++ 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)) { ++ 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 (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 ++ pkt as possible" for he same txq ++ ==> Add counter to trigger txq switch ++ */ ++ if (txq->pkt_sent > hwq->size) { ++ txq->pkt_sent = 0; ++ list_rotate_left(&hwq->list); ++ } ++ } ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ /* Unable to complete PS traffic request because of hwq credit */ ++ if (txq->push_limit && txq->sta) { ++ if (txq->ps_id == LEGACY_PS_ID) { ++ /* for legacy PS abort SP and wait next ps-poll */ ++ txq->sta->ps.sp_cnt[txq->ps_id] -= ++ txq->push_limit; ++ txq->push_limit = 0; ++ } ++ /* for u-apsd need to complete the SP to send EOSP frame */ ++ } ++#ifndef CONFIG_ONE_TXQ ++ /* restart netdev queue if number of queued buffer is below threshold */ ++#ifdef CONFIG_TX_NETIF_FLOWCTRL ++ if (unlikely(txq->status & RWNX_TXQ_NDEV_FLOW_CTRL) && ++ (skb_queue_len(&txq->sk_list) < ++ RWNX_NDEV_FLOW_CTRL_RESTART)) { ++#else ++ if (unlikely(txq->status & RWNX_TXQ_NDEV_FLOW_CTRL) && ++ skb_queue_len(&txq->sk_list) < ++ RWNX_NDEV_FLOW_CTRL_RESTART) { ++#endif ++ ++ 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_ONE_TXQ */ ++#endif /* CONFIG_RWNX_FULLMAC */ ++ } ++ ++ if (mu_enable) ++ rwnx_txq_release_mu_lock(rwnx_hw); ++} ++ ++/** ++ * rwnx_hwq_process_all - Process all HW queue list ++ * ++ * @rwnx_hw: Driver main data ++ * ++ * Loop over all HWQ, and process them if needed ++ * To be called with tx_lock hold ++ */ ++void rwnx_hwq_process_all(struct rwnx_hw *rwnx_hw) ++{ ++ int id; ++ ++ rwnx_mu_group_sta_select(rwnx_hw); ++ ++ for (id = ARRAY_SIZE(rwnx_hw->hwq) - 1; id >= 0; id--) { ++ if (rwnx_hw->hwq[id].need_processing) { ++ rwnx_hwq_process(rwnx_hw, &rwnx_hw->hwq[id]); ++ } ++ } ++} ++ ++/** ++ * rwnx_hwq_init - Initialize all hwq structures ++ * ++ * @rwnx_hw: Driver main data ++ * ++ */ ++void rwnx_hwq_init(struct rwnx_hw *rwnx_hw) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(rwnx_hw->hwq); i++) { ++ struct rwnx_hwq *hwq = &rwnx_hw->hwq[i]; ++ ++ hwq->id = i; ++ hwq->size = nx_txdesc_cnt[i]; ++ INIT_LIST_HEAD(&hwq->list); ++ } ++} +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_txq.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_txq.h +new file mode 100755 +index 000000000..6f311037d +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_txq.h +@@ -0,0 +1,404 @@ ++/** ++ **************************************************************************************** ++ * ++ * @file rwnx_txq.h ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ **************************************************************************************** ++ */ ++#ifndef _RWNX_TXQ_H_ ++#define _RWNX_TXQ_H_ ++ ++#include ++#include ++#include ++ ++#include ++ ++#ifdef CONFIG_RWNX_FULLMAC ++/** ++ * Fullmac TXQ configuration: ++ * - STA: 1 TXQ per TID (limited to 8) ++ * 1 TXQ for bufferable MGT frames ++ * - VIF: 1 TXQ for Multi/Broadcast + ++ * 1 TXQ for MGT for unknown STAs or non-bufferable MGT frames ++ * - 1 TXQ for offchannel transmissions ++ * ++ * ++ * Txq mapping looks like ++ * for NX_REMOTE_STA_MAX=10 and NX_VIRT_DEV_MAX=4 ++ * ++ * | TXQ | NDEV_ID | VIF | STA | TID | HWQ | ++ * |-----+---------+-----+-------+------+-----|- ++ * | 0 | 0 | | 0 | 0 | 1 | 9 TXQ per STA ++ * | 1 | 1 | | 0 | 1 | 0 | (8 data + 1 mgmt) ++ * | 2 | 2 | | 0 | 2 | 0 | ++ * | 3 | 3 | | 0 | 3 | 1 | ++ * | 4 | 4 | | 0 | 4 | 2 | ++ * | 5 | 5 | | 0 | 5 | 2 | ++ * | 6 | 6 | | 0 | 6 | 3 | ++ * | 7 | 7 | | 0 | 7 | 3 | ++ * | 8 | N/A | | 0 | MGMT | 3 | ++ * |-----+---------+-----+-------+------+-----|- ++ * | ... | | | | | | Same for all STAs ++ * |-----+---------+-----+-------+------+-----|- ++ * | 90 | 80 | 0 | BC/MC | 0 | 1/4 | 1 TXQ for BC/MC per VIF ++ * | ... | | | | | | ++ * | 93 | 80 | 3 | BC/MC | 0 | 1/4 | ++ * |-----+---------+-----+-------+------+-----|- ++ * | 94 | N/A | 0 | N/A | MGMT | 3 | 1 TXQ for unknown STA per VIF ++ * | ... | | | | | | ++ * | 97 | N/A | 3 | N/A | MGMT | 3 | ++ * |-----+---------+-----+-------+------+-----|- ++ * | 98 | N/A | | N/A | MGMT | 3 | 1 TXQ for offchannel frame ++ */ ++#define NX_NB_TID_PER_STA 8 ++#define NX_NB_TXQ_PER_STA (NX_NB_TID_PER_STA + 1) ++#define NX_NB_TXQ_PER_VIF 2 ++#define NX_NB_TXQ \ ++ ((NX_NB_TXQ_PER_STA * NX_REMOTE_STA_MAX) + \ ++ (NX_NB_TXQ_PER_VIF * NX_VIRT_DEV_MAX) + 1) ++ ++#define NX_FIRST_VIF_TXQ_IDX (NX_REMOTE_STA_MAX * NX_NB_TXQ_PER_STA) ++#define NX_FIRST_BCMC_TXQ_IDX NX_FIRST_VIF_TXQ_IDX ++#define NX_FIRST_UNK_TXQ_IDX (NX_FIRST_BCMC_TXQ_IDX + NX_VIRT_DEV_MAX) ++ ++#define NX_OFF_CHAN_TXQ_IDX \ ++ (NX_FIRST_VIF_TXQ_IDX + (NX_VIRT_DEV_MAX * NX_NB_TXQ_PER_VIF)) ++ ++#define NX_FIRST_VIF_TXQ_IDX_FOR_OLD_IC \ ++ (NX_REMOTE_STA_MAX_FOR_OLD_IC * NX_NB_TXQ_PER_STA) ++#define NX_FIRST_BCMC_TXQ_IDX_FOR_OLD_IC NX_FIRST_VIF_TXQ_IDX_FOR_OLD_IC ++#define NX_FIRST_UNK_TXQ_IDX_FOR_OLD_IC \ ++ (NX_FIRST_BCMC_TXQ_IDX_FOR_OLD_IC + NX_VIRT_DEV_MAX) ++ ++#define NX_OFF_CHAN_TXQ_IDX_FOR_OLD_IC \ ++ (NX_FIRST_VIF_TXQ_IDX_FOR_OLD_IC + \ ++ (NX_VIRT_DEV_MAX * NX_NB_TXQ_PER_VIF)) ++ ++#define NX_BCMC_TXQ_TYPE 0 ++#define NX_UNK_TXQ_TYPE 1 ++ ++/** ++ * Each data TXQ is a netdev queue. TXQ to send MGT are not data TXQ as ++ * they did not recieved buffer from netdev interface. ++ * Need to allocate the maximum case. ++ * AP : all STAs + 1 BC/MC ++ */ ++#define NX_NB_NDEV_TXQ ((NX_NB_TID_PER_STA * NX_REMOTE_STA_MAX) + 1) ++#define NX_NB_NDEV_TXQ_FOR_OLD_IC \ ++ ((NX_NB_TID_PER_STA * NX_REMOTE_STA_MAX_FOR_OLD_IC) + 1) ++ ++#define NX_BCMC_TXQ_NDEV_IDX (NX_NB_TID_PER_STA * NX_REMOTE_STA_MAX) ++#define NX_BCMC_TXQ_NDEV_IDX_FOR_OLD_IC \ ++ (NX_NB_TID_PER_STA * NX_REMOTE_STA_MAX_FOR_OLD_IC) ++#define NX_STA_NDEV_IDX(tid, sta_idx) ((tid) + (sta_idx)*NX_NB_TID_PER_STA) ++#define NDEV_NO_TXQ 0xffff ++#if (NX_NB_NDEV_TXQ >= NDEV_NO_TXQ) ++#error("Need to increase struct rwnx_txq->ndev_idx size") ++#endif ++ ++/* stop netdev queue when number of queued buffers if greater than this */ ++#define RWNX_NDEV_FLOW_CTRL_STOP 64 ++/* restart netdev queue when number of queued buffers is lower than this */ ++#define RWNX_NDEV_FLOW_CTRL_RESTART 64 ++ ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++#define TXQ_INACTIVE 0xffff ++#if (NX_NB_TXQ >= TXQ_INACTIVE) ++#error("Need to increase struct rwnx_txq->idx size") ++#endif ++ ++#define NX_TXQ_INITIAL_CREDITS 64 ++ ++/** ++ * TXQ tid sorted by decreasing priority ++ */ ++extern const int nx_tid_prio[NX_NB_TID_PER_STA]; ++ ++/** ++ * struct rwnx_hwq - Structure used to save information relative to ++ * an AC TX queue (aka HW queue) ++ * @list: List of TXQ, that have buffers ready for this HWQ ++ * @credits: available credit for the queue (i.e. nb of buffers that ++ * can be pushed to FW ) ++ * @id Id of the HWQ among RWNX_HWQ_.... ++ * @size size of the queue ++ * @need_processing Indicate if hwq should be processed ++ * @len number of packet ready to be pushed to fw for this HW queue ++ * @len_stop threshold to stop mac80211(i.e. netdev) queues. Stop queue when ++ * driver has more than @len_stop packets ready. ++ * @len_start threshold to wake mac8011 queues. Wake queue when driver has ++ * less than @len_start packets ready. ++ */ ++struct rwnx_hwq { ++ struct list_head list; ++ u8 size; ++ u8 id; ++ bool need_processing; ++}; ++ ++/** ++ * enum rwnx_push_flags - Flags of pushed buffer ++ * ++ * @RWNX_PUSH_RETRY Pushing a buffer for retry ++ * @RWNX_PUSH_IMMEDIATE Pushing a buffer without queuing it first ++ */ ++enum rwnx_push_flags { ++ RWNX_PUSH_RETRY = BIT(0), ++ RWNX_PUSH_IMMEDIATE = BIT(1), ++}; ++ ++/** ++ * enum rwnx_txq_flags - TXQ status flag ++ * ++ * @RWNX_TXQ_IN_HWQ_LIST: The queue is scheduled for transmission ++ * @RWNX_TXQ_STOP_FULL: No more credits for the queue ++ * @RWNX_TXQ_STOP_CSA: CSA is in progress ++ * @RWNX_TXQ_STOP_STA_PS: Destiniation sta is currently in power save mode ++ * @RWNX_TXQ_STOP_VIF_PS: Vif owning this queue is currently in power save mode ++ * @RWNX_TXQ_STOP_CHAN: Channel of this queue is not the current active channel ++ * @RWNX_TXQ_STOP_MU_POS: TXQ is stopped waiting for all the buffers pushed to ++ * fw to be confirmed ++ * @RWNX_TXQ_STOP: All possible reason to have a txq stopped ++ * @RWNX_TXQ_NDEV_FLOW_CTRL: associated netdev queue is currently stopped. ++ * Note: when a TXQ is flowctrl it is NOT stopped ++ */ ++enum rwnx_txq_flags { ++ RWNX_TXQ_IN_HWQ_LIST = BIT(0), ++ RWNX_TXQ_STOP_FULL = BIT(1), ++ RWNX_TXQ_STOP_CSA = BIT(2), ++ RWNX_TXQ_STOP_STA_PS = BIT(3), ++ RWNX_TXQ_STOP_VIF_PS = BIT(4), ++ RWNX_TXQ_STOP_CHAN = BIT(5), ++ RWNX_TXQ_STOP_MU_POS = BIT(6), ++ RWNX_TXQ_STOP = ++ (RWNX_TXQ_STOP_FULL | RWNX_TXQ_STOP_CSA | RWNX_TXQ_STOP_STA_PS | ++ RWNX_TXQ_STOP_VIF_PS | RWNX_TXQ_STOP_CHAN), ++ RWNX_TXQ_NDEV_FLOW_CTRL = BIT(7), ++}; ++ ++/** ++ * struct rwnx_txq - Structure used to save information relative to ++ * a RA/TID TX queue ++ * ++ * @idx: Unique txq idx. Set to TXQ_INACTIVE if txq is not used. ++ * @status: bitfield of @rwnx_txq_flags. ++ * @credits: available credit for the queue (i.e. nb of buffers that ++ * can be pushed to FW). ++ * @pkt_sent: number of consecutive pkt sent without leaving HW queue list ++ * @pkt_pushed: number of pkt currently pending for transmission confirmation ++ * @sched_list: list node for HW queue schedule list (rwnx_hwq.list) ++ * @sk_list: list of buffers to push to fw ++ * @last_retry_skb: pointer on the last skb in @sk_list that is a retry. ++ * (retry skb are stored at the beginning of the list) ++ * NULL if no retry skb is queued in @sk_list ++ * @nb_retry: Number of retry packet queued. ++ * @hwq: Pointer on the associated HW queue. ++ * @push_limit: number of packet to push before removing the txq from hwq list. ++ * (we always have push_limit < skb_queue_len(sk_list)) ++ * @tid: TID ++ * ++ * SOFTMAC specific: ++ * @baw: Block Ack window information ++ * @amsdu_anchor: pointer to rwnx_sw_txhdr of the first subframe of the A-MSDU. ++ * NULL if no A-MSDU frame is in construction ++ * @amsdu_ht_len_cap: ++ * @amsdu_vht_len_cap: ++ * @nb_ready_mac80211: Number of buffer ready in mac80211 txq ++ * ++ * FULLMAC specific ++ * @ps_id: Index to use for Power save mode (LEGACY or UAPSD) ++ * @ndev_idx: txq idx from netdev point of view (0xFF for non netdev queue) ++ * @ndev: pointer to ndev of the corresponding vif ++ * @amsdu: pointer to rwnx_sw_txhdr of the first subframe of the A-MSDU. ++ * NULL if no A-MSDU frame is in construction ++ * @amsdu_len: Maximum size allowed for an A-MSDU. 0 means A-MSDU not allowed ++ */ ++struct rwnx_txq { ++ u16 idx; ++ u8 status; ++ s8 credits; ++ u8 pkt_sent; ++ u8 pkt_pushed[CONFIG_USER_MAX]; ++ struct list_head sched_list; ++ struct sk_buff_head sk_list; ++ struct sk_buff *last_retry_skb; ++ struct rwnx_hwq *hwq; ++ int nb_retry; ++ u8 push_limit; ++ u8 tid; ++#ifdef CONFIG_MAC80211_TXQ ++ unsigned long nb_ready_mac80211; ++#endif ++#ifdef CONFIG_RWNX_FULLMAC ++ struct rwnx_sta *sta; ++ u8 ps_id; ++ u16 ndev_idx; ++ struct net_device *ndev; ++#ifdef CONFIG_RWNX_AMSDUS_TX ++ struct rwnx_sw_txhdr *amsdu; ++ u16 amsdu_len; ++#endif /* CONFIG_RWNX_AMSDUS_TX */ ++#endif /* CONFIG_RWNX_FULLMAC */ ++#ifdef CONFIG_RWNX_MUMIMO_TX ++ u8 mumimo_info; ++#endif ++}; ++ ++struct rwnx_sta; ++struct rwnx_vif; ++struct rwnx_hw; ++struct rwnx_sw_txhdr; ++ ++#ifdef CONFIG_RWNX_MUMIMO_TX ++#define RWNX_TXQ_GROUP_ID(txq) ((txq)->mumimo_info & 0x3f) ++#define RWNX_TXQ_POS_ID(txq) (((txq)->mumimo_info >> 6) & 0x3) ++#else ++#define RWNX_TXQ_GROUP_ID(txq) 0 ++#define RWNX_TXQ_POS_ID(txq) 0 ++#endif /* CONFIG_RWNX_MUMIMO_TX */ ++ ++static inline bool rwnx_txq_is_stopped(struct rwnx_txq *txq) ++{ ++ return (txq->status & RWNX_TXQ_STOP); ++} ++ ++static inline bool rwnx_txq_is_full(struct rwnx_txq *txq) ++{ ++ return (txq->status & RWNX_TXQ_STOP_FULL); ++} ++ ++static inline bool rwnx_txq_is_scheduled(struct rwnx_txq *txq) ++{ ++ return (txq->status & RWNX_TXQ_IN_HWQ_LIST); ++} ++ ++/** ++ * foreach_sta_txq - Macro to iterate over all TXQ of a STA in increasing ++ * TID order ++ * ++ * @sta: pointer to rwnx_sta ++ * @txq: pointer to rwnx_txq updated with the next TXQ at each iteration ++ * @tid: int updated with the TXQ tid at each iteration ++ * @rwnx_hw: main driver data ++ */ ++#ifdef CONFIG_MAC80211_TXQ ++#define foreach_sta_txq(sta, txq, tid, rwnx_hw) \ ++ for (tid = 0, txq = rwnx_txq_sta_get(sta, 0); tid < NX_NB_TXQ_PER_STA; \ ++ tid++, txq = rwnx_txq_sta_get(sta, tid)) ++ ++#elif defined(CONFIG_RWNX_FULLMAC) /* CONFIG_RWNX_FULLMAC */ ++#define foreach_sta_txq(sta, txq, tid, rwnx_hw) \ ++ for (tid = 0, txq = rwnx_txq_sta_get(sta, 0, rwnx_hw); \ ++ tid < (is_multicast_sta(sta->sta_idx) ? 1 : NX_NB_TXQ_PER_STA); \ ++ tid++, txq++) ++ ++#endif ++ ++/** ++ * foreach_sta_txq_prio - Macro to iterate over all TXQ of a STA in ++ * decreasing priority order ++ * ++ * @sta: pointer to rwnx_sta ++ * @txq: pointer to rwnx_txq updated with the next TXQ at each iteration ++ * @tid: int updated with the TXQ tid at each iteration ++ * @i: int updated with ieration count ++ * @rwnx_hw: main driver data ++ * ++ * Note: For fullmac txq for mgmt frame is skipped ++ */ ++#ifdef CONFIG_RWNX_FULLMAC ++#define foreach_sta_txq_prio(sta, txq, tid, i, rwnx_hw) \ ++ for (i = 0, tid = nx_tid_prio[0], \ ++ txq = rwnx_txq_sta_get(sta, tid, rwnx_hw); \ ++ i < NX_NB_TID_PER_STA; i++, tid = nx_tid_prio[i], \ ++ txq = rwnx_txq_sta_get(sta, tid, rwnx_hw)) ++#endif ++ ++/** ++ * foreach_vif_txq - Macro to iterate over all TXQ of a VIF (in AC order) ++ * ++ * @vif: pointer to rwnx_vif ++ * @txq: pointer to rwnx_txq updated with the next TXQ at each iteration ++ * @ac: int updated with the TXQ ac at each iteration ++ */ ++#ifdef CONFIG_MAC80211_TXQ ++#define foreach_vif_txq(vif, txq, ac) \ ++ for (ac = RWNX_HWQ_BK, txq = rwnx_txq_vif_get(vif, ac); \ ++ ac < NX_NB_TXQ_PER_VIF; ac++, txq = rwnx_txq_vif_get(vif, ac)) ++ ++#else ++#define foreach_vif_txq(vif, txq, ac) \ ++ for (ac = RWNX_HWQ_BK, txq = &vif->txqs[0]; ac < NX_NB_TXQ_PER_VIF; \ ++ ac++, txq++) ++#endif ++ ++#ifdef CONFIG_RWNX_FULLMAC ++struct rwnx_txq *rwnx_txq_sta_get(struct rwnx_sta *sta, u8 tid, ++ struct rwnx_hw *rwnx_hw); ++struct rwnx_txq *rwnx_txq_vif_get(struct rwnx_vif *vif, u8 type); ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++/** ++ * rwnx_txq_vif_get_status - return status bits related to the vif ++ * ++ * @rwnx_vif: Pointer to vif structure ++ */ ++static inline u8 rwnx_txq_vif_get_status(struct rwnx_vif *rwnx_vif) ++{ ++ struct rwnx_txq *txq = rwnx_txq_vif_get(rwnx_vif, 0); ++ return (txq->status & (RWNX_TXQ_STOP_CHAN | RWNX_TXQ_STOP_VIF_PS)); ++} ++ ++void rwnx_txq_vif_init(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif, ++ u8 status); ++void rwnx_txq_vif_deinit(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif); ++void rwnx_txq_sta_init(struct rwnx_hw *rwnx_hw, struct rwnx_sta *rwnx_sta, ++ u8 status); ++void rwnx_txq_sta_deinit(struct rwnx_hw *rwnx_hw, struct rwnx_sta *rwnx_sta); ++#ifdef CONFIG_RWNX_FULLMAC ++void rwnx_txq_unk_vif_init(struct rwnx_vif *rwnx_vif); ++void rwnx_txq_unk_vif_deinit(struct rwnx_vif *vif); ++void rwnx_txq_offchan_init(struct rwnx_vif *rwnx_vif); ++void rwnx_txq_offchan_deinit(struct rwnx_vif *rwnx_vif); ++void rwnx_txq_tdls_vif_init(struct rwnx_vif *rwnx_vif); ++void rwnx_txq_tdls_vif_deinit(struct rwnx_vif *vif); ++void rwnx_txq_tdls_sta_start(struct rwnx_vif *rwnx_vif, u16 reason, ++ struct rwnx_hw *rwnx_hw); ++void rwnx_txq_tdls_sta_stop(struct rwnx_vif *rwnx_vif, u16 reason, ++ struct rwnx_hw *rwnx_hw); ++#endif ++ ++void rwnx_txq_add_to_hw_list(struct rwnx_txq *txq); ++void rwnx_txq_del_from_hw_list(struct rwnx_txq *txq); ++void rwnx_txq_stop(struct rwnx_txq *txq, u16 reason); ++void rwnx_txq_start(struct rwnx_txq *txq, u16 reason); ++void rwnx_txq_vif_start(struct rwnx_vif *vif, u16 reason, ++ struct rwnx_hw *rwnx_hw); ++void rwnx_txq_vif_stop(struct rwnx_vif *vif, u16 reason, ++ struct rwnx_hw *rwnx_hw); ++ ++#ifdef CONFIG_RWNX_FULLMAC ++void rwnx_txq_sta_start(struct rwnx_sta *sta, u16 reason, ++ struct rwnx_hw *rwnx_hw); ++void rwnx_txq_sta_stop(struct rwnx_sta *sta, u16 reason, ++ struct rwnx_hw *rwnx_hw); ++void rwnx_txq_offchan_start(struct rwnx_hw *rwnx_hw); ++void rwnx_txq_sta_switch_vif(struct rwnx_sta *sta, struct rwnx_vif *old_vif, ++ struct rwnx_vif *new_vif); ++ ++#endif /* CONFIG_RWNX_FULLMAC */ ++ ++int rwnx_txq_queue_skb(struct sk_buff *skb, struct rwnx_txq *txq, ++ struct rwnx_hw *rwnx_hw, bool retry); ++void rwnx_txq_confirm_any(struct rwnx_hw *rwnx_hw, struct rwnx_txq *txq, ++ struct rwnx_hwq *hwq, struct rwnx_sw_txhdr *sw_txhdr); ++ ++void rwnx_hwq_init(struct rwnx_hw *rwnx_hw); ++void rwnx_hwq_process(struct rwnx_hw *rwnx_hw, struct rwnx_hwq *hwq); ++void rwnx_hwq_process_all(struct rwnx_hw *rwnx_hw); ++ ++#endif /* _RWNX_TXQ_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_utils.c b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_utils.c +new file mode 100755 +index 000000000..bf33cf980 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_utils.c +@@ -0,0 +1,37 @@ ++/** ++ * rwnx_utils.c ++ * ++ * IPC utility function definitions ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ */ ++#include "rwnx_utils.h" ++#include "rwnx_defs.h" ++#include "rwnx_rx.h" ++#include "rwnx_tx.h" ++#include "rwnx_msg_rx.h" ++#include "rwnx_debugfs.h" ++#include "rwnx_prof.h" ++#include "ipc_host.h" ++ ++extern int get_testmode(void); ++extern void get_fw_path(char *fw_path); ++extern int testmode; ++extern char aic_fw_path[200]; ++ ++int rwnx_init_aic(struct rwnx_hw *rwnx_hw) ++{ ++ RWNX_DBG(RWNX_FN_ENTRY_STR); ++#ifdef AICWF_SDIO_SUPPORT ++ aicwf_sdio_host_init(&(rwnx_hw->sdio_env), NULL, NULL, rwnx_hw); ++#else ++ aicwf_usb_host_init(&(rwnx_hw->usb_env), NULL, NULL, rwnx_hw); ++#endif ++ rwnx_cmd_mgr_init(rwnx_hw->cmd_mgr); ++ ++ testmode = get_testmode(); ++ memset(aic_fw_path, 0, 200); ++ get_fw_path(aic_fw_path); ++ ++ return 0; ++} +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_utils.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_utils.h +new file mode 100755 +index 000000000..a157ec57e +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_utils.h +@@ -0,0 +1,134 @@ ++/** ++ * rwnx_ipc_utils.h ++ * ++ * IPC utility function declarations ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ */ ++#ifndef _RWNX_IPC_UTILS_H_ ++#define _RWNX_IPC_UTILS_H_ ++ ++#include ++#include ++#include ++#include "aicwf_debug.h" ++ ++#include "lmac_msg.h" ++#if 0 ++#ifdef CONFIG_RWNX_DBG ++/* #define RWNX_DBG(format, arg...) pr_warn(format, ## arg) */ ++#define RWNX_DBG printk ++#else ++#define RWNX_DBG(a...) \ ++ do { \ ++ } while (0) ++#endif ++ ++#define RWNX_FN_ENTRY_STR ">>> %s()\n", __func__ ++#endif ++enum rwnx_dev_flag { ++ RWNX_DEV_RESTARTING, ++ RWNX_DEV_STACK_RESTARTING, ++ RWNX_DEV_STARTED, ++}; ++ ++struct rwnx_hw; ++struct rwnx_sta; ++ ++/** ++ * struct rwnx_ipc_elem - Generic IPC buffer of fixed size ++ * ++ * @addr: Host address of the buffer. ++ * @dma_addr: DMA address of the buffer. ++ */ ++struct rwnx_ipc_elem { ++ void *addr; ++ dma_addr_t dma_addr; ++}; ++ ++/** ++ * struct rwnx_ipc_elem_pool - Generic pool of IPC buffers of fixed size ++ * ++ * @nb: Number of buffers currenlty allocated in the pool ++ * @buf: Array of buffers (size of array is @nb) ++ * @pool: DMA pool in which buffers have been allocated ++ */ ++struct rwnx_ipc_elem_pool { ++ int nb; ++ struct rwnx_ipc_elem *buf; ++ struct dma_pool *pool; ++}; ++ ++/** ++ * struct rwnx_ipc_elem - Generic IPC buffer of variable size ++ * ++ * @addr: Host address of the buffer. ++ * @dma_addr: DMA address of the buffer. ++ * @size: Size, in bytes, of the buffer ++ */ ++struct rwnx_ipc_elem_var { ++ void *addr; ++ dma_addr_t dma_addr; ++ size_t size; ++}; ++ ++/** ++ * struct rwnx_ipc_dbgdump_elem - IPC buffer for debug dump ++ * ++ * @mutex: Mutex to protect access to debug dump ++ * @buf: IPC buffer ++ */ ++struct rwnx_ipc_dbgdump_elem { ++ struct mutex mutex; ++ struct rwnx_ipc_elem_var buf; ++}; ++ ++static const u32 rwnx_rxbuff_pattern = 0xCAFEFADE; ++ ++/* ++ * Maximum Length of Radiotap header vendor specific data(in bytes) ++ */ ++#define RADIOTAP_HDR_VEND_MAX_LEN 16 ++ ++/* ++ * Maximum Radiotap Header Length without vendor specific data (in bytes) ++ */ ++#define RADIOTAP_HDR_MAX_LEN 80 ++ ++/* ++ * Unsupported HT Frame data length (in bytes) ++ */ ++#define UNSUP_RX_VEC_DATA_LEN 2 ++ ++/** ++ * struct rwnx_ipc_skb_elem - IPC buffer for SKB element ++ * ++ * @skb: Pointer to the skb buffer allocated ++ * @dma_addr: DMA address of the data buffer fo skb ++ * ++ */ ++struct rwnx_ipc_skb_elem { ++ struct sk_buff *skb; ++ dma_addr_t dma_addr; ++}; ++ ++#ifdef CONFIG_RWNX_FULLMAC ++ ++/* Maximum number of rx buffer the fw may use at the same time */ ++#define RWNX_RXBUFF_MAX (64 * NX_REMOTE_STA_MAX) ++ ++/** ++ * struct rwnx_ipc_rxbuf_elems - IPC buffers for RX ++ * ++ * @skb: Array of buffer push to FW. ++ * @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. ++ */ ++struct rwnx_ipc_rxbuf_elems { ++ struct sk_buff *skb[RWNX_RXBUFF_MAX]; ++ int idx; ++}; ++ ++#endif /* CONFIG_RWNX_FULLMAC */ ++#endif /* _RWNX_IPC_UTILS_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_v7.c b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_v7.c +new file mode 100755 +index 000000000..af00bd8c2 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_v7.c +@@ -0,0 +1,191 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_v7.c - Support for v7 platform ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++#include "rwnx_v7.h" ++#include "rwnx_defs.h" ++#include "rwnx_irqs.h" ++#include "reg_access.h" ++#include "hal_desc.h" ++ ++struct rwnx_v7 { ++ u8 *pci_bar0_vaddr; ++ u8 *pci_bar1_vaddr; ++}; ++ ++static int rwnx_v7_platform_enable(struct rwnx_hw *rwnx_hw) ++{ ++ int ret; ++ ++ /* sched_setscheduler on ONESHOT threaded irq handler for BCNs ? */ ++ ret = request_irq(rwnx_hw->plat->pci_dev->irq, rwnx_irq_hdlr, 0, "rwnx", ++ rwnx_hw); ++ return ret; ++} ++ ++static int rwnx_v7_platform_disable(struct rwnx_hw *rwnx_hw) ++{ ++ free_irq(rwnx_hw->plat->pci_dev->irq, rwnx_hw); ++ return 0; ++} ++ ++static void rwnx_v7_platform_deinit(struct rwnx_plat *rwnx_plat) ++{ ++#ifdef CONFIG_PCI ++ struct rwnx_v7 *rwnx_v7 = (struct rwnx_v7 *)rwnx_plat->priv; ++ ++ pci_disable_device(rwnx_plat->pci_dev); ++ iounmap(rwnx_v7->pci_bar0_vaddr); ++ iounmap(rwnx_v7->pci_bar1_vaddr); ++ pci_release_regions(rwnx_plat->pci_dev); ++ pci_clear_master(rwnx_plat->pci_dev); ++ pci_disable_msi(rwnx_plat->pci_dev); ++#endif ++ kfree(rwnx_plat); ++} ++ ++static u8 *rwnx_v7_get_address(struct rwnx_plat *rwnx_plat, int addr_name, ++ unsigned int offset) ++{ ++ struct rwnx_v7 *rwnx_v7 = (struct rwnx_v7 *)rwnx_plat->priv; ++ ++ if (WARN(addr_name >= RWNX_ADDR_MAX, "Invalid address %d", addr_name)) ++ return NULL; ++ ++ if (addr_name == RWNX_ADDR_CPU) ++ return rwnx_v7->pci_bar0_vaddr + offset; ++ else ++ return rwnx_v7->pci_bar1_vaddr + offset; ++} ++ ++static void rwnx_v7_ack_irq(struct rwnx_plat *rwnx_plat) ++{ ++} ++ ++static const u32 rwnx_v7_config_reg[] = { ++ NXMAC_DEBUG_PORT_SEL_ADDR, SYSCTRL_DIAG_CONF_ADDR, ++ SYSCTRL_PHYDIAG_CONF_ADDR, SYSCTRL_RIUDIAG_CONF_ADDR, ++ RF_V7_DIAGPORT_CONF1_ADDR, ++}; ++ ++static const u32 rwnx_v7_he_config_reg[] = { ++ SYSCTRL_DIAG_CONF0, ++ SYSCTRL_DIAG_CONF1, ++ SYSCTRL_DIAG_CONF2, ++ SYSCTRL_DIAG_CONF3, ++}; ++ ++static int rwnx_v7_get_config_reg(struct rwnx_plat *rwnx_plat, const u32 **list) ++{ ++ u32 fpga_sign; ++ ++ if (!list) ++ return 0; ++ ++ fpga_sign = RWNX_REG_READ(rwnx_plat, RWNX_ADDR_SYSTEM, ++ SYSCTRL_SIGNATURE_ADDR); ++ if (__FPGA_TYPE(fpga_sign) == 0xc0ca) { ++ *list = rwnx_v7_he_config_reg; ++ return ARRAY_SIZE(rwnx_v7_he_config_reg); ++ } else { ++ *list = rwnx_v7_config_reg; ++ return ARRAY_SIZE(rwnx_v7_config_reg); ++ } ++} ++ ++/** ++ * rwnx_v7_platform_init - Initialize the DINI platform ++ * ++ * @pci_dev PCI device ++ * @rwnx_plat Pointer on struct rwnx_stat * to be populated ++ * ++ * @return 0 on success, < 0 otherwise ++ * ++ * Allocate and initialize a rwnx_plat structure for the dini platform. ++ */ ++int rwnx_v7_platform_init(struct pci_dev *pci_dev, struct rwnx_plat **rwnx_plat) ++{ ++ struct rwnx_v7 *rwnx_v7; ++ u16 pci_cmd; ++ int ret = 0; ++ ++ *rwnx_plat = kzalloc(sizeof(struct rwnx_plat) + sizeof(struct rwnx_v7), ++ GFP_KERNEL); ++ if (!*rwnx_plat) ++ return -ENOMEM; ++ ++ rwnx_v7 = (struct rwnx_v7 *)(*rwnx_plat)->priv; ++ ++ /* Hotplug fixups */ ++ pci_read_config_word(pci_dev, PCI_COMMAND, &pci_cmd); ++ pci_cmd |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR; ++ pci_write_config_word(pci_dev, PCI_COMMAND, pci_cmd); ++ //pci_write_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES >> 2); ++ ++ ret = pci_enable_device(pci_dev); ++ if (ret) { ++ dev_err(&(pci_dev->dev), "pci_enable_device failed\n"); ++ goto out_enable; ++ } ++ ++ pci_set_master(pci_dev); ++ ++#if 0 ++ ret = pci_request_regions(pci_dev, KBUILD_MODNAME); ++ if (ret) { ++ dev_err(&(pci_dev->dev), "pci_request_regions failed\n"); ++ goto out_request; ++ } ++#endif ++#ifdef CONFIG_PCI ++ if (pci_enable_msi(pci_dev)) { ++ dev_err(&(pci_dev->dev), "pci_enable_msi failed\n"); ++ goto out_msi; ++ } ++#endif ++ ++ rwnx_v7->pci_bar0_vaddr = (u8 *)pci_ioremap_bar(pci_dev, 0); ++ if (!rwnx_v7->pci_bar0_vaddr) { ++ dev_err(&(pci_dev->dev), "pci_ioremap_bar(%d) failed\n", 0); ++ ret = -ENOMEM; ++ goto out_bar0; ++ } ++ rwnx_v7->pci_bar1_vaddr = (u8 *)pci_ioremap_bar(pci_dev, 1); ++ if (!rwnx_v7->pci_bar1_vaddr) { ++ dev_err(&(pci_dev->dev), "pci_ioremap_bar(%d) failed\n", 1); ++ ret = -ENOMEM; ++ goto out_bar1; ++ } ++ ++ (*rwnx_plat)->enable = rwnx_v7_platform_enable; ++ (*rwnx_plat)->disable = rwnx_v7_platform_disable; ++ (*rwnx_plat)->deinit = rwnx_v7_platform_deinit; ++ (*rwnx_plat)->get_address = rwnx_v7_get_address; ++ (*rwnx_plat)->ack_irq = rwnx_v7_ack_irq; ++ (*rwnx_plat)->get_config_reg = rwnx_v7_get_config_reg; ++ ++ return 0; ++ ++out_bar1: ++ iounmap(rwnx_v7->pci_bar0_vaddr); ++out_bar0: ++#ifdef CONFIG_PCI ++ pci_disable_msi(pci_dev); ++out_msi: ++#endif ++ pci_release_regions(pci_dev); ++//out_request: ++#ifdef CONFIG_PCI ++ pci_clear_master(pci_dev); ++#endif ++ pci_disable_device(pci_dev); ++out_enable: ++ kfree(*rwnx_plat); ++ return ret; ++} +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_v7.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_v7.h +new file mode 100755 +index 000000000..412c273db +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_v7.h +@@ -0,0 +1,20 @@ ++/** ++ ****************************************************************************** ++ * ++ * @file rwnx_v7.h ++ * ++ * Copyright (C) RivieraWaves 2012-2019 ++ * ++ ****************************************************************************** ++ */ ++ ++#ifndef _RWNX_V7_H_ ++#define _RWNX_V7_H_ ++ ++#include ++#include "rwnx_platform.h" ++ ++int rwnx_v7_platform_init(struct pci_dev *pci_dev, ++ struct rwnx_plat **rwnx_plat); ++ ++#endif /* _RWNX_V7_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_version.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_version.h +new file mode 100755 +index 000000000..cfe5e6378 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_version.h +@@ -0,0 +1,12 @@ ++#ifndef _RWNX_VERSION_H_ ++#define _RWNX_VERSION_H_ ++ ++#include "rwnx_version_gen.h" ++ ++static inline void rwnx_print_version(void) ++{ ++ AICWFDBG(LOGINFO, RWNX_VERS_BANNER "\n"); ++ AICWFDBG(LOGINFO, "RELEASE_DATE:%s \r\n", RELEASE_DATE); ++} ++ ++#endif /* _RWNX_VERSION_H_ */ +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_version_gen.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_version_gen.h +new file mode 100755 +index 000000000..6fcb679c8 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_version_gen.h +@@ -0,0 +1,4 @@ ++#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 RELEASE_DATE "2025_0410_b99ca8b6" +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_wakelock.c b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_wakelock.c +new file mode 100755 +index 000000000..95e07796c +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_wakelock.c +@@ -0,0 +1,92 @@ ++#include ++#include ++#include ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) ++#include ++#else ++#include ++#endif ++#include "rwnx_defs.h" ++#include "rwnx_wakelock.h" ++ ++/* flare-edge (6.18 port): wakeup_source_create()/_add()/_remove()/_destroy() ++ * are gone from the public API (drivers/base/power/wakeup.c keeps them but ++ * no longer exports them) — wakeup_source_register(dev, name) / ++ * wakeup_source_unregister(ws) is the only supported entry point now, and ++ * is exactly the create+add / relax+remove+destroy sequence internally ++ * (see wakeup_source_register()'s own implementation). dev=NULL registers ++ * an anonymous source not tied to a struct device, matching the old ++ * wakeup_source_create() behavior used here. */ ++struct wakeup_source *rwnx_wakeup_init(const char *name) ++{ ++ return wakeup_source_register(NULL, name); ++} ++ ++void rwnx_wakeup_deinit(struct wakeup_source *ws) ++{ ++ if (ws && ws->active) ++ __pm_relax(ws); ++ wakeup_source_unregister(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 ++ ++#if defined(CONFIG_PLATFORM_ROCKCHIP2) || defined(CONFIG_PLATFORM_ROCKCHIP) ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) ++ return wakeup_source_register(dev, name); ++#else ++ return wakeup_source_register(name); ++#endif ++ ++#else ++ return wakeup_source_register(name); ++#endif //#if defined(CONFIG_PLATFORM_ROCKCHIP2) || defined(CONFIG_PLATFORM_ROCKCHIP) ++ ++#endif //LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0) ++} ++ ++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_irqrx = rwnx_wakeup_init("rwnx_irqrx_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_irqrx); ++ rwnx_wakeup_deinit(rwnx_hw->ws_pwrctrl); ++ rwnx_hw->ws_tx = NULL; ++ rwnx_hw->ws_rx = NULL; ++ rwnx_hw->ws_irqrx = NULL; ++ rwnx_hw->ws_pwrctrl = NULL; ++} +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_wakelock.h b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_wakelock.h +new file mode 100755 +index 000000000..694509bd3 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/rwnx_wakelock.h +@@ -0,0 +1,22 @@ ++#ifndef __RWNX_WAKELOCK_H ++#define __RWNX_WAKELOCK_H ++ ++#include ++#include ++#include ++ ++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/drivers/net/wireless/aic8800/aic8800_fdrv/sdio_host.c b/drivers/net/wireless/aic8800/aic8800_fdrv/sdio_host.c +new file mode 100755 +index 000000000..ce6a96173 +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/sdio_host.c +@@ -0,0 +1,141 @@ ++/** ++ * sdio_host.c ++ * ++ * SDIO host function declarations ++ * ++ * Copyright (C) AICSemi 2018-2020 ++ */ ++ ++#include "sdio_host.h" ++//#include "ipc_compat.h" ++#include "rwnx_tx.h" ++#include "rwnx_platform.h" ++#include "aicwf_debug.h" ++ ++/** ++ **************************************************************************************** ++ */ ++void aicwf_sdio_host_init(struct sdio_host_env_tag *env, void *cb, ++ void *shared_env_ptr, void *pthis) ++{ ++ // Reset the environments ++ ++ // Reset the Host environment ++ memset(env, 0, sizeof(struct sdio_host_env_tag)); ++ // Save the pointer to the register base ++ env->pthis = pthis; ++} ++ ++/** ++ **************************************************************************************** ++ */ ++volatile struct txdesc_host * ++aicwf_sdio_host_txdesc_get(struct sdio_host_env_tag *env, const int queue_idx) ++{ ++ // struct ipc_shared_env_tag *shared_env_ptr = env->shared; ++ volatile struct txdesc_host *txdesc_free = NULL; ++ uint32_t used_idx = env->txdesc_used_idx[queue_idx]; ++ uint32_t free_idx = env->txdesc_free_idx[queue_idx]; ++ ++ // ASSERT_ERR(queue_idx < SDIO_TXQUEUE_CNT); ++ // ASSERT_ERR((free_idx - used_idx) <= SDIO_TXDESC_CNT); ++ ++ // Check if a free descriptor is available ++ if (free_idx != (used_idx + SDIO_TXDESC_CNT)) { ++ // Get the pointer to the first free descriptor ++ // txdesc_free = shared_env_ptr->txdesc[queue_idx] + (free_idx % IPC_TXDESC_CNT); ++ } else { ++ txdesc_free = NULL; ++ } ++ ++ return txdesc_free; ++} ++ ++/** ++ **************************************************************************************** ++ */ ++void aicwf_sdio_host_txdesc_push(struct sdio_host_env_tag *env, ++ const int queue_idx, const uint64_t host_id) ++{ ++ //printk("push, %d, %d, 0x%llx \r\n", queue_idx, env->txdesc_free_idx[queue_idx], host_id); ++ // Save the host id in the environment ++ env->tx_host_id[queue_idx][env->txdesc_free_idx[queue_idx] % ++ SDIO_TXDESC_CNT] = host_id; ++ ++ // Increment the index ++ env->txdesc_free_idx[queue_idx]++; ++ if (env->txdesc_free_idx[queue_idx] == 0x80000000) ++ env->txdesc_free_idx[queue_idx] = 0; ++} ++ ++/** ++ **************************************************************************************** ++ */ ++void aicwf_sdio_host_tx_cfm_handler(struct sdio_host_env_tag *env, u32 *data) ++{ ++ u32 queue_idx = 0; // data[0]; ++ //struct rwnx_hw *rwnx_hw = (struct rwnx_hw *)env->pthis; ++ struct sk_buff *skb = NULL; ++ struct rwnx_txhdr *txhdr; ++ ++ // 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]++; ++ uint32_t used_idx = data[1]; ++ unsigned long host_id = ++ env->tx_host_id[queue_idx][used_idx % SDIO_TXDESC_CNT]; ++ ++ // Reset the host id in the array ++ env->tx_host_id[queue_idx][used_idx % SDIO_TXDESC_CNT] = 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] = used_idx; ++ AICWFDBG(LOGERROR, "ERROR:No more confirmations\r\n"); ++ //break; ++ } ++ // set the cfm status ++ skb = (struct sk_buff *)host_id; ++ txhdr = (struct rwnx_txhdr *)skb->data; ++ txhdr->hw_hdr.cfm.status = (union rwnx_hw_txstatus)data[0]; ++ AICWFDBG( ++ LOGINFO, ++ "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) { ++ // 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; ++ // and exit the loop ++ AICWFDBG(LOGERROR, "ERROR:rwnx_txdatacfm,\r\n"); ++ // break; ++ } ++ } ++} ++ ++int aicwf_rwnx_sdio_platform_init(struct aic_sdio_dev *sdiodev) ++{ ++ struct rwnx_plat *rwnx_plat = NULL; ++ void *drvdata; ++ int ret = -ENODEV; ++ ++ rwnx_plat = kzalloc(sizeof(struct rwnx_plat), GFP_KERNEL); ++ ++ if (!rwnx_plat) { ++ return -ENOMEM; ++ } ++ ++ rwnx_plat->sdiodev = sdiodev; ++ ret = rwnx_platform_init(rwnx_plat, &drvdata); ++ ++ return ret; ++} +diff --git a/drivers/net/wireless/aic8800/aic8800_fdrv/sdio_host.h b/drivers/net/wireless/aic8800/aic8800_fdrv/sdio_host.h +new file mode 100755 +index 000000000..e0b62e5fd +--- /dev/null ++++ b/drivers/net/wireless/aic8800/aic8800_fdrv/sdio_host.h +@@ -0,0 +1,42 @@ ++/** ++ * sdio_host.h ++ * ++ * SDIO host function declarations ++ * ++ * Copyright (C) AICSemi 2018-2020 ++ */ ++ ++#ifndef _SDIO_HOST_H_ ++#define _SDIO_HOST_H_ ++ ++#include "lmac_types.h" ++#include "aicwf_sdio.h" ++ ++#define SDIO_TXQUEUE_CNT NX_TXQ_CNT ++#define SDIO_TXDESC_CNT NX_TXDESC_CNT ++ ++/// Definition of the IPC Host environment structure. ++struct sdio_host_env_tag { ++ // Index used that points to the first free TX desc ++ uint32_t txdesc_free_idx[SDIO_TXQUEUE_CNT]; ++ // Index used that points to the first used TX desc ++ uint32_t txdesc_used_idx[SDIO_TXQUEUE_CNT]; ++ // Array storing the currently pushed host ids, per IPC queue ++ uint64_t tx_host_id[SDIO_TXQUEUE_CNT][SDIO_TXDESC_CNT]; ++ ++ /// Pointer to the attached object (used in callbacks and register accesses) ++ void *pthis; ++}; ++ ++extern void aicwf_sdio_host_init(struct sdio_host_env_tag *env, void *cb, ++ void *shared_env_ptr, void *pthis); ++ ++extern void aicwf_sdio_host_txdesc_push(struct sdio_host_env_tag *env, ++ const int queue_idx, ++ const uint64_t host_id); ++ ++extern void aicwf_sdio_host_tx_cfm_handler(struct sdio_host_env_tag *env, ++ u32 *data); ++extern int aicwf_rwnx_sdio_platform_init(struct aic_sdio_dev *sdiodev); ++ ++#endif diff --git a/patches/70-audio-codec.patch b/patches/70-audio-codec.patch new file mode 100644 index 0000000..0f87caf --- /dev/null +++ b/patches/70-audio-codec.patch @@ -0,0 +1,3999 @@ +diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig +index 91ac99bc3..bbc83867a 100644 +--- a/sound/soc/codecs/Kconfig ++++ b/sound/soc/codecs/Kconfig +@@ -1604,6 +1604,14 @@ config SND_SOC_RK817 + tristate "Rockchip RK817 audio CODEC" + depends on MFD_RK8XX || COMPILE_TEST + ++config SND_SOC_RK_DSM ++ tristate "Rockchip Delta-sigma Digital Converter Interface" ++ depends on ARCH_ROCKCHIP || COMPILE_TEST ++ help ++ This is a device driver for the digital speaker modulator (DSM) ++ embedded in some Rockchip SoCs (e.g. RV1106), used to drive a ++ Class-D speaker output alongside the analog acodec. ++ + config SND_SOC_RL6231 + tristate + default y if SND_SOC_RT5514=y +@@ -1919,6 +1927,15 @@ config SND_SOC_RTQ9128 + To compile this driver as a module, choose M here: the module + will be called snd-soc-rtq9128. + ++config SND_SOC_RV1106 ++ tristate "Rockchip RV1106 CODEC" ++ depends on ARCH_ROCKCHIP || COMPILE_TEST ++ select REGMAP_MMIO ++ help ++ This is a device driver for the analog audio codec (acodec) ++ embedded in the Rockchip RV1106 SoC, used for speaker/headphone ++ output and microphone input (e.g. on the Luckfox Pico 86-Panel). ++ + config SND_SOC_SDW_MOCKUP + tristate "SoundWire mockup codec" + depends on EXPERT +diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile +index da4077463..ae15009e0 100644 +--- a/sound/soc/codecs/Makefile ++++ b/sound/soc/codecs/Makefile +@@ -231,6 +231,7 @@ snd-soc-pm4125-sdw-y := pm4125-sdw.o + snd-soc-rk3308-y := rk3308_codec.o + snd-soc-rk3328-y := rk3328_codec.o + snd-soc-rk817-y := rk817_codec.o ++snd-soc-rk-dsm-y := rk_dsm.o + snd-soc-rl6231-y := rl6231.o + snd-soc-rt-sdw-common-y := rt-sdw-common.o + snd-soc-rl6347a-y := rl6347a.o +@@ -283,6 +284,7 @@ snd-soc-rt9123-y := rt9123.o + snd-soc-rt9123p-y := rt9123p.o + snd-soc-rtq9124-y := rtq9124.o + snd-soc-rtq9128-y := rtq9128.o ++snd-soc-rv1106-y := rv1106_codec.o + snd-soc-sdw-mockup-y := sdw-mockup.o + snd-soc-sgtl5000-y := sgtl5000.o + snd-soc-alc5623-y := alc5623.o +@@ -662,6 +664,7 @@ endif + obj-$(CONFIG_SND_SOC_RK3308) += snd-soc-rk3308.o + obj-$(CONFIG_SND_SOC_RK3328) += snd-soc-rk3328.o + obj-$(CONFIG_SND_SOC_RK817) += snd-soc-rk817.o ++obj-$(CONFIG_SND_SOC_RK_DSM) += snd-soc-rk-dsm.o + obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o + obj-$(CONFIG_SND_SOC_RT_SDW_COMMON) += snd-soc-rt-sdw-common.o + obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o +@@ -715,6 +718,7 @@ obj-$(CONFIG_SND_SOC_RT9123) += snd-soc-rt9123.o + obj-$(CONFIG_SND_SOC_RT9123P) += snd-soc-rt9123p.o + obj-$(CONFIG_SND_SOC_RTQ9124) += snd-soc-rtq9124.o + obj-$(CONFIG_SND_SOC_RTQ9128) += snd-soc-rtq9128.o ++obj-$(CONFIG_SND_SOC_RV1106) += snd-soc-rv1106.o + obj-$(CONFIG_SND_SOC_SDW_MOCKUP) += snd-soc-sdw-mockup.o + obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o + obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o +diff --git a/sound/soc/codecs/rk_dsm.c b/sound/soc/codecs/rk_dsm.c +new file mode 100644 +index 000000000..4bcbcbaf5 +--- /dev/null ++++ b/sound/soc/codecs/rk_dsm.c +@@ -0,0 +1,651 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Rockchip Audio Delta-sigma Digital Converter Interface ++ * ++ * Copyright (C) 2023 Rockchip Electronics Co.,Ltd ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "rk_dsm.h" ++ ++#define RK3562_GRF_PERI_AUDIO_CON (0x0070) ++ ++struct rk_dsm_soc_data { ++ int (*init)(struct device *dev); ++ void (*deinit)(struct device *dev); ++}; ++ ++struct rk_dsm_priv { ++ struct regmap *grf; ++ struct regmap *regmap; ++ struct clk *clk_dac; ++ struct clk *pclk; ++ unsigned int pa_ctl_delay_ms; ++ struct gpio_desc *pa_ctl; ++ struct reset_control *rc; ++ const struct rk_dsm_soc_data *data; ++}; ++ ++/* DAC digital gain */ ++static const DECLARE_TLV_DB_SCALE(dac_tlv, -95625, 375, 0); ++ ++/* DAC Cutoff for High Pass Filter */ ++static const char * const dac_hpf_cutoff_text[] = { ++ "80Hz", "100Hz", "120Hz", "140Hz", ++}; ++ ++static SOC_ENUM_SINGLE_DECL(dac_hpf_cutoff_enum, DACHPF, 4, ++ dac_hpf_cutoff_text); ++ ++static const char * const pa_ctl[] = {"Off", "On"}; ++ ++static const struct soc_enum pa_enum = ++ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(pa_ctl), pa_ctl); ++ ++static int rk_dsm_dac_vol_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); ++ struct soc_mixer_control *mc = ++ (struct soc_mixer_control *)kcontrol->private_value; ++ unsigned int val = snd_soc_component_read(component, mc->reg); ++ unsigned int sign = snd_soc_component_read(component, DACVOGP); ++ unsigned int mask = (1 << fls(mc->max)) - 1; ++ unsigned int shift = mc->shift; ++ int mid = mc->max / 2; ++ int uv; ++ ++ uv = (val >> shift) & mask; ++ if (sign) ++ uv = mid + uv; ++ else ++ uv = mid - uv; ++ ++ ucontrol->value.integer.value[0] = uv; ++ ucontrol->value.integer.value[1] = uv; ++ ++ return 0; ++} ++ ++static int rk_dsm_dac_vol_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); ++ struct soc_mixer_control *mc = ++ (struct soc_mixer_control *)kcontrol->private_value; ++ unsigned int reg = mc->reg; ++ unsigned int rreg = mc->rreg; ++ unsigned int shift = mc->shift; ++ unsigned int mask = (1 << fls(mc->max)) - 1; ++ unsigned int val, val_mask, sign; ++ int uv = ucontrol->value.integer.value[0]; ++ int min = mc->min; ++ int mid = mc->max / 2; ++ ++ if (uv > mid) { ++ sign = DSM_DACVOGP_VOLGPL0_POS | DSM_DACVOGP_VOLGPR0_POS; ++ uv = uv - mid; ++ } else { ++ sign = DSM_DACVOGP_VOLGPL0_NEG | DSM_DACVOGP_VOLGPR0_NEG; ++ uv = mid - uv; ++ } ++ ++ val = ((uv + min) & mask); ++ val_mask = mask << shift; ++ val = val << shift; ++ ++ snd_soc_component_update_bits(component, reg, val_mask, val); ++ snd_soc_component_update_bits(component, rreg, val_mask, val); ++ snd_soc_component_write(component, DACVOGP, sign); ++ ++ return 0; ++} ++ ++static int rk_dsm_dac_pa_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); ++ struct rk_dsm_priv *rd = snd_soc_component_get_drvdata(component); ++ ++ if (!rd->pa_ctl) ++ return -EINVAL; ++ ++ ucontrol->value.enumerated.item[0] = gpiod_get_value(rd->pa_ctl); ++ ++ return 0; ++} ++ ++static int rk_dsm_dac_pa_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); ++ struct rk_dsm_priv *rd = snd_soc_component_get_drvdata(component); ++ ++ if (!rd->pa_ctl) ++ return -EINVAL; ++ ++ gpiod_set_value(rd->pa_ctl, ucontrol->value.enumerated.item[0]); ++ ++ return 0; ++} ++ ++static const struct snd_kcontrol_new rk_dsm_snd_controls[] = { ++ SOC_DOUBLE_R_EXT_TLV("DAC Digital Volume", ++ DACVOLL0, DACVOLR0, 0, 0x1fe, 0, ++ rk_dsm_dac_vol_get, ++ rk_dsm_dac_vol_put, ++ dac_tlv), ++ ++ SOC_ENUM("DAC HPF Cutoff", dac_hpf_cutoff_enum), ++ SOC_SINGLE("DAC HPF Switch", DACHPF, 0, 1, 0), ++ SOC_ENUM_EXT("Power Amplifier", pa_enum, ++ rk_dsm_dac_pa_get, ++ rk_dsm_dac_pa_put), ++}; ++ ++/* ++ * ACDC_CLK D2A_CLK D2A_SYNC Sample rates supported ++ * 49.152MHz 49.152MHz 6.144MHz 12/24/48/96/192kHz ++ * 45.154MHz 45.154MHz 5.644MHz 11.025/22.05/44.1/88.2/176.4kHz ++ * 32.768MHz 32.768MHz 4.096MHz 8/16/32/64/128kHz ++ */ ++static void rk_dsm_get_clk(unsigned int samplerate, ++ unsigned int *mclk, ++ unsigned int *sclk) ++{ ++ switch (samplerate) { ++ case 12000: ++ case 24000: ++ case 48000: ++ case 96000: ++ case 192000: ++ *mclk = 49152000; ++ *sclk = 6144000; ++ break; ++ case 11025: ++ case 22050: ++ case 44100: ++ case 88200: ++ case 176400: ++ *mclk = 45158400; ++ *sclk = 5644800; ++ break; ++ case 8000: ++ case 16000: ++ case 32000: ++ case 64000: ++ case 128000: ++ *mclk = 32768000; ++ *sclk = 4096000; ++ break; ++ default: ++ *mclk = 0; ++ *sclk = 0; ++ break; ++ } ++} ++ ++static void rk_dsm_enable_clk_dac(struct rk_dsm_priv *rd) ++{ ++ regmap_update_bits(rd->regmap, DACCLKCTRL, ++ DSM_DACCLKCTRL_DAC_CKE_MASK | ++ DSM_DACCLKCTRL_I2SRX_CKE_MASK | ++ DSM_DACCLKCTRL_CKE_BCLKRX_MASK | ++ DSM_DACCLKCTRL_DAC_SYNC_ENA_MASK | ++ DSM_DACCLKCTRL_DAC_MODE_ATTENU_MASK, ++ DSM_DACCLKCTRL_DAC_CKE_EN | ++ DSM_DACCLKCTRL_I2SRX_CKE_EN | ++ DSM_DACCLKCTRL_CKE_BCLKRX_EN | ++ DSM_DACCLKCTRL_DAC_SYNC_ENA_EN | ++ DSM_DACCLKCTRL_DAC_MODE_ATTENU_EN); ++} ++ ++static int rk_dsm_set_clk(struct rk_dsm_priv *rd, ++ struct snd_pcm_substream *substream, ++ unsigned int samplerate) ++{ ++ unsigned int mclk, sclk, bclk; ++ unsigned int div_bclk; ++ ++ rk_dsm_get_clk(samplerate, &mclk, &sclk); ++ if (!mclk || !sclk) ++ return -EINVAL; ++ ++ bclk = 64 * samplerate; ++ div_bclk = DIV_ROUND_CLOSEST(mclk, bclk); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ clk_set_rate(rd->clk_dac, mclk); ++ ++ rk_dsm_enable_clk_dac(rd); ++ ++ regmap_update_bits(rd->regmap, DACSCLKRXINT_DIV, ++ DSM_DACSCLKRXINT_DIV_SCKRXDIV_MASK, ++ DSM_DACSCLKRXINT_DIV_SCKRXDIV(div_bclk)); ++ regmap_update_bits(rd->regmap, I2S_CKR0, ++ DSM_I2S_CKR0_RSD_MASK, ++ DSM_I2S_CKR0_RSD_64); ++ } ++ ++ return 0; ++} ++ ++static int rk_dsm_set_dai_fmt(struct snd_soc_dai *dai, ++ unsigned int fmt) ++{ ++ struct rk_dsm_priv *rd = ++ snd_soc_component_get_drvdata(dai->component); ++ unsigned int mask = 0, val = 0; ++ ++ /* master mode only */ ++ regmap_update_bits(rd->regmap, I2S_CKR1, ++ DSM_I2S_CKR1_MSS_MASK, ++ DSM_I2S_CKR1_MSS_MASTER); ++ ++ mask = DSM_I2S_CKR1_CKP_MASK | ++ DSM_I2S_CKR1_RLP_MASK; ++ ++ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { ++ case SND_SOC_DAIFMT_NB_NF: ++ val = DSM_I2S_CKR1_CKP_NORMAL | ++ DSM_I2S_CKR1_RLP_NORMAL; ++ break; ++ case SND_SOC_DAIFMT_IB_IF: ++ val = DSM_I2S_CKR1_CKP_INVERTED | ++ DSM_I2S_CKR1_RLP_INVERTED; ++ break; ++ case SND_SOC_DAIFMT_IB_NF: ++ val = DSM_I2S_CKR1_CKP_INVERTED | ++ DSM_I2S_CKR1_RLP_NORMAL; ++ break; ++ case SND_SOC_DAIFMT_NB_IF: ++ val = DSM_I2S_CKR1_CKP_NORMAL | ++ DSM_I2S_CKR1_RLP_INVERTED; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ regmap_update_bits(rd->regmap, I2S_CKR1, mask, val); ++ ++ return 0; ++} ++ ++static int rk_dsm_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, ++ struct snd_soc_dai *dai) ++{ ++ struct rk_dsm_priv *rd = ++ snd_soc_component_get_drvdata(dai->component); ++ unsigned int srt = 0, val = 0; ++ ++ rk_dsm_set_clk(rd, substream, params_rate(params)); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ switch (params_rate(params)) { ++ case 8000: ++ case 11025: ++ case 12000: ++ srt = 0; ++ break; ++ case 16000: ++ case 22050: ++ case 24000: ++ srt = 1; ++ break; ++ case 32000: ++ case 44100: ++ case 48000: ++ srt = 2; ++ break; ++ case 64000: ++ case 88200: ++ case 96000: ++ srt = 3; ++ break; ++ case 128000: ++ case 176400: ++ case 192000: ++ srt = 4; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ regmap_update_bits(rd->regmap, DACCFG1, ++ DSM_DACCFG1_DACSRT_MASK, ++ DSM_DACCFG1_DACSRT(srt)); ++ ++ switch (params_format(params)) { ++ case SNDRV_PCM_FORMAT_S16_LE: ++ val = 16; ++ break; ++ case SNDRV_PCM_FORMAT_S24_LE: ++ case SNDRV_PCM_FORMAT_S32_LE: ++ val = 24; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ regmap_update_bits(rd->regmap, I2S_RXCR0, ++ DSM_I2S_RXCR0_VDW_MASK, ++ DSM_I2S_RXCR0_VDW(val)); ++ regmap_update_bits(rd->regmap, DACPWM_CTRL, ++ DSM_DACPWM_CTRL_PWM_MODE_CKE_MASK | ++ DSM_DACPWM_CTRL_PWM_EN_MASK, ++ DSM_DACPWM_CTRL_PWM_MODE_CKE_EN | ++ DSM_DACPWM_CTRL_PWM_EN); ++ } ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ regmap_update_bits(rd->regmap, I2S_XFER, ++ DSM_I2S_XFER_RXS_MASK, ++ DSM_I2S_XFER_RXS_START); ++ regmap_update_bits(rd->regmap, DACDIGEN, ++ DSM_DACDIGEN_DAC_GLBEN_MASK | ++ DSM_DACDIGEN_DACEN_L0R1_MASK, ++ DSM_DACDIGEN_DAC_GLBEN_EN | ++ DSM_DACDIGEN_DACEN_L0R1_EN); ++ } ++ ++ return 0; ++} ++ ++static int rk_dsm_pcm_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct rk_dsm_priv *rd = ++ snd_soc_component_get_drvdata(dai->component); ++ ++ gpiod_set_value(rd->pa_ctl, 1); ++ if (rd->pa_ctl_delay_ms) ++ msleep(rd->pa_ctl_delay_ms); ++ ++ return 0; ++} ++ ++static void rk_dsm_reset(struct rk_dsm_priv *rd) ++{ ++ if (IS_ERR(rd->rc)) ++ return; ++ ++ reset_control_assert(rd->rc); ++ udelay(5); ++ reset_control_deassert(rd->rc); ++ udelay(5); ++} ++ ++static void rk_dsm_pcm_shutdown(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct rk_dsm_priv *rd = ++ snd_soc_component_get_drvdata(dai->component); ++ ++ gpiod_set_value(rd->pa_ctl, 0); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ regmap_update_bits(rd->regmap, DACPWM_CTRL, ++ DSM_DACPWM_CTRL_PWM_MODE_CKE_MASK | ++ DSM_DACPWM_CTRL_PWM_EN_MASK, ++ DSM_DACPWM_CTRL_PWM_MODE_CKE_DIS | ++ DSM_DACPWM_CTRL_PWM_DIS); ++ regmap_update_bits(rd->regmap, I2S_XFER, ++ DSM_I2S_XFER_RXS_MASK, ++ DSM_I2S_XFER_RXS_STOP); ++ regmap_update_bits(rd->regmap, I2S_CLR, ++ DSM_I2S_CLR_RXC_MASK, ++ DSM_I2S_CLR_RXC_CLR); ++ regmap_update_bits(rd->regmap, DACDIGEN, ++ DSM_DACDIGEN_DAC_GLBEN_MASK | ++ DSM_DACDIGEN_DACEN_L0R1_MASK, ++ DSM_DACDIGEN_DAC_GLBEN_DIS | ++ DSM_DACDIGEN_DACEN_L0R1_DIS); ++ } ++ ++ rk_dsm_reset(rd); ++} ++ ++static const struct snd_soc_dai_ops rd_dai_ops = { ++ .hw_params = rk_dsm_hw_params, ++ .set_fmt = rk_dsm_set_dai_fmt, ++ .startup = rk_dsm_pcm_startup, ++ .shutdown = rk_dsm_pcm_shutdown, ++}; ++ ++static struct snd_soc_dai_driver rd_dai[] = { ++ { ++ .name = "rk_dsm", ++ .id = 0, ++ .playback = { ++ .stream_name = "Playback", ++ .channels_min = 2, ++ .channels_max = 2, ++ .rates = SNDRV_PCM_RATE_8000_192000, ++ .formats = (SNDRV_PCM_FMTBIT_S16_LE | ++ SNDRV_PCM_FMTBIT_S24_LE | ++ SNDRV_PCM_FMTBIT_S32_LE), ++ }, ++ .ops = &rd_dai_ops, ++ }, ++}; ++ ++static const struct snd_soc_component_driver soc_codec_dev_rd = { ++ .controls = rk_dsm_snd_controls, ++ .num_controls = ARRAY_SIZE(rk_dsm_snd_controls), ++}; ++ ++static const struct regmap_config rd_regmap_config = { ++ .reg_bits = 32, ++ .reg_stride = 4, ++ .val_bits = 32, ++ .max_register = VERSION, ++ .cache_type = REGCACHE_FLAT, ++}; ++ ++static int rk3562_soc_init(struct device *dev) ++{ ++ struct rk_dsm_priv *rd = dev_get_drvdata(dev); ++ ++ if (IS_ERR(rd->grf)) ++ return PTR_ERR(rd->grf); ++ ++ /* enable internal codec to i2s1 */ ++ return regmap_write(rd->grf, RK3562_GRF_PERI_AUDIO_CON, ++ (BIT(14) << 16 | BIT(14) | 0x0a100a10)); ++} ++ ++static void rk3562_soc_deinit(struct device *dev) ++{ ++ struct rk_dsm_priv *rd = dev_get_drvdata(dev); ++ ++ if (IS_ERR(rd->grf)) ++ return; ++ ++ regmap_write(rd->grf, RK3562_GRF_PERI_AUDIO_CON, (BIT(14) << 16) | 0x0a100a10); ++} ++ ++static const struct rk_dsm_soc_data rk3562_data = { ++ .init = rk3562_soc_init, ++ .deinit = rk3562_soc_deinit, ++}; ++ ++#ifdef CONFIG_OF ++static const struct of_device_id rd_of_match[] = { ++ { .compatible = "rockchip,rk3562-dsm", .data = &rk3562_data }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, rd_of_match); ++#endif ++ ++#ifdef CONFIG_PM ++static int rk_dsm_runtime_resume(struct device *dev) ++{ ++ struct rk_dsm_priv *rd = dev_get_drvdata(dev); ++ int ret = 0; ++ ++ ret = clk_prepare_enable(rd->pclk); ++ if (ret) ++ return ret; ++ ++ regcache_cache_only(rd->regmap, false); ++ regcache_mark_dirty(rd->regmap); ++ ++ ret = clk_prepare_enable(rd->clk_dac); ++ if (ret) ++ goto err; ++ ++ return 0; ++err: ++ clk_disable_unprepare(rd->pclk); ++ ++ return ret; ++} ++ ++static int rk_dsm_runtime_suspend(struct device *dev) ++{ ++ struct rk_dsm_priv *rd = dev_get_drvdata(dev); ++ ++ regcache_cache_only(rd->regmap, true); ++ clk_disable_unprepare(rd->clk_dac); ++ clk_disable_unprepare(rd->pclk); ++ ++ return 0; ++} ++#endif ++ ++static int rk_dsm_platform_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct rk_dsm_priv *rd; ++ void __iomem *base; ++ int ret = 0; ++ ++ rd = devm_kzalloc(&pdev->dev, sizeof(*rd), GFP_KERNEL); ++ if (!rd) ++ return -ENOMEM; ++ ++ rd->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); ++ if (IS_ERR(rd->grf)) ++ return PTR_ERR(rd->grf); ++ ++ if (device_property_read_u32(&pdev->dev, "rockchip,pa-ctl-delay-ms", ++ &rd->pa_ctl_delay_ms)) ++ rd->pa_ctl_delay_ms = 0; ++ ++ rd->rc = devm_reset_control_get(&pdev->dev, "reset"); ++ ++ rd->clk_dac = devm_clk_get(&pdev->dev, "dac"); ++ if (IS_ERR(rd->clk_dac)) ++ return PTR_ERR(rd->clk_dac); ++ ++ rd->pclk = devm_clk_get(&pdev->dev, "pclk"); ++ if (IS_ERR(rd->pclk)) ++ return PTR_ERR(rd->pclk); ++ ++ base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); ++ ++ rd->regmap = ++ devm_regmap_init_mmio(&pdev->dev, base, &rd_regmap_config); ++ if (IS_ERR(rd->regmap)) ++ return PTR_ERR(rd->regmap); ++ ++ platform_set_drvdata(pdev, rd); ++ ++ rd->data = device_get_match_data(&pdev->dev); ++ if (rd->data && rd->data->init) { ++ ret = rd->data->init(&pdev->dev); ++ if (ret) ++ return ret; ++ } ++ ++ pm_runtime_enable(&pdev->dev); ++ if (!pm_runtime_enabled(&pdev->dev)) { ++ ret = rk_dsm_runtime_resume(&pdev->dev); ++ if (ret) ++ goto err_pm_disable; ++ } ++ ++ regmap_update_bits(rd->regmap, DACPWM_CTRL, ++ DSM_DACPWM_CTRL_PWM_MODE_MASK, ++ DSM_DACPWM_CTRL_PWM_MODE_0); ++ ++ rd->pa_ctl = devm_gpiod_get_optional(&pdev->dev, "pa-ctl", ++ GPIOD_OUT_LOW); ++ ++ if (!rd->pa_ctl) { ++ dev_info(&pdev->dev, "no need pa-ctl gpio\n"); ++ } else if (IS_ERR(rd->pa_ctl)) { ++ ret = PTR_ERR(rd->pa_ctl); ++ dev_err(&pdev->dev, "fail to request gpio pa-ctl\n"); ++ goto err_suspend; ++ } ++ ++ ret = devm_snd_soc_register_component(&pdev->dev, &soc_codec_dev_rd, ++ rd_dai, ARRAY_SIZE(rd_dai)); ++ ++ if (ret) ++ goto err_suspend; ++ ++ return 0; ++ ++err_suspend: ++ if (!pm_runtime_status_suspended(&pdev->dev)) ++ rk_dsm_runtime_suspend(&pdev->dev); ++err_pm_disable: ++ pm_runtime_disable(&pdev->dev); ++ ++ if (rd->data && rd->data->deinit) ++ rd->data->deinit(&pdev->dev); ++ ++ return ret; ++} ++ ++static void rk_dsm_platform_remove(struct platform_device *pdev) ++{ ++ struct rk_dsm_priv *rd = dev_get_drvdata(&pdev->dev); ++ ++ pm_runtime_disable(&pdev->dev); ++ if (!pm_runtime_status_suspended(&pdev->dev)) ++ rk_dsm_runtime_suspend(&pdev->dev); ++ ++ if (rd->data && rd->data->deinit) ++ rd->data->deinit(&pdev->dev); ++} ++ ++static const struct dev_pm_ops rd_pm = { ++ SET_RUNTIME_PM_OPS(rk_dsm_runtime_suspend, ++ rk_dsm_runtime_resume, NULL) ++}; ++ ++static struct platform_driver rk_dsm_driver = { ++ .driver = { ++ .name = "rk_dsm", ++ .of_match_table = of_match_ptr(rd_of_match), ++ .pm = &rd_pm, ++ }, ++ .probe = rk_dsm_platform_probe, ++ .remove = rk_dsm_platform_remove, ++}; ++module_platform_driver(rk_dsm_driver); ++ ++MODULE_AUTHOR("Jason Zhu "); ++MODULE_DESCRIPTION("ASoC Rockchip Delta-sigma Digital Converter Driver"); ++MODULE_LICENSE("GPL"); +diff --git a/sound/soc/codecs/rk_dsm.h b/sound/soc/codecs/rk_dsm.h +new file mode 100644 +index 000000000..553b1c490 +--- /dev/null ++++ b/sound/soc/codecs/rk_dsm.h +@@ -0,0 +1,168 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Rockchip Audio Delta-sigma Digital Converter driver ++ * ++ * Copyright (C) 2023 Rockchip Electronics Co., Ltd ++ * ++ */ ++ ++#ifndef _RK_DSM_H ++#define _RK_DSM_H ++ ++#define DACVUCTL 0x0000 ++#define DACVUCTIME 0x0004 ++#define DACDIGEN 0x0008 ++#define DACCLKCTRL 0x000c ++#define DACINT_DIV 0x0014 ++#define DACSCLKRXINT_DIV 0x0020 ++#define DACPWM_DIV 0x0024 ++#define DACPWM_CTRL 0x0028 ++#define DACCFG1 0x0044 ++#define DACMUTE 0x0048 ++#define DACMUTEST 0x004c ++#define DACVOLL0 0x0050 ++#define DACVOLL1 0x0054 ++#define DACVOLL2 0x0058 ++#define DACVOLL3 0x005c ++#define DACVOLR0 0x0060 ++#define DACVOLR1 0x0064 ++#define DACVOLR2 0x0068 ++#define DACVOLR3 0x006c ++#define DACVOGP 0x0070 ++#define DACRVOLL0 0x0074 ++#define DACRVOLL1 0x0078 ++#define DACRVOLL2 0x007c ++#define DACRVOLL3 0x0080 ++#define DACRVOLR0 0x0084 ++#define DACRVOLR1 0x0088 ++#define DACRVOLR2 0x008c ++#define DACRVOLR3 0x0090 ++#define DACLMT0 0x0094 ++#define DACLMT1 0x0098 ++#define DACLMT2 0x009c ++#define DACMIXCTRLL 0x00a0 ++#define DACMIXCTRLR 0x00a4 ++#define DACHPF 0x00a8 ++#define I2S_RXCR0 0x010c ++#define I2S_RXCR1 0x0110 ++#define I2S_CKR0 0x0114 ++#define I2S_CKR1 0x0118 ++#define I2S_XFER 0x011c ++#define I2S_CLR 0x0120 ++#define VERSION 0x0140 ++ ++/* DACDIGEN */ ++#define DSM_DACDIGEN_DACEN_L0R1_MASK BIT(0) ++#define DSM_DACDIGEN_DACEN_L0R1_EN BIT(0) ++#define DSM_DACDIGEN_DACEN_L0R1_DIS 0 ++#define DSM_DACDIGEN_DAC_GLBEN_MASK BIT(4) ++#define DSM_DACDIGEN_DAC_GLBEN_EN BIT(4) ++#define DSM_DACDIGEN_DAC_GLBEN_DIS 0 ++/* DACCLKCTRL */ ++#define DSM_DACCLKCTRL_DAC_MODE_ATTENU_MASK BIT(0) ++#define DSM_DACCLKCTRL_DAC_MODE_ATTENU_EN BIT(0) ++#define DSM_DACCLKCTRL_DAC_MODE_ATTENU_DIS 0 ++#define DSM_DACCLKCTRL_DAC_SYNC_STATUS_MASK BIT(1) ++#define DSM_DACCLKCTRL_DAC_SYNC_STATUS_DONE 0 ++#define DSM_DACCLKCTRL_DAC_SYNC_ENA_MASK BIT(2) ++#define DSM_DACCLKCTRL_DAC_SYNC_ENA_EN BIT(2) ++#define DSM_DACCLKCTRL_DAC_SYNC_ENA_DIS 0 ++#define DSM_DACCLKCTRL_CKE_BCLKRX_MASK BIT(3) ++#define DSM_DACCLKCTRL_CKE_BCLKRX_EN BIT(3) ++#define DSM_DACCLKCTRL_CKE_BCLKRX_DIS 0 ++#define DSM_DACCLKCTRL_I2SRX_CKE_MASK BIT(4) ++#define DSM_DACCLKCTRL_I2SRX_CKE_EN BIT(4) ++#define DSM_DACCLKCTRL_I2SRX_CKE_DIS 0 ++#define DSM_DACCLKCTRL_DAC_CKE_MASK BIT(5) ++#define DSM_DACCLKCTRL_DAC_CKE_EN BIT(5) ++#define DSM_DACCLKCTRL_DAC_CKE_DIS 0 ++/* DACINT_DIV */ ++#define DSM_DACINT_DIV_INT_DIV_CON_MASK GENMASK(7, 0) ++#define DSM_DACINT_DIV_INT_DIV_CON(x) ((x) - 1) ++/* DACSCLKRXINT_DIV */ ++#define DSM_DACSCLKRXINT_DIV_SCKRXDIV_MASK GENMASK(7, 0) ++#define DSM_DACSCLKRXINT_DIV_SCKRXDIV(x) ((x) - 1) ++/* DACPWM_DIV */ ++#define DSM_DACPWM_DIV_AUDIO_PWM_DIV_MASK GENMASK(7, 0) ++#define DSM_DACPWM_DIV_AUDIO_PWM_DIV(x) ((x) - 1) ++/* DACPWM_CTRL */ ++#define DSM_DACPWM_CTRL_DITH_SEL_MASK GENMASK(2, 0) ++#define DSM_DACPWM_CTRL_DITH_SEL(x) (x) ++#define DSM_DACPWM_CTRL_PWM_EN_MASK BIT(3) ++#define DSM_DACPWM_CTRL_PWM_EN BIT(3) ++#define DSM_DACPWM_CTRL_PWM_DIS 0 ++#define DSM_DACPWM_CTRL_PWM_MODE_MASK GENMASK(5, 4) ++#define DSM_DACPWM_CTRL_PWM_MODE_1 (0x2 << 4) ++#define DSM_DACPWM_CTRL_PWM_MODE_0 (0x1 << 4) ++#define DSM_DACPWM_CTRL_PWM_MODE_DAC (0x0 << 4) ++#define DSM_DACPWM_CTRL_PWM_MODE_CKE_MASK BIT(6) ++#define DSM_DACPWM_CTRL_PWM_MODE_CKE_EN BIT(6) ++#define DSM_DACPWM_CTRL_PWM_MODE_CKE_DIS 0 ++/* DACCFG1 */ ++#define DSM_DACCFG1_DACSRT_MASK GENMASK(4, 2) ++#define DSM_DACCFG1_DACSRT(x) ((x) << 2) ++/* DACMUTE */ ++#define DSM_DACMUTE_DACMT_MASK BIT(0) ++#define DSM_DACMUTE_DACUNMT_MASK BIT(1) ++/* DACVOLL0 */ ++#define DSM_DACVOLL0_DACLV0_MASK GENMASK(7, 0) ++#define DSM_DACVOLL0_DACLV0(x) (x) ++/* DACVOLR0 */ ++#define DSM_DACVOLR0_DACRV0_MASK GENMASK(7, 0) ++#define DSM_DACVOLR0_DACRV0(x) (x) ++/* DACVOGP */ ++#define DSM_DACVOGP_VOLGPL0_MASK BIT(0) ++#define DSM_DACVOGP_VOLGPL0_POS BIT(0) ++#define DSM_DACVOGP_VOLGPL0_NEG 0 ++#define DSM_DACVOGP_VOLGPR0_MASK BIT(1) ++#define DSM_DACVOGP_VOLGPR0_POS BIT(1) ++#define DSM_DACVOGP_VOLGPR0_NEG 0 ++/* DACMIXCTRLL */ ++#define DSM_DACMIXCTRLL_MIXMODE_L0_MASK GENMASK(1, 0) ++#define DSM_DACMIXCTRLL_MIXMODE_L0_LR 2 ++#define DSM_DACMIXCTRLL_MIXMODE_L0_R 1 ++#define DSM_DACMIXCTRLL_MIXMODE_L0_L 0 ++/* DACMIXCTRLR */ ++#define DSM_DACMIXCTRLR_MIXMODE_R0_MASK GENMASK(1, 0) ++#define DSM_DACMIXCTRLR_MIXMODE_R0_LR 2 ++#define DSM_DACMIXCTRLR_MIXMODE_R0_L 1 ++#define DSM_DACMIXCTRLR_MIXMODE_R0_R 0 ++/* DACHPF */ ++#define DSM_DACHPF_HPFEN_L0R0_MASK BIT(0) ++#define DSM_DACHPF_HPFEN_L0R0_EN BIT(0) ++#define DSM_DACHPF_HPFCF_MASK GENMASK(5, 4) ++#define DSM_DACHPF_HPFCF_140HZ (0x3 << 4) ++#define DSM_DACHPF_HPFCF_120HZ (0x2 << 4) ++#define DSM_DACHPF_HPFCF_100HZ (0x1 << 4) ++#define DSM_DACHPF_HPFCF_80HZ (0x0 << 4) ++/* I2S_RXCR0 */ ++#define DSM_I2S_RXCR0_VDW_MASK GENMASK(4, 0) ++#define DSM_I2S_RXCR0_VDW(x) ((x) - 1) ++/* I2S_RXCR1 */ ++#define DSM_I2S_RXCR1_CEX_MASK BIT(4) ++#define DSM_I2S_RXCR1_CEX_EXCHANGE BIT(4) ++#define DSM_I2S_RXCR1_RCSR_MASK GENMASK(7, 6) ++#define DSM_I2S_RXCR1_RCSR_2CH (0x0 << 6) ++/* I2S_CKR0 */ ++#define DSM_I2S_CKR0_RSD_MASK GENMASK(3, 2) ++#define DSM_I2S_CKR0_RSD_64 (0 << 2) ++#define DSM_I2S_CKR0_RSD_128 (1 << 2) ++#define DSM_I2S_CKR0_RSD_256 (2 << 2) ++/* I2S_CKR1 */ ++#define DSM_I2S_CKR1_RLP_MASK BIT(1) ++#define DSM_I2S_CKR1_RLP_INVERTED BIT(1) ++#define DSM_I2S_CKR1_RLP_NORMAL 0 ++#define DSM_I2S_CKR1_CKP_MASK BIT(2) ++#define DSM_I2S_CKR1_CKP_INVERTED BIT(2) ++#define DSM_I2S_CKR1_CKP_NORMAL 0 ++#define DSM_I2S_CKR1_MSS_MASK BIT(3) ++#define DSM_I2S_CKR1_MSS_MASTER 0 ++/* I2S_XFER */ ++#define DSM_I2S_XFER_RXS_MASK BIT(1) ++#define DSM_I2S_XFER_RXS_START BIT(1) ++#define DSM_I2S_XFER_RXS_STOP 0 ++/* I2S_CLR */ ++#define DSM_I2S_CLR_RXC_MASK BIT(1) ++#define DSM_I2S_CLR_RXC_CLR BIT(1) ++ ++#endif +diff --git a/sound/soc/codecs/rv1106_codec.c b/sound/soc/codecs/rv1106_codec.c +new file mode 100644 +index 000000000..32d5acc0c +--- /dev/null ++++ b/sound/soc/codecs/rv1106_codec.c +@@ -0,0 +1,2332 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * rv1106_codec.c - Rockchip RV1106 SoC Codec Driver ++ * ++ * Copyright (C) 2022 Rockchip Electronics Co., Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * 6.18 port note: is a vendor-BSP-only header not ++ * present in mainline. Nothing in this file actually uses symbols from it ++ * (PERI_GRF_PERI_CON1 is defined locally below and the GRF is accessed via ++ * the generic syscon/regmap API), so the include is simply dropped. ++ * is replaced with , which is ++ * where gpiod_direction_output()/devm_gpiod_get_optional() actually live. ++ */ ++ ++#include "rv1106_codec.h" ++ ++#if defined(CONFIG_DEBUG_FS) ++#include ++#include ++#include ++#endif ++ ++#define CODEC_DRV_NAME "rv1106-acodec" ++ ++#define PERI_GRF_PERI_CON1 0x004 ++#define ACODEC_AD2DA_LOOP_MSK (1 << 23) ++#define ACODEC_AD2DA_LOOP_EN (1 << 7) ++#define ACODEC_AD2DA_LOOP_DIS (1 << 7) ++/* Control the i2s sdo sdi interface that connect to internal acodec ++ * 1: connect to internal acodec ++ * 0: connect to external acodec ++ */ ++#define ACODEC_MSK (1 << 22) ++#define ACODEC_EN (1 << 6) ++#define ACODEC_DIS (0 << 6) ++ ++#define LR(b, x, v) (((1 << b) & x) ? v : 0) ++#define L(x, v) LR(0, x, v) ++#define R(x, v) LR(1, x, v) ++ ++#define ADCL (1 << 0) ++#define ADCR (1 << 1) ++ ++#define NOT_SPECIFIED (-1) ++ ++enum soc_id_e { ++ SOC_RV1103 = 0x1103, ++ SOC_RV1106 = 0x1106, ++}; ++ ++enum adc_mode_e { ++ DIFF_ADCL = 0, /* Differential ADCL, the ADCR is not used */ ++ SING_ADCL, /* Single-end ADCL, the ADCR is not used */ ++ DIFF_ADCR, /* Differential ADCR, the ADCL is not used */ ++ SING_ADCR, /* Single-end ADCR, the ADCL is not used */ ++ SING_ADCLR, /* Single-end ADCL and ADCR */ ++ DIFF_ADCLR, /* Differential ADCL and ADCR (Not supported on rv1103 codec) */ ++ ADC_MODE_NUM, ++}; ++ ++struct rv1106_codec_priv { ++ const struct device *plat_dev; ++ struct device dev; ++ struct reset_control *reset; ++ struct regmap *regmap; ++ struct regmap *grf; ++ struct clk *pclk_acodec; ++ struct clk *mclk_acodec; ++ struct clk *mclk_cpu; ++ struct gpio_desc *pa_ctl_gpio; ++ struct snd_soc_component *component; ++ ++ enum adc_mode_e adc_mode; ++ enum soc_id_e soc_id; ++ ++ u32 pa_ctl_delay_ms; ++ u32 micbias_volt; ++ ++ /* AGC L/R Off/on */ ++ unsigned int agc_l; ++ unsigned int agc_r; ++ ++ /* AGC L/R Approximate Sample Rate */ ++ unsigned int agc_asr_l; ++ unsigned int agc_asr_r; ++ ++ /* ADC MIC Mute/Work */ ++ unsigned int mic_mute_l; ++ unsigned int mic_mute_r; ++ ++ /* DAC Control Manually */ ++ unsigned int dac_ctrl_manual; ++ ++ /* For the high pass filter */ ++ unsigned int hpf_cutoff; ++ ++ /* Specify init gains after codec startup */ ++ unsigned int init_mic_gain; ++ unsigned int init_alc_gain; ++ unsigned int init_lineout_gain; ++ ++ bool adc_enable; ++ bool dac_enable; ++ bool micbias_enable; ++ bool micbias_used; ++ ++#if defined(CONFIG_DEBUG_FS) ++ struct dentry *dbg_codec; ++#endif ++}; ++ ++static const DECLARE_TLV_DB_SCALE(rv1106_codec_alc_agc_gain_tlv, ++ -1800, 150, 2850); ++static const DECLARE_TLV_DB_SCALE(rv1106_codec_alc_agc_max_gain_tlv, ++ -1350, 600, 2850); ++static const DECLARE_TLV_DB_SCALE(rv1106_codec_alc_agc_min_gain_tlv, ++ -1800, 600, 2400); ++static const DECLARE_TLV_DB_SCALE(rv1106_codec_adc_alc_gain_tlv, ++ -900, 150, 3750); ++static const DECLARE_TLV_DB_SCALE(rv1106_codec_adc_dig_gain_tlv, ++ -9750, 50, 3000); ++static const DECLARE_TLV_DB_SCALE(rv1106_codec_dac_lineout_gain_tlv, ++ -3900, 150, 600); ++ ++static const DECLARE_TLV_DB_RANGE(rv1106_codec_adc_mic_gain_tlv, ++ 1, 1, TLV_DB_SCALE_ITEM(0, 0, 0), ++ 2, 2, TLV_DB_SCALE_ITEM(2000, 0, 0), ++ 3, 3, TLV_DB_SCALE_ITEM(1200, 0, 0), ++); ++ ++static const DECLARE_TLV_DB_RANGE(rv1106_codec_dac_hpmix_gain_tlv, ++ 1, 2, TLV_DB_SCALE_ITEM(0, 600, 0), ++); ++ ++static int check_micbias(int volt); ++ ++static int rv1106_codec_adc_enable(struct rv1106_codec_priv *rv1106); ++static int rv1106_codec_adc_disable(struct rv1106_codec_priv *rv1106); ++ ++static int rv1106_codec_micbias_enable(struct rv1106_codec_priv *rv1106, ++ int micbias_volt); ++static int rv1106_codec_hpmix_gain_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int rv1106_codec_hpmix_gain_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int rv1106_codec_micbias_disable(struct rv1106_codec_priv *rv1106); ++static int rv1106_codec_hpf_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int rv1106_codec_hpf_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int rv1106_codec_adc_mode_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int rv1106_codec_adc_mode_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int rv1106_codec_agc_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int rv1106_codec_agc_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int rv1106_codec_agc_asr_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int rv1106_codec_agc_asr_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int rv1106_codec_mic_mute_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int rv1106_codec_mic_mute_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int rv1106_codec_mic_gain_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int rv1106_codec_mic_gain_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int rv1106_codec_micbias_volts_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int rv1106_codec_micbias_volts_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int rv1106_codec_main_micbias_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int rv1106_codec_main_micbias_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int rv1106_codec_dac_ctrl_manual_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++static int rv1106_codec_dac_ctrl_manual_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol); ++ ++static const char *offon_text[2] = { ++ [0] = "Off", ++ [1] = "On", ++}; ++ ++static const char *noneoffon_text[3] = { ++ [0] = "None", ++ [1] = "Off", ++ [2] = "On", ++}; ++ ++static const char *mute_text[2] = { ++ [0] = "Work", ++ [1] = "Mute", ++}; ++ ++/* ADC MICBIAS Volt */ ++#define MICBIAS_VOLT_NUM 8 ++ ++#define MICBIAS_VREFx0_8 0 ++#define MICBIAS_VREFx0_825 1 ++#define MICBIAS_VREFx0_85 2 ++#define MICBIAS_VREFx0_875 3 ++#define MICBIAS_VREFx0_9 4 ++#define MICBIAS_VREFx0_925 5 ++#define MICBIAS_VREFx0_95 6 ++#define MICBIAS_VREFx0_975 7 ++ ++static const char *micbias_volts_enum_array[MICBIAS_VOLT_NUM] = { ++ [MICBIAS_VREFx0_8] = "VREFx0_8", ++ [MICBIAS_VREFx0_825] = "VREFx0_825", ++ [MICBIAS_VREFx0_85] = "VREFx0_85", ++ [MICBIAS_VREFx0_875] = "VREFx0_875", ++ [MICBIAS_VREFx0_9] = "VREFx0_9", ++ [MICBIAS_VREFx0_925] = "VREFx0_925", ++ [MICBIAS_VREFx0_95] = "VREFx0_95", ++ [MICBIAS_VREFx0_975] = "VREFx0_975", ++}; ++ ++static const char *adc_mode_enum_array[ADC_MODE_NUM] = { ++ [DIFF_ADCL] = "DiffadcL", ++ [SING_ADCL] = "SingadcL", ++ [DIFF_ADCR] = "DiffadcR", ++ [SING_ADCR] = "SingadcR", ++ [SING_ADCLR] = "SingadcLR", ++ [DIFF_ADCLR] = "DiffadcLR", ++}; ++ ++static const struct soc_enum rv1106_adc_mode_enum_array[] = { ++ SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(adc_mode_enum_array), adc_mode_enum_array), ++}; ++ ++static const struct soc_enum rv1106_micbias_volts_enum_array[] = { ++ SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(micbias_volts_enum_array), micbias_volts_enum_array), ++}; ++ ++/* ADC MICBIAS Main Switch */ ++static const struct soc_enum rv1106_main_micbias_enum_array[] = { ++ SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(offon_text), offon_text), ++}; ++ ++static const struct soc_enum rv1106_hpf_enum_array[] = { ++ SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(offon_text), offon_text), ++}; ++ ++/* ALC AGC Switch */ ++static const struct soc_enum rv1106_agc_enum_array[] = { ++ SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(offon_text), offon_text), ++ SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(offon_text), offon_text), ++}; ++ ++/* ADC MIC Mute/Work Switch */ ++static const struct soc_enum rv1106_mic_mute_enum_array[] = { ++ SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(mute_text), mute_text), ++ SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(mute_text), mute_text), ++}; ++ ++/* DAC Control Manually */ ++static const struct soc_enum rv1106_dac_pa_ctrl_maunal_enum_array[] = { ++ SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(noneoffon_text), noneoffon_text), ++}; ++ ++/* ALC AGC Approximate Sample Rate */ ++#define AGC_ASR_NUM 8 ++ ++#define AGC_ASR_96KHZ 0 ++#define AGC_ASR_48KHZ 1 ++#define AGC_ASR_44_1KHZ 2 ++#define AGC_ASR_32KHZ 3 ++#define AGC_ASR_24KHZ 4 ++#define AGC_ASR_16KHZ 5 ++#define AGC_ASR_12KHZ 6 ++#define AGC_ASR_8KHZ 7 ++ ++static const char *agc_asr_text[AGC_ASR_NUM] = { ++ [AGC_ASR_96KHZ] = "96KHz", ++ [AGC_ASR_48KHZ] = "48KHz", ++ [AGC_ASR_44_1KHZ] = "44.1KHz", ++ [AGC_ASR_32KHZ] = "32KHz", ++ [AGC_ASR_24KHZ] = "24KHz", ++ [AGC_ASR_16KHZ] = "16KHz", ++ [AGC_ASR_12KHZ] = "12KHz", ++ [AGC_ASR_8KHZ] = "8KHz", ++}; ++ ++static const struct soc_enum rv1106_agc_asr_enum_array[] = { ++ SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(agc_asr_text), agc_asr_text), ++ SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(agc_asr_text), agc_asr_text), ++}; ++ ++static const struct snd_kcontrol_new rv1106_codec_dapm_controls[] = { ++ /* ADC MIC */ ++ SOC_SINGLE_EXT_TLV("ADC MIC Left Gain", ++ ACODEC_ADC_ANA_CTL2, ++ ACODEC_ADC_L_MIC_GAIN_SFT, ++ ACODEC_ADC_MIC_GAIN_MAX, ++ 0, ++ rv1106_codec_mic_gain_get, ++ rv1106_codec_mic_gain_put, ++ rv1106_codec_adc_mic_gain_tlv), ++ SOC_SINGLE_EXT_TLV("ADC MIC Right Gain", ++ ACODEC_ADC_ANA_CTL2, ++ ACODEC_ADC_R_MIC_GAIN_SFT, ++ ACODEC_ADC_MIC_GAIN_MAX, ++ 0, ++ rv1106_codec_mic_gain_get, ++ rv1106_codec_mic_gain_put, ++ rv1106_codec_adc_mic_gain_tlv), ++ ++ /* ADC ALC */ ++ SOC_SINGLE_RANGE_TLV("ADC ALC Left Volume", ++ ACODEC_ADC_ANA_CTL4, ++ ACODEC_ADC_L_ALC_GAIN_SFT, ++ ACODEC_ADC_L_ALC_GAIN_MIN, ++ ACODEC_ADC_L_ALC_GAIN_MAX, ++ 0, rv1106_codec_adc_alc_gain_tlv), ++ SOC_SINGLE_RANGE_TLV("ADC ALC Right Volume", ++ ACODEC_ADC_ANA_CTL5, ++ ACODEC_ADC_R_ALC_GAIN_SFT, ++ ACODEC_ADC_R_ALC_GAIN_MIN, ++ ACODEC_ADC_R_ALC_GAIN_MAX, ++ 0, rv1106_codec_adc_alc_gain_tlv), ++ ++ /* ADC Digital Volume */ ++ SOC_SINGLE_RANGE_TLV("ADC Digital Left Volume", ++ ACODEC_ADC_L_DIG_VOL, ++ ACODEC_ADC_L_DIG_VOL_SFT, ++ ACODEC_ADC_L_DIG_VOL_MIN, ++ ACODEC_ADC_L_DIG_VOL_MAX, ++ 0, rv1106_codec_adc_dig_gain_tlv), ++ SOC_SINGLE_RANGE_TLV("ADC Digital Right Volume", ++ ACODEC_ADC_R_DIG_VOL, ++ ACODEC_ADC_R_DIG_VOL_SFT, ++ ACODEC_ADC_R_DIG_VOL_MIN, ++ ACODEC_ADC_R_DIG_VOL_MAX, ++ 0, rv1106_codec_adc_dig_gain_tlv), ++ ++ /* ADC High Pass Filter */ ++ SOC_ENUM_EXT("ADC HPF Cut-off", rv1106_hpf_enum_array[0], ++ rv1106_codec_hpf_get, rv1106_codec_hpf_put), ++ ++ /* ALC AGC Group */ ++ SOC_SINGLE_RANGE_TLV("ALC AGC Left Volume", ++ ACODEC_ADC_PGA_AGC_L_CTL3, ++ ACODEC_AGC_PGA_GAIN_SFT, ++ ACODEC_AGC_PGA_GAIN_MIN, ++ ACODEC_AGC_PGA_GAIN_MAX, ++ 0, rv1106_codec_alc_agc_gain_tlv), ++ SOC_SINGLE_RANGE_TLV("ALC AGC Right Volume", ++ ACODEC_ADC_PGA_AGC_R_CTL3, ++ ACODEC_AGC_PGA_GAIN_SFT, ++ ACODEC_AGC_PGA_GAIN_MIN, ++ ACODEC_AGC_PGA_GAIN_MAX, ++ 0, rv1106_codec_alc_agc_gain_tlv), ++ ++ /* ALC AGC MAX */ ++ SOC_SINGLE_RANGE_TLV("ALC AGC Left Max Volume", ++ ACODEC_ADC_PGA_AGC_L_CTL9, ++ ACODEC_AGC_MAX_GAIN_PGA_SFT, ++ ACODEC_AGC_MAX_GAIN_PGA_MIN, ++ ACODEC_AGC_MAX_GAIN_PGA_MAX, ++ 0, rv1106_codec_alc_agc_max_gain_tlv), ++ SOC_SINGLE_RANGE_TLV("ALC AGC Right Max Volume", ++ ACODEC_ADC_PGA_AGC_R_CTL9, ++ ACODEC_AGC_MAX_GAIN_PGA_SFT, ++ ACODEC_AGC_MAX_GAIN_PGA_MIN, ++ ACODEC_AGC_MAX_GAIN_PGA_MAX, ++ 0, rv1106_codec_alc_agc_max_gain_tlv), ++ ++ /* ALC AGC MIN */ ++ SOC_SINGLE_RANGE_TLV("ALC AGC Left Min Volume", ++ ACODEC_ADC_PGA_AGC_L_CTL9, ++ ACODEC_AGC_MIN_GAIN_PGA_SFT, ++ ACODEC_AGC_MIN_GAIN_PGA_MIN, ++ ACODEC_AGC_MIN_GAIN_PGA_MAX, ++ 0, rv1106_codec_alc_agc_min_gain_tlv), ++ SOC_SINGLE_RANGE_TLV("ALC AGC Right Min Volume", ++ ACODEC_ADC_PGA_AGC_R_CTL9, ++ ACODEC_AGC_MIN_GAIN_PGA_SFT, ++ ACODEC_AGC_MIN_GAIN_PGA_MIN, ++ ACODEC_AGC_MIN_GAIN_PGA_MAX, ++ 0, rv1106_codec_alc_agc_min_gain_tlv), ++ ++ /* ALC AGC Switch */ ++ SOC_ENUM_EXT("ALC AGC Left Switch", rv1106_agc_enum_array[0], ++ rv1106_codec_agc_get, rv1106_codec_agc_put), ++ SOC_ENUM_EXT("ALC AGC Right Switch", rv1106_agc_enum_array[1], ++ rv1106_codec_agc_get, rv1106_codec_agc_put), ++ ++ /* ALC AGC Approximate Sample Rate */ ++ SOC_ENUM_EXT("AGC Left Approximate Sample Rate", rv1106_agc_asr_enum_array[0], ++ rv1106_codec_agc_asr_get, rv1106_codec_agc_asr_put), ++ SOC_ENUM_EXT("AGC Right Approximate Sample Rate", rv1106_agc_asr_enum_array[1], ++ rv1106_codec_agc_asr_get, rv1106_codec_agc_asr_put), ++ ++ /* ADC Mode */ ++ SOC_ENUM_EXT("ADC Mode", rv1106_adc_mode_enum_array[0], ++ rv1106_codec_adc_mode_get, rv1106_codec_adc_mode_put), ++ ++ /* ADC MICBIAS Voltage */ ++ SOC_ENUM_EXT("ADC MICBIAS Voltage", rv1106_micbias_volts_enum_array[0], ++ rv1106_codec_micbias_volts_get, rv1106_codec_micbias_volts_put), ++ ++ /* ADC Main MICBIAS Switch */ ++ SOC_ENUM_EXT("ADC Main MICBIAS", rv1106_main_micbias_enum_array[0], ++ rv1106_codec_main_micbias_get, rv1106_codec_main_micbias_put), ++ ++ /* ADC MIC Mute/Work Switch */ ++ SOC_ENUM_EXT("ADC MIC Left Switch", rv1106_mic_mute_enum_array[0], ++ rv1106_codec_mic_mute_get, rv1106_codec_mic_mute_put), ++ SOC_ENUM_EXT("ADC MIC Right Switch", rv1106_mic_mute_enum_array[1], ++ rv1106_codec_mic_mute_get, rv1106_codec_mic_mute_put), ++ ++ /* DAC LINEOUT */ ++ SOC_SINGLE_RANGE_TLV("DAC LINEOUT Volume", ++ ACODEC_DAC_ANA_CTL2, ++ ACODEC_DAC_LINEOUT_GAIN_SFT, ++ ACODEC_DAC_LINEOUT_GAIN_MIN, ++ ACODEC_DAC_LINEOUT_GAIN_MAX, ++ 0, rv1106_codec_dac_lineout_gain_tlv), ++ ++ /* DAC HPMIX */ ++ SOC_SINGLE_EXT_TLV("DAC HPMIX Volume", ++ ACODEC_DAC_HPMIX_CTL, ++ ACODEC_DAC_HPMIX_GAIN_SFT, ++ ACODEC_DAC_HPMIX_GAIN_MAX, ++ 0, ++ rv1106_codec_hpmix_gain_get, ++ rv1106_codec_hpmix_gain_put, ++ rv1106_codec_dac_hpmix_gain_tlv), ++ ++ /* DAC Control Manually */ ++ SOC_ENUM_EXT("DAC Control Manually", rv1106_dac_pa_ctrl_maunal_enum_array[0], ++ rv1106_codec_dac_ctrl_manual_get, rv1106_codec_dac_ctrl_manual_put), ++}; ++ ++static unsigned int using_adc_lr(enum adc_mode_e adc_mode) ++{ ++ if (adc_mode >= SING_ADCLR && adc_mode <= DIFF_ADCLR) ++ return (ADCL | ADCR); ++ else if (adc_mode >= DIFF_ADCR && adc_mode <= SING_ADCR) ++ return ADCR; ++ else ++ return ADCL; ++} ++ ++static bool using_adc_diff(enum adc_mode_e adc_mode) ++{ ++ if (adc_mode == DIFF_ADCL || ++ adc_mode == DIFF_ADCR || ++ adc_mode == DIFF_ADCLR) ++ return true; ++ else ++ return false; ++} ++ ++static int check_adc_mode(struct rv1106_codec_priv *rv1106) ++{ ++ if (rv1106->soc_id == SOC_RV1103 && ++ (rv1106->adc_mode == DIFF_ADCLR || ++ rv1106->adc_mode == DIFF_ADCR)) { ++ dev_err(rv1106->plat_dev, ++ "%s: Differential mode rv1103 only supports 'DiffadcL'\n", __func__); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int rv1106_codec_adc_mode_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ ++ ucontrol->value.integer.value[0] = rv1106->adc_mode; ++ ++ return 0; ++} ++ ++static int rv1106_codec_adc_mode_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ unsigned int last_mode = rv1106->adc_mode; ++ ++ rv1106->adc_mode = ucontrol->value.integer.value[0]; ++ if (check_adc_mode(rv1106)) { ++ dev_err(rv1106->plat_dev, ++ "%s - something error checking ADC mode\n", __func__); ++ rv1106->adc_mode = last_mode; ++ return 0; ++ } ++ ++ return 0; ++} ++ ++static int rv1106_codec_agc_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; ++ ++ if (e->shift_l) ++ ucontrol->value.integer.value[0] = rv1106->agc_r; ++ else ++ ucontrol->value.integer.value[0] = rv1106->agc_l; ++ ++ return 0; ++} ++ ++static int rv1106_codec_agc_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; ++ unsigned int value = ucontrol->value.integer.value[0]; ++ ++ if (value) { ++ /* ALC AGC On */ ++ if (e->shift_l) { ++ /* ALC AGC Right On */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_PGA_AGC_R_CTL9, ++ ACODEC_AGC_FUNC_SEL_MSK, ++ ACODEC_AGC_FUNC_SEL_EN); ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_HPF_PGA_CTL, ++ ACODEC_ADC_R_PGA_MSK, ++ ACODEC_ADC_PGA_ALCR_EN); ++ ++ rv1106->agc_r = 1; ++ } else { ++ /* ALC AGC Left On */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_PGA_AGC_L_CTL9, ++ ACODEC_AGC_FUNC_SEL_MSK, ++ ACODEC_AGC_FUNC_SEL_EN); ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_HPF_PGA_CTL, ++ ACODEC_ADC_L_PGA_MSK, ++ ACODEC_ADC_PGA_ALCL_EN); ++ ++ rv1106->agc_l = 1; ++ } ++ } else { ++ /* ALC AGC Off */ ++ if (e->shift_l) { ++ /* ALC AGC Right Off */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_PGA_AGC_R_CTL9, ++ ACODEC_AGC_FUNC_SEL_MSK, ++ ACODEC_AGC_FUNC_SEL_DIS); ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_HPF_PGA_CTL, ++ ACODEC_ADC_R_PGA_MSK, ++ ACODEC_ADC_PGA_ALCR_DIS); ++ ++ rv1106->agc_r = 0; ++ } else { ++ /* ALC AGC Left Off */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_PGA_AGC_L_CTL9, ++ ACODEC_AGC_FUNC_SEL_MSK, ++ ACODEC_AGC_FUNC_SEL_DIS); ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_HPF_PGA_CTL, ++ ACODEC_ADC_L_PGA_MSK, ++ ACODEC_ADC_PGA_ALCL_DIS); ++ ++ rv1106->agc_l = 0; ++ } ++ } ++ ++ return 0; ++} ++ ++static int rv1106_codec_agc_asr_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; ++ unsigned int value; ++ ++ if (e->shift_l) { ++ regmap_read(rv1106->regmap, ACODEC_ADC_PGA_AGC_R_CTL4, &value); ++ rv1106->agc_asr_r = value >> ACODEC_AGC_APPROX_RATE_SFT; ++ ucontrol->value.integer.value[0] = rv1106->agc_asr_r; ++ } else { ++ regmap_read(rv1106->regmap, ACODEC_ADC_PGA_AGC_L_CTL4, &value); ++ rv1106->agc_asr_l = value >> ACODEC_AGC_APPROX_RATE_SFT; ++ ucontrol->value.integer.value[0] = rv1106->agc_asr_l; ++ } ++ ++ return 0; ++} ++ ++static int rv1106_codec_agc_asr_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; ++ unsigned int value; ++ ++ value = ucontrol->value.integer.value[0] << ACODEC_AGC_APPROX_RATE_SFT; ++ ++ if (e->shift_l) { ++ /* ALC AGC Right Approximate Sample Rate */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_PGA_AGC_R_CTL4, ++ ACODEC_AGC_APPROX_RATE_MSK, ++ value); ++ rv1106->agc_asr_r = ucontrol->value.integer.value[0]; ++ } else { ++ /* ALC AGC Left Approximate Sample Rate */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_PGA_AGC_L_CTL4, ++ ACODEC_AGC_APPROX_RATE_MSK, ++ value); ++ rv1106->agc_asr_l = ucontrol->value.integer.value[0]; ++ } ++ ++ return 0; ++} ++ ++static int rv1106_codec_mic_mute_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; ++ unsigned int value; ++ ++ if (e->shift_l) { ++ /* ADC MIC Right Mute/Work Infos */ ++ regmap_read(rv1106->regmap, ACODEC_ADC_BIST_MODE_SEL, &value); ++ rv1106->mic_mute_r = (value & ACODEC_ADC_R_BIST_SINE) >> ++ ACODEC_ADC_R_BIST_SFT; ++ ucontrol->value.integer.value[0] = rv1106->mic_mute_r; ++ } else { ++ /* ADC MIC Left Mute/Work Infos */ ++ regmap_read(rv1106->regmap, ACODEC_ADC_BIST_MODE_SEL, &value); ++ rv1106->mic_mute_l = (value & ACODEC_ADC_L_BIST_SINE) >> ++ ACODEC_ADC_L_BIST_SFT; ++ ucontrol->value.integer.value[0] = rv1106->mic_mute_l; ++ } ++ ++ return 0; ++} ++ ++static int rv1106_codec_mic_mute_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; ++ unsigned int value; ++ ++ if (e->shift_l) { ++ /* ADC MIC Right Mute/Work Configuration */ ++ value = ucontrol->value.integer.value[0] << ACODEC_ADC_R_BIST_SFT; ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_BIST_MODE_SEL, ++ ACODEC_ADC_R_BIST_SINE, ++ value); ++ rv1106->mic_mute_r = ucontrol->value.integer.value[0]; ++ } else { ++ /* ADC MIC Left Mute/Work Configuration */ ++ value = ucontrol->value.integer.value[0] << ACODEC_ADC_L_BIST_SFT; ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_BIST_MODE_SEL, ++ ACODEC_ADC_L_BIST_SINE, ++ value); ++ rv1106->mic_mute_l = ucontrol->value.integer.value[0]; ++ } ++ ++ return 0; ++} ++ ++static int rv1106_codec_micbias_volts_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ ++ ucontrol->value.integer.value[0] = rv1106->micbias_volt; ++ ++ return 0; ++} ++ ++static int rv1106_codec_micbias_volts_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ unsigned int volt = ucontrol->value.integer.value[0]; ++ int ret; ++ ++ ret = check_micbias(volt); ++ if (ret < 0) { ++ dev_err(rv1106->plat_dev, "Invalid micbias volt: %d\n", ++ volt); ++ return ret; ++ } ++ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL0, ++ ACODEC_ADC_LEVEL_RANGE_MICBIAS_MSK, ++ volt); ++ ++ rv1106->micbias_volt = volt; ++ ++ return 0; ++} ++ ++static int rv1106_codec_main_micbias_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ ++ ucontrol->value.integer.value[0] = rv1106->micbias_enable; ++ ++ return 0; ++} ++ ++static int rv1106_codec_main_micbias_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ unsigned int on = ucontrol->value.integer.value[0]; ++ ++ if (on) { ++ if (!rv1106->micbias_enable) ++ rv1106_codec_micbias_enable(rv1106, rv1106->micbias_volt); ++ } else { ++ if (rv1106->micbias_enable) ++ rv1106_codec_micbias_disable(rv1106); ++ } ++ ++ return 0; ++} ++ ++static int rv1106_codec_mic_gain_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ /* ++ * 6.18 port note: snd_soc_get_volsw_range()/snd_soc_put_volsw_range() ++ * no longer exist as separate mainline entry points -- the unified ++ * snd_soc_get_volsw()/snd_soc_put_volsw() already honour the xmin ++ * field of struct soc_mixer_control (populated via SOC_SINGLE_VALUE), ++ * so they are a drop-in replacement here. ++ */ ++ return snd_soc_get_volsw(kcontrol, ucontrol); ++} ++ ++static int rv1106_codec_mic_gain_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ unsigned int index = ucontrol->value.integer.value[0]; ++ ++ /* ++ * From the TRM, the gain of MIC Boost only supports: ++ * 0dB (index == 1) ++ * 20dB(index == 2) ++ * 12dB(index == 3) ++ */ ++ if ((index < ACODEC_ADC_MIC_GAIN_MIN) || ++ (index > ACODEC_ADC_MIC_GAIN_MAX)) { ++ dev_err(rv1106->plat_dev, "%s: invalid mic gain index: %d\n", ++ __func__, index); ++ return -EINVAL; ++ } ++ ++ return snd_soc_put_volsw(kcontrol, ucontrol); ++} ++ ++static int rv1106_codec_hpf_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ unsigned int value; ++ ++ regmap_read(rv1106->regmap, ACODEC_ADC_HPF_PGA_CTL, &value); ++ if (value & ACODEC_ADC_HPF_MSK) ++ rv1106->hpf_cutoff = 1; ++ else ++ rv1106->hpf_cutoff = 0; ++ ++ ucontrol->value.integer.value[0] = rv1106->hpf_cutoff; ++ ++ return 0; ++} ++ ++static int rv1106_codec_hpf_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ unsigned int value = ucontrol->value.integer.value[0]; ++ ++ if (value) { ++ /* Enable high pass filter for ADCs */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_HPF_PGA_CTL, ++ ACODEC_ADC_HPF_MSK, ++ ACODEC_ADC_HPF_EN); ++ } else { ++ /* Disable high pass filter for ADCs. */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_HPF_PGA_CTL, ++ ACODEC_ADC_HPF_MSK, ++ ACODEC_ADC_HPF_DIS); ++ } ++ ++ rv1106->hpf_cutoff = value; ++ ++ return 0; ++} ++ ++static void rv1106_codec_pa_ctrl(struct rv1106_codec_priv *rv1106, bool on) ++{ ++ if (!rv1106->pa_ctl_gpio) ++ return; ++ ++ if (on) { ++ gpiod_direction_output(rv1106->pa_ctl_gpio, on); ++ msleep(rv1106->pa_ctl_delay_ms); ++ } else { ++ gpiod_direction_output(rv1106->pa_ctl_gpio, on); ++ } ++} ++ ++static int rv1106_codec_reset(struct snd_soc_component *component) ++{ ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ ++ reset_control_assert(rv1106->reset); ++ usleep_range(10000, 11000); /* estimated value */ ++ reset_control_deassert(rv1106->reset); ++ ++ regmap_write(rv1106->regmap, ACODEC_GLB_CON, 0x00); ++ usleep_range(10000, 11000); /* estimated value */ ++ regmap_write(rv1106->regmap, ACODEC_GLB_CON, ++ ACODEC_CODEC_SYS_WORK | ++ ACODEC_CODEC_CORE_WORK); ++ ++ return 0; ++} ++ ++static int rv1106_set_bias_level(struct snd_soc_component *component, ++ enum snd_soc_bias_level level) ++{ ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ ++ switch (level) { ++ case SND_SOC_BIAS_ON: ++ break; ++ case SND_SOC_BIAS_PREPARE: ++ break; ++ case SND_SOC_BIAS_STANDBY: ++ regcache_cache_only(rv1106->regmap, false); ++ regcache_sync(rv1106->regmap); ++ break; ++ case SND_SOC_BIAS_OFF: ++ break; ++ } ++ ++ return 0; ++} ++ ++static int rv1106_set_dai_fmt(struct snd_soc_dai *codec_dai, ++ unsigned int fmt) ++{ ++ struct snd_soc_component *component = codec_dai->component; ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ unsigned int adc_aif1 = 0, adc_aif2 = 0, dac_aif1 = 0, dac_aif2 = 0; ++ ++ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { ++ case SND_SOC_DAIFMT_CBC_CFC: /* 6.18: was SND_SOC_DAIFMT_CBS_CFS */ ++ adc_aif2 |= ACODEC_ADC_IO_MODE_SLAVE; ++ adc_aif2 |= ACODEC_ADC_MODE_SLAVE; ++ dac_aif2 |= ACODEC_DAC_IO_MODE_SLAVE; ++ dac_aif2 |= ACODEC_DAC_MODE_SLAVE; ++ break; ++ case SND_SOC_DAIFMT_CBP_CFP: /* 6.18: was SND_SOC_DAIFMT_CBM_CFM */ ++ adc_aif2 |= ACODEC_ADC_IO_MODE_MASTER; ++ adc_aif2 |= ACODEC_ADC_MODE_MASTER; ++ dac_aif2 |= ACODEC_DAC_IO_MODE_MASTER; ++ dac_aif2 |= ACODEC_DAC_MODE_MASTER; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { ++ case SND_SOC_DAIFMT_DSP_A: ++ adc_aif1 |= ACODEC_ADC_I2S_MODE_PCM; ++ dac_aif1 |= ACODEC_DAC_I2S_MODE_PCM; ++ break; ++ case SND_SOC_DAIFMT_I2S: ++ adc_aif1 |= ACODEC_ADC_I2S_MODE_I2S; ++ dac_aif1 |= ACODEC_DAC_I2S_MODE_I2S; ++ break; ++ case SND_SOC_DAIFMT_RIGHT_J: ++ adc_aif1 |= ACODEC_ADC_I2S_MODE_RJ; ++ dac_aif1 |= ACODEC_DAC_I2S_MODE_RJ; ++ break; ++ case SND_SOC_DAIFMT_LEFT_J: ++ adc_aif1 |= ACODEC_ADC_I2S_MODE_LJ; ++ dac_aif1 |= ACODEC_DAC_I2S_MODE_LJ; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { ++ case SND_SOC_DAIFMT_NB_NF: ++ adc_aif1 |= ACODEC_ADC_I2S_LRC_POL_NORMAL; ++ adc_aif2 |= ACODEC_ADC_I2S_BIT_CLK_POL_NORMAL; ++ dac_aif1 |= ACODEC_DAC_I2S_LRC_POL_NORMAL; ++ dac_aif2 |= ACODEC_DAC_I2S_BIT_CLK_POL_NORMAL; ++ break; ++ case SND_SOC_DAIFMT_IB_IF: ++ adc_aif1 |= ACODEC_ADC_I2S_LRC_POL_REVERSAL; ++ adc_aif2 |= ACODEC_ADC_I2S_BIT_CLK_POL_REVERSAL; ++ dac_aif1 |= ACODEC_DAC_I2S_LRC_POL_REVERSAL; ++ dac_aif2 |= ACODEC_DAC_I2S_BIT_CLK_POL_REVERSAL; ++ break; ++ case SND_SOC_DAIFMT_IB_NF: ++ adc_aif1 |= ACODEC_ADC_I2S_LRC_POL_NORMAL; ++ adc_aif2 |= ACODEC_ADC_I2S_BIT_CLK_POL_REVERSAL; ++ dac_aif1 |= ACODEC_DAC_I2S_LRC_POL_NORMAL; ++ dac_aif2 |= ACODEC_DAC_I2S_BIT_CLK_POL_REVERSAL; ++ break; ++ case SND_SOC_DAIFMT_NB_IF: ++ adc_aif1 |= ACODEC_ADC_I2S_LRC_POL_REVERSAL; ++ adc_aif2 |= ACODEC_ADC_I2S_BIT_CLK_POL_NORMAL; ++ dac_aif1 |= ACODEC_DAC_I2S_LRC_POL_REVERSAL; ++ dac_aif2 |= ACODEC_DAC_I2S_BIT_CLK_POL_NORMAL; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_I2S_CTL0, ++ ACODEC_ADC_I2S_LRC_POL_MSK | ++ ACODEC_ADC_I2S_MODE_MSK, ++ adc_aif1); ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_I2S_CTL1, ++ ACODEC_ADC_IO_MODE_MSK | ++ ACODEC_ADC_MODE_MSK | ++ ACODEC_ADC_I2S_BIT_CLK_POL_MSK, ++ adc_aif2); ++ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_I2S_CTL0, ++ ACODEC_DAC_I2S_LRC_POL_MSK | ++ ACODEC_DAC_I2S_MODE_MSK, ++ dac_aif1); ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_I2S_CTL1, ++ ACODEC_DAC_IO_MODE_MSK | ++ ACODEC_DAC_MODE_MSK | ++ ACODEC_DAC_I2S_BIT_CLK_POL_MSK, ++ dac_aif2); ++ ++ return 0; ++} ++ ++static int rv1106_codec_dac_dig_config(struct rv1106_codec_priv *rv1106, ++ struct snd_pcm_hw_params *params) ++{ ++ unsigned int dac_aif1 = 0, dac_aif2 = 0; ++ ++ switch (params_format(params)) { ++ case SNDRV_PCM_FORMAT_S16_LE: ++ dac_aif1 |= ACODEC_DAC_I2S_VALID_LEN_16BITS; ++ break; ++ case SNDRV_PCM_FORMAT_S20_3LE: ++ dac_aif1 |= ACODEC_DAC_I2S_VALID_LEN_20BITS; ++ break; ++ case SNDRV_PCM_FORMAT_S24_LE: ++ dac_aif1 |= ACODEC_DAC_I2S_VALID_LEN_24BITS; ++ break; ++ case SNDRV_PCM_FORMAT_S32_LE: ++ dac_aif1 |= ACODEC_DAC_I2S_VALID_LEN_32BITS; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ dac_aif1 |= ACODEC_DAC_I2S_LR_NORMAL; ++ dac_aif2 |= ACODEC_DAC_I2S_WORK; ++ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_I2S_CTL0, ++ ACODEC_DAC_I2S_VALID_LEN_MSK | ++ ACODEC_DAC_I2S_LR_MSK, ++ dac_aif1); ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_I2S_CTL1, ++ ACODEC_DAC_I2S_MSK, ++ dac_aif2); ++ ++ return 0; ++} ++ ++static int rv1106_codec_adc_dig_config(struct rv1106_codec_priv *rv1106, ++ struct snd_pcm_hw_params *params) ++{ ++ unsigned int adc_aif1 = 0, adc_aif2 = 0; ++ ++ switch (params_format(params)) { ++ case SNDRV_PCM_FORMAT_S16_LE: ++ adc_aif1 |= ACODEC_ADC_I2S_VALID_LEN_16BITS; ++ break; ++ case SNDRV_PCM_FORMAT_S20_3LE: ++ adc_aif1 |= ACODEC_ADC_I2S_VALID_LEN_20BITS; ++ break; ++ case SNDRV_PCM_FORMAT_S24_LE: ++ adc_aif1 |= ACODEC_ADC_I2S_VALID_LEN_24BITS; ++ break; ++ case SNDRV_PCM_FORMAT_S32_LE: ++ adc_aif1 |= ACODEC_ADC_I2S_VALID_LEN_32BITS; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ adc_aif1 |= ACODEC_ADC_I2S_DATA_SEL_NORMAL; ++ adc_aif2 |= ACODEC_ADC_I2S_WORK; ++ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_I2S_CTL0, ++ ACODEC_ADC_I2S_VALID_LEN_MSK | ++ ACODEC_ADC_I2S_DATA_SEL_MSK, ++ adc_aif1); ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_I2S_CTL1, ++ ACODEC_ADC_I2S_MSK, ++ adc_aif2); ++ ++ return 0; ++} ++ ++static int rv1106_codec_dac_mute(struct rv1106_codec_priv *rv1106, int mute) ++{ ++ if (mute) { ++ /* Mute DAC HPMIX/LINEOUT */ ++ regmap_update_bits(rv1106->regmap, ++ ACODEC_DAC_ANA_CTL1, ++ ACODEC_DAC_L_LINEOUT_MUTE_MSK, ++ ACODEC_DAC_L_LINEOUT_MUTE); ++ regmap_update_bits(rv1106->regmap, ++ ACODEC_DAC_HPMIX_CTL, ++ ACODEC_DAC_HPMIX_MUTE_MSK, ++ ACODEC_DAC_HPMIX_MUTE); ++ rv1106_codec_pa_ctrl(rv1106, false); ++ } else { ++ /* Unmute DAC HPMIX/LINEOUT */ ++ regmap_update_bits(rv1106->regmap, ++ ACODEC_DAC_HPMIX_CTL, ++ ACODEC_DAC_HPMIX_MUTE_MSK, ++ ACODEC_DAC_HPMIX_WORK); ++ regmap_update_bits(rv1106->regmap, ++ ACODEC_DAC_ANA_CTL1, ++ ACODEC_DAC_L_LINEOUT_MUTE_MSK, ++ ACODEC_DAC_L_LINEOUT_WORK); ++ rv1106_codec_pa_ctrl(rv1106, true); ++ } ++ ++ return 0; ++} ++ ++static int rv1106_mute_stream(struct snd_soc_dai *dai, int mute, int stream) ++{ ++ struct snd_soc_component *component = dai->component; ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ ++ if (stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ if (rv1106->dac_ctrl_manual == 1) ++ mute = 1; /* Force DAC control off manually */ ++ else if (rv1106->dac_ctrl_manual == 2) ++ mute = 0; /* Force DAC control on manually */ ++ ++ rv1106_codec_dac_mute(rv1106, mute); ++ } ++ ++ return 0; ++} ++ ++static int rv1106_codec_dac_enable(struct rv1106_codec_priv *rv1106) ++{ ++ /* Step 01 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL0, ++ ACODEC_DAC_IBIAS_MSK, ++ ACODEC_DAC_IBIAS_EN); ++ udelay(20); ++ ++ /* Step 02 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL0, ++ ACODEC_DAC_L_REF_VOL_BUF_MSK, ++ ACODEC_DAC_L_REF_VOL_BUF_EN); ++ /* Waiting the stable reference voltage */ ++ usleep_range(1000, 2000); ++ ++ /* Step 03 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL1, ++ ACODEC_DAC_L_LINEOUT_MSK, ++ ACODEC_DAC_L_LINEOUT_EN); ++ udelay(20); ++ ++ /* Step 04 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL1, ++ ACODEC_DAC_L_LINEOUT_SIGNAL_MSK, ++ ACODEC_DAC_L_LINEOUT_SIGNAL_WORK); ++ udelay(20); ++ ++ /* Step 05 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_HPMIX_CTL, ++ ACODEC_DAC_HPMIX_MSK, ++ ACODEC_DAC_HPMIX_EN); ++ udelay(20); ++ ++ /* Step 06 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_HPMIX_CTL, ++ ACODEC_DAC_HPMIX_MDL_MSK, ++ ACODEC_DAC_HPMIX_MDL_WORK); ++ udelay(20); ++ ++ /* Step 07 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_HPMIX_CTL, ++ ACODEC_DAC_HPMIX_SEL_MSK, ++ ACODEC_DAC_HPMIX_I2S); ++ /* Waiting HPMIX be stable */ ++ usleep_range(18000, 20000); ++ ++ /* Step 08 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL0, ++ ACODEC_DAC_L_REF_VOL_MSK, ++ ACODEC_DAC_L_REF_VOL_EN); ++ udelay(20); ++ ++ /* Step 09 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL0, ++ ACODEC_DAC_L_CLK_MSK, ++ ACODEC_DAC_L_CLK_EN); ++ udelay(20); ++ ++ /* Step 10 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL0, ++ ACODEC_DAC_SRC_SIGNAL_MSK, ++ ACODEC_DAC_SRC_SIGNAL_EN); ++ udelay(20); ++ ++ /* Step 11 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL0, ++ ACODEC_DAC_L_SIGNAL_MSK, ++ ACODEC_DAC_L_SIGNAL_WORK); ++ udelay(20); ++ ++ /* Step 12 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_HPMIX_CTL, ++ ACODEC_DAC_HPMIX_MUTE_MSK, ++ ACODEC_DAC_HPMIX_WORK); ++ udelay(20); ++ ++ /* Step 13 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL1, ++ ACODEC_DAC_L_LINEOUT_MUTE_MSK, ++ ACODEC_DAC_L_LINEOUT_WORK); ++ ++ /* Skip setting gains that Step 14/15 */ ++ ++ rv1106->dac_enable = true; ++ return 0; ++} ++ ++static int rv1106_codec_dac_disable(struct rv1106_codec_priv *rv1106) ++{ ++ /* Step 01 */ ++ /* Skip cleaning the gain to GAIN_LINEOUTL */ ++ ++ /* Step 02 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL1, ++ ACODEC_DAC_L_LINEOUT_MUTE_MSK, ++ ACODEC_DAC_L_LINEOUT_MUTE); ++ ++ /* Step 03 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL1, ++ ACODEC_DAC_L_LINEOUT_SIGNAL_MSK, ++ ACODEC_DAC_L_LINEOUT_SIGNAL_INIT); ++ /* Step 04 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL1, ++ ACODEC_DAC_L_LINEOUT_MSK, ++ ACODEC_DAC_L_LINEOUT_DIS); ++ /* Step 05 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_HPMIX_CTL, ++ ACODEC_DAC_HPMIX_MUTE_MSK, ++ ACODEC_DAC_HPMIX_MUTE); ++ /* Step 06 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_HPMIX_CTL, ++ ACODEC_DAC_HPMIX_MDL_MSK, ++ ACODEC_DAC_HPMIX_MDL_INIT); ++ /* Step 07 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_HPMIX_CTL, ++ ACODEC_DAC_HPMIX_MSK, ++ ACODEC_DAC_HPMIX_DIS); ++ /* Step 08 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL0, ++ ACODEC_DAC_SRC_SIGNAL_MSK, ++ ACODEC_DAC_SRC_SIGNAL_DIS); ++ /* Step 09 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL0, ++ ACODEC_DAC_L_CLK_MSK, ++ ACODEC_DAC_L_CLK_DIS); ++ ++ /* Step 10 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL0, ++ ACODEC_DAC_L_REF_VOL_MSK, ++ ACODEC_DAC_L_REF_VOL_DIS); ++ /* Step 11 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL0, ++ ACODEC_DAC_L_REF_VOL_BUF_MSK, ++ ACODEC_DAC_L_REF_VOL_BUF_DIS); ++ ++ /* Step 12 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL0, ++ ACODEC_DAC_IBIAS_MSK, ++ ACODEC_DAC_IBIAS_DIS); ++ ++ /* Step 13 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL0, ++ ACODEC_DAC_L_SIGNAL_MSK, ++ ACODEC_DAC_L_SIGNAL_INIT); ++ ++ ++ rv1106->dac_enable = false; ++ ++ return 0; ++} ++ ++static int rv1106_codec_power_on(struct rv1106_codec_priv *rv1106) ++{ ++ /* vendor step 1 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL0, ++ ACODEC_DAC_L_REF_POP_SOUND_MSK, ++ ACODEC_DAC_L_REF_POP_SOUND_WORK); ++ /* vendor step 2. Charging */ ++ regmap_update_bits(rv1106->regmap, ACODEC_CURRENT_CHARGE_CTL, ++ ACODEC_ADC_CURRENT_CHARGE_MSK, ++ ACODEC_ADC_SEL_I(0xff)); ++ /* vendor step 3. Supply the power of the analog part. */ ++ /* vendor step 4 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL0, ++ ACODEC_ADC_REF_VOL_MSK, ACODEC_ADC_REF_VOL_EN); ++ /* vendor step 5. Wait charging completed */ ++ msleep(20); ++ /* vendor step 6 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_CURRENT_CHARGE_CTL, ++ ACODEC_ADC_CURRENT_CHARGE_MSK, ++ ACODEC_ADC_SEL_I(0x02)); ++ return 0; ++} ++ ++static int rv1106_codec_power_off(struct rv1106_codec_priv *rv1106) ++{ ++ /* ++ * 0. Keep the power on and disable the DAC and ADC path. ++ */ ++ ++ /* vendor step 1 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_CURRENT_CHARGE_CTL, ++ ACODEC_ADC_CURRENT_CHARGE_MSK, ++ ACODEC_ADC_SEL_I(0xff)); ++ /* vendor step 3 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL0, ++ ACODEC_ADC_REF_VOL_MSK, ++ ACODEC_ADC_REF_VOL_DIS); ++ /* vendor step 3. Wait until the voltage of VCM keep stable at AGND. */ ++ msleep(20); ++ ++ return 0; ++} ++ ++static int rv1106_codec_adc_i2s_route(struct rv1106_codec_priv *rv1106) ++{ ++ regmap_write(rv1106->grf, PERI_GRF_PERI_CON1, ++ ACODEC_MSK | ACODEC_EN); ++ return 0; ++} ++ ++static int check_micbias(int volt) ++{ ++ switch (volt) { ++ case ACODEC_ADC_MICBIAS_VOLT_0_975: ++ case ACODEC_ADC_MICBIAS_VOLT_0_95: ++ case ACODEC_ADC_MICBIAS_VOLT_0_925: ++ case ACODEC_ADC_MICBIAS_VOLT_0_9: ++ case ACODEC_ADC_MICBIAS_VOLT_0_875: ++ case ACODEC_ADC_MICBIAS_VOLT_0_85: ++ case ACODEC_ADC_MICBIAS_VOLT_0_825: ++ case ACODEC_ADC_MICBIAS_VOLT_0_8: ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++static int rv1106_codec_micbias_enable(struct rv1106_codec_priv *rv1106, ++ int volt) ++{ ++ int ret; ++ ++ if (!rv1106->micbias_used) ++ return 0; ++ ++ /* 0. Power up the ACODEC and keep the AVDDH stable */ ++ ++ /* vendor step 1 */ ++ ret = check_micbias(volt); ++ if (ret < 0) { ++ dev_err(rv1106->plat_dev, "This is an invalid volt: %d\n", ++ volt); ++ return ret; ++ } ++ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL0, ++ ACODEC_ADC_LEVEL_RANGE_MICBIAS_MSK, ++ volt); ++ ++ /* vendor step 4 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL0, ++ ACODEC_MICBIAS_MSK, ++ ACODEC_MICBIAS_WORK); ++ ++ /* waiting micbias stabled*/ ++ mdelay(20); ++ ++ rv1106->micbias_enable = true; ++ ++ return 0; ++} ++ ++static int rv1106_codec_micbias_disable(struct rv1106_codec_priv *rv1106) ++{ ++ if (!rv1106->micbias_used) ++ return 0; ++ ++ /* Step 0. Enable the MICBIAS and keep the Audio Codec stable */ ++ /* Do nothing */ ++ ++ /* vendor step 1 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL0, ++ ACODEC_MICBIAS_MSK, ++ ACODEC_MICBIAS_RST); ++ ++ rv1106->micbias_enable = false; ++ ++ return 0; ++} ++ ++static int rv1106_codec_hpmix_gain_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ /* 6.18 port note: see rv1106_codec_mic_gain_get() above. */ ++ return snd_soc_get_volsw(kcontrol, ucontrol); ++} ++ ++static int rv1106_codec_hpmix_gain_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ unsigned int index = ucontrol->value.integer.value[0]; ++ ++ if ((index < ACODEC_DAC_HPMIX_GAIN_MIN) || ++ (index > ACODEC_DAC_HPMIX_GAIN_MAX)) { ++ dev_err(rv1106->plat_dev, "%s: invalid gain index: %d\n", ++ __func__, index); ++ return -EINVAL; ++ } ++ ++ return snd_soc_put_volsw(kcontrol, ucontrol); ++} ++ ++static int rv1106_codec_dac_ctrl_manual_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ ++ ucontrol->value.integer.value[0] = rv1106->dac_ctrl_manual; ++ ++ return 0; ++} ++ ++static int rv1106_codec_dac_ctrl_manual_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ ++ rv1106->dac_ctrl_manual = ucontrol->value.integer.value[0]; ++ ++ if (rv1106->dac_ctrl_manual == 0) ++ return 0; ++ ++ if (rv1106->dac_ctrl_manual == 1) ++ rv1106_codec_dac_mute(rv1106, 1); /* Force DAC control off manually */ ++ else if (rv1106->dac_ctrl_manual == 2) ++ rv1106_codec_dac_mute(rv1106, 0); /* Force DAC control on manually */ ++ ++ return 0; ++} ++ ++static int rv1106_codec_adc_enable(struct rv1106_codec_priv *rv1106) ++{ ++ unsigned int lr = using_adc_lr(rv1106->adc_mode); ++ bool is_diff = using_adc_diff(rv1106->adc_mode); ++ unsigned int agc_func_en; ++ int ret; ++ ++ dev_dbg(rv1106->plat_dev, "%s: soc_id: 0x%x lr: %d is_diff: %d\n", ++ __func__, rv1106->soc_id, lr, is_diff); ++ ++ ret = check_adc_mode(rv1106); ++ if (ret < 0) { ++ dev_err(rv1106->plat_dev, ++ "%s - something error checking ADC mode: %d\n", ++ __func__, ret); ++ return ret; ++ } ++ ++ /* vendor step 00 */ ++ if (rv1106->soc_id == SOC_RV1103 && rv1106->adc_mode == DIFF_ADCL) { ++ /* The ADCL is differential mode on rv1103 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL3, ++ ACODEC_ADC_L_MODE_SEL_MSK, ++ ACODEC_ADC_L_FULL_DIFFER2); ++ } else if (rv1106->soc_id == SOC_RV1106 && is_diff) { ++ /* The differential mode on rv1106 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL3, ++ L(lr, ACODEC_ADC_L_MODE_SEL_MSK) | ++ R(lr, ACODEC_ADC_R_MODE_SEL_MSK), ++ L(lr, ACODEC_ADC_L_FULL_DIFFER) | ++ R(lr, ACODEC_ADC_R_FULL_DIFFER)); ++ } else { ++ /* The single-end mode */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL3, ++ L(lr, ACODEC_ADC_L_MODE_SEL_MSK) | ++ R(lr, ACODEC_ADC_R_MODE_SEL_MSK), ++ L(lr, ACODEC_ADC_L_SINGLE_END) | ++ R(lr, ACODEC_ADC_R_SINGLE_END)); ++ } ++ ++ /* vendor step 01 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL1, ++ L(lr, ACODEC_ADC_L_MIC_MSK) | ++ R(lr, ACODEC_ADC_R_MIC_MSK), ++ L(lr, ACODEC_ADC_L_MIC_WORK) | ++ R(lr, ACODEC_ADC_R_MIC_WORK)); ++ ++ /* vendor step 02 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL0, ++ ACODEC_ADC_IBIAS_MSK, ++ ACODEC_ADC_IBIAS_EN); ++ ++ /* vendor step 03 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL1, ++ L(lr, ACODEC_ADC_L_REF_VOL_BUF_MSK) | ++ R(lr, ACODEC_ADC_R_REF_VOL_BUF_MSK), ++ L(lr, ACODEC_ADC_L_REF_VOL_BUF_EN) | ++ R(lr, ACODEC_ADC_R_REF_VOL_BUF_EN)); ++ /* waiting VREF be stable */ ++ msleep(100); ++ ++ /* vendor step 04 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL3, ++ L(lr, ACODEC_MIC_L_MSK) | ++ R(lr, ACODEC_MIC_R_MSK), ++ L(lr, ACODEC_MIC_L_EN) | ++ R(lr, ACODEC_MIC_R_EN)); ++ ++ /* vendor step 05 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL3, ++ L(lr, ACODEC_ADC_L_MSK) | ++ R(lr, ACODEC_ADC_R_MSK), ++ L(lr, ACODEC_ADC_L_EN) | ++ R(lr, ACODEC_ADC_R_EN)); ++ ++ /* vendor step 06 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL6, ++ L(lr, ACODEC_ADC_L_CLK_MSK) | ++ R(lr, ACODEC_ADC_R_CLK_MSK), ++ L(lr, ACODEC_ADC_L_CLK_WORK) | ++ R(lr, ACODEC_ADC_R_CLK_WORK)); ++ ++ /* vendor step 07 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL6, ++ L(lr, ACODEC_ADC_L_WORK) | ++ R(lr, ACODEC_ADC_R_WORK), ++ L(lr, ACODEC_ADC_L_WORK) | ++ R(lr, ACODEC_ADC_R_WORK)); ++ ++ /* vendor step 08 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL6, ++ L(lr, ACODEC_ADC_L_SIGNAL_EN) | ++ R(lr, ACODEC_ADC_R_SIGNAL_EN), ++ L(lr, ACODEC_ADC_L_SIGNAL_EN) | ++ R(lr, ACODEC_ADC_R_SIGNAL_EN)); ++ ++ /* vendor step 09 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL6, ++ L(lr, ACODEC_ADC_L_ALC_MSK) | ++ R(lr, ACODEC_ADC_R_ALC_MSK), ++ L(lr, ACODEC_ADC_L_ALC_WORK) | ++ R(lr, ACODEC_ADC_R_ALC_WORK)); ++ ++ /* vendor step 10 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL1, ++ L(lr, ACODEC_ADC_L_MIC_SIGNAL_MSK) | ++ R(lr, ACODEC_ADC_R_MIC_SIGNAL_MSK), ++ L(lr, ACODEC_ADC_L_MIC_SIGNAL_WORK) | ++ R(lr, ACODEC_ADC_R_MIC_SIGNAL_WORK)); ++ ++ /* vendor step 11, configure GAIN_MICL/R by user */ ++ ++ /* vendor step 12, configure GAIN_ALCL/R by user */ ++ ++ /* vendor step 13 */ ++ regmap_read(rv1106->regmap, ACODEC_ADC_ANA_CTL1, &agc_func_en); ++ if (agc_func_en & ACODEC_AGC_FUNC_SEL_EN) { ++ regmap_update_bits(rv1106->regmap, ++ ACODEC_ADC_ANA_CTL1, ++ L(lr, ACODEC_ADC_L_ZERO_CROSS_DET_MSK) | ++ R(lr, ACODEC_ADC_R_ZERO_CROSS_DET_MSK), ++ L(lr, ACODEC_ADC_L_ZERO_CROSS_DET_EN) | ++ R(lr, ACODEC_ADC_R_ZERO_CROSS_DET_EN)); ++ } ++ ++ rv1106->adc_enable = true; ++ ++ return 0; ++} ++ ++static int rv1106_codec_adc_disable(struct rv1106_codec_priv *rv1106) ++{ ++ /* vendor step 1 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL1, ++ ACODEC_ADC_L_ZERO_CROSS_DET_MSK | ++ ACODEC_ADC_R_ZERO_CROSS_DET_MSK, ++ ACODEC_ADC_L_ZERO_CROSS_DET_DIS | ++ ACODEC_ADC_R_ZERO_CROSS_DET_DIS); ++ ++ /* vendor step 2 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL6, ++ ACODEC_ADC_L_WORK | ++ ACODEC_ADC_R_WORK, ++ ACODEC_ADC_L_INIT | ++ ACODEC_ADC_R_INIT); ++ ++ /* vendor step 3 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL6, ++ ACODEC_ADC_L_CLK_WORK | ++ ACODEC_ADC_R_CLK_WORK, ++ ACODEC_ADC_L_CLK_RST | ++ ACODEC_ADC_R_CLK_RST); ++ ++ /* vendor step 4 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL3, ++ ACODEC_ADC_L_MSK | ++ ACODEC_ADC_R_MSK, ++ ACODEC_ADC_L_DIS | ++ ACODEC_ADC_R_DIS); ++ ++ /* vendor step 5 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL3, ++ ACODEC_MIC_L_MSK | ++ ACODEC_MIC_R_MSK, ++ ACODEC_MIC_L_DIS | ++ ACODEC_MIC_R_DIS); ++ ++ /* vendor step 6 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL1, ++ ACODEC_ADC_L_REF_VOL_BUF_MSK | ++ ACODEC_ADC_R_REF_VOL_BUF_MSK, ++ ACODEC_ADC_L_REF_VOL_BUF_DIS | ++ ACODEC_ADC_R_REF_VOL_BUF_DIS); ++ ++ /* vendor step 7 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL0, ++ ACODEC_ADC_IBIAS_MSK, ++ ACODEC_ADC_IBIAS_DIS); ++ ++ /* vendor step 8 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL6, ++ ACODEC_ADC_L_SIGNAL_EN | ++ ACODEC_ADC_R_SIGNAL_EN, ++ ACODEC_ADC_L_SIGNAL_DIS | ++ ACODEC_ADC_R_SIGNAL_DIS); ++ ++ /* vendor step 9 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL6, ++ ACODEC_ADC_L_ALC_MSK | ++ ACODEC_ADC_R_ALC_MSK, ++ ACODEC_ADC_L_ALC_INIT | ++ ACODEC_ADC_R_ALC_INIT); ++ ++ /* vendor step 10 */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL1, ++ ACODEC_ADC_L_MIC_SIGNAL_MSK | ++ ACODEC_ADC_R_MIC_SIGNAL_MSK, ++ ACODEC_ADC_L_MIC_SIGNAL_INIT | ++ ACODEC_ADC_R_MIC_SIGNAL_INIT); ++ ++ rv1106->adc_enable = false; ++ ++ return 0; ++} ++ ++static int rv1106_codec_open_capture(struct rv1106_codec_priv *rv1106) ++{ ++ rv1106_codec_adc_enable(rv1106); ++ ++ return 0; ++} ++ ++static int rv1106_codec_close_capture(struct rv1106_codec_priv *rv1106) ++{ ++ rv1106_codec_adc_disable(rv1106); ++ return 0; ++} ++ ++static int rv1106_codec_open_playback(struct rv1106_codec_priv *rv1106) ++{ ++ rv1106_codec_dac_enable(rv1106); ++ return 0; ++} ++ ++static int rv1106_codec_close_playback(struct rv1106_codec_priv *rv1106) ++{ ++ rv1106_codec_dac_disable(rv1106); ++ return 0; ++} ++ ++static int rv1106_codec_dlp_down(struct rv1106_codec_priv *rv1106) ++{ ++ rv1106_codec_micbias_disable(rv1106); ++ rv1106_codec_power_off(rv1106); ++ return 0; ++} ++ ++static int rv1106_codec_dlp_up(struct rv1106_codec_priv *rv1106) ++{ ++ rv1106_codec_power_on(rv1106); ++ rv1106_codec_micbias_enable(rv1106, rv1106->micbias_volt); ++ return 0; ++} ++ ++static int rv1106_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, ++ struct snd_soc_dai *dai) ++{ ++ struct snd_soc_component *component = dai->component; ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ rv1106_codec_open_playback(rv1106); ++ rv1106_codec_dac_dig_config(rv1106, params); ++ } else { ++ rv1106_codec_open_capture(rv1106); ++ rv1106_codec_adc_dig_config(rv1106, params); ++ } ++ ++ return 0; ++} ++ ++static void rv1106_pcm_shutdown(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct snd_soc_component *component = dai->component; ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ rv1106_codec_close_playback(rv1106); ++ else ++ rv1106_codec_close_capture(rv1106); ++ ++ regcache_cache_only(rv1106->regmap, false); ++ regcache_sync(rv1106->regmap); ++} ++ ++static const struct snd_soc_dai_ops rv1106_dai_ops = { ++ .hw_params = rv1106_hw_params, ++ .set_fmt = rv1106_set_dai_fmt, ++ .mute_stream = rv1106_mute_stream, ++ .shutdown = rv1106_pcm_shutdown, ++}; ++ ++static struct snd_soc_dai_driver rv1106_dai[] = { ++ { ++ .name = "rv1106-hifi", ++ .id = ACODEC_HIFI, ++ .playback = { ++ .stream_name = "HiFi Playback", ++ .channels_min = 1, ++ .channels_max = 2, ++ .rates = SNDRV_PCM_RATE_8000_192000, ++ .formats = (SNDRV_PCM_FMTBIT_S16_LE | ++ SNDRV_PCM_FMTBIT_S20_3LE | ++ SNDRV_PCM_FMTBIT_S24_LE | ++ SNDRV_PCM_FMTBIT_S32_LE), ++ }, ++ .capture = { ++ .stream_name = "HiFi Capture", ++ .channels_min = 1, ++ .channels_max = 4, ++ .rates = SNDRV_PCM_RATE_8000_192000, ++ .formats = (SNDRV_PCM_FMTBIT_S16_LE | ++ SNDRV_PCM_FMTBIT_S20_3LE | ++ SNDRV_PCM_FMTBIT_S24_LE | ++ SNDRV_PCM_FMTBIT_S32_LE), ++ }, ++ .ops = &rv1106_dai_ops, ++ }, ++}; ++ ++static int rv1106_suspend(struct snd_soc_component *component) ++{ ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ ++ rv1106_codec_dlp_down(rv1106); ++ clk_disable_unprepare(rv1106->mclk_acodec); ++ clk_disable_unprepare(rv1106->pclk_acodec); ++ rv1106_set_bias_level(component, SND_SOC_BIAS_OFF); ++ return 0; ++} ++ ++static int rv1106_resume(struct snd_soc_component *component) ++{ ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ int ret = 0; ++ ++ ret = clk_prepare_enable(rv1106->pclk_acodec); ++ if (ret < 0) { ++ dev_err(rv1106->plat_dev, ++ "Failed to enable acodec pclk_acodec: %d\n", ret); ++ goto out; ++ } ++ ++ ret = clk_prepare_enable(rv1106->mclk_acodec); ++ if (ret < 0) { ++ dev_err(rv1106->plat_dev, ++ "Failed to enable acodec mclk_acodec: %d\n", ret); ++ goto out; ++ } ++ ++ rv1106_codec_dlp_up(rv1106); ++out: ++ rv1106_set_bias_level(component, SND_SOC_BIAS_STANDBY); ++ return ret; ++} ++ ++static int rv1106_codec_default_gains(struct rv1106_codec_priv *rv1106) ++{ ++ int gainl, gainr; ++ ++ /** ++ * MIC Gain ++ * 0dB (0x01) ++ * 20dB (0x02) ++ * 12dB (0x03) ++ */ ++ if (rv1106->init_mic_gain == NOT_SPECIFIED) { ++ gainl = ACODEC_ADC_L_MIC_GAIN_0DB; ++ gainr = ACODEC_ADC_R_MIC_GAIN_0DB; ++ } else { ++ gainl = ((rv1106->init_mic_gain >> 4) & 0x03) << ACODEC_ADC_L_MIC_GAIN_SFT; ++ gainr = ((rv1106->init_mic_gain >> 0) & 0x03) << ACODEC_ADC_R_MIC_GAIN_SFT; ++ } ++ ++ /* Prepare ADC gains */ ++ /* vendor step 12, set MIC PGA default gains */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL2, ++ ACODEC_ADC_L_MIC_GAIN_MSK | ++ ACODEC_ADC_R_MIC_GAIN_MSK, ++ gainl | gainr); ++ ++ /** ++ * ALC Gain (0dB: 0x06) ++ * min: -9.0dB (0x00) ++ * max: +37.5dB (0x1f) ++ * step: +1.5dB ++ */ ++ if (rv1106->init_alc_gain == NOT_SPECIFIED) { ++ gainl = ACODEC_ADC_L_ALC_GAIN_0DB; ++ gainr = ACODEC_ADC_R_ALC_GAIN_0DB; ++ } else { ++ gainl = ((rv1106->init_alc_gain >> 4) & 0x1f); ++ gainr = ((rv1106->init_alc_gain >> 0) & 0x1f); ++ } ++ /* vendor step 13, set ALC default gains */ ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL4, ++ ACODEC_ADC_L_ALC_GAIN_MSK, ++ gainl); ++ regmap_update_bits(rv1106->regmap, ACODEC_ADC_ANA_CTL5, ++ ACODEC_ADC_R_ALC_GAIN_MSK, ++ gainr); ++ ++ /* Prepare DAC gains */ ++ /* Step 19, set LINEOUT default gains */ ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_GAIN_SEL, ++ ACODEC_DAC_DIG_GAIN_MSK, ++ ACODEC_DAC_DIG_GAIN(ACODEC_DAC_DIG_0DB)); /* The calibrated fixed gain */ ++ /** ++ * Lineout Gain (0dB: 0x1a) ++ * min: -39.0dB (0x00) ++ * max: +6.0dB (0x1f) ++ * step: +1.5dB ++ */ ++ if (rv1106->init_lineout_gain == NOT_SPECIFIED) ++ gainl = ACODEC_DAC_LINEOUT_GAIN_0DB; ++ else ++ gainl = rv1106->init_lineout_gain & 0x1f; ++ regmap_update_bits(rv1106->regmap, ACODEC_DAC_ANA_CTL2, ++ ACODEC_DAC_LINEOUT_GAIN_MSK, ++ gainl); ++ return 0; ++} ++ ++static int rv1106_codec_check_micbias(struct rv1106_codec_priv *rv1106, ++ struct device_node *np) ++{ ++ /* Check internal of acodec micbias */ ++ rv1106->micbias_used = ++ of_property_read_bool(np, "acodec,micbias"); ++ ++ /* Using 0.9*AVDD by default */ ++ rv1106->micbias_volt = ACODEC_ADC_MICBIAS_VOLT_0_9; ++ ++ return 0; ++} ++ ++static int rv1106_codec_dapm_controls_prepare(struct rv1106_codec_priv *rv1106) ++{ ++ rv1106->adc_mode = DIFF_ADCL; ++ rv1106->dac_ctrl_manual = 0; ++ rv1106->hpf_cutoff = 0; ++ rv1106->agc_l = 0; ++ rv1106->agc_r = 0; ++ rv1106->agc_asr_l = AGC_ASR_96KHZ; ++ rv1106->agc_asr_r = AGC_ASR_96KHZ; ++ ++ return 0; ++} ++ ++static int rv1106_codec_prepare(struct rv1106_codec_priv *rv1106) ++{ ++ /* Clear registers for ADC and DAC */ ++ rv1106_codec_close_playback(rv1106); ++ rv1106_codec_close_capture(rv1106); ++ rv1106_codec_default_gains(rv1106); ++ rv1106_codec_dapm_controls_prepare(rv1106); ++ ++ return 0; ++} ++ ++static int rv1106_probe(struct snd_soc_component *component) ++{ ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ ++ rv1106->component = component; ++ rv1106_codec_reset(component); ++ rv1106_codec_dlp_up(rv1106); ++ rv1106_codec_prepare(rv1106); ++ ++ regcache_cache_only(rv1106->regmap, false); ++ regcache_sync(rv1106->regmap); ++ ++ return 0; ++} ++ ++static void rv1106_remove(struct snd_soc_component *component) ++{ ++ struct rv1106_codec_priv *rv1106 = snd_soc_component_get_drvdata(component); ++ ++ rv1106_codec_pa_ctrl(rv1106, false); ++ rv1106_codec_micbias_disable(rv1106); ++ rv1106_codec_power_off(rv1106); ++ regcache_cache_only(rv1106->regmap, false); ++ regcache_sync(rv1106->regmap); ++} ++ ++static const struct snd_soc_component_driver soc_codec_dev_rv1106 = { ++ .probe = rv1106_probe, ++ .remove = rv1106_remove, ++ .suspend = rv1106_suspend, ++ .resume = rv1106_resume, ++ .set_bias_level = rv1106_set_bias_level, ++ .controls = rv1106_codec_dapm_controls, ++ .num_controls = ARRAY_SIZE(rv1106_codec_dapm_controls), ++}; ++ ++/* Set the default value or reset value */ ++static const struct reg_default rv1106_codec_reg_defaults[] = { ++ { ACODEC_RESET_CTL, 0x03 }, ++}; ++ ++static bool rv1106_codec_write_read_reg(struct device *dev, unsigned int reg) ++{ ++ /* All registers can be read / write */ ++ return true; ++} ++ ++static bool rv1106_codec_volatile_reg(struct device *dev, unsigned int reg) ++{ ++ /* All registers can be read / write */ ++ return true; ++} ++ ++static const struct regmap_config rv1106_codec_regmap_config = { ++ .reg_bits = 32, ++ .reg_stride = 4, ++ .val_bits = 32, ++ .max_register = ACODEC_REG_MAX, ++ .writeable_reg = rv1106_codec_write_read_reg, ++ .readable_reg = rv1106_codec_write_read_reg, ++ .volatile_reg = rv1106_codec_volatile_reg, ++ .reg_defaults = rv1106_codec_reg_defaults, ++ .num_reg_defaults = ARRAY_SIZE(rv1106_codec_reg_defaults), ++ .cache_type = REGCACHE_FLAT, ++}; ++ ++static ssize_t adc_enable_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct rv1106_codec_priv *rv1106 = ++ container_of(dev, struct rv1106_codec_priv, dev); ++ ++ return sprintf(buf, "%d\n", rv1106->adc_enable); ++} ++ ++static ssize_t adc_enable_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct rv1106_codec_priv *rv1106 = ++ container_of(dev, struct rv1106_codec_priv, dev); ++ unsigned long enable; ++ int ret = kstrtoul(buf, 10, &enable); ++ ++ if (ret < 0) { ++ dev_err(dev, "Invalid enable: %ld, ret: %d\n", ++ enable, ret); ++ return -EINVAL; ++ } ++ ++ if (enable) ++ rv1106_codec_open_capture(rv1106); ++ else ++ rv1106_codec_close_capture(rv1106); ++ ++ dev_info(dev, "ADC enable: %ld\n", enable); ++ ++ return count; ++} ++ ++static ssize_t dac_enable_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct rv1106_codec_priv *rv1106 = ++ container_of(dev, struct rv1106_codec_priv, dev); ++ ++ return sprintf(buf, "%d\n", rv1106->dac_enable); ++} ++ ++static ssize_t dac_enable_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct rv1106_codec_priv *rv1106 = ++ container_of(dev, struct rv1106_codec_priv, dev); ++ unsigned long enable; ++ int ret = kstrtoul(buf, 10, &enable); ++ ++ if (ret < 0) { ++ dev_err(dev, "Invalid enable: %ld, ret: %d\n", ++ enable, ret); ++ return -EINVAL; ++ } ++ ++ if (enable) ++ rv1106_codec_open_playback(rv1106); ++ else ++ rv1106_codec_close_playback(rv1106); ++ ++ dev_info(dev, "DAC enable: %ld\n", enable); ++ ++ return count; ++} ++ ++static const struct device_attribute acodec_attrs[] = { ++ __ATTR_RW(adc_enable), ++ __ATTR_RW(dac_enable), ++}; ++ ++static void rv1106_codec_device_release(struct device *dev) ++{ ++ /* Do nothing */ ++} ++ ++static int rv1106_codec_sysfs_init(struct platform_device *pdev, ++ struct rv1106_codec_priv *rv1106) ++{ ++ struct device *dev = &rv1106->dev; ++ int i; ++ ++ dev->release = rv1106_codec_device_release; ++ dev->parent = &pdev->dev; ++ set_dev_node(dev, dev_to_node(&pdev->dev)); ++ dev_set_name(dev, "acodec_attrs"); ++ ++ if (device_register(dev)) { ++ dev_err(&pdev->dev, ++ "Register 'acodec_attrs' failed\n"); ++ dev->parent = NULL; ++ return -ENOMEM; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(acodec_attrs); i++) { ++ if (device_create_file(dev, &acodec_attrs[i])) { ++ dev_err(&pdev->dev, ++ "Create 'acodec_attrs' failed\n"); ++ device_unregister(dev); ++ return -ENOMEM; ++ } ++ } ++ ++ return 0; ++} ++ ++static int rv1106_codec_sysfs_exit(struct rv1106_codec_priv *rv1106) ++{ ++ struct device *dev = &rv1106->dev; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(acodec_attrs); i++) ++ device_remove_file(dev, &acodec_attrs[i]); ++ ++ device_unregister(dev); ++ return 0; ++} ++ ++#if defined(CONFIG_DEBUG_FS) ++static int rv1106_codec_debugfs_reg_show(struct seq_file *s, void *v) ++{ ++ struct rv1106_codec_priv *rv1106 = s->private; ++ unsigned int i; ++ unsigned int val; ++ ++ for (i = ACODEC_RESET_CTL; i <= ACODEC_ADC_PGA_AGC_R_CTL9; i += 4) { ++ regmap_read(rv1106->regmap, i, &val); ++ if (!(i % 16)) ++ seq_printf(s, "\nR:%04x: ", i); ++ seq_printf(s, "%08x ", val); ++ } ++ ++ seq_puts(s, "\n"); ++ ++ return 0; ++} ++ ++static ssize_t rv1106_codec_debugfs_reg_operate(struct file *file, ++ const char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct rv1106_codec_priv *rv1106 = ++ ((struct seq_file *)file->private_data)->private; ++ unsigned int reg, val; ++ char op; ++ char kbuf[32]; ++ int ret; ++ ++ if (count >= sizeof(kbuf)) ++ return -EINVAL; ++ ++ if (copy_from_user(kbuf, buf, count)) ++ return -EFAULT; ++ kbuf[count] = '\0'; ++ ++ ret = sscanf(kbuf, "%c,%x,%x", &op, ®, &val); ++ if (ret != 3) { ++ pr_err("sscanf failed: %d\n", ret); ++ return -EFAULT; ++ } ++ ++ if (op == 'w') { ++ pr_info("Write reg: 0x%04x with val: 0x%08x\n", reg, val); ++ regmap_write(rv1106->regmap, reg, val); ++ regcache_cache_only(rv1106->regmap, false); ++ regcache_sync(rv1106->regmap); ++ pr_info("Read back reg: 0x%04x with val: 0x%08x\n", reg, val); ++ } else if (op == 'r') { ++ regmap_read(rv1106->regmap, reg, &val); ++ pr_info("Read reg: 0x%04x with val: 0x%08x\n", reg, val); ++ } else { ++ pr_err("This is an invalid operation: %c\n", op); ++ } ++ ++ return count; ++} ++ ++static int rv1106_codec_debugfs_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, ++ rv1106_codec_debugfs_reg_show, inode->i_private); ++} ++ ++static const struct file_operations rv1106_codec_reg_debugfs_fops = { ++ .owner = THIS_MODULE, ++ .open = rv1106_codec_debugfs_open, ++ .read = seq_read, ++ .write = rv1106_codec_debugfs_reg_operate, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++#endif /* CONFIG_DEBUG_FS */ ++ ++static const struct of_device_id rv1106_codec_of_match[] = { ++ { .compatible = "rockchip,rv1103-codec", .data = (void *)SOC_RV1103}, ++ { .compatible = "rockchip,rv1106-codec", .data = (void *)SOC_RV1106}, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, rv1106_codec_of_match); ++ ++static int rv1106_platform_probe(struct platform_device *pdev) ++{ ++ const struct of_device_id *of_id; ++ struct device_node *np = pdev->dev.of_node; ++ struct rv1106_codec_priv *rv1106; ++ struct resource *res; ++ void __iomem *base; ++ int ret; ++ ++ rv1106 = devm_kzalloc(&pdev->dev, sizeof(*rv1106), GFP_KERNEL); ++ if (!rv1106) ++ return -ENOMEM; ++ ++ of_id = of_match_device(rv1106_codec_of_match, &pdev->dev); ++ if (of_id) ++ rv1106->soc_id = (enum soc_id_e)of_id->data; ++ dev_info(&pdev->dev, "current soc_id: rv%x\n", rv1106->soc_id); ++ ++ rv1106->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); ++ if (IS_ERR(rv1106->grf)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(rv1106->grf), ++ "Missing 'rockchip,grf' property\n"); ++ ++ rv1106->plat_dev = &pdev->dev; ++ rv1106->reset = devm_reset_control_get(&pdev->dev, "acodec-reset"); ++ if (IS_ERR(rv1106->reset)) { ++ ret = PTR_ERR(rv1106->reset); ++ if (ret != -ENOENT) ++ return ret; ++ ++ dev_dbg(&pdev->dev, "No reset control found\n"); ++ rv1106->reset = NULL; ++ } ++ ++ rv1106->init_mic_gain = NOT_SPECIFIED; ++ of_property_read_u32(np, "init-mic-gain", &rv1106->init_mic_gain); ++ ++ rv1106->init_alc_gain = NOT_SPECIFIED; ++ of_property_read_u32(np, "init-alc-gain", &rv1106->init_alc_gain); ++ ++ rv1106->init_lineout_gain = NOT_SPECIFIED; ++ of_property_read_u32(np, "init-lineout-gain", &rv1106->init_lineout_gain); ++ ++ rv1106->pa_ctl_gpio = devm_gpiod_get_optional(&pdev->dev, "pa-ctl", ++ GPIOD_OUT_LOW); ++ if (IS_ERR(rv1106->pa_ctl_gpio)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(rv1106->pa_ctl_gpio), ++ "Unable to claim gpio pa-ctl\n"); ++ ++ if (rv1106->pa_ctl_gpio) ++ of_property_read_u32(np, "pa-ctl-delay-ms", ++ &rv1106->pa_ctl_delay_ms); ++ ++ dev_info(&pdev->dev, "%s pa_ctl_gpio and pa_ctl_delay_ms: %d\n", ++ rv1106->pa_ctl_gpio ? "Use" : "No use", ++ rv1106->pa_ctl_delay_ms); ++ ++ /* Close external PA during startup. */ ++ rv1106_codec_pa_ctrl(rv1106, false); ++ ++ rv1106->pclk_acodec = devm_clk_get(&pdev->dev, "pclk_acodec"); ++ if (IS_ERR(rv1106->pclk_acodec)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(rv1106->pclk_acodec), ++ "Can't get acodec pclk_acodec\n"); ++ ++ rv1106->mclk_acodec = devm_clk_get(&pdev->dev, "mclk_acodec"); ++ if (IS_ERR(rv1106->mclk_acodec)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(rv1106->mclk_acodec), ++ "Can't get acodec mclk_acodec\n"); ++ ++ rv1106->mclk_cpu = devm_clk_get(&pdev->dev, "mclk_cpu"); ++ if (IS_ERR(rv1106->mclk_cpu)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(rv1106->mclk_cpu), ++ "Can't get acodec mclk_cpu\n"); ++ ++ ret = rv1106_codec_sysfs_init(pdev, rv1106); ++ if (ret < 0) ++ return dev_err_probe(&pdev->dev, ret, "Sysfs init failed\n"); ++ ++#if defined(CONFIG_DEBUG_FS) ++ rv1106->dbg_codec = debugfs_create_dir(CODEC_DRV_NAME, NULL); ++ if (IS_ERR(rv1106->dbg_codec)) ++ dev_err(&pdev->dev, ++ "Failed to create debugfs dir for rv1106!\n"); ++ else ++ debugfs_create_file("reg", 0644, rv1106->dbg_codec, ++ rv1106, &rv1106_codec_reg_debugfs_fops); ++#endif ++ ++ ret = clk_prepare_enable(rv1106->pclk_acodec); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "Failed to enable acodec pclk_acodec: %d\n", ret); ++ goto failed_2; ++ } ++ ++ ret = clk_prepare_enable(rv1106->mclk_acodec); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "Failed to enable acodec mclk_acodec: %d\n", ret); ++ goto failed_1; ++ } ++ ++ /** ++ * In PERICRU_PERICLKSEL_CON08, the mclk_acodec_t/rx_div are div 4 ++ * by default, we need to calibrate once, make the div is 1 and keep ++ * the rate of mclk_acodec is the same with mclk_i2s. ++ * ++ * FIXME: need to handle div dynamically if the DSMAUDIO is enabled. ++ */ ++ clk_set_rate(rv1106->mclk_acodec, clk_get_rate(rv1106->mclk_cpu)); ++ ++ rv1106_codec_check_micbias(rv1106, np); ++ ++ ret = rv1106_codec_adc_i2s_route(rv1106); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "Failed to route ADC to i2s: %d\n", ++ ret); ++ goto failed; ++ } ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(base)) { ++ ret = PTR_ERR(base); ++ dev_err(&pdev->dev, "Failed to ioremap resource\n"); ++ goto failed; ++ } ++ ++ rv1106->regmap = devm_regmap_init_mmio(&pdev->dev, base, ++ &rv1106_codec_regmap_config); ++ if (IS_ERR(rv1106->regmap)) { ++ ret = PTR_ERR(rv1106->regmap); ++ dev_err(&pdev->dev, "Failed to regmap mmio\n"); ++ goto failed; ++ } ++ ++ platform_set_drvdata(pdev, rv1106); ++ ret = devm_snd_soc_register_component(&pdev->dev, &soc_codec_dev_rv1106, ++ rv1106_dai, ARRAY_SIZE(rv1106_dai)); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); ++ goto failed; ++ } ++ ++ return ret; ++ ++failed: ++ clk_disable_unprepare(rv1106->mclk_acodec); ++failed_1: ++ clk_disable_unprepare(rv1106->pclk_acodec); ++failed_2: ++#if defined(CONFIG_DEBUG_FS) ++ debugfs_remove_recursive(rv1106->dbg_codec); ++#endif ++ rv1106_codec_sysfs_exit(rv1106); ++ ++ return ret; ++} ++ ++static void rv1106_platform_remove(struct platform_device *pdev) ++{ ++ struct rv1106_codec_priv *rv1106 = ++ (struct rv1106_codec_priv *)platform_get_drvdata(pdev); ++ ++ clk_disable_unprepare(rv1106->mclk_acodec); ++ clk_disable_unprepare(rv1106->pclk_acodec); ++#if defined(CONFIG_DEBUG_FS) ++ debugfs_remove_recursive(rv1106->dbg_codec); ++#endif ++ rv1106_codec_sysfs_exit(rv1106); ++} ++ ++static struct platform_driver rv1106_codec_driver = { ++ .driver = { ++ .name = CODEC_DRV_NAME, ++ .of_match_table = of_match_ptr(rv1106_codec_of_match), ++ }, ++ .probe = rv1106_platform_probe, ++ .remove = rv1106_platform_remove, ++}; ++module_platform_driver(rv1106_codec_driver); ++ ++MODULE_DESCRIPTION("ASoC RV1106 Codec Driver"); ++MODULE_AUTHOR("Jason Zhu "); ++MODULE_LICENSE("GPL"); +diff --git a/sound/soc/codecs/rv1106_codec.h b/sound/soc/codecs/rv1106_codec.h +new file mode 100644 +index 000000000..a62fd549f +--- /dev/null ++++ b/sound/soc/codecs/rv1106_codec.h +@@ -0,0 +1,753 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * rv1106_codec.h - Rockchip RV1106 SoC Codec Driver ++ * ++ * Copyright (C) 2022 Rockchip Electronics Co., Ltd. ++ */ ++ ++#ifndef __RV1106_CODEC_H__ ++#define __RV1106_CODEC_H__ ++ ++#define ACODEC_RESET_CTL 0x00 /* REG 0x00 */ ++#define ACODEC_GLB_CON ACODEC_RESET_CTL ++#define ACODEC_MUTE_DA_DITHER_CTL 0x04 /* REG 0x01 */ ++ ++/* ADC DIGITAL REGISTERS */ ++#define ACODEC_ADC_I2S_CTL0 0x08 /* REG 0x02 */ ++#define ACODEC_ADC_I2S_CTL1 0x0c /* REG 0x03 */ ++#define ACODEC_DAC_I2S_CTL0 0x10 /* REG 0x04 */ ++#define ACODEC_DAC_I2S_CTL1 0x14 /* REG 0x05 */ ++#define ACODEC_DAC_GAIN_SEL 0x18 /* REG 0x06 */ ++#define ACODEC_DAC_L_BIST_MODE_SEL 0x1c /* REG 0x07 */ ++#define ACODEC_ADC_L_DIG_VOL 0x20 /* REG 0x08 */ ++#define ACODEC_ADC_R_DIG_VOL 0x24 /* REG 0x09 */ ++#define ACODEC_ADC_HPF_PGA_CTL 0x28 /* REG 0x0a */ ++#define ACODEC_INIT_DELAY_CNT1 0x2c /* REG 0x0b */ ++#define ACODEC_INIT_DELAY_CNT2 0x30 /* REG 0x0c */ ++#define ACODEC_ADC_BIST_MODE_SEL 0x34 /* REG 0x0d */ ++#define ACODEC_DAC_CONFIG_OUTPUT 0x38 /* REG 0x0e */ ++#define ACODEC_LINEOUT_CTL 0x80 /* REG 0x20 */ ++#define ACODEC_CURRENT_CHARGE_CTL 0x84 /* REG 0x21 */ ++ ++#define ACODEC_ADC_ANA_CTL0 0x88 /* REG 0x22 */ ++#define ACODEC_ADC_ANA_CTL1 0x8c /* REG 0x23 */ ++#define ACODEC_ADC_ANA_CTL2 0x90 /* REG 0x24 */ ++#define ACODEC_ADC_ANA_CTL3 0x94 /* REG 0x25 */ ++#define ACODEC_ADC_ANA_CTL4 0x98 /* REG 0x26 */ ++#define ACODEC_ADC_ANA_CTL5 0x9c /* REG 0x27 */ ++#define ACODEC_ADC_ANA_CTL6 0xa0 /* REG 0x28 */ ++ ++#define ACODEC_DAC_ANA_CTL0 0xa4 /* REG 0x29 */ ++#define ACODEC_DAC_ANA_CTL1 0xa8 /* REG 0x2a */ ++#define ACODEC_DAC_ANA_CTL2 0xac /* REG 0x2b */ ++#define ACODEC_DAC_HPMIX_CTL 0xbc /* REG 0x2f */ ++ ++/* The description of the agc register for the left channel */ ++#define ACODEC_ADC_PGA_AGC_L_CTL0 0x100 /* REG 0x40 */ ++#define ACODEC_ADC_PGA_AGC_L_CTL1 0x104 /* REG 0x41 */ ++#define ACODEC_ADC_PGA_AGC_L_CTL2 0x108 /* REG 0x42 */ ++#define ACODEC_ADC_PGA_AGC_L_CTL3 0x10c /* REG 0x43 */ ++#define ACODEC_ADC_PGA_AGC_L_CTL4 0x110 /* REG 0x44 */ ++#define ACODEC_ADC_PGA_AGC_L_CTL5 0x114 /* REG 0x45 */ ++#define ACODEC_ADC_PGA_AGC_L_CTL6 0x118 /* REG 0x46 */ ++#define ACODEC_ADC_PGA_AGC_L_CTL7 0x11c /* REG 0x47 */ ++#define ACODEC_ADC_PGA_AGC_L_CTL8 0x120 /* REG 0x48 */ ++#define ACODEC_ADC_PGA_AGC_L_CTL9 0x124 /* REG 0x49 */ ++ ++/* The description of the agc register for the right channel */ ++#define ACODEC_ADC_PGA_AGC_R_CTL0 0x140 /* REG 0x50 */ ++#define ACODEC_ADC_PGA_AGC_R_CTL1 0x144 /* REG 0x51 */ ++#define ACODEC_ADC_PGA_AGC_R_CTL2 0x148 /* REG 0x52 */ ++#define ACODEC_ADC_PGA_AGC_R_CTL3 0x14c /* REG 0x53 */ ++#define ACODEC_ADC_PGA_AGC_R_CTL4 0x150 /* REG 0x54 */ ++#define ACODEC_ADC_PGA_AGC_R_CTL5 0x154 /* REG 0x55 */ ++#define ACODEC_ADC_PGA_AGC_R_CTL6 0x158 /* REG 0x56 */ ++#define ACODEC_ADC_PGA_AGC_R_CTL7 0x15c /* REG 0x57 */ ++#define ACODEC_ADC_PGA_AGC_R_CTL8 0x160 /* REG 0x58 */ ++#define ACODEC_ADC_PGA_AGC_R_CTL9 0x164 /* REG 0x59 */ ++ ++#define ACODEC_REG_MAX ACODEC_ADC_PGA_AGC_R_CTL9 ++ ++/* ACODEC_RESET_CTL */ ++#define ACODEC_CODEC_BIST_MSK (1 << 7) ++#define ACODEC_CODEC_BIST_WORK (1 << 7) ++#define ACODEC_CODEC_BIST_RST (0 << 7) ++#define ACODEC_CODEC_CORE_RST_MSK (1 << 1) ++#define ACODEC_CODEC_CORE_WORK (1 << 1) ++#define ACODEC_CODEC_CORE_RST (0 << 1) ++#define ACODEC_CODEC_SYS_RST_MSK (1 << 0) ++#define ACODEC_CODEC_SYS_WORK (1 << 0) ++#define ACODEC_CODEC_SYS_RST (0 << 0) ++ ++/* ACODEC_MUTE_DA_DITHER_CTL */ ++#define ACODEC_DAC_MUTE_MSK (1 << 7) ++#define ACODEC_DAC_MUTE_EN (1 << 7) ++#define ACODEC_DAC_MUTE_DIS (0 << 7) ++#define ACODEC_DITHER_LEVEL_SEL (1 << 3) ++#define ACODEC_DA_MSK (1 << 2) ++#define ACODEC_DA_EN (1 << 2) ++#define ACODEC_DA_DIS (0 << 2) ++#define ACODEC_DITHER_MSK (1 << 1) ++#define ACODEC_DITHER_EN (1 << 1) ++#define ACODEC_DITHER_DIS (0 << 1) ++#define ACODEC_DITHER_SIGN (1 << 0) ++ ++/* ACODEC_ADC_I2S_CTL0 */ ++#define ACODEC_ADC_I2S_LRC_POL_MSK (1 << 7) ++#define ACODEC_ADC_I2S_LRC_POL_REVERSAL (1 << 7) ++#define ACODEC_ADC_I2S_LRC_POL_NORMAL (0 << 7) ++#define ACODEC_ADC_I2S_VALID_LEN_SFT 5 ++#define ACODEC_ADC_I2S_VALID_LEN_MSK (0x3 << ACODEC_ADC_I2S_VALID_LEN_SFT) ++#define ACODEC_ADC_I2S_VALID_LEN_32BITS (0x3 << ACODEC_ADC_I2S_VALID_LEN_SFT) ++#define ACODEC_ADC_I2S_VALID_LEN_24BITS (0x2 << ACODEC_ADC_I2S_VALID_LEN_SFT) ++#define ACODEC_ADC_I2S_VALID_LEN_20BITS (0x1 << ACODEC_ADC_I2S_VALID_LEN_SFT) ++#define ACODEC_ADC_I2S_VALID_LEN_16BITS (0x0 << ACODEC_ADC_I2S_VALID_LEN_SFT) ++#define ACODEC_ADC_I2S_MODE_SFT 3 ++#define ACODEC_ADC_I2S_MODE_MSK (0x3 << ACODEC_ADC_I2S_MODE_SFT) ++#define ACODEC_ADC_I2S_MODE_PCM (0x3 << ACODEC_ADC_I2S_MODE_SFT) ++#define ACODEC_ADC_I2S_MODE_I2S (0x2 << ACODEC_ADC_I2S_MODE_SFT) ++#define ACODEC_ADC_I2S_MODE_LJ (0x1 << ACODEC_ADC_I2S_MODE_SFT) ++#define ACODEC_ADC_I2S_MODE_RJ (0x0 << ACODEC_ADC_I2S_MODE_SFT) ++#define ACODEC_ADC_I2S_SEL_DATA_MSK (1 << 2) ++#define ACODEC_ADC_I2S_SEL_ADC_DATA (1 << 2) ++#define ACODEC_ADC_I2S_SEL_ADCL_DACL_DATA (0 << 2) ++#define ACODEC_ADC_I2S_DATA_SEL 0 ++#define ACODEC_ADC_I2S_DATA_SEL_MSK (0x3 << ACODEC_ADC_I2S_DATA_SEL) ++#define ACODEC_ADC_I2S_DATA_SWAP (0x3 << ACODEC_ADC_I2S_DATA_SEL) ++#define ACODEC_ADC_I2S_DATA_SEL_LEFT (0x2 << ACODEC_ADC_I2S_DATA_SEL) ++#define ACODEC_ADC_I2S_DATA_SEL_RIGHT (0x1 << ACODEC_ADC_I2S_DATA_SEL) ++#define ACODEC_ADC_I2S_DATA_SEL_NORMAL (0x0 << ACODEC_ADC_I2S_DATA_SEL) ++ ++/* ACODEC_ADC_I2S_CTL1 */ ++#define ACODEC_DAC_IO_MODE_MSK (0x1 << 7) ++#define ACODEC_DAC_IO_MODE_MASTER (0x1 << 7) ++#define ACODEC_DAC_IO_MODE_SLAVE (0x0 << 7) ++#define ACODEC_DAC_MODE_MSK (0x1 << 6) ++#define ACODEC_DAC_MODE_MASTER (0x1 << 6) ++#define ACODEC_DAC_MODE_SLAVE (0x0 << 6) ++#define ACODEC_ADC_IO_MODE_MSK (0x1 << 5) ++#define ACODEC_ADC_IO_MODE_MASTER (0x1 << 5) ++#define ACODEC_ADC_IO_MODE_SLAVE (0x0 << 5) ++#define ACODEC_ADC_MODE_MSK (0x1 << 4) ++#define ACODEC_ADC_MODE_MASTER (0x1 << 4) ++#define ACODEC_ADC_MODE_SLAVE (0x0 << 4) ++#define ACODEC_ADC_I2S_FRAME_LEN_SFT 2 ++#define ACODEC_ADC_I2S_FRAME_LEN_MSK (0x3 << ACODEC_ADC_I2S_FRAME_LEN_SFT) ++#define ACODEC_ADC_I2S_FRAME_32BITS (0x3 << ACODEC_ADC_I2S_FRAME_LEN_SFT) ++#define ACODEC_ADC_I2S_FRAME_24BITS (0x1 << ACODEC_ADC_I2S_FRAME_LEN_SFT) ++#define ACODEC_ADC_I2S_MSK (0x1 << 1) ++#define ACODEC_ADC_I2S_WORK (0x1 << 1) ++#define ACODEC_ADC_I2S_RESET (0x0 << 1) ++#define ACODEC_ADC_I2S_BIT_CLK_POL_MSK (0x1 << 0) ++#define ACODEC_ADC_I2S_BIT_CLK_POL_REVERSAL (0x1 << 0) ++#define ACODEC_ADC_I2S_BIT_CLK_POL_NORMAL (0x0 << 0) ++ ++/* ACODEC_DAC_I2S_CTL0 */ ++#define ACODEC_DAC_I2S_LRC_POL_MSK (0x1 << 7) ++#define ACODEC_DAC_I2S_LRC_POL_REVERSAL (0x1 << 7) ++#define ACODEC_DAC_I2S_LRC_POL_NORMAL (0x0 << 7) ++#define ACODEC_DAC_I2S_VALID_LEN_SFT 5 ++#define ACODEC_DAC_I2S_VALID_LEN_MSK (0x3 << ACODEC_DAC_I2S_VALID_LEN_SFT) ++#define ACODEC_DAC_I2S_VALID_LEN_32BITS (0x3 << ACODEC_DAC_I2S_VALID_LEN_SFT) ++#define ACODEC_DAC_I2S_VALID_LEN_24BITS (0x2 << ACODEC_DAC_I2S_VALID_LEN_SFT) ++#define ACODEC_DAC_I2S_VALID_LEN_20BITS (0x1 << ACODEC_DAC_I2S_VALID_LEN_SFT) ++#define ACODEC_DAC_I2S_VALID_LEN_16BITS (0x0 << ACODEC_DAC_I2S_VALID_LEN_SFT) ++#define ACODEC_DAC_I2S_MODE_SFT 3 ++#define ACODEC_DAC_I2S_MODE_MSK (0x3 << ACODEC_DAC_I2S_MODE_SFT) ++#define ACODEC_DAC_I2S_MODE_PCM (0x3 << ACODEC_DAC_I2S_MODE_SFT) ++#define ACODEC_DAC_I2S_MODE_I2S (0x2 << ACODEC_DAC_I2S_MODE_SFT) ++#define ACODEC_DAC_I2S_MODE_LJ (0x1 << ACODEC_DAC_I2S_MODE_SFT) ++#define ACODEC_DAC_I2S_MODE_RJ (0x0 << ACODEC_DAC_I2S_MODE_SFT) ++#define ACODEC_DAC_I2S_LR_MSK (0x1 << 2) ++#define ACODEC_DAC_I2S_LR_SWAP (0x1 << 2) ++#define ACODEC_DAC_I2S_LR_NORMAL (0x0 << 2) ++ ++/* ACODEC_DAC_I2S_CTL1 */ ++#define ACODEC_DAC_DE_EMPHASIS_FILTER_SFT 4 ++#define ACODEC_DAC_DE_EMPHASIS_FILTER_MSK (0x3 << ACODEC_DAC_I2S_VALID_LEN_SFT) ++#define ACODEC_DAC_48_DE_EMPHASIS_FILTER (0x3 << ACODEC_DAC_I2S_VALID_LEN_SFT) ++#define ACODEC_DAC_441_DE_EMPHASIS_FILTER (0x2 << ACODEC_DAC_I2S_VALID_LEN_SFT) ++#define ACODEC_DAC_32_DE_EMPHASIS_FILTER (0x1 << ACODEC_DAC_I2S_VALID_LEN_SFT) ++#define ACODEC_DAC_NO_DE_EMPHASIS_FILTER (0x0 << ACODEC_DAC_I2S_VALID_LEN_SFT) ++#define ACODEC_DAC_I2S_FRAME_LEN_SFT 2 ++#define ACODEC_DAC_I2S_FRAME_LEN_MSK (0x3 << ACODEC_DAC_I2S_FRAME_LEN_SFT) ++#define ACODEC_DAC_I2S_FRAME_32BITS (0x3 << ACODEC_DAC_I2S_FRAME_LEN_SFT) ++#define ACODEC_DAC_I2S_FRAME_24BITS (0x2 << ACODEC_DAC_I2S_FRAME_LEN_SFT) ++#define ACODEC_DAC_I2S_FRAME_20BITS (0x1 << ACODEC_DAC_I2S_FRAME_LEN_SFT) ++#define ACODEC_DAC_I2S_FRAME_16BITS (0x0 << ACODEC_DAC_I2S_FRAME_LEN_SFT) ++#define ACODEC_DAC_I2S_MSK (0x1 << 1) ++#define ACODEC_DAC_I2S_WORK (0x1 << 1) ++#define ACODEC_DAC_I2S_RESET (0x0 << 1) ++#define ACODEC_DAC_I2S_BIT_CLK_POL_MSK (0x1 << 0) ++#define ACODEC_DAC_I2S_BIT_CLK_POL_REVERSAL (0x1 << 0) ++#define ACODEC_DAC_I2S_BIT_CLK_POL_NORMAL (0x0 << 0) ++ ++/* ACODEC_DAC_GAIN_SEL */ ++#define ACODEC_DAC_DIG_GAIN_SFT 0 ++#define ACODEC_DAC_DIG_GAIN_MSK (0xff << ACODEC_DAC_DIG_GAIN_SFT) ++#define ACODEC_DAC_DIG_GAIN(x) ((x) & ACODEC_DAC_DIG_GAIN_MSK) ++#define ACODEC_DAC_DIG_0DB 0xed ++ ++/* ACODEC_DAC_L_BIST_MODE_SEL */ ++#define ACODEC_DAC_L_CH_BIST_SFT 4 ++#define ACODEC_DAC_L_CH_BIST_MSK (0x3 << ACODEC_DAC_L_CH_BIST_SFT) ++#define ACODEC_DAC_L_CH_BIST_SINE (0x1 << ACODEC_DAC_L_CH_BIST_SFT) ++#define ACODEC_DAC_L_CH_BIST_LEFT (0x0 << ACODEC_DAC_L_CH_BIST_SFT) /* normal mode */ ++ ++/* ACODEC_ADC_L_DIG_VOL */ ++#define ACODEC_ADC_L_DIG_VOL_MAX 0xff ++#define ACODEC_ADC_L_DIG_VOL_MIN 0 ++#define ACODEC_ADC_L_DIG_VOL_SFT 0 ++#define ACODEC_ADC_L_DIG_VOL_MUTE 0 ++#define ACODEC_ADC_L_DIG_VOL_0DB 0xc3 ++ ++/* ACODEC_ADC_R_DIG_VOL */ ++#define ACODEC_ADC_R_DIG_VOL_MAX 0xff ++#define ACODEC_ADC_R_DIG_VOL_MIN 0 ++#define ACODEC_ADC_R_DIG_VOL_SFT 0 ++#define ACODEC_ADC_R_DIG_VOL_MUTE 0 ++#define ACODEC_ADC_R_DIG_VOL_0DB 0xc3 ++ ++/* ACODEC_ADC_HPF_PGA_CTL */ ++#define ACODEC_ADC_FILTER_MSK (1 << 7) ++#define ACODEC_ADC_FILTER_EN (1 << 7) ++#define ACODEC_ADC_FILTER_DIS (0 << 7) ++#define ACODEC_ADC_AGC_MSK (1 << 6) ++#define ACODEC_ADC_FILTER_OUTPUT (1 << 6) ++#define ACODEC_ADC_SINC_OUTPUT (0 << 6) ++#define ACODEC_ADC_L_PGA_MSK (1 << 5) ++#define ACODEC_ADC_PGA_ALCL_EN (1 << 5) ++#define ACODEC_ADC_PGA_ALCL_DIS (0 << 5) ++#define ACODEC_ADC_R_PGA_MSK (1 << 4) ++#define ACODEC_ADC_PGA_ALCR_EN (1 << 4) ++#define ACODEC_ADC_PGA_ALCR_DIS (0 << 4) ++#define ACODEC_ADC_HPF_SFT 2 ++#define ACODEC_ADC_HPF_MSK (3 << ACODEC_ADC_HPF_SFT) ++#define ACODEC_ADC_HPF_EN (3 << ACODEC_ADC_HPF_SFT) ++#define ACODEC_ADC_HPF_DIS (0 << ACODEC_ADC_HPF_SFT) ++#define ACODEC_ADC_R_DATA_POL_INV_MSK (1 << 1) ++#define ACODEC_ADC_R_DATA_POL_INV_EN (1 << 1) ++#define ACODEC_ADC_R_DATA_POL_INV_DIS (0 << 1) ++#define ACODEC_ADC_L_DATA_POL_INV_MSK (1 << 0) ++#define ACODEC_ADC_L_DATA_POL_INV_EN (1 << 0) ++#define ACODEC_ADC_L_DATA_POL_INV_DIS (0 << 0) ++ ++/* ACODEC_ADC_BIST_MODE_SEL */ ++#define ACODEC_ADC_R_BIST_SFT 6 ++#define ACODEC_ADC_R_BIST_MSK (0x3 << ACODEC_ADC_R_BIST_SFT) ++#define ACODEC_ADC_R_BIST_SINE (0x1 << ACODEC_ADC_R_BIST_SFT) ++#define ACODEC_ADC_BIST_RIGHT (0x0 << ACODEC_ADC_R_BIST_SFT) /* normal mode */ ++#define ACODEC_ADC_L_BIST_SFT 4 ++#define ACODEC_ADC_L_BIST_MSK (0x3 << ACODEC_ADC_L_BIST_SFT) ++#define ACODEC_ADC_L_BIST_SINE (0x1 << ACODEC_ADC_L_BIST_SFT) ++#define ACODEC_ADC_BIST_LEFT (0x0 << ACODEC_ADC_L_BIST_SFT) /* normal mode */ ++ ++/* ACODEC_LINEOUT_CTL */ ++#define ACODEC_DAC_LINEOUT_EN_SFT 7 ++#define ACODEC_DAC_LINEOUT_EN_WORK (0x1 << ACODEC_DAC_LINEOUT_EN_SFT) ++#define ACODEC_DAC_LINEOUT_EN_RST (0x0 << ACODEC_DAC_LINEOUT_EN_SFT) ++#define ACODEC_DAC_LINEOUT_INI_SFT 6 ++#define ACODEC_DAC_LINEOUT_INI_WORK (0x1 << ACODEC_DAC_LINEOUT_INI_SFT) ++#define ACODEC_DAC_LINEOUT_INI_RST (0x0 << ACODEC_DAC_LINEOUT_INI_SFT) ++#define ACODEC_DAC_IBIAS_SEL_SFT 0 ++#define ACODEC_DAC_IBIAS_SEL_MSK (0xf << ACODEC_DAC_IBIAS_SEL_SFT) ++ ++/* ACODEC_CURRENT_CHARGE_CTL */ ++#define ACODEC_ADC_CURRENT_CHARGE_SFT 0 ++#define ACODEC_ADC_CURRENT_CHARGE_MSK (0xff << ACODEC_ADC_CURRENT_CHARGE_SFT) ++/* ++ * 1: Choose the current I ++ * 0: Don't choose the current I ++ */ ++#define ACODEC_ADC_SEL_I(x) (x & 0xff) ++ ++/* ACODEC_ADC_ANA_CTL0 */ ++#define ACODEC_ADC_REF_VOL_MSK (0x1 << 5) ++#define ACODEC_ADC_REF_VOL_EN (0x1 << 5) ++#define ACODEC_ADC_REF_VOL_DIS (0x0 << 5) ++#define ACODEC_ADC_IBIAS_MSK (0x1 << 4) ++#define ACODEC_ADC_IBIAS_EN (0x1 << 4) ++#define ACODEC_ADC_IBIAS_DIS (0x0 << 4) ++#define ACODEC_MICBIAS_SFT 3 ++#define ACODEC_MICBIAS_MSK (0x1 << 3) ++#define ACODEC_MICBIAS_WORK (0x1 << 3) ++#define ACODEC_MICBIAS_RST (0x0 << 3) ++#define ACODEC_ADC_LEVEL_RANGE_MICBIAS_SFT 0 ++#define ACODEC_ADC_LEVEL_RANGE_MICBIAS_MSK (0x7 << ACODEC_ADC_LEVEL_RANGE_MICBIAS_SFT) ++#define ACODEC_ADC_MICBIAS_VOLT_0_975 (0x7 << ACODEC_ADC_LEVEL_RANGE_MICBIAS_SFT) ++#define ACODEC_ADC_MICBIAS_VOLT_0_95 (0x6 << ACODEC_ADC_LEVEL_RANGE_MICBIAS_SFT) ++#define ACODEC_ADC_MICBIAS_VOLT_0_925 (0x5 << ACODEC_ADC_LEVEL_RANGE_MICBIAS_SFT) ++#define ACODEC_ADC_MICBIAS_VOLT_0_9 (0x4 << ACODEC_ADC_LEVEL_RANGE_MICBIAS_SFT) ++#define ACODEC_ADC_MICBIAS_VOLT_0_875 (0x3 << ACODEC_ADC_LEVEL_RANGE_MICBIAS_SFT) ++#define ACODEC_ADC_MICBIAS_VOLT_0_85 (0x2 << ACODEC_ADC_LEVEL_RANGE_MICBIAS_SFT) ++#define ACODEC_ADC_MICBIAS_VOLT_0_825 (0x1 << ACODEC_ADC_LEVEL_RANGE_MICBIAS_SFT) ++#define ACODEC_ADC_MICBIAS_VOLT_0_8 (0x0 << ACODEC_ADC_LEVEL_RANGE_MICBIAS_SFT) ++ ++/* ACODEC_ADC_ANA_CTL1 */ ++#define ACODEC_ADC_L_MIC_MSK (0x1 << 7) ++#define ACODEC_ADC_L_MIC_WORK (0x1 << 7) ++#define ACODEC_ADC_L_MIC_MUTE (0x0 << 7) ++#define ACODEC_ADC_L_MIC_SIGNAL_MSK (0x1 << 6) ++#define ACODEC_ADC_L_MIC_SIGNAL_WORK (0x1 << 6) ++#define ACODEC_ADC_L_MIC_SIGNAL_INIT (0x0 << 6) ++#define ACODEC_ADC_L_REF_VOL_BUF_MSK (0x1 << 5) ++#define ACODEC_ADC_L_REF_VOL_BUF_EN (0x1 << 5) ++#define ACODEC_ADC_L_REF_VOL_BUF_DIS (0x0 << 5) ++#define ACODEC_ADC_L_ZERO_CROSS_DET_MSK (0x1 << 4) ++#define ACODEC_ADC_L_ZERO_CROSS_DET_EN (0x1 << 4) ++#define ACODEC_ADC_L_ZERO_CROSS_DET_DIS (0x0 << 4) ++#define ACODEC_ADC_R_MIC_MSK (0x1 << 3) ++#define ACODEC_ADC_R_MIC_WORK (0x1 << 3) ++#define ACODEC_ADC_R_MIC_MUTE (0x0 << 3) ++#define ACODEC_ADC_R_MIC_SIGNAL_MSK (0x1 << 2) ++#define ACODEC_ADC_R_MIC_SIGNAL_WORK (0x1 << 2) ++#define ACODEC_ADC_R_MIC_SIGNAL_INIT (0x0 << 2) ++#define ACODEC_ADC_R_REF_VOL_BUF_MSK (0x1 << 1) ++#define ACODEC_ADC_R_REF_VOL_BUF_EN (0x1 << 1) ++#define ACODEC_ADC_R_REF_VOL_BUF_DIS (0x0 << 1) ++#define ACODEC_ADC_R_ZERO_CROSS_DET_MSK (0x1 << 0) ++#define ACODEC_ADC_R_ZERO_CROSS_DET_EN (0x1 << 0) ++#define ACODEC_ADC_R_ZERO_CROSS_DET_DIS (0x0 << 0) ++ ++/* ACODEC_ADC_ANA_CTL2 */ ++#define ACODEC_ADC_MIC_GAIN_MAX 0x3 ++#define ACODEC_ADC_MIC_GAIN_MIN 0x1 ++#define ACODEC_ADC_L_MIC_GAIN_SFT 6 ++#define ACODEC_ADC_L_MIC_GAIN_MSK (0x3 << ACODEC_ADC_L_MIC_GAIN_SFT) ++#define ACODEC_ADC_L_MIC_GAIN_12DB (0x3 << ACODEC_ADC_L_MIC_GAIN_SFT) ++#define ACODEC_ADC_L_MIC_GAIN_20DB (0x2 << ACODEC_ADC_L_MIC_GAIN_SFT) ++#define ACODEC_ADC_L_MIC_GAIN_0DB (0x1 << ACODEC_ADC_L_MIC_GAIN_SFT) ++#define ACODEC_ADC_R_MIC_GAIN_SFT 4 ++#define ACODEC_ADC_R_MIC_GAIN_MSK (0x3 << ACODEC_ADC_R_MIC_GAIN_SFT) ++#define ACODEC_ADC_R_MIC_GAIN_12DB (0x3 << ACODEC_ADC_R_MIC_GAIN_SFT) ++#define ACODEC_ADC_R_MIC_GAIN_20DB (0x2 << ACODEC_ADC_R_MIC_GAIN_SFT) ++#define ACODEC_ADC_R_MIC_GAIN_0DB (0x1 << ACODEC_ADC_R_MIC_GAIN_SFT) ++#define ACODEC_ADC_IBIAS_SEL_SFT 0 ++#define ACODEC_ADC_IBIAS_SEL_MSK (0xf << ACODEC_ADC_IBIAS_SEL_SFT) ++ ++/* ACODEC_ADC_ANA_CTL3 */ ++#define ACODEC_ADC_L_MODE_SEL_SFT 6 ++#define ACODEC_ADC_L_MODE_SEL_MSK (0x3 << ACODEC_ADC_L_MODE_SEL_SFT) ++#define ACODEC_ADC_L_FULL_DIFFER2 (0x2 << ACODEC_ADC_L_MODE_SEL_SFT) /* Only used for rv1103 acodec */ ++#define ACODEC_ADC_L_SINGLE_END (0x1 << ACODEC_ADC_L_MODE_SEL_SFT) ++#define ACODEC_ADC_L_FULL_DIFFER (0x0 << ACODEC_ADC_L_MODE_SEL_SFT) ++#define ACODEC_ADC_L_MSK (0x1 << 5) ++#define ACODEC_ADC_L_EN (0x1 << 5) ++#define ACODEC_ADC_L_DIS (0x0 << 5) ++#define ACODEC_MIC_L_MSK (0x1 << 4) ++#define ACODEC_MIC_L_EN (0x1 << 4) ++#define ACODEC_MIC_L_DIS (0x0 << 4) ++#define ACODEC_ADC_R_MODE_SEL_SFT 2 ++#define ACODEC_ADC_R_MODE_SEL_MSK (0x3 << ACODEC_ADC_R_MODE_SEL_SFT) ++#define ACODEC_ADC_R_SINGLE_END (0x1 << ACODEC_ADC_R_MODE_SEL_SFT) ++#define ACODEC_ADC_R_FULL_DIFFER (0x0 << ACODEC_ADC_R_MODE_SEL_SFT) ++#define ACODEC_ADC_R_MSK (0x1 << 1) ++#define ACODEC_ADC_R_EN (0x1 << 1) ++#define ACODEC_ADC_R_DIS (0x0 << 1) ++#define ACODEC_MIC_R_MSK (0x1 << 0) ++#define ACODEC_MIC_R_EN (0x1 << 0) ++#define ACODEC_MIC_R_DIS (0x0 << 0) ++ ++/* ACODEC_ADC_ANA_CTL4 */ ++#define ACODEC_ADC_L_ALC_GAIN_MAX 0x1f ++#define ACODEC_ADC_L_ALC_GAIN_MIN 0 ++#define ACODEC_ADC_L_ALC_GAIN_SFT 0 ++#define ACODEC_ADC_L_ALC_GAIN_MSK (0x1f << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_PDB_37_5 (0x1f << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_PDB_36 (0x1e << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_PDB_34_5 (0x1d << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_PDB_33 (0x1c << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_PDB_31_5 (0x1b << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_PDB_30 (0x1a << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_PDB_28_5 (0x19 << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_PDB_27 (0x18 << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_PDB_25_5 (0x17 << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_PDB_24 (0x16 << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_PDB_22_5 (0x15 << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_PDB_21 (0x14 << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_PDB_19_5 (0x13 << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_PDB_18 (0x12 << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_PDB_16_5 (0x11 << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_PDB_15 (0x10 << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_PDB_13_5 (0x0f << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_PDB_12 (0x0e << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_PDB_10_5 (0x0d << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_PDB_9 (0x0c << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_PDB_7_5 (0x0b << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_PDB_6 (0x0a << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_PDB_4_5 (0x09 << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_PDB_3 (0x08 << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_PDB_1_5 (0x07 << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_0DB (0x06 << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_NDB_1_5 (0x05 << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_NDB_3 (0x04 << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_NDB_4_5 (0x03 << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_NDB_6 (0x02 << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_NDB_7_5 (0x01 << ACODEC_ADC_L_ALC_GAIN_SFT) ++#define ACODEC_ADC_L_ALC_GAIN_NDB_9 (0x00 << ACODEC_ADC_L_ALC_GAIN_SFT) ++ ++/* ACODEC_ADC_ANA_CTL5 */ ++#define ACODEC_ADC_R_ALC_GAIN_MAX 0x1f ++#define ACODEC_ADC_R_ALC_GAIN_MIN 0 ++#define ACODEC_ADC_R_ALC_GAIN_SFT 0 ++#define ACODEC_ADC_R_ALC_GAIN_MSK (0x1f << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_PDB_37_5 (0x1f << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_PDB_36 (0x1e << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_PDB_34_5 (0x1d << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_PDB_33 (0x1c << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_PDB_31_5 (0x1b << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_PDB_30 (0x1a << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_PDB_28_5 (0x19 << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_PDB_27 (0x18 << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_PDB_25_5 (0x17 << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_PDB_24 (0x16 << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_PDB_22_5 (0x15 << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_PDB_21 (0x14 << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_PDB_19_5 (0x13 << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_PDB_18 (0x12 << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_PDB_16_5 (0x11 << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_PDB_15 (0x10 << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_PDB_13_5 (0x0f << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_PDB_12 (0x0e << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_PDB_10_5 (0x0d << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_PDB_9 (0x0c << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_PDB_7_5 (0x0b << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_PDB_6 (0x0a << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_PDB_4_5 (0x09 << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_PDB_3 (0x08 << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_PDB_1_5 (0x07 << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_0DB (0x06 << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_NDB_1_5 (0x05 << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_NDB_3 (0x04 << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_NDB_4_5 (0x03 << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_NDB_6 (0x02 << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_NDB_7_5 (0x01 << ACODEC_ADC_R_ALC_GAIN_SFT) ++#define ACODEC_ADC_R_ALC_GAIN_NDB_9 (0x00 << ACODEC_ADC_R_ALC_GAIN_SFT) ++ ++/* ACODEC_ADC_ANA_CTL6 */ ++#define ACODEC_ADC_L_ALC_MSK (0x1 << 7) ++#define ACODEC_ADC_L_ALC_WORK (0x1 << 7) ++#define ACODEC_ADC_L_ALC_INIT (0x0 << 7) ++#define ACODEC_ADC_L_CLK_MSK (0x1 << 6) ++#define ACODEC_ADC_L_CLK_WORK (0x1 << 6) ++#define ACODEC_ADC_L_CLK_RST (0x0 << 6) ++#define ACODEC_ADC_L_WORK (0x1 << 5) ++#define ACODEC_ADC_L_INIT (0x0 << 5) ++#define ACODEC_ADC_L_SIGNAL_EN (0x1 << 4) ++#define ACODEC_ADC_L_SIGNAL_DIS (0x0 << 4) ++#define ACODEC_ADC_R_ALC_MSK (0x1 << 3) ++#define ACODEC_ADC_R_ALC_WORK (0x1 << 3) ++#define ACODEC_ADC_R_ALC_INIT (0x0 << 3) ++#define ACODEC_ADC_R_CLK_MSK (0x1 << 2) ++#define ACODEC_ADC_R_CLK_WORK (0x1 << 2) ++#define ACODEC_ADC_R_CLK_RST (0x0 << 2) ++#define ACODEC_ADC_R_WORK (0x1 << 1) ++#define ACODEC_ADC_R_INIT (0x0 << 1) ++#define ACODEC_ADC_R_SIGNAL_EN (0x1 << 0) ++#define ACODEC_ADC_R_SIGNAL_DIS (0x0 << 0) ++ ++/* ACODEC_DAC_ANA_CTL0 */ ++#define ACODEC_DAC_IBIAS_MSK (0x1 << 7) ++#define ACODEC_DAC_IBIAS_EN (0x1 << 7) ++#define ACODEC_DAC_IBIAS_DIS (0x0 << 7) ++#define ACODEC_DAC_L_REF_VOL_BUF_MSK (0x1 << 6) ++#define ACODEC_DAC_L_REF_VOL_BUF_EN (0x1 << 6) ++#define ACODEC_DAC_L_REF_VOL_BUF_DIS (0x0 << 6) ++#define ACODEC_DAC_L_REF_POP_SOUND_MSK (0x3 << 4) ++#define ACODEC_DAC_L_REF_POP_SOUND_WORK (0x2 << 4) ++#define ACODEC_DAC_L_REF_POP_SOUND_INIT (0x1 << 4) ++#define ACODEC_DAC_L_REF_POP_SOUND_DIS (0x0 << 4) ++#define ACODEC_DAC_L_REF_VOL_MSK (0x1 << 3) ++#define ACODEC_DAC_L_REF_VOL_EN (0x1 << 3) ++#define ACODEC_DAC_L_REF_VOL_DIS (0x0 << 3) ++#define ACODEC_DAC_L_CLK_MSK (0x1 << 2) ++#define ACODEC_DAC_L_CLK_EN (0x1 << 2) ++#define ACODEC_DAC_L_CLK_DIS (0x0 << 2) ++#define ACODEC_DAC_SRC_SIGNAL_MSK (0x1 << 1) ++#define ACODEC_DAC_SRC_SIGNAL_EN (0x1 << 1) ++#define ACODEC_DAC_SRC_SIGNAL_DIS (0x0 << 1) ++#define ACODEC_DAC_L_SIGNAL_MSK (0x1 << 0) ++#define ACODEC_DAC_L_SIGNAL_WORK (0x1 << 0) ++#define ACODEC_DAC_L_SIGNAL_INIT (0x0 << 0) ++ ++/* ACODEC_DAC_ANA_CTL1 */ ++#define ACODEC_DAC_L_LINEOUT_MUTE_MSK (0x1 << 6) ++#define ACODEC_DAC_L_LINEOUT_MUTE (0x0 << 6) ++#define ACODEC_DAC_L_LINEOUT_WORK (0x1 << 6) ++#define ACODEC_DAC_L_LINEOUT_SIGNAL_MSK (0x1 << 5) ++#define ACODEC_DAC_L_LINEOUT_SIGNAL_WORK (0x1 << 5) ++#define ACODEC_DAC_L_LINEOUT_SIGNAL_INIT (0x0 << 5) ++#define ACODEC_DAC_L_LINEOUT_MSK (0x1 << 4) ++#define ACODEC_DAC_L_LINEOUT_EN (0x1 << 4) ++#define ACODEC_DAC_L_LINEOUT_DIS (0x0 << 4) ++#define ACODEC_DAC_DRV_STRENGTH_SFT 0 ++#define ACODEC_DAC_DRV_STRENGTH_MSK (0xf << ACODEC_DAC_DRV_STRENGTH_SFT) ++#define ACODEC_DAC_DRV_STRENGTH_20_4 (0x8 << ACODEC_DAC_DRV_STRENGTH_SFT) ++#define ACODEC_DAC_DRV_STRENGTH_22_7 (0x7 << ACODEC_DAC_DRV_STRENGTH_SFT) ++#define ACODEC_DAC_DRV_STRENGTH_25_7 (0x6 << ACODEC_DAC_DRV_STRENGTH_SFT) ++#define ACODEC_DAC_DRV_STRENGTH_29_7 (0x5 << ACODEC_DAC_DRV_STRENGTH_SFT) ++#define ACODEC_DAC_DRV_STRENGTH_35_5 (0x4 << ACODEC_DAC_DRV_STRENGTH_SFT) ++#define ACODEC_DAC_DRV_STRENGTH_44_2 (0x3 << ACODEC_DAC_DRV_STRENGTH_SFT) ++#define ACODEC_DAC_DRV_STRENGTH_60_1 (0x2 << ACODEC_DAC_DRV_STRENGTH_SFT) ++#define ACODEC_DAC_DRV_STRENGTH_100 (0x1 << ACODEC_DAC_DRV_STRENGTH_SFT) ++ ++/* ACODEC_DAC_ANA_CTL2 */ ++#define ACODEC_DAC_LINEOUT_GAIN_MAX 0x1e ++#define ACODEC_DAC_LINEOUT_GAIN_MIN 0 ++#define ACODEC_DAC_LINEOUT_GAIN_SFT 0 ++#define ACODEC_DAC_LINEOUT_GAIN_MSK (0x1f << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_PDB_6_0 (0x1f << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_PDB_6 (0x1e << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_PDB_4_5 (0x1d << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_PDB_3 (0x1c << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_PDB_1_5 (0x1b << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_0DB (0x1a << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_NDB_1_5 (0x19 << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_NDB_3 (0x18 << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_NDB_4_5 (0x17 << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_NDB_6 (0x16 << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_NDB_7_5 (0x15 << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_NDB_9 (0x14 << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_NDB_10_5 (0x13 << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_NDB_12 (0x12 << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_NDB_13_5 (0x11 << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_NDB_15 (0x10 << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_NDB_16_5 (0x0f << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_NDB_18 (0x0e << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_NDB_19_5 (0x0d << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_NDB_21 (0x0c << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_NDB_22_5 (0x0b << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_NDB_24 (0x0a << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_NDB_25_5 (0x09 << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_NDB_27 (0x08 << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_NDB_28_5 (0x07 << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_NDB_30 (0x06 << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_NDB_31_5 (0x05 << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_NDB_33 (0x04 << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_NDB_34_5 (0x03 << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_NDB_36 (0x02 << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_NDB_37_5 (0x01 << ACODEC_DAC_LINEOUT_GAIN_SFT) ++#define ACODEC_DAC_LINEOUT_GAIN_NDB_39 (0x00 << ACODEC_DAC_LINEOUT_GAIN_SFT) ++ ++/* ACODEC_DAC_HPMIX_CTL */ ++#define ACODEC_DAC_HPMIX_MSK (0x1 << 7) ++#define ACODEC_DAC_HPMIX_EN (0x1 << 7) ++#define ACODEC_DAC_HPMIX_DIS (0x0 << 7) ++#define ACODEC_DAC_HPMIX_GAIN_SFT 5 ++#define ACODEC_DAC_HPMIX_GAIN_MAX 2 ++#define ACODEC_DAC_HPMIX_GAIN_MIN 1 ++#define ACODEC_DAC_HPMIX_GAIN_MSK (0x3 << ACODEC_DAC_HPMIX_GAIN_SFT) ++#define ACODEC_DAC_HPMIX_GAIN_6DB (0x2 << ACODEC_DAC_HPMIX_GAIN_SFT) ++#define ACODEC_DAC_HPMIX_GAIN_0DB (0x1 << ACODEC_DAC_HPMIX_GAIN_SFT) ++#define ACODEC_DAC_HPMIX_MDL_MSK (0x1 << 4) ++#define ACODEC_DAC_HPMIX_MDL_WORK (0x1 << 4) ++#define ACODEC_DAC_HPMIX_MDL_INIT (0x0 << 4) ++#define ACODEC_DAC_HPMIX_MUTE_MSK (0x1 << 3) ++#define ACODEC_DAC_HPMIX_WORK (0x1 << 3) ++#define ACODEC_DAC_HPMIX_MUTE (0x0 << 3) ++#define ACODEC_DAC_HPMIX_SEL_SFT 0 ++#define ACODEC_DAC_HPMIX_SEL_MSK (0x7 << ACODEC_DAC_HPMIX_SEL_SFT) ++#define ACODEC_DAC_HPMIX_ADCR (0x4 << ACODEC_DAC_HPMIX_SEL_SFT) ++#define ACODEC_DAC_HPMIX_ADCL (0x2 << ACODEC_DAC_HPMIX_SEL_SFT) ++#define ACODEC_DAC_HPMIX_I2S (0x1 << ACODEC_DAC_HPMIX_SEL_SFT) ++ ++/* ACODEC_ADC_PGA_AGC_L_CTL0 */ ++#define ACODEC_GAIN_ATTACK_MSK (1 << 6) ++#define ACODEC_GAIN_ATTACK_JACK (1 << 6) ++#define ACODEC_GAIN_ATTACK_NORMAL (0 << 6) ++#define ACODEC_CTRL_GEN_SFT 4 ++#define ACODEC_CTRL_GEN_MSK (0x3 << ACODEC_ALC_CTRL_GEN_SFT) ++#define ACODEC_CTRL_GEN_JACK3 (0x3 << ACODEC_ALC_CTRL_GEN_SFT) ++#define ACODEC_CTRL_GEN_JACK2 (0x2 << ACODEC_ALC_CTRL_GEN_SFT) ++#define ACODEC_CTRL_GEN_JACK1 (0x1 << ACODEC_ALC_CTRL_GEN_SFT) ++#define ACODEC_CTRL_GEN_NORMAL (0x0 << ACODEC_ALC_CTRL_GEN_SFT) ++#define ACODEC_AGC_HOLD_TIME_SFT 0 ++#define ACODEC_AGC_HOLD_TIME_MSK (0xf << ACODEC_AGC_HOLD_TIME_SFT) ++#define ACODEC_AGC_HOLD_TIME_1S (0xa << ACODEC_AGC_HOLD_TIME_SFT) ++#define ACODEC_AGC_HOLD_TIME_512MS (0x9 << ACODEC_AGC_HOLD_TIME_SFT) ++#define ACODEC_AGC_HOLD_TIME_256MS (0x8 << ACODEC_AGC_HOLD_TIME_SFT) ++#define ACODEC_AGC_HOLD_TIME_128MS (0x7 << ACODEC_AGC_HOLD_TIME_SFT) ++#define ACODEC_AGC_HOLD_TIME_64MS (0x6 << ACODEC_AGC_HOLD_TIME_SFT) ++#define ACODEC_AGC_HOLD_TIME_32MS (0x5 << ACODEC_AGC_HOLD_TIME_SFT) ++#define ACODEC_AGC_HOLD_TIME_16MS (0x4 << ACODEC_AGC_HOLD_TIME_SFT) ++#define ACODEC_AGC_HOLD_TIME_8MS (0x3 << ACODEC_AGC_HOLD_TIME_SFT) ++#define ACODEC_AGC_HOLD_TIME_4MS (0x2 << ACODEC_AGC_HOLD_TIME_SFT) ++#define ACODEC_AGC_HOLD_TIME_2MS (0x1 << ACODEC_AGC_HOLD_TIME_SFT) ++#define ACODEC_AGC_HOLD_TIME_0MS (0x0 << ACODEC_AGC_HOLD_TIME_SFT) ++ ++/* ACODEC_ADC_PGA_AGC_L_CTL1 */ ++#define ACODEC_AGC_DECAY_TIME_SFT 4 ++/* Normal mode (reg_agc_mode = 0) */ ++#define ACODEC_AGC_DECAY_NORMAL_MSK (0xf << ACODEC_AGC_DECAY_TIME_SFT) ++#define ACODEC_AGC_DECAY_NORMAL_512MS (0xa << ACODEC_AGC_DECAY_TIME_SFT) ++#define ACODEC_AGC_DECAY_NORMAL_256MS (0x9 << ACODEC_AGC_DECAY_TIME_SFT) ++#define ACODEC_AGC_DECAY_NORMAL_128MS (0x8 << ACODEC_AGC_DECAY_TIME_SFT) ++#define ACODEC_AGC_DECAY_NORMAL_64MS (0x7 << ACODEC_AGC_DECAY_TIME_SFT) ++#define ACODEC_AGC_DECAY_NORMAL_32MS (0x6 << ACODEC_AGC_DECAY_TIME_SFT) ++#define ACODEC_AGC_DECAY_NORMAL_16MS (0x5 << ACODEC_AGC_DECAY_TIME_SFT) ++#define ACODEC_AGC_DECAY_NORMAL_8MS (0x4 << ACODEC_AGC_DECAY_TIME_SFT) ++#define ACODEC_AGC_DECAY_NORMAL_4MS (0x3 << ACODEC_AGC_DECAY_TIME_SFT) ++#define ACODEC_AGC_DECAY_NORMAL_2MS (0x2 << ACODEC_AGC_DECAY_TIME_SFT) ++#define ACODEC_AGC_DECAY_NORMAL_1MS (0x1 << ACODEC_AGC_DECAY_TIME_SFT) ++#define ACODEC_AGC_DECAY_NORMAL_0MS (0x0 << ACODEC_AGC_DECAY_TIME_SFT) ++/* Limiter mode (reg_agc_mode = 1) */ ++#define ACODEC_AGC_DECAY_LIMITER_MSK (0xf << ACODEC_AGC_DECAY_TIME_SFT) ++#define ACODEC_AGC_DECAY_LIMITER_128MS (0xa << ACODEC_AGC_DECAY_TIME_SFT) ++#define ACODEC_AGC_DECAY_LIMITER_64MS (0x9 << ACODEC_AGC_DECAY_TIME_SFT) ++#define ACODEC_AGC_DECAY_LIMITER_32MS (0x8 << ACODEC_AGC_DECAY_TIME_SFT) ++#define ACODEC_AGC_DECAY_LIMITER_16MS (0x7 << ACODEC_AGC_DECAY_TIME_SFT) ++#define ACODEC_AGC_DECAY_LIMITER_8MS (0x6 << ACODEC_AGC_DECAY_TIME_SFT) ++#define ACODEC_AGC_DECAY_LIMITER_4MS (0x5 << ACODEC_AGC_DECAY_TIME_SFT) ++#define ACODEC_AGC_DECAY_LIMITER_2MS (0x4 << ACODEC_AGC_DECAY_TIME_SFT) ++#define ACODEC_AGC_DECAY_LIMITER_1MS (0x3 << ACODEC_AGC_DECAY_TIME_SFT) ++#define ACODEC_AGC_DECAY_LIMITER_500US (0x2 << ACODEC_AGC_DECAY_TIME_SFT) ++#define ACODEC_AGC_DECAY_LIMITER_250US (0x1 << ACODEC_AGC_DECAY_TIME_SFT) ++#define ACODEC_AGC_DECAY_LIMITER_125US (0x0 << ACODEC_AGC_DECAY_TIME_SFT) ++#define ACODEC_AGC_ATTACK_TIME_SFT 0 ++/* Normal mode (reg_agc_mode = 0) */ ++#define ACODEC_AGC_ATTACK_NORMAL_MSK (0xf << ACODEC_AGC_ATTACK_TIME_SFT) ++#define ACODEC_AGC_ATTACK_NORMAL_128MS (0xa << ACODEC_AGC_ATTACK_TIME_SFT) ++#define ACODEC_AGC_ATTACK_NORMAL_64MS (0x9 << ACODEC_AGC_ATTACK_TIME_SFT) ++#define ACODEC_AGC_ATTACK_NORMAL_32MS (0x8 << ACODEC_AGC_ATTACK_TIME_SFT) ++#define ACODEC_AGC_ATTACK_NORMAL_16MS (0x7 << ACODEC_AGC_ATTACK_TIME_SFT) ++#define ACODEC_AGC_ATTACK_NORMAL_8MS (0x6 << ACODEC_AGC_ATTACK_TIME_SFT) ++#define ACODEC_AGC_ATTACK_NORMAL_4MS (0x5 << ACODEC_AGC_ATTACK_TIME_SFT) ++#define ACODEC_AGC_ATTACK_NORMAL_2MS (0x4 << ACODEC_AGC_ATTACK_TIME_SFT) ++#define ACODEC_AGC_ATTACK_NORMAL_1MS (0x3 << ACODEC_AGC_ATTACK_TIME_SFT) ++#define ACODEC_AGC_ATTACK_NORMAL_500US (0x2 << ACODEC_AGC_ATTACK_TIME_SFT) ++#define ACODEC_AGC_ATTACK_NORMAL_250US (0x1 << ACODEC_AGC_ATTACK_TIME_SFT) ++#define ACODEC_AGC_ATTACK_NORMAL_125US (0x0 << ACODEC_AGC_ATTACK_TIME_SFT) ++/* Limiter mode (reg_agc_mode = 1) */ ++#define ACODEC_AGC_ATTACK_LIMITER_MSK (0xf << ACODEC_AGC_ATTACK_TIME_SFT) ++#define ACODEC_AGC_ATTACK_LIMITER_32MS (0xa << ACODEC_AGC_ATTACK_TIME_SFT) ++#define ACODEC_AGC_ATTACK_LIMITER_16MS (0x9 << ACODEC_AGC_ATTACK_TIME_SFT) ++#define ACODEC_AGC_ATTACK_LIMITER_8MS (0x8 << ACODEC_AGC_ATTACK_TIME_SFT) ++#define ACODEC_AGC_ATTACK_LIMITER_4MS (0x7 << ACODEC_AGC_ATTACK_TIME_SFT) ++#define ACODEC_AGC_ATTACK_LIMITER_2MS (0x6 << ACODEC_AGC_ATTACK_TIME_SFT) ++#define ACODEC_AGC_ATTACK_LIMITER_1MS (0x5 << ACODEC_AGC_ATTACK_TIME_SFT) ++#define ACODEC_AGC_ATTACK_LIMITER_500US (0x4 << ACODEC_AGC_ATTACK_TIME_SFT) ++#define ACODEC_AGC_ATTACK_LIMITER_250US (0x3 << ACODEC_AGC_ATTACK_TIME_SFT) ++#define ACODEC_AGC_ATTACK_LIMITER_125US (0x2 << ACODEC_AGC_ATTACK_TIME_SFT) ++#define ACODEC_AGC_ATTACK_LIMITER_64US (0x1 << ACODEC_AGC_ATTACK_TIME_SFT) ++#define ACODEC_AGC_ATTACK_LIMITER_32US (0x0 << ACODEC_AGC_ATTACK_TIME_SFT) ++ ++/* ACODEC_ADC_PGA_AGC_L_CTL2 */ ++#define ACODEC_AGC_MODE_LIMITER (0x1 << 7) ++#define ACODEC_AGC_MODE_NORMAL (0x0 << 7) ++#define ACODEC_AGC_ZERO_CRO_EN (0x1 << 6) ++#define ACODEC_AGC_ZERO_CRO_DIS (0x0 << 6) ++#define ACODEC_AGC_AMP_RECOVER_GAIN (0x1 << 5) ++#define ACODEC_AGC_AMP_RECOVER_LVOL (0x0 << 5) ++#define ACODEC_AGC_FAST_DEC_EN (0x1 << 4) ++#define ACODEC_AGC_FAST_DEC_DIS (0x0 << 4) ++#define ACODEC_AGC_NOISE_GATE_EN (0x1 << 3) ++#define ACODEC_AGC_NOISE_GATE_DIS (0x0 << 3) ++#define ACODEC_AGC_NOISE_GATE_THRESH_SFT 0 ++#define ACODEC_AGC_NOISE_GATE_THRESH_MSK (0x7 << ACODEC_AGC_NOISE_GATE_THRESH_SFT) ++#define ACODEC_AGC_NOISE_GATE_THRESH_N81DB (0x7 << ACODEC_AGC_NOISE_GATE_THRESH_SFT) ++#define ACODEC_AGC_NOISE_GATE_THRESH_N75DB (0x6 << ACODEC_AGC_NOISE_GATE_THRESH_SFT) ++#define ACODEC_AGC_NOISE_GATE_THRESH_N69DB (0x5 << ACODEC_AGC_NOISE_GATE_THRESH_SFT) ++#define ACODEC_AGC_NOISE_GATE_THRESH_N63DB (0x4 << ACODEC_AGC_NOISE_GATE_THRESH_SFT) ++#define ACODEC_AGC_NOISE_GATE_THRESH_N57DB (0x3 << ACODEC_AGC_NOISE_GATE_THRESH_SFT) ++#define ACODEC_AGC_NOISE_GATE_THRESH_N51DB (0x2 << ACODEC_AGC_NOISE_GATE_THRESH_SFT) ++#define ACODEC_AGC_NOISE_GATE_THRESH_N45DB (0x1 << ACODEC_AGC_NOISE_GATE_THRESH_SFT) ++#define ACODEC_AGC_NOISE_GATE_THRESH_N39DB (0x0 << ACODEC_AGC_NOISE_GATE_THRESH_SFT) ++ ++/* ACODEC_ADC_PGA_AGC_L_CTL3 */ ++#define ACODEC_AGC_PGA_ZERO_CRO_EN (0x1 << 5) ++#define ACODEC_AGC_PGA_ZERO_CRO_DIS (0x0 << 5) ++#define ACODEC_AGC_PGA_GAIN_MAX 0x1f ++#define ACODEC_AGC_PGA_GAIN_MIN 0 ++#define ACODEC_AGC_PGA_GAIN_SFT 0 ++#define ACODEC_AGC_PGA_GAIN_MSK (0x1f << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_PDB_28_5 (0x1f << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_PDB_27 (0x1e << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_PDB_25_5 (0x1d << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_PDB_24 (0x1c << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_PDB_22_5 (0x1b << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_PDB_21 (0x1a << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_PDB_19_5 (0x19 << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_PDB_18 (0x18 << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_PDB_16_5 (0x17 << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_PDB_15 (0x16 << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_PDB_13_5 (0x15 << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_PDB_12 (0x14 << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_PDB_10_5 (0x13 << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_PDB_9 (0x12 << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_PDB_7_5 (0x11 << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_PDB_6 (0x10 << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_PDB_4_5 (0x0f << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_PDB_3 (0x0e << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_PDB_1_5 (0x0d << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_0DB (0x0c << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_NDB_1_5 (0x0b << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_NDB_3 (0x0a << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_NDB_4_5 (0x09 << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_NDB_6 (0x08 << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_NDB_7_5 (0x07 << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_NDB_9 (0x06 << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_NDB_10_5 (0x05 << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_NDB_12 (0x04 << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_NDB_13_5 (0x03 << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_NDB_15 (0x02 << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_NDB_16_5 (0x01 << ACODEC_AGC_PGA_GAIN_SFT) ++#define ACODEC_AGC_PGA_GAIN_NDB_18 (0x00 << ACODEC_AGC_PGA_GAIN_SFT) ++ ++/* ACODEC_ADC_PGA_AGC_L_CTL4 */ ++#define ACODEC_AGC_SLOW_CLK_EN (0x1 << 3) ++#define ACODEC_AGC_SLOW_CLK_DIS (0x0 << 3) ++#define ACODEC_AGC_APPROX_RATE_SFT 0 ++#define ACODEC_AGC_APPROX_RATE_MSK (0x7 << ACODEC_AGC_APPROX_RATE_SFT) ++#define ACODEC_AGC_APPROX_RATE_8K (0x7 << ACODEC_AGC_APPROX_RATE_SFT) ++#define ACODEC_AGC_APPROX_RATE_12K (0x6 << ACODEC_AGC_APPROX_RATE_SFT) ++#define ACODEC_AGC_APPROX_RATE_16K (0x5 << ACODEC_AGC_APPROX_RATE_SFT) ++#define ACODEC_AGC_APPROX_RATE_24K (0x4 << ACODEC_AGC_APPROX_RATE_SFT) ++#define ACODEC_AGC_APPROX_RATE_32K (0x3 << ACODEC_AGC_APPROX_RATE_SFT) ++#define ACODEC_AGC_APPROX_RATE_44_1K (0x2 << ACODEC_AGC_APPROX_RATE_SFT) ++#define ACODEC_AGC_APPROX_RATE_48K (0x1 << ACODEC_AGC_APPROX_RATE_SFT) ++#define ACODEC_AGC_APPROX_RATE_96K (0x0 << ACODEC_AGC_APPROX_RATE_SFT) ++ ++/* ACODEC_ADC_PGA_AGC_L_CTL5 */ ++#define ACODEC_AGC_LO_8BITS_AGC_MAX_MSK 0xff ++ ++/* ACODEC_ADC_PGA_AGC_L_CTL6 */ ++#define ACODEC_AGC_HI_8BITS_AGC_MAX_MSK 0xff ++ ++/* ACODEC_ADC_PGA_AGC_L_CTL7 */ ++#define ACODEC_AGC_LO_8BITS_AGC_MIN_MSK 0xff ++ ++/* ACODEC_ADC_PGA_AGC_L_CTL8 */ ++#define ACODEC_AGC_HI_8BITS_AGC_MIN_MSK 0xff ++ ++/* ACODEC_ADC_PGA_AGC_L_CTL9 */ ++#define ACODEC_AGC_FUNC_SEL_MSK (0x1 << 6) ++#define ACODEC_AGC_FUNC_SEL_EN (0x1 << 6) ++#define ACODEC_AGC_FUNC_SEL_DIS (0x0 << 6) ++#define ACODEC_AGC_MAX_GAIN_PGA_MAX 0x7 ++#define ACODEC_AGC_MAX_GAIN_PGA_MIN 0 ++#define ACODEC_AGC_MAX_GAIN_PGA_SFT 3 ++#define ACODEC_AGC_MAX_GAIN_PGA_MSK (0x7 << ACODEC_AGC_MAX_GAIN_PGA_SFT) ++#define ACODEC_AGC_MAX_GAIN_PGA_PDB_28_5 (0x7 << ACODEC_AGC_MAX_GAIN_PGA_SFT) ++#define ACODEC_AGC_MAX_GAIN_PGA_PDB_22_5 (0x6 << ACODEC_AGC_MAX_GAIN_PGA_SFT) ++#define ACODEC_AGC_MAX_GAIN_PGA_PDB_16_5 (0x5 << ACODEC_AGC_MAX_GAIN_PGA_SFT) ++#define ACODEC_AGC_MAX_GAIN_PGA_PDB_10_5 (0x4 << ACODEC_AGC_MAX_GAIN_PGA_SFT) ++#define ACODEC_AGC_MAX_GAIN_PGA_PDB_4_5 (0x3 << ACODEC_AGC_MAX_GAIN_PGA_SFT) ++#define ACODEC_AGC_MAX_GAIN_PGA_NDB_1_5 (0x2 << ACODEC_AGC_MAX_GAIN_PGA_SFT) ++#define ACODEC_AGC_MAX_GAIN_PGA_NDB_7_5 (0x1 << ACODEC_AGC_MAX_GAIN_PGA_SFT) ++#define ACODEC_AGC_MAX_GAIN_PGA_NDB_13_5 (0x0 << ACODEC_AGC_MAX_GAIN_PGA_SFT) ++#define ACODEC_AGC_MIN_GAIN_PGA_MAX 0x7 ++#define ACODEC_AGC_MIN_GAIN_PGA_MIN 0 ++#define ACODEC_AGC_MIN_GAIN_PGA_SFT 0 ++#define ACODEC_AGC_MIN_GAIN_PGA_MSK (0x7 << ACODEC_AGC_MIN_GAIN_PGA_SFT) ++#define ACODEC_AGC_MIN_GAIN_PGA_PDB_24 (0x7 << ACODEC_AGC_MIN_GAIN_PGA_SFT) ++#define ACODEC_AGC_MIN_GAIN_PGA_PDB_18 (0x6 << ACODEC_AGC_MIN_GAIN_PGA_SFT) ++#define ACODEC_AGC_MIN_GAIN_PGA_PDB_12 (0x5 << ACODEC_AGC_MIN_GAIN_PGA_SFT) ++#define ACODEC_AGC_MIN_GAIN_PGA_PDB_6 (0x4 << ACODEC_AGC_MIN_GAIN_PGA_SFT) ++#define ACODEC_AGC_MIN_GAIN_PGA_0DB (0x3 << ACODEC_AGC_MIN_GAIN_PGA_SFT) ++#define ACODEC_AGC_MIN_GAIN_PGA_NDB_6 (0x2 << ACODEC_AGC_MIN_GAIN_PGA_SFT) ++#define ACODEC_AGC_MIN_GAIN_PGA_NDB_12 (0x1 << ACODEC_AGC_MIN_GAIN_PGA_SFT) ++#define ACODEC_AGC_MIN_GAIN_PGA_NDB_18 (0x0 << ACODEC_AGC_MIN_GAIN_PGA_SFT) ++ ++#define ACODEC_HIFI 0x0 ++ ++#endif /* __RV1106_CODEC_H__ */ diff --git a/patches/80-misc-thermal-rtc-adc.patch b/patches/80-misc-thermal-rtc-adc.patch new file mode 100644 index 0000000..7b91fad --- /dev/null +++ b/patches/80-misc-thermal-rtc-adc.patch @@ -0,0 +1,1128 @@ +diff --git a/drivers/char/hw_random/rockchip-rng.c b/drivers/char/hw_random/rockchip-rng.c +index 6e3ed4b85..464cda390 100644 +--- a/drivers/char/hw_random/rockchip-rng.c ++++ b/drivers/char/hw_random/rockchip-rng.c +@@ -468,6 +468,14 @@ static const struct of_device_id rk_rng_dt_match[] = { + { .compatible = "rockchip,rk3568-rng", .data = (void *)&rk3568_soc_data }, + { .compatible = "rockchip,rk3576-rng", .data = (void *)&rk3576_soc_data }, + { .compatible = "rockchip,rk3588-rng", .data = (void *)&rk3588_soc_data }, ++ /* ++ * RV1106 has the same standalone TRNG_V1 IP as RK3588 (identical ++ * register map: CTRL 0x00, STAT 0x04, MODE 0x08, ISTAT 0x14, ++ * RAND0-7 0x20-0x3c). Reuse rk3588_soc_data; the driver grabs clocks ++ * via clk_bulk_get_all and treats the reset as optional, so the ++ * rv1106 clock/reset names need no special handling. ++ */ ++ { .compatible = "rockchip,rv1106-rng", .data = (void *)&rk3588_soc_data }, + { /* sentinel */ }, + }; + +diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c +index 6721da0ed..cbd992cf4 100644 +--- a/drivers/iio/adc/rockchip_saradc.c ++++ b/drivers/iio/adc/rockchip_saradc.c +@@ -348,8 +348,25 @@ static const struct rockchip_saradc_data rk3588_saradc_data = { + .read = rockchip_saradc_read_v2, + }; + ++/* RV1106: a 2-channel v2 SARADC (ported from the vendor driver). */ ++static const struct iio_chan_spec rockchip_rv1106_saradc_iio_channels[] = { ++ SARADC_CHANNEL(0, "adc0", 10), ++ SARADC_CHANNEL(1, "adc1", 10), ++}; ++ ++static const struct rockchip_saradc_data rv1106_saradc_data = { ++ .channels = rockchip_rv1106_saradc_iio_channels, ++ .num_channels = ARRAY_SIZE(rockchip_rv1106_saradc_iio_channels), ++ .clk_rate = 1000000, ++ .start = rockchip_saradc_start_v2, ++ .read = rockchip_saradc_read_v2, ++}; ++ + static const struct of_device_id rockchip_saradc_match[] = { + { ++ .compatible = "rockchip,rv1106-saradc", ++ .data = &rv1106_saradc_data, ++ }, { + .compatible = "rockchip,saradc", + .data = &saradc_data, + }, { +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c +index 643578266..c4823ba07 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c +@@ -1374,6 +1374,62 @@ static const struct rk_gmac_ops rv1126_ops = { + .set_speed = rk_set_clk_mac_speed, + }; + ++/* ++ * RV1106: single RMII MAC wired to the on-die 10/100 FEPHY. RMII mode and the ++ * RMII reference-clock divider live in the VO GRF (offsets within the big ++ * grf syscon@ff000000, size 0x68000). Ported from the vendor 5.10 dwmac-rk.c. ++ * The vendor also programmed a bandgap trim (from OTP) into MACPHY_CON1; that ++ * is an analog optimisation the FEPHY runs without, and mainline's fephy ++ * powerup helper doesn't carry it — omitted here (see rng-otp/ for the OTP ++ * cell). CON0 powerup is enough to bring the PHY up. ++ */ ++#define RV1106_VOGRF_GMAC_CLK_CON 0x60004 ++#define RV1106_VOGRF_MACPHY_RMII_MODE GRF_BIT(0) ++#define RV1106_VOGRF_GMAC_CLK_RMII_DIV2 GRF_BIT(2) ++#define RV1106_VOGRF_GMAC_CLK_RMII_DIV20 GRF_CLR_BIT(2) ++#define RV1106_VOGRF_MACPHY_CON0 0x60028 ++ ++static void rv1106_set_to_rmii(struct rk_priv_data *bsp_priv) ++{ ++ regmap_write(bsp_priv->grf, RV1106_VOGRF_GMAC_CLK_CON, ++ RV1106_VOGRF_MACPHY_RMII_MODE | ++ RV1106_VOGRF_GMAC_CLK_RMII_DIV2); ++} ++ ++static int rv1106_set_speed(struct rk_priv_data *bsp_priv, ++ phy_interface_t interface, int speed) ++{ ++ unsigned int val; ++ ++ if (speed == 10) ++ val = RV1106_VOGRF_GMAC_CLK_RMII_DIV20; ++ else if (speed == 100) ++ val = RV1106_VOGRF_GMAC_CLK_RMII_DIV2; ++ else ++ return -EINVAL; ++ ++ regmap_write(bsp_priv->grf, RV1106_VOGRF_GMAC_CLK_CON, val); ++ ++ return 0; ++} ++ ++static void rv1106_integrated_phy_powerup(struct rk_priv_data *bsp_priv) ++{ ++ rk_gmac_integrated_fephy_powerup(bsp_priv, RV1106_VOGRF_MACPHY_CON0); ++} ++ ++static void rv1106_integrated_phy_powerdown(struct rk_priv_data *bsp_priv) ++{ ++ rk_gmac_integrated_fephy_powerdown(bsp_priv, RV1106_VOGRF_MACPHY_CON0); ++} ++ ++static const struct rk_gmac_ops rv1106_ops = { ++ .set_to_rmii = rv1106_set_to_rmii, ++ .set_speed = rv1106_set_speed, ++ .integrated_phy_powerup = rv1106_integrated_phy_powerup, ++ .integrated_phy_powerdown = rv1106_integrated_phy_powerdown, ++}; ++ + static int rk_gmac_clk_init(struct plat_stmmacenet_data *plat) + { + struct rk_priv_data *bsp_priv = plat->bsp_priv; +@@ -1813,6 +1869,7 @@ static const struct of_device_id rk_gmac_dwmac_match[] = { + { .compatible = "rockchip,rk3568-gmac", .data = &rk3568_ops }, + { .compatible = "rockchip,rk3576-gmac", .data = &rk3576_ops }, + { .compatible = "rockchip,rk3588-gmac", .data = &rk3588_ops }, ++ { .compatible = "rockchip,rv1106-gmac", .data = &rv1106_ops }, + { .compatible = "rockchip,rv1108-gmac", .data = &rv1108_ops }, + { .compatible = "rockchip,rv1126-gmac", .data = &rv1126_ops }, + { } +diff --git a/drivers/nvmem/rockchip-otp.c b/drivers/nvmem/rockchip-otp.c +index d88f12c53..073a5724a 100644 +--- a/drivers/nvmem/rockchip-otp.c ++++ b/drivers/nvmem/rockchip-otp.c +@@ -294,6 +294,29 @@ static const struct rockchip_data rk3588_data = { + .reg_read = rk3588_otp_read, + }; + ++/* ++ * RV1106 uses the same SBPI-protocol OTP controller as the rk3568/rk3588 ++ * family (the vendor 5.10 driver selected rk3568_otp_read, which is the same ++ * SBPI sequence as mainline's rk3588_otp_read). Six clocks, matching the DT ++ * clock-names usr/sbpi/apb/phy/arb/pmc. 0x80 bytes of user OTP. ++ */ ++static const char * const rv1106_otp_clocks[] = { ++ "usr", "sbpi", "apb", "phy", "arb", "pmc", ++}; ++ ++static const struct rockchip_data rv1106_data = { ++ .size = 0x80, ++ .clks = rv1106_otp_clocks, ++ .num_clks = ARRAY_SIZE(rv1106_otp_clocks), ++ /* ++ * User-mode OTPC_USER read (rockchip_otp_reset -> ecc_enable -> ++ * per-byte FSM), same sequence the vendor 5.10 driver used for ++ * rv1106 (its rk3568_otp_read). rk3588_otp_read uses a different ++ * addressing path and times out on this controller. ++ */ ++ .reg_read = px30_otp_read, ++}; ++ + static const struct of_device_id rockchip_otp_match[] = { + { + .compatible = "rockchip,px30-otp", +@@ -311,6 +334,10 @@ static const struct of_device_id rockchip_otp_match[] = { + .compatible = "rockchip,rk3588-otp", + .data = &rk3588_data, + }, ++ { ++ .compatible = "rockchip,rv1106-otp", ++ .data = &rv1106_data, ++ }, + { /* sentinel */ }, + }; + MODULE_DEVICE_TABLE(of, rockchip_otp_match); +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index 2933c41c7..fb389789a 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -1400,6 +1400,12 @@ config RTC_DRV_NTXEC + original design manufacturer Netronix. + + comment "on-CPU RTC drivers" ++config RTC_DRV_ROCKCHIP ++ tristate "Rockchip RV1106 RTC" ++ depends on ARCH_ROCKCHIP || COMPILE_TEST ++ help ++ The RV1106 internal RTC (rockchip,rv1106-rtc). Ported from the vendor. ++ + + config RTC_DRV_ASM9260 + tristate "Alphascale asm9260 RTC" +diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile +index 8221bda6e..e1bff733a 100644 +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -197,3 +197,4 @@ obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o + obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o + obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o + obj-$(CONFIG_RTC_DRV_ZYNQMP) += rtc-zynqmp.o ++obj-$(CONFIG_RTC_DRV_ROCKCHIP) += rtc-rockchip.o +diff --git a/drivers/rtc/rtc-rockchip.c b/drivers/rtc/rtc-rockchip.c +new file mode 100644 +index 000000000..5c088a9cf +--- /dev/null ++++ b/drivers/rtc/rtc-rockchip.c +@@ -0,0 +1,824 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (c) 2022 Rockchip Electronics Co., Ltd ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* RTC_CTRL_REG bitfields */ ++ ++#define RTC_REG(x) ((x)) ++#define RTC_SET_SECONDS RTC_REG(0x0) ++#define RTC_SET_MINUTES RTC_REG(0x4) ++#define RTC_SET_HOURS RTC_REG(0x8) ++#define RTC_SET_DAYS RTC_REG(0xc) ++#define RTC_SET_MONTHS RTC_REG(0x10) ++#define RTC_SET_YEARL RTC_REG(0x14) ++#define RTC_SET_YEARH RTC_REG(0x18) ++#define RTC_SET_WEEKS RTC_REG(0x1c) ++#define RTC_ALARM_SECONDS RTC_REG(0x20) ++#define RTC_ALARM_MINUTES RTC_REG(0x24) ++#define RTC_ALARM_HOURS RTC_REG(0x28) ++#define RTC_ALARM_DAYS RTC_REG(0x2c) ++#define RTC_ALARM_MONTHS RTC_REG(0x30) ++#define RTC_ALARM_YEARL RTC_REG(0x34) ++#define RTC_ALARM_YEARH RTC_REG(0x38) ++#define RTC_CTRL RTC_REG(0x3C) ++#define RTC_STATUS0 RTC_REG(0x40) ++#define RTC_STATUS1 RTC_REG(0x44) ++#define RTC_INT0_EN RTC_REG(0x48) ++#define RTC_INT1_EN RTC_REG(0x4c) ++#define RTC_MSEC_CTRL RTC_REG(0x50) ++#define RTC_MSEC_CNT RTC_REG(0x54) ++#define RTC_COMP_H RTC_REG(0x58) ++#define RTC_COMP_D RTC_REG(0x5c) ++#define RTC_COMP_M RTC_REG(0x60) ++#define RTC_ANALOG_CTRL RTC_REG(0x64) ++#define RTC_ANALOG_TEST RTC_REG(0x68) ++#define RTC_LDO_CTRL RTC_REG(0x6c) ++#define RTC_XO_TRIM0 RTC_REG(0x70) ++#define RTC_XO_TRIM1 RTC_REG(0x74) ++#define RTC_VPTAT_TRIM RTC_REG(0x78) ++#define RTC_ANALOG_EN RTC_REG(0x7c) ++#define RTC_CLK32K_TEST RTC_REG(0x80) ++#define RTC_TEST_ST RTC_REG(0x84) ++#define RTC_TEST_LEN RTC_REG(0x88) ++#define RTC_CNT_0 RTC_REG(0x8c) ++#define RTC_CNT_1 RTC_REG(0x90) ++#define RTC_CNT_2 RTC_REG(0x94) ++#define RTC_CNT_3 RTC_REG(0x98) ++#define RTC_MAX_REGISTER RTC_CNT_3 ++ ++#define VI_GRF_VI_MISC_CON0 0x50000 ++#define RTC_CLAMP_EN BIT(6) ++ ++/* RTC_CTRL_REG bitfields */ ++#define RTC_CTRL_REG_START_RTC BIT(0) ++#define RTC_TIMEOUT (3000 * 1000) ++ ++/* RK630 has a shadowed register for saving a "frozen" RTC time. ++ * When user setting "GET_TIME" to 1, the time will save in this shadowed ++ * register. If set "READSEL" to 1, user read rtc time register, actually ++ * get the time of that moment. If we need the real time, clr this bit. ++ */ ++#define RTC_CTRL_REG_RTC_GET_TIME BIT(6) ++#define RTC_CTRL_REG_RTC_READSEL_M BIT(7) ++#define RTC_INT_REG_ALARM_EN BIT(7) ++#define RTC_D2A_XO_EN BIT(0) ++#define RTC_D2A_CLK_OUT_EN BIT(5) ++ ++#define RTC_STATUS_MASK 0xFF ++ ++#define SECONDS_REG_MSK 0x7F ++#define MINUTES_REG_MAK 0x7F ++#define HOURS_REG_MSK 0x3F ++#define DAYS_REG_MSK 0x3F ++#define MONTHS_REG_MSK 0x1F ++#define YEARS_REG_MSK 0xFF ++#define WEEKS_REG_MSK 0x7 ++ ++#define RTC_VREF_INIT 0x40 ++ ++#define CLK_32K_ENABLE BIT(5) ++#define D2A_POR_REG_SEL1 BIT(4) ++#define D2A_POR_REG_SEL0 BIT(1) ++ ++#define NUM_TIME_REGS 8 ++#define NUM_ALARM_REGS 7 ++ ++#define DISABLE_ALARM_INT 0x3F ++#define ENABLE_ALARM_INT 0xFF ++#define ALARM_INT_STATUS BIT(4) ++ ++#define CLK32K_TEST_EN BIT(0) ++#define CLK32K_TEST_START BIT(0) ++#define CLK32K_TEST_STATUS BIT(1) ++#define CLK32K_TEST_DONE BIT(2) ++#define CLK32K_TEST_LEN 1 ++ ++#define CLK32K_COMP_DIR_ADD BIT(7) ++#define CLK32K_COMP_EN BIT(2) ++#define CLK32K_NO_COMP 0x1 ++ ++#define CLK32K_TEST_REF_CLK 24000000 ++ ++#define RTC_WRITE_MASK 0xc4522900 ++ ++enum { ++ ROCKCHIP_RV1106_RTC = 1, ++}; ++ ++struct rockchip_rtc { ++ struct regmap *regmap; ++ struct rtc_device *rtc; ++ struct regmap *grf; ++ struct clk_bulk_data *clks; ++ int num_clks; ++ int irq; ++ unsigned int flag; ++ unsigned int mode; ++ struct delayed_work trim_work; ++ bool suspend_bypass; ++}; ++ ++static unsigned int rockchip_rtc_write(struct regmap *map, ++ u32 offset, u32 val) ++{ ++ return regmap_write(map, offset, val | RTC_WRITE_MASK); ++} ++ ++static unsigned int rockchip_rtc_update_bits(struct regmap *map, ++ u32 offset, u32 mask, ++ u32 set) ++{ ++ unsigned int val; ++ ++ regmap_read(map, offset, &val); ++ return regmap_write(map, offset, (val & ~mask) | set | RTC_WRITE_MASK); ++} ++ ++/* Read current time and date in RTC */ ++static int rockchip_rtc_read_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct rockchip_rtc *rtc = dev_get_drvdata(dev); ++ u32 rtc_data[NUM_TIME_REGS]; ++ int ret; ++ int yearl, yearh; ++ ++ /* No shadowed registers, need read time three time to update time */ ++ ret = regmap_bulk_read(rtc->regmap, RTC_SET_SECONDS, ++ rtc_data, NUM_TIME_REGS); ++ if (ret) { ++ dev_err(dev, "Failed to bulk read rtc_data: %d\n", ret); ++ return ret; ++ } ++ ret = regmap_bulk_read(rtc->regmap, RTC_SET_SECONDS, ++ rtc_data, NUM_TIME_REGS); ++ if (ret) { ++ dev_err(dev, "Failed to bulk read rtc_data: %d\n", ret); ++ return ret; ++ } ++ ret = regmap_bulk_read(rtc->regmap, RTC_SET_SECONDS, ++ rtc_data, NUM_TIME_REGS); ++ if (ret) { ++ dev_err(dev, "Failed to bulk read rtc_data: %d\n", ret); ++ return ret; ++ } ++ ++ tm->tm_sec = bcd2bin(rtc_data[0] & SECONDS_REG_MSK); ++ tm->tm_min = bcd2bin(rtc_data[1] & MINUTES_REG_MAK); ++ tm->tm_hour = bcd2bin(rtc_data[2] & HOURS_REG_MSK); ++ tm->tm_mday = bcd2bin(rtc_data[3] & DAYS_REG_MSK); ++ tm->tm_mon = (bcd2bin(rtc_data[4] & MONTHS_REG_MSK)) - 1; ++ yearl = (bcd2bin(rtc_data[5] & YEARS_REG_MSK)); ++ yearh = (bcd2bin(rtc_data[6] & YEARS_REG_MSK)); ++ tm->tm_year = yearh * 100 + yearl + 100; ++ tm->tm_wday = bcd2bin(rtc_data[7] & WEEKS_REG_MSK); ++ ++ dev_dbg(dev, "RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", ++ 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, ++ tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec); ++ ++ return ret; ++} ++ ++/* Set current time and date in RTC */ ++static int rockchip_rtc_set_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct rockchip_rtc *rtc = dev_get_drvdata(dev); ++ u32 rtc_data[NUM_TIME_REGS]; ++ int ret, status = 0; ++ int yearl, yearh; ++ ++ dev_dbg(dev, "set RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", ++ 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, ++ tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec); ++ ++ rtc_data[0] = bin2bcd(tm->tm_sec) | RTC_WRITE_MASK; ++ rtc_data[1] = bin2bcd(tm->tm_min) | RTC_WRITE_MASK; ++ rtc_data[2] = bin2bcd(tm->tm_hour) | RTC_WRITE_MASK; ++ rtc_data[3] = bin2bcd(tm->tm_mday) | RTC_WRITE_MASK; ++ rtc_data[4] = bin2bcd(tm->tm_mon + 1) | RTC_WRITE_MASK; ++ if (tm->tm_year > 199) { ++ yearh = (tm->tm_year - 100) / 100; ++ yearl = tm->tm_year - 100 - yearh * 100; ++ } else { ++ yearh = 0; ++ yearl = tm->tm_year - 100 - yearh * 100; ++ } ++ rtc_data[5] = bin2bcd(yearl) | RTC_WRITE_MASK; ++ rtc_data[6] = bin2bcd(yearh) | RTC_WRITE_MASK; ++ rtc_data[7] = bin2bcd(tm->tm_wday) | RTC_WRITE_MASK; ++ ++ /* Stop RTC while updating the RTC registers */ ++ ret = rockchip_rtc_update_bits(rtc->regmap, RTC_CTRL, ++ RTC_CTRL_REG_START_RTC, 0); ++ if (ret) { ++ dev_err(dev, "Failed to update RTC control: %d\n", ret); ++ return ret; ++ } ++ ++ ret = regmap_read_poll_timeout(rtc->regmap, RTC_STATUS1, status, ++ !(status & RTC_CTRL_REG_START_RTC), ++ 0, RTC_TIMEOUT); ++ if (ret) ++ dev_err(dev, ++ "%s:timeout Update RTC_STATUS1 : %d\n", ++ __func__, ret); ++ ++ ret = regmap_bulk_write(rtc->regmap, RTC_SET_SECONDS, ++ rtc_data, NUM_TIME_REGS); ++ if (ret) { ++ dev_err(dev, "Failed to bull write rtc_data: %d\n", ret); ++ return ret; ++ } ++ ++ /* Start RTC again */ ++ ret = rockchip_rtc_update_bits(rtc->regmap, RTC_CTRL, ++ RTC_CTRL_REG_RTC_READSEL_M | ++ RTC_CTRL_REG_START_RTC, ++ RTC_CTRL_REG_RTC_READSEL_M | ++ RTC_CTRL_REG_START_RTC); ++ if (ret) { ++ dev_err(dev, "Failed to update RTC control: %d\n", ret); ++ return ret; ++ } ++ ++ ret = regmap_read_poll_timeout(rtc->regmap, RTC_STATUS1, status, ++ (status & RTC_CTRL_REG_START_RTC), ++ 0, RTC_TIMEOUT); ++ if (ret) ++ dev_err(dev, ++ "%s:timeout Update RTC_STATUS1 : %d\n", ++ __func__, ret); ++ ++ return 0; ++} ++ ++/* Read alarm time and date in RTC */ ++static int rockchip_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) ++{ ++ struct rockchip_rtc *rtc = dev_get_drvdata(dev); ++ u32 alrm_data[NUM_ALARM_REGS]; ++ u32 int_reg; ++ int yearl, yearh; ++ int ret; ++ ++ ret = regmap_bulk_read(rtc->regmap, ++ RTC_ALARM_SECONDS, ++ alrm_data, NUM_ALARM_REGS); ++ if (ret) { ++ dev_err(dev, "Failed to read RTC alarm date REG: %d\n", ret); ++ return ret; ++ } ++ ++ alrm->time.tm_sec = bcd2bin(alrm_data[0] & SECONDS_REG_MSK); ++ alrm->time.tm_min = bcd2bin(alrm_data[1] & MINUTES_REG_MAK); ++ alrm->time.tm_hour = bcd2bin(alrm_data[2] & HOURS_REG_MSK); ++ alrm->time.tm_mday = bcd2bin(alrm_data[3] & DAYS_REG_MSK); ++ alrm->time.tm_mon = (bcd2bin(alrm_data[4] & MONTHS_REG_MSK)) - 1; ++ yearl = (bcd2bin(alrm_data[5] & YEARS_REG_MSK)); ++ yearh = (bcd2bin(alrm_data[6] & YEARS_REG_MSK)); ++ alrm->time.tm_year = yearh * 100 + yearl + 100; ++ ++ ret = regmap_read(rtc->regmap, RTC_INT0_EN, &int_reg); ++ if (ret) { ++ dev_err(dev, "Failed to read RTC INT REG: %d\n", ret); ++ return ret; ++ } ++ ++ dev_dbg(dev, ++ "alrm read RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", ++ 1900 + alrm->time.tm_year, alrm->time.tm_mon + 1, ++ alrm->time.tm_mday, alrm->time.tm_wday, alrm->time.tm_hour, ++ alrm->time.tm_min, alrm->time.tm_sec); ++ ++ alrm->enabled = (int_reg & RTC_INT_REG_ALARM_EN) ? 1 : 0; ++ ++ return 0; ++} ++ ++static int rockchip_rtc_stop_alarm(struct rockchip_rtc *rtc) ++{ ++ int ret; ++ ++ ret = rockchip_rtc_write(rtc->regmap, RTC_INT0_EN, 0); ++ ++ return ret; ++} ++ ++static int rockchip_rtc_start_alarm(struct rockchip_rtc *rtc) ++{ ++ int ret; ++ ++ ret = rockchip_rtc_write(rtc->regmap, RTC_STATUS0, RTC_STATUS_MASK); ++ ret = rockchip_rtc_write(rtc->regmap, RTC_STATUS0, 0); ++ ret = rockchip_rtc_write(rtc->regmap, RTC_INT0_EN, ENABLE_ALARM_INT); ++ ++ return ret; ++} ++ ++static int rockchip_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) ++{ ++ struct rockchip_rtc *rtc = dev_get_drvdata(dev); ++ u32 alrm_data[NUM_ALARM_REGS]; ++ int yearl, yearh; ++ int ret; ++ ++ ret = rockchip_rtc_stop_alarm(rtc); ++ if (ret) { ++ dev_err(dev, "Failed to stop alarm: %d\n", ret); ++ return ret; ++ } ++ dev_dbg(dev, ++ "alrm set RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", ++ 1900 + alrm->time.tm_year, alrm->time.tm_mon + 1, ++ alrm->time.tm_mday, alrm->time.tm_wday, alrm->time.tm_hour, ++ alrm->time.tm_min, alrm->time.tm_sec); ++ ++ alrm_data[0] = bin2bcd(alrm->time.tm_sec) | RTC_WRITE_MASK; ++ alrm_data[1] = bin2bcd(alrm->time.tm_min) | RTC_WRITE_MASK; ++ alrm_data[2] = bin2bcd(alrm->time.tm_hour) | RTC_WRITE_MASK; ++ alrm_data[3] = bin2bcd(alrm->time.tm_mday) | RTC_WRITE_MASK; ++ alrm_data[4] = bin2bcd(alrm->time.tm_mon + 1) | RTC_WRITE_MASK; ++ if (alrm->time.tm_year > 199) { ++ yearh = (alrm->time.tm_year - 100) / 100; ++ yearl = alrm->time.tm_year - 100 - yearh * 100; ++ } else { ++ yearh = 0; ++ yearl = alrm->time.tm_year - 100 - yearh * 100; ++ } ++ alrm_data[5] = bin2bcd(yearl) | RTC_WRITE_MASK; ++ alrm_data[6] = bin2bcd(yearh) | RTC_WRITE_MASK; ++ ++ ret = regmap_bulk_write(rtc->regmap, ++ RTC_ALARM_SECONDS, ++ alrm_data, NUM_ALARM_REGS); ++ if (ret) { ++ dev_err(dev, "Failed to bulk write: %d\n", ret); ++ return ret; ++ } ++ if (alrm->enabled) { ++ ret = rockchip_rtc_start_alarm(rtc); ++ if (ret) { ++ dev_err(dev, "Failed to start alarm: %d\n", ret); ++ return ret; ++ } ++ } ++ return 0; ++} ++ ++static int rockchip_rtc_alarm_irq_enable(struct device *dev, ++ unsigned int enabled) ++{ ++ struct rockchip_rtc *rtc = dev_get_drvdata(dev); ++ ++ if (enabled) ++ return rockchip_rtc_start_alarm(rtc); ++ ++ return rockchip_rtc_stop_alarm(rtc); ++} ++ ++/* ++ * We will just handle setting the frequency and make use the framework for ++ * reading the periodic interrupts. ++ * ++ */ ++static irqreturn_t rockchip_rtc_alarm_irq(int irq, void *data) ++{ ++ struct rockchip_rtc *rtc = data; ++ int ret, status; ++ ++ ret = regmap_read(rtc->regmap, RTC_STATUS0, &status); ++ if (ret) { ++ pr_err("Failed to read RTC INT REG: %d\n", ret); ++ return ret; ++ } ++ ++ ret = rockchip_rtc_write(rtc->regmap, RTC_STATUS0, status); ++ if (ret) { ++ pr_err("%s:Failed to update RTC status: %d\n", __func__, ret); ++ return ret; ++ } ++ if (status & ALARM_INT_STATUS) { ++ pr_info("Alarm by: %s\n", __func__); ++ rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static const struct rtc_class_ops rockchip_rtc_ops = { ++ .read_time = rockchip_rtc_read_time, ++ .set_time = rockchip_rtc_set_time, ++ .read_alarm = rockchip_rtc_readalarm, ++ .set_alarm = rockchip_rtc_setalarm, ++ .alarm_irq_enable = rockchip_rtc_alarm_irq_enable, ++}; ++ ++/* ++ * Due to the analog generator 32k clock affected by ++ * temperature, voltage, clock precision need test ++ * with the environment change. In rtc test, ++ * use 24M clock as reference clock to measure the 32k clock. ++ * Before start test 32k clock, we should enable clk32k test(0x80), ++ * and configure test length, when rtc test done(0x84[2]), ++ * latch the 24M clock domain counter, ++ * and read out the counter from rtc_test ++ * registers(0x8c~0x98) via apb bus. ++ * In RTC digital design, we set three level compensation, ++ * the compensation value due to the ++ * RTC 32k clock test result, and if we need compensation, ++ * we need configure the compensation enable bit. ++ * Comp every hour, compensation at last minute every hour, ++ * and support add time and sub time by the MSB bit. ++ * Comp every day, compensation at last minute in last hour every day, ++ * and support add time and sub time by the MSB bit. ++ * Comp every month, compensation at last minute ++ * in last hour in last day every month, ++ * and support add time and sub time by the MSB bit. ++ */ ++static void rockchip_rtc_compensation_delay_work(struct work_struct *work) ++{ ++ struct rockchip_rtc *rtc = container_of(work, struct rockchip_rtc, trim_work.work); ++ u64 camp; ++ u32 count[4], counts, g_ref, tcamp; ++ int ret, done = 0, trim_dir, c_hour, ++ c_day, c_det_day, c_mon, c_det_mon; ++ ++ ret = rockchip_rtc_update_bits(rtc->regmap, RTC_CLK32K_TEST, ++ CLK32K_TEST_EN, CLK32K_TEST_EN); ++ if (ret) { ++ pr_err("%s:Failed to update RTC CLK32K TEST: %d\n", ++ __func__, ret); ++ return; ++ } ++ ++ ret = rockchip_rtc_write(rtc->regmap, RTC_TEST_LEN, ++ CLK32K_TEST_LEN); ++ if (ret) { ++ pr_err("%s:Failed to update RTC CLK32K TEST LEN: %d\n", ++ __func__, ret); ++ return; ++ } ++ ++ ret = rockchip_rtc_update_bits(rtc->regmap, RTC_TEST_ST, ++ CLK32K_TEST_START, ++ CLK32K_TEST_START); ++ if (ret) { ++ pr_err("%s:Failed to update RTC CLK32K TEST STATUS : %d\n", ++ __func__, ret); ++ return; ++ } ++ ret = regmap_read_poll_timeout(rtc->regmap, RTC_TEST_ST, done, ++ (done & CLK32K_TEST_DONE), 20000, RTC_TIMEOUT); ++ if (ret) ++ pr_err("%s:timeout waiting for RTC TEST STATUS : %d\n", ++ __func__, ret); ++ ++ ret = regmap_bulk_read(rtc->regmap, ++ RTC_CNT_0, ++ count, 4); ++ if (ret) { ++ pr_err("Failed to read RTC count REG: %d\n", ret); ++ return; ++ } ++ ++ counts = count[0] | (count[1] << 8) | ++ (count[2] << 16) | (count[3] << 24); ++ g_ref = CLK32K_TEST_REF_CLK * (CLK32K_TEST_LEN + 1); ++ ++ if (counts > g_ref) { ++ trim_dir = 0; ++ camp = 36ULL * (32768 * (counts - g_ref)); ++ do_div(camp, (g_ref / 100)); ++ } else { ++ trim_dir = CLK32K_COMP_DIR_ADD; ++ camp = 36ULL * (32768 * (g_ref - counts)); ++ do_div(camp, (g_ref / 100)); ++ } ++ tcamp = (u32)camp; ++ c_hour = DIV_ROUND_CLOSEST(tcamp, 32768); ++ c_day = DIV_ROUND_CLOSEST(24 * tcamp, 32768); ++ c_mon = DIV_ROUND_CLOSEST(30 * 24 * tcamp, 32768); ++ ++ if (c_hour > 1) ++ rockchip_rtc_write(rtc->regmap, RTC_COMP_H, bin2bcd((c_hour - 1)) | trim_dir); ++ else ++ rockchip_rtc_write(rtc->regmap, RTC_COMP_H, CLK32K_NO_COMP); ++ ++ if (c_day > c_hour * 23) { ++ c_det_day = c_day - c_hour * 23; ++ trim_dir = CLK32K_COMP_DIR_ADD; ++ } else { ++ c_det_day = c_hour * 24 - c_day; ++ trim_dir = 0; ++ } ++ ++ if (c_det_day > 1) ++ rockchip_rtc_write(rtc->regmap, RTC_COMP_D, ++ bin2bcd((c_det_day - 1)) | trim_dir); ++ else ++ rockchip_rtc_write(rtc->regmap, RTC_COMP_D, CLK32K_NO_COMP); ++ ++ if (c_mon > (29 * c_day + 23 * c_hour)) { ++ c_det_mon = c_mon - 29 * c_day - 23 * c_hour; ++ trim_dir = CLK32K_COMP_DIR_ADD; ++ } else { ++ c_det_mon = 29 * c_day + 23 * c_hour - c_mon; ++ trim_dir = 0; ++ } ++ ++ if (c_det_mon) ++ rockchip_rtc_write(rtc->regmap, RTC_COMP_M, ++ bin2bcd((c_det_mon - 1)) | trim_dir); ++ else ++ rockchip_rtc_write(rtc->regmap, RTC_COMP_M, CLK32K_NO_COMP); ++ ++ ret = regmap_read(rtc->regmap, RTC_CTRL, &done); ++ if (ret) { ++ pr_err("Failed to read RTC_CTRL: %d\n", ret); ++ return; ++ } ++ ++ ret = rockchip_rtc_update_bits(rtc->regmap, RTC_CTRL, ++ CLK32K_COMP_EN, CLK32K_COMP_EN); ++ if (ret) { ++ pr_err("%s:Failed to update RTC CTRL : %d\n", __func__, ret); ++ return; ++ } ++ return; ++} ++ ++static bool rockchip_rtc_is_trimed(struct rockchip_rtc *rtc) ++{ ++ int ret, comp_done; ++ ++ ret = regmap_read(rtc->regmap, RTC_CTRL, &comp_done); ++ if (ret) { ++ pr_err("%s: Failed to read RTC_CTRL: %d\n", __func__, ret); ++ return false; ++ } ++ return (comp_done & CLK32K_COMP_EN) == CLK32K_COMP_EN; ++} ++ ++static void rockchip_rtc_trim_start(struct rockchip_rtc *rtc) ++{ ++ if (!rockchip_rtc_is_trimed(rtc)) ++ queue_delayed_work(system_long_wq, &rtc->trim_work, ++ msecs_to_jiffies(5000)); ++} ++ ++static void __maybe_unused rockchip_rtc_trim_close(struct rockchip_rtc *rtc) ++{ ++ if (!rockchip_rtc_is_trimed(rtc)) ++ cancel_delayed_work_sync(&rtc->trim_work); ++} ++ ++/* Enable the alarm if it should be enabled (in case it was disabled to ++ * prevent use as a wake source). ++ */ ++#ifdef CONFIG_PM_SLEEP ++/* Turn off the alarm if it should not be a wake source. */ ++static int rockchip_rtc_suspend(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct rockchip_rtc *rtc = dev_get_drvdata(&pdev->dev); ++ ++ if (rtc->suspend_bypass) ++ return 0; ++ ++ if (device_may_wakeup(dev)) ++ enable_irq_wake(rtc->irq); ++ ++ rockchip_rtc_trim_close(rtc); ++ ++ if (rtc->grf) { ++ switch (rtc->mode) { ++ case ROCKCHIP_RV1106_RTC: ++ regmap_write(rtc->grf, VI_GRF_VI_MISC_CON0, ++ (RTC_CLAMP_EN << 16)); ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ clk_bulk_disable_unprepare(rtc->num_clks, rtc->clks); ++ ++ return 0; ++} ++ ++/* Enable the alarm if it should be enabled (in case it was disabled to ++ * prevent use as a wake source). ++ */ ++static int rockchip_rtc_resume(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct rockchip_rtc *rtc = dev_get_drvdata(&pdev->dev); ++ int ret; ++ ++ if (rtc->suspend_bypass) ++ return 0; ++ ++ if (device_may_wakeup(dev)) ++ disable_irq_wake(rtc->irq); ++ ++ if (rtc->grf) { ++ switch (rtc->mode) { ++ case ROCKCHIP_RV1106_RTC: ++ regmap_write(rtc->grf, VI_GRF_VI_MISC_CON0, ++ (RTC_CLAMP_EN << 16) | RTC_CLAMP_EN); ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ ret = clk_bulk_prepare_enable(rtc->num_clks, rtc->clks); ++ if (ret) { ++ dev_err(dev, "Cannot enable clock.\n"); ++ return ret; ++ } ++ rockchip_rtc_trim_start(rtc); ++ ++ return 0; ++} ++#endif ++ ++static SIMPLE_DEV_PM_OPS(rockchip_rtc_pm_ops, ++ rockchip_rtc_suspend, rockchip_rtc_resume); ++ ++static const struct of_device_id rockchip_rtc_of_match[] = { ++ { ++ .compatible = "rockchip,rv1106-rtc", ++ .data = (void *)ROCKCHIP_RV1106_RTC ++ }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, rockchip_rtc_of_match); ++ ++static void rockchip_rtc_clk_disable(void *data) ++{ ++ struct rockchip_rtc *rtc = data; ++ ++ clk_bulk_disable_unprepare(rtc->num_clks, rtc->clks); ++} ++ ++static int rockchip_rtc_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct rockchip_rtc *rtc; ++ int ret; ++ struct rtc_time tm_read, tm = { ++ .tm_wday = 0, ++ .tm_year = 121, ++ .tm_mon = 0, ++ .tm_mday = 1, ++ .tm_hour = 12, ++ .tm_min = 0, ++ .tm_sec = 0, ++ }; ++ ++ rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); ++ if (!rtc) ++ return -ENOMEM; ++ ++ rtc->regmap = device_node_to_regmap(np); ++ if (IS_ERR(rtc->regmap)) ++ return dev_err_probe(dev, PTR_ERR(rtc->regmap), ++ "no regmap available\n"); ++ ++ rtc->mode = (uintptr_t)device_get_match_data(dev); ++ rtc->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); ++ if (IS_ERR(rtc->grf)) { ++ dev_warn(dev, "Missing rockchip,grf property\n"); ++ rtc->grf = NULL; ++ } else { ++ switch (rtc->mode) { ++ case ROCKCHIP_RV1106_RTC: ++ regmap_write(rtc->grf, VI_GRF_VI_MISC_CON0, ++ (RTC_CLAMP_EN << 16) | RTC_CLAMP_EN); ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ ++ platform_set_drvdata(pdev, rtc); ++ ++ rtc->num_clks = devm_clk_bulk_get_all(&pdev->dev, &rtc->clks); ++ if (rtc->num_clks < 1) ++ return -ENODEV; ++ ret = clk_bulk_prepare_enable(rtc->num_clks, rtc->clks); ++ if (ret) ++ return dev_err_probe(dev, ret, "Cannot enable clock.\n"); ++ ret = devm_add_action_or_reset(dev, rockchip_rtc_clk_disable, rtc); ++ if (ret) ++ return dev_err_probe(dev, ret, ++ "Failed to add clk disable action."); ++ ++ ret = rockchip_rtc_update_bits(rtc->regmap, RTC_VPTAT_TRIM, ++ D2A_POR_REG_SEL1 | ++ CLK_32K_ENABLE, ++ D2A_POR_REG_SEL1 | ++ CLK_32K_ENABLE); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, ++ "Failed to write RTC_VPTAT_TRIM\n"); ++ ret = rockchip_rtc_update_bits(rtc->regmap, RTC_ANALOG_EN, ++ D2A_POR_REG_SEL0, ++ 0x00); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, ++ "Failed to write RTC_ANALOG_EN\n"); ++ ++ ret = rockchip_rtc_update_bits(rtc->regmap, RTC_LDO_CTRL, ++ RTC_D2A_XO_EN, ++ RTC_D2A_XO_EN); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, ++ "Failed to update RTC_LDO_CTRL\n"); ++ ++ ret = rockchip_rtc_update_bits(rtc->regmap, RTC_ANALOG_EN, ++ RTC_D2A_CLK_OUT_EN, ++ RTC_D2A_CLK_OUT_EN); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, ++ "Failed to update RTC_ANALOG_EN\n"); ++ ++ /* start rtc running by default, and use shadowed timer. */ ++ ret = rockchip_rtc_update_bits(rtc->regmap, RTC_CTRL, ++ RTC_CTRL_REG_START_RTC | ++ RTC_CTRL_REG_RTC_READSEL_M, ++ RTC_CTRL_REG_RTC_READSEL_M | ++ RTC_CTRL_REG_START_RTC); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, ++ "Failed to update RTC control\n"); ++ ++ ret = rockchip_rtc_write(rtc->regmap, RTC_STATUS0, RTC_STATUS_MASK); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, ++ "Failed to write RTC status0\n"); ++ ++ ret = rockchip_rtc_write(rtc->regmap, RTC_STATUS0, 0); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, ++ "Failed to write RTC status0\n"); ++ ++ device_init_wakeup(&pdev->dev, 1); ++ ++ rockchip_rtc_read_time(&pdev->dev, &tm_read); ++ if (rtc_valid_tm(&tm_read) != 0) ++ rockchip_rtc_set_time(&pdev->dev, &tm); ++ ++ rtc->rtc = devm_rtc_allocate_device(&pdev->dev); ++ if (IS_ERR(rtc->rtc)) ++ return PTR_ERR(rtc->rtc); ++ ++ rtc->rtc->ops = &rockchip_rtc_ops; ++ ++ rtc->irq = platform_get_irq(pdev, 0); ++ if (rtc->irq < 0) ++ return dev_err_probe(&pdev->dev, rtc->irq, "No IRQ resource\n"); ++ ++ /* request alarm irq of rtc */ ++ ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, ++ &rockchip_rtc_alarm_irq, IRQF_ONESHOT, ++ "RTC alarm", rtc); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, ++ "Failed to request alarm IRQ %d\n", ++ rtc->irq); ++ ++ /* If rtc 32k used as time for deep sleep, the rtc suspend func bypass do nothing. */ ++ rtc->suspend_bypass = device_property_read_bool(&pdev->dev, ++ "rockchip,rtc-suspend-bypass"); ++ ++ INIT_DELAYED_WORK(&rtc->trim_work, rockchip_rtc_compensation_delay_work); ++ rockchip_rtc_trim_start(rtc); ++ ++ return devm_rtc_register_device(rtc->rtc); ++} ++ ++static struct platform_driver rockchip_rtc_driver = { ++ .probe = rockchip_rtc_probe, ++ .driver = { ++ .name = "rockchip-rtc", ++ .pm = &rockchip_rtc_pm_ops, ++ .of_match_table = rockchip_rtc_of_match, ++ }, ++}; ++ ++module_platform_driver(rockchip_rtc_driver); ++ ++MODULE_DESCRIPTION("RTC driver for the rockchip"); ++MODULE_AUTHOR("Zhang Qing "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c +index c49ddf70f..10bbab6ec 100644 +--- a/drivers/thermal/rockchip_thermal.c ++++ b/drivers/thermal/rockchip_thermal.c +@@ -276,6 +276,19 @@ struct rockchip_thermal_data { + + + #define RK_MAX_TEMP (180000) ++/* vendor rv1106 tsadc uses these names + register defs */ ++#define MIN_TEMP (-60000) ++#define MAX_TEMP (180000) ++/* rv1106 tsadc (TSADCV9 + VOGRF) register defs, ported from vendor */ ++#define TSADCV9_Q_MAX 0x210 ++#define TSADCV9_FLOW_CON 0x218 ++#define TSADCV9_AUTO_SRC (0x10001 << 0) ++#define TSADCV9_PD_MODE (0x10001 << 4) ++#define TSADCV9_Q_MAX_VAL (0xffff0400 << 0) ++#define RV1106_VOGRF_TSADC_CON 0x6000C ++#define RV1106_VOGRF_TSADC_TSEN (0x10001 << 8) ++#define RV1106_VOGRF_TSADC_ANA (0xff0007 << 0) ++ + + /** + * struct tsadc_table - code to temperature conversion table +@@ -1120,6 +1133,68 @@ static const struct rockchip_tsadc_chip px30_tsadc_data = { + }, + }; + ++static const struct tsadc_table rv1106_code_table[] = { ++ {0, MIN_TEMP}, ++ {363, MIN_TEMP}, ++ {396, -40000}, ++ {504, 25000}, ++ {605, 85000}, ++ {673, 125000}, ++ {758, MAX_TEMP}, ++ {TSADCV2_DATA_MASK, MAX_TEMP}, ++}; ++ ++static void rk_tsadcv9_initialize(struct regmap *grf, void __iomem *regs, ++ enum tshut_polarity tshut_polarity) ++{ ++ regmap_write(grf, RV1106_VOGRF_TSADC_CON, RV1106_VOGRF_TSADC_TSEN); ++ udelay(10); ++ regmap_write(grf, RV1106_VOGRF_TSADC_CON, RV1106_VOGRF_TSADC_ANA); ++ udelay(100); ++ ++ writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV3_AUTO_PERIOD); ++ writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, ++ regs + TSADCV3_AUTO_PERIOD_HT); ++ writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_COUNT, ++ regs + TSADCV3_HIGHT_INT_DEBOUNCE); ++ writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT, ++ regs + TSADCV3_HIGHT_TSHUT_DEBOUNCE); ++ writel_relaxed(TSADCV9_AUTO_SRC, regs + TSADCV2_INT_PD); ++ writel_relaxed(TSADCV9_PD_MODE, regs + TSADCV9_FLOW_CON); ++ writel_relaxed(TSADCV9_Q_MAX_VAL, regs + TSADCV9_Q_MAX); ++ if (tshut_polarity == TSHUT_HIGH_ACTIVE) ++ writel_relaxed(TSADCV2_AUTO_TSHUT_POLARITY_HIGH | ++ TSADCV2_AUTO_TSHUT_POLARITY_MASK, ++ regs + TSADCV2_AUTO_CON); ++ else ++ writel_relaxed(TSADCV2_AUTO_TSHUT_POLARITY_MASK, ++ regs + TSADCV2_AUTO_CON); ++ writel_relaxed(TSADCV3_AUTO_Q_SEL_EN | (TSADCV3_AUTO_Q_SEL_EN << 16), ++ regs + TSADCV2_AUTO_CON); ++} ++ ++static const struct rockchip_tsadc_chip rv1106_tsadc_data = { ++ /* top, big_core0, big_core1, little_core, center, gpu, npu */ ++ .chn_offset = 0, /* cpu sensor is channel 0 */ ++ .chn_num = 1, /* seven channels for tsadc */ ++ .tshut_mode = TSHUT_MODE_CRU, /* default TSHUT via CRU */ ++ .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ ++ .tshut_temp = 95000, ++ .initialize = rk_tsadcv9_initialize, ++ .irq_ack = rk_tsadcv4_irq_ack, ++ .control = rk_tsadcv4_control, ++ .get_temp = rk_tsadcv4_get_temp, ++ .set_alarm_temp = rk_tsadcv3_alarm_temp, ++ .set_tshut_temp = rk_tsadcv3_tshut_temp, ++ .set_tshut_mode = rk_tsadcv4_tshut_mode, ++ .table = { ++ .id = rv1106_code_table, ++ .length = ARRAY_SIZE(rv1106_code_table), ++ .data_mask = TSADCV2_DATA_MASK, ++ .mode = ADC_INCREMENT, ++ }, ++}; ++ + static const struct rockchip_tsadc_chip rv1108_tsadc_data = { + /* cpu */ + .chn_offset = 0, +@@ -1358,6 +1433,9 @@ static const struct of_device_id of_rockchip_thermal_match[] = { + { + .compatible = "rockchip,rv1108-tsadc", + .data = (void *)&rv1108_tsadc_data, ++ }, { ++ .compatible = "rockchip,rv1106-tsadc", ++ .data = (void *)&rv1106_tsadc_data, + }, + { + .compatible = "rockchip,rk3228-tsadc", diff --git a/patches/README.md b/patches/README.md new file mode 100644 index 0000000..44023d7 --- /dev/null +++ b/patches/README.md @@ -0,0 +1,40 @@ +# RV1106 kernel patch series (pristine linux-6.18.46 → WardenOS) + +The delta that forward-ports the vendor Rockchip 5.10.160 RV1106 support onto a +pristine upstream **linux-6.18.46**, as a reviewable, subsystem-split series. Every +patch applies cleanly onto pristine 6.18.46 (`git apply --check`), and the whole set +reproduces the 223-file / ~136K-line delta that boots and is hardware-verified on +`warden-c8a3` (see `../kernel/rv1106-enablement/`). + +Build it with `../build/build-kernel.sh` (fetch pristine → apply these → configure +with `../build/warden_defconfig` → `zImage` + `rv1106-warden.dtb`). + +## The series + +| Patch | Scope | +|---|---| +| `05-build-wiring.patch` | top-level `drivers/{Kconfig,Makefile}` (wire in rknpu) | +| `10-clk-rv1106.patch` | CRU clock driver (`clk-rv1106.c`, reuses rv1126 data) | +| `15-pinctrl.patch` | `pinctrl-rockchip` RV1106 iomux | +| `20-arch-dts-bindings.patch` | `arch/arm` DTs (`rv1106.dtsi`, `rv1106-warden.dts`, pinctrl), mach, configs, `include/dt-bindings` | +| `25-usb-phy.patch` | inno-usb2 phy | +| `30-drm-vop-panel-rgb.patch` | VOP (`rgb_dclk_pol`=0 + WIN1 scanout), panel-simple bus-format, rockchip_rgb | +| `35-mailbox-hpmcu.patch` | rockchip-mailbox (rv1106 num_chans=1) | +| `40-pvtm-soc.patch` | PVTM (core+pmu) + `include/soc/rockchip/pvtm.h` | +| `45-npu-rknpu.patch` | open GPL rknpu 0.9.2 driver + `rknpu_ioctl.h` uapi | +| `50-rga.patch` | RGA 2D (rga3) + `drivers/video` wiring | +| `60-wifi-aic8800.patch` | out-of-tree AIC8800 wifi/BT (the 88.5K-line vendor blob) | +| `70-audio-codec.patch` | `rv1106_codec` + I2S wiring | +| `80-misc-thermal-rtc-adc.patch` | tsadc, rtc-rockchip, saradc, trng, otp, gmac, goodix touch | + +## Provenance & regeneration + +Baseline: `linux-6.18.46` from kernel.org (`build/linux-6.18.46.tar.xz.sha256` +pins the tarball). The series was generated by overlaying the hardware-verified +source tree onto pristine (build artifacts excluded) and splitting `git diff` by +subsystem. Licensing/origin of each block is tracked in +`../kernel/rv1106-enablement/PROVENANCE.md`. + +Whitespace: `60-wifi-aic8800.patch` carries the vendor blob's trailing-whitespace +verbatim; `git apply --whitespace=nowarn` (the build wrapper) accepts it. Do not +re-flow vendor code — it must stay diffable against future vendor drops.